From 4640f3e9104a2052ec2b1c6e62ddcf7ed4a8f53a Mon Sep 17 00:00:00 2001 From: Adrien Guatto Date: Wed, 4 Oct 2023 15:40:22 +0200 Subject: [PATCH] Publication du jalon 1 --- flap/AUTEURS | 2 + flap/README.md | 31 + flap/dune-project | 3 + flap/runtime/runtime.c | 37 ++ flap/src/commandLineOptions.ml | 162 +++++ flap/src/common/architecture.mli | 26 + flap/src/common/compilers.ml | 114 ++++ flap/src/common/compilers.mli | 45 ++ flap/src/common/languages.ml | 95 +++ flap/src/common/languages.mli | 80 +++ flap/src/common/memory.ml | 49 ++ flap/src/common/memory.mli | 39 ++ flap/src/common/mint.ml | 17 + flap/src/common/mint.mli | 34 + flap/src/common/optimizers.ml | 57 ++ flap/src/common/syntacticAnalysis.ml | 12 + flap/src/common/syntacticAnalysis.mli | 11 + flap/src/dune | 29 + flap/src/elf/elf.ml | 37 ++ flap/src/elf/elfAST.ml | 1 + flap/src/elf/elfInitialization.ml | 7 + flap/src/elf/elfInterpreter.ml | 37 ++ flap/src/elf/elfTypechecker.ml | 9 + flap/src/elf/x86_64toElf.ml | 48 ++ flap/src/flap.ml | 236 +++++++ flap/src/fopix/fopix.ml | 32 + flap/src/fopix/fopixAST.ml | 65 ++ flap/src/fopix/fopixInitialization.ml | 4 + flap/src/fopix/fopixInterpreter.ml | 395 ++++++++++++ flap/src/fopix/fopixLexer.mll | 111 ++++ flap/src/fopix/fopixParser.mly | 164 +++++ flap/src/fopix/fopixPrettyPrinter.ml | 131 ++++ flap/src/fopix/fopixTypechecker.ml | 7 + flap/src/fopix/hobixToFopix.ml | 297 +++++++++ flap/src/hobix/HobixParser.mly | 21 + flap/src/hobix/hobix.ml | 35 ++ flap/src/hobix/hobixAST.ml | 51 ++ flap/src/hobix/hobixInitialization.ml | 4 + flap/src/hobix/hobixInterpreter.ml | 418 +++++++++++++ flap/src/hobix/hobixLexer.mll | 206 ++++++ flap/src/hobix/hobixParser.mly | 204 ++++++ flap/src/hobix/hobixPrettyPrinter.ml | 155 +++++ flap/src/hobix/hobixTypechecker.ml | 11 + flap/src/hobix/hobixTypes.ml | 5 + flap/src/hobix/hopixToHobix.ml | 312 ++++++++++ flap/src/hobix/patternMatchingCompiler.ml | 182 ++++++ flap/src/hopix/hopix.ml | 44 ++ flap/src/hopix/hopixAST.ml | 150 +++++ flap/src/hopix/hopixASTHelper.ml | 15 + flap/src/hopix/hopixInitialization.ml | 4 + flap/src/hopix/hopixInterpreter.ml | 356 +++++++++++ flap/src/hopix/hopixLexer.mll | 32 + flap/src/hopix/hopixParser.mly | 23 + flap/src/hopix/hopixPrettyPrinter.ml | 394 ++++++++++++ flap/src/hopix/hopixSyntacticSugar.mli | 26 + flap/src/hopix/hopixTypechecker.ml | 102 +++ flap/src/hopix/hopixTypes.ml | 493 +++++++++++++++ flap/src/hopix/hopixTypes.mli | 97 +++ flap/src/options.ml | 80 +++ flap/src/retrolix/fopixToRetrolix.ml | 404 ++++++++++++ flap/src/retrolix/retrolix.ml | 33 + flap/src/retrolix/retrolixAST.ml | 180 ++++++ flap/src/retrolix/retrolixConstantFolding.ml | 83 +++ flap/src/retrolix/retrolixDataflowEngines.ml | 130 ++++ flap/src/retrolix/retrolixDataflowSigs.ml | 48 ++ flap/src/retrolix/retrolixDataflowUtils.ml | 105 ++++ .../retrolix/retrolixDeadCodeElimination.ml | 63 ++ flap/src/retrolix/retrolixInitialization.ml | 7 + .../src/retrolix/retrolixInterferenceGraph.ml | 79 +++ flap/src/retrolix/retrolixInterpreter.ml | 383 ++++++++++++ flap/src/retrolix/retrolixKillMove.ml | 23 + flap/src/retrolix/retrolixLexer.mll | 167 +++++ flap/src/retrolix/retrolixLivenessAnalysis.ml | 142 +++++ flap/src/retrolix/retrolixParser.mly | 194 ++++++ flap/src/retrolix/retrolixPrettyPrinter.ml | 137 ++++ .../retrolix/retrolixRegisterAllocation.ml | 225 +++++++ flap/src/retrolix/retrolixTypechecker.ml | 181 ++++++ flap/src/retrolix/retrolixUtils.ml | 199 ++++++ flap/src/utilities/dict.ml | 25 + flap/src/utilities/dict.mli | 15 + flap/src/utilities/digraph.ml | 160 +++++ flap/src/utilities/digraph.mli | 102 +++ flap/src/utilities/error.ml | 33 + flap/src/utilities/error.mli | 32 + flap/src/utilities/extPPrint.ml | 25 + flap/src/utilities/extStd.ml | 340 ++++++++++ flap/src/utilities/graph.ml | 428 +++++++++++++ flap/src/utilities/graph.mli | 99 +++ flap/src/utilities/int16.ml | 29 + flap/src/utilities/int16.mli | 22 + flap/src/utilities/list.ml | 9 + flap/src/utilities/listMonad.ml | 12 + flap/src/utilities/listMonad.mli | 93 +++ flap/src/utilities/option.ml | 7 + flap/src/utilities/position.ml | 152 +++++ flap/src/utilities/position.mli | 112 ++++ flap/src/utilities/stdUserInput.ml | 22 + flap/src/utilities/userInput.ml | 1 + flap/src/version.ml | 1 + flap/src/x86-64/retrolixToX86_64.ml | 584 ++++++++++++++++++ flap/src/x86-64/x86_64.ml | 33 + flap/src/x86-64/x86_64_AST.ml | 299 +++++++++ flap/src/x86-64/x86_64_Architecture.ml | 189 ++++++ flap/src/x86-64/x86_64_Initialization.ml | 6 + flap/src/x86-64/x86_64_Interpreter.ml | 42 ++ flap/src/x86-64/x86_64_PrettyPrinter.ml | 199 ++++++ flap/src/x86-64/x86_64_Typechecker.ml | 9 + .../01-constructor-application.bad.expected | 2 + ...application.bad.parsing-no-positions.hopix | 2 + .../01-constructor-application.good.expected | 1 + ...pplication.good.parsing-no-positions.hopix | 2 + .../02-app2.bad.expected | 2 + .../02-app2.bad.parsing-no-positions.hopix | 1 + .../03-app2-2.bad.expected | 2 + .../03-app2-2.bad.parsing-no-positions.hopix | 2 + .../04-app2-3.bad.expected | 2 + .../04-app2-3.bad.parsing-no-positions.hopix | 1 + .../05-app3.bad.expected | 2 + .../05-app3.bad.parsing-no-positions.hopix | 1 + .../06-lexer-var-id-1.bad.expected | 2 + ...er-var-id-1.bad.parsing-no-positions.hopix | 1 + .../06-lexer-var-id-1.good.expected | 1 + ...r-var-id-1.good.parsing-no-positions.hopix | 1 + .../07-lexer-var-id-2.bad.expected | 2 + ...er-var-id-2.bad.parsing-no-positions.hopix | 1 + .../07-lexer-var-id-2.good.expected | 1 + ...r-var-id-2.good.parsing-no-positions.hopix | 1 + .../08-lexer-all-id-1.bad.expected | 2 + ...er-all-id-1.bad.parsing-no-positions.hopix | 2 + .../08-lexer-all-id-1.good.expected | 2 + ...r-all-id-1.good.parsing-no-positions.hopix | 2 + .../09-lexer-constr-id-1.bad.expected | 1 + ...constr-id-1.bad.parsing-no-positions.hopix | 1 + .../09-lexer-constr-id-1.good.expected | 1 + ...onstr-id-1.good.parsing-no-positions.hopix | 1 + .../10-lexer-constr-id-2.bad.expected | 2 + ...constr-id-2.bad.parsing-no-positions.hopix | 1 + .../10-lexer-constr-id-2.good.expected | 1 + ...onstr-id-2.good.parsing-no-positions.hopix | 1 + .../100-ref-2.bad.expected | 2 + .../100-ref-2.bad.parsing-no-positions.hopix | 1 + .../100-ref-2.good.expected | 1 + .../100-ref-2.good.parsing-no-positions.hopix | 1 + .../101-ref-3.bad.expected | 2 + .../101-ref-3.bad.parsing-no-positions.hopix | 3 + .../101-ref-3.good.expected | 1 + .../101-ref-3.good.parsing-no-positions.hopix | 3 + .../102-ref-4.bad.expected | 2 + .../102-ref-4.bad.parsing-no-positions.hopix | 2 + .../102-ref-4.good.expected | 1 + .../102-ref-4.good.parsing-no-positions.hopix | 3 + .../103-ref-5.bad.expected | 2 + .../103-ref-5.bad.parsing-no-positions.hopix | 3 + .../103-ref-5.good.expected | 1 + .../103-ref-5.good.parsing-no-positions.hopix | 3 + .../104-assignment.bad.expected | 2 + ...-assignment.bad.parsing-no-positions.hopix | 2 + .../104-assignment.good.expected | 1 + ...assignment.good.parsing-no-positions.hopix | 2 + .../105-assignment-2.bad.expected | 2 + ...ssignment-2.bad.parsing-no-positions.hopix | 2 + .../105-assignment-2.good.expected | 1 + ...signment-2.good.parsing-no-positions.hopix | 2 + .../106-assignment-3.bad.expected | 2 + ...ssignment-3.bad.parsing-no-positions.hopix | 2 + .../106-assignment-3.good.expected | 1 + ...signment-3.good.parsing-no-positions.hopix | 2 + .../107-assignment-4.bad.expected | 2 + ...ssignment-4.bad.parsing-no-positions.hopix | 2 + .../107-assignment-4.good.expected | 1 + ...signment-4.good.parsing-no-positions.hopix | 2 + .../108-type-ascription-1.bad.expected | 2 + ...scription-1.bad.parsing-no-positions.hopix | 2 + .../108-type-ascription-1.good.expected | 1 + ...cription-1.good.parsing-no-positions.hopix | 2 + .../109-type-ascription-2.bad.expected | 2 + ...scription-2.bad.parsing-no-positions.hopix | 2 + .../109-type-ascription-2.good.expected | 1 + ...cription-2.good.parsing-no-positions.hopix | 2 + .../11-lexer-constr-id-3.bad.expected | 2 + ...constr-id-3.bad.parsing-no-positions.hopix | 1 + .../11-lexer-constr-id-3.good.expected | 1 + ...onstr-id-3.good.parsing-no-positions.hopix | 1 + .../110-type-ascription-3.bad.expected | 2 + ...scription-3.bad.parsing-no-positions.hopix | 1 + .../110-type-ascription-3.good.expected | 1 + ...cription-3.good.parsing-no-positions.hopix | 1 + .../111-deref-1.bad.expected | 2 + ...111-deref-1.bad.parsing-no-positions.hopix | 2 + .../111-deref-1.good.expected | 1 + ...11-deref-1.good.parsing-no-positions.hopix | 2 + .../112-deref-2.bad.expected | 2 + ...112-deref-2.bad.parsing-no-positions.hopix | 2 + .../112-deref-2.good.expected | 1 + ...12-deref-2.good.parsing-no-positions.hopix | 2 + .../113-deref-3.good.expected | 1 + ...13-deref-3.good.parsing-no-positions.hopix | 1 + .../114-while-1.bad.expected | 2 + ...114-while-1.bad.parsing-no-positions.hopix | 2 + .../114-while-1.good.expected | 1 + ...14-while-1.good.parsing-no-positions.hopix | 2 + .../115-while-2.bad.expected | 2 + ...115-while-2.bad.parsing-no-positions.hopix | 5 + .../115-while-2.good.expected | 2 + ...15-while-2.good.parsing-no-positions.hopix | 6 + .../116-for-1.bad.expected | 2 + .../116-for-1.bad.parsing-no-positions.hopix | 2 + .../116-for-1.good.expected | 1 + .../116-for-1.good.parsing-no-positions.hopix | 2 + .../117-for-2.bad.expected | 2 + .../117-for-2.bad.parsing-no-positions.hopix | 2 + .../117-for-2.good.expected | 1 + .../117-for-2.good.parsing-no-positions.hopix | 2 + .../118-do-while-1.bad.expected | 2 + ...-do-while-1.bad.parsing-no-positions.hopix | 2 + .../118-do-while-1.good.expected | 1 + ...do-while-1.good.parsing-no-positions.hopix | 2 + .../119-do-while-2.bad.expected | 2 + ...-do-while-2.bad.parsing-no-positions.hopix | 6 + .../119-do-while-2.good.expected | 3 + ...do-while-2.good.parsing-no-positions.hopix | 6 + .../12-lexer-label-id-1.bad.expected | 2 + ...-label-id-1.bad.parsing-no-positions.hopix | 1 + .../12-lexer-label-id-1.good.expected | 1 + ...label-id-1.good.parsing-no-positions.hopix | 1 + .../12-lexer-label-id-2.bad.expected | 2 + ...-label-id-2.bad.parsing-no-positions.hopix | 1 + .../12-lexer-label-id-2.good.expected | 1 + ...label-id-2.good.parsing-no-positions.hopix | 1 + .../13-type-con-id-1.bad.expected | 2 + ...pe-con-id-1.bad.parsing-no-positions.hopix | 1 + .../13-type-con-id-1.good.expected | 1 + ...e-con-id-1.good.parsing-no-positions.hopix | 1 + .../14-type-con-id-2.bad.expected | 2 + ...pe-con-id-2.bad.parsing-no-positions.hopix | 1 + .../14-type-con-id-2.good.expected | 1 + ...e-con-id-2.good.parsing-no-positions.hopix | 1 + .../15-int-literal-1.bad.expected | 2 + ...t-literal-1.bad.parsing-no-positions.hopix | 1 + .../15-int-literal-1.good.expected | 1 + ...-literal-1.good.parsing-no-positions.hopix | 1 + .../16-int-literal-2.bad.expected | 2 + ...t-literal-2.bad.parsing-no-positions.hopix | 1 + .../16-int-literal-2.good.expected | 1 + ...-literal-2.good.parsing-no-positions.hopix | 1 + .../17-int-literal-3.bad.expected | 2 + ...t-literal-3.bad.parsing-no-positions.hopix | 1 + .../17-int-literal-3.good.expected | 1 + ...-literal-3.good.parsing-no-positions.hopix | 1 + .../18-int-literal-4.bad.expected | 2 + ...t-literal-4.bad.parsing-no-positions.hopix | 1 + .../18-int-literal-4.good.expected | 1 + ...-literal-4.good.parsing-no-positions.hopix | 1 + .../19-int-literal-5.bad.expected | 2 + ...t-literal-5.bad.parsing-no-positions.hopix | 1 + .../19-int-literal-5.good.expected | 1 + ...-literal-5.good.parsing-no-positions.hopix | 1 + .../20-int-literal-6.bad.expected | 2 + ...t-literal-6.bad.parsing-no-positions.hopix | 1 + .../20-int-literal-6.good.expected | 1 + ...-literal-6.good.parsing-no-positions.hopix | 1 + .../21-char-literal-1.bad.expected | 2 + ...r-literal-1.bad.parsing-no-positions.hopix | 1 + .../21-char-literal-1.good.expected | 1 + ...-literal-1.good.parsing-no-positions.hopix | 1 + .../22-char-literal-2.bad.expected | 2 + ...r-literal-2.bad.parsing-no-positions.hopix | 1 + .../22-char-literal-2.good.expected | 1 + ...-literal-2.good.parsing-no-positions.hopix | 1 + .../23-char-literal-3.bad.expected | 2 + ...r-literal-3.bad.parsing-no-positions.hopix | 1 + .../23-char-literal-3.good.expected | 1 + ...-literal-3.good.parsing-no-positions.hopix | 1 + .../24-char-literal-4.bad.expected | 2 + ...r-literal-4.bad.parsing-no-positions.hopix | 1 + .../24-char-literal-4.good.expected | 1 + ...-literal-4.good.parsing-no-positions.hopix | 1 + .../25-char-literal-5.bad.expected | 2 + ...r-literal-5.bad.parsing-no-positions.hopix | 1 + .../25-char-literal-5.good.expected | 1 + ...-literal-5.good.parsing-no-positions.hopix | 1 + .../26-char-literal-6.bad.expected | 2 + ...r-literal-6.bad.parsing-no-positions.hopix | 1 + .../26-char-literal-6.good.expected | 2 + ...-literal-6.good.parsing-no-positions.hopix | 2 + .../27-string-literal-1.bad.expected | 2 + ...g-literal-1.bad.parsing-no-positions.hopix | 1 + .../27-string-literal-1.good.expected | 2 + ...-literal-1.good.parsing-no-positions.hopix | 1 + .../28-string-literal-2.bad.expected | 2 + ...g-literal-2.bad.parsing-no-positions.hopix | 1 + .../28-string-literal-2.good.expected | 2 + ...-literal-2.good.parsing-no-positions.hopix | 1 + .../29-string-literal-3.bad.expected | 2 + ...g-literal-3.bad.parsing-no-positions.hopix | 1 + .../29-string-literal-3.good.expected | 1 + ...-literal-3.good.parsing-no-positions.hopix | 1 + .../30-string-literal-4.bad.expected | 2 + ...g-literal-4.bad.parsing-no-positions.hopix | 1 + .../30-string-literal-4.good.expected | 1 + ...-literal-4.good.parsing-no-positions.hopix | 1 + .../31-type-definition-sum-1.bad.expected | 2 + ...ition-sum-1.bad.parsing-no-positions.hopix | 1 + .../31-type-definition-sum-1.good.expected | 1 + ...tion-sum-1.good.parsing-no-positions.hopix | 1 + .../32-type-definition-sum-2.bad.expected | 2 + ...ition-sum-2.bad.parsing-no-positions.hopix | 1 + .../32-type-definition-sum-2.good.expected | 1 + ...tion-sum-2.good.parsing-no-positions.hopix | 1 + .../33-type-definition-sum-3.bad.expected | 2 + ...ition-sum-3.bad.parsing-no-positions.hopix | 1 + .../33-type-definition-sum-3.good.expected | 1 + ...tion-sum-3.good.parsing-no-positions.hopix | 1 + .../34-type-definition-sum-4.bad.expected | 2 + ...ition-sum-4.bad.parsing-no-positions.hopix | 1 + .../34-type-definition-sum-4.good.expected | 1 + ...tion-sum-4.good.parsing-no-positions.hopix | 1 + .../35-type-definition-sum-5.bad.expected | 2 + ...ition-sum-5.bad.parsing-no-positions.hopix | 1 + .../35-type-definition-sum-5.good.expected | 1 + ...tion-sum-5.good.parsing-no-positions.hopix | 1 + .../36-type-definition-sum-6.bad.expected | 2 + ...ition-sum-6.bad.parsing-no-positions.hopix | 1 + .../36-type-definition-sum-6.good.expected | 1 + ...tion-sum-6.good.parsing-no-positions.hopix | 1 + .../37-type-definition-sum-7.bad.expected | 2 + ...ition-sum-7.bad.parsing-no-positions.hopix | 1 + .../37-type-definition-sum-7.good.expected | 3 + ...tion-sum-7.good.parsing-no-positions.hopix | 1 + .../38-type-definition-record-1.bad.expected | 2 + ...on-record-1.bad.parsing-no-positions.hopix | 1 + .../38-type-definition-record-1.good.expected | 3 + ...n-record-1.good.parsing-no-positions.hopix | 1 + .../39-type-definition-record-2.bad.expected | 2 + ...on-record-2.bad.parsing-no-positions.hopix | 2 + .../39-type-definition-record-2.good.expected | 6 + ...n-record-2.good.parsing-no-positions.hopix | 2 + .../40-type-definition-record-3.bad.expected | 2 + ...on-record-3.bad.parsing-no-positions.hopix | 8 + .../40-type-definition-record-3.good.expected | 10 + ...n-record-3.good.parsing-no-positions.hopix | 8 + .../41-external-definition-1.bad.expected | 2 + ...efinition-1.bad.parsing-no-positions.hopix | 1 + .../41-external-definition-1.good.expected | 1 + ...finition-1.good.parsing-no-positions.hopix | 1 + .../42-external-definition-2.good.expected | 1 + ...finition-2.good.parsing-no-positions.hopix | 1 + .../43-external-definition-3.bad.expected | 1 + ...efinition-3.bad.parsing-no-positions.hopix | 1 + .../43-external-definition-3.good.expected | 1 + ...finition-3.good.parsing-no-positions.hopix | 1 + .../44-value-definition-1.bad.expected | 2 + ...efinition-1.bad.parsing-no-positions.hopix | 1 + .../44-value-definition-1.good.expected | 1 + ...finition-1.good.parsing-no-positions.hopix | 1 + .../45-value-definition-2.bad.expected | 2 + ...efinition-2.bad.parsing-no-positions.hopix | 1 + .../45-value-definition-2.good.expected | 1 + ...finition-2.good.parsing-no-positions.hopix | 1 + .../46-value-definition-3.bad.expected | 2 + ...efinition-3.bad.parsing-no-positions.hopix | 1 + .../46-value-definition-3.good.expected | 1 + ...finition-3.good.parsing-no-positions.hopix | 1 + .../47-instanciation.bad.expected | 1 + ...stanciation.bad.parsing-no-positions.hopix | 1 + .../47-instanciation.good.expected | 1 + ...tanciation.good.parsing-no-positions.hopix | 1 + .../48-instanciation-2.bad.expected | 2 + ...anciation-2.bad.parsing-no-positions.hopix | 1 + .../48-instanciation-2.good.expected | 1 + ...nciation-2.good.parsing-no-positions.hopix | 1 + .../49-instanciation-3.bad.expected | 2 + ...anciation-3.bad.parsing-no-positions.hopix | 1 + .../49-instanciation-3.good.expected | 1 + ...nciation-3.good.parsing-no-positions.hopix | 1 + .../50-instanciation-4.bad.expected | 2 + ...anciation-4.bad.parsing-no-positions.hopix | 1 + .../50-instanciation-4.good.expected | 1 + ...nciation-4.good.parsing-no-positions.hopix | 1 + .../51-instanciation-5.bad.expected | 2 + ...anciation-5.bad.parsing-no-positions.hopix | 1 + .../51-instanciation-5.good.expected | 1 + ...nciation-5.good.parsing-no-positions.hopix | 1 + .../52-instanciation-6.bad.expected | 2 + ...anciation-6.bad.parsing-no-positions.hopix | 1 + .../52-instanciation-6.good.expected | 1 + ...nciation-6.good.parsing-no-positions.hopix | 1 + .../53-instanciation-7.bad.expected | 2 + ...anciation-7.bad.parsing-no-positions.hopix | 1 + .../53-instanciation-7.good.expected | 1 + ...nciation-7.good.parsing-no-positions.hopix | 1 + .../54-constructor-1.bad.expected | 2 + ...nstructor-1.bad.parsing-no-positions.hopix | 1 + .../54-constructor-1.good.expected | 1 + ...structor-1.good.parsing-no-positions.hopix | 1 + .../55-constructor-2.bad.expected | 1 + ...nstructor-2.bad.parsing-no-positions.hopix | 1 + .../55-constructor-2.good.expected | 1 + ...structor-2.good.parsing-no-positions.hopix | 1 + .../56-constructor-3.bad.expected | 2 + ...nstructor-3.bad.parsing-no-positions.hopix | 1 + .../56-constructor-3.good.expected | 6 + ...structor-3.good.parsing-no-positions.hopix | 1 + .../57-constructor-4.bad.expected | 2 + ...nstructor-4.bad.parsing-no-positions.hopix | 1 + .../57-constructor-4.good.expected | 1 + ...structor-4.good.parsing-no-positions.hopix | 1 + .../58-record-1.bad.expected | 2 + ...58-record-1.bad.parsing-no-positions.hopix | 1 + .../58-record-1.good.expected | 1 + ...8-record-1.good.parsing-no-positions.hopix | 1 + .../59-record-2.bad.expected | 2 + ...59-record-2.bad.parsing-no-positions.hopix | 1 + .../59-record-2.good.expected | 1 + ...9-record-2.good.parsing-no-positions.hopix | 1 + .../60-record-3.bad.expected | 2 + ...60-record-3.bad.parsing-no-positions.hopix | 1 + .../60-record-3.good.expected | 1 + ...0-record-3.good.parsing-no-positions.hopix | 1 + .../61-record-projection-1.bad.expected | 2 + ...rojection-1.bad.parsing-no-positions.hopix | 1 + .../61-record-projection-1.good.expected | 1 + ...ojection-1.good.parsing-no-positions.hopix | 1 + .../62-record-projection-2.bad.expected | 2 + ...rojection-2.bad.parsing-no-positions.hopix | 1 + .../62-record-projection-2.good.expected | 1 + ...ojection-2.good.parsing-no-positions.hopix | 1 + .../63-record-projection-3.bad.expected | 2 + ...rojection-3.bad.parsing-no-positions.hopix | 1 + .../63-record-projection-3.good.expected | 1 + ...ojection-3.good.parsing-no-positions.hopix | 1 + .../65-sequence-1.bad.expected | 2 + ...-sequence-1.bad.parsing-no-positions.hopix | 1 + .../65-sequence-1.good.expected | 1 + ...sequence-1.good.parsing-no-positions.hopix | 1 + .../66-sequence-2.bad.expected | 2 + ...-sequence-2.bad.parsing-no-positions.hopix | 1 + .../66-sequence-2.good.expected | 1 + ...sequence-2.good.parsing-no-positions.hopix | 1 + .../67-sequence-3.bad.expected | 2 + ...-sequence-3.bad.parsing-no-positions.hopix | 1 + .../67-sequence-3.good.expected | 1 + ...sequence-3.good.parsing-no-positions.hopix | 1 + .../68-local-definition.bad.expected | 2 + ...-definition.bad.parsing-no-positions.hopix | 3 + .../68-local-definition.good.expected | 1 + ...definition.good.parsing-no-positions.hopix | 3 + .../69-local-definition-2.bad.expected | 2 + ...efinition-2.bad.parsing-no-positions.hopix | 6 + .../69-local-definition-2.good.expected | 2 + ...finition-2.good.parsing-no-positions.hopix | 6 + .../70-local-definition-3.bad.expected | 2 + ...efinition-3.bad.parsing-no-positions.hopix | 2 + .../70-local-definition-3.good.expected | 1 + ...finition-3.good.parsing-no-positions.hopix | 3 + .../71-local-definition-4.bad.expected | 2 + ...efinition-4.bad.parsing-no-positions.hopix | 4 + .../71-local-definition-4.good.expected | 1 + ...finition-4.good.parsing-no-positions.hopix | 4 + .../72-local-definition-5.bad.expected | 2 + ...efinition-5.bad.parsing-no-positions.hopix | 5 + .../72-local-definition-5.good.expected | 6 + ...finition-5.good.parsing-no-positions.hopix | 5 + .../73-lambda-1.bad.expected | 2 + ...73-lambda-1.bad.parsing-no-positions.hopix | 1 + .../73-lambda-1.good.expected | 1 + ...3-lambda-1.good.parsing-no-positions.hopix | 1 + .../74-lambda-2.bad.expected | 2 + ...74-lambda-2.bad.parsing-no-positions.hopix | 1 + .../74-lambda-2.good.expected | 1 + ...4-lambda-2.good.parsing-no-positions.hopix | 1 + .../75-lambda-3.bad.expected | 2 + ...75-lambda-3.bad.parsing-no-positions.hopix | 1 + .../75-lambda-3.good.expected | 1 + ...5-lambda-3.good.parsing-no-positions.hopix | 1 + .../76-lambda-4.bad.expected | 2 + ...76-lambda-4.bad.parsing-no-positions.hopix | 1 + .../76-lambda-4.good.expected | 1 + ...6-lambda-4.good.parsing-no-positions.hopix | 1 + .../77-application-1.bad.expected | 2 + ...plication-1.bad.parsing-no-positions.hopix | 1 + .../77-application-1.good.expected | 1 + ...lication-1.good.parsing-no-positions.hopix | 1 + .../78-application-2.bad.expected | 2 + ...plication-2.bad.parsing-no-positions.hopix | 1 + .../78-application-2.good.expected | 1 + ...lication-2.good.parsing-no-positions.hopix | 1 + .../79-application-3.bad.expected | 2 + ...plication-3.bad.parsing-no-positions.hopix | 1 + .../79-application-3.good.expected | 1 + ...lication-3.good.parsing-no-positions.hopix | 1 + .../80-application-4.bad.expected | 2 + ...plication-4.bad.parsing-no-positions.hopix | 1 + .../80-application-4.good.expected | 1 + ...lication-4.good.parsing-no-positions.hopix | 1 + .../81-application-5.bad.expected | 2 + ...plication-5.bad.parsing-no-positions.hopix | 1 + .../81-application-5.good.expected | 1 + ...lication-5.good.parsing-no-positions.hopix | 1 + .../82-application-6.bad.expected | 2 + ...plication-6.bad.parsing-no-positions.hopix | 1 + .../82-application-6.good.expected | 1 + ...lication-6.good.parsing-no-positions.hopix | 1 + .../83-application-7.bad.expected | 2 + ...plication-7.bad.parsing-no-positions.hopix | 1 + .../83-application-7.good.expected | 1 + ...lication-7.good.parsing-no-positions.hopix | 1 + .../84-infix-application-1.bad.expected | 2 + ...plication-1.bad.parsing-no-positions.hopix | 1 + .../84-infix-application-1.good.expected | 1 + ...lication-1.good.parsing-no-positions.hopix | 1 + .../85-infix-application-2.bad.expected | 2 + ...plication-2.bad.parsing-no-positions.hopix | 1 + .../85-infix-application-2.good.expected | 1 + ...lication-2.good.parsing-no-positions.hopix | 1 + .../86-infix-application-3.bad.expected | 2 + ...plication-3.bad.parsing-no-positions.hopix | 2 + .../86-infix-application-3.good.expected | 2 + ...lication-3.good.parsing-no-positions.hopix | 2 + .../87-infix-application-4.bad.expected | 2 + ...plication-4.bad.parsing-no-positions.hopix | 1 + .../87-infix-application-4.good.expected | 2 + ...lication-4.good.parsing-no-positions.hopix | 1 + .../88-case-1.bad.expected | 2 + .../88-case-1.bad.parsing-no-positions.hopix | 7 + .../88-case-1.good.expected | 4 + .../88-case-1.good.parsing-no-positions.hopix | 7 + .../89-case-2.bad.expected | 2 + .../89-case-2.bad.parsing-no-positions.hopix | 4 + .../89-case-2.good.expected | 1 + .../89-case-2.good.parsing-no-positions.hopix | 4 + .../90-case-3.bad.expected | 2 + .../90-case-3.bad.parsing-no-positions.hopix | 7 + .../90-case-3.good.expected | 7 + .../90-case-3.good.parsing-no-positions.hopix | 7 + .../91-case-4.bad.expected | 2 + .../91-case-4.bad.parsing-no-positions.hopix | 4 + .../91-case-4.good.expected | 4 + .../91-case-4.good.parsing-no-positions.hopix | 5 + .../92-case-5.bad.expected | 2 + .../92-case-5.bad.parsing-no-positions.hopix | 5 + .../92-case-5.good.expected | 5 + .../92-case-5.good.parsing-no-positions.hopix | 5 + .../93-case-6.bad.expected | 2 + .../93-case-6.bad.parsing-no-positions.hopix | 5 + .../93-case-6.good.expected | 2 + .../93-case-6.good.parsing-no-positions.hopix | 6 + .../94-case-7.bad.expected | 2 + .../94-case-7.bad.parsing-no-positions.hopix | 4 + .../94-case-7.good.expected | 1 + .../94-case-7.good.parsing-no-positions.hopix | 4 + .../95-case-8.bad.expected | 2 + .../95-case-8.bad.parsing-no-positions.hopix | 2 + .../95-case-8.good.expected | 1 + .../95-case-8.good.parsing-no-positions.hopix | 2 + .../96-if-then-else.bad.expected | 2 + ...f-then-else.bad.parsing-no-positions.hopix | 2 + .../96-if-then-else.good.expected | 1 + ...-then-else.good.parsing-no-positions.hopix | 2 + .../97-if-then-else-2.bad.expected | 2 + ...then-else-2.bad.parsing-no-positions.hopix | 4 + .../97-if-then-else-2.good.expected | 3 + ...hen-else-2.good.parsing-no-positions.hopix | 6 + .../98-if-then-else-3.bad.expected | 2 + ...then-else-3.bad.parsing-no-positions.hopix | 5 + .../98-if-then-else-3.good.expected | 7 + ...hen-else-3.good.parsing-no-positions.hopix | 5 + .../98-if-then-else-4.bad.expected | 2 + ...then-else-4.bad.parsing-no-positions.hopix | 2 + .../98-if-then-else-4.good.expected | 3 + ...hen-else-4.good.parsing-no-positions.hopix | 2 + .../99-ref-1.bad.expected | 2 + .../99-ref-1.bad.parsing-no-positions.hopix | 1 + .../99-ref-1.good.expected | 1 + .../99-ref-1.good.parsing-no-positions.hopix | 1 + .../999-slam.good.expected | 100 +++ .../999-slam.good.parsing-no-positions.hopix | 126 ++++ .../01-constructor-application.bad.expected | 2 + ...-constructor-application.bad.parsing.hopix | 2 + .../01-constructor-application.good.expected | 1 + ...constructor-application.good.parsing.hopix | 2 + flap/tests/01-Parsing/02-app2.bad.expected | 2 + .../01-Parsing/02-app2.bad.parsing.hopix | 1 + flap/tests/01-Parsing/03-app2-2.bad.expected | 2 + .../01-Parsing/03-app2-2.bad.parsing.hopix | 2 + flap/tests/01-Parsing/04-app2-3.bad.expected | 2 + .../01-Parsing/04-app2-3.bad.parsing.hopix | 1 + flap/tests/01-Parsing/05-app3.bad.expected | 2 + .../01-Parsing/05-app3.bad.parsing.hopix | 1 + .../01-Parsing/06-lexer-var-id-1.bad.expected | 2 + .../06-lexer-var-id-1.bad.parsing.hopix | 1 + .../06-lexer-var-id-1.good.expected | 1 + .../06-lexer-var-id-1.good.parsing.hopix | 1 + .../01-Parsing/07-lexer-var-id-2.bad.expected | 2 + .../07-lexer-var-id-2.bad.parsing.hopix | 1 + .../07-lexer-var-id-2.good.expected | 1 + .../07-lexer-var-id-2.good.parsing.hopix | 1 + .../01-Parsing/08-lexer-all-id-1.bad.expected | 2 + .../08-lexer-all-id-1.bad.parsing.hopix | 2 + .../08-lexer-all-id-1.good.expected | 2 + .../08-lexer-all-id-1.good.parsing.hopix | 2 + .../09-lexer-constr-id-1.bad.expected | 1 + .../09-lexer-constr-id-1.bad.parsing.hopix | 1 + .../09-lexer-constr-id-1.good.expected | 1 + .../09-lexer-constr-id-1.good.parsing.hopix | 1 + .../10-lexer-constr-id-2.bad.expected | 2 + .../10-lexer-constr-id-2.bad.parsing.hopix | 1 + .../10-lexer-constr-id-2.good.expected | 1 + .../10-lexer-constr-id-2.good.parsing.hopix | 1 + flap/tests/01-Parsing/100-ref-2.bad.expected | 2 + .../01-Parsing/100-ref-2.bad.parsing.hopix | 1 + flap/tests/01-Parsing/100-ref-2.good.expected | 1 + .../01-Parsing/100-ref-2.good.parsing.hopix | 1 + flap/tests/01-Parsing/101-ref-3.bad.expected | 2 + .../01-Parsing/101-ref-3.bad.parsing.hopix | 3 + flap/tests/01-Parsing/101-ref-3.good.expected | 1 + .../01-Parsing/101-ref-3.good.parsing.hopix | 3 + flap/tests/01-Parsing/102-ref-4.bad.expected | 2 + .../01-Parsing/102-ref-4.bad.parsing.hopix | 2 + flap/tests/01-Parsing/102-ref-4.good.expected | 1 + .../01-Parsing/102-ref-4.good.parsing.hopix | 3 + flap/tests/01-Parsing/103-ref-5.bad.expected | 2 + .../01-Parsing/103-ref-5.bad.parsing.hopix | 3 + flap/tests/01-Parsing/103-ref-5.good.expected | 1 + .../01-Parsing/103-ref-5.good.parsing.hopix | 3 + .../01-Parsing/104-assignment.bad.expected | 2 + .../104-assignment.bad.parsing.hopix | 2 + .../01-Parsing/104-assignment.good.expected | 1 + .../104-assignment.good.parsing.hopix | 2 + .../01-Parsing/105-assignment-2.bad.expected | 2 + .../105-assignment-2.bad.parsing.hopix | 2 + .../01-Parsing/105-assignment-2.good.expected | 1 + .../105-assignment-2.good.parsing.hopix | 2 + .../01-Parsing/106-assignment-3.bad.expected | 2 + .../106-assignment-3.bad.parsing.hopix | 2 + .../01-Parsing/106-assignment-3.good.expected | 1 + .../106-assignment-3.good.parsing.hopix | 2 + .../01-Parsing/107-assignment-4.bad.expected | 2 + .../107-assignment-4.bad.parsing.hopix | 2 + .../01-Parsing/107-assignment-4.good.expected | 1 + .../107-assignment-4.good.parsing.hopix | 2 + .../108-type-ascription-1.bad.expected | 2 + .../108-type-ascription-1.bad.parsing.hopix | 2 + .../108-type-ascription-1.good.expected | 1 + .../108-type-ascription-1.good.parsing.hopix | 2 + .../109-type-ascription-2.bad.expected | 2 + .../109-type-ascription-2.bad.parsing.hopix | 2 + .../109-type-ascription-2.good.expected | 1 + .../109-type-ascription-2.good.parsing.hopix | 2 + .../11-lexer-constr-id-3.bad.expected | 2 + .../11-lexer-constr-id-3.bad.parsing.hopix | 1 + .../11-lexer-constr-id-3.good.expected | 1 + .../11-lexer-constr-id-3.good.parsing.hopix | 1 + .../110-type-ascription-3.bad.expected | 2 + .../110-type-ascription-3.bad.parsing.hopix | 1 + .../110-type-ascription-3.good.expected | 1 + .../110-type-ascription-3.good.parsing.hopix | 1 + .../tests/01-Parsing/111-deref-1.bad.expected | 2 + .../01-Parsing/111-deref-1.bad.parsing.hopix | 2 + .../01-Parsing/111-deref-1.good.expected | 1 + .../01-Parsing/111-deref-1.good.parsing.hopix | 2 + .../tests/01-Parsing/112-deref-2.bad.expected | 2 + .../01-Parsing/112-deref-2.bad.parsing.hopix | 2 + .../01-Parsing/112-deref-2.good.expected | 1 + .../01-Parsing/112-deref-2.good.parsing.hopix | 2 + .../01-Parsing/113-deref-3.good.expected | 1 + .../01-Parsing/113-deref-3.good.parsing.hopix | 1 + .../tests/01-Parsing/114-while-1.bad.expected | 2 + .../01-Parsing/114-while-1.bad.parsing.hopix | 2 + .../01-Parsing/114-while-1.good.expected | 1 + .../01-Parsing/114-while-1.good.parsing.hopix | 2 + .../tests/01-Parsing/115-while-2.bad.expected | 2 + .../01-Parsing/115-while-2.bad.parsing.hopix | 5 + .../01-Parsing/115-while-2.good.expected | 2 + .../01-Parsing/115-while-2.good.parsing.hopix | 6 + flap/tests/01-Parsing/116-for-1.bad.expected | 2 + .../01-Parsing/116-for-1.bad.parsing.hopix | 2 + flap/tests/01-Parsing/116-for-1.good.expected | 1 + .../01-Parsing/116-for-1.good.parsing.hopix | 2 + flap/tests/01-Parsing/117-for-2.bad.expected | 2 + .../01-Parsing/117-for-2.bad.parsing.hopix | 2 + flap/tests/01-Parsing/117-for-2.good.expected | 1 + .../01-Parsing/117-for-2.good.parsing.hopix | 2 + .../01-Parsing/118-do-while-1.bad.expected | 2 + .../118-do-while-1.bad.parsing.hopix | 2 + .../01-Parsing/118-do-while-1.good.expected | 1 + .../118-do-while-1.good.parsing.hopix | 2 + .../01-Parsing/119-do-while-2.bad.expected | 2 + .../119-do-while-2.bad.parsing.hopix | 6 + .../01-Parsing/119-do-while-2.good.expected | 3 + .../119-do-while-2.good.parsing.hopix | 6 + .../12-lexer-label-id-1.bad.expected | 2 + .../12-lexer-label-id-1.bad.parsing.hopix | 1 + .../12-lexer-label-id-1.good.expected | 1 + .../12-lexer-label-id-1.good.parsing.hopix | 1 + .../12-lexer-label-id-2.bad.expected | 2 + .../12-lexer-label-id-2.bad.parsing.hopix | 1 + .../12-lexer-label-id-2.good.expected | 1 + .../12-lexer-label-id-2.good.parsing.hopix | 1 + .../01-Parsing/13-type-con-id-1.bad.expected | 2 + .../13-type-con-id-1.bad.parsing.hopix | 1 + .../01-Parsing/13-type-con-id-1.good.expected | 1 + .../13-type-con-id-1.good.parsing.hopix | 1 + .../01-Parsing/14-type-con-id-2.bad.expected | 2 + .../14-type-con-id-2.bad.parsing.hopix | 1 + .../01-Parsing/14-type-con-id-2.good.expected | 1 + .../14-type-con-id-2.good.parsing.hopix | 1 + .../01-Parsing/15-int-literal-1.bad.expected | 2 + .../15-int-literal-1.bad.parsing.hopix | 1 + .../01-Parsing/15-int-literal-1.good.expected | 1 + .../15-int-literal-1.good.parsing.hopix | 1 + .../01-Parsing/16-int-literal-2.bad.expected | 2 + .../16-int-literal-2.bad.parsing.hopix | 1 + .../01-Parsing/16-int-literal-2.good.expected | 1 + .../16-int-literal-2.good.parsing.hopix | 1 + .../01-Parsing/17-int-literal-3.bad.expected | 2 + .../17-int-literal-3.bad.parsing.hopix | 1 + .../01-Parsing/17-int-literal-3.good.expected | 1 + .../17-int-literal-3.good.parsing.hopix | 1 + .../01-Parsing/18-int-literal-4.bad.expected | 2 + .../18-int-literal-4.bad.parsing.hopix | 1 + .../01-Parsing/18-int-literal-4.good.expected | 1 + .../18-int-literal-4.good.parsing.hopix | 1 + .../01-Parsing/19-int-literal-5.bad.expected | 2 + .../19-int-literal-5.bad.parsing.hopix | 1 + .../01-Parsing/19-int-literal-5.good.expected | 1 + .../19-int-literal-5.good.parsing.hopix | 1 + .../01-Parsing/20-int-literal-6.bad.expected | 2 + .../20-int-literal-6.bad.parsing.hopix | 1 + .../01-Parsing/20-int-literal-6.good.expected | 1 + .../20-int-literal-6.good.parsing.hopix | 1 + .../01-Parsing/21-char-literal-1.bad.expected | 2 + .../21-char-literal-1.bad.parsing.hopix | 1 + .../21-char-literal-1.good.expected | 1 + .../21-char-literal-1.good.parsing.hopix | 1 + .../01-Parsing/22-char-literal-2.bad.expected | 2 + .../22-char-literal-2.bad.parsing.hopix | 1 + .../22-char-literal-2.good.expected | 1 + .../22-char-literal-2.good.parsing.hopix | 1 + .../01-Parsing/23-char-literal-3.bad.expected | 2 + .../23-char-literal-3.bad.parsing.hopix | 1 + .../23-char-literal-3.good.expected | 1 + .../23-char-literal-3.good.parsing.hopix | 1 + .../01-Parsing/24-char-literal-4.bad.expected | 2 + .../24-char-literal-4.bad.parsing.hopix | 1 + .../24-char-literal-4.good.expected | 1 + .../24-char-literal-4.good.parsing.hopix | 1 + .../01-Parsing/25-char-literal-5.bad.expected | 2 + .../25-char-literal-5.bad.parsing.hopix | 1 + .../25-char-literal-5.good.expected | 1 + .../25-char-literal-5.good.parsing.hopix | 1 + .../01-Parsing/26-char-literal-6.bad.expected | 2 + .../26-char-literal-6.bad.parsing.hopix | 1 + .../26-char-literal-6.good.expected | 2 + .../26-char-literal-6.good.parsing.hopix | 2 + .../27-string-literal-1.bad.expected | 2 + .../27-string-literal-1.bad.parsing.hopix | 1 + .../27-string-literal-1.good.expected | 2 + .../27-string-literal-1.good.parsing.hopix | 1 + .../28-string-literal-2.bad.expected | 2 + .../28-string-literal-2.bad.parsing.hopix | 1 + .../28-string-literal-2.good.expected | 2 + .../28-string-literal-2.good.parsing.hopix | 1 + .../29-string-literal-3.bad.expected | 2 + .../29-string-literal-3.bad.parsing.hopix | 1 + .../29-string-literal-3.good.expected | 1 + .../29-string-literal-3.good.parsing.hopix | 1 + .../30-string-literal-4.bad.expected | 2 + .../30-string-literal-4.bad.parsing.hopix | 1 + .../30-string-literal-4.good.expected | 1 + .../30-string-literal-4.good.parsing.hopix | 1 + .../31-type-definition-sum-1.bad.expected | 2 + ...31-type-definition-sum-1.bad.parsing.hopix | 1 + .../31-type-definition-sum-1.good.expected | 1 + ...1-type-definition-sum-1.good.parsing.hopix | 1 + .../32-type-definition-sum-2.bad.expected | 2 + ...32-type-definition-sum-2.bad.parsing.hopix | 1 + .../32-type-definition-sum-2.good.expected | 1 + ...2-type-definition-sum-2.good.parsing.hopix | 1 + .../33-type-definition-sum-3.bad.expected | 2 + ...33-type-definition-sum-3.bad.parsing.hopix | 1 + .../33-type-definition-sum-3.good.expected | 1 + ...3-type-definition-sum-3.good.parsing.hopix | 1 + .../34-type-definition-sum-4.bad.expected | 2 + ...34-type-definition-sum-4.bad.parsing.hopix | 1 + .../34-type-definition-sum-4.good.expected | 1 + ...4-type-definition-sum-4.good.parsing.hopix | 1 + .../35-type-definition-sum-5.bad.expected | 2 + ...35-type-definition-sum-5.bad.parsing.hopix | 1 + .../35-type-definition-sum-5.good.expected | 1 + ...5-type-definition-sum-5.good.parsing.hopix | 1 + .../36-type-definition-sum-6.bad.expected | 2 + ...36-type-definition-sum-6.bad.parsing.hopix | 1 + .../36-type-definition-sum-6.good.expected | 1 + ...6-type-definition-sum-6.good.parsing.hopix | 1 + .../37-type-definition-sum-7.bad.expected | 2 + ...37-type-definition-sum-7.bad.parsing.hopix | 1 + .../37-type-definition-sum-7.good.expected | 3 + ...7-type-definition-sum-7.good.parsing.hopix | 1 + .../38-type-definition-record-1.bad.expected | 2 + ...type-definition-record-1.bad.parsing.hopix | 1 + .../38-type-definition-record-1.good.expected | 3 + ...ype-definition-record-1.good.parsing.hopix | 1 + .../39-type-definition-record-2.bad.expected | 2 + ...type-definition-record-2.bad.parsing.hopix | 2 + .../39-type-definition-record-2.good.expected | 6 + ...ype-definition-record-2.good.parsing.hopix | 2 + .../40-type-definition-record-3.bad.expected | 2 + ...type-definition-record-3.bad.parsing.hopix | 8 + .../40-type-definition-record-3.good.expected | 10 + ...ype-definition-record-3.good.parsing.hopix | 8 + .../41-external-definition-1.bad.expected | 2 + ...41-external-definition-1.bad.parsing.hopix | 1 + .../41-external-definition-1.good.expected | 1 + ...1-external-definition-1.good.parsing.hopix | 1 + .../42-external-definition-2.good.expected | 1 + ...2-external-definition-2.good.parsing.hopix | 1 + .../43-external-definition-3.bad.expected | 1 + ...43-external-definition-3.bad.parsing.hopix | 1 + .../43-external-definition-3.good.expected | 1 + ...3-external-definition-3.good.parsing.hopix | 1 + .../44-value-definition-1.bad.expected | 2 + .../44-value-definition-1.bad.parsing.hopix | 1 + .../44-value-definition-1.good.expected | 1 + .../44-value-definition-1.good.parsing.hopix | 1 + .../45-value-definition-2.bad.expected | 2 + .../45-value-definition-2.bad.parsing.hopix | 1 + .../45-value-definition-2.good.expected | 1 + .../45-value-definition-2.good.parsing.hopix | 1 + .../46-value-definition-3.bad.expected | 2 + .../46-value-definition-3.bad.parsing.hopix | 1 + .../46-value-definition-3.good.expected | 1 + .../46-value-definition-3.good.parsing.hopix | 1 + .../01-Parsing/47-instanciation.bad.expected | 1 + .../47-instanciation.bad.parsing.hopix | 1 + .../01-Parsing/47-instanciation.good.expected | 1 + .../47-instanciation.good.parsing.hopix | 1 + .../48-instanciation-2.bad.expected | 2 + .../48-instanciation-2.bad.parsing.hopix | 1 + .../48-instanciation-2.good.expected | 1 + .../48-instanciation-2.good.parsing.hopix | 1 + .../49-instanciation-3.bad.expected | 2 + .../49-instanciation-3.bad.parsing.hopix | 1 + .../49-instanciation-3.good.expected | 1 + .../49-instanciation-3.good.parsing.hopix | 1 + .../50-instanciation-4.bad.expected | 2 + .../50-instanciation-4.bad.parsing.hopix | 1 + .../50-instanciation-4.good.expected | 1 + .../50-instanciation-4.good.parsing.hopix | 1 + .../51-instanciation-5.bad.expected | 2 + .../51-instanciation-5.bad.parsing.hopix | 1 + .../51-instanciation-5.good.expected | 1 + .../51-instanciation-5.good.parsing.hopix | 1 + .../52-instanciation-6.bad.expected | 2 + .../52-instanciation-6.bad.parsing.hopix | 1 + .../52-instanciation-6.good.expected | 1 + .../52-instanciation-6.good.parsing.hopix | 1 + .../53-instanciation-7.bad.expected | 2 + .../53-instanciation-7.bad.parsing.hopix | 1 + .../53-instanciation-7.good.expected | 1 + .../53-instanciation-7.good.parsing.hopix | 1 + .../01-Parsing/54-constructor-1.bad.expected | 2 + .../54-constructor-1.bad.parsing.hopix | 1 + .../01-Parsing/54-constructor-1.good.expected | 1 + .../54-constructor-1.good.parsing.hopix | 1 + .../01-Parsing/55-constructor-2.bad.expected | 1 + .../55-constructor-2.bad.parsing.hopix | 1 + .../01-Parsing/55-constructor-2.good.expected | 1 + .../55-constructor-2.good.parsing.hopix | 1 + .../01-Parsing/56-constructor-3.bad.expected | 2 + .../56-constructor-3.bad.parsing.hopix | 1 + .../01-Parsing/56-constructor-3.good.expected | 6 + .../56-constructor-3.good.parsing.hopix | 1 + .../01-Parsing/57-constructor-4.bad.expected | 2 + .../57-constructor-4.bad.parsing.hopix | 1 + .../01-Parsing/57-constructor-4.good.expected | 1 + .../57-constructor-4.good.parsing.hopix | 1 + .../tests/01-Parsing/58-record-1.bad.expected | 2 + .../01-Parsing/58-record-1.bad.parsing.hopix | 1 + .../01-Parsing/58-record-1.good.expected | 1 + .../01-Parsing/58-record-1.good.parsing.hopix | 1 + .../tests/01-Parsing/59-record-2.bad.expected | 2 + .../01-Parsing/59-record-2.bad.parsing.hopix | 1 + .../01-Parsing/59-record-2.good.expected | 1 + .../01-Parsing/59-record-2.good.parsing.hopix | 1 + .../tests/01-Parsing/60-record-3.bad.expected | 2 + .../01-Parsing/60-record-3.bad.parsing.hopix | 1 + .../01-Parsing/60-record-3.good.expected | 1 + .../01-Parsing/60-record-3.good.parsing.hopix | 1 + .../61-record-projection-1.bad.expected | 2 + .../61-record-projection-1.bad.parsing.hopix | 1 + .../61-record-projection-1.good.expected | 1 + .../61-record-projection-1.good.parsing.hopix | 1 + .../62-record-projection-2.bad.expected | 2 + .../62-record-projection-2.bad.parsing.hopix | 1 + .../62-record-projection-2.good.expected | 1 + .../62-record-projection-2.good.parsing.hopix | 1 + .../63-record-projection-3.bad.expected | 2 + .../63-record-projection-3.bad.parsing.hopix | 1 + .../63-record-projection-3.good.expected | 1 + .../63-record-projection-3.good.parsing.hopix | 1 + .../01-Parsing/65-sequence-1.bad.expected | 2 + .../65-sequence-1.bad.parsing.hopix | 1 + .../01-Parsing/65-sequence-1.good.expected | 1 + .../65-sequence-1.good.parsing.hopix | 1 + .../01-Parsing/66-sequence-2.bad.expected | 2 + .../66-sequence-2.bad.parsing.hopix | 1 + .../01-Parsing/66-sequence-2.good.expected | 1 + .../66-sequence-2.good.parsing.hopix | 1 + .../01-Parsing/67-sequence-3.bad.expected | 2 + .../67-sequence-3.bad.parsing.hopix | 1 + .../01-Parsing/67-sequence-3.good.expected | 1 + .../67-sequence-3.good.parsing.hopix | 1 + .../68-local-definition.bad.expected | 2 + .../68-local-definition.bad.parsing.hopix | 3 + .../68-local-definition.good.expected | 1 + .../68-local-definition.good.parsing.hopix | 3 + .../69-local-definition-2.bad.expected | 2 + .../69-local-definition-2.bad.parsing.hopix | 6 + .../69-local-definition-2.good.expected | 2 + .../69-local-definition-2.good.parsing.hopix | 6 + .../70-local-definition-3.bad.expected | 2 + .../70-local-definition-3.bad.parsing.hopix | 2 + .../70-local-definition-3.good.expected | 1 + .../70-local-definition-3.good.parsing.hopix | 3 + .../71-local-definition-4.bad.expected | 2 + .../71-local-definition-4.bad.parsing.hopix | 4 + .../71-local-definition-4.good.expected | 1 + .../71-local-definition-4.good.parsing.hopix | 4 + .../72-local-definition-5.bad.expected | 2 + .../72-local-definition-5.bad.parsing.hopix | 5 + .../72-local-definition-5.good.expected | 6 + .../72-local-definition-5.good.parsing.hopix | 5 + .../tests/01-Parsing/73-lambda-1.bad.expected | 2 + .../01-Parsing/73-lambda-1.bad.parsing.hopix | 1 + .../01-Parsing/73-lambda-1.good.expected | 1 + .../01-Parsing/73-lambda-1.good.parsing.hopix | 1 + .../tests/01-Parsing/74-lambda-2.bad.expected | 2 + .../01-Parsing/74-lambda-2.bad.parsing.hopix | 1 + .../01-Parsing/74-lambda-2.good.expected | 1 + .../01-Parsing/74-lambda-2.good.parsing.hopix | 1 + .../tests/01-Parsing/75-lambda-3.bad.expected | 2 + .../01-Parsing/75-lambda-3.bad.parsing.hopix | 1 + .../01-Parsing/75-lambda-3.good.expected | 1 + .../01-Parsing/75-lambda-3.good.parsing.hopix | 1 + .../tests/01-Parsing/76-lambda-4.bad.expected | 2 + .../01-Parsing/76-lambda-4.bad.parsing.hopix | 1 + .../01-Parsing/76-lambda-4.good.expected | 1 + .../01-Parsing/76-lambda-4.good.parsing.hopix | 1 + .../01-Parsing/77-application-1.bad.expected | 2 + .../77-application-1.bad.parsing.hopix | 1 + .../01-Parsing/77-application-1.good.expected | 1 + .../77-application-1.good.parsing.hopix | 1 + .../01-Parsing/78-application-2.bad.expected | 2 + .../78-application-2.bad.parsing.hopix | 1 + .../01-Parsing/78-application-2.good.expected | 1 + .../78-application-2.good.parsing.hopix | 1 + .../01-Parsing/79-application-3.bad.expected | 2 + .../79-application-3.bad.parsing.hopix | 1 + .../01-Parsing/79-application-3.good.expected | 1 + .../79-application-3.good.parsing.hopix | 1 + .../01-Parsing/80-application-4.bad.expected | 2 + .../80-application-4.bad.parsing.hopix | 1 + .../01-Parsing/80-application-4.good.expected | 1 + .../80-application-4.good.parsing.hopix | 1 + .../01-Parsing/81-application-5.bad.expected | 2 + .../81-application-5.bad.parsing.hopix | 1 + .../01-Parsing/81-application-5.good.expected | 1 + .../81-application-5.good.parsing.hopix | 1 + .../01-Parsing/82-application-6.bad.expected | 2 + .../82-application-6.bad.parsing.hopix | 1 + .../01-Parsing/82-application-6.good.expected | 1 + .../82-application-6.good.parsing.hopix | 1 + .../01-Parsing/83-application-7.bad.expected | 2 + .../83-application-7.bad.parsing.hopix | 1 + .../01-Parsing/83-application-7.good.expected | 1 + .../83-application-7.good.parsing.hopix | 1 + .../84-infix-application-1.bad.expected | 2 + .../84-infix-application-1.bad.parsing.hopix | 1 + .../84-infix-application-1.good.expected | 1 + .../84-infix-application-1.good.parsing.hopix | 1 + .../85-infix-application-2.bad.expected | 2 + .../85-infix-application-2.bad.parsing.hopix | 1 + .../85-infix-application-2.good.expected | 1 + .../85-infix-application-2.good.parsing.hopix | 1 + .../86-infix-application-3.bad.expected | 2 + .../86-infix-application-3.bad.parsing.hopix | 2 + .../86-infix-application-3.good.expected | 2 + .../86-infix-application-3.good.parsing.hopix | 2 + .../87-infix-application-4.bad.expected | 2 + .../87-infix-application-4.bad.parsing.hopix | 1 + .../87-infix-application-4.good.expected | 2 + .../87-infix-application-4.good.parsing.hopix | 1 + flap/tests/01-Parsing/88-case-1.bad.expected | 2 + .../01-Parsing/88-case-1.bad.parsing.hopix | 7 + flap/tests/01-Parsing/88-case-1.good.expected | 4 + .../01-Parsing/88-case-1.good.parsing.hopix | 7 + flap/tests/01-Parsing/89-case-2.bad.expected | 2 + .../01-Parsing/89-case-2.bad.parsing.hopix | 4 + flap/tests/01-Parsing/89-case-2.good.expected | 1 + .../01-Parsing/89-case-2.good.parsing.hopix | 4 + flap/tests/01-Parsing/90-case-3.bad.expected | 2 + .../01-Parsing/90-case-3.bad.parsing.hopix | 7 + flap/tests/01-Parsing/90-case-3.good.expected | 7 + .../01-Parsing/90-case-3.good.parsing.hopix | 7 + flap/tests/01-Parsing/91-case-4.bad.expected | 2 + .../01-Parsing/91-case-4.bad.parsing.hopix | 4 + flap/tests/01-Parsing/91-case-4.good.expected | 4 + .../01-Parsing/91-case-4.good.parsing.hopix | 5 + flap/tests/01-Parsing/92-case-5.bad.expected | 2 + .../01-Parsing/92-case-5.bad.parsing.hopix | 5 + flap/tests/01-Parsing/92-case-5.good.expected | 5 + .../01-Parsing/92-case-5.good.parsing.hopix | 5 + flap/tests/01-Parsing/93-case-6.bad.expected | 2 + .../01-Parsing/93-case-6.bad.parsing.hopix | 5 + flap/tests/01-Parsing/93-case-6.good.expected | 2 + .../01-Parsing/93-case-6.good.parsing.hopix | 6 + flap/tests/01-Parsing/94-case-7.bad.expected | 2 + .../01-Parsing/94-case-7.bad.parsing.hopix | 4 + flap/tests/01-Parsing/94-case-7.good.expected | 1 + .../01-Parsing/94-case-7.good.parsing.hopix | 4 + flap/tests/01-Parsing/95-case-8.bad.expected | 2 + .../01-Parsing/95-case-8.bad.parsing.hopix | 2 + flap/tests/01-Parsing/95-case-8.good.expected | 1 + .../01-Parsing/95-case-8.good.parsing.hopix | 2 + .../01-Parsing/96-if-then-else.bad.expected | 2 + .../96-if-then-else.bad.parsing.hopix | 2 + .../01-Parsing/96-if-then-else.good.expected | 1 + .../96-if-then-else.good.parsing.hopix | 2 + .../01-Parsing/97-if-then-else-2.bad.expected | 2 + .../97-if-then-else-2.bad.parsing.hopix | 4 + .../97-if-then-else-2.good.expected | 3 + .../97-if-then-else-2.good.parsing.hopix | 6 + .../01-Parsing/98-if-then-else-3.bad.expected | 2 + .../98-if-then-else-3.bad.parsing.hopix | 5 + .../98-if-then-else-3.good.expected | 7 + .../98-if-then-else-3.good.parsing.hopix | 5 + .../01-Parsing/98-if-then-else-4.bad.expected | 2 + .../98-if-then-else-4.bad.parsing.hopix | 2 + .../98-if-then-else-4.good.expected | 3 + .../98-if-then-else-4.good.parsing.hopix | 2 + flap/tests/01-Parsing/99-ref-1.bad.expected | 2 + .../01-Parsing/99-ref-1.bad.parsing.hopix | 1 + flap/tests/01-Parsing/99-ref-1.good.expected | 1 + .../01-Parsing/99-ref-1.good.parsing.hopix | 1 + flap/tests/01-Parsing/999-slam.good.expected | 100 +++ .../01-Parsing/999-slam.good.parsing.hopix | 126 ++++ flap/tests/Makefile | 67 ++ flap/tests/README.md | 11 + jalons/jalon-1.pdf | Bin 0 -> 448492 bytes 1050 files changed, 13913 insertions(+) create mode 100644 flap/AUTEURS create mode 100644 flap/README.md create mode 100644 flap/dune-project create mode 100644 flap/runtime/runtime.c create mode 100644 flap/src/commandLineOptions.ml create mode 100644 flap/src/common/architecture.mli create mode 100644 flap/src/common/compilers.ml create mode 100644 flap/src/common/compilers.mli create mode 100644 flap/src/common/languages.ml create mode 100644 flap/src/common/languages.mli create mode 100644 flap/src/common/memory.ml create mode 100644 flap/src/common/memory.mli create mode 100644 flap/src/common/mint.ml create mode 100644 flap/src/common/mint.mli create mode 100644 flap/src/common/optimizers.ml create mode 100644 flap/src/common/syntacticAnalysis.ml create mode 100644 flap/src/common/syntacticAnalysis.mli create mode 100644 flap/src/dune create mode 100644 flap/src/elf/elf.ml create mode 100644 flap/src/elf/elfAST.ml create mode 100644 flap/src/elf/elfInitialization.ml create mode 100644 flap/src/elf/elfInterpreter.ml create mode 100644 flap/src/elf/elfTypechecker.ml create mode 100644 flap/src/elf/x86_64toElf.ml create mode 100644 flap/src/flap.ml create mode 100644 flap/src/fopix/fopix.ml create mode 100644 flap/src/fopix/fopixAST.ml create mode 100644 flap/src/fopix/fopixInitialization.ml create mode 100644 flap/src/fopix/fopixInterpreter.ml create mode 100644 flap/src/fopix/fopixLexer.mll create mode 100644 flap/src/fopix/fopixParser.mly create mode 100644 flap/src/fopix/fopixPrettyPrinter.ml create mode 100644 flap/src/fopix/fopixTypechecker.ml create mode 100644 flap/src/fopix/hobixToFopix.ml create mode 100644 flap/src/hobix/HobixParser.mly create mode 100644 flap/src/hobix/hobix.ml create mode 100644 flap/src/hobix/hobixAST.ml create mode 100644 flap/src/hobix/hobixInitialization.ml create mode 100644 flap/src/hobix/hobixInterpreter.ml create mode 100644 flap/src/hobix/hobixLexer.mll create mode 100644 flap/src/hobix/hobixParser.mly create mode 100644 flap/src/hobix/hobixPrettyPrinter.ml create mode 100644 flap/src/hobix/hobixTypechecker.ml create mode 100644 flap/src/hobix/hobixTypes.ml create mode 100644 flap/src/hobix/hopixToHobix.ml create mode 100644 flap/src/hobix/patternMatchingCompiler.ml create mode 100644 flap/src/hopix/hopix.ml create mode 100644 flap/src/hopix/hopixAST.ml create mode 100644 flap/src/hopix/hopixASTHelper.ml create mode 100644 flap/src/hopix/hopixInitialization.ml create mode 100644 flap/src/hopix/hopixInterpreter.ml create mode 100644 flap/src/hopix/hopixLexer.mll create mode 100644 flap/src/hopix/hopixParser.mly create mode 100644 flap/src/hopix/hopixPrettyPrinter.ml create mode 100644 flap/src/hopix/hopixSyntacticSugar.mli create mode 100644 flap/src/hopix/hopixTypechecker.ml create mode 100644 flap/src/hopix/hopixTypes.ml create mode 100644 flap/src/hopix/hopixTypes.mli create mode 100644 flap/src/options.ml create mode 100644 flap/src/retrolix/fopixToRetrolix.ml create mode 100644 flap/src/retrolix/retrolix.ml create mode 100644 flap/src/retrolix/retrolixAST.ml create mode 100644 flap/src/retrolix/retrolixConstantFolding.ml create mode 100644 flap/src/retrolix/retrolixDataflowEngines.ml create mode 100644 flap/src/retrolix/retrolixDataflowSigs.ml create mode 100644 flap/src/retrolix/retrolixDataflowUtils.ml create mode 100644 flap/src/retrolix/retrolixDeadCodeElimination.ml create mode 100644 flap/src/retrolix/retrolixInitialization.ml create mode 100644 flap/src/retrolix/retrolixInterferenceGraph.ml create mode 100644 flap/src/retrolix/retrolixInterpreter.ml create mode 100644 flap/src/retrolix/retrolixKillMove.ml create mode 100644 flap/src/retrolix/retrolixLexer.mll create mode 100644 flap/src/retrolix/retrolixLivenessAnalysis.ml create mode 100644 flap/src/retrolix/retrolixParser.mly create mode 100644 flap/src/retrolix/retrolixPrettyPrinter.ml create mode 100644 flap/src/retrolix/retrolixRegisterAllocation.ml create mode 100644 flap/src/retrolix/retrolixTypechecker.ml create mode 100644 flap/src/retrolix/retrolixUtils.ml create mode 100644 flap/src/utilities/dict.ml create mode 100644 flap/src/utilities/dict.mli create mode 100644 flap/src/utilities/digraph.ml create mode 100644 flap/src/utilities/digraph.mli create mode 100644 flap/src/utilities/error.ml create mode 100644 flap/src/utilities/error.mli create mode 100644 flap/src/utilities/extPPrint.ml create mode 100644 flap/src/utilities/extStd.ml create mode 100644 flap/src/utilities/graph.ml create mode 100644 flap/src/utilities/graph.mli create mode 100644 flap/src/utilities/int16.ml create mode 100644 flap/src/utilities/int16.mli create mode 100644 flap/src/utilities/list.ml create mode 100644 flap/src/utilities/listMonad.ml create mode 100644 flap/src/utilities/listMonad.mli create mode 100644 flap/src/utilities/option.ml create mode 100644 flap/src/utilities/position.ml create mode 100644 flap/src/utilities/position.mli create mode 100644 flap/src/utilities/stdUserInput.ml create mode 100644 flap/src/utilities/userInput.ml create mode 100644 flap/src/version.ml create mode 100644 flap/src/x86-64/retrolixToX86_64.ml create mode 100644 flap/src/x86-64/x86_64.ml create mode 100644 flap/src/x86-64/x86_64_AST.ml create mode 100644 flap/src/x86-64/x86_64_Architecture.ml create mode 100644 flap/src/x86-64/x86_64_Initialization.ml create mode 100644 flap/src/x86-64/x86_64_Interpreter.ml create mode 100644 flap/src/x86-64/x86_64_PrettyPrinter.ml create mode 100644 flap/src/x86-64/x86_64_Typechecker.ml create mode 100644 flap/tests/01-Parsing-no-positions/01-constructor-application.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/01-constructor-application.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/01-constructor-application.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/01-constructor-application.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/02-app2.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/02-app2.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/03-app2-2.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/03-app2-2.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/04-app2-3.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/04-app2-3.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/05-app3.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/05-app3.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/06-lexer-var-id-1.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/06-lexer-var-id-1.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/06-lexer-var-id-1.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/06-lexer-var-id-1.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/07-lexer-var-id-2.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/07-lexer-var-id-2.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/07-lexer-var-id-2.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/07-lexer-var-id-2.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/08-lexer-all-id-1.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/08-lexer-all-id-1.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/08-lexer-all-id-1.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/08-lexer-all-id-1.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/09-lexer-constr-id-1.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/09-lexer-constr-id-1.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/09-lexer-constr-id-1.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/09-lexer-constr-id-1.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/10-lexer-constr-id-2.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/10-lexer-constr-id-2.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/10-lexer-constr-id-2.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/10-lexer-constr-id-2.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/100-ref-2.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/100-ref-2.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/100-ref-2.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/100-ref-2.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/101-ref-3.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/101-ref-3.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/101-ref-3.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/101-ref-3.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/102-ref-4.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/102-ref-4.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/102-ref-4.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/102-ref-4.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/103-ref-5.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/103-ref-5.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/103-ref-5.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/103-ref-5.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/104-assignment.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/104-assignment.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/104-assignment.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/104-assignment.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/105-assignment-2.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/105-assignment-2.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/105-assignment-2.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/105-assignment-2.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/106-assignment-3.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/106-assignment-3.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/106-assignment-3.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/106-assignment-3.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/107-assignment-4.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/107-assignment-4.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/107-assignment-4.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/107-assignment-4.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/108-type-ascription-1.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/108-type-ascription-1.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/108-type-ascription-1.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/108-type-ascription-1.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/109-type-ascription-2.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/109-type-ascription-2.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/109-type-ascription-2.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/109-type-ascription-2.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/11-lexer-constr-id-3.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/11-lexer-constr-id-3.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/11-lexer-constr-id-3.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/11-lexer-constr-id-3.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/110-type-ascription-3.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/110-type-ascription-3.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/110-type-ascription-3.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/110-type-ascription-3.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/111-deref-1.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/111-deref-1.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/111-deref-1.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/111-deref-1.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/112-deref-2.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/112-deref-2.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/112-deref-2.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/112-deref-2.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/113-deref-3.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/113-deref-3.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/114-while-1.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/114-while-1.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/114-while-1.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/114-while-1.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/115-while-2.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/115-while-2.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/115-while-2.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/115-while-2.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/116-for-1.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/116-for-1.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/116-for-1.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/116-for-1.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/117-for-2.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/117-for-2.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/117-for-2.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/117-for-2.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/118-do-while-1.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/118-do-while-1.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/118-do-while-1.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/118-do-while-1.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/119-do-while-2.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/119-do-while-2.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/119-do-while-2.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/119-do-while-2.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/12-lexer-label-id-1.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/12-lexer-label-id-1.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/12-lexer-label-id-1.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/12-lexer-label-id-1.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/12-lexer-label-id-2.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/12-lexer-label-id-2.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/12-lexer-label-id-2.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/12-lexer-label-id-2.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/13-type-con-id-1.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/13-type-con-id-1.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/13-type-con-id-1.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/13-type-con-id-1.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/14-type-con-id-2.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/14-type-con-id-2.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/14-type-con-id-2.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/14-type-con-id-2.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/15-int-literal-1.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/15-int-literal-1.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/15-int-literal-1.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/15-int-literal-1.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/16-int-literal-2.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/16-int-literal-2.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/16-int-literal-2.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/16-int-literal-2.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/17-int-literal-3.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/17-int-literal-3.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/17-int-literal-3.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/17-int-literal-3.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/18-int-literal-4.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/18-int-literal-4.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/18-int-literal-4.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/18-int-literal-4.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/19-int-literal-5.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/19-int-literal-5.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/19-int-literal-5.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/19-int-literal-5.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/20-int-literal-6.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/20-int-literal-6.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/20-int-literal-6.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/20-int-literal-6.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/21-char-literal-1.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/21-char-literal-1.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/21-char-literal-1.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/21-char-literal-1.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/22-char-literal-2.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/22-char-literal-2.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/22-char-literal-2.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/22-char-literal-2.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/23-char-literal-3.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/23-char-literal-3.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/23-char-literal-3.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/23-char-literal-3.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/24-char-literal-4.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/24-char-literal-4.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/24-char-literal-4.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/24-char-literal-4.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/25-char-literal-5.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/25-char-literal-5.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/25-char-literal-5.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/25-char-literal-5.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/26-char-literal-6.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/26-char-literal-6.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/26-char-literal-6.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/26-char-literal-6.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/27-string-literal-1.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/27-string-literal-1.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/27-string-literal-1.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/27-string-literal-1.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/28-string-literal-2.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/28-string-literal-2.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/28-string-literal-2.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/28-string-literal-2.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/29-string-literal-3.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/29-string-literal-3.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/29-string-literal-3.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/29-string-literal-3.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/30-string-literal-4.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/30-string-literal-4.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/30-string-literal-4.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/30-string-literal-4.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/31-type-definition-sum-1.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/31-type-definition-sum-1.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/31-type-definition-sum-1.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/31-type-definition-sum-1.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/32-type-definition-sum-2.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/32-type-definition-sum-2.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/32-type-definition-sum-2.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/32-type-definition-sum-2.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/33-type-definition-sum-3.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/33-type-definition-sum-3.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/33-type-definition-sum-3.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/33-type-definition-sum-3.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/34-type-definition-sum-4.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/34-type-definition-sum-4.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/34-type-definition-sum-4.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/34-type-definition-sum-4.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/35-type-definition-sum-5.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/35-type-definition-sum-5.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/35-type-definition-sum-5.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/35-type-definition-sum-5.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/36-type-definition-sum-6.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/36-type-definition-sum-6.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/36-type-definition-sum-6.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/36-type-definition-sum-6.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/37-type-definition-sum-7.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/37-type-definition-sum-7.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/37-type-definition-sum-7.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/37-type-definition-sum-7.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/38-type-definition-record-1.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/38-type-definition-record-1.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/38-type-definition-record-1.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/38-type-definition-record-1.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/39-type-definition-record-2.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/39-type-definition-record-2.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/39-type-definition-record-2.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/39-type-definition-record-2.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/40-type-definition-record-3.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/40-type-definition-record-3.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/40-type-definition-record-3.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/40-type-definition-record-3.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/41-external-definition-1.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/41-external-definition-1.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/41-external-definition-1.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/41-external-definition-1.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/42-external-definition-2.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/42-external-definition-2.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/43-external-definition-3.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/43-external-definition-3.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/43-external-definition-3.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/43-external-definition-3.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/44-value-definition-1.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/44-value-definition-1.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/44-value-definition-1.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/44-value-definition-1.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/45-value-definition-2.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/45-value-definition-2.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/45-value-definition-2.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/45-value-definition-2.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/46-value-definition-3.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/46-value-definition-3.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/46-value-definition-3.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/46-value-definition-3.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/47-instanciation.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/47-instanciation.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/47-instanciation.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/47-instanciation.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/48-instanciation-2.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/48-instanciation-2.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/48-instanciation-2.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/48-instanciation-2.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/49-instanciation-3.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/49-instanciation-3.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/49-instanciation-3.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/49-instanciation-3.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/50-instanciation-4.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/50-instanciation-4.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/50-instanciation-4.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/50-instanciation-4.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/51-instanciation-5.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/51-instanciation-5.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/51-instanciation-5.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/51-instanciation-5.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/52-instanciation-6.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/52-instanciation-6.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/52-instanciation-6.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/52-instanciation-6.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/53-instanciation-7.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/53-instanciation-7.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/53-instanciation-7.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/53-instanciation-7.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/54-constructor-1.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/54-constructor-1.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/54-constructor-1.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/54-constructor-1.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/55-constructor-2.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/55-constructor-2.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/55-constructor-2.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/55-constructor-2.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/56-constructor-3.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/56-constructor-3.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/56-constructor-3.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/56-constructor-3.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/57-constructor-4.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/57-constructor-4.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/57-constructor-4.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/57-constructor-4.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/58-record-1.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/58-record-1.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/58-record-1.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/58-record-1.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/59-record-2.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/59-record-2.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/59-record-2.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/59-record-2.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/60-record-3.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/60-record-3.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/60-record-3.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/60-record-3.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/61-record-projection-1.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/61-record-projection-1.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/61-record-projection-1.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/61-record-projection-1.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/62-record-projection-2.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/62-record-projection-2.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/62-record-projection-2.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/62-record-projection-2.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/63-record-projection-3.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/63-record-projection-3.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/63-record-projection-3.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/63-record-projection-3.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/65-sequence-1.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/65-sequence-1.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/65-sequence-1.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/65-sequence-1.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/66-sequence-2.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/66-sequence-2.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/66-sequence-2.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/66-sequence-2.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/67-sequence-3.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/67-sequence-3.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/67-sequence-3.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/67-sequence-3.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/68-local-definition.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/68-local-definition.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/68-local-definition.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/68-local-definition.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/69-local-definition-2.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/69-local-definition-2.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/69-local-definition-2.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/69-local-definition-2.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/70-local-definition-3.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/70-local-definition-3.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/70-local-definition-3.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/70-local-definition-3.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/71-local-definition-4.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/71-local-definition-4.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/71-local-definition-4.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/71-local-definition-4.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/72-local-definition-5.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/72-local-definition-5.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/72-local-definition-5.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/72-local-definition-5.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/73-lambda-1.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/73-lambda-1.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/73-lambda-1.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/73-lambda-1.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/74-lambda-2.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/74-lambda-2.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/74-lambda-2.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/74-lambda-2.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/75-lambda-3.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/75-lambda-3.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/75-lambda-3.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/75-lambda-3.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/76-lambda-4.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/76-lambda-4.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/76-lambda-4.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/76-lambda-4.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/77-application-1.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/77-application-1.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/77-application-1.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/77-application-1.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/78-application-2.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/78-application-2.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/78-application-2.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/78-application-2.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/79-application-3.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/79-application-3.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/79-application-3.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/79-application-3.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/80-application-4.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/80-application-4.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/80-application-4.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/80-application-4.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/81-application-5.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/81-application-5.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/81-application-5.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/81-application-5.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/82-application-6.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/82-application-6.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/82-application-6.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/82-application-6.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/83-application-7.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/83-application-7.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/83-application-7.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/83-application-7.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/84-infix-application-1.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/84-infix-application-1.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/84-infix-application-1.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/84-infix-application-1.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/85-infix-application-2.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/85-infix-application-2.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/85-infix-application-2.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/85-infix-application-2.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/86-infix-application-3.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/86-infix-application-3.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/86-infix-application-3.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/86-infix-application-3.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/87-infix-application-4.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/87-infix-application-4.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/87-infix-application-4.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/87-infix-application-4.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/88-case-1.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/88-case-1.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/88-case-1.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/88-case-1.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/89-case-2.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/89-case-2.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/89-case-2.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/89-case-2.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/90-case-3.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/90-case-3.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/90-case-3.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/90-case-3.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/91-case-4.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/91-case-4.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/91-case-4.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/91-case-4.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/92-case-5.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/92-case-5.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/92-case-5.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/92-case-5.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/93-case-6.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/93-case-6.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/93-case-6.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/93-case-6.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/94-case-7.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/94-case-7.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/94-case-7.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/94-case-7.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/95-case-8.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/95-case-8.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/95-case-8.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/95-case-8.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/96-if-then-else.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/96-if-then-else.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/96-if-then-else.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/96-if-then-else.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/97-if-then-else-2.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/97-if-then-else-2.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/97-if-then-else-2.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/97-if-then-else-2.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/98-if-then-else-3.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/98-if-then-else-3.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/98-if-then-else-3.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/98-if-then-else-3.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/98-if-then-else-4.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/98-if-then-else-4.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/98-if-then-else-4.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/98-if-then-else-4.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/99-ref-1.bad.expected create mode 100644 flap/tests/01-Parsing-no-positions/99-ref-1.bad.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/99-ref-1.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/99-ref-1.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing-no-positions/999-slam.good.expected create mode 100644 flap/tests/01-Parsing-no-positions/999-slam.good.parsing-no-positions.hopix create mode 100644 flap/tests/01-Parsing/01-constructor-application.bad.expected create mode 100644 flap/tests/01-Parsing/01-constructor-application.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/01-constructor-application.good.expected create mode 100644 flap/tests/01-Parsing/01-constructor-application.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/02-app2.bad.expected create mode 100644 flap/tests/01-Parsing/02-app2.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/03-app2-2.bad.expected create mode 100644 flap/tests/01-Parsing/03-app2-2.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/04-app2-3.bad.expected create mode 100644 flap/tests/01-Parsing/04-app2-3.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/05-app3.bad.expected create mode 100644 flap/tests/01-Parsing/05-app3.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/06-lexer-var-id-1.bad.expected create mode 100644 flap/tests/01-Parsing/06-lexer-var-id-1.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/06-lexer-var-id-1.good.expected create mode 100644 flap/tests/01-Parsing/06-lexer-var-id-1.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/07-lexer-var-id-2.bad.expected create mode 100644 flap/tests/01-Parsing/07-lexer-var-id-2.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/07-lexer-var-id-2.good.expected create mode 100644 flap/tests/01-Parsing/07-lexer-var-id-2.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/08-lexer-all-id-1.bad.expected create mode 100644 flap/tests/01-Parsing/08-lexer-all-id-1.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/08-lexer-all-id-1.good.expected create mode 100644 flap/tests/01-Parsing/08-lexer-all-id-1.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/09-lexer-constr-id-1.bad.expected create mode 100644 flap/tests/01-Parsing/09-lexer-constr-id-1.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/09-lexer-constr-id-1.good.expected create mode 100644 flap/tests/01-Parsing/09-lexer-constr-id-1.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/10-lexer-constr-id-2.bad.expected create mode 100644 flap/tests/01-Parsing/10-lexer-constr-id-2.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/10-lexer-constr-id-2.good.expected create mode 100644 flap/tests/01-Parsing/10-lexer-constr-id-2.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/100-ref-2.bad.expected create mode 100644 flap/tests/01-Parsing/100-ref-2.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/100-ref-2.good.expected create mode 100644 flap/tests/01-Parsing/100-ref-2.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/101-ref-3.bad.expected create mode 100644 flap/tests/01-Parsing/101-ref-3.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/101-ref-3.good.expected create mode 100644 flap/tests/01-Parsing/101-ref-3.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/102-ref-4.bad.expected create mode 100644 flap/tests/01-Parsing/102-ref-4.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/102-ref-4.good.expected create mode 100644 flap/tests/01-Parsing/102-ref-4.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/103-ref-5.bad.expected create mode 100644 flap/tests/01-Parsing/103-ref-5.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/103-ref-5.good.expected create mode 100644 flap/tests/01-Parsing/103-ref-5.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/104-assignment.bad.expected create mode 100644 flap/tests/01-Parsing/104-assignment.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/104-assignment.good.expected create mode 100644 flap/tests/01-Parsing/104-assignment.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/105-assignment-2.bad.expected create mode 100644 flap/tests/01-Parsing/105-assignment-2.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/105-assignment-2.good.expected create mode 100644 flap/tests/01-Parsing/105-assignment-2.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/106-assignment-3.bad.expected create mode 100644 flap/tests/01-Parsing/106-assignment-3.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/106-assignment-3.good.expected create mode 100644 flap/tests/01-Parsing/106-assignment-3.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/107-assignment-4.bad.expected create mode 100644 flap/tests/01-Parsing/107-assignment-4.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/107-assignment-4.good.expected create mode 100644 flap/tests/01-Parsing/107-assignment-4.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/108-type-ascription-1.bad.expected create mode 100644 flap/tests/01-Parsing/108-type-ascription-1.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/108-type-ascription-1.good.expected create mode 100644 flap/tests/01-Parsing/108-type-ascription-1.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/109-type-ascription-2.bad.expected create mode 100644 flap/tests/01-Parsing/109-type-ascription-2.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/109-type-ascription-2.good.expected create mode 100644 flap/tests/01-Parsing/109-type-ascription-2.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/11-lexer-constr-id-3.bad.expected create mode 100644 flap/tests/01-Parsing/11-lexer-constr-id-3.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/11-lexer-constr-id-3.good.expected create mode 100644 flap/tests/01-Parsing/11-lexer-constr-id-3.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/110-type-ascription-3.bad.expected create mode 100644 flap/tests/01-Parsing/110-type-ascription-3.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/110-type-ascription-3.good.expected create mode 100644 flap/tests/01-Parsing/110-type-ascription-3.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/111-deref-1.bad.expected create mode 100644 flap/tests/01-Parsing/111-deref-1.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/111-deref-1.good.expected create mode 100644 flap/tests/01-Parsing/111-deref-1.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/112-deref-2.bad.expected create mode 100644 flap/tests/01-Parsing/112-deref-2.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/112-deref-2.good.expected create mode 100644 flap/tests/01-Parsing/112-deref-2.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/113-deref-3.good.expected create mode 100644 flap/tests/01-Parsing/113-deref-3.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/114-while-1.bad.expected create mode 100644 flap/tests/01-Parsing/114-while-1.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/114-while-1.good.expected create mode 100644 flap/tests/01-Parsing/114-while-1.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/115-while-2.bad.expected create mode 100644 flap/tests/01-Parsing/115-while-2.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/115-while-2.good.expected create mode 100644 flap/tests/01-Parsing/115-while-2.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/116-for-1.bad.expected create mode 100644 flap/tests/01-Parsing/116-for-1.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/116-for-1.good.expected create mode 100644 flap/tests/01-Parsing/116-for-1.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/117-for-2.bad.expected create mode 100644 flap/tests/01-Parsing/117-for-2.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/117-for-2.good.expected create mode 100644 flap/tests/01-Parsing/117-for-2.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/118-do-while-1.bad.expected create mode 100644 flap/tests/01-Parsing/118-do-while-1.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/118-do-while-1.good.expected create mode 100644 flap/tests/01-Parsing/118-do-while-1.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/119-do-while-2.bad.expected create mode 100644 flap/tests/01-Parsing/119-do-while-2.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/119-do-while-2.good.expected create mode 100644 flap/tests/01-Parsing/119-do-while-2.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/12-lexer-label-id-1.bad.expected create mode 100644 flap/tests/01-Parsing/12-lexer-label-id-1.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/12-lexer-label-id-1.good.expected create mode 100644 flap/tests/01-Parsing/12-lexer-label-id-1.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/12-lexer-label-id-2.bad.expected create mode 100644 flap/tests/01-Parsing/12-lexer-label-id-2.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/12-lexer-label-id-2.good.expected create mode 100644 flap/tests/01-Parsing/12-lexer-label-id-2.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/13-type-con-id-1.bad.expected create mode 100644 flap/tests/01-Parsing/13-type-con-id-1.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/13-type-con-id-1.good.expected create mode 100644 flap/tests/01-Parsing/13-type-con-id-1.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/14-type-con-id-2.bad.expected create mode 100644 flap/tests/01-Parsing/14-type-con-id-2.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/14-type-con-id-2.good.expected create mode 100644 flap/tests/01-Parsing/14-type-con-id-2.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/15-int-literal-1.bad.expected create mode 100644 flap/tests/01-Parsing/15-int-literal-1.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/15-int-literal-1.good.expected create mode 100644 flap/tests/01-Parsing/15-int-literal-1.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/16-int-literal-2.bad.expected create mode 100644 flap/tests/01-Parsing/16-int-literal-2.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/16-int-literal-2.good.expected create mode 100644 flap/tests/01-Parsing/16-int-literal-2.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/17-int-literal-3.bad.expected create mode 100644 flap/tests/01-Parsing/17-int-literal-3.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/17-int-literal-3.good.expected create mode 100644 flap/tests/01-Parsing/17-int-literal-3.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/18-int-literal-4.bad.expected create mode 100644 flap/tests/01-Parsing/18-int-literal-4.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/18-int-literal-4.good.expected create mode 100644 flap/tests/01-Parsing/18-int-literal-4.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/19-int-literal-5.bad.expected create mode 100644 flap/tests/01-Parsing/19-int-literal-5.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/19-int-literal-5.good.expected create mode 100644 flap/tests/01-Parsing/19-int-literal-5.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/20-int-literal-6.bad.expected create mode 100644 flap/tests/01-Parsing/20-int-literal-6.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/20-int-literal-6.good.expected create mode 100644 flap/tests/01-Parsing/20-int-literal-6.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/21-char-literal-1.bad.expected create mode 100644 flap/tests/01-Parsing/21-char-literal-1.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/21-char-literal-1.good.expected create mode 100644 flap/tests/01-Parsing/21-char-literal-1.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/22-char-literal-2.bad.expected create mode 100644 flap/tests/01-Parsing/22-char-literal-2.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/22-char-literal-2.good.expected create mode 100644 flap/tests/01-Parsing/22-char-literal-2.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/23-char-literal-3.bad.expected create mode 100644 flap/tests/01-Parsing/23-char-literal-3.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/23-char-literal-3.good.expected create mode 100644 flap/tests/01-Parsing/23-char-literal-3.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/24-char-literal-4.bad.expected create mode 100644 flap/tests/01-Parsing/24-char-literal-4.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/24-char-literal-4.good.expected create mode 100644 flap/tests/01-Parsing/24-char-literal-4.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/25-char-literal-5.bad.expected create mode 100644 flap/tests/01-Parsing/25-char-literal-5.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/25-char-literal-5.good.expected create mode 100644 flap/tests/01-Parsing/25-char-literal-5.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/26-char-literal-6.bad.expected create mode 100644 flap/tests/01-Parsing/26-char-literal-6.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/26-char-literal-6.good.expected create mode 100644 flap/tests/01-Parsing/26-char-literal-6.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/27-string-literal-1.bad.expected create mode 100644 flap/tests/01-Parsing/27-string-literal-1.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/27-string-literal-1.good.expected create mode 100644 flap/tests/01-Parsing/27-string-literal-1.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/28-string-literal-2.bad.expected create mode 100644 flap/tests/01-Parsing/28-string-literal-2.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/28-string-literal-2.good.expected create mode 100644 flap/tests/01-Parsing/28-string-literal-2.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/29-string-literal-3.bad.expected create mode 100644 flap/tests/01-Parsing/29-string-literal-3.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/29-string-literal-3.good.expected create mode 100644 flap/tests/01-Parsing/29-string-literal-3.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/30-string-literal-4.bad.expected create mode 100644 flap/tests/01-Parsing/30-string-literal-4.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/30-string-literal-4.good.expected create mode 100644 flap/tests/01-Parsing/30-string-literal-4.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/31-type-definition-sum-1.bad.expected create mode 100644 flap/tests/01-Parsing/31-type-definition-sum-1.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/31-type-definition-sum-1.good.expected create mode 100644 flap/tests/01-Parsing/31-type-definition-sum-1.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/32-type-definition-sum-2.bad.expected create mode 100644 flap/tests/01-Parsing/32-type-definition-sum-2.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/32-type-definition-sum-2.good.expected create mode 100644 flap/tests/01-Parsing/32-type-definition-sum-2.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/33-type-definition-sum-3.bad.expected create mode 100644 flap/tests/01-Parsing/33-type-definition-sum-3.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/33-type-definition-sum-3.good.expected create mode 100644 flap/tests/01-Parsing/33-type-definition-sum-3.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/34-type-definition-sum-4.bad.expected create mode 100644 flap/tests/01-Parsing/34-type-definition-sum-4.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/34-type-definition-sum-4.good.expected create mode 100644 flap/tests/01-Parsing/34-type-definition-sum-4.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/35-type-definition-sum-5.bad.expected create mode 100644 flap/tests/01-Parsing/35-type-definition-sum-5.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/35-type-definition-sum-5.good.expected create mode 100644 flap/tests/01-Parsing/35-type-definition-sum-5.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/36-type-definition-sum-6.bad.expected create mode 100644 flap/tests/01-Parsing/36-type-definition-sum-6.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/36-type-definition-sum-6.good.expected create mode 100644 flap/tests/01-Parsing/36-type-definition-sum-6.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/37-type-definition-sum-7.bad.expected create mode 100644 flap/tests/01-Parsing/37-type-definition-sum-7.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/37-type-definition-sum-7.good.expected create mode 100644 flap/tests/01-Parsing/37-type-definition-sum-7.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/38-type-definition-record-1.bad.expected create mode 100644 flap/tests/01-Parsing/38-type-definition-record-1.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/38-type-definition-record-1.good.expected create mode 100644 flap/tests/01-Parsing/38-type-definition-record-1.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/39-type-definition-record-2.bad.expected create mode 100644 flap/tests/01-Parsing/39-type-definition-record-2.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/39-type-definition-record-2.good.expected create mode 100644 flap/tests/01-Parsing/39-type-definition-record-2.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/40-type-definition-record-3.bad.expected create mode 100644 flap/tests/01-Parsing/40-type-definition-record-3.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/40-type-definition-record-3.good.expected create mode 100644 flap/tests/01-Parsing/40-type-definition-record-3.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/41-external-definition-1.bad.expected create mode 100644 flap/tests/01-Parsing/41-external-definition-1.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/41-external-definition-1.good.expected create mode 100644 flap/tests/01-Parsing/41-external-definition-1.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/42-external-definition-2.good.expected create mode 100644 flap/tests/01-Parsing/42-external-definition-2.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/43-external-definition-3.bad.expected create mode 100644 flap/tests/01-Parsing/43-external-definition-3.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/43-external-definition-3.good.expected create mode 100644 flap/tests/01-Parsing/43-external-definition-3.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/44-value-definition-1.bad.expected create mode 100644 flap/tests/01-Parsing/44-value-definition-1.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/44-value-definition-1.good.expected create mode 100644 flap/tests/01-Parsing/44-value-definition-1.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/45-value-definition-2.bad.expected create mode 100644 flap/tests/01-Parsing/45-value-definition-2.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/45-value-definition-2.good.expected create mode 100644 flap/tests/01-Parsing/45-value-definition-2.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/46-value-definition-3.bad.expected create mode 100644 flap/tests/01-Parsing/46-value-definition-3.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/46-value-definition-3.good.expected create mode 100644 flap/tests/01-Parsing/46-value-definition-3.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/47-instanciation.bad.expected create mode 100644 flap/tests/01-Parsing/47-instanciation.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/47-instanciation.good.expected create mode 100644 flap/tests/01-Parsing/47-instanciation.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/48-instanciation-2.bad.expected create mode 100644 flap/tests/01-Parsing/48-instanciation-2.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/48-instanciation-2.good.expected create mode 100644 flap/tests/01-Parsing/48-instanciation-2.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/49-instanciation-3.bad.expected create mode 100644 flap/tests/01-Parsing/49-instanciation-3.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/49-instanciation-3.good.expected create mode 100644 flap/tests/01-Parsing/49-instanciation-3.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/50-instanciation-4.bad.expected create mode 100644 flap/tests/01-Parsing/50-instanciation-4.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/50-instanciation-4.good.expected create mode 100644 flap/tests/01-Parsing/50-instanciation-4.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/51-instanciation-5.bad.expected create mode 100644 flap/tests/01-Parsing/51-instanciation-5.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/51-instanciation-5.good.expected create mode 100644 flap/tests/01-Parsing/51-instanciation-5.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/52-instanciation-6.bad.expected create mode 100644 flap/tests/01-Parsing/52-instanciation-6.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/52-instanciation-6.good.expected create mode 100644 flap/tests/01-Parsing/52-instanciation-6.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/53-instanciation-7.bad.expected create mode 100644 flap/tests/01-Parsing/53-instanciation-7.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/53-instanciation-7.good.expected create mode 100644 flap/tests/01-Parsing/53-instanciation-7.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/54-constructor-1.bad.expected create mode 100644 flap/tests/01-Parsing/54-constructor-1.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/54-constructor-1.good.expected create mode 100644 flap/tests/01-Parsing/54-constructor-1.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/55-constructor-2.bad.expected create mode 100644 flap/tests/01-Parsing/55-constructor-2.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/55-constructor-2.good.expected create mode 100644 flap/tests/01-Parsing/55-constructor-2.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/56-constructor-3.bad.expected create mode 100644 flap/tests/01-Parsing/56-constructor-3.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/56-constructor-3.good.expected create mode 100644 flap/tests/01-Parsing/56-constructor-3.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/57-constructor-4.bad.expected create mode 100644 flap/tests/01-Parsing/57-constructor-4.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/57-constructor-4.good.expected create mode 100644 flap/tests/01-Parsing/57-constructor-4.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/58-record-1.bad.expected create mode 100644 flap/tests/01-Parsing/58-record-1.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/58-record-1.good.expected create mode 100644 flap/tests/01-Parsing/58-record-1.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/59-record-2.bad.expected create mode 100644 flap/tests/01-Parsing/59-record-2.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/59-record-2.good.expected create mode 100644 flap/tests/01-Parsing/59-record-2.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/60-record-3.bad.expected create mode 100644 flap/tests/01-Parsing/60-record-3.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/60-record-3.good.expected create mode 100644 flap/tests/01-Parsing/60-record-3.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/61-record-projection-1.bad.expected create mode 100644 flap/tests/01-Parsing/61-record-projection-1.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/61-record-projection-1.good.expected create mode 100644 flap/tests/01-Parsing/61-record-projection-1.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/62-record-projection-2.bad.expected create mode 100644 flap/tests/01-Parsing/62-record-projection-2.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/62-record-projection-2.good.expected create mode 100644 flap/tests/01-Parsing/62-record-projection-2.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/63-record-projection-3.bad.expected create mode 100644 flap/tests/01-Parsing/63-record-projection-3.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/63-record-projection-3.good.expected create mode 100644 flap/tests/01-Parsing/63-record-projection-3.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/65-sequence-1.bad.expected create mode 100644 flap/tests/01-Parsing/65-sequence-1.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/65-sequence-1.good.expected create mode 100644 flap/tests/01-Parsing/65-sequence-1.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/66-sequence-2.bad.expected create mode 100644 flap/tests/01-Parsing/66-sequence-2.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/66-sequence-2.good.expected create mode 100644 flap/tests/01-Parsing/66-sequence-2.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/67-sequence-3.bad.expected create mode 100644 flap/tests/01-Parsing/67-sequence-3.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/67-sequence-3.good.expected create mode 100644 flap/tests/01-Parsing/67-sequence-3.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/68-local-definition.bad.expected create mode 100644 flap/tests/01-Parsing/68-local-definition.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/68-local-definition.good.expected create mode 100644 flap/tests/01-Parsing/68-local-definition.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/69-local-definition-2.bad.expected create mode 100644 flap/tests/01-Parsing/69-local-definition-2.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/69-local-definition-2.good.expected create mode 100644 flap/tests/01-Parsing/69-local-definition-2.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/70-local-definition-3.bad.expected create mode 100644 flap/tests/01-Parsing/70-local-definition-3.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/70-local-definition-3.good.expected create mode 100644 flap/tests/01-Parsing/70-local-definition-3.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/71-local-definition-4.bad.expected create mode 100644 flap/tests/01-Parsing/71-local-definition-4.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/71-local-definition-4.good.expected create mode 100644 flap/tests/01-Parsing/71-local-definition-4.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/72-local-definition-5.bad.expected create mode 100644 flap/tests/01-Parsing/72-local-definition-5.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/72-local-definition-5.good.expected create mode 100644 flap/tests/01-Parsing/72-local-definition-5.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/73-lambda-1.bad.expected create mode 100644 flap/tests/01-Parsing/73-lambda-1.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/73-lambda-1.good.expected create mode 100644 flap/tests/01-Parsing/73-lambda-1.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/74-lambda-2.bad.expected create mode 100644 flap/tests/01-Parsing/74-lambda-2.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/74-lambda-2.good.expected create mode 100644 flap/tests/01-Parsing/74-lambda-2.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/75-lambda-3.bad.expected create mode 100644 flap/tests/01-Parsing/75-lambda-3.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/75-lambda-3.good.expected create mode 100644 flap/tests/01-Parsing/75-lambda-3.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/76-lambda-4.bad.expected create mode 100644 flap/tests/01-Parsing/76-lambda-4.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/76-lambda-4.good.expected create mode 100644 flap/tests/01-Parsing/76-lambda-4.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/77-application-1.bad.expected create mode 100644 flap/tests/01-Parsing/77-application-1.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/77-application-1.good.expected create mode 100644 flap/tests/01-Parsing/77-application-1.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/78-application-2.bad.expected create mode 100644 flap/tests/01-Parsing/78-application-2.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/78-application-2.good.expected create mode 100644 flap/tests/01-Parsing/78-application-2.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/79-application-3.bad.expected create mode 100644 flap/tests/01-Parsing/79-application-3.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/79-application-3.good.expected create mode 100644 flap/tests/01-Parsing/79-application-3.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/80-application-4.bad.expected create mode 100644 flap/tests/01-Parsing/80-application-4.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/80-application-4.good.expected create mode 100644 flap/tests/01-Parsing/80-application-4.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/81-application-5.bad.expected create mode 100644 flap/tests/01-Parsing/81-application-5.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/81-application-5.good.expected create mode 100644 flap/tests/01-Parsing/81-application-5.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/82-application-6.bad.expected create mode 100644 flap/tests/01-Parsing/82-application-6.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/82-application-6.good.expected create mode 100644 flap/tests/01-Parsing/82-application-6.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/83-application-7.bad.expected create mode 100644 flap/tests/01-Parsing/83-application-7.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/83-application-7.good.expected create mode 100644 flap/tests/01-Parsing/83-application-7.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/84-infix-application-1.bad.expected create mode 100644 flap/tests/01-Parsing/84-infix-application-1.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/84-infix-application-1.good.expected create mode 100644 flap/tests/01-Parsing/84-infix-application-1.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/85-infix-application-2.bad.expected create mode 100644 flap/tests/01-Parsing/85-infix-application-2.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/85-infix-application-2.good.expected create mode 100644 flap/tests/01-Parsing/85-infix-application-2.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/86-infix-application-3.bad.expected create mode 100644 flap/tests/01-Parsing/86-infix-application-3.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/86-infix-application-3.good.expected create mode 100644 flap/tests/01-Parsing/86-infix-application-3.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/87-infix-application-4.bad.expected create mode 100644 flap/tests/01-Parsing/87-infix-application-4.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/87-infix-application-4.good.expected create mode 100644 flap/tests/01-Parsing/87-infix-application-4.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/88-case-1.bad.expected create mode 100644 flap/tests/01-Parsing/88-case-1.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/88-case-1.good.expected create mode 100644 flap/tests/01-Parsing/88-case-1.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/89-case-2.bad.expected create mode 100644 flap/tests/01-Parsing/89-case-2.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/89-case-2.good.expected create mode 100644 flap/tests/01-Parsing/89-case-2.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/90-case-3.bad.expected create mode 100644 flap/tests/01-Parsing/90-case-3.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/90-case-3.good.expected create mode 100644 flap/tests/01-Parsing/90-case-3.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/91-case-4.bad.expected create mode 100644 flap/tests/01-Parsing/91-case-4.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/91-case-4.good.expected create mode 100644 flap/tests/01-Parsing/91-case-4.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/92-case-5.bad.expected create mode 100644 flap/tests/01-Parsing/92-case-5.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/92-case-5.good.expected create mode 100644 flap/tests/01-Parsing/92-case-5.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/93-case-6.bad.expected create mode 100644 flap/tests/01-Parsing/93-case-6.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/93-case-6.good.expected create mode 100644 flap/tests/01-Parsing/93-case-6.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/94-case-7.bad.expected create mode 100644 flap/tests/01-Parsing/94-case-7.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/94-case-7.good.expected create mode 100644 flap/tests/01-Parsing/94-case-7.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/95-case-8.bad.expected create mode 100644 flap/tests/01-Parsing/95-case-8.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/95-case-8.good.expected create mode 100644 flap/tests/01-Parsing/95-case-8.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/96-if-then-else.bad.expected create mode 100644 flap/tests/01-Parsing/96-if-then-else.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/96-if-then-else.good.expected create mode 100644 flap/tests/01-Parsing/96-if-then-else.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/97-if-then-else-2.bad.expected create mode 100644 flap/tests/01-Parsing/97-if-then-else-2.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/97-if-then-else-2.good.expected create mode 100644 flap/tests/01-Parsing/97-if-then-else-2.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/98-if-then-else-3.bad.expected create mode 100644 flap/tests/01-Parsing/98-if-then-else-3.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/98-if-then-else-3.good.expected create mode 100644 flap/tests/01-Parsing/98-if-then-else-3.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/98-if-then-else-4.bad.expected create mode 100644 flap/tests/01-Parsing/98-if-then-else-4.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/98-if-then-else-4.good.expected create mode 100644 flap/tests/01-Parsing/98-if-then-else-4.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/99-ref-1.bad.expected create mode 100644 flap/tests/01-Parsing/99-ref-1.bad.parsing.hopix create mode 100644 flap/tests/01-Parsing/99-ref-1.good.expected create mode 100644 flap/tests/01-Parsing/99-ref-1.good.parsing.hopix create mode 100644 flap/tests/01-Parsing/999-slam.good.expected create mode 100644 flap/tests/01-Parsing/999-slam.good.parsing.hopix create mode 100644 flap/tests/Makefile create mode 100644 flap/tests/README.md create mode 100644 jalons/jalon-1.pdf diff --git a/flap/AUTEURS b/flap/AUTEURS new file mode 100644 index 0000000..8ba2ad2 --- /dev/null +++ b/flap/AUTEURS @@ -0,0 +1,2 @@ +nom1,prenom1,email1 +nom2,prenom2,email2 diff --git a/flap/README.md b/flap/README.md new file mode 100644 index 0000000..6ec2c1f --- /dev/null +++ b/flap/README.md @@ -0,0 +1,31 @@ +# The Flap Compiler + +## Prerequisites + +Flap requires **OCaml 4.10+**, as well as the tools and libraries listed +below. They should be installed prior to attempting to build Flap. + +- The **dune** build system. +- The **utop** enhanced interactive toplevel. +- The **pprint** library. +- The **menhir** parser generator and library. +- The **sexplib** library. +- The **ppx_sexp_conv** syntax extension. + +The easiest way to install them is via OPAM. + +`` +opam install dune utop pprint menhir sexplib ppx_sexp_conv +`` + +In addition, running the test requires the [cram](https://bitheap.org/cram/) +tool. It is probably provided by your Linux distribution. + +## Build instructions + +To compile the compiler, run `dune build` from this directory. + +To run the compiler, run `dune exec ./src/flap.exe -- OPTIONS file` from this +directory. Alternatively, `flap.exe` can be found in `_build/default/src/`. + +The test suite can be found in the `tests` directory. See the README there. diff --git a/flap/dune-project b/flap/dune-project new file mode 100644 index 0000000..e9d1ed4 --- /dev/null +++ b/flap/dune-project @@ -0,0 +1,3 @@ +(lang dune 2.7) +(using menhir 2.1) +(cram enable) diff --git a/flap/runtime/runtime.c b/flap/runtime/runtime.c new file mode 100644 index 0000000..3f7a276 --- /dev/null +++ b/flap/runtime/runtime.c @@ -0,0 +1,37 @@ +#include +#include +#include +#include + +int equal_string(const char* s1, const char* s2) { + return (strcmp (s1, s2) == 0 ? 1 : 0); +} + +int equal_char(char c1, char c2) { + return (c1 == c2 ? 1 : 0); +} + +void print_string(const char* s) { + printf("%s", s); +} + +void print_int(int64_t n) { + fprintf(stderr, "Students! This is your job!\n"); +} + +void observe_int(int64_t n) { + print_int(n); +} + +intptr_t* allocate_block (int64_t n) { + return (intptr_t*)malloc (n * sizeof (int64_t)); +} + +intptr_t read_block (intptr_t* block, int64_t n) { + return block[n]; +} + +int64_t write_block (intptr_t* block, int64_t n, intptr_t v) { + block[n] = v; + return 0; +} diff --git a/flap/src/commandLineOptions.ml b/flap/src/commandLineOptions.ml new file mode 100644 index 0000000..47d80d7 --- /dev/null +++ b/flap/src/commandLineOptions.ml @@ -0,0 +1,162 @@ +(** Command line arguments analysis. *) + +let options_list = + ref [] + +let push local_options = + options_list := !options_list @ local_options + +let options names kind doc = + let first_shot = + let state = ref true in + fun s -> + if !state then (state := false; s) + else + (List.hd (Str.(split (regexp " ") doc))) + in + List.map (fun n -> (n, kind, first_shot doc)) names + +let optimizers_options () = + List.map (fun (module O : Optimizers.Optimizer) -> Arg.( + options + ["--" ^ O.shortname] + (Set O.activated) + (Printf.sprintf " Activate optimization `%s'." O.longname) + )) !Optimizers.optimizers + +let show_version_and_exits () = + Printf.printf "flap %s\n%!" Version.number; + exit 0 + +let generic_options () = Arg.(align (List.flatten [ + options + ["--version"; "-v"] + (Unit show_version_and_exits) + " Show the version number and exits."; + + options + ["--source"; "-s"] + (String Options.set_source_language) + (" Set the source programming language"); + + options + ["--target"; "-t"] + (String Options.set_target_language) + (" Set the target programming language"); + + options + ["--interactive"; "-i"] + (Bool Options.set_interactive_mode) + ("(true|false) Set the compiler mode"); + + options + ["--run"; "-r"] + (Bool Options.set_running_mode) + ("(true|false) Ask the compiler to run the compiled code"); + + options + ["--verbose"; "-V"] + (Bool Options.set_verbose_mode) + ("(true|false) Ask the compiler to be verbose"); + + options + ["--verbose-eval"; "-VV"] + (Bool Options.set_verbose_eval) + ("(true|false) Ask the compiler to be show the result of evaluation"); + + options + ["--dry"; "-d"] + (Bool Options.set_dry_mode) + ("(true|false) Ask the compiler not to produce compiled file"); + + options + ["--unsafe"; "-u"] + (Bool Options.set_unsafe) + ("(true|false) Ask the compiler not to typecheck"); + + options + ["--bench"; "-B"] + (Bool Options.set_benchmark) + ("(true|false) Ask the compiler to show evaluation time."); + + options + ["--using"; "-!" ] + (String Options.insert_using) + (" Force the compilation to use this intermediate language"); + + options + ["--types"; "-T"] + (Bool Options.set_show_types) + ("(true|false) Ask the compiler to show types for toplevel values."); + + options + ["--infer"; "-I"] + (Bool Options.set_infer_types) + ("(true|false) Ask the compiler to infer types for toplevel values."); + + options + ["--typechecking"; "-C"] + (Bool Options.set_check_types) + ("(true|false) Ask the compiler to check types for toplevel values."); + + options + ["--sexp-in"] + (Bool Options.set_use_sexp_in) + ("(true|false) Activate sexp parsing."); + + options + ["--sexp-out"] + (Bool Options.set_use_sexp_out) + ("(true|false) Activate sexp printing."); + + options + ["--scripts-dir"; "-IS"] + (String Options.set_scripts_dir) + ("[dirname] Set the directory where compiler scripts are located."); + + options + ["--include-dir"; "-II"] + (String Options.set_include_dir) + ("[dirname] Set the directory where runtime.c is located."); + + options + ["--output-file"; "-o"] + (String Options.set_output_file) + "[filename] Set the output file."; + + options + ["--fast-pattern-matching"; "-fpm"] + (Bool Options.set_fast_match) + " Enable efficient pattern-matching compilation."; + + options + ["--backend"; "-b"] + (String Options.set_backend) + "[architecture] Set the architecture backend, default is x86-64."; + + options + ["--regalloc-strategy"; "-R"] + (String Options.set_regalloc) + "[strategy] Set the register allocation strategy, default is naive \ + (alternatives: advanced)."; + + options + ["--debug"; "-D"] + (Bool Options.set_debug_mode) + ("(true|false) Ask the compiler to dump internal information"); + + options + ["--loc"; "-l"] + (Bool Options.set_print_locs) + ("(true|false) Ask the compiler to print locations in error messages"); + +] @ (List.flatten (optimizers_options ())))) + +let usage_msg = + "flap [options] input_filename" + +let parse () = + Arg.parse !options_list Options.set_input_filename usage_msg + +let initialize () = + push (generic_options ()) diff --git a/flap/src/common/architecture.mli b/flap/src/common/architecture.mli new file mode 100644 index 0000000..c79178d --- /dev/null +++ b/flap/src/common/architecture.mli @@ -0,0 +1,26 @@ +(** This module defines a common interface to specify target architectures. *) + +module type S = sig + + (** The type of hardware registers. *) + type register + + (** Hardware registers that can be used by register allocation. *) + val allocable_registers : register list + + (** Registers used as effective arguments for functions. *) + val argument_passing_registers : register list + + (** Registers that must be preserved through function calls. *) + val callee_saved_registers : register list + + (** Registers that are *not* preserved by function calls. *) + val caller_saved_registers : register list + + (** The register that holds the value returned by a function. *) + val return_register : register + + (** A human representation of register identifier. *) + val string_of_register : register -> string + +end diff --git a/flap/src/common/compilers.ml b/flap/src/common/compilers.ml new file mode 100644 index 0000000..ab2bcea --- /dev/null +++ b/flap/src/common/compilers.ml @@ -0,0 +1,114 @@ +(** Compilers. *) + +open Languages + +(** A compiler translates programs from a source language + into programs of a target language. *) +module type Compiler = sig + + module Source : Language + module Target : Language + + type environment + val initial_environment : unit -> environment + + val translate : Source.ast -> environment -> Target.ast * environment + +end + +(** Given a compiler from L1 to L2 and a compiler from L2 to L3, + one can get compiler from L1 to L3. *) +let compose (module C1 : Compiler) (module C2 : Compiler) : (module Compiler) = + let c2_source_is_c1_target = + Obj.magic (* Do not do this at home, kids! *) + in + (module struct + module Source = C1.Source + + module Target = C2.Target + + type environment = C1.environment * C2.environment + + let initial_environment () = + (C1.initial_environment (), C2.initial_environment ()) + + let translate source (env1, env2) = + let (intermediate, env1') = + C1.translate source env1 + in + let (target, env2') = + C2.translate (c2_source_is_c1_target intermediate) env2 + in + (target, (env1', env2')) + end : Compiler) + +let rec join = function + | [x] -> x + | [x; y] -> compose x y + | x :: xs -> compose x (join xs) + | _ -> assert false + +let string_of_compiler_passes xs = + String.concat " -> " ( + List.map (fun (module C : Compiler) -> C.Source.extension + ) xs) + +(** Compiler implementations are stored in the following + mutable association list. *) +let compilers : (string * (string * (module Compiler))) list ref = + ref [] + +let register (module C : Compiler) = + let source = C.Source.name and target = C.Target.name in + compilers := (source, (target, (module C))) :: !compilers + +let compilers_from source = + List.( + !compilers + |> filter (fun (source', _) -> source = source') + |> map snd + ) + +let find _ source target using = List.(ExtStd.List.Monad.( + let rec search seen source target = + if List.mem source seen then + fail + else ( + take_one (compilers_from source) >>= fun (target', m) -> + if target = target' then + return [(target', m)] + else ( + search (source :: seen) target' target >>= fun ms -> + return ((target', m) :: ms) + ) + ) + in + run (search [] source target) + |> filter (fun p -> for_all (fun u -> exists (fun (l, _) -> l = u) p) using) + |> map (map snd) +)) + +let get ?(using=[]) (module Source : Language) (module Target : Language) = + let using = List.map (fun (module L : Language) -> L.name) using in + match find compilers Source.name Target.name using with + | [] -> + Error.global_error + "during compilation" + "Sorry, there is no such compiler in flap." + | [x] -> + join x + | xs -> + Error.global_error + "during compilation" + ("Sorry, there are many ways to implement this compiler in flap:\n" ^ + String.concat "\n" (List.map string_of_compiler_passes xs)) + +(** There is an easy way to compile a language into itself: + just use the identity function :-). *) +module Identity (L : Language) : Compiler = struct + module Source = L + module Target = L + type environment = unit + let initial_environment () = () + let translate x () = (x, ()) +end diff --git a/flap/src/common/compilers.mli b/flap/src/common/compilers.mli new file mode 100644 index 0000000..db572fa --- /dev/null +++ b/flap/src/common/compilers.mli @@ -0,0 +1,45 @@ +(** Compilers + + A compiler is a translator from a source language to a target + language. + +*) +open Languages + +module type Compiler = sig + + module Source : Language + module Target : Language + + (** It is convenient to maintain some information about a program + along its compilation: an environment is meant to store that + kind of information. *) + type environment + val initial_environment : unit -> environment + + (** [translate source env] returns a [target] program semantically + equivalent to [source] as a well as an enriched environment + [env] that contains information related to the compilation of + [source]. *) + val translate : Source.ast -> environment -> Target.ast * environment + +end + +(** [register compiler] integrates [compiler] is the set of flap's compilers. *) +val register : (module Compiler) -> unit + +(** [get ?using source target] returns a compiler from [source] to + [target] built by composing flap's compilers. [using] is empty if + not specified. + + [using] represents a list of languages that must appear in the + compilation chain. It is useful to disambiguate between several + choices when distinct compilation chains exist between two + languages. If [using] is not precise enough to kill the + ambiguity, flap issues a global error. *) +val get : ?using:(module Language) list + -> (module Language) -> (module Language) -> (module Compiler) + +(** There is an easy way to compile a language into itself: + just use the identity function :-). *) +module Identity (L : Language) : Compiler diff --git a/flap/src/common/languages.ml b/flap/src/common/languages.ml new file mode 100644 index 0000000..c03dbfa --- /dev/null +++ b/flap/src/common/languages.ml @@ -0,0 +1,95 @@ +module type Language = sig + + (** A language as a [name]. *) + val name : string + + (** {1 Syntax} *) + + (** A syntax is defined by the type of abstract syntax trees. *) + type ast + + (** [parse_filename f] turns the content of file [f] into an + abstract syntax tree if that content is a syntactically valid + input. *) + val parse_filename : string -> ast + + (** Each language has its own extension for source code filenames. *) + val extension : string + + (** [executable_format] should true when programs of the language are directly + executable when dumped on disk as files. *) + val executable_format : bool + + (** [parse_string c] is the same as [parse_filename] except that the + source code is directly given as a string. *) + val parse_string : string -> ast + + (** [print ast] turns an abstract syntax tree into a human-readable + form. *) + val print_ast : ast -> string + + (** {2 Semantic} *) + + (** A runtime environment contains all the information necessary + to evaluate a program. *) + type runtime + + (** In the interactive loop, we will display some observable + feedback about the evaluation. *) + type observable + + (** The evaluation starts with an initial runtime. *) + val initial_runtime : unit -> runtime + + (** [evaluate runtime p] executes the program [p] and + produces a new runtime as well as an observation + of this runtime. *) + val evaluate : runtime -> ast -> runtime * observable + + (** [print_observable o] returns a human-readable + representation of an observable. *) + val print_observable : runtime -> observable -> string + + (** {3 Static semantic} *) + + (** During type checking, static information (aka types) + are stored in the typing environment. *) + type typing_environment + + (** A typing environment to start with. *) + val initial_typing_environment : unit -> typing_environment + + (** [typecheck tenv p] checks if [p] is a well-typed program + and returns an extension of the typing environment [tenv] + with the values defined in the program. *) + val typecheck : typing_environment -> ast -> typing_environment + + (** [print_typing_environment tenv] returns a human-readable + representation of [tenv]. *) + val print_typing_environment : typing_environment -> string + +end + +(** We store all the language implementations in the following + hashing table. *) +let languages : (string, (module Language)) Hashtbl.t = + Hashtbl.create 13 + +let extensions : (string, (module Language)) Hashtbl.t = + Hashtbl.create 13 + +let get (l : string) : (module Language) = + try + Hashtbl.find languages l + with Not_found -> + Error.global_error "initialization" "There is no such language." + +let get_from_extension (l : string) : (module Language) = + try + Hashtbl.find extensions l + with Not_found -> + Error.global_error "initialization" "This extension is not supported." + +let register (module L : Language) = + Hashtbl.add languages L.name (module L); + Hashtbl.add extensions L.extension (module L) diff --git a/flap/src/common/languages.mli b/flap/src/common/languages.mli new file mode 100644 index 0000000..10ea9f7 --- /dev/null +++ b/flap/src/common/languages.mli @@ -0,0 +1,80 @@ +module type Language = sig + (** A language has a [name]. *) + val name : string + + (** {1 Syntax} *) + + (** The syntax of a language is defined by its Abstract Syntax Trees. *) + type ast + + (** [parse_filename f] turns the content of file [f] into an + abstract syntax tree if that content is a syntactically valid + input. *) + val parse_filename : string -> ast + + (** Each language has its own extension for source code filenames. *) + val extension : string + + (** [executable_format] should true when programs of the language are directly + executable when dumped on disk as files. *) + val executable_format : bool + + (** [parse_string c] is the same as [parse_filename] except that the + source code is directly given as a string. *) + val parse_string : string -> ast + + (** [print ast] turns an abstract syntax tree into a human-readable + form. *) + val print_ast : ast -> string + + (** {2 Semantics} *) + + (** A runtime environment contains all the information necessary + to evaluate a program. *) + type runtime + + (** In the interactive loop, we will display some observable + feedback about the evaluation. *) + type observable + + (** The evaluation starts with an initial runtime. *) + val initial_runtime : unit -> runtime + + (** [evaluate runtime p] executes the program [p] and + produces a new runtime as well as an observation + of this runtime. *) + val evaluate : runtime -> ast -> runtime * observable + + (** [print_observable o] returns a human-readable + representation of an observable. *) + val print_observable : runtime -> observable -> string + + (** {3 Type Checking} *) + + (** A typing environment stores static information about the program. *) + type typing_environment + + (** The initial typing environment contains predefined static information, + like the type for constants. *) + val initial_typing_environment : unit -> typing_environment + + (** [typecheck env p] checks if the program [p] is well-formed + and enriches the typing environment accordingly. If [p] is + not well-formed an {!Error} is issued. *) + val typecheck : typing_environment -> ast -> typing_environment + + (** [print_typing_environment] returns a human-readable + representation of a typing environment. *) + val print_typing_environment : typing_environment -> string +end + +(** [get name] returns a language of flap called [name] if it exists. *) +val get : string -> (module Language) + +(** [get_from_extension ext] returns a language of flap whose extension + is [ext] if it exists. *) +val get_from_extension : string -> (module Language) + + +(** [register l] inserts [l] in the set of flap's languages. *) +val register : (module Language) -> unit diff --git a/flap/src/common/memory.ml b/flap/src/common/memory.ml new file mode 100644 index 0000000..052fb0a --- /dev/null +++ b/flap/src/common/memory.ml @@ -0,0 +1,49 @@ +type location = int + +type 'a block = 'a array + +type 'a memory = { + mutable bound : int; + data : 'a block option array; +} + +type 'a t = 'a memory + +let create size = { + bound = 0; + data = Array.make size None +} + +exception OutOfMemory + +let allocate mem size init = + let size = Mint.to_int size in + if mem.bound >= Array.length mem.data then + raise OutOfMemory + else ( + let location = mem.bound in + mem.data.(location) <- Some (Array.make size init); + mem.bound <- mem.bound + 1; + location + ) + +exception InvalidDereference of location + +let dereference mem location = + match mem.data.(location) with + | None -> raise (InvalidDereference location) + | Some b -> b + +let size block = + Mint.of_int (Array.length block) + +let read block i = + block.(Mint.to_int i) + +let write block i x = + block.(Mint.to_int i) <- x + +let array_of_block block = + block + +let print_location x = "#" ^ string_of_int x diff --git a/flap/src/common/memory.mli b/flap/src/common/memory.mli new file mode 100644 index 0000000..288d863 --- /dev/null +++ b/flap/src/common/memory.mli @@ -0,0 +1,39 @@ +(** This module defines a memory model. *) + +(** A memory is data structure... *) +type 'a t + +(** that maps locations... *) +type location + +(** to blocks of data of type ['a]. *) +type 'a block + +(** [create size] produces a fresh memory of [size] potential blocks. *) +val create : int -> 'a t + +(** [allocate mem size init] produces a location that points to a fresh block + of size cells. These cells are initialized with [init]. *) +val allocate : 'a t -> Mint.t -> 'a -> location + +(** The following exception is raised if no new block can be allocated in the + memory. *) +exception OutOfMemory + +(** [dereference mem location] returns the block pointed by [location]. *) +val dereference : 'a t -> location -> 'a block + +(** [size block] returns the length of a block. *) +val size : 'a block -> Mint.t + +(** [read block i] returns the content of the i-th cell of the block *) +val read : 'a block -> Mint.t -> 'a + +(** [write block i x] sets the content of the i-th cell of the block to [x]. *) +val write : 'a block -> Mint.t -> 'a -> unit + +(** [array_of_block b] returns the cells of [b] packed in an array. *) +val array_of_block : 'a block -> 'a array + +(** [print_location l] returns a human-readable representation of [l]. *) +val print_location : location -> string diff --git a/flap/src/common/mint.ml b/flap/src/common/mint.ml new file mode 100644 index 0000000..0252159 --- /dev/null +++ b/flap/src/common/mint.ml @@ -0,0 +1,17 @@ +include Int64 + +exception DoesNotFit + +let to_int n = + if n < of_int Stdlib.min_int || n > of_int Stdlib.max_int + then raise DoesNotFit + else to_int n + +let t_of_sexp s = + of_string @@ Int64.to_string @@ Sexplib.Conv.int64_of_sexp s + +let sexp_of_t n = + Sexplib.Conv.sexp_of_int64 @@ Int64.of_string @@ to_string n + +let size_in_bytes = + 8 diff --git a/flap/src/common/mint.mli b/flap/src/common/mint.mli new file mode 100644 index 0000000..f9d74b3 --- /dev/null +++ b/flap/src/common/mint.mli @@ -0,0 +1,34 @@ +(** This module defines the integer type used in all languages. *) + +type t = Int64.t + +(** {2 Basic Values} *) + +val zero : t +val one : t + +(** {2 Arithmetic Operations} *) + +val add : t -> t -> t +val sub : t -> t -> t +val mul : t -> t -> t +val div : t -> t -> t + +(** {2 Conversions} *) + +exception DoesNotFit + +val of_int : int -> t +val to_int : t -> int + +val of_string : string -> t +val to_string : t -> string + +(** {2 Serialization} *) + +val t_of_sexp : Sexplib.Sexp.t -> t +val sexp_of_t : t -> Sexplib.Sexp.t + +(** {2 Low-level information} *) + +val size_in_bytes : int diff --git a/flap/src/common/optimizers.ml b/flap/src/common/optimizers.ml new file mode 100644 index 0000000..5252e2d --- /dev/null +++ b/flap/src/common/optimizers.ml @@ -0,0 +1,57 @@ +(** Optimizers. *) + +open Languages +open Compilers + +(** An optimizer rewrites programs from a language to try + to improve their efficiency. + + An optimizer has a name and its application is optional. +*) +module type Optimizer = sig + + val shortname : string + + val longname : string + + val activated : bool ref + + module Source : Language + + val translate : Source.ast -> Source.ast + +end + +let optimizers : (module Optimizer) list ref = + ref [] + +let register (module O : Optimizer) = + optimizers := (module O) :: !optimizers + +let find_optimizers source = + List.filter (fun (module O : Optimizer) -> + !O.activated && O.Source.name = source + ) !optimizers + +let optimize + (type t) + (module Source : Language with type ast = t) (ast : t) = + List.fold_left (fun ast (module O : Optimizer) -> + (* Kids, do not do that at home. *) + Obj.magic (O.translate (Obj.magic ast)) + ) ast (find_optimizers Source.name) + +let optimizing_compiler (module C : Compiler) = + (module struct + + module Source = C.Source + module Target = C.Target + + type environment = C.environment + let initial_environment = C.initial_environment + + let translate source env = + let source = optimize (module Source) source in + C.translate source env + + end : Compiler) diff --git a/flap/src/common/syntacticAnalysis.ml b/flap/src/common/syntacticAnalysis.ml new file mode 100644 index 0000000..9642e2d --- /dev/null +++ b/flap/src/common/syntacticAnalysis.ml @@ -0,0 +1,12 @@ +let parsing_step = "during parsing" + +let process ~lexer_init ~lexer_fun ~parser_fun ~input = + parser_fun lexer_fun (lexer_init input) + +let process ~lexer_init ~lexer_fun ~parser_fun ~input = try + process ~lexer_init ~lexer_fun ~parser_fun ~input +with + | Sys_error msg -> + Error.global_error parsing_step msg + | _ -> + Error.global_error parsing_step "Syntax error." diff --git a/flap/src/common/syntacticAnalysis.mli b/flap/src/common/syntacticAnalysis.mli new file mode 100644 index 0000000..deccde7 --- /dev/null +++ b/flap/src/common/syntacticAnalysis.mli @@ -0,0 +1,11 @@ +(** This module helps combining {!Lexer} and {!Parser}. *) + +(** [process lexer_init lexer_fun parser_fun input] initializes a lexer, + and composes it with a parser in order to transform an input text into + an abstract syntax tree. *) +val process : + lexer_init : ('a -> 'lexbuf) -> + lexer_fun : ('lexbuf -> 'token) -> + parser_fun : (('lexbuf -> 'token) -> 'lexbuf -> 'ast) -> + input : 'a -> + 'ast diff --git a/flap/src/dune b/flap/src/dune new file mode 100644 index 0000000..7feeec6 --- /dev/null +++ b/flap/src/dune @@ -0,0 +1,29 @@ +(copy_files# common/*.{ml,mli}) +(copy_files# elf/*.{ml,mli}) +(copy_files# fopix/*.{ml,mli}) +(copy_files# hopix/*.{ml,mli}) +(copy_files# hobix/*.{ml,mli}) +(copy_files# retrolix/*.{ml,mli}) +(copy_files# utilities/*.{ml,mli}) +(copy_files# x86-64/*.{ml,mli}) +(copy_files fopix/*.{mll,mly}) +(copy_files hopix/*.{mll,mly}) +(copy_files hobix/*.{mll,mly}) +(copy_files retrolix/*.{mll,mly}) +(copy_files# ../runtime/runtime.c) + +(executable + (name flap) + (libraries str unix pprint menhirLib sexplib) + (modules_without_implementation architecture hopixSyntacticSugar) + (preprocess (pps ppx_sexp_conv)) + (promote (until-clean)) +) + +(ocamllex fopixLexer hopixLexer hobixLexer retrolixLexer) +(menhir + (modules fopixParser hopixParser hobixParser retrolixParser) + (infer true) + (flags --explain --table)) + +(env (dev (flags (:standard -warn-error -A -w -9 -w -32)))) diff --git a/flap/src/elf/elf.ml b/flap/src/elf/elf.ml new file mode 100644 index 0000000..23937b4 --- /dev/null +++ b/flap/src/elf/elf.ml @@ -0,0 +1,37 @@ +(** The ELF binary format. *) + +module AST = ElfAST + +let name = "elf" + +type ast = AST.t + +let parse lexer_init input = + SyntacticAnalysis.process + ~lexer_init + ~lexer_fun:RetrolixLexer.token + ~parser_fun:RetrolixParser.program + ~input + +let no_parser () = + Error.global_error + "during source analysis" + "There is no parser for ELF in flap." + +let parse_filename _ = + no_parser () + +let extension = + ".elf" + +let executable_format = + true + +let parse_string _ = + no_parser () + +let print_ast (buf : ast) = + Buffer.contents buf + +include ElfInterpreter +include ElfTypechecker diff --git a/flap/src/elf/elfAST.ml b/flap/src/elf/elfAST.ml new file mode 100644 index 0000000..e1db2f0 --- /dev/null +++ b/flap/src/elf/elfAST.ml @@ -0,0 +1 @@ +type t = Buffer.t diff --git a/flap/src/elf/elfInitialization.ml b/flap/src/elf/elfInitialization.ml new file mode 100644 index 0000000..1959960 --- /dev/null +++ b/flap/src/elf/elfInitialization.ml @@ -0,0 +1,7 @@ +open Optimizers + +(** Register some compilers that have ELF as a target or source language. *) +let initialize () = + Languages.register (module Elf); + Compilers.register (optimizing_compiler (module X86_64toElf)); + () diff --git a/flap/src/elf/elfInterpreter.ml b/flap/src/elf/elfInterpreter.ml new file mode 100644 index 0000000..67991d0 --- /dev/null +++ b/flap/src/elf/elfInterpreter.ml @@ -0,0 +1,37 @@ +(** This module implements the interpreter for X86-64 programs. *) + +open ElfAST + +type runtime = unit + +type observable = { + exit_status : Unix.process_status; + stdout : string; + stderr : string; +} + +let initial_runtime () = () + +let show_runtime _ = () + +let evaluate (_ : runtime) (buf : t) = + (* 1. Generate a temporary .s file. + 2. Call gcc to generate an executable linked with runtime.o + 3. Execute this program, capturing its stdout/stderr + *) + let fn = Filename.chop_extension (Options.get_input_filename ()) ^ ".elf" in + let oc = open_out fn in + Buffer.output_buffer oc buf; + close_out oc; + ExtStd.Unix.add_exec_bits fn; + let exit_status, stdout, stderr = + ExtStd.Unix.output_and_error_of_command ("./" ^ fn) + in + (), { exit_status; stdout; stderr; } + +let print_observable (_ : runtime) (obs : observable) = + Printf.sprintf + "Process exited with status %s.\nSTDOUT:\n%s\nSTDERR:\n%s\n\n" + (ExtStd.Unix.string_of_process_status obs.exit_status) + obs.stdout + obs.stderr diff --git a/flap/src/elf/elfTypechecker.ml b/flap/src/elf/elfTypechecker.ml new file mode 100644 index 0000000..1b81df2 --- /dev/null +++ b/flap/src/elf/elfTypechecker.ml @@ -0,0 +1,9 @@ +(** There is no typechecker for ELF programs in flap. *) + +type typing_environment = unit + +let initial_typing_environment () = () + +let typecheck () _ast = () + +let print_typing_environment () = "" diff --git a/flap/src/elf/x86_64toElf.ml b/flap/src/elf/x86_64toElf.ml new file mode 100644 index 0000000..c33a1bc --- /dev/null +++ b/flap/src/elf/x86_64toElf.ml @@ -0,0 +1,48 @@ +module Source = X86_64 +module Target = Elf + +type environment = unit + +let initial_environment () = + () + +let installation_directory () = + Filename.dirname Sys.argv.(0) + +let gcc ~src ~tgt = + let open Filename in + let runtime = + concat (installation_directory ()) "runtime.c" + in + Printf.sprintf + "gcc -no-pie -g %s %s -o %s" + src + runtime + tgt + +let translate (p : X86_64.ast) _env = + (* 1. Generate a temporary .s file. + 2. Call gcc to generate an executable linked with runtime.o + 3. Execute this program, capturing its stdout/stderr + *) + let asmf = Filename.temp_file "flap" ".s" in + let elff = Filename.temp_file "flap" ".elf" in + let oc = open_out asmf in + PPrint.ToChannel.compact oc (X86_64_PrettyPrinter.program p); + close_out oc; + let exit_status, _, stderr = + ExtStd.Unix.output_and_error_of_command (gcc ~src:asmf ~tgt:elff) + in + if exit_status <> Unix.WEXITED 0 + then + Error.error + "ELF" + Position.dummy + (Printf.sprintf "Could not assemble or link file \"%s\":\n%s" asmf stderr) + else + let ic = open_in elff in + let b = ExtStd.Buffer.slurp ic in + close_in ic; + List.iter Sys.remove [asmf; elff]; + b, + () diff --git a/flap/src/flap.ml b/flap/src/flap.ml new file mode 100644 index 0000000..f93c7f3 --- /dev/null +++ b/flap/src/flap.ml @@ -0,0 +1,236 @@ +(** The main driver module. + + The role of this module is to have [flap] behave as the command + line options say. In particular, these options determine: + + - if the compiler is run in interactive or batch mode. + - what is the source language of the compiler. + - what is the target language of the compiler. + +*) + +(* -------------------------- *) +(* Initialization process *) +(* -------------------------- *) + +open Options + +let rec initialize () = + initialize_languages (); + initialize_options (); + initialize_prompt () + +and initialize_prompt () = + UserInput.set_prompt "flap> " + +and initialize_options () = + CommandLineOptions.initialize (); + if not (!Sys.interactive) then CommandLineOptions.parse () + +and initialize_languages () = + HopixInitialization.initialize (); + ElfInitialization.initialize (); + X86_64_Initialization.initialize (); + RetrolixInitialization.initialize (); + FopixInitialization.initialize (); + HobixInitialization.initialize () + +(** Infer source language from the extension of the input file or from the + related command line option. *) +let infer_source_language () = + if Options.is_source_language_set () + then Languages.get @@ Options.get_source_language () + else + Options.get_input_filename () + |> Filename.extension + |> Languages.get_from_extension + +(** Given the source language and the target language returns + the right compiler (as a first-class module). *) +let get_compiler () : (module Compilers.Compiler) = + let source_language = + infer_source_language () + in + let target_language = + if is_target_language_set () then + Languages.get (get_target_language ()) + else + source_language + in + let using = List.map Languages.get (Options.get_using ()) in + Compilers.get ~using source_language target_language + +(** The evaluation function evaluates some code and prints the results + into the standard output. It also benchmarks the time taken to + evaluates the code, if asked. *) +let eval runtime eval print = + let now = Unix.gettimeofday () in + let runtime, observation = eval runtime in + let elapsed_time = Unix.gettimeofday () -. now in + if Options.get_benchmark () then + Printf.eprintf "[%fs]\n" elapsed_time; + if Options.get_verbose_eval () then + print_endline (print runtime observation); + runtime + +(* -------------------- **) +(* Interactive mode *) +(* -------------------- **) +(** + + The interactive mode is a basic read-compile-eval-print loop. + +*) +let interactive_loop () = + + Printf.printf " Flap version %s\n\n%!" Version.number; + + let module Compiler = (val get_compiler () : Compilers.Compiler) in + let open Compiler in + + let read () = + initialize_prompt (); + let b = Buffer.create 13 in + let rec read prev = + let c = UserInput.input_char stdin in + if c = "\n" then + if prev <> "\\" then ( + Buffer.add_string b prev; + Buffer.contents b + ) else ( + UserInput.set_prompt "....> "; + read c + ) + else ( + Buffer.add_string b prev; + read c + ) + in + read "" + in + + let rec step + : Target.runtime -> Compiler.environment -> Source.typing_environment + -> Target.runtime * Compiler.environment * Source.typing_environment = + fun runtime cenvironment tenvironment -> + try + match read () with + | "+debug" -> + Options.set_verbose_mode true; + step runtime cenvironment tenvironment + + | "-debug" -> + Options.set_verbose_mode false; + step runtime cenvironment tenvironment + + | input -> + let ast = Compiler.Source.parse_string input in + let tenvironment = + if Options.get_unsafe () then + tenvironment + else + Compiler.Source.typecheck tenvironment ast + in + let cast, cenvironment = Compiler.translate ast cenvironment in + if Options.get_verbose_mode () then + print_endline (Target.print_ast cast); + let runtime = Compiler.Target.( + eval runtime (fun r -> evaluate r cast) print_observable + ) + in + step runtime cenvironment tenvironment + with + | e when !Sys.interactive -> raise e (* display exception at toplevel *) + | Error.Error (positions, msg) -> + output_string stdout (Error.print_error positions msg); + step runtime cenvironment tenvironment + | End_of_file -> + (runtime, cenvironment, tenvironment) + | e -> + print_endline (Printexc.get_backtrace ()); + print_endline (Printexc.to_string e); + step runtime cenvironment tenvironment + in + Error.resume_on_error (); + ignore (step + (Target.initial_runtime ()) + (Compiler.initial_environment ()) + (Source.initial_typing_environment ()) + ) + +(* ------------- **) +(* Batch mode *) +(* ------------- **) +(** + + In batch mode, the compiler loads a file written in the source + language and produces a file written in the target language. + + The filename of the output file is determined by the basename + of the input filename concatenated with the extension of the + target language. + + If the running mode is set, the compiler will also interpret + the compiled code. + +*) +let batch_compilation () = + Error.exit_on_error (); + let module Compiler = (val get_compiler () : Compilers.Compiler) in + let open Compiler in + let input_filename = Options.get_input_filename () in + let module_name = Filename.chop_extension input_filename in + let ast = Source.parse_filename input_filename in + if not (Options.get_unsafe ()) then + Compiler.Source.( + let tenv = typecheck (initial_typing_environment ()) ast in + if Options.get_show_types () then ( + print_endline (print_typing_environment tenv) + ) + ); + let cast, _ = Compiler.(translate ast (initial_environment ())) in + let output_filename = + if Options.get_output_file () = "" then + let output_filename = module_name ^ Target.extension in + if output_filename = input_filename then + module_name ^ Target.extension ^ "-optimized" + else + output_filename + else + Options.get_output_file () + in + if Options.get_verbose_mode () then + output_string stdout (Target.print_ast cast ^ "\n"); + if not (Options.get_dry_mode () || output_filename = input_filename) then ( + let cout = open_out output_filename in + output_string cout (Target.print_ast cast); + close_out cout; + if Target.executable_format then ExtStd.Unix.add_exec_bits output_filename; + ); + if Options.get_running_mode () then Compiler.Target.( + ignore ( + try + let print = + if Options.get_verbose_eval () then + print_observable + else + fun _ _ -> "" + in + eval (initial_runtime ()) (fun r -> evaluate r cast) print + with + | e -> + print_endline (Printexc.get_backtrace ()); + print_endline (Printexc.to_string e); + exit 1 + ) + ) + +(** -------------- **) +(** Entry point *) +(** -------------- **) +let main = + initialize (); + match get_mode () with + | _ when !Sys.interactive -> () + | Interactive -> interactive_loop () + | Batch -> batch_compilation () diff --git a/flap/src/fopix/fopix.ml b/flap/src/fopix/fopix.ml new file mode 100644 index 0000000..5f8aff0 --- /dev/null +++ b/flap/src/fopix/fopix.ml @@ -0,0 +1,32 @@ +(** The fopix programming language. *) + +module AST = FopixAST + +let name = "fopix" + +type ast = FopixAST.t + +let parse lexer_init input = + SyntacticAnalysis.process + ~lexer_init + ~lexer_fun:FopixLexer.token + ~parser_fun:FopixParser.program + ~input + +let parse_filename filename = + parse Lexing.from_channel (open_in filename) + +let extension = + ".fopix" + +let executable_format = + false + +let parse_string = + parse Lexing.from_string + +let print_ast ast = + FopixPrettyPrinter.(to_string program ast) + +include FopixInterpreter +include FopixTypechecker diff --git a/flap/src/fopix/fopixAST.ml b/flap/src/fopix/fopixAST.ml new file mode 100644 index 0000000..e649413 --- /dev/null +++ b/flap/src/fopix/fopixAST.ml @@ -0,0 +1,65 @@ +(** The abstract syntax tree for Fopix programs. *) + +(** + + Fopix is a first order language. + + Like the C language, Fopix only allows toplevel functions. These + functions can be called directly by using their names in the source + code or indirectly by means of (dynamically computed) function + pointers. Toplevel functions are mutually recursive. + + As in C, the control-flow can be structured by loops, + conditionals and switchs. + + Contrary to C, Fopix does not make a distinction between statements + and expressions. Besides, the notion of variable is similar to the + one of functional language: variables are immutable. + +*) + +type program = definition list + +and definition = + (** [val x = e] *) + | DefineValue of identifier * expression + (** [def f (x1, ..., xN) = e] *) + | DefineFunction of function_identifier * formals * expression + (** [external f : arity] *) + | ExternalFunction of function_identifier * int + +and expression = + (** [0, 1, 2, ], ['a', 'b', ...], ["Dalek", "Master", ...] *) + | Literal of literal + (** [x, y, z, ginette] *) + | Variable of identifier + (** [val x = e1; e2] *) + | Define of identifier * expression * expression + (** [f (e1, .., eN)] *) + | FunCall of function_identifier * expression list + (** [call e with (e1, .., eN)] *) + | UnknownFunCall of expression * expression list + (** [while e do e' end] *) + | While of expression * expression + (** [if e then e1 else e2 end] *) + | IfThenElse of expression * expression * expression + (** [switch e in c1 | c2 | .. | cN orelse e_default end] + where [ci := ! | e]. *) + | Switch of expression * expression option array * expression option + +and literal = + | LInt of Mint.t + | LString of string + | LChar of char + | LFun of function_identifier + +and identifier = + | Id of string + +and formals = + identifier list + +and function_identifier = + | FunId of string + +and t = program diff --git a/flap/src/fopix/fopixInitialization.ml b/flap/src/fopix/fopixInitialization.ml new file mode 100644 index 0000000..dd6435c --- /dev/null +++ b/flap/src/fopix/fopixInitialization.ml @@ -0,0 +1,4 @@ +let initialize () = + Languages.register (module Fopix); + Compilers.register (module Compilers.Identity (Fopix)); + Compilers.register (module HobixToFopix) diff --git a/flap/src/fopix/fopixInterpreter.ml b/flap/src/fopix/fopixInterpreter.ml new file mode 100644 index 0000000..51fae11 --- /dev/null +++ b/flap/src/fopix/fopixInterpreter.ml @@ -0,0 +1,395 @@ +open Error +open FopixAST + +(** [error pos msg] reports runtime error messages. *) +let error positions msg = + errorN "execution" positions msg + +(** Every expression of fopi evaluates into a [value]. *) +type value = + | VUnit + | VInt of Mint.t + | VBool of bool + | VChar of char + | VString of string + | VAddress of Memory.location + | VFun of function_identifier + +type 'a coercion = value -> 'a option +let value_as_int = function VInt x -> Some x | _ -> None +let value_as_bool = function VBool x -> Some x | _ -> None +let value_as_address = function VAddress x -> Some x | _ -> None +let value_as_unit = function VUnit -> Some () | _ -> None + +type 'a wrapper = 'a -> value +let int_as_value x = VInt x +let bool_as_value x = VBool x +let address_as_value x = VAddress x +let unit_as_value () = VUnit + +let print_value m v = + let max_depth = 5 in + + let rec print_value d v = + if d >= max_depth then "..." else + match v with + | VInt x -> + Mint.to_string x + | VBool true -> + "true" + | VBool false -> + "false" + | VChar c -> + "'" ^ Char.escaped c ^ "'" + | VString s -> + "\"" ^ String.escaped s ^ "\"" + | VUnit -> + "()" + | VAddress a -> + print_block m d a + | VFun _ -> + "" + and print_block m d a = + let b = Memory.dereference m a in + let vs = Array.to_list (Memory.array_of_block b) in + "[ " ^ String.concat "; " (List.map (print_value (d + 1)) vs) ^ " ]" + in + print_value 0 v + +module Environment : sig + type t + val initial : t + val bind : t -> identifier -> value -> t + exception UnboundIdentifier of identifier + val lookup : identifier -> t -> value + val last : t -> (identifier * value * t) option + val print : value Memory.t -> t -> string +end = struct + type t = (identifier * value) list + + let initial = [] + + let bind e x v = (x, v) :: e + + exception UnboundIdentifier of identifier + + let _ = + Printexc.register_printer (function + | UnboundIdentifier (Id x) -> + Some (Printf.sprintf "Unbound identifier %s" x) + | _ -> + None + ) + + let lookup x e = + try + List.assoc x e + with Not_found -> + raise (UnboundIdentifier x) + + let last = function + | [] -> None + | (x, v) :: e -> Some (x, v, e) + + let print_binding memory (Id x, v) = + (* Identifiers starting with '_' are reserved for the compiler. + Their values must not be observable by users. *) + if x.[0] = '_' then + "" + else + x ^ " = " ^ print_value memory v + + let print memory env = + String.concat "\n" ( + List.(filter (fun s -> s <> "") (map (print_binding memory) env)) + ) + +end + +type runtime = { + memory : value Memory.t; + environment : Environment.t; + functions : (function_identifier * (formals * expression)) list; +} + +type observable = { + new_environment : Environment.t; + } + +let initial_runtime () = + let bind_bool s b env = Environment.bind env (Id s) (VBool b) in + let bind_unit s env = Environment.bind env (Id s) VUnit in + { + memory = Memory.create (640 * 1024); + environment = + Environment.initial + |> bind_bool "true" true + |> bind_bool "false" false + |> bind_unit "nothing"; + functions = []; + } + +let rec evaluate runtime ast = + let runtime = List.fold_left bind_function runtime ast in + let runtime' = List.fold_left declaration runtime ast in + (runtime', extract_observable runtime runtime') + +and bind_function runtime = function + | DefineValue _ -> + runtime + + | DefineFunction (f, xs, e) -> + { runtime with + functions = (f, (xs, e)) :: runtime.functions + } + + | ExternalFunction _ -> + runtime + +and declaration runtime = function + | DefineValue (i, e) -> + let v = expression runtime e in + { runtime with environment = Environment.bind runtime.environment i v } + | DefineFunction _ -> + runtime + | ExternalFunction _ -> + runtime + +and arith_operator_of_symbol = function + | "`+`" -> Mint.add + | "`-`" -> Mint.sub + | "`/`" -> Mint.div + | "`*`" -> Mint.mul + | _ -> assert false + +and cmp_operator_of_symbol = function + | "` ( < ) + | "`>?`" -> ( > ) + | "`<=?`" -> ( <= ) + | "`>=?`" -> ( >= ) + | "`=?`" -> ( = ) + | _ -> assert false + +and boolean_operator_of_symbol = function + | "`&&`" -> ( && ) + | "`||`" -> ( || ) + | _ -> assert false + +and evaluation_of_binary_symbol environment = function + | ("`+`" | "`-`" | "`*`" | "`/`") as s -> + arith_binop environment (arith_operator_of_symbol s) + | ("`?`" | "`<=?`" | "`>=?`" | "`=?`") as s -> + arith_cmpop environment (cmp_operator_of_symbol s) + | _ -> assert false + +and is_binary_primitive = function + | "`+`" | "`-`" | "`*`" | "`/`" | "`?`" | "`<=?`" | "`>=?`" | "`=?`" + | "`&&`" | "`||`" -> true + | _ -> false + +and expression runtime = function + | Literal l -> + literal l + + | Variable (Id "true") -> + VBool true + + | Variable (Id "false") -> + VBool false + + | Variable x -> + Environment.lookup x runtime.environment + + | While (cond, e) -> + let rec loop () = + match expression runtime cond with + | VBool true -> + ignore (expression runtime e); + loop () + | VBool false -> + () + | _ -> + assert false (* By typing. *) + in + loop (); + VUnit + + | Switch (e, bs, default) -> + begin match value_as_int (expression runtime e) with + | None -> error [] "Switch on integers only." + | Some i -> + let i = Mint.to_int i in + if i < Array.length bs && bs.(i) <> None then + match bs.(i) with + | None -> assert false (* By condition. *) + | Some t -> expression runtime t + else match default with + | Some t -> expression runtime t + | None -> error [] "No default case in switch." + end + + | IfThenElse (c, t, f) -> + begin match value_as_bool (expression runtime c) with + | Some true -> expression runtime t + | Some false -> expression runtime f + | None -> error [] "Condition is not a boolean." + end + + | Define (x, ex, e) -> + let v = expression runtime ex in + let runtime = { runtime with + environment = Environment.bind runtime.environment x v + } + in + expression runtime e + + | FunCall (FunId "allocate_block", [size]) -> + begin match value_as_int (expression runtime size) with + | Some size -> + let a = Memory.allocate runtime.memory size VUnit in + VAddress a + | None -> + error [] "A block size should be an integer." + end + + | (FunCall (FunId "read_block", [location; index])) as e -> + begin match + (value_as_address (expression runtime location), + value_as_int (expression runtime index)) + with + | Some location, Some index -> + let block = Memory.dereference runtime.memory location in + Memory.read block index + | None, _ -> + error [] (Printf.sprintf "Expecting a block while evaluating %s" (FopixPrettyPrinter.(to_string expression e))) + | _, None -> + error [] "Expecting an integer." + end + + | FunCall (FunId "equal_string", [e1; e2]) -> + begin match expression runtime e1, expression runtime e2 with + | VString s1, VString s2 -> VBool (String.compare s1 s2 = 0) + | _ -> assert false (* By typing. *) + end + + | FunCall (FunId "equal_char", [e1; e2]) -> + begin match expression runtime e1, expression runtime e2 with + | VChar s1, VChar s2 -> VBool (Char.compare s1 s2 = 0) + | _ -> assert false (* By typing. *) + end + + | FunCall (FunId ("observe_int" | "print_int"), [e]) -> + begin match expression runtime e with + | VInt x -> + ignore (print_string (Mint.to_string x)); + VUnit + | _ -> assert false (* By typing. *) + end + + | FunCall (FunId "print_string", [e]) -> + begin match expression runtime e with + | VString s -> print_string s + | _ -> assert false (* By typing. *) + end + + | FunCall (FunId "write_block", [location; index; e]) -> + begin match + (value_as_address (expression runtime location), + value_as_int (expression runtime index)) + with + | Some location, Some index -> + let v = expression runtime e in + let block = Memory.dereference runtime.memory location in + Memory.write block index v; + VUnit + | None, _ -> + error [] "Expecting a block." + | _, None -> + error [] "Expecting an integer." + end + + | FunCall (FunId (("`&&`" | "`||`") as binop), [e1; e2]) -> + begin match expression runtime e1, binop with + | VBool true, "`&&`" | VBool false, "`||`" -> expression runtime e2 + | VBool false, "`&&`" -> VBool false + | VBool true, "`||`" -> VBool true + | _, _ -> assert false (* By typing. *) + end + + | FunCall (FunId s, [e1; e2]) when is_binary_primitive s -> + evaluation_of_binary_symbol runtime s e1 e2 + + | FunCall (f, arguments) -> + let vs = List.map (expression runtime) arguments in + let (formals, body) = try + List.assoc f runtime.functions + with Not_found -> + let FunId f = f in + error [] (Printf.sprintf "Unbound function `%s'." f) + in + let runtime = + { runtime with + environment = + Environment.(List.fold_left2 bind runtime.environment formals vs) + } + in + expression runtime body + + | UnknownFunCall (e, arguments) -> + begin match expression runtime e with + | VFun f -> + expression runtime (FunCall (f, arguments)) + | _ -> + assert false (* By construction. *) + end + +and binop +: type a b. + _ -> string -> + a coercion -> b wrapper -> _ -> (a -> a -> b) -> _ -> _ -> value += fun m kind coerce wrap runtime op l r -> + let lv = expression runtime l + and rv = expression runtime r in + match coerce lv, coerce rv with + | Some li, Some ri -> + wrap (op li ri) + | _, _ -> + error [] (Printf.sprintf "Invalid %s binary operation between %s and %s." + kind (print_value m lv) (print_value m rv)) + +and arith_binop env = + binop env.memory "arithmetic" value_as_int int_as_value env +and arith_cmpop env = + binop env.memory "comparison" value_as_int bool_as_value env +and boolean_binop env = + binop env.memory "boolean" value_as_bool bool_as_value env + +and literal = function + | LInt x -> VInt x + | LString s -> VString s + | LChar c -> VChar c + | LFun f -> VFun f + +and print_string s = + output_string stdout s; + flush stdout; + VUnit + +and extract_observable runtime runtime' = + let rec substract new_environment env env' = + if env == env' then new_environment + else + match Environment.last env' with + | None -> assert false (* Absurd. *) + | Some (x, v, env') -> + let new_environment = Environment.bind new_environment x v in + substract new_environment env env' + in + { + new_environment = + substract Environment.initial runtime.environment runtime'.environment + } + +let print_observable runtime observation = + Environment.print runtime.memory observation.new_environment diff --git a/flap/src/fopix/fopixLexer.mll b/flap/src/fopix/fopixLexer.mll new file mode 100644 index 0000000..073520e --- /dev/null +++ b/flap/src/fopix/fopixLexer.mll @@ -0,0 +1,111 @@ +{ (* Emacs, be a -*- tuareg -*- to open this file. *) + open Lexing + open Error + open Position + open FopixParser + + let next_line_and f lexbuf = + Lexing.new_line lexbuf; + f lexbuf + + let error lexbuf = + error "during lexing" (lex_join lexbuf.lex_start_p lexbuf.lex_curr_p) + +} + +let newline = ('\010' | '\013' | "\013\010") + +let blank = [' ' '\009' '\012'] + +let digit = ['0'-'9'] + +let lowercase_alpha = ['a'-'z' '_'] + +let uppercase_alpha = ['A'-'Z' '_'] + +let alpha = lowercase_alpha | uppercase_alpha + +let alphanum = alpha | digit | '_' + +let identifier = alpha alphanum* + +rule token = parse + (** Layout *) + | newline { next_line_and token lexbuf } + | blank+ { token lexbuf } + | "/*" { comment 1 lexbuf } + + (** Keywords *) + | "val" { VAL } + | "in" { IN } + | "def" { DEF } + | "end" { END } + | "if" { IF } + | "then" { THEN } + | "else" { ELSE } + | "eval" { EVAL } + | "external" { EXTERNAL } + | "switch" { SWITCH } + | "call" { CALL } + | "with" { WITH } + | "orelse" { ORELSE } + | "while" { WHILE } + | "do" { DO } + + (** Literals *) + | digit+ as d { INT (Mint.of_string d) } + + (** Identifiers *) + | identifier as i { ID i } + + (** Infix operators *) + | "=" { EQUAL } + | ":" { COLON } + | "+" { PLUS } + | "*" { STAR } + | "/" { SLASH } + | "-" { MINUS } + | "=?" { EQ } + | ">?" { GT } + | ">=?" { GTE } + | " INT +%token ID + +%right SEMICOLON +%nonassoc ASSIGNS +%left LOR +%left LAND +%nonassoc GT GTE LT LTE EQ +%left PLUS MINUS +%left STAR SLASH +%nonassoc LBRACKET + +%start program + +%% + +program: ds=definition* EOF +{ + ds +} +| error { + let pos = Position.lex_join $startpos $endpos in + Error.error "parsing" pos "Syntax error." +} + +definition: VAL x=located(identifier) EQUAL e=located(expression) +{ + DefineValue (x, e) +} +| DEF f=located(function_identifier) + LPAREN xs=separated_list(COMMA, identifier) RPAREN + EQUAL e=located(expression) +{ + DefineFunction (f, xs, e) +} +| EVAL e=located(expression) +{ + DefineValue (Id "_", e) +} +| EXTERNAL f=located(function_identifier) COLON n=INT +{ + ExternalFunction (f, Int64.to_int n) +} + +expression: + l=literal +{ + Literal l +} +| x=identifier +{ + Variable x +} +| VAL x=located(identifier) + EQUAL + e1=located(expression) + SEMICOLON + e2=located(expression) +{ + Define (x, e1, e2) +} +| IF + c=located(expression) + THEN t=located(expression) + ELSE f=located(expression) + END +{ + IfThenElse (c, t, f) +} +| f=function_identifier + LPAREN es=separated_list(COMMA, located(expression)) RPAREN +{ + FunCall (f, es) +} +| l=located(expression) b=binop r=located(expression) { + FunCall (FunId b, [l; r]) +} +| CALL f=located(expression) WITH LPAREN es=separated_list(COMMA, located(expression)) RPAREN +{ + UnknownFunCall (f, es) +} +| e=located(expression) LBRACKET i=located(expression) RBRACKET { + FunCall (FunId "read_block", [e; i]) +} +| e=located(expression) + LBRACKET i=located(expression) RBRACKET + ASSIGNS v=located(expression) { + FunCall (FunId "write_block", [e; i; v]) +} +| e1=located(expression) SEMICOLON e2=located(expression) { + Define (Id "_", e1, e2) +} +| WHILE e=expression DO b=expression END +{ + While (e, b) +} +| SWITCH e=expression IN + bs=separated_list(PIPE, optional_case) + ORELSE d=expression + END +{ + Switch (e, Array.of_list bs, Some d) +} +| SWITCH e=expression IN bs=separated_list(PIPE, optional_case) END +{ + Switch (e, Array.of_list bs, None) +} +| LPAREN e=expression RPAREN { + e +} + +optional_case: + BANG +{ + None +} +| e=expression +{ + Some e +} + +%inline binop: + PLUS { "`+`" } +| MINUS { "`-`" } +| STAR { "`*`" } +| SLASH { "`/`" } +| GT { "`>?`" } +| GTE { "`>=?`" } +| LT { "` + nest 2 ( + group (string "val" ++ identifier x ++ string "=") + ++ group (expression e) + ) + + | DefineFunction (f, xs, e) -> + nest 2 ( + group (string "def" ++ function_identifier f + ++ PPrint.OCaml.tuple (List.map identifier xs) + ++ string "=") + ++ group (expression e) + ) + + | ExternalFunction (f, n) -> + group (string "external" ++ function_identifier f + ++ string ":" ++ string (string_of_int n)) + +and identifier (Id x) = + string x + +and function_identifier (FunId x) = + string x + +and expression = function + | Literal l -> + literal l + | Variable x -> + identifier x + | FunCall (FunId f, es) -> + funcall f es + | While (cond, e) -> + nest 2 ( + group (string "while" + ++ group (expression cond) + ++ string "do" + ++ group (expression e) + ++ string "done") + ) + | IfThenElse (c, t, f) -> + nest 2 ( + group (string "if" + ++ group (expression c) + ++ string "then" + ) + ++ group (expression t)) + ++ nest 2 ( + group (string "else" + ++ group (expression f)) + ) + ++ string "end" + | Define (x, e1, e2) -> + nest 2 ( + group ( + group (string "val" + ++ identifier x + ++ string "=" + ) + ++ group (expression e1) + ++ string ";" + ) + ) + ++ group (expression e2) + | UnknownFunCall (e, es) -> + string "call" ++ parens (expression e) ++ string "with" + ++ PPrint.OCaml.tuple (List.map expression es) + | Switch (e, bs, default) -> + group (string "switch" ++ expression e ++ string "in") + ++ group ( + branches bs + ) ^^ begin match default with + | None -> empty + | Some t -> break 1 ^^ group (string "orelse" ++ expression t) + end ++ string "end" + +and branches bs = + let bs = List.mapi (fun i x -> (i, x)) (Array.to_list bs) in + separate_map (string "|" ^^ break 1) (fun (i, t) -> + group ( + string (string_of_int i) ^^ match t with + | None -> string "!" + | Some t -> expression t) + ) bs + +and funcall f es = + match f, es with + | ("`=?`" | "`*`" | "`/`" | "`+`" | "`-`" | "`%`" + | "`?`" | "`<=?`" | "`>=?`"), + [ lhs; rhs ] -> + let op = String.(sub f 1 (length f - 2)) in + group (parens (expression lhs ++ string op ++ expression rhs)) + | _, _ -> + let ts = PPrint.OCaml.tuple (List.map expression es) in + group (string f ++ ts) + +and literal = function + | LInt x -> + int x + | LChar c -> + char c + | LString s -> + string_literal s + | LFun (FunId f) -> + string ("&" ^ f) + +and char c = + group (string "'" ^^ string (Char.escaped c) ^^ string "'") + +and string_literal s = + group (string "\"" ^^ string (String.escaped s) ^^ string "\"") + +and int x = + string (Mint.to_string x) + +let to_string f x = + let b = Buffer.create 13 in + ToBuffer.pretty 0.7 80 b (f x); + Buffer.contents b diff --git a/flap/src/fopix/fopixTypechecker.ml b/flap/src/fopix/fopixTypechecker.ml new file mode 100644 index 0000000..bbbdc55 --- /dev/null +++ b/flap/src/fopix/fopixTypechecker.ml @@ -0,0 +1,7 @@ +type typing_environment = unit + +let initial_typing_environment () = () + +let typecheck () _ = () + +let print_typing_environment () = "" diff --git a/flap/src/fopix/hobixToFopix.ml b/flap/src/fopix/hobixToFopix.ml new file mode 100644 index 0000000..478622a --- /dev/null +++ b/flap/src/fopix/hobixToFopix.ml @@ -0,0 +1,297 @@ +(** This module implements a compiler from Hobix to Fopix. *) + +(** As in any module that implements {!Compilers.Compiler}, the source + language and the target language must be specified. *) + +module Source = Hobix +module S = Source.AST +module Target = Fopix +module T = Target.AST + +(** + + The translation from Hobix to Fopix turns anonymous + lambda-abstractions into toplevel functions and applications into + function calls. In other words, it translates a high-level language + (like OCaml) into a first order language (like C). + + To do so, we follow the closure conversion technique. + + The idea is to make explicit the construction of closures, which + represent functions as first-class objects. A closure is a block + that contains a code pointer to a toplevel function [f] followed by all + the values needed to execute the body of [f]. For instance, consider + the following OCaml code: + + let f = + let x = 6 * 7 in + let z = x + 1 in + fun y -> x + y * z + + The values needed to execute the function "fun y -> x + y * z" are + its free variables "x" and "z". The same program with explicit usage + of closure can be written like this: + + let g y env = env[1] + y * env[2] + let f = + let x = 6 * 7 in + let z = x + 1 in + [| g; x; z |] + + (in an imaginary OCaml in which arrays are untyped.) + + Once closures are explicited, there are no more anonymous functions! + + But, wait, how to we call such a function? Let us see that on an + example: + + let f = ... (* As in the previous example *) + let u = f 0 + + The application "f 0" must be turned into an expression in which + "f" is a closure and the call to "f" is replaced to a call to "g" + with the proper arguments. The argument "y" of "g" is known from + the application: it is "0". Now, where is "env"? Easy! It is the + closure itself! We get: + + let g y env = env[1] + y * env[2] + let f = + let x = 6 * 7 in + let z = x + 1 in + [| g; x; z |] + let u = f[0] 0 f + + (Remark: Did you notice that this form of "auto-application" is + very similar to the way "this" is defined in object-oriented + programming languages?) + +*) + +(** + Helpers functions. +*) + +let error pos msg = + Error.error "compilation" pos msg + +let make_fresh_variable = + let r = ref 0 in + fun () -> incr r; T.Id (Printf.sprintf "_%d" !r) + + +let make_fresh_function_identifier = + let r = ref 0 in + fun () -> incr r; T.FunId (Printf.sprintf "_%d" !r) + +let define e f = + let x = make_fresh_variable () in + T.Define (x, e, f x) + +let rec defines ds e = + match ds with + | [] -> + e + | (x, d) :: ds -> + T.Define (x, d, defines ds e) + +let seq a b = + define a (fun _ -> b) + +let rec seqs = function + | [] -> assert false + | [x] -> x + | x :: xs -> seq x (seqs xs) + +let allocate_block e = + T.(FunCall (FunId "allocate_block", [e])) + +let write_block e i v = + T.(FunCall (FunId "write_block", [e; i; v])) + +let read_block e i = + T.(FunCall (FunId "read_block", [e; i])) + +let lint i = + T.(Literal (LInt (Int64.of_int i))) + + +(** [free_variables e] returns the list of free variables that + occur in [e].*) +let free_variables = + let module M = + Set.Make (struct type t = S.identifier let compare = compare end) + in + let rec unions f = function + | [] -> M.empty + | [s] -> f s + | s :: xs -> M.union (f s) (unions f xs) + in + let rec fvs = function + | S.Literal _ -> + M.empty + | S.Variable x -> + M.singleton x + | S.While (cond, e) -> + failwith "Students! This is your job!" + | S.Define (vd, a) -> + failwith "Students! This is your job!" + | S.ReadBlock (a, b) -> + unions fvs [a; b] + | S.Apply (a, b) -> + unions fvs (a :: b) + | S.WriteBlock (a, b, c) | S.IfThenElse (a, b, c) -> + unions fvs [a; b; c] + | S.AllocateBlock a -> + fvs a + | S.Fun (xs, e) -> + failwith "Students! This is your job!" + | S.Switch (a, b, c) -> + let c = match c with None -> [] | Some c -> [c] in + unions fvs (a :: ExtStd.Array.present_to_list b @ c) + in + fun e -> M.elements (fvs e) + +(** + + A closure compilation environment relates an identifier to the way + it is accessed in the compiled version of the function's + body. + + Indeed, consider the following example. Imagine that the following + function is to be compiled: + + fun x -> x + y + + In that case, the closure compilation environment will contain: + + x -> x + y -> "the code that extract the value of y from the closure environment" + + Indeed, "x" is a local variable that can be accessed directly in + the compiled version of this function's body whereas "y" is a free + variable whose value must be retrieved from the closure's + environment. + +*) +type environment = { + vars : (HobixAST.identifier, FopixAST.expression) Dict.t; + externals : (HobixAST.identifier, int) Dict.t; +} + +let initial_environment () = + { vars = Dict.empty; externals = Dict.empty } + +let bind_external id n env = + { env with externals = Dict.insert id n env.externals } + +let is_external id env = + Dict.lookup id env.externals <> None + +let reset_vars env = + { env with vars = Dict.empty } + +(** Precondition: [is_external id env = true]. *) +let arity_of_external id env = + match Dict.lookup id env.externals with + | Some n -> n + | None -> assert false (* By is_external. *) + + +(** [translate p env] turns an Hobix program [p] into a Fopix program + using [env] to retrieve contextual information. *) +let translate (p : S.t) env = + let rec program env defs = + let env, defs = ExtStd.List.foldmap definition env defs in + (List.flatten defs, env) + and definition env = function + | S.DeclareExtern (id, n) -> + let env = bind_external id n env in + (env, [T.ExternalFunction (function_identifier id, n)]) + | S.DefineValue vd -> + (env, value_definition env vd) + and value_definition env = function + | S.SimpleValue (x, e) -> + let fs, e = expression (reset_vars env) e in + fs @ [T.DefineValue (identifier x, e)] + | S.RecFunctions fdefs -> + let fs, defs = define_recursive_functions fdefs in + fs @ List.map (fun (x, e) -> T.DefineValue (x, e)) defs + + and define_recursive_functions rdefs = + failwith "Students! This is your job!" + and expression env = function + | S.Literal l -> + [], T.Literal (literal l) + | S.While (cond, e) -> + let cfs, cond = expression env cond in + let efs, e = expression env e in + cfs @ efs, T.While (cond, e) + | S.Variable x -> + let xc = + match Dict.lookup x env.vars with + | None -> T.Variable (identifier x) + | Some e -> e + in + ([], xc) + | S.Define (vdef, a) -> + failwith "Students! This is your job!" + | S.Apply (a, bs) -> + failwith "Students! This is your job!" + | S.IfThenElse (a, b, c) -> + let afs, a = expression env a in + let bfs, b = expression env b in + let cfs, c = expression env c in + afs @ bfs @ cfs, T.IfThenElse (a, b, c) + + | S.Fun (x, e) -> + failwith "Students! This is your job!" + | S.AllocateBlock a -> + let afs, a = expression env a in + (afs, allocate_block a) + | S.WriteBlock (a, b, c) -> + let afs, a = expression env a in + let bfs, b = expression env b in + let cfs, c = expression env c in + afs @ bfs @ cfs, + T.FunCall (T.FunId "write_block", [a; b; c]) + | S.ReadBlock (a, b) -> + let afs, a = expression env a in + let bfs, b = expression env b in + afs @ bfs, + T.FunCall (T.FunId "read_block", [a; b]) + | S.Switch (a, bs, default) -> + let afs, a = expression env a in + let bsfs, bs = + ExtStd.List.foldmap (fun bs t -> + match ExtStd.Option.map (expression env) t with + | None -> (bs, None) + | Some (bs', t') -> (bs @ bs', Some t') + ) [] (Array.to_list bs) + in + let dfs, default = match default with + | None -> [], None + | Some e -> let bs, e = expression env e in bs, Some e + in + afs @ bsfs @ dfs, + T.Switch (a, Array.of_list bs, default) + + + and expressions env = function + | [] -> + [], [] + | e :: es -> + let efs, es = expressions env es in + let fs, e = expression env e in + fs @ efs, e :: es + + and literal = function + | S.LInt x -> T.LInt x + | S.LString s -> T.LString s + | S.LChar c -> T.LChar c + + and identifier (S.Id x) = T.Id x + + and function_identifier (S.Id x) = T.FunId x + + in + program env p diff --git a/flap/src/hobix/HobixParser.mly b/flap/src/hobix/HobixParser.mly new file mode 100644 index 0000000..1e6e8f3 --- /dev/null +++ b/flap/src/hobix/HobixParser.mly @@ -0,0 +1,21 @@ +%{ + + open HopixAST + + +%} + +%token EOF +%token INT + + +%start program + +%% + +program: EOF +{ + [] +} + + diff --git a/flap/src/hobix/hobix.ml b/flap/src/hobix/hobix.ml new file mode 100644 index 0000000..d9e642f --- /dev/null +++ b/flap/src/hobix/hobix.ml @@ -0,0 +1,35 @@ +(** The hobix programming language. *) + +let name = "hobix" + +module AST = HobixAST + +type ast = HobixAST.t + +let executable_format = false + +let parse lexer_init input = + SyntacticAnalysis.process + ~lexer_init + ~lexer_fun:HobixLexer.token + ~parser_fun:HobixParser.program + ~input + +let parse_filename filename = + parse Lexing.from_channel (open_in filename) + +let extension = + ".hobix" + +let parse_string s = + parse Lexing.from_string s + +let print_ast ast = + HobixPrettyPrinter.(to_string program ast) + +let print_expression e = + HobixPrettyPrinter.(to_string expression e) + +include HobixInterpreter + +include HobixTypechecker diff --git a/flap/src/hobix/hobixAST.ml b/flap/src/hobix/hobixAST.ml new file mode 100644 index 0000000..4fa169b --- /dev/null +++ b/flap/src/hobix/hobixAST.ml @@ -0,0 +1,51 @@ +(** The abstract syntax tree for hobix programs. *) + +(** A program is a list of definitions. *) +type program = definition list + +and definition = + (** A toplevel declaration for an external value of arity n. *) + | DeclareExtern of identifier * int + (** A toplevel definition for a value. *) + | DefineValue of value_definition + +and value_definition = + (** A simple (non recursive) value definition. *) + | SimpleValue of identifier * expression + (** A definition for mutually recursive functions. *) + | RecFunctions of (identifier * expression) list + +and expression = + (** A literal is a constant written "as is". *) + | Literal of literal + (** A variable identifies a value. *) + | Variable of identifier + (** A local definition [val x₁ := e₁ ; e₂]. *) + | Define of value_definition * expression + (** A function application [a (b_1, ..., b_N)]. *) + | Apply of expression * expression list + (** A conditional expression of the form [if ... then ... else ... fi]. *) + | IfThenElse of expression * expression * expression + (** An anonymous function [ \ x => e ]. *) + | Fun of identifier list * expression + (** Allocate a block of size n [ alloc_block n ]. *) + | AllocateBlock of expression + (** Write a value v at offset i of block b [ alloc_write b i v ]. *) + | WriteBlock of expression * expression * expression + (** Read a value at offset i of block b [ alloc_read b i ]. *) + | ReadBlock of expression * expression + (** Jump to the i-th branch if i < |bs|, jump to default otherwise + if it is present. [switch i in bs orelse default] *) + | Switch of expression * expression option array * expression option + (** While-loop *) + | While of expression * expression + +and literal = + | LInt of Int64.t + | LString of string + | LChar of char + +and identifier = + | Id of string + +and t = program diff --git a/flap/src/hobix/hobixInitialization.ml b/flap/src/hobix/hobixInitialization.ml new file mode 100644 index 0000000..02c6da3 --- /dev/null +++ b/flap/src/hobix/hobixInitialization.ml @@ -0,0 +1,4 @@ +let initialize () = + Languages.register (module Hobix); + Compilers.register (module HopixToHobix); + Compilers.register (module Compilers.Identity (Hobix)) diff --git a/flap/src/hobix/hobixInterpreter.ml b/flap/src/hobix/hobixInterpreter.ml new file mode 100644 index 0000000..d00705b --- /dev/null +++ b/flap/src/hobix/hobixInterpreter.ml @@ -0,0 +1,418 @@ +open Error +open HobixAST + +(** [error pos msg] reports runtime error messages. *) +let error positions msg = + errorN "execution" positions msg + +(** Every expression of hobix evaluates into a [value]. *) +type 'e gvalue = + | VInt of Int64.t + | VChar of char + | VString of string + | VUnit + | VAddress of Memory.location + | VPrimitive of string * ('e gvalue list -> 'e gvalue) + | VBool of bool + | VFun of identifier list * expression * 'e + +type ('a, 'e) coercion = 'e gvalue -> 'a option +let value_as_int = function VInt x -> Some x | _ -> None +let value_as_bool = function VBool x -> Some x | _ -> None +let value_as_char = function VChar c -> Some c | _ -> None +let value_as_addr = function VAddress a -> Some a | _ -> None + +let ( >>= ) m f = + match m with + | None -> None + | Some x -> f x + +let return x = + Some x + +let trust_me = function + | None -> assert false (* Impossible. *) + | Some x -> x + +type ('a, 'e) wrapper = 'a -> 'e gvalue +let int_as_value x = VInt x +let bool_as_value x = VBool x + +let primitive name ?(error = fun () -> assert false) coercion wrapper f = + VPrimitive (name, fun x -> + match coercion x with + | None -> error () + | Some x -> wrapper (f x) + ) + +let print_value m v = + let max_depth = 5 in + + let rec print_value d v = + if d >= max_depth then "..." else + match v with + | VInt x -> + Int64.to_string x + | VBool true -> + "true" + | VBool false -> + "false" + | VChar c -> + "'" ^ Char.escaped c ^ "'" + | VString s -> + "\"" ^ String.escaped s ^ "\"" + | VUnit -> + "()" + | VAddress a -> + print_block m d a + | VFun _ -> + "" + | VPrimitive (s, _) -> + Printf.sprintf "" s + and print_block m d a = + let b = Memory.dereference m a in + let vs = Array.to_list (Memory.array_of_block b) in + "[ " ^ String.concat "; " (List.map (print_value d) vs) ^ " ]" + in + print_value 0 v + +module Environment : sig + type t + val empty : t + val bind : t -> identifier -> t gvalue -> t + val update : identifier -> t -> t gvalue -> unit + exception UnboundIdentifier of identifier + val lookup : identifier -> t -> t gvalue + val last : t -> (identifier * t gvalue * t) option + val print : t gvalue Memory.t -> t -> string +end = struct + + type t = + | EEmpty + | EBind of identifier * t gvalue ref * t + + let empty = EEmpty + + let bind e x v = + EBind (x, ref v, e) + + exception UnboundIdentifier of identifier + + let lookup' x = + let rec aux = function + | EEmpty -> raise (UnboundIdentifier x) + | EBind (y, v, e) -> + if x = y then v else aux e + in + aux + + let lookup x e = !(lookup' x e) + + let update x e v = + lookup' x e := v + + let last = function + | EBind (x, v, e) -> Some (x, !v, e) + | EEmpty -> None + + let print_binding m (Id x, v) = + x ^ " = " ^ print_value m !v + + let print m e = + let b = Buffer.create 13 in + let push x v = Buffer.add_string b (print_binding m (x, v)) in + let rec aux = function + | EEmpty -> Buffer.contents b + | EBind (x, v, EEmpty) -> push x v; aux EEmpty + | EBind (x, v, e) -> push x v; Buffer.add_string b "\n"; aux e + in + aux e + +end + +type value = Environment.t gvalue + +type formals = identifier list + +type runtime = { + memory : value Memory.t; + environment : Environment.t; +} + +type observable = { + new_memory : value Memory.t; + new_environment : Environment.t; +} + +(** [primitives] is an environment that contains the implementation + of all primitives (+, <, ...). *) +let primitives = + let intbin name out op = + VPrimitive (name, function [VInt x; VInt y] -> out (op x y) + | _ -> + Printf.printf "%s\n" name; + assert false (* By typing. *) + ) + in + let bind_all what l x = + List.fold_left (fun env (x, v) -> Environment.bind env (Id x) (what x v)) x l + in + (* Define arithmetic binary operators. *) + let binarith name = + intbin name (fun x -> VInt x) in + let binarithops = Int64.( + [ ("`+`", add); ("`-`", sub); ("`*`", mul); ("`/`", div) ] + ) in + (* Define arithmetic comparison operators. *) + let cmparith name = intbin name (fun x -> VBool x) in + let cmparithops = + [ ("`=?`", ( = )); ("`?`", ( > )); + ("`>=?`", ( >= )); ("`<=?`", ( <= )) ] + in + let boolbin name out op = + VPrimitive (name, function [VBool x; VBool y] -> out (op x y) + | _ -> assert false (* By typing. *) + ) + in + let boolarith name = boolbin name (fun x -> VBool x) in + let boolarithops = + [ ("`||`", ( || )); ("`&&`", ( && )) ] + in + let print s = + output_string stdout s; + flush stdout; + VUnit + in + let print_int = + VPrimitive ("print_int", function + | [ VInt x ] -> print (Int64.to_string x) + | _ -> assert false (* By typing. *) + ) + in + let print_string = + VPrimitive ("print_string", function + | [ VString x ] -> print x + | _ -> assert false (* By typing. *) + ) + in + let equal_string = + VPrimitive ("equal_string", function + | [ VString x; VString y ] -> VBool (String.compare x y = 0) + | _ -> assert false (* By typing. *) + ) + in + let equal_char = + VPrimitive ("equal_char", function + | [ VChar x; VChar y ] -> VBool (Char.compare x y = 0) + | _ -> assert false (* By typing. *) + ) + in + let bind' x w env = Environment.bind env (Id x) w in + Environment.empty + |> bind_all binarith binarithops + |> bind_all cmparith cmparithops + |> bind_all boolarith boolarithops + |> bind' "print_int" print_int + |> bind' "print_string" print_string + |> bind' "equal_string" equal_string + |> bind' "equal_char" equal_char + |> bind' "true" (VBool true) + |> bind' "false" (VBool false) + |> bind' "nothing" VUnit + +let initial_runtime () = { + memory = Memory.create (640 * 1024); + environment = primitives; +} + +let rec evaluate runtime ast = + try + let runtime' = List.fold_left definition runtime ast in + (runtime', extract_observable runtime runtime') + with Environment.UnboundIdentifier (Id x) -> + Error.error "interpretation" Position.dummy (Printf.sprintf "`%s' is unbound." x) + +(* [definition pos runtime d] evaluates the new definition [d] + into a new runtime [runtime']. In the specification, this + is the judgment: + + E, M ⊢ dᵥ ⇒ E', M' + +*) +and definition runtime d = + match d with + | DefineValue vd -> + value_definition runtime vd + + | DeclareExtern _ -> + runtime + +and value_definition runtime = function + | SimpleValue (x, e) -> + let v = expression runtime.environment runtime.memory e in + { runtime with environment = + bind_identifier runtime.environment x v + } + | RecFunctions rdefs -> + { runtime with environment = + define_recvalues runtime.environment runtime.memory rdefs + } + +and define_recvalues environment memory rdefs = + let environment = + List.fold_left (fun env (x, _) -> + bind_identifier env x VUnit) environment rdefs + in + let vs = expressions environment memory (snd (List.split rdefs)) in + List.iter2 (fun (x, _) v -> + Environment.update x environment v + ) rdefs vs; + environment + +(* [expression pos runtime e] evaluates into a value [v] if + + E, M ⊢ e ⇓ v, M' + + and E = [runtime.environment], M = [runtime.memory]. +*) +and expression environment memory = function + | Apply (a, b) -> + let vbs () = expressions environment memory b in + begin match expression environment memory a with + | VPrimitive ("`||", _) -> + begin match expression environment memory (List.nth b 0) with + | VBool true -> VBool true + | _ -> expression environment memory (List.nth b 1) + end + | VPrimitive ("`&&", _) -> + begin match expression environment memory (List.nth b 0) with + | VBool false -> VBool false + | _ -> expression environment memory (List.nth b 1) + end + + | VPrimitive (_, f) -> + f (vbs ()) + + | VFun (xs, e, environment) -> + expression (List.fold_left2 bind_identifier environment xs (vbs ())) memory e + + | _ -> + assert false (* By typing. *) + end + + | While (c, e) -> + let rec aux () = + match expression environment memory c with + | VBool true -> + ignore (expression environment memory e); + aux () + | VBool false -> + VUnit + | _ -> + assert false (* By typing. *) + in + aux () + + | Switch (e, branches, default) -> + begin match expression environment memory e with + | VInt i -> + let i = Int64.to_int i in + if i < 0 then assert false; (* By typing. *) + if i < Array.length branches && branches.(i) <> None then + match branches.(i) with + | None -> assert false (* By condition. *) + | Some t -> expression environment memory t + else begin match default with + | None -> assert false; (* By typing. *) + | Some t -> expression environment memory t + end + | _ -> assert false (* By typing. *) + end + + | Fun (p, e) -> + VFun (p, e, environment) + + | Literal l -> + literal l + + | Variable x -> + Environment.lookup x environment + + | Define (vd, e) -> + let runtime = value_definition { environment; memory } vd in + expression runtime.environment runtime.memory e + + | IfThenElse (c, t, f) -> + let v = expression environment memory c in + begin match value_as_bool v with + | None -> assert false (* By typing. *) + | Some true -> expression environment memory t + | Some false -> expression environment memory f + end + + | AllocateBlock e -> + begin match expression environment memory e with + | VInt x -> + let a = Memory.allocate memory x (VInt Int64.zero) in + VAddress a + | _ -> + assert false (* By typing. *) + end + + | WriteBlock (b, i, v) -> + let bv = expression environment memory b in + (value_as_addr bv >>= fun a -> + let bi = expression environment memory i in + value_as_int bi >>= fun i -> + let bb = expression environment memory v in + let b = Memory.dereference memory a in + Memory.write b i bb; + return (VUnit) + ) |> trust_me (* By typing. *) + + | ReadBlock (b, i) -> + let bv = expression environment memory b in + (value_as_addr bv >>= fun a -> + let bi = expression environment memory i in + value_as_int bi >>= fun i -> + let b = Memory.dereference memory a in + return (Memory.read b i) + ) |> trust_me (* By typing. *) + +and expressions environment memory es = + let rec aux vs = function + | [] -> + List.rev vs + | e :: es -> + let v = expression environment memory e in + aux (v :: vs) es + in + aux [] es + +and bind_identifier environment (x : identifier) v = + Environment.bind environment x v + +and literal = function + | LInt x -> VInt x + | LChar c -> VChar c + | LString s -> VString s + +and extract_observable runtime runtime' = + let rec substract new_environment env env' = + if env == env' then new_environment + else + match Environment.last env' with + | None -> assert false (* Absurd. *) + | Some (x, v, env') -> + let new_environment = Environment.bind new_environment x v in + substract new_environment env env' + in + { + new_environment = + substract Environment.empty runtime.environment runtime'.environment; + new_memory = + runtime'.memory + } + +let print_observable _ observation = + Environment.print observation.new_memory observation.new_environment diff --git a/flap/src/hobix/hobixLexer.mll b/flap/src/hobix/hobixLexer.mll new file mode 100644 index 0000000..9d40ba7 --- /dev/null +++ b/flap/src/hobix/hobixLexer.mll @@ -0,0 +1,206 @@ +{ + open Lexing + open Error + open Position + open HobixParser + + let next_line_and f lexbuf = + Lexing.new_line lexbuf; + f lexbuf + + let error lexbuf = + error "during lexing" (lex_join lexbuf.lex_start_p lexbuf.lex_curr_p) + + let string_buffer = + Buffer.create 13 + +} + +let newline = ('\010' | '\013' | "\013\010") + +let blank = [' ' '\009' '\012'] + +let symbol = [ '+' '-' '*' '/' '<' '=' '>' '?' '&' ] + +let digit = ['0'-'9'] + +let lowercase_alpha = ['a'-'z' '_'] + +let uppercase_alpha = ['A'-'Z'] + +let alpha = lowercase_alpha | uppercase_alpha + +let alphanum = alpha | digit | '_' + +let basic_identifier = lowercase_alpha alphanum* + +let prefix_alien_identifier = "`" (alpha | symbol | digit)+ + +let infix_alien_identifier = "`" (alpha | symbol | digit)+ "`" + +let identifier = basic_identifier | prefix_alien_identifier | infix_alien_identifier + +let uidentifier = uppercase_alpha alphanum* +let hexa = [ '0'-'9' 'a'-'f' 'A'-'F'] + +rule token = parse + (** Layout *) + | newline { next_line_and token lexbuf } + | blank+ { token lexbuf } + | "{*" { comment 1 lexbuf } + | "**" { commentline lexbuf } + + (** Keywords *) + | "val" { VAL } + | "if" { IF } + | "fi" { FI } + | "while" { WHILE } + | "then" { THEN } + | "else" { ELSE } + | "and" { AND } + | "or" { OR } + | "nothing" { NOTHING } + | "extern" { EXTERN } + | "newblock" { NEWBLOCK } + | "fun" { FUN } + | "switch" { SWITCH } + | "in" { IN } + + (** Identifiers *) + | identifier as i { ID i } + | infix_alien_identifier as i { INFIXID i } + + (** Literals *) + | digit+ as d { INT (Int64.of_string d) } + | ("0x" |"0X") hexa+ { INT (Int64.of_string (lexeme lexbuf)) } + | ("0b" |"0B") ['0'-'1']+ { INT (Int64.of_string (lexeme lexbuf)) } + | '"' { string lexbuf } + | "'\\n'" { LCHAR '\n' } + | "'\\t'" { LCHAR '\t' } + | "'\\b'" { LCHAR '\b' } + | "'\\r'" { LCHAR '\r' } + | "'\\\\'" { LCHAR '\\' } + | "'\\''" { LCHAR '\'' } + | '\'' ([^ '\\' '\''] as c) '\'' { + if (Char.code c < 32) then + error lexbuf ( + Printf.sprintf + "The ASCII character %d is not printable." (Char.code c) + ); + LCHAR c + } + | "'\\" (digit digit digit as i) "'" { + let c = int_of_string i in + if c < 0 || c > 255 then error lexbuf ""; + LCHAR (char_of_int c) + } + | "'\\0" ("x" | "X") (hexa hexa as i) "'" { + let c = int_of_string ("0x" ^ i) in + if c < 0 || c > 255 then error lexbuf ""; + LCHAR (char_of_int c) + } + | "'\\0" ("b" | "B") (['0'-'1']+ as i) "'" { + let c = int_of_string ("0b" ^ i) in + if c < 0 || c > 255 then error lexbuf ""; + LCHAR (char_of_int c) + } + (* *) + + (** Infix operators *) + | "=" { EQUAL } + | ":" { COLON } + | "=>" { DRARROW } + | "=?" { EQ } + | ">?" { GT } + | ">=?" { GTE } + | "?" { DRARROW } + | "&&" { LAND } + | "||" { LOR } + | "-" { MINUS } + | "+" { PLUS } + | "*" { STAR } + | "/" { SLASH } + + (** Punctuation *) + | ":=" { DEQUAL } + | "|" { PIPE } + | ";" { SEMICOLON } + | "(" { LPAREN } + | ")" { RPAREN } + | "[" { LBRACKET } + | "]" { RBRACKET } + | "{" { LBRACE } + | "}" { RBRACE } + | "," { COMMA } + | "\\" { BACKSLASH } + | eof { EOF } + + (** Lexing error. *) + | _ { error lexbuf "unexpected character." } + +and comment level = parse + | "*}" { + if level = 1 then + token lexbuf + else + comment (pred level) lexbuf + } + | "{*" { + comment (succ level) lexbuf + } + | eof { + error lexbuf "unterminated comment." + } + | newline { + next_line_and (comment level) lexbuf + } + | _ { + comment level lexbuf + } + +and commentline = parse + | newline { next_line_and token lexbuf } + | eof { EOF } + | _ { commentline lexbuf } + +and string = parse +| "\\n" { Buffer.add_char string_buffer '\n'; string lexbuf } +| "\\t" { Buffer.add_char string_buffer '\t'; string lexbuf } +| "\\b" { Buffer.add_char string_buffer '\b'; string lexbuf } +| "\\r" { Buffer.add_char string_buffer '\r'; string lexbuf } +| '\\' '\'' { Buffer.add_char string_buffer '\''; string lexbuf } +| '\\' '"' { Buffer.add_char string_buffer '"'; string lexbuf } +| "\\\\" { Buffer.add_char string_buffer '\\'; string lexbuf } + +| '\\' (_ as c) { error lexbuf + (Printf.sprintf "Bad escape sequence in string '\\%c'" c) + } +| "\\" (digit digit digit as i) { + let c = int_of_string i in + if c < 0 || c > 255 then error lexbuf ""; + Buffer.add_char string_buffer (char_of_int c); string lexbuf +} +| "\\0" ("x" | "X") (hexa hexa as i) { + let c = int_of_string ("0x" ^ i) in + if c < 0 || c > 255 then error lexbuf ""; + Buffer.add_char string_buffer (char_of_int c); string lexbuf +} +| "\\0" ("b" | "B") (['0'-'1']+ as i) { + let c = int_of_string ("0b" ^ i) in + if c < 0 || c > 255 then error lexbuf ""; + Buffer.add_char string_buffer (char_of_int c); string lexbuf +} +| '"' { + let s = Buffer.contents string_buffer in + Buffer.clear string_buffer; + LSTRING s +} +| _ as c { + Buffer.add_char string_buffer c; + string lexbuf +} +| eof { + error lexbuf "Unterminated string." +} diff --git a/flap/src/hobix/hobixParser.mly b/flap/src/hobix/hobixParser.mly new file mode 100644 index 0000000..7d93e37 --- /dev/null +++ b/flap/src/hobix/hobixParser.mly @@ -0,0 +1,204 @@ +%{ + + open HobixAST + +%} + +%token VAL +%token PLUS MINUS STAR SLASH +%token FUN WHILE +%token LTE LT GT GTE EQUAL EQ LAND LOR +%token IF THEN ELSE FI NEWBLOCK +%token AND OR EXTERN NOTHING IN SWITCH PIPE +%token LBRACKET RBRACKET COMMA BACKSLASH DRARROW +%token LBRACE RBRACE COLON +%token LSTRING +%token LCHAR +%token LPAREN RPAREN +%token SEMICOLON DEQUAL EOF +%token INT +%token ID INFIXID +%type expression + +%right SEMICOLON +%nonassoc FUN AND ELSE +%nonassoc DEQUAL +%nonassoc DRARROW +%left LOR +%left LAND +%nonassoc LTE LT GT GTE EQ +%left INFIXID +%left PLUS MINUS +%left STAR SLASH + +%start program + +%% + +program: ds=definition* EOF +{ + ds +} + +definition: +VAL d=value_def +{ + let (x, e) = d in + DefineValue (SimpleValue (x, e)) +} +| FUN d=function_definition ds=mutfun +{ + DefineValue (RecFunctions (d :: ds)) +} +| EXTERN x=identifier COLON n=INT +{ + DeclareExtern (x, Int64.to_int n) +} +| error { + let pos = Position.lex_join $startpos $endpos in + Error.error "parsing" pos "Syntax error." +} + +%inline value_def: +x=identifier EQUAL e=expression +{ + (x, e) +} + +%inline function_definition: +x=identifier +LPAREN xs=separated_list(COMMA, identifier) RPAREN +EQUAL e=expression +{ + (x, Fun (xs, e)) +} + +mutfun: +/* empty */ %prec AND { [] } +| AND d=function_definition ds=mutfun +{ d::ds } + +expression: +s=simple_expression +{ + s +} +| e1=expression SEMICOLON e2=expression +{ + Define (SimpleValue (Id "__nothing__", e1), e2) +} +| VAL vdef=value_def SEMICOLON e2=expression +{ + let (id,e1) = vdef in Define (SimpleValue (id, e1),e2) +} +| FUN d=function_definition ds=mutfun SEMICOLON e=expression %prec FUN +{ + Define (RecFunctions (d::ds), e) +} +| WHILE e=expression LBRACE b=expression RBRACE +{ + While (e, b) +} +| NEWBLOCK LPAREN e=expression RPAREN +{ + AllocateBlock e +} +| b=simple_expression LBRACKET i=expression RBRACKET DEQUAL rhs=expression +{ + WriteBlock (b, i, rhs) +} +| lhs=expression b=binop rhs=expression +{ + Apply (Variable (Id b), [lhs; rhs]) +} +| IF c=expression THEN t=expression ELSE e=expression FI +{ + IfThenElse (c, t, e) +} +| BACKSLASH + LPAREN xs=separated_list(COMMA, identifier) RPAREN + DRARROW e=expression +{ + Fun (xs, e) +} +| SWITCH e=expression IN bs=list(branch) OR ELSE d=default +{ + let i = List.fold_left (fun i (j, _) -> max i j) 0 bs in + let abs = Array.make i None in + List.iter (fun (i, e) -> abs.(i) <- Some e) bs; + Switch (e, abs, d) +} + +%inline default: NOTHING { None } +| e=expression { Some e } + +branch: PIPE x=INT DRARROW e=expression +{ + (Int64.to_int x, e) +} + +simple_expression: +| a=simple_expression + LPAREN bs=separated_list(COMMA, expression) RPAREN +{ + Apply (a, bs) +} +| b=simple_expression LBRACKET i=expression RBRACKET +{ + ReadBlock (b, i) +} + +| e=very_simple_expression +{ + e +} + +very_simple_expression: + l=literal +{ + Literal l +} +| x=identifier +{ + HobixAST.Variable x +} +| LPAREN e=expression RPAREN +{ + e +} + +%inline binop: + x=INFIXID { String.(sub x 0 (length x - 1)) } +| PLUS { "`+`" } +| MINUS { "`-`" } +| STAR { "`*`" } +| SLASH { "`/`" } +| GT { "`>?`" } +| GTE { "`>=?`" } +| LT { "` + value_definition "val" vd + | DeclareExtern (x, n) -> + group (string "extern" ++ identifier x + ++ string ":" ++ string (string_of_int n)) + +and value_definition ?(parens=false) what = function + | SimpleValue (x, e) -> + let pe = + if parens then may_paren_expression e else expression e + in + nest 2 (group (group (string what ++ identifier x ++ string "=") + ++ group pe)) + | RecFunctions rv -> + group ( + string "fun" + ++ separate_map + (hardline ^^ string "and" ^^ break 1) + function_definition + rv + ) + +and function_definition (f, e) = + match e with + | Fun (xs, e) -> + group ( + identifier f + ++ group (string "(" ++ separate_map (string "," ^^ break 1) identifier xs ++ string ")") + ++ string "=" + ) ++ group (expression e) + | _ -> + assert false + +and identifier (Id x) = + string x + +and expression = function + | Literal l -> + literal l + + | While (c, b) -> + nest 2 (group (string "while" ++ may_paren_expression c + ++ string "{" ^^ break 1 + ++ expression b + ++ break 1 ^^ string "}")) + + | Variable x -> + identifier x + + | Define (vd, e2) -> + nest 2 ( + group (value_definition ~parens:true "val" vd ^^ string ";" + )) + ++ group (expression e2) + + | Fun (p, e) -> + nest 2 (group ( + group (string "\\" ^^ function_parameters p ++ string "=>") ++ + group (expression e) + )) + + | Apply (a, bs) -> + group ( + parens_at_left_of_application a (expression a) + ++ parens (separate_map (string "," ^^ break 1) expression bs) + ) + + | IfThenElse (c, t, f) -> + nest 2 (group ( + group (string "if" + ++ group (may_paren_expression c) + ++ string "then" + ) + ++ group (may_paren_expression t) + )) + ++ nest 2 (group ( + string "else" + ++ group (may_paren_expression f) + ++ string "fi" + )) + + | WriteBlock (e1, e2, e3) -> + parens (expression e1) ^^ string "[" ^^ expression e2 + ^^ string "] := " ^^ may_paren_expression e3 + + | ReadBlock (e1, e2) -> + parens (expression e1) ^^ string "[" ^^ expression e2 ^^ string "]" + + | AllocateBlock e1 -> + expression (Apply (Variable (Id "newblock"), [e1])) + + | Switch (i, bs, default) -> + group (string "switch" ++ expression i ++ string "in") + ++ group ( + branches bs + ) ++ string "or else" ++ begin match default with + | None -> string "nothing" + | Some t -> expression t + end +and branches bs = + let bs = List.mapi (fun i x -> (i, x)) (Array.to_list bs) in + separate_map (string "|" ^^ break 1) (fun (i, t) -> + nest 2 (group ( + string (string_of_int i) + ++ string "=>" + ++ match t with + | None -> string "!" + | Some t -> expression t) + )) bs + +and function_parameters xs = + parens (separate_map (string "," ^^ break 1) identifier xs) + +and may_paren_expression e = match e with + | Fun _ | Define _ -> parens (expression e) + | _ -> expression e + +and literal = function + | LInt x -> + int x + | LChar c -> + char c + | LString s -> + string_literal s + +and char c = + group (string "'" ^^ string (Char.escaped c) ^^ string "'") + +and string_literal s = + group (string "\"" ^^ string (String.escaped s) ^^ string "\"") + +and parens_at_left_of_application e = + match e with + | Apply _ | Variable _ | Literal _ -> fun x -> x + | _ -> parens + +and parens_at_right_of_application e = + match e with + | Variable _ | Literal _ -> fun x -> x + | _ -> parens + +let to_string f x = + let b = Buffer.create 13 in + ToBuffer.pretty 0.8 80 b (f x); + Buffer.contents b diff --git a/flap/src/hobix/hobixTypechecker.ml b/flap/src/hobix/hobixTypechecker.ml new file mode 100644 index 0000000..5ef99c9 --- /dev/null +++ b/flap/src/hobix/hobixTypechecker.ml @@ -0,0 +1,11 @@ +(** This module implements a type checker for Hopix. *) + +let initial_typing_environment = HopixTypes.initial_typing_environment + +type typing_environment = HopixTypes.typing_environment + +let typecheck tenv _ = + tenv + +let print_typing_environment = + HopixTypes.string_of_typing_environment diff --git a/flap/src/hobix/hobixTypes.ml b/flap/src/hobix/hobixTypes.ml new file mode 100644 index 0000000..ce63d7f --- /dev/null +++ b/flap/src/hobix/hobixTypes.ml @@ -0,0 +1,5 @@ +type typing_environment = unit + +let initial_typing_environment () = () + +let print_typing_environment _ = "" diff --git a/flap/src/hobix/hopixToHobix.ml b/flap/src/hobix/hopixToHobix.ml new file mode 100644 index 0000000..c56db7c --- /dev/null +++ b/flap/src/hobix/hopixToHobix.ml @@ -0,0 +1,312 @@ +(** From Hopix to Hobix *) + +module Source = Hopix +module Target = Hobix + +(** The compilation environment. + ———————————————————————————– + + To translate a program written in a source language into another + semantically equivalent program written in a target language, it + is convenient to carry some information about the correspondence + between the two programs along the process. The compilation + environment is meant to that. + + In this particular pass, we want to remember an assignment of + integers to constructor and label identifiers. Therefore, the + compilation environment is composed of two maps representing these + assignments. The environment is populated each time we cross a + type definitions while it is read each time we translate language + constructions related to record and tagged values. +*) + +module ConstructorMap = Map.Make (struct + type t = HopixAST.constructor + let compare = compare +end) + +module LabelMap = Map.Make (struct + type t = HopixAST.label + let compare = compare +end) + +type environment = { + constructor_tags : Int64.t ConstructorMap.t; + label_positions : Int64.t LabelMap.t; +} + +let initial_environment () = { + constructor_tags = ConstructorMap.empty; + label_positions = LabelMap.empty; +} + +let index_of_constructor env k = + ConstructorMap.find k env.constructor_tags + +let position_of_label env l = + LabelMap.find l env.label_positions + +(** Code generation + ——————————————— + + A compilation pass produces code. We could directly + write down caml expressions made of applications of + HobixAST constructors. Yet, the resulting code would + be ugly... + + A better way consists in defining functions that build + Hobix AST terms and are convenient to use. Here are a + list of functions that may be convenient to you when + you will implement this pass. + +*) + +(** [fresh_identifier ()] returns a fresh identifier, that is + an identifier that has never been seen before. *) +let fresh_identifier = + let r = ref 0 in + fun () -> incr r; HobixAST.Id ("_h2h_" ^ string_of_int !r) + +(** [def w (fun x -> e)] returns an abstract syntax tree of + the form: + + val x = w; e + + where [x] is chosen fresh. +*) +let def w f = + let x = fresh_identifier () in + HobixAST.(Define (SimpleValue (x, w), f x)) + +(** [defines [d1; ..; dN] e] returns an abstract syntax tree of + the form: + + val d1; + .. + val dN; + e + +*) +let defines = + List.fold_right (fun (x, xe) e -> + HobixAST.(Define (SimpleValue (x, xe), e))) + +(** [seq s1 s2] is + + val _ = s1; + s2 + +*) +let seq s1 s2 = + HobixAST.(Define (SimpleValue (fresh_identifier (), s1), s2)) + +(** [htrue] represents the primitive true in Hobix. *) +let htrue = + HobixAST.(Variable (Id "true")) + +(** [seqs [s1; ...; sN] is + + val _ = s1; + ... + val _ = s(N - 1); + sN +*) +let rec seqs = function + | [] -> assert false + | [e] -> e + | e :: es -> seq e (seqs es) + +(** [is_equal e1 e2] is the boolean expression [e1 = e2]. *) +let is_equal l e1 e2 = + let equality = HobixAST.(match l with + | LInt _ -> "`=?`" + | LString _ -> "equal_string" + | LChar _ -> "equal_char" + ) in + HobixAST.(Apply (Variable (Id equality), [e1; e2])) + +(** [conj e1 e2] is the boolean expression [e1 && e2]. *) +let conj e1 e2 = + HobixAST.(Apply (Variable (Id "`&&`"), [ e1; e2 ])) + +(** [conjs [e1; ..; eN]] is the boolean expression [e1 && .. && eN]. *) +let rec conjs = function + | [] -> htrue + | [c] -> c + | c :: cs -> conj c (conjs cs) + +(** [component x i] returns [x[i]] where x is an Hobix expression + denoting a block. *) +let component x i = + failwith "Students! This is your job!" + + +let located f x = f (Position.value x) +let located' f x = Position.map f x + +let is_binop = function + | "`+`" | "`-`" | "`*`" | "`/`" + | "`=?`" | "`>=?`" | "`<=?`" | "`>?`" | "` + true + | _ -> + false + +let arity_of_type = HopixAST.(function + | TyVar _ -> 0 + | TyCon (_, _) -> 0 + | TyArrow (_, _) -> 1 + | TyTuple _ -> 0 +) + +let eta2 f = + failwith "Students! This is your job!" + +(** [program env p] turns an Hopix program into an equivalent + Hobix program. *) +let rec program env p = + let env, defs = ExtStd.List.foldmap definition' env p in + (List.flatten defs, env) + +(** Compilation of Hopix toplevel definitions. *) +and definition' env p = + definition env (Position.value p) + +and definition env = HobixAST.(function + | HopixAST.DeclareExtern (x, s) -> + let { Position.value = HopixAST.ForallTy (_, ty); _ } = s in + let ty = Position.value ty in + env, [DeclareExtern (located identifier x, arity_of_type ty)] + + | HopixAST.DefineValue vd -> + let vd = value_definition env vd in + env, [DefineValue vd] + + | HopixAST.DefineType (_, _, tydef) -> + type_definition env tydef, [] +) + +and value_definition env = function + | HopixAST.SimpleValue (x, _, e) -> + HobixAST.SimpleValue (located identifier x, located (expression env) e) + | HopixAST.RecFunctions fs -> + HobixAST.RecFunctions (List.map (function_binding env) fs) + +and function_binding env (f, _, fdef) = + (located identifier f, function_definition env fdef) + +and function_definition env (HopixAST.FunctionDefinition (x, e)) = + let y = HopixASTHelper.fresh_identifier () in + let wpos t = Position.(with_pos (position x) t) in + let e = HopixAST.( + Case (wpos (Variable (wpos y, None)), + [ + wpos (Branch (x, e)) + ]) + ) + in + (HobixAST.Fun ([identifier y], expression env e)) + +and identifier (HopixAST.Id x) = + HobixAST.Id x + +(** Compilation of Hopix expressions. *) +and expression env = HobixAST.(function + | HopixAST.Variable ({ value = HopixAST.Id x }, _) when is_binop x -> + eta2 (HobixAST.Id x) + + | HopixAST.Variable (x, _) -> + Variable (located identifier x) + + | HopixAST.Tagged (k, _, es) -> + failwith "Students! This is your job!" + + | HopixAST.Case (e, bs) -> + failwith "Students! This is your job!" + + | HopixAST.Ref e -> + failwith "Students! This is your job!" + + | HopixAST.Read r -> + failwith "Students! This is your job!" + + | HopixAST.Assign (r, v) -> + failwith "Students! This is your job!" + + | HopixAST.While (c, b) -> + HobixAST.While (located (expression env) c, + located (expression env) b) + + | HopixAST.Apply (a, b) -> + Apply (located (expression env) a, + [located (expression env) b]) + + | HopixAST.Literal l -> + Literal (located literal l) + + | HopixAST.Define (vd, e) -> + Define (value_definition env vd, located (expression env) e) + + | HopixAST.TypeAnnotation (e, _) -> + located (expression env) e + + | HopixAST.IfThenElse (c, t, f) -> + let f = located (expression env) f in + HobixAST.IfThenElse (located (expression env) c, + located (expression env) t, + f) + + | HopixAST.Record (fs, _) -> + failwith "Students! This is your job!" + + | HopixAST.Tuple ts -> + failwith "Students! This is your job!" + + | HopixAST.Field (e, l, _) -> + failwith "Students! This is your job!" + + | HopixAST.Sequence es -> + seqs (List.map (located (expression env)) es) + + | HopixAST.For (x, start, stop, e) -> + failwith "Students! This is your job!" + + | HopixAST.Fun fdef -> + failwith "Students! This is your job!" +) + + +(** [expands_or_patterns branches] returns a sequence of branches + equivalent to [branches] except that their patterns do not contain + any disjunction. {ListMonad} can be useful to implement this + transformation. *) +and expands_or_patterns branches = + failwith "Students! This is your job!" + + +(** [pattern env scrutinee p] returns an HopixAST expression + representing a boolean condition [c] and a list of definitions + [ds] such that: + + - [c = true] if and only if [p] matches the [scrutinee] ; + - [ds] binds all the variables that appear in [p]. + + Precondition: p does not contain any POr. + *) +and pattern env scrutinee p = HobixAST.( + failwith "Students! This is your job!" +) + +and literal = HobixAST.(function + | HopixAST.LInt x -> LInt x + | HopixAST.LString s -> LString s + | HopixAST.LChar c -> LChar c +) + +(** Compilation of type definitions. *) +and type_definition env t = + failwith "Students! This is your job!" + +(** Here is the compiler! *) +let translate source env = + program env source diff --git a/flap/src/hobix/patternMatchingCompiler.ml b/flap/src/hobix/patternMatchingCompiler.ml new file mode 100644 index 0000000..1b6cfed --- /dev/null +++ b/flap/src/hobix/patternMatchingCompiler.ml @@ -0,0 +1,182 @@ +(** This module implements an optimized compilation of pattern-matching. + + It is based on the article + + "Compiling Pattern Matching to Good Decision Trees" + + written by Luc Maranget + and published in the proceedings of the ML workshop 2005. + +*) +open Position + +module S = HopixAST +module T = HobixAST + +(** A path is a sequence of indices which allow for accessing + a component which may be deeply nested inside a block. *) +type path = int list + +(** Each identifier bound by the pattern will finally be associated to + a path. *) +type binding = T.identifier * path + +(** A pattern-matching matrix has a row for each possible + case and as many columns as the number of components of + the matched value. *) +type matrix = row list + +and row = S.pattern list * binding list * T.expression + +(** [nb_columns m] returns the number of columns of [m]. *) +let nb_columns = function + | [] -> + 0 + | (ps, _, _) :: rows -> + let n = List.length ps in + assert (List.for_all (fun (ps, _, _) -> List.length ps = n) rows); + n + +(** [string_of_path occ] produces a human-readable version of [occ]. *) +let string_of_path occ = + String.concat "." (List.rev_map string_of_int occ) + +(** [string_of_bindings bs] produces a human-readable version of [bs]. *) +let string_of_bindings bs = + String.concat ", " ( + List.map (fun (T.Id x, p) -> + Printf.sprintf "%s = %s" x (string_of_path p) + ) bs) + +(** [string_of_matrix m] produces a human-readable version of [m]. *) +let string_of_matrix m = + let csizes = Array.make (nb_columns m) 0 in + let string_of_pattern i p = + let s = HopixPrettyPrinter.(to_string pattern p) in + csizes.(i) <- max csizes.(i) (String.length s); + s + in + let complete_pattern i p = + p ^ String.make (csizes.(i) - String.length p) ' ' + in + let string_of_expression e = + HobixPrettyPrinter.(to_string expression e) + in + let b = Buffer.create 13 in + List.map (fun (ps, bs, e) -> + (List.mapi string_of_pattern ps, + string_of_bindings bs, + string_of_expression e)) m + |> List.iter (fun (ps, bs, e) -> + Buffer.add_string b ( + String.concat " " (List.mapi complete_pattern ps) + ^ " -> " ^ bs ^ " in " ^ e ^ "\n" + ) + ); + Buffer.contents b + +(** We may observe if a value is a tagged value with a specific + constructor or is equal to a given literal. *) +type observation = + | CTag of S.constructor + | CLit of S.literal + +(** [head_constructors m] returns the list of observations of the + first column of [m] without repetition. Each observation comes with + its arity. A literal has an arity of 0 and constructor has for arity + the number of arguments it is applied to. This function assumes + that the patterns in the matrix are well-typed, hence we can deduce + the arity of the constructors directly from their application. *) +let head_constructors : matrix -> (observation * int) list = + failwith "Students! This is your job!" + +(** [specialize occ c arity m] returns the matrix [m] in which rows that + do not match the observation [c] are removed and the others + have new columns to match the subcomponents of [c]. + - [m] must have at least one row and one column. + - [arity] is the arity of [c]. + - [occ] is the path to the scrutinee's component matched by the + first column of [m]. +*) +let specialize occ c arity (m : matrix) = + failwith "Students! This is your job!" + +(** [default occ m] returns the default matrix of [m], that is the matrix + corresponding to the remaining tests to do if the default case of the + first column of [m] has been chosen. *) +let default occ (m : matrix) = + failwith "Students! This is your job!" + +(** [split n] returns the list of occurrences [occ.0; occ.1; ..; + occ.(n - 1)]. *) +let split n occ = + failwith "Students! This is your job!" + +(** [swap_columns i m] returns a new matrix which is [m] in which + column 0 and column i have been exchanged. *) +let swap_columns i m = + failwith "Students! This is your job!" + +(** [swap_occurences i occs] returns a new list of occurrences in + which the occ numbered 0 and the occ numbered i have been + exchanged. *) +let swap_occurences i occs = + failwith "Students! This is your job!" + +type decision_tree = + | Fail + | Leaf of binding list * T.expression + | Switch of path * (observation * decision_tree) list * decision_tree option + | Swap of int * decision_tree + +let string_of_constructor = function + | CTag (S.KId s) -> s + | CLit l -> HopixPrettyPrinter.(to_string literal l) + +(** [string_of_decision_tree t] produces a human-readable version of [t]. *) +let string_of_decision_tree t = + let b = Buffer.create 13 in + let offset = 2 in + let show indent s = + Buffer.add_string b (String.make (offset * indent) ' ' ^ s ^ "\n") + in + let rec aux prefix indent = function + | Fail -> + show indent (prefix ^ "fail") + | Leaf (bs, e) -> + show indent ( + prefix + ^ string_of_bindings bs + ^ HobixPrettyPrinter.(to_string expression e)) + | Switch (occ, ts, default) -> + show indent (prefix ^ string_of_path occ ^ "?"); + List.iter (fun (c, t) -> aux (string_of_constructor c) (indent + 1) t) ts; + begin match default with + | None -> () + | Some t -> aux "default: " (indent + 1) t + end + | Swap (i, t) -> + aux ("swap" ^ string_of_int i ^ ":") (indent + 1) t + in + aux "" 0 t; + Buffer.contents b + + +(** [decision_tree_of_matrix m] returns a decision tree that + implements [m] efficiently. *) +let decision_tree_of_matrix (m : matrix) : decision_tree = + failwith "Students! This is your job!" + +(** [compile_decision_tree index_of_constructor x t] returns an + expression in Hobix which corresponds to the application of [t] to + [x]. [index_of_constructor k] returns the integer which represents + the constructor k in Hobix. *) +let compile_decision_tree (index_of_constructor : S.constructor -> int) x t = + failwith "Students! This is your job!" + +(** [translate branches x] returns an [Hobix] expression which implements + an efficient pattern matching of [x] with the [branches]. *) +let translate (index_of_constructor : S.constructor -> int) bs x = + let matrix = List.map (fun (p, e) -> ([p.value], [], e)) bs in + let decision_tree = decision_tree_of_matrix matrix in + compile_decision_tree index_of_constructor x decision_tree diff --git a/flap/src/hopix/hopix.ml b/flap/src/hopix/hopix.ml new file mode 100644 index 0000000..b22c3ee --- /dev/null +++ b/flap/src/hopix/hopix.ml @@ -0,0 +1,44 @@ +(** The Hopix programming language. *) + +let name = "hopix" + +module AST = HopixAST + +type ast = HopixAST.t + +let parse lexer_init input = + SyntacticAnalysis.process + ~lexer_init + ~lexer_fun:HopixLexer.token + ~parser_fun:HopixParser.program + ~input + +let parse_filename filename = + if Options.get_use_sexp_in () then + ExtStd.Stdlib.file_content filename + |> Sexplib.Sexp.of_string + |> HopixAST.program_of_sexp + else + parse Lexing.from_channel (open_in filename) + +let extension = + ".hopix" + +let executable_format = + false + +let parse_string = + parse Lexing.from_string + +let print_ast ast = + if Options.get_use_sexp_out () then + HopixAST.sexp_of_program ast |> Sexplib.Sexp.to_string + else + HopixPrettyPrinter.(to_string program ast) + +let print_expression e = + HopixPrettyPrinter.(to_string expression e) + +include HopixInterpreter + +include HopixTypechecker diff --git a/flap/src/hopix/hopixAST.ml b/flap/src/hopix/hopixAST.ml new file mode 100644 index 0000000..d3df029 --- /dev/null +++ b/flap/src/hopix/hopixAST.ml @@ -0,0 +1,150 @@ +(** The abstract syntax tree for hopix programs. *) + +open Sexplib.Std +open Position + +(** A program is a list of definitions. *) +type program = definition located list +[@@deriving sexp] + +and definition = + (** A type definition. *) + | DefineType of + type_constructor located * type_variable located list * type_definition + (** A toplevel declaration for an external value. *) + | DeclareExtern of identifier located * type_scheme located + (** A toplevel definition of value(s). *) + | DefineValue of value_definition + +and type_definition = + (** A sum type for tagged values + [K₁ (ty₁₁, ..., ty₁ₙ) | ... | Kₙ (tyₙ₁, ..., tyₘₖ)]. + *) + | DefineSumType of (constructor located * ty located list) list + (** A record type { l₁ : ty₁, ..., lₙ : tyₙ}. *) + | DefineRecordType of (label located * ty located) list + (** A type with no visible definition. *) + | Abstract + +and expression = + (** A literal is a constant written "as is". *) + | Literal of literal located + (** A variable identifies a value. If this value is polymorphic, it can be + instantiated using a list of types.*) + | Variable of identifier located * ty located list option + (** A tagged value [K (e₁, ..., eₙ)]. *) + | Tagged of + constructor located * ty located list option * expression located list + (** A record [{l₁ = e₁, ..., lₙ = eₙ} ]. *) + | Record of (label located * expression located) list * ty located list option + (** A record field access [e.l]. *) + | Field of expression located * label located * ty located list option + (** A tuple [(e₁, ..., en)]. *) + | Tuple of expression located list + (** A sequence [e₁ ; ... ; eₙ] *) + | Sequence of expression located list + (** A local definition of value(s) [value_definition; e₂]. *) + | Define of value_definition * expression located + (** An anonymous function [ pattern -> e ]. *) + | Fun of function_definition + (** A function application [a₁ (a₂))]. *) + | Apply of expression located * expression located + (** A reference allocation. *) + | Ref of expression located + (** An assignment. *) + | Assign of expression located * expression located + (** A dereference. *) + | Read of expression located + (** A pattern matching [match (e) { p₁ -> e₁ | ... | pₙ -> eₙ }]. *) + | Case of expression located * branch located list + (** A conditional expression of the form [if (...) ... else ...]. *) + | IfThenElse of expression located * expression located * expression located + (** An unbounded loop of the form [while (...) { ... }]. *) + | While of expression located * expression located + (** A bounded loop of the form [for x in (e₁ to e₂) { ... }]. *) + | For of + identifier located + * expression located * expression located + * expression located + (** A type annotation [(e : ty)]. *) + | TypeAnnotation of expression located * ty located + +and value_definition = + (** A toplevel definition for a value. *) + | SimpleValue of expression located polymorphic_definition + (** A toplevel definition for mutually recursive functions. *) + | RecFunctions of function_definition polymorphic_definition list + +and 'a polymorphic_definition = + identifier located * type_scheme located option * 'a + +and function_definition = + | FunctionDefinition of pattern located * expression located + +and type_arguments = + type_variable located list + +and pattern = + (** A pattern which is simply an identifier. *) + | PVariable of identifier located + (** A wildcard pattern [_]. *) + | PWildcard + (** A pattern with a type annotation of type form [p : ty] *) + | PTypeAnnotation of pattern located * ty located + (** A literal pattern. *) + | PLiteral of literal located + (** A pattern for a tagged value K (p₁, ..., pₙ). *) + | PTaggedValue of + constructor located * ty located list option * pattern located list + (** A pattern for a record {l₁ = p₁, ..., lₙ = pₙ } < ty₁, ..., tyₘ >. *) + | PRecord of (label located * pattern located) list * ty located list option + (** A pattern for a tuple (p₁, ..., pₙ). *) + | PTuple of pattern located list + (** A disjunctive pattern [ p₁ | ... | pₙ ]. *) + | POr of pattern located list + (** A conjunctive pattern [ p₁ & ... & pₙ ]. *) + | PAnd of pattern located list + +and branch = + (** A branch in a pattern matching [p => e]. *) + | Branch of pattern located * expression located + +and ty = + (** An instantiated type constructor [t ]. *) + | TyCon of type_constructor * ty located list + (** A function type [ty₁ → ty₂]. *) + | TyArrow of ty located * ty located + (** A tuple type [ty₁ * ... * tyₙ]. *) + | TyTuple of ty located list + (** A type variable ['a]. *) + | TyVar of type_variable + +and type_scheme = + ForallTy of type_variable located list * ty located + +and literal = + | LInt of Mint.t + | LString of string + | LChar of char + +and identifier = + | Id of string + +and type_constructor = + | TCon of string + +and type_variable = + | TId of string + +and constructor = + | KId of string + +and label = + | LId of string + +[@@deriving sexp] + +type t = program + +[@@deriving sexp] + diff --git a/flap/src/hopix/hopixASTHelper.ml b/flap/src/hopix/hopixASTHelper.ml new file mode 100644 index 0000000..dfcf5d0 --- /dev/null +++ b/flap/src/hopix/hopixASTHelper.ml @@ -0,0 +1,15 @@ +open HopixAST + +module LabelSet = Set.Make (struct + type t = label + let compare = compare +end) + +module TypeVariableSet = Set.Make (struct + type t = type_variable + let compare = compare +end) + +let fresh_identifier = + let count = ref (-1) in + fun () -> incr count; Id ("id" ^ string_of_int !count) diff --git a/flap/src/hopix/hopixInitialization.ml b/flap/src/hopix/hopixInitialization.ml new file mode 100644 index 0000000..1574c6c --- /dev/null +++ b/flap/src/hopix/hopixInitialization.ml @@ -0,0 +1,4 @@ +let initialize () = + Languages.register (module Hopix); + Compilers.register (module Compilers.Identity (Hopix)) + diff --git a/flap/src/hopix/hopixInterpreter.ml b/flap/src/hopix/hopixInterpreter.ml new file mode 100644 index 0000000..c8a3ad5 --- /dev/null +++ b/flap/src/hopix/hopixInterpreter.ml @@ -0,0 +1,356 @@ +open Position +open Error +open HopixAST + +(** [error pos msg] reports execution error messages. *) +let error positions msg = + errorN "execution" positions msg + +(** Every expression of Hopix evaluates into a [value]. + + The [value] type is not defined here. Instead, it will be defined + by instantiation of following ['e gvalue] with ['e = environment]. + Why? The value type and the environment type are mutually recursive + and since we do not want to define them simultaneously, this + parameterization is a way to describe how the value type will use + the environment type without an actual definition of this type. + +*) +type 'e gvalue = + | VInt of Mint.t + | VChar of char + | VString of string + | VUnit + | VTagged of constructor * 'e gvalue list + | VTuple of 'e gvalue list + | VRecord of (label * 'e gvalue) list + | VLocation of Memory.location + | VClosure of 'e * pattern located * expression located + | VPrimitive of string * ('e gvalue Memory.t -> 'e gvalue -> 'e gvalue) + +(** Two values for booleans. *) +let ptrue = VTagged (KId "True", []) +let pfalse = VTagged (KId "False", []) + +(** + We often need to check that a value has a specific shape. + To that end, we introduce the following coercions. A + coercion of type [('a, 'e)] coercion tries to convert an + Hopix value into a OCaml value of type ['a]. If this conversion + fails, it returns [None]. +*) + +type ('a, 'e) coercion = 'e gvalue -> 'a option +let fail = None +let ret x = Some x +let value_as_int = function VInt x -> ret x | _ -> fail +let value_as_char = function VChar c -> ret c | _ -> fail +let value_as_string = function VString s -> ret s | _ -> fail +let value_as_tagged = function VTagged (k, vs) -> ret (k, vs) | _ -> fail +let value_as_record = function VRecord fs -> ret fs | _ -> fail +let value_as_location = function VLocation l -> ret l | _ -> fail +let value_as_closure = function VClosure (e, p, b) -> ret (e, p, b) | _ -> fail +let value_as_primitive = function VPrimitive (p, f) -> ret (p, f) | _ -> fail +let value_as_bool = function + | VTagged (KId "True", []) -> true + | VTagged (KId "False", []) -> false + | _ -> assert false + +(** + It is also very common to have to inject an OCaml value into + the types of Hopix values. That is the purpose of a wrapper. + *) +type ('a, 'e) wrapper = 'a -> 'e gvalue +let int_as_value x = VInt x +let bool_as_value b = if b then ptrue else pfalse + +(** + + The flap toplevel needs to print the result of evaluations. This is + especially useful for debugging and testing purpose. Do not modify + the code of this function since it is used by the testsuite. + +*) +let print_value m v = + (** To avoid to print large (or infinite) values, we stop at depth 5. *) + let max_depth = 5 in + + let rec print_value d v = + if d >= max_depth then "..." else + match v with + | VInt x -> + Mint.to_string x + | VChar c -> + "'" ^ Char.escaped c ^ "'" + | VString s -> + "\"" ^ String.escaped s ^ "\"" + | VUnit -> + "()" + | VLocation a -> + print_array_value d (Memory.dereference m a) + | VTagged (KId k, []) -> + k + | VTagged (KId k, vs) -> + k ^ print_tuple d vs + | VTuple (vs) -> + print_tuple d vs + | VRecord fs -> + "{" + ^ String.concat ", " ( + List.map (fun (LId f, v) -> f ^ " = " ^ print_value (d + 1) v + ) fs) ^ "}" + | VClosure _ -> + "" + | VPrimitive (s, _) -> + Printf.sprintf "" s + and print_tuple d vs = + "(" ^ String.concat ", " (List.map (print_value (d + 1)) vs) ^ ")" + and print_array_value d block = + let r = Memory.read block in + let n = Mint.to_int (Memory.size block) in + "[ " ^ String.concat ", " ( + List.(map (fun i -> print_value (d + 1) (r (Mint.of_int i))) + (ExtStd.List.range 0 (n - 1)) + )) ^ " ]" + in + print_value 0 v + +let print_values m vs = + String.concat "; " (List.map (print_value m) vs) + +module Environment : sig + (** Evaluation environments map identifiers to values. *) + type t + + (** The empty environment. *) + val empty : t + + (** [bind env x v] extends [env] with a binding from [x] to [v]. *) + val bind : t -> identifier -> t gvalue -> t + + (** [update pos x env v] modifies the binding of [x] in [env] so + that [x ↦ v] ∈ [env]. *) + val update : Position.t -> identifier -> t -> t gvalue -> unit + + (** [lookup pos x env] returns [v] such that [x ↦ v] ∈ env. *) + val lookup : Position.t -> identifier -> t -> t gvalue + + (** [UnboundIdentifier (x, pos)] is raised when [update] or + [lookup] assume that there is a binding for [x] in [env], + where there is no such binding. *) + exception UnboundIdentifier of identifier * Position.t + + (** [last env] returns the latest binding in [env] if it exists. *) + val last : t -> (identifier * t gvalue * t) option + + (** [print env] returns a human readable representation of [env]. *) + val print : t gvalue Memory.t -> t -> string +end = struct + + type t = + | EEmpty + | EBind of identifier * t gvalue ref * t + + let empty = EEmpty + + let bind e x v = + EBind (x, ref v, e) + + exception UnboundIdentifier of identifier * Position.t + + let lookup' pos x = + let rec aux = function + | EEmpty -> raise (UnboundIdentifier (x, pos)) + | EBind (y, v, e) -> + if x = y then v else aux e + in + aux + + let lookup pos x e = !(lookup' pos x e) + + let update pos x e v = + lookup' pos x e := v + + let last = function + | EBind (x, v, e) -> Some (x, !v, e) + | EEmpty -> None + + let print_binding m (Id x, v) = + x ^ " = " ^ print_value m !v + + let print m e = + let b = Buffer.create 13 in + let push x v = Buffer.add_string b (print_binding m (x, v)) in + let rec aux = function + | EEmpty -> Buffer.contents b + | EBind (x, v, EEmpty) -> push x v; aux EEmpty + | EBind (x, v, e) -> push x v; Buffer.add_string b "\n"; aux e + in + aux e + +end + +(** + We have everything we need now to define [value] as an instantiation + of ['e gvalue] with ['e = Environment.t], as promised. +*) +type value = Environment.t gvalue + +(** + The following higher-order function lifts a function [f] of type + ['a -> 'b] as a [name]d Hopix primitive function, that is, an + OCaml function of type [value -> value]. +*) +let primitive name ?(error = fun () -> assert false) coercion wrapper f +: value += VPrimitive (name, fun x -> + match coercion x with + | None -> error () + | Some x -> wrapper (f x) + ) + +type runtime = { + memory : value Memory.t; + environment : Environment.t; +} + +type observable = { + new_memory : value Memory.t; + new_environment : Environment.t; +} + +(** [primitives] is an environment that contains the implementation + of all primitives (+, <, ...). *) +let primitives = + let intbin name out op = + let error m v = + Printf.eprintf + "Invalid arguments for `%s': %s\n" + name (print_value m v); + assert false (* By typing. *) + in + VPrimitive (name, fun m -> function + | VInt x -> + VPrimitive (name, fun m -> function + | VInt y -> out (op x y) + | v -> error m v) + | v -> error m v) + in + let bind_all what l x = + List.fold_left (fun env (x, v) -> Environment.bind env (Id x) (what x v)) + x l + in + (* Define arithmetic binary operators. *) + let binarith name = + intbin name (fun x -> VInt x) in + let binarithops = Mint.( + [ ("`+`", add); ("`-`", sub); ("`*`", mul); ("`/`", div) ] + ) in + (* Define arithmetic comparison operators. *) + let cmparith name = intbin name bool_as_value in + let cmparithops = + [ ("`=?`", ( = )); + ("`?`", ( > )); + ("`>=?`", ( >= )); + ("`<=?`", ( <= )) ] + in + let boolbin name out op = + VPrimitive (name, fun _ x -> VPrimitive (name, fun _ y -> + out (op (value_as_bool x) (value_as_bool y)))) + in + let boolarith name = boolbin name (fun x -> if x then ptrue else pfalse) in + let boolarithops = + [ ("`||`", ( || )); ("`&&`", ( && )) ] + in + let generic_printer = + VPrimitive ("print", fun m v -> + output_string stdout (print_value m v); + flush stdout; + VUnit + ) + in + let print s = + output_string stdout s; + flush stdout; + VUnit + in + let print_int = + VPrimitive ("print_int", fun _ -> function + | VInt x -> print (Mint.to_string x) + | _ -> assert false (* By typing. *) + ) + in + let print_string = + VPrimitive ("print_string", fun _ -> function + | VString x -> print x + | _ -> assert false (* By typing. *) + ) + in + let bind' x w env = Environment.bind env (Id x) w in + Environment.empty + |> bind_all binarith binarithops + |> bind_all cmparith cmparithops + |> bind_all boolarith boolarithops + |> bind' "print" generic_printer + |> bind' "print_int" print_int + |> bind' "print_string" print_string + |> bind' "true" ptrue + |> bind' "false" pfalse + |> bind' "nothing" VUnit + +let initial_runtime () = { + memory = Memory.create (640 * 1024 (* should be enough. -- B.Gates *)); + environment = primitives; +} + +let rec evaluate runtime ast = + try + let runtime' = List.fold_left definition runtime ast in + (runtime', extract_observable runtime runtime') + with Environment.UnboundIdentifier (Id x, pos) -> + Error.error "interpretation" pos (Printf.sprintf "`%s' is unbound." x) + +(** [definition pos runtime d] evaluates the new definition [d] + into a new runtime [runtime']. In the specification, this + is the judgment: + + E, M ⊢ dv ⇒ E', M' + +*) +and definition runtime d = +failwith "Students! This is your job!" + +and expression' environment memory e = + expression (position e) environment memory (value e) + +(** [expression pos runtime e] evaluates into a value [v] if + + E, M ⊢ e ⇓ v, M' + + and E = [runtime.environment], M = [runtime.memory]. +*) +and expression _ environment memory = +failwith "Students! This is your job!" + +(** This function returns the difference between two runtimes. *) +and extract_observable runtime runtime' = + let rec substract new_environment env env' = + if env == env' then new_environment + else + match Environment.last env' with + | None -> assert false (* Absurd. *) + | Some (x, v, env') -> + let new_environment = Environment.bind new_environment x v in + substract new_environment env env' + in + { + new_environment = + substract Environment.empty runtime.environment runtime'.environment; + new_memory = + runtime'.memory + } + +(** This function displays a difference between two runtimes. *) +let print_observable (_ : runtime) observation = + Environment.print observation.new_memory observation.new_environment diff --git a/flap/src/hopix/hopixLexer.mll b/flap/src/hopix/hopixLexer.mll new file mode 100644 index 0000000..980c832 --- /dev/null +++ b/flap/src/hopix/hopixLexer.mll @@ -0,0 +1,32 @@ +{ (* -*- tuareg -*- *) + open Lexing + open Error + open Position + open HopixParser + + let next_line_and f lexbuf = + Lexing.new_line lexbuf; + f lexbuf + + let error lexbuf = + error "during lexing" (lex_join lexbuf.lex_start_p lexbuf.lex_curr_p) + + +} + +let newline = ('\010' | '\013' | "\013\010") + +let blank = [' ' '\009' '\012'] + +let digit = ['0'-'9'] + + +rule token = parse + (** Layout *) + | newline { next_line_and token lexbuf } + | blank+ { token lexbuf } + | eof { EOF } + + (** Lexing error. *) + | _ { error lexbuf "unexpected character." } + diff --git a/flap/src/hopix/hopixParser.mly b/flap/src/hopix/hopixParser.mly new file mode 100644 index 0000000..9d94e29 --- /dev/null +++ b/flap/src/hopix/hopixParser.mly @@ -0,0 +1,23 @@ +%{ (* -*- tuareg -*- *) + + open HopixAST + open Position + + +%} + +%token EOF + + +%start program + +%% + +program: EOF +{ + [] +} + +%inline located(X): x=X { + Position.with_poss $startpos $endpos x +} diff --git a/flap/src/hopix/hopixPrettyPrinter.ml b/flap/src/hopix/hopixPrettyPrinter.ml new file mode 100644 index 0000000..93b9ebe --- /dev/null +++ b/flap/src/hopix/hopixPrettyPrinter.ml @@ -0,0 +1,394 @@ +open PPrint +open ExtPPrint +open HopixAST +open Position + +let int i = string (Mint.to_string i) + +let colon = string "," + +let semicolon = string ";" + +let sqbrackets d = string "[" ^^ d ^^ string "]" + +let angles d = string "<" ^^ d ^^ string ">" + +let separate_postgrouped_map sep f xs = + let rec aux = function + | [] -> empty + | x :: xs -> group (sep ^^ f x) ^^ break 1 ^^ aux xs + in + match xs with + | [] -> empty + | x :: xs -> f x ^^ break 1 ^^ aux xs + +let gtype_definition sep what around ks = + around (break 1 ^^ group ( + separate_postgrouped_map (break 1 ^^ string sep ^^ break 1) what ks + )) + +let rec program p = + separate_map hardline (located definition) p + +and definition = function + | DefineType (t, ts, tdef) -> + nest 2 ( + group (group (string "type" + ++ located type_constructor t + ^^ group (type_parameters_angles ts)) + ++ string "=") + ++ type_definition tdef) + | DeclareExtern (x, t) -> + group (string "extern" ++ located identifier x + ++ string ":" ++ located type_scheme t) + | DefineValue vdef -> + group (value_definition false vdef) + +and rec_function_definition paren rv = + group (string "fun" + ^^ space + ^^ separate_map (hardline ^^ string "and" ^^ space) + (fun (x, d) -> + nest 2 ( + group (located identifier x ^^ break 1 ^^ + let sep = space ^^ string "=" ^^ break 1 in + located (function_definition paren sep) d))) + rv) + +and function_definition paren sep = function + | FunctionDefinition (p, e) -> + group (located pattern p) + ^^ sep ^^ group (located (if_paren_expression paren) e) + +and type_parameters ts = + separate_map (comma ^^ break 1) (located type_variable) ts + +and type_parameters_angles = function + | [] -> + empty + | ts -> + angles (type_parameters ts) + +and type_parameters_bracketed = function + | [] -> + empty + | ts -> + sqbrackets (type_parameters ts) + +and type_definition = function + | DefineSumType ks -> + gtype_definition "|" dataconstructor_definition (fun x -> x) ks + | DefineRecordType ls -> + gtype_definition "," label_definition braces ls + | Abstract -> + empty + +and label (LId s) = + string s + +and dataconstructor_definition (k, tys) = + match tys with + | [] -> + located dataconstructor k + | _ -> + group (located dataconstructor k + ++ parens ( + separate_map (string "," ^^ break 1) (located ty) tys + )) + +and label_definition (l, t) = + group (located label l ++ string ":" ++ located ty t) + +and dataconstructor (KId k) = + string k + +and value_definition paren = function + | SimpleValue (x, ot, e) -> + nest 2 (group (group ( + string "let" ++ located identifier x + ^^ optional_type_scheme_annotation ot + ++ string "=") + ++ group (located (if_paren_expression paren) e + ))) + | RecFunctions (f :: fs) -> + rec_function "fun" f ++ + separate_map (break 1) (rec_function "and") fs + | RecFunctions [] -> + assert false (* By parsing. *) + +and rec_function prefix (f, ot, fdef) = + group (nest 2 ( + group (string prefix + ^^ optional_type_scheme_annotation ot + ++ located identifier f) + ++ function_definition true (space ^^ string "=" ^^ break 1) fdef + )) + +and optional_type_annotation = function + | None -> empty + | Some t -> type_annotation t + +and type_annotation t = + group (break 1 ^^ string ":" ++ located ty t) + +and optional_type_scheme_annotation = function + | None -> empty + | Some t -> type_scheme_annotation t + +and type_scheme_annotation t = + group (break 1 ^^ string ":" ++ located type_scheme t) + +and type_scheme (ForallTy (ts, t)) = + type_parameters_bracketed ts ^^ located ty t + +and ty t = match t with + | TyCon (tcon, []) -> + type_constructor tcon + | TyCon (tcon, tys) -> + group (type_constructor tcon + ^^ angles ( + separate_map (string "," ^^ break 1) (located ty) tys + )) + | TyVar tvar -> + type_variable tvar + | TyTuple tys -> + parens (separate_map (break 1 ^^ string "*" ^^ break 1) (located ty) tys) + | TyArrow (in_, out) -> + group ( + ((located may_paren_ty) in_ + ++ string "->") ++ located may_paren_ty out) + +and may_paren_ty t = + match t with + | TyArrow _ -> parens (ty t) + | _ -> ty t + +and type_constructor (TCon s) = + string s + +and type_variable (TId x) = + string x + +and identifier (Id x) = + string x + +and is_infix s = + String.length s >= 2 && s.[0] = '`' && s.[String.length s - 1] = '`' + +and infix_operator s = + string (String.(sub s 1 (length s - 2))) + +and expression = function + | Literal l -> + located literal l + + | Variable (x, tys) -> + located identifier x ^^ optional_type_instantiation tys + + | TypeAnnotation (e, t) -> + parens (located expression e ++ group (string ":" ++ located ty t)) + + | Define (vdef, e2) -> + nest 2 ( + group (value_definition true vdef ++ string ";" + )) + ^^ break 1 ^^ group (located expression e2) + + | Fun (fdef) -> + string "\\" + ++ function_definition true (space ^^ string "->" ^^ break 1) fdef + + | Record (ls, tys) -> + braces (separate_map (comma ^^ break 1) make_label ls) + ^^ optional_type_instantiation tys + + | Apply ({ value = Apply ({ value = Variable ({ value = Id x; _ }, _); _ }, lhs); _ }, rhs) + when is_infix x -> + parens (located expression lhs ++ infix_operator x ++ located expression rhs) + + | Apply (a, b) -> + group ( + located may_paren_expression a + ++ located may_paren_expression b + ) + + | IfThenElse (c, t, e) -> + group (string "if" ++ guarded_expression (c, t)) + ^^ else_expression e + + | Tagged (k, ts, es) -> + group ( + located dataconstructor k + ^^ optional_type_instantiation ts + ^^ (match es with + | [] -> + empty + | es -> + parens ( + separate_map (colon ^^ break 1) (located expression) es + )) + ) + + | Tuple es -> + group ( + parens ( + separate_map (colon ^^ break 1) (located expression) es + )) + + | Case (e, bs) -> + group ( + group (group ( + string "match" + ++ parens (located expression e)) ++ string "{" + ) + ++ group (separate_map (break 1) (located branch) bs) + ++ string "}" + ) + + | Field (e, l, ts) -> + located may_paren_expression e ^^ string "." ^^ located label l + ^^ optional_type_instantiation ts + + | Sequence es -> + separate_map (semicolon ^^ break 1) (located may_paren_expression) es + + | Ref e -> + string "ref" ++ located may_paren_expression e + + | Assign (lhs, rhs) -> + group (located may_paren_expression lhs + ++ string ":=" + ++ located expression rhs) + + | Read e -> + group (parens (string "!" ++ located may_paren_expression e)) + + | While (e, b) -> + nest 2 (group (string "while" ++ parens (located expression e) + ++ braces' (located expression b))) + + | For (x, start, stop, e) -> + nest 2 (group ( + string "for" + ++ located identifier x + ++ string "from" + ++ parens (located expression start) + ++ string "to" + ++ parens (located expression stop) + ++ braces' (located expression e))) + + +and delimit l r d = + surround 2 1 (!^ l) d (!^ r) + +and braces' d = + delimit "{" "}" d + +and make_label (l, e) = + located label l ++ string "=" ++ located expression e + +and guarded_expression (c, t) = + nest 2 ( + parens (located expression c) + ^^ (break 1) + ^^ prefix 2 1 (!^ "then") (braces' (located expression t)) + ) + +and optional_type_instantiation = function + | None -> + empty + | Some tys -> + space + ^^ string "<" + ++ separate_map (comma ^^ break 1) (located may_paren_ty) tys + ++ string ">" + +and else_expression e = + break 1 ^^ prefix 2 1 (!^ "else") (braces' (located expression e)) + +and function_type_arguments = function + | None -> + empty + | Some ts -> + angles (separate_map (break 1) (located ty) ts) + +and may_paren_under_if e = match e with + | IfThenElse _ -> + parens (expression e) + | _ -> + expression e + +and delimited = function + | Record _ | For _ | Variable _ | Tagged _ | Literal _ + | While _ | Tuple _ | TypeAnnotation _ -> + (* Delimited expressions, no need to put parenthesis around. + Some inner sub-expressions may need parens, though *) + true + | Define _ | IfThenElse _ | Fun _ | Apply _ | Field _ + | Ref _ | Read _ | Assign _ | Case _ | Sequence _ -> + false + +and may_paren_expression e = + if delimited e then expression e else parens (expression e) + +and if_paren_expression b e = + if b && not (delimited e) then parens (expression e) else expression e + +and branch (Branch (p, e)) = + group (nest 2 (group (string "|" ++ located pattern p ++ string "->") + ++ located may_paren_expression e)) + +and patterns ps = + parens (separate_map (comma ^^ break 1) (located pattern) ps) + +and pattern = function + | PWildcard -> + string "_" + | PVariable x -> + located identifier x + | PTypeAnnotation (p, t) -> + parens (located pattern p ++ string ":" ++ located ty t) + | PTaggedValue (k, tys, ps) -> + located dataconstructor k + ^^ optional_type_instantiation tys + ^^ (match ps with + | [] -> + empty + | ps -> + parens (separate_map (comma ^^ break 1) (located pattern) ps) + ) + | PTuple ps -> + parens (separate_map (comma ^^ break 1) (located pattern) ps) + | PRecord (ls, tys) -> + braces (separate_map (comma ^^ break 1) label_pattern ls) + ++ optional_type_instantiation tys + | PAnd ps -> + parens + (separate_map (break 1 ^^ string "&" ^^ break 1) (located pattern) ps) + | POr ps -> + parens + (separate_map (break 1 ^^ string "|" ^^ break 1) (located pattern) ps) + | PLiteral l -> + located literal l + +and label_pattern (f, p) = + located label f ++ string "=" ++ located pattern p + +and literal = function + | LInt x -> + int x + | LChar c -> + char c + | LString s -> + string_literal s + +and char c = + group (string "'" ^^ string (Char.escaped c) ^^ string "'") + +and string_literal s = + group (string "\"" ^^ string (String.escaped s) ^^ string "\"") + +let to_string f x = + let b = Buffer.create 13 in + ToBuffer.pretty 0.8 80 b (group (f x)); + Buffer.contents b diff --git a/flap/src/hopix/hopixSyntacticSugar.mli b/flap/src/hopix/hopixSyntacticSugar.mli new file mode 100644 index 0000000..74a2dc2 --- /dev/null +++ b/flap/src/hopix/hopixSyntacticSugar.mli @@ -0,0 +1,26 @@ +open Position +open HopixAST + +(** [fresh_identifier ()] returns a new fresh identifier each time it + is called. *) +val fresh_identifier : unit -> identifier + +(** [make_multi_assignments [e1; ...; eN] [f1; ...; fN]] returns + an expression of the form: + [ + let x_1 = f1 in + ... + let x_N = fN in + e1 := x1; + ... + eN := xN + ] *) +val make_multi_assignments + : expression located list -> expression located list -> expression + +(** [make_delayed_computation e] returns an expression of the form: + + [ \() => e ] + +*) +val make_delayed_computation : expression located -> expression diff --git a/flap/src/hopix/hopixTypechecker.ml b/flap/src/hopix/hopixTypechecker.ml new file mode 100644 index 0000000..b1b324f --- /dev/null +++ b/flap/src/hopix/hopixTypechecker.ml @@ -0,0 +1,102 @@ +(** This module implements a bidirectional type checker for Hopix. *) + +open HopixAST + +(** Error messages *) + +let invalid_instantiation pos given expected = + HopixTypes.type_error pos ( + Printf.sprintf + "Invalid number of types in instantiation: \ + %d given while %d were expected." given expected + ) + +let check_equal_types pos ~expected ~given = + if expected <> given + then + HopixTypes.(type_error pos + Printf.(sprintf + "Type mismatch.\nExpected:\n %s\nGiven:\n %s" + (string_of_aty expected) + (string_of_aty given))) + +(** Linearity-checking code for patterns *) + +let rec check_pattern_linearity + : identifier list -> pattern Position.located -> identifier list + = fun vars Position.{ value; position; } -> + failwith "Students! This is your job!" + +(** Type-checking code *) + +let check_type_scheme : + HopixTypes.typing_environment -> + Position.t -> + HopixAST.type_scheme -> + HopixTypes.aty_scheme * HopixTypes.typing_environment + = fun env pos (ForallTy (ts, ty)) -> + failwith "Students! This is your job!" + +let synth_literal : HopixAST.literal -> HopixTypes.aty = + fun l -> + failwith "Students! This is your job!" + +let rec check_pattern : + HopixTypes.typing_environment -> + HopixAST.pattern Position.located -> + HopixTypes.aty -> + HopixTypes.typing_environment + = fun env Position.({ value = p; position = pos; } as pat) expected -> + failwith "Students! This is your job!" + +and synth_pattern : + HopixTypes.typing_environment -> + HopixAST.pattern Position.located -> + HopixTypes.aty * HopixTypes.typing_environment + = fun env Position.{ value = p; position = pos; } -> + failwith "Students! This is your job!" + +let rec synth_expression : + HopixTypes.typing_environment -> + HopixAST.expression Position.located -> + HopixTypes.aty + = fun env Position.{ value = e; position = pos; } -> + failwith "Students! This is your job!" + +and check_expression : + HopixTypes.typing_environment -> + HopixAST.expression Position.located -> + HopixTypes.aty -> + unit + = fun env (Position.{ value = e; position = pos; } as exp) expected -> + failwith "Students! This is your job!" + +and check_value_definition : + HopixTypes.typing_environment -> + HopixAST.value_definition -> + HopixTypes.typing_environment + = fun env def -> + failwith "Students! This is your job!" + +let check_definition env = function + | DefineValue vdef -> + check_value_definition env vdef + + | DefineType (t, ts, tdef) -> + let ts = List.map Position.value ts in + HopixTypes.bind_type_definition (Position.value t) ts tdef env + + | DeclareExtern (x, tys) -> + let tys, _ = Position.located_pos (check_type_scheme env) tys in + HopixTypes.bind_value (Position.value x) tys env + +let typecheck env program = + List.fold_left + (fun env d -> Position.located (check_definition env) d) + env program + +type typing_environment = HopixTypes.typing_environment + +let initial_typing_environment = HopixTypes.initial_typing_environment + +let print_typing_environment = HopixTypes.string_of_typing_environment diff --git a/flap/src/hopix/hopixTypes.ml b/flap/src/hopix/hopixTypes.ml new file mode 100644 index 0000000..dcf0e64 --- /dev/null +++ b/flap/src/hopix/hopixTypes.ml @@ -0,0 +1,493 @@ +open HopixAST +open HopixASTHelper + +let type_error = Error.error "typechecking" + +type variable = type_variable + +type aty = + | ATyVar of type_variable + | ATyCon of type_constructor * aty list + | ATyTuple of aty list + | ATyArrow of aty * aty + +let make_fresh_name_generator () = + let r = ref (-1) in + let mangle () = + if !r > 26 then + "a" ^ string_of_int !r + else + String.make 1 (Char.(chr (code 'a' + !r))) + in + fun () -> + incr r; TId ("`" ^ mangle ()) + +let fresh = make_fresh_name_generator () + +let rec hprod_destruct = function + | ATyTuple tys -> List.(flatten (map hprod_destruct tys)) + | ty -> [ty] + +let hprod tys = + ATyTuple (List.(flatten (map hprod_destruct tys))) + +let rec aty_of_ty = function + | TyVar x -> ATyVar x + | TyCon (t, ts) -> ATyCon (t, List.map aty_of_ty' ts) + | TyArrow (ins, out) -> ATyArrow (aty_of_ty' ins, aty_of_ty' out) + | TyTuple ins -> hprod (List.map aty_of_ty' ins) + +and aty_of_ty' x = aty_of_ty (Position.value x) + +let pretty_print_aty bound_vars aty = + let fresh = make_fresh_name_generator () in + let r = ref [] in + let print_var = + fun x -> + (if not (List.mem x bound_vars) then + x + else try + List.assoc x !r + with Not_found -> + let y = fresh () in + r := (x, y) :: !r; + y + ) |> function (TId x) -> x + in + let rec print_aty = function + | ATyVar x -> + print_var x + | ATyArrow (ins, out) -> + let ins = print_aty' ins in + let out = print_aty' out in + ins ^ " -> " ^ out + | ATyTuple tys -> + String.concat " * " (List.map print_aty' tys) + | ATyCon (TCon x, []) -> + x + | ATyCon (TCon x, ts) -> + x ^ "<" ^ String.concat ", " (List.map print_aty' ts) ^ ">" + and print_aty' = function + | (ATyArrow (_, _)) as t -> "(" ^ print_aty t ^ ")" + | x -> print_aty x + in + let s = print_aty aty in + (s, !r) + +let string_of_aty aty = fst (pretty_print_aty [] aty) + +let tvar x = + ATyVar (TId x) + +let ( --> ) tys ty = + List.fold_left (fun ty aty -> ATyArrow (aty, ty)) ty (List.rev tys) + +exception NotAFunction + +let output_type_of_function = function + | ATyArrow (_, ty) -> ty + | _ -> raise NotAFunction + +let constant x = TCon x, ATyCon (TCon x, []) +let tcunit, hunit = constant "unit" +let tcbool, hbool = constant "bool" +let tcint, hint = constant "int" +let tcstring, hstring = constant "string" +let tcchar, hchar = constant "char" + +let tcref = TCon "mut" +let href ty = ATyCon (tcref, [ty]) + +exception NotAReference + +let type_error_wrong_shape shape pos given = + type_error pos + (Printf.sprintf + "This expression has type %s which should be a %s type." + (string_of_aty given) + shape) + +type 'res destruction_fun = Position.t -> aty -> 'res + +let destruct_function_type pos ty = + match ty with + | ATyArrow (dom, cod) -> + dom, cod + | given -> + type_error_wrong_shape "function" pos given + +let rec destruct_function_type_maximally pos = function + | ATyArrow (ins, out) -> + let ins', out = destruct_function_type_maximally pos out in + (ins :: ins', out) + | ty -> + ([], ty) + +let destruct_product_type pos ty = + match ty with + | ATyTuple tys -> + tys + | given -> + type_error_wrong_shape "product" pos given + +let destruct_constructed_type pos ty = + match ty with + | ATyCon (tc, tys) -> + tc, tys + | given -> + type_error_wrong_shape "constructed" pos given + +let destruct_reference_type pos ty = + match ty with + | ATyCon (tc, [ty]) when tc = tcref -> + ty + | given -> + type_error_wrong_shape "reference" pos given + +let rec occurs x = function + | ATyVar tv -> x = tv + | ATyCon (_, tys) -> List.exists (occurs x) tys + | ATyArrow (ins, out) -> List.exists (occurs x) [out; ins] + | ATyTuple tys -> List.exists (occurs x) tys + +let free_type_variables ty = + let rec aux accu = function + | ATyVar tv -> TypeVariableSet.add tv accu + | ATyCon (_, tys) -> aux' accu tys + | ATyArrow (ins, out) -> aux (aux accu out) ins + | ATyTuple tys -> aux' accu tys + and aux' accu tys = List.fold_left aux accu tys + in + aux TypeVariableSet.empty ty + +type aty_scheme = Scheme of type_variable list * aty + +let rec ty_of_aty' = function + | ATyVar tv -> + TyVar tv + | ATyCon (tycon, atys) -> + TyCon (tycon, List.map ty_of_aty atys) + | ATyArrow (atydom, atycod) -> + TyArrow (ty_of_aty atydom, ty_of_aty atycod) + | ATyTuple atys -> + TyTuple (List.map ty_of_aty atys) + +and ty_of_aty aty = Position.unknown_pos (ty_of_aty' aty) + +let type_scheme_of_aty_scheme (Scheme (bound, aty)) = + ForallTy (List.map Position.unknown_pos bound, ty_of_aty aty) + +let pp_aty_scheme atys = + HopixPrettyPrinter.type_scheme @@ type_scheme_of_aty_scheme atys + +let free_type_variables_scheme (Scheme (bound, aty)) = + let open TypeVariableSet in + diff (free_type_variables aty) (of_list bound) + +let mk_type_scheme ty = + Scheme (TypeVariableSet.elements @@ free_type_variables ty, ty) + +let monomorphic_type_scheme ty = + Scheme ([], ty) + +exception NotAMonotype + +let type_of_monotype = function + | Scheme ([], ty) -> ty + | _ -> raise NotAMonotype + +exception InvalidInstantiation of { expected : int; given : int; } + +let rec substitute phi = function + | ATyVar tv -> + (try List.assoc tv phi with Not_found -> ATyVar tv) + | ATyArrow (ins, out) -> + ATyArrow (substitute phi ins, substitute phi out) + | ATyCon (t, tys) -> + ATyCon (t, List.map (substitute phi) tys) + | ATyTuple tys -> + hprod (List.map (substitute phi) tys) + +let instantiate_type_scheme (Scheme (ts, ty)) types = + if List.(length ts <> length types) then + raise (InvalidInstantiation { expected = List.length ts; + given = List.length types; }); + let substitution = List.combine ts types in + substitute substitution ty + +let refresh_type_scheme (Scheme (ts, ty)) = + let ts' = List.map (fun _ -> fresh ()) ts in + let phi = List.(map (fun (x, y) -> (x, ATyVar y)) (combine ts ts')) in + Scheme (ts', substitute phi ty) + +type type_information = + | Abstract + | Sum of constructor list + | Record of label list + +type typing_environment = { + values : (identifier * aty_scheme) list; + constructors : (constructor * aty_scheme) list; + destructors : (label * aty_scheme) list; + type_constructors : (type_constructor * (int * type_information)) list; + type_variables : type_variable list; +} + +let pp_typing_environment env = + let open PPrint in + let pp_binding pp_id (x, tys) = + group (pp_id x ^^ space ^^ colon ^/^ pp_aty_scheme tys) + in + group @@ separate_map + (semi ^^ break 1) + (pp_binding HopixPrettyPrinter.identifier) env.values + +let free_type_variables_env_values { values; _ } = + List.fold_left + (fun free (_, tys) -> + TypeVariableSet.union free @@ free_type_variables_scheme tys) + TypeVariableSet.empty + values + +let generalize_type_scheme env aty = + let open TypeVariableSet in + let free_aty = free_type_variables aty in + let free_env = free_type_variables_env_values env in + Scheme (elements @@ diff free_aty free_env, aty) + +let diffdomain tenv tenv' = + let d = + List.fold_left (fun s (x, _) -> + if not (List.mem_assoc x tenv.values) then x :: s else s + ) [] tenv'.values + in + List.sort compare d + +type binding = + | Identifier of identifier + | TypeConstructor of type_constructor + | Constructor of constructor + | Label of label + +exception Unbound of Position.position * binding + +let string_of_binding = function + | Identifier (Id x) -> Printf.sprintf "identifier `%s'" x + | TypeConstructor (TCon t) -> Printf.sprintf "type constructor `%s'" t + | Constructor (KId k) -> Printf.sprintf "constructor `%s'" k + | Label (LId l) -> Printf.sprintf "label `%s'" l + +let check_well_formed_type pos env ty = + let rec aux = function + | ATyVar ((TId a) as x) -> + if not (List.mem x env.type_variables) then + type_error pos ( + Printf.sprintf "Ill-formed type: unbound type variable %s." a + ) + | ATyCon (tcon, atys) -> + (try + let (arity, _) = List.assoc tcon env.type_constructors in + List.iter aux atys; + if List.length atys <> arity then + type_error pos "Ill-formed type: invalid arity." + with Not_found -> + type_error pos "Ill-formed type: unbound type constructor.") + + | ATyTuple tys -> + List.iter aux tys + + | ATyArrow (ins, out) -> + aux ins; + aux out + in + aux ty + +let internalize_ty env ty = + let pos = Position.position ty in + let ty = Position.value ty in + let aty = aty_of_ty ty in + check_well_formed_type pos env aty; + aty + +let empty_typing_environment = { + values = []; + constructors = []; + type_constructors = []; + destructors = []; + type_variables = [] +} + +let print_tenv env = + Printf.sprintf "tvs: %s\n" ( + String.concat ", " (List.map (fun (TId x) -> x) env.type_variables) + ) + +let bind_type_variable pos env tv = + if List.mem tv env.type_variables then + type_error pos ( + Printf.sprintf + "The type variable `%s' is already bound in the environment." + (HopixPrettyPrinter.(to_string type_variable tv)) + ); + { env with type_variables = tv :: env.type_variables } + +let bind_type_variables pos env ts = + List.fold_left (fun env t -> + bind_type_variable pos env t + ) env ts + +let is_type_variable_defined _ env tv = + List.mem tv env.type_variables + +let bind_value x scheme env = { + env with values = (x, scheme) :: env.values +} + +type 'key type_scheme_lookup_fun = + Position.t -> 'key -> typing_environment -> aty_scheme + +let lookup_type_scheme_of_identifier pos x env = + try + List.assoc x env.values + with Not_found -> + raise (Unbound (pos, Identifier x)) + +let make_pre_type_environment env ts x arity tdef = + let env = bind_type_variables Position.dummy env ts in + let type_constructors = (x, (arity, tdef)) :: env.type_constructors in + { env with type_constructors; constructors = [] } + +let bind_abstract_type x ts env = + let arity = List.length ts in + let type_constructors = (x, (arity, Abstract)) :: env.type_constructors in + { env with type_constructors } + +let bind_sum_type_definition x ts ds env = + let arity = List.length ts in + let constructors = List.map (fun (k, _) -> Position.value k) ds in + let pre_env = make_pre_type_environment env ts x arity (Sum constructors) in + let constructor_definition (k, tys) = + let atys = List.map (internalize_ty pre_env) tys in + let scheme = + Scheme (ts, atys --> ATyCon (x, List.map (fun v -> ATyVar v) ts)) + in + (Position.value k, scheme) + in + let constructors = List.map constructor_definition ds @ env.constructors in + let type_constructors = + (x, (arity, Sum (List.map fst constructors))) :: env.type_constructors + in + { env with type_constructors; constructors } + +let bind_record_type_definition x ts fs env = + let arity = List.length ts in + let labels = List.map (fun (l, _) -> Position.value l) fs in + let pre_env = make_pre_type_environment env ts x arity (Record labels) in + let destructor_definition (l, ty) = + let aty = internalize_ty pre_env ty in + let scheme = + Scheme (ts, [ATyCon (x, List.map (fun v -> ATyVar v) ts)] --> aty) + in + (Position.value l, scheme) + in + let destructors = List.map destructor_definition fs @ env.destructors in + let type_constructors = + (x, (arity, Record labels)) :: env.type_constructors + in + { env with type_constructors; destructors } + +let bind_type_definition x ts td tenv = + match td with + | DefineSumType ks -> + bind_sum_type_definition x ts ks tenv + | DefineRecordType fs -> + bind_record_type_definition x ts fs tenv + | Abstract -> + bind_abstract_type x ts tenv + +let lookup_type_scheme_of_constructor pos k env = + try + List.assoc k env.constructors + with Not_found -> + raise (Unbound (pos, Constructor k)) + +let lookup_type_scheme_of_label pos l env = + try + List.assoc l env.destructors + with Not_found -> + raise (Unbound (pos, Label l)) + +let lookup_information_of_type_constructor pos ((TCon t) as tc) env = + try let _, info = List.assoc tc env.type_constructors in info + with Not_found -> + type_error pos Printf.(sprintf "Unbound type constructor %s." t) + +let lookup_fields_of_type_constructor pos ((TCon t) as tc) env = + match lookup_information_of_type_constructor pos tc env with + | Record fields -> fields + | _ -> type_error pos Printf.(sprintf "Type %s is not a record type." t) + +let lookup_type_constructor_of_label pos l env = + try + let label_type_definition (_, (_, d)) = + match d with + | Record labels -> List.mem l labels + | _ -> false + in + let (tycon, (arity, labels)) = + List.find label_type_definition env.type_constructors + in + let labels = match labels with Record ls -> ls | _ -> assert false in + (tycon, arity, labels) + with Not_found -> + raise (Unbound (pos, Label l)) + +let initial_typing_environment () = + empty_typing_environment |> + List.fold_right (fun ti env -> bind_abstract_type ti [] env) [ + tcunit; tcstring; tcchar; tcint; tcbool + ] |> + bind_abstract_type (TCon "mut") [TId "'a"] + |> List.fold_right (fun (x, s) env -> + bind_value (Id x) (mk_type_scheme s) env + ) [ + "true", hbool; + "false", hbool; + "nothing" , hunit; + "print_int", [hint] --> hunit; + "print_string", [hstring] --> hunit; + "print", [tvar "'a"] --> hunit; + "`||`", [hbool; hbool] --> hbool; + "`&&`", [hbool; hbool] --> hbool; + "`=?`", [hint; hint] --> hbool; + "`<=?`", [hint; hint] --> hbool; + "`>=?`", [hint; hint] --> hbool; + "` hbool; + "`>?`", [hint; hint] --> hbool; + "`+`", [hint; hint] --> hint; + "`*`", [hint; hint] --> hint; + "`-`", [hint; hint] --> hint; + "`/`", [hint; hint] --> hint; + ] + +let print_type_scheme (Scheme (ts, aty)) = + let sty, subst = pretty_print_aty ts aty in + let ts = List.(map (fun x -> assoc x subst) ts) in + let forall = + let type_variable (TId s) = s in + match ts with + | [] -> "" + | ts -> "[" ^ String.concat ", " (List.map type_variable ts) ^ "] " + in + forall ^ sty + +let string_of_declaration (Id x, s) = + x ^ " : " ^ print_type_scheme s + +let string_of_typing_environment tenv = + let excluded = initial_typing_environment () in + let values = List.filter (fun (x, _) -> + not (List.mem_assoc x excluded.values) + ) (List.rev tenv.values) + in + String.concat "\n" (List.map string_of_declaration values) diff --git a/flap/src/hopix/hopixTypes.mli b/flap/src/hopix/hopixTypes.mli new file mode 100644 index 0000000..e023f3a --- /dev/null +++ b/flap/src/hopix/hopixTypes.mli @@ -0,0 +1,97 @@ +open HopixAST + +(** Abstract syntax for types. + + The following internal syntax for types is the same as the one for + the types [ty] defined in {!HopixAST} except that all positions + have been erased. + + *) +type aty = + | ATyVar of type_variable + | ATyCon of type_constructor * aty list + | ATyTuple of aty list + | ATyArrow of aty * aty + +type aty_scheme = Scheme of type_variable list * aty + +val string_of_aty : aty -> string + +val monomorphic_type_scheme : aty -> aty_scheme + +val instantiate_type_scheme : aty_scheme -> aty list -> aty + +type 'res destruction_fun = Position.t -> aty -> 'res + +val destruct_function_type : (aty * aty) destruction_fun + +val destruct_function_type_maximally : (aty list * aty) destruction_fun + +val destruct_product_type : aty list destruction_fun + +val destruct_constructed_type : (type_constructor * aty list) destruction_fun + +val destruct_reference_type : aty destruction_fun + +type typing_environment + +val initial_typing_environment : unit -> typing_environment + +val string_of_typing_environment : typing_environment -> string + +val bind_type_variable : + Position.t -> typing_environment -> type_variable -> typing_environment + +val bind_type_variables : + Position.t -> typing_environment -> type_variable list -> typing_environment + +val internalize_ty : typing_environment -> ty Position.located -> aty + +type binding = + | Identifier of identifier + | TypeConstructor of type_constructor + | Constructor of constructor + | Label of label + +val string_of_binding : binding -> string + +exception Unbound of Position.position * binding + +exception InvalidInstantiation of { expected : int; given : int; } + +type 'key type_scheme_lookup_fun = + Position.t -> 'key -> typing_environment -> aty_scheme + +val lookup_type_scheme_of_constructor : constructor type_scheme_lookup_fun + +val lookup_type_scheme_of_label : label type_scheme_lookup_fun + +val lookup_type_scheme_of_identifier : identifier type_scheme_lookup_fun + +val lookup_type_constructor_of_label + : Position.t -> label -> typing_environment -> + type_constructor * int * label list + +val lookup_fields_of_type_constructor + : Position.t -> type_constructor -> typing_environment -> label list + +val bind_value + : identifier -> aty_scheme -> typing_environment -> typing_environment + +val bind_type_definition + : type_constructor -> type_variable list -> type_definition + -> typing_environment -> typing_environment + +val type_error : Position.t -> string -> 'a + +val hunit : aty +val hint : aty +val hbool : aty +val hstring : aty +val hchar : aty +val hprod : aty list -> aty +val href : aty -> aty + +val generalize_type_scheme : typing_environment -> aty -> aty_scheme + +val string_of_typing_environment : typing_environment -> string diff --git a/flap/src/options.ml b/flap/src/options.ml new file mode 100644 index 0000000..59ed7c1 --- /dev/null +++ b/flap/src/options.ml @@ -0,0 +1,80 @@ +(** Options *) + +open ExtStd + +let error msg = + Error.global_error + "during analysis of options" + msg + +let make_string_option what kind = + let language = ref "" in + let get () = + if !language = "" then + error (Printf.sprintf "You should specify the %s %s using '--%s'." + kind what kind); + !language + in + let set = ( := ) language in + let is_set () = !language <> "" in + get, set, is_set + +let (get_source_language, set_source_language, is_source_language_set) = + make_string_option "language" "source" + +let (get_target_language, set_target_language, is_target_language_set) = + make_string_option "language" "target" + +type mode = Interactive | Batch + +let mode = ref Batch + +let set_mode = ( := ) mode + +let get_mode () = !mode + +let (get_input_filename, set_input_filename, is_input_filename_set) = + make_string_option "filename" "input" + +let using : string list ref = ref [] +let insert_using x = using := x :: !using +let get_using () = !using + +let set_interactive_mode = function + | true -> set_mode Interactive + | false -> set_mode Batch + +let set_running_mode, get_running_mode = Ref.as_functions false +let set_verbose_mode, get_verbose_mode = Ref.as_functions false +let set_dry_mode, get_dry_mode = Ref.as_functions false +let set_benchmark, get_benchmark = Ref.as_functions false +let set_unsafe, get_unsafe = Ref.as_functions false +let set_show_types, get_show_types = Ref.as_functions false +let set_infer_types, get_infer_types = Ref.as_functions false +let set_check_types, get_check_types = Ref.as_functions true +let set_verbose_eval, get_verbose_eval = Ref.as_functions false +let set_use_sexp_in, get_use_sexp_in = Ref.as_functions false +let set_use_sexp_out, get_use_sexp_out = Ref.as_functions false +let set_scripts_dir, get_scripts_dir = Ref.as_functions "/bin" +let set_include_dir, get_include_dir = Ref.as_functions "/usr/include" +let set_output_file, get_output_file = Ref.as_functions "" +let set_fast_match, get_fast_match = Ref.as_functions false +let set_backend, get_backend = Ref.as_functions "x86-64" +let set_regalloc, get_regalloc = Ref.as_functions "naive" +let set_debug_mode, get_debug_mode = Ref.as_functions false +let set_print_locs, get_print_locs = Ref.functions_of_ref Error.print_locs + +let get_architecture () : (module Architecture.S) = + match get_backend () with + | "x86-64" -> (module X86_64_Architecture) + | s -> error (Printf.sprintf "`%s' is not a valid architecture." s) + +type regalloc_variant = Naive | Realistic + +let get_regalloc_variant () = + match get_regalloc () with + | "naive" -> Naive + | "realistic" -> Realistic + | s -> error ( + Printf.sprintf "`%s' is not a valid register allocation strategy." s + ) diff --git a/flap/src/retrolix/fopixToRetrolix.ml b/flap/src/retrolix/fopixToRetrolix.ml new file mode 100644 index 0000000..bf998e9 --- /dev/null +++ b/flap/src/retrolix/fopixToRetrolix.ml @@ -0,0 +1,404 @@ +(** This module implements a compiler from Fopix to Retrolix. *) + +(** + + Here are the two main problems to be solved. + + 1. Fopix has complex expressions while Retrolix has only atomic + instructions. In addition, in Fopix, scopes can arbitrarily nested + while Retrolix has only one scope per function. + + 2. Fopix is independent from the calling conventions of the target + architecture while Retrolix is not. In particular, hardware registers + are used in Retrolix to pass the first arguments to a function while + in Fopix there is no such mechanism. + +*) + +let error pos msg = + Error.error "compilation" pos msg + +(** As in any module that implements {!Compilers.Compiler}, the source + language and the target language must be specified. *) +module Source = Fopix +module Target = Retrolix +module S = Source.AST +module T = Target.AST + +(** We are targetting the X86_64_Architecture. *) +module Arch = X86_64_Architecture + +(** The compilation environment stores the list of global + variables (to compute local variables) and a table + representing a renaming (for alpha-conversion). *) +type environment = T.IdSet.t * (S.identifier * S.identifier) list + +(** Initially, the environment is empty. *) +let initial_environment () = (T.IdSet.empty, []) + +(** [fresh_label ()] returns a new identifier for a label. *) +let fresh_label = + let c = ref 0 in + fun () -> incr c; T.Label ("l" ^ string_of_int !c) + +(** [fresh_label ()] returns a new identifier for a variable. *) +let fresh_variable = + let c = ref 0 in + fun () -> incr c; T.(Id ("X" ^ string_of_int !c)) + +(** [translate' p env] turns a Fopix program [p] into a Retrolix + program using [env] to retrieve contextual information. *) +let rec translate' p env = + (** The global variables are extracted in a first pass. *) + let (globals, renaming) = env in + let globals = List.fold_left get_globals globals p in + let env = (globals, renaming) in + (** Then, we translate Fopix declarations into Retrolix declarations. *) + let defs = List.map (declaration globals) p in + (defs, env) + +and identifier (S.Id x) = + T.Id x + +and register r = + T.((`Register (RId (Arch.string_of_register r)) : lvalue)) + +and get_globals env = function + | S.DefineValue (x, _) -> + push env x + | _ -> + env + +and push env x = + T.IdSet.add (identifier x) env + +and declaration env = T.(function + | S.DefineValue (S.Id x, e) -> + let x = Id x in + let ec = expression (`Variable x) e in + let locals = locals env ec in + DValues ([x], (locals, ec @ [labelled T.Ret])) + + | S.DefineFunction (S.FunId f, xs, e) -> + Target.AST.( + let in_registers_arguments, _, remaining = Arch.( + ExtStd.List.asymmetric_map2 + (fun r x -> + labelled (Assign (`Variable (identifier x), + Copy, + [(register r :> rvalue)]))) + argument_passing_registers + xs + ) + in + let save_registers, restore_registers = List.( + if Options.(get_regalloc_variant () = Realistic) then + split ( + List.map (fun r -> + let x = `Variable (fresh_variable ()) in + let r = register r in + labelled (Assign (x, Copy, [(r :> rvalue)])), + (fun () -> labelled (Assign (r, Copy, [x]))) + ) Arch.allocable_callee_saved_registers) + else ([], [])) + in + let return = + labelled Ret + in + let prolog = + in_registers_arguments + @ save_registers + in + let postlog = + (List.map (fun f -> f ()) restore_registers) @ + [return] + in + let function_body = + let x = `Variable (fresh_variable ()) in + expression x e @ [ + labelled (Assign (register Arch.return_register, Copy, [x])) + ] + in + let ec = prolog @ function_body @ postlog in + let remaining = List.map identifier remaining in + let locals = locals env ec in + let locals = List.filter (fun x -> not (List.mem x remaining)) locals in + DFunction (FId f, remaining, (locals, ec)) + ) + + | S.ExternalFunction (S.FunId f, _) -> + DExternalFunction (FId f) +) +(** [expression out e] compiles [e] into a block of Retrolix + instructions that stores the evaluation of [e] into [out]. *) +and expression out = T.(function + | S.Literal l -> + [labelled (Assign (out, Copy, [ `Immediate (literal l) ]))] + + | S.Variable (S.Id "true") -> + expression out (S.(Literal (LInt (Mint.one)))) + + | S.Variable (S.Id "false") -> + expression out (S.(Literal (LInt (Mint.zero)))) + + | S.Variable (S.Id x) -> + [labelled (Assign (out, Copy, [ `Variable (Id x) ]))] + + | S.Define (S.Id x, e1, e2) -> + (** Hey student! The following code is wrong in general, + hopefully, you will implement [preprocess] in such a way that + it will work, right? *) + expression (`Variable (Id x)) e1 @ expression out e2 + + | S.While (c, e) -> + let tc = expression out e in + let l = fresh_label () in + let cc = condition (first_label tc) l c in + cc @ tc @ [labelled (Jump (first_label cc))] + @ [l, Comment "Exit of while loop"] + + | S.IfThenElse (c, t, f) -> + let tc = expression out t + and fc = expression out f in + let l = fresh_label () in + condition (first_label tc) (first_label fc) c + @ tc + @ [labelled (Jump l) ] + @ fc + @ [l, Comment "Join control point"] + + | S.FunCall (S.FunId "`&&`", [e1; e2]) -> + expression out (S.(IfThenElse (e1, e2, Variable (Id "false")))) + + | S.FunCall (S.FunId "`||`", [e1; e2]) -> + expression out (S.(IfThenElse (e1, Variable (Id "true"), e2))) + + | S.FunCall (S.FunId f, es) when is_binop f -> + assign out (binop f) es + + | S.FunCall (S.FunId f, _) as e when is_condition f -> + expression out (S.( + IfThenElse (e, Literal (LInt Mint.one), Literal (LInt Mint.zero))) + ) + + | S.FunCall (S.FunId f, actuals) -> + call None (`Immediate (LFun (FId f))) actuals out + + | S.UnknownFunCall (ef, actuals) -> + let f, ef = as_rvalue ef in + ef @ (call None f actuals out) + + | S.Switch (e, cases, default) -> + let f, ef = as_rvalue e in + let l = fresh_label () in + let cases = Array.to_list cases in + let ldefault, cdefault = + match default with + | None -> None, [] + | Some e -> let l, le = expression_block l out e in (Some l, le) + in + let branch lces = function + | None -> (match ldefault with + | None -> assert false (* By exhaustiveness. *) + | Some l -> (lces, l)) + | Some e -> + let (l, lces') = expression_block l out e in + (lces @ lces', l) + in + let lces, lcases = ExtStd.List.foldmap branch cdefault cases in + ef @ [ + labelled (T.Switch (f, Array.of_list lcases, ldefault)) + ] + @ lces + @ [(l, Comment "Join control point")] +) + +and expression_block l out (e : S.expression) = + let lstart = fresh_label () in + let ec = expression out e in + (lstart, [(lstart, T.Comment "Start block")] @ ec @ [labelled (T.Jump l)]) + +and call tail = + match tail with + | None -> + normal_call + | Some _ -> + failwith "Not implemented yet" + +and push_input_arguments actuals = + let xs, es = List.(split (map as_rvalue actuals)) in + (** The first four arguments are passed to a0 ... a3. *) + let in_registers_arguments, _, remaining = Arch.( + ExtStd.List.asymmetric_map2 + (fun r x -> + labelled (Target.AST.(Assign (`Register (RId (string_of_register r)), + Copy, + [x])))) + argument_passing_registers + xs + ) + in + (List.flatten es @ in_registers_arguments, remaining) + +and normal_call f actuals out = Target.AST.( + (** Implementing calling conventions. *) + let _save_registers, _restore_registers = List.( + map (fun r -> + let x = `Variable (fresh_variable ()) in + let r = register r in + labelled (Assign (x, Copy, [(r :> rvalue)])), + (fun () -> labelled (Assign (r, Copy, [x]))) + ) Arch.caller_saved_registers |> split) + in + let in_registers_arguments, remaining = push_input_arguments actuals in + let result_register = register Arch.return_register in + let get_result = + labelled ( + Assign (out, Copy, [ (result_register :> rvalue)]) + ) + in + in_registers_arguments + @ [(labelled (Target.AST.Call (f, remaining, false)))] + @ [get_result] +) + +and as_rvalue e = + let x = `Variable (fresh_variable ()) in + (x, expression x e) + +and as_rvalues rs f = + let xs, es = List.(split (map as_rvalue rs)) in + List.flatten es @ f xs + +and assign out op rs = + as_rvalues rs (fun xs -> + [labelled (T.Assign (out, op, xs))] + ) + +and condition lt lf c = +T.(match c with + | S.FunCall (S.FunId "`&&`", [a; b]) -> + let lta = fresh_label () in + condition lta lf a + @ [ (lta, Comment "Left-hand-side of conjunction is true.") ] + @ condition lt lf b + + | S.FunCall (S.FunId "`||`", [a; b]) -> + let lfa = fresh_label () in + condition lt lfa a + @ [ (lfa, Comment "Left-hand-side of disjunction is false.") ] + @ condition lt lf b + + | S.FunCall (S.FunId f, [a; b]) when is_condition f -> + as_rvalues [a; b] @@ fun args -> [ + labelled (ConditionalJump (condition_op f, args, lt, lf)) + ] + | c -> + let x = fresh_variable () in + expression (`Variable x) c + @ [ labelled (ConditionalJump (EQ, [ `Variable x; + `Immediate (LInt (Mint.of_int 0)) ], + lf, + lt))] +) + +and first_label = function + | [] -> assert false + | (l, _) :: _ -> l + +and labelled i = + (fresh_label (), i) + +and literal = T.(function + | S.LInt x -> + LInt x + | S.LFun (S.FunId f) -> + LFun (FId f) + | S.LChar c -> + LChar c + | S.LString s -> + LString s +) + +and is_binop = function + | "`+`" | "`-`" | "`*`" | "`/`" -> true + | _ -> false + +and binop = T.(function + | "`+`" -> Add + | "`-`" -> Sub + | "`*`" -> Mul + | "`/`" -> Div + | _ -> assert false (* By [is_binop] *) +) + +and is_condition = function + | "`?`" | "`=?`" | "`<=?`" | "`>=?`" -> true + | _ -> false + +and condition_op = T.(function + | "` LT + | "`>?`" -> GT + | "`<=?`" -> LTE + | "`>=?`" -> GTE + | "`=?`" -> EQ + | _ -> assert false +) + +let fresh_name = + let c = ref 0 in + fun (S.Id x) -> incr c; S.Id (x ^ string_of_int !c) + +let rec preprocess p (globals, renaming) = + let renaming, p = ExtStd.List.foldmap declaration renaming p in + (p, (globals, renaming)) + +and rename renaming x = + let y = fresh_name x in + ((x, y) :: renaming, y) + +and declaration renaming = S.(function + | DefineValue (x, e) -> + let renaming, x' = rename renaming x in + (renaming, DefineValue (x', expression renaming e)) + + | DefineFunction (f, xs, e) -> + let renaming', xs = ExtStd.List.foldmap rename renaming xs in + (renaming, DefineFunction (f, xs, expression renaming' e)) + + | ExternalFunction (f, n) -> + (renaming, ExternalFunction (f, n)) +) +and expression renaming = S.(function + | Variable x -> + Variable (try List.assoc x renaming with Not_found -> x) + | Define (x, e1, e2) -> + let renaming, x' = rename renaming x in + Define (x', + expression renaming e1, + expression renaming e2) + | FunCall (f, es) -> + FunCall (f, List.map (expression renaming) es) + | IfThenElse (e1, e2, e3) -> + IfThenElse (expression renaming e1, + expression renaming e2, + expression renaming e3) + | UnknownFunCall (f, es) -> + UnknownFunCall (expression renaming f, + List.map (expression renaming) es) + | Literal l -> + Literal l + | While (e, s) -> + While (expression renaming e, expression renaming s) + | Switch (e, es, d) -> + Switch (expression renaming e, + Array.map (Option.map (expression renaming)) es, + Option.map (expression renaming) d) +) + +(** [translate p env] turns the fopix program [p] into a semantically + equivalent retrolix program. *) +let translate p env = + let p, env = preprocess p env in + let p, env = translate' p env in + (p, env) diff --git a/flap/src/retrolix/retrolix.ml b/flap/src/retrolix/retrolix.ml new file mode 100644 index 0000000..17c47a3 --- /dev/null +++ b/flap/src/retrolix/retrolix.ml @@ -0,0 +1,33 @@ +(** The retrolix programming language. *) + +module AST = RetrolixAST + +let name = "retrolix" + +type ast = + RetrolixAST.t + +let parse lexer_init input = + SyntacticAnalysis.process + ~lexer_init + ~lexer_fun:RetrolixLexer.token + ~parser_fun:RetrolixParser.program + ~input + +let parse_filename filename = + parse Lexing.from_channel (open_in filename) + +let extension = + ".retrolix" + +let executable_format = + false + +let parse_string = + parse Lexing.from_string + +let print_ast ast = + ExtPPrint.to_string RetrolixPrettyPrinter.program ast + +include RetrolixInterpreter +include RetrolixTypechecker diff --git a/flap/src/retrolix/retrolixAST.ml b/flap/src/retrolix/retrolixAST.ml new file mode 100644 index 0000000..082a687 --- /dev/null +++ b/flap/src/retrolix/retrolixAST.ml @@ -0,0 +1,180 @@ +(** The abstract syntax tree for retrolix programs. *) + +(** + + Retrolix is a "Register-Transfer-Language" inspired by one of the + intermediate languages of Compcert, a certified compiler for C. + + Retrolix is an idealized low-level language for the target + architecture. + + Contrary to standard assembly code, a program in Retrolix can + - define and call functions ; + - use an arbitrary number of local variables (also named pseudo-registers) ; + - refer to literals directly in instructions (no data segment). + + Like assembly code, a program in Retrolix: + - has only access to very basic instructions ; + - can use hardware registers ; + - must follow the target architecture calling conventions regarding register + usage to pass function arguments and return ; and register values + preservation through function calls. + + Retrolix is designed to express low-level optimizations in a + target-agnostic way. It is similar to LLVM's IR or GCC's GIMPLE + except that it is simplified for pedagogical purpose. + +*) + +type literal = + | LInt of Mint.t + | LFun of function_identifier + | LChar of char + | LString of string + +and identifier = Id of string + +and label = Label of string + +and function_identifier = FId of string + +type register = RId of string + +type lvalue = [ `Variable of identifier | `Register of register ] + +type rvalue = [ lvalue | `Immediate of literal ] + +type t = definition list + +and definition = + (** DValues (xs, b) is a block [b] that defines global variables [xs]. *) + | DValues of identifier list * block + (** DFunction (f, xs, ys, b) is a function definition with formal + parameters [xs], and block [b]. *) + | DFunction of function_identifier * identifier list * block + | DExternalFunction of function_identifier + +and block = + (** a block consists in a list of local variables and a list of + instructions. *) + identifier list * labelled_instruction list + +and labelled_instruction = + label * instruction + +and instruction = + (** call r (r1, ⋯, rN) tail *) + | Call of rvalue * rvalue list * bool + (** ret r *) + | Ret + (** l ← op r1, ⋯, rN *) + | Assign of lvalue * op * rvalue list + (** jump ℓ *) + | Jump of label + (** jumpif condition r1, r2 → ℓ1, ℓ2 *) + | ConditionalJump of condition * rvalue list * label * label + (** switch r -> l1, ..., lN orelse l. *) + | Switch of rvalue * label array * label option + (** ;; comment *) + | Comment of string + (** exit *) + | Exit + +and op = + | Copy + | Add | Mul | Div | Sub + | And | Or + +and condition = + | GT | LT | GTE | LTE | EQ + +(** We will need the following pieces of information to be carrying + along the translation: *) +module IdCmp = struct + type t = identifier + let equal = (=) + let compare = compare + let print (Id s) = PPrint.string s + let hash = Hashtbl.hash +end +module IdSet = ExtStd.Set (IdCmp) +module IdMap = ExtStd.Map (IdCmp) +module IdHT = Hashtbl.Make (IdCmp) +module FIdCmp = struct + type t = function_identifier + let compare = compare +end +module FIdSet = Set.Make (FIdCmp) +module FIdMap = Map.Make (FIdCmp) +module LabelCmp = struct + type t = label + let equal = (=) + let hash = Hashtbl.hash + let compare = compare + let print (Label s) = PPrint.string s +end +module LabelSet = ExtStd.Set (LabelCmp) +module LabelMap = ExtStd.Map (LabelCmp) +module LabelTab = Hashtbl.Make (LabelCmp) + +(** + + In Retrolix, the toplevel value declarations define global + variables. The identifiers of these variables must be distinct. + +*) +exception GlobalIdentifiersMustBeUnique of identifier + +(** [globals p] returns the global variables of the program [p]. It + checks that each definition is unique. *) +let globals = + List.fold_left (fun globals -> function + | DValues (xs, _) -> + let add globals x = + if IdSet.mem x globals then + raise (GlobalIdentifiersMustBeUnique x); + IdSet.add x globals + in + List.fold_left add globals xs + | _ -> + globals + ) IdSet.empty + +(** [externals p] returns the extern functions of the program [p]. *) +let externals = + List.fold_left (fun externals -> function + | DExternalFunction f -> + FIdSet.add f externals + | _ -> + externals + ) FIdSet.empty + +(** + Every function in Retrolix starts with a declaration + of local variables. So we need a way to compute the + local variables of some generated code. This is the + purpose of the next function. +*) + +(** [locals globals b] takes a set of variables [globals] and returns + the variables use in the list of instructions [b] which are not + in [globals]. *) +let locals globals b = +IdSet.( + let unions = List.fold_left union empty in + let rec locals (_, i) = + match i with + | Call (r, rs, _) -> + unions ([rvalue r] @ List.map rvalue rs) + | Assign (l, _, rs) -> + unions (rvalue (l :> rvalue) :: List.map rvalue rs) + | ConditionalJump (_, rs, _, _) -> + unions (List.map rvalue rs) + | _ -> + empty + and rvalue = function + | `Variable x when not (IdSet.mem x globals) -> singleton x + | _ -> empty + in + elements (unions (List.map locals b)) +) diff --git a/flap/src/retrolix/retrolixConstantFolding.ml b/flap/src/retrolix/retrolixConstantFolding.ml new file mode 100644 index 0000000..45b2a5f --- /dev/null +++ b/flap/src/retrolix/retrolixConstantFolding.ml @@ -0,0 +1,83 @@ +open RetrolixAST +open RetrolixUtils + +let activated = ref false + +module Source = Retrolix + +let shortname = "cf" + +let longname = "constant folding" + +(** {2 The Analysis Itself} *) + +module ConstantDomain = + struct + let global_variables = ref [] + + module D = + struct + type t = + | Bot + | Const of RetrolixAST.literal + | Top + + let print x = + match x with + | Bot -> + PPrint.string "Bot" + | Const l -> + RetrolixPrettyPrinter.literal l + | Top -> + PPrint.string "Top" + + let equal = + Stdlib.(=) + + let compare = + Stdlib.compare + + let le x y = + failwith "Student! This is your job!" + + let bot = + failwith "Student! This is your job!" + + let lub x y = + failwith "Student! This is your job!" + end + + module DV = RetrolixDataflowUtils.PerLValueProperty(D) + include DV + + (* This function sets to [Top] every lvalue that may have been modified by + an opaque function call: caller-saved registers, global variables. *) + let clobber_registers_and_globals x = + failwith "Student! This is your job!" + + + let transfer (lab, insn) x = + failwith "Student! This is your job!" + end + +module ConstantAnalysis = RetrolixDataflowEngines.Default(ConstantDomain) + +(** {2 Putting Everything Together} *) + +let error lab msg = + Printf.eprintf "%sundefined behavior (%s)\n" + (ExtPPrint.to_string (RetrolixPrettyPrinter.label 0) lab) + msg; + exit 1 + +let analyze ((locals, _) as block) = + failwith "Student! This is your job!" + + +let rewrite sol (lab, insn) = + let _, r = sol lab in + failwith "Students! This is your job!" + +let translate p = + ConstantDomain.global_variables := RetrolixUtils.global_variables p; + RetrolixUtils.transform_blocks analyze rewrite p diff --git a/flap/src/retrolix/retrolixDataflowEngines.ml b/flap/src/retrolix/retrolixDataflowEngines.ml new file mode 100644 index 0000000..5145f92 --- /dev/null +++ b/flap/src/retrolix/retrolixDataflowEngines.ml @@ -0,0 +1,130 @@ +open RetrolixDataflowSigs + +open AST + +(** This module implements a slow and inefficient dataflow engine using a very + naive iteration strategy, with no acceleration at all. *) +module Naive : ENGINE = + functor (D : DOMAIN) -> + struct + module D = D + + module Edge = struct + type t = unit + let compare = Stdlib.compare + let print () = PPrint.empty + end + + module FG = RetrolixDataflowUtils.FlowGraph(Edge) + open FG + + type result = label -> (D.t * D.t) + + let same_solution s1 s2 = + LabelMap.equal + (fun (x1, x2) (y1, y2) -> D.equal x1 y1 && D.equal x2 y2) + s1 + s2 + + let input_of, output_of = + let get f sol v = f (LabelMap.find v.FG.Vertex.label sol) in + get fst, get snd + + let join_input x v sol = + let x', y = LabelMap.find v.FG.Vertex.label sol in + LabelMap.add v.FG.Vertex.label (D.lub x x', y) sol + + let join_output y v sol = + let (x, _) = LabelMap.find v.FG.Vertex.label sol in + LabelMap.add v.FG.Vertex.label (x, y) sol + + let transfer dir gr sol = + let is_fwd = dir = `Forward in + let fold_outputs = + if is_fwd then G.fold_successors else G.fold_predecessors + in + let transfer_vertex v sol = + let y = D.transfer (v.Vertex.label, v.Vertex.insn) (input_of sol v) in + let sol = join_output y v sol in + fold_outputs + v.FG.Vertex.label + (fun out () -> join_input y out) + sol + gr.graph + in + G.fold_vertices transfer_vertex gr.graph sol + + let analyze ?(init = `Input D.bot) ~direction block = + let gr = FG.flow_graph_of_block (fun () -> ()) block in + if Options.get_debug_mode () then + ( + let fn = Filename.temp_file "cfg" ".dot" in + let oc = open_out fn in + FG.G.dump_graphviz gr.graph oc; + close_out oc; + Printf.printf "[dataflow] CFG stored in %s.\n" fn + ); + let start = + let input_vertices = + LabelSet.of_list + @@ List.map FG.Vertex.label + @@ match direction with + | `Forward -> FG.G.initial_vertices gr.graph + | `Backward -> FG.G.terminal_vertices gr.graph + in + FG.G.fold_vertices + (fun v init_sol -> + let vl = FG.Vertex.label v in + let x = + match init with + | `Input x -> + if LabelSet.mem vl input_vertices then x else D.bot + | `All f -> + f vl + in + LabelMap.add vl (x, D.bot) init_sol) + gr.FG.graph + LabelMap.empty + in + let rec fix i current = + if Options.get_debug_mode () then + ( + Printf.printf "[dataflow] Solution at iteration %d:\n" i; + ExtPPrint.to_channel + (LabelMap.print + (fun (i, o) -> PPrint.OCaml.tuple [D.print i; D.print o]) + current) + ); + let next = transfer direction gr current in + if same_solution current next then current else fix (i + 1) next + in + let res = fix 0 start in + fun lab -> LabelMap.find lab res + end + +(** This module implements a more efficient strategy involving a worklist and + iterative computation of the solution. *) +module Worklist : ENGINE = + functor (D : DOMAIN) -> + struct + module D = D + + module Edge = struct + type t = unit + let compare () () = 0 + let print () = PPrint.empty + end + + module FG = RetrolixDataflowUtils.FlowGraph(Edge) + open FG + + type result = label -> (D.t * D.t) + + let analyze ?(init = `Input D.bot) ~direction block = + let work = Queue.create () in + let dirty = LabelTab.create 100 in + + failwith "Students! This is your job!" + end + +module Default : ENGINE = Naive diff --git a/flap/src/retrolix/retrolixDataflowSigs.ml b/flap/src/retrolix/retrolixDataflowSigs.ml new file mode 100644 index 0000000..5d0f677 --- /dev/null +++ b/flap/src/retrolix/retrolixDataflowSigs.ml @@ -0,0 +1,48 @@ +module AST = RetrolixAST + +(** A property is the result of a dataflow analysis. The set of properties + should form a semilattice, that is, be ordered, have a least element, and a + least upper bound operator. *) +module type PROPERTY = + sig + (** The type of properties. *) + type t + + val print : t -> PPrint.document + val equal : t -> t -> bool + val compare : t -> t -> int + + (** The ordering relation of the semilattice. *) + val le : t -> t -> bool + (** The smallest element of the semilattice. *) + val bot : t + (** The least upper bound (or "join") of the semilattice. *) + val lub : t -> t -> t + end + +(** A domain provides a space of properties together with a transfer function + that specifies the semantics of an instruction w.r.t. to properties. *) +module type DOMAIN = + sig + include PROPERTY + val transfer : AST.labelled_instruction -> t -> t + end + +(** An analysis provides a way to compute the result of a dataflow analysis for + the specified domain D. *) +module type ANALYSIS = + sig + module D : DOMAIN + + type result = AST.label -> (D.t * D.t) + + val analyze : + ?init:[ `Input of D.t | `All of AST.label -> D.t ] -> + direction:[ `Forward | `Backward ] -> + AST.block -> + result + end + +(** An engine implements an algorithm turning a domain into an analysis for this + domain. *) +module type ENGINE = functor (D : DOMAIN) -> ANALYSIS with module D = D diff --git a/flap/src/retrolix/retrolixDataflowUtils.ml b/flap/src/retrolix/retrolixDataflowUtils.ml new file mode 100644 index 0000000..46e9b5c --- /dev/null +++ b/flap/src/retrolix/retrolixDataflowUtils.ml @@ -0,0 +1,105 @@ +open RetrolixDataflowSigs + +module AST = RetrolixAST +module Utils = RetrolixUtils +module PP = RetrolixPrettyPrinter + +module PerLValueProperty (P : PROPERTY) + : PROPERTY with type t = P.t Utils.LValueMap.t = struct + type t = P.t Utils.LValueMap.t + + let print m = + Utils.LValueMap.print P.print m + + let equal = + Utils.LValueMap.equal P.equal + + let compare = + Utils.LValueMap.compare P.compare + + let le m1 m2 = + Utils.LValueMap.for_all + (fun k x -> + let y = try Utils.LValueMap.find k m2 with Not_found -> P.bot in + P.le x y) + m1 + + let bot = + Utils.LValueMap.empty + + let lub m1 m2 = + let p_of_opt xo = match xo with None -> P.bot | Some x -> x in + let merge _ xo yo = Some (P.lub (p_of_opt xo) (p_of_opt yo)) in + Utils.LValueMap.merge merge m1 m2 + + let bot_lvalues lvs = + List.fold_left + (fun m lv -> Utils.LValueMap.add lv P.bot m) + Utils.LValueMap.empty + (lvs @ List.map RetrolixUtils.register X86_64_Architecture.all_registers) +end + +module FlowGraph (Edge : Digraph.EDGE) = struct + open RetrolixAST + + module Vertex = struct + type t = + { + label : label; + insn : instruction; + } + + let print { label; insn; } = + RetrolixPrettyPrinter.labelled_instruction + RetrolixPrettyPrinter.nodecorations + 0 + (label, insn) + + module Label = struct + type t = label + let compare = Stdlib.compare + let print = RetrolixPrettyPrinter.label 0 + end + + let label { label; _ } = label + end + + module G = Digraph.Make(Edge)(Vertex) + + type t = + { + initial : label; + locals : IdSet.t; + graph : G.t; + } + + let flow_graph_of_block make_default_edge ((locals, insns) : block) = + let initial = + match insns with + | [] -> + failwith "flow_graph_of_block: empty block" + | (initial, _) :: _ -> + initial + in + let locals = + List.fold_left (fun locals id -> IdSet.add id locals) IdSet.empty locals + in + let graph = + List.fold_left + (fun graph (label, insn) -> G.add_vertex graph { label; insn; }) + G.empty + insns + in + let graph = + let targets = RetrolixUtils.instruction_targets insns in + List.fold_left + (fun graph (src, _, ldsts) -> + List.fold_left + (fun graph dst -> G.add_edge graph ~src ~dst (make_default_edge ())) + graph + ldsts) + graph + targets + in + { initial; locals; graph; } +end diff --git a/flap/src/retrolix/retrolixDeadCodeElimination.ml b/flap/src/retrolix/retrolixDeadCodeElimination.ml new file mode 100644 index 0000000..f8c0dd9 --- /dev/null +++ b/flap/src/retrolix/retrolixDeadCodeElimination.ml @@ -0,0 +1,63 @@ +open RetrolixAST +open RetrolixUtils + +let activated = ref false + +module Source = Retrolix + +let shortname = "dce" + +let longname = "dead-code elimination" + +(** {2 The Analysis Itself} *) + +module LivenessDomain = + struct + type t = LValueSet.t + + let print = LValueSet.print + + let equal = LValueSet.equal + + let compare = LValueSet.compare + + let bot = + failwith "Students! This is your job!" + + let le = + failwith "Students! This is your job!" + + let lub = + failwith "Students! This is your job!" + + let global_variables = + ref bot + + + + let gen insn = + failwith "Students! This is your job!" + + let kill insn = + failwith "Students! This is your job!" + + let transfer (_, insn) liveout = + failwith "Students! This is your job!" + end + +module LivenessAnalysis = RetrolixDataflowEngines.Default(LivenessDomain) + +(** {2 Putting Everything Together} *) + +let analyze block = + failwith "Students! This is your job!" + +let rewrite sol (lab, insn) = + failwith "Students! This is your job!" + +let translate p = + LivenessDomain.global_variables := + LValueSet.of_list + @@ List.map (fun v -> `Variable v) + @@ RetrolixUtils.global_variables p; + RetrolixUtils.transform_blocks analyze rewrite p diff --git a/flap/src/retrolix/retrolixInitialization.ml b/flap/src/retrolix/retrolixInitialization.ml new file mode 100644 index 0000000..f828208 --- /dev/null +++ b/flap/src/retrolix/retrolixInitialization.ml @@ -0,0 +1,7 @@ +open Optimizers + +(** Register some compilers that process Retrolix programs. *) +let initialize () = + Languages.register (module Retrolix); + Compilers.(register (optimizing_compiler (module Identity (Retrolix)))); + Compilers.(register (optimizing_compiler (module FopixToRetrolix))) diff --git a/flap/src/retrolix/retrolixInterferenceGraph.ml b/flap/src/retrolix/retrolixInterferenceGraph.ml new file mode 100644 index 0000000..f44ee2c --- /dev/null +++ b/flap/src/retrolix/retrolixInterferenceGraph.ml @@ -0,0 +1,79 @@ +open RetrolixAST +open RetrolixLivenessAnalysis +open RetrolixUtils + +(** Interference graph. *) + +(** In the interference graph, there will be two kinds of edges: *) +type relation = + (** If two variables cannot be represented in the same register + because their liveness ranges intersect, we say that they are in + a conflict relation. *) + | Conflict + + (** If two variables are related by a MOVE instruction, we will try + to put them in the same register, we say that they are in + a preference relation. *) + | Preference + +(** Interference graph. *) + +module EdgeLabel = struct + type t = relation + let compare = compare + let all = [Conflict; Preference] + let to_string = function Conflict -> "c" | Preference -> "p" +end + +module NodeLabel = struct + type t = RetrolixAST.lvalue + let compare = compare + let to_string = RetrolixUtils.string_of_lvalue +end + +module InterferenceGraph = Graph.Make (EdgeLabel) (NodeLabel) + +type t = InterferenceGraph.t + +(** [add_node g n] inserts [n] in [g] if it is not already there. *) +let add_node g n = + try InterferenceGraph.add_node g [n] + with InterferenceGraph.InvalidNode -> g + +(** [add_relation g c n1 n2] creates an edge of kind [c] between [n1] + and [n2]. This function inserts [n1] and [n2] in [g] if needed.*) +let add_relation g c n1 n2 = + assert (n1 <> n2); + let g = add_node g n1 in + let g = add_node g n2 in + InterferenceGraph.add_edge g n1 c n2 + +(** [are_in_relation g c] is a predicate returning [true] if [n1] + and [n2] are in relation [c] in [g]. *) +let are_in_relation g c n1 n2 = + InterferenceGraph.are_connected g n1 c n2 + +(** The empty graph. *) +let empty_graph = InterferenceGraph.empty + +(** + + To construct the interference graph: + + 1. At any non-move instruction that defines variable a (where + live-out variables are b1, ..., bj) add interference edges (a, b1), + ..., (a, bj). + + 2. At a move instruction a ← c (where variables b1, ..., bj are + live-out) add interference edges (a, b1), ..., (a, bj) for any bi + that is not the same as c. Besides, add an preference edge (a, c) + if a and c are not in interference. Notice that interference + overrides preference: if a subsequel instruction implies an + interference between a and c, the preference relation is removed. + + [forbidden] represents the list of global variables: they must not be + colorized. Hence, they more or less behave as the hardware registers. + +*) +let interference_graph forbidden b liveness : t = + failwith "Student! This is your job!" diff --git a/flap/src/retrolix/retrolixInterpreter.ml b/flap/src/retrolix/retrolixInterpreter.ml new file mode 100644 index 0000000..7db2969 --- /dev/null +++ b/flap/src/retrolix/retrolixInterpreter.ml @@ -0,0 +1,383 @@ +(** This module implements the interpreter of the Retrolix programming + language. *) + +open Error +open RetrolixAST + +let error msg = + global_error "retrolix execution" msg + +(** ----------------------- *) +(** {1 Runtime definition } *) +(** ----------------------- *) + +(** This exception is raised to stop the machine. *) +exception ExitNow + +type data = + | DUnit + | DInt of Mint.t + | DBool of bool + | DString of string + | DChar of char + | DLocation of Memory.location + | DFun of function_identifier + +let print_data m data = + let max_depth = 5 in + let rec print_value d v = + if d >= max_depth then "..." + else match v with + | DUnit -> "()" + | DInt x -> Mint.to_string x + | DLocation l -> print_block (d + 1) l + | DFun (FId f) -> "@" ^ f + | DBool true -> "true" + | DBool false -> "false" + | DChar c -> "'" ^ Char.escaped c ^ "'" + | DString s -> "\"" ^ String.escaped s ^ "\"" + and print_block d a = + let b = Memory.dereference m a in + let vs = Array.to_list (Memory.array_of_block b) in + "[ " ^ String.concat "; " (List.map (print_value d) vs) ^ " ]" + in + print_value 0 data + +let type_of = function + | DUnit -> "unit" + | DInt _ -> "int" + | DLocation _ -> "location" + | DFun _ -> "function_ptr" + | DChar _ -> "char" + | DString _ -> "string" + | DBool _ -> "bool" + +let coercion_error expectation v = + error ("Expecting " ^ expectation ^ " get " ^ type_of v) + +let as_int = function DInt x -> x | v -> coercion_error "int" v +let as_loc = function DLocation x -> x | v -> coercion_error "location" v +let as_fun = function DFun f -> f | v -> coercion_error "function_ptr" v + +let from_unit () = DUnit +let from_int x = DInt x +let from_location x = DLocation x +let from_fid x = DFun x + +let is_intermediate (Id x) = (x.[0] = 'X') + +module IdMap = Map.Make (struct + type t = identifier + let compare = compare +end) + +module RIdMap = Map.Make (struct + type t = register + let compare = compare +end) + +module FIdMap = Map.Make (struct + type t = function_identifier + let compare = compare +end) + +type runtime = { + gvariables : data IdMap.t; + lvariables : data IdMap.t; + registers : data RIdMap.t; + mutable memory : data Memory.t; + functions : function_definition FIdMap.t +} + +and function_definition = { + formals : identifier list; + body : block; +} + +type observable = { + new_variables : data IdMap.t +} + +let initial_runtime () = { + gvariables = IdMap.empty; + lvariables = IdMap.empty; + registers = RIdMap.empty; + memory = Memory.create (640 * 1024); + functions = FIdMap.empty; +} + +let print_runtime runtime = + let idmap m = + String.concat "," (List.map (fun (Id s, v) -> + Printf.sprintf "%s = %s" s (print_data runtime.memory v) + ) (IdMap.bindings m)) + in + let ridmap m = + String.concat "," (List.map (fun (RId s, v) -> + Printf.sprintf "%s = %s" s (print_data runtime.memory v) + ) (RIdMap.bindings m)) + in + let gvariables = idmap + and lvariables = idmap + and registers = ridmap + in + Printf.sprintf "\ + gvariables = %s\n\ + lvariables = %s\n\ + registers = %s\n\ +" + (gvariables runtime.gvariables) + (lvariables runtime.lvariables) + (registers runtime.registers) + +(** -------------------------- *) +(** {1 Instruction execution } *) +(** -------------------------- *) + +let evaluate runtime0 (ast : t) = + let extract_function_definition runtime = function + | DValues _ -> runtime + | DFunction (f, formals, body) -> + { runtime with functions = + FIdMap.add f { formals; body } runtime.functions + } + | DExternalFunction _ -> + runtime + in + let rec program runtime ds = + let runtime = List.fold_left extract_function_definition runtime ds in + List.fold_left definition runtime ds + and definition runtime = function + | DValues (xs, b) -> + let runtime = + { runtime with + gvariables = List.fold_left + (fun gvariables x -> IdMap.add x DUnit gvariables) + runtime.gvariables + xs; + } + in + block runtime b + | DFunction _ -> + runtime + | DExternalFunction _ -> + runtime + and block runtime b = + let jump_table = Hashtbl.create 13 in + let rec make = function + | [(l, i)] -> + Hashtbl.add jump_table l (i, None) + | (l, i) :: ((l', _) :: _ as is) -> + Hashtbl.add jump_table l (i, Some l'); + make is + | [] -> assert false + in + make (snd b); + let locals0 = runtime.lvariables in + let locals = fst b in + let start_label = fst (List.hd (snd b)) in + let start = Hashtbl.find jump_table start_label in + let runtime = + List.fold_left (fun r x -> + bind_local r x (DInt Mint.zero) + ) runtime locals + in + let runtime = instruction runtime jump_table start_label start in + { runtime with lvariables = locals0 } + + and instruction runtime jump_table l (i, next) = + let jump l runtime = + if not (Hashtbl.mem jump_table l) then + let Label l = l in + failwith (Printf.sprintf "Label %s not found" l) + else + instruction runtime jump_table l (Hashtbl.find jump_table l) + in + let continue runtime = + match next with + | None -> runtime + | Some l -> jump l runtime + in + match i with + | Call (f, rs, _) -> + call runtime (rvalue runtime f) (List.map (rvalue runtime) rs) + |> continue + | Ret -> + runtime + | Assign (x, o, rs) -> + assign runtime x (op l runtime o (List.map (rvalue runtime) rs)) + |> continue + | Jump l -> + jump l runtime + | ConditionalJump (c, rs, l1, l2) -> + if condition l c (List.map (rvalue runtime) rs) then + jump l1 runtime + else + jump l2 runtime + | Comment _ -> + continue runtime + | Switch (r, ls, default) -> + begin match rvalue runtime r with + | DInt x -> + let x = Mint.to_int x in + if x < Array.length ls then + jump ls.(x) runtime + else + begin match default with + | None -> failwith "Non exhaustive switch." + | Some l -> jump l runtime + end + | _ -> + assert false (* By typing. *) + end + | Exit -> + runtime + and rvalue runtime = function + | `Variable x -> + (try + IdMap.find x runtime.lvariables + with Not_found -> + (try + IdMap.find x runtime.gvariables + with Not_found -> + let Id x = x in + failwith (Printf.sprintf "Variable %s not found" x) + ) + ) + | `Register x -> + (try + RIdMap.find x runtime.registers + with Not_found -> + DInt Mint.zero + ) + | `Immediate l -> + literal l + and op _ _ o vs = + match o, vs with + | Copy, [ v ] -> v + | Add, [ DInt x; DInt y ] -> + DInt (Mint.add x y) + | Mul, [ DInt x; DInt y ] -> + DInt (Mint.mul x y) + | Div, [ DInt x; DInt y ] -> + DInt (Mint.div x y) + | Sub, [ DInt x; DInt y ] -> + DInt (Mint.sub x y) + | _, _ -> + assert false + + and condition (Label l) op vs = + match op, vs with + | GT, [ DInt x1; DInt x2 ] -> x1 > x2 + | LT, [ DInt x1; DInt x2 ] -> x1 < x2 + | GTE, [ DInt x1; DInt x2 ] -> x1 >= x2 + | LTE, [ DInt x1; DInt x2 ] -> x1 <= x2 + | EQ, [ DInt x1; DInt x2 ] -> x1 = x2 + | _, vs -> + failwith ( + Printf.sprintf "Line %s: Invalid comparison with %s\n" + l + (String.concat " " (List.map type_of vs)) + ) + + and literal = function + | LInt x -> DInt x + | LFun f -> DFun f + | LString s -> DString s + | LChar c -> DChar c + + and assign runtime lvalue v = + match lvalue with + | `Variable x -> + if IdMap.mem x runtime.lvariables then + { runtime with lvariables = IdMap.add x v runtime.lvariables } + else if IdMap.mem x runtime.gvariables then + { runtime with gvariables = IdMap.add x v runtime.gvariables } + else failwith "Assignment to an unbound variable." + | `Register x -> + { runtime with registers = RIdMap.add x v runtime.registers } + + and call runtime fv vs = + match fv with + | DFun f -> + (try + let fdef = FIdMap.find f runtime.functions in + let runtime = List.fold_left2 bind_local runtime fdef.formals vs in + block runtime fdef.body + with Not_found -> + external_function runtime vs f + ) + | _ -> + assert false + + and external_function runtime vs (FId f) = + let module Arch : Architecture.S = (val Options.get_architecture ()) in + let mk_reg r = `Register (RId (Arch.string_of_register r)) in + let return value runtime = Arch.( + assign runtime (mk_reg return_register) value + ) + in + let vs = Arch.( + List.(map (rvalue runtime) (map mk_reg argument_passing_registers)) + ) @ vs + in + match f, vs with + | "allocate_block", (DInt size :: _) -> + let addr = Memory.allocate runtime.memory size (DInt Mint.zero) in + return (DLocation addr) runtime + | "write_block", (DLocation location :: DInt i :: v :: _) -> + let block = Memory.dereference runtime.memory location in + Memory.write block i v; + return DUnit runtime + | "read_block", (DLocation location :: DInt i :: _) -> + let block = Memory.dereference runtime.memory location in + return (Memory.read block i) runtime + | "equal_char", (DChar c1 :: DChar c2 :: _) -> + return (DInt (Int64.of_int (if c1 = c2 then 1 else 0))) runtime + | "equal_string", (DString s1 :: DString s2 :: _) -> + return (DInt (Int64.of_int (if s1 = s2 then 1 else 0))) runtime + | ("observe_int" | "print_int"), (DInt i :: _) -> + print_string (Mint.to_string i); + flush stdout; + return DUnit runtime + | "print_char", (DChar i :: _) -> + print_char i; + return DUnit runtime + | "print_string", (DString i :: _) -> + print_string i; + return DUnit runtime + | "add_eight_int", + (DInt i1 :: DInt i2 :: DInt i3 :: DInt i4 + :: DInt i5 :: DInt i6 :: DInt i7 :: DInt i8 :: _) -> + let r = + List.fold_left Mint.add Mint.zero [i1; i2; i3; i4; i5; i6; i7; i8] + in + return (DInt r) runtime + | _ -> + Printf.eprintf + "NoSuchFunction or InvalidApplication of `%s' \ + (%d argument(s) provided : %s)." + f + (List.length vs) + (String.concat " " (List.map type_of vs)); + return DUnit runtime + + and bind_local runtime x v = + { runtime with lvariables = IdMap.add x v runtime.lvariables } + in + let extract_observable runtime = + { new_variables = + IdMap.filter + (fun x _ -> not (IdMap.mem x runtime0.gvariables + || is_intermediate x)) + runtime.gvariables + } + in + let runtime = program runtime0 ast in + let observable = extract_observable runtime in + (runtime, observable) + +let print_observable runtime obs = + String.concat "\n" (List.map (fun (Id k, v) -> + Printf.sprintf "%s = %s" k (print_data runtime.memory v) + ) (IdMap.bindings obs.new_variables)) diff --git a/flap/src/retrolix/retrolixKillMove.ml b/flap/src/retrolix/retrolixKillMove.ml new file mode 100644 index 0000000..41b36e1 --- /dev/null +++ b/flap/src/retrolix/retrolixKillMove.ml @@ -0,0 +1,23 @@ +(** This module removes all useless MOV in a program. *) + +open RetrolixAST + +(** [kill_moves p] produces a program [p] in which we have deleted + all the moves whose destination and source are equal. *) +let kill_moves p = + let rec definition = function + | DValues (xs, b) -> + DValues (xs, block b) + | DFunction (f, xs, b) -> + DFunction (f, xs, block b) + | x -> + x + and block (locals, instructions) = + (locals, List.map (fun (l, i) -> (l, instruction i)) instructions) + and instruction = function + | Assign (x, Copy, [r]) when (x :> rvalue) = r -> + Comment "Killed move" + | i -> + i + in + List.map definition p diff --git a/flap/src/retrolix/retrolixLexer.mll b/flap/src/retrolix/retrolixLexer.mll new file mode 100644 index 0000000..170df38 --- /dev/null +++ b/flap/src/retrolix/retrolixLexer.mll @@ -0,0 +1,167 @@ +{ (* Emacs, use -*- tuareg -*- to open this file! *) + open Lexing + open Error + open Position + open RetrolixParser + + let next_line_and f lexbuf = + Lexing.new_line lexbuf; + f lexbuf + + let error lexbuf = + error "during lexing" (lex_join lexbuf.lex_start_p lexbuf.lex_curr_p) + + let string_buffer = + Buffer.create 13 + +} + +let newline = ('\010' | '\013' | "\013\010") + +let blank = [' ' '\009' '\012'] + +let digit = ['0'-'9'] + +let lowercase_alpha = ['a'-'z' '_'] + +let uppercase_alpha = ['A'-'Z' '_'] + +let alpha = lowercase_alpha | uppercase_alpha + +let alphanum = alpha | digit + +let identifier = alpha alphanum* + +let hexa = [ '0'-'9' 'a'-'f' 'A'-'F'] + +rule token = parse + (** Layout *) + | newline { next_line_and token lexbuf } + | blank+ { token lexbuf } + | ";;" ([^';' '\n']* as c) { COMMENT c } + + (** Keywords *) + | "add" { ADD } + | "mul" { MUL } + | "div" { DIV } + | "sub" { SUB } + | "copy" { COPY } + | "and" { AND } + | "or" { OR } + | "gt" { GT } + | "gte" { GTE } + | "lt" { LT } + | "lte" { LTE } + | "eq" { EQ } + | "jumpif" { JUMPIF } + | "jump" { JUMP } + | "switch" { SWITCH } + | "orelse" { ORELSE } + | "exit" { EXIT } + | "def" { DEF } + | "globals" { GLOBALS } + | "end" { END } + | "local" { LOCAL } + | "ret" { RET } + | "call" { CALL } + | "tail" { TAIL } + | "external" { EXTERNAL } + | identifier as i { ID i } + | '%' (identifier as i) { RID i } + + (** Literals *) + | digit+ as d { INT (Mint.of_string d) } + | '"' { string lexbuf } + | "'\\n'" { LCHAR '\n' } + | "'\\t'" { LCHAR '\t' } + | "'\\b'" { LCHAR '\b' } + | "'\\r'" { LCHAR '\r' } + | "'\\\\'" { LCHAR '\\' } + | "'\\''" { LCHAR '\'' } + | '\'' ([^ '\\' '\''] as c) '\'' { + if (Char.code c < 32) then + error lexbuf ( + Printf.sprintf + "The ASCII character %d is not printable." (Char.code c) + ); + LCHAR c + } + | "'\\" (digit digit digit as i) "'" { + let c = int_of_string i in + if c < 0 || c > 255 then error lexbuf ""; + LCHAR (char_of_int c) + } + | "'\\0" "x" (hexa hexa as i) "'" { + let c = int_of_string ("0x" ^ i) in + if c < 0 || c > 255 then error lexbuf ""; + LCHAR (char_of_int c) + } + | "'\\0" "o" (['0'-'7']+ as i) "'" { + let c = int_of_string ("0o" ^ i) in + if c < 0 || c > 255 then error lexbuf ""; + LCHAR (char_of_int c) + } + | "'\\0" "b" (['0'-'1']+ as i) "'" { + let c = int_of_string ("0b" ^ i) in + if c < 0 || c > 255 then error lexbuf ""; + LCHAR (char_of_int c) + } + + (** Punctuation *) + | ":" { COLON } + | ";" { SEMICOLON } + | "," { COMMA } + | "(" { LPAREN } + | ")" { RPAREN } + | "<-" { LARROW } + | "->" { RARROW } + | "&" { UPPERSAND } + | eof { EOF } + + (** Lexing error. *) + | _ { error lexbuf "unexpected character." } + +and string = parse +| "\\n" { Buffer.add_char string_buffer '\n'; string lexbuf } +| "\\t" { Buffer.add_char string_buffer '\t'; string lexbuf } +| "\\b" { Buffer.add_char string_buffer '\b'; string lexbuf } +| "\\r" { Buffer.add_char string_buffer '\r'; string lexbuf } +| '\\' '\'' { Buffer.add_char string_buffer '\''; string lexbuf } +| '\\' '"' { Buffer.add_char string_buffer '"'; string lexbuf } +| "\\\\" { Buffer.add_char string_buffer '\\'; string lexbuf } + +| '\\' (_ as c) { error lexbuf + (Printf.sprintf "Bad escape sequence in string '\\%c'" c) + } +| "\\" (digit digit digit as i) { + let c = int_of_string i in + if c < 0 || c > 255 then error lexbuf ""; + Buffer.add_char string_buffer (char_of_int c); string lexbuf +} +| "\\0" "x" (hexa hexa as i) { + let c = int_of_string ("0x" ^ i) in + if c < 0 || c > 255 then error lexbuf ""; + Buffer.add_char string_buffer (char_of_int c); string lexbuf +} +| "\\0" "b" (['0'-'1']+ as i) { + let c = int_of_string ("0b" ^ i) in + if c < 0 || c > 255 then error lexbuf ""; + Buffer.add_char string_buffer (char_of_int c); string lexbuf +} +| "\\0" "o" (['0'-'7']+ as i) { + let c = int_of_string ("0o" ^ i) in + if c < 0 || c > 255 then error lexbuf ""; + Buffer.add_char string_buffer (char_of_int c); string lexbuf +} +| '"' { + let s = Buffer.contents string_buffer in + Buffer.clear string_buffer; + LSTRING s +} +| _ as c { + Buffer.add_char string_buffer c; + string lexbuf +} +| eof { + error lexbuf "Unterminated string." +} diff --git a/flap/src/retrolix/retrolixLivenessAnalysis.ml b/flap/src/retrolix/retrolixLivenessAnalysis.ml new file mode 100644 index 0000000..367422c --- /dev/null +++ b/flap/src/retrolix/retrolixLivenessAnalysis.ml @@ -0,0 +1,142 @@ +(** + + Liveness Analysis + ================= + + Liveness analysis is a *data flow* analysis. This means that it + overapproximates the set of possible values that can get involved + at each program point. The notion of "set of possible values" here + should be understood in a very broad set as it usually characterize + an abstract semantic notion like "the definitions that are + available", "the variables that are alive", ... etc. + + To do that, the analysis works on the control-flow graph (CFG) (i) + by defining a *transfer function* for each node that + overapproximates the effects of the node instruction on the values + ; (ii) by refining the overapproximation iteratively until a + fixpoint is reached. + + More precisely, a transfer function is defined by two functions + _IN_ and _OUT_ such that for each program point ℓ, IN(ℓ) is the set + of possible values entering ℓ and OUT(ℓ) is the set of possible + values leaving ℓ. If the _domain_ of the transfer function is equiped + with a partial order with no infinite descending chain and if + _IN_ and _OUT_ are monotonic with respect to this partial order, + then by Kleene-Knaster-Tarski's theorem, there exist a fixpoint. + + For liveness analysis, the transfer functions are defined as follows: + + 1. The analysis abstract domain contains sets of alive variables. + The partial order is ⊆. Given that there is only a finite number + of variables, there is no infinite descending chain. + + 2. x ∈ IN(ℓ) + if x ∈ (OUT(ℓ) \ DEF(ℓ)) ∨ (∃ ℓ' -> ℓ, x ∈ OUT(ℓ')) ∨ x ∈ USE(ℓ) + + x ∈ OUT(ℓ) + if ∃ ℓ', ℓ -> ℓ', x ∈ IN(ℓ') + + where: + - USE(ℓ) is the set of variables possibly read at ℓ. + - DEF(ℓ) is the set of variables possibly written at ℓ. + + or equivalently, removing the redundancy between IN and OUT: + + IN(ℓ) = USE(ℓ) ∪ (OUT(ℓ) ∖ DEF(ℓ)) + OUT(ℓ) = ⋃_{s ∈ successors (ℓ)} IN(s) + + Notice that OUT(ℓ) only depends on the values IN(s) obtained from + its successors. This is a characteristic of *backward data flow + analysis*. We will consider *forward* analyses is a forthcoming + optimization. + +*) + +open RetrolixAST +open RetrolixUtils + +(** + + The result of the liveness analysis is a mapping from program + points to pairs of sets of variables. + +*) +type liveness_analysis_result = { + live_in : LSet.t LabelMap.t; + live_out : LSet.t LabelMap.t; +} + +let empty_results = + { + live_in = LabelMap.empty; + live_out = LabelMap.empty; + } + +let string_of_results r = + Printf.sprintf + "IN:\n%s\nOUT:\n%s\n" + (string_of_lmap r.live_in) + (string_of_lmap r.live_out) + +(** [def i] returns the variables defined by the instruction [i]. *) +let def i = + failwith "Student! This is your job!" + +(** [use i] returns the variables used by [i]. *) +let use i = + failwith "Student! This is your job!" + +(** [instructions_of_labels b] returns a function [instruction_of_label] + such that [instruction_of_label l] returns the instruction labelled by + [l] in the block [b]. *) +let instructions_of_labels ((_, is) : block) = + let m = LabelMap.(List.fold_left (fun m (l, i) -> add l i m) empty is) in + fun l -> try LabelMap.find l m with Not_found -> assert false + +(** [liveness_analysis b] returns the liveness analysis of block [b]. + + There are many ways to implement this analysis, but some + implementations will converge faster than others! Let us recall + what we said during the course: + + 1. A backward analysis converges faster by traversing the CFG + from exit to entry. + + 2. A fixpoint computation is better implemented using a *work list* + that maintains the nodes whose analysis may need a refinement. + + Typically, in the case of the liveness analysis, when considering a + node [n], we compute [IN(n)] and if it has changed we must update + [OUT(p)] for all predecessors of [n] and consider these predecessors + on more time. (This again suggests a backward traversal of the CFG.) + +*) +let liveness_analysis b : liveness_analysis_result = + failwith "Student! This is your job!" + + +(** + + Some debugging functions. + +*) + +let debug_liveness b results = + if Options.get_verbose_mode () then RetrolixPrettyPrinter.( + let get_decoration space m l = + let s = try LabelMap.find l m with Not_found -> LSet.empty in + [PPrint.string ("{ " ^ string_of_lset s ^ " }")] + @ (if space then [PPrint.empty] else []) + in + let decorations = { + pre = get_decoration false results.live_in; + post = get_decoration true results.live_out + } + in + let p = ExtPPrint.to_string (block decorations) b in + Printf.eprintf "Liveness:\n%s\n" p; + ); + results + +let process b = + liveness_analysis b |> debug_liveness b diff --git a/flap/src/retrolix/retrolixParser.mly b/flap/src/retrolix/retrolixParser.mly new file mode 100644 index 0000000..41d450e --- /dev/null +++ b/flap/src/retrolix/retrolixParser.mly @@ -0,0 +1,194 @@ +%{ (* Emacs, use -*- tuareg -*- to open this file! *) + + open RetrolixAST + + let fresh_label = + let r = ref 0 in + fun () -> incr r; Label ("_L" ^ string_of_int !r) + + let bool_of_unit_option o = + match o with None -> false | Some () -> true +%} + +%token SEMICOLON COLON COMMA EOF DEF EXTERNAL GLOBALS END LPAREN RPAREN +%token LOCAL CALL TAIL RET LARROW RARROW EXIT UPPERSAND +%token JUMP JUMPIF SWITCH ORELSE +%token GT LT GTE LTE EQ +%token ADD MUL DIV SUB COPY AND OR +%token INT +%token ID RID COMMENT LSTRING +%token LCHAR +%type lvalue +%type rvalue +%start program + +%% + +program: ds=definition* EOF +{ + ds +} +| error { + let pos = Position.lex_join $startpos $endpos in + Error.error "parsing" pos "Syntax error." +} + +definition: GLOBALS LPAREN xs=separated_list(COMMA, identifier) + RPAREN b=block END { + DValues (xs, b) +} +| DEF f=function_identifier + LPAREN xs=separated_list(COMMA, identifier) RPAREN + b=block + END +{ + DFunction (f, xs, b) +} +| EXTERNAL f=function_identifier +{ + DExternalFunction f +} + +locals: LOCAL xs=separated_nonempty_list(COMMA, identifier) COLON +{ + xs +} +| /* empty word */ +{ + [] +} + +block: xs=locals ls=labelled_instruction* +{ + (xs, ls) +} + +identifier: x=ID { + Id x +} + +labelled_instruction: l=label COLON i=instruction SEMICOLON { + (l, i) +} +| i=instruction SEMICOLON { + (fresh_label (), i) +} + +label: l=ID { + Label l +} + +orelse_label: ORELSE l=label { + l +} + +instruction: + CALL f=rvalue + LPAREN xs=separated_list(COMMA, rvalue) RPAREN t=option(TAIL) +{ + Call (f, xs, bool_of_unit_option t) +} +| f=function_identifier + LPAREN xs=separated_list(COMMA, rvalue) RPAREN t=option(TAIL) +{ + Call (`Immediate (LFun f), xs, bool_of_unit_option t) +} +| RET +{ + Ret +} +| l=lvalue LARROW o=op xs=separated_list(COMMA, rvalue) +{ + Assign (l, o, xs) +} +| JUMP l=label +{ + Jump l +} +| JUMPIF c=condition xs=separated_list(COMMA, rvalue) + RARROW l1=label COMMA l2=label +{ + ConditionalJump (c, xs, l1, l2) +} +| SWITCH rv=rvalue + RARROW ls=separated_list(COMMA, label) + dl=option(orelse_label) +{ + Switch (rv, Array.of_list ls, dl) +} +| c=COMMENT +{ + Comment c +} +| EXIT +{ + Exit +} + +condition: + GT { GT } +| LT { LT } +| GTE { GTE } +| LTE { LTE } +| EQ { EQ } + +op: + ADD { Add } +| MUL { Mul } +| DIV { Div } +| SUB { Sub } +| COPY { Copy } +| AND { And } +| OR { Or } + +lvalue: + v=identifier +{ + `Variable v +} +| r=register +{ + `Register r +} + +register: r=RID +{ + RId r +} + +rvalue: + l=lvalue +{ + (l :> rvalue) +} +| l=literal +{ + `Immediate l +} + +literal: x=INT +{ + LInt x +} +| UPPERSAND x=function_identifier +{ + LFun x +} +| c=LCHAR +{ + LChar c +} +| s=LSTRING +{ + LString s +} + + +%inline located(X): x=X { + Position.with_poss $startpos $endpos x +} + +function_identifier: x=ID +{ + FId x +} diff --git a/flap/src/retrolix/retrolixPrettyPrinter.ml b/flap/src/retrolix/retrolixPrettyPrinter.ml new file mode 100644 index 0000000..7008e1d --- /dev/null +++ b/flap/src/retrolix/retrolixPrettyPrinter.ml @@ -0,0 +1,137 @@ +(** This module offers a pretty-printer for Retrolix programs. *) + +open PPrint + +open RetrolixAST + +let located f x = f (Position.value x) + +let max_label_length c = + List.fold_left (fun m (Label l, _) -> max m (String.length l)) 0 c + +let ( ++ ) x y = + x ^^ break 1 ^^ y + +let vcat = separate_map hardline (fun x -> x) + +type decorations = { + pre : label -> document list; + post : label -> document list; +} + +let nodecorations = { pre = (fun _ -> []); post = (fun _ -> []) } + +let rec program ?(decorations=nodecorations) p = + vcat (List.map (definition decorations) p) + +and definition decorations = function + | DValues (xs, b) -> + group (string "globals" ++ parens (identifiers xs)) + ^^ hardline + ^^ block decorations b ++ string "end" ^^ hardline + | DFunction (f, xs, b) -> + group (string "def" + ++ function_identifier ~uppersand:false f + ++ parens (identifiers xs)) + ^^ hardline + ^^ block decorations b ++ string "end" ^^ hardline + | DExternalFunction f -> + group (string "external" ++ function_identifier ~uppersand:false f) + +and block decorations (ls, b) = + let shift = max_label_length b in + locals ls ^^ vcat (List.map (labelled_instruction decorations shift) b) + +and identifiers xs = + separate_map (comma ^^ space) identifier xs + +and identifier (Id x) = + string x + +and function_identifier ?(uppersand = true) (FId x) = + string (if uppersand then "&" ^ x else x) + +and locals = function + | [] -> + empty + | xs -> + group (string "local" ++ group (identifiers xs) ++ string ":") ^^ break 1 + +and labelled_instruction decorations lsize (l, i) = + vcat ( + (decorations.pre l) + @ [ group (label lsize l ^^ group (instruction i) ^^ string ";") ] + @ (decorations.post l) + ) + +and label lsize (Label l) = + string (Printf.sprintf "%*s: " lsize l) + +and instruction = function + | Call (f, xs, tail) -> + string "call" ++ rvalue f ++ parens (rvalues xs) + ++ (if tail then string "tail" else empty) + + | Ret -> + string "ret" + + | Assign (l, o, rs) -> + lvalue l ++ string "<-" ++ string (op o) ++ rvalues rs + + | Jump (Label l) -> + string "jump" ++ string l + + | ConditionalJump (c, rs, Label l1, Label l2) -> + string "jumpif" ++ string (condition c) ++ rvalues rs + ++ string "->" ++ string l1 ^^ string ", " ++ string l2 + + | Comment s -> + string (";; " ^ s) + + | Switch (r, ls, default) -> + string "switch" ++ rvalue r + ++ separate_map (break 0 ^^ comma ^^ space) slabel (Array.to_list ls) + ++ (match default with None -> empty | Some l -> string "orelse" ++ slabel l) + + | Exit -> + string "exit" + +and slabel (Label s) = + string s + +and lvalue = function + | `Variable x -> identifier x + | `Register r -> register r + +and rvalue = function + | #lvalue as l -> lvalue l + | `Immediate l -> literal l + +and rvalues rs = + separate_map (break 0 ^^ comma ^^ space) rvalue rs + +and literal = function + | LInt x -> string (Mint.to_string x) + | LFun f -> function_identifier f + | LString s -> string ("\"" ^ String.escaped s ^ "\"") + | LChar c -> string ("'" ^ Char.escaped c ^ "'") + +and register (RId x) = string ("%" ^ x) + +and op = function + | Copy -> "copy" + | Add -> "add" + | Mul -> "mul" + | Div -> "div" + | Sub -> "sub" + | And -> "and" + | Or -> "or" + +and condition = function + | GT -> "gt" + | LT -> "lt" + | GTE -> "gte" + | LTE -> "lte" + | EQ -> "eq" + +let instruction i = group (instruction i) diff --git a/flap/src/retrolix/retrolixRegisterAllocation.ml b/flap/src/retrolix/retrolixRegisterAllocation.ml new file mode 100644 index 0000000..698fba4 --- /dev/null +++ b/flap/src/retrolix/retrolixRegisterAllocation.ml @@ -0,0 +1,225 @@ +(** + + The register allocation translates a Retrolix program into an + equivalent Retrolix program that uses hardware registers as much as + possible to hold intermediate results. + + Register allocation is done in two steps: + + - a static analysis called "Liveness Analysis of Variables" is + performed to compute a graph. This graph overapproximates the interference + relation of program variables, i.e. the intersection between the + live ranges of variables. The nodes of the graph are the program + variables and, in this graph, a node for 'x' and a node 'y' are + connected iff 'x' and 'y' are in interference. + + - a graph coloring algorithm is executed on the interference graph: + if two variables live at the same time, then their values cannot + be carried by the same register ; thus, it suffices to use a different + color for their nodes. Graph coloring is NP-complete. Yet, we will + use a simple recursive algorithm that provides good results in + practice. + +*) + +open RetrolixAST +open RetrolixUtils +open RetrolixInterferenceGraph + +(** + + Register allocation is an optimization. + + Hence, we register this translation as such in the compiler. + +*) + +let activated = ref false + +module Source = Retrolix + +let shortname = "regalloc" + +let longname = "register allocation" + +(** + + Coloring, definitions and operators. + +*) + +type colorization = Color of register | OnStack | Undecided + +type coloring = colorization LValueMap.t + +let color_of_register r = + match RetrolixUtils.register r with `Register r -> r | _ -> assert false + +let colors = + List.map color_of_register X86_64_Architecture.allocable_registers + +let is_precolored_node n = + match n with + | `Register r -> List.mem r colors + | _ -> false + +let nb_colors = List.length colors + +let colorization coloring x = + try LValueMap.find x coloring with Not_found -> Undecided + +let assign_colorization coloring x c = + LValueMap.add x c coloring + +(** In the initial coloring, hardware registers are colored by themselves. *) +let initial_coloring : coloring = + List.fold_left (fun c r -> + let color = Color (color_of_register r) + and register = RetrolixUtils.register r in + assign_colorization c register color) + LValueMap.empty + X86_64_Architecture.all_registers + +let string_of_colorization = function + | OnStack -> "On stack" + | Color r -> RetrolixUtils.string_of_register r + | Undecided -> "undecided" + +let string_of_coloring coloring = + LValueMap.bindings coloring |> + List.map (fun (x, c) -> + Printf.sprintf "%s -> %s\n" + (string_of_lvalue x) (string_of_colorization c) + ) |> String.concat "" + +(** [build_variable_relations forbidden b] computes the interference + graph for the block [b], assuming that coloring global variables + is [forbidden]. *) +module G = RetrolixInterferenceGraph.InterferenceGraph +let build_variable_relations forbidden b : G.t = + RetrolixLivenessAnalysis.process b |> + RetrolixInterferenceGraph.interference_graph forbidden b + +(** [rewrite_block coloring b] rewrites [b] to use more hardware + registers as described by [coloring]. *) +let rewrite_block coloring (xs, is) = + let lv : lvalue -> lvalue = function + | `Variable (Id _) as v -> + begin match colorization coloring v with + | Color r -> `Register r + | OnStack -> v + | Undecided -> v + end + | l -> l + in + let rv = function + | `Immediate l -> `Immediate l + | #lvalue as l -> (lv l :> rvalue) + in + List.( + let var x = `Variable x in + let xs = filter (fun x -> colorization coloring (var x) = OnStack) xs in + let is = map (fun (l, i) -> (l, RetrolixUtils.map_on_value lv rv i)) is in + (xs, is) + ) + +(** + + Graph simplification + ==================== + + Given an interference graph, there are three possible cases: + + 1. The graph only contains nodes that are not colorable because + they are hardware registers or global variables for instance. + The [initial_coloring] is fine for this graph. + + 2. There is a simplifiable node in the graph, that is a node whose + degree is strictly less than the number of available [colors]. + + 3. There are no simplifiable nodes in the graph. The coloring + algorithm must try different from simplification to continue + its work. + +*) +type simplify_result = + | PrecoloredGraph + | SimplifiableNode of NodeLabel.t + | NoSimplifiableNode + +(** [simplify uncolorable g] observes [g] to determine the + [simplify_result]. [uncolorable] is a predicate to filter + nodes that are not colorable. *) +let simplify (uncolorable : NodeLabel.t -> bool) g : simplify_result = + failwith "Student! This is your job!" + +(** + + Variable spilling + ================= + + At some point, if there is no more simplification (or coalescing) + to do, we must choose a variable that can be potentially spilled, + that is allocated [OnStack]. As graph coloring is NP-complete, + there is no way to quickly compute a local optimal choice. Yet, + considering the graph and the instructions, some reasonable + heuristic can be defined. + +*) + +(** [pick_spilling_candidate uncolorable g b] returns a node to + consider for spilling. *) +let pick_spilling_candidate (uncolorable : NodeLabel.t -> bool) g _ +: NodeLabel.t = + failwith "Student! This is your job!" + +(** [colorize_block_variables_naively forbidden b] rewrites [b] to + use more hardware registers if that is possible. [forbidden] + is a list of variables that cannot be stored in hardware registers. *) +let colorize_block_variables_naively forbidden b = + failwith "Student! This is your job!" + +(** + + Coalescence + =========== + + We can coalesce two nodes if they are not in conflict and if Briggs' + or George's criterion is satisfied. + +*) +let can_coalesce g n1 n2 = + failwith "Student! This is your job!" + +(** [colorize_block_variables_meticulously forbidden b] performs + register allocation on [b] trying to optimize variable copy. *) +let colorize_block_variables_meticulously forbidden b = + failwith "Student! This is your job!" + +(** + + Putting all together. + +*) +let translate_block forbidden b = Options.( + match get_regalloc_variant () with + | Naive -> + colorize_block_variables_naively forbidden b + | Realistic -> + colorize_block_variables_meticulously forbidden b + ) + +let translate p = + let variables = List.map (fun x -> `Variable x) in + let globals = variables (RetrolixUtils.global_variables p) in + let rec program ds = + List.map definition ds + and definition = function + | DValues (xs, b) -> + DValues (xs, translate_block globals b) + | DFunction (f, xs, b) -> + DFunction (f, xs, translate_block (variables xs @ globals) b) + | DExternalFunction f -> + DExternalFunction f + in + program p |> RetrolixKillMove.kill_moves diff --git a/flap/src/retrolix/retrolixTypechecker.ml b/flap/src/retrolix/retrolixTypechecker.ml new file mode 100644 index 0000000..69bc38a --- /dev/null +++ b/flap/src/retrolix/retrolixTypechecker.ml @@ -0,0 +1,181 @@ +(** A scope-checker for Retrolix programs. *) + +open RetrolixAST + +(** {2 Errors} *) + +let type_error ?(loc = Position.dummy) message = + Error.error "typechecking" loc message + +let unknown_variable (Id xn) = + type_error ("Unbound variable " ^ xn) + +let unknown_function (FId fn) = + type_error ("Unbound function " ^ fn) + +let unknown_label (Label ln) = + type_error ("Unbound label " ^ ln) + +let duplicate_global (Id xn) = + type_error ("Global variable " ^ xn ^ " has been declared twice") + +let duplicate_function (FId fn) = + type_error ("Function " ^ fn ^ " has been declared twice") + +let duplicate_label (Label ln) = + type_error ("Label " ^ ln ^ " has been declared twice") + +(** {2 Runtime functions} *) + +let runtime_funs = + List.map + (fun fn -> FId fn) + [ + "allocate_block"; + "read_block"; + "write_block"; + "equal_string"; + "equal_char"; + "observe_int"; "print_int"; + "print_string"; + "add_eight_int"; + ] + +(** {2 Environments} *) + +type typing_environment = + { + variables : IdSet.t; + functions : FIdSet.t; + labels : LabelSet.t + } + +let print_typing_environment _ = + "" + +let initial_typing_environment () = + { + variables = IdSet.empty; + functions = FIdSet.of_list runtime_funs; + labels = LabelSet.empty; + } + +let var_is_declared env x = + IdSet.mem x env.variables + +let fun_is_declared env f = + FIdSet.mem f env.functions + +let label_is_declared env l = + LabelSet.mem l env.labels + +let declare_var env x = + { env with variables = IdSet.add x env.variables; } + +let declare_vars ?on_shadowing env xs = + let f = + match on_shadowing with + | None -> fun _ _ -> () + | Some f -> fun env x -> if var_is_declared env x then f x + in + let declare_enrich_var env x = f env x; declare_var env x in + List.fold_left declare_enrich_var env xs + +let define_label env l = + if label_is_declared env l then duplicate_label l; + { env with labels = LabelSet.add l env.labels; } + +let define_labels env body = + List.fold_left (fun env (l, _) -> define_label env l) env body + +let declare_fun env f = + { env with functions = FIdSet.add f env.functions; } + +let with_labels ~base ~labelled = + { base with labels = labelled.labels; } + +(** {2 Type-checking} *) + +let typecheck_literal env lit = + match lit with + | LInt _ | LChar _ | LString _ -> + () + | LFun f -> + if not (fun_is_declared env f) then unknown_function f + +let typecheck_lvalue env (lv : lvalue) = + match lv with + | `Variable x -> + if not (var_is_declared env x) then unknown_variable x + | `Register _ -> + () + +let typecheck_rvalue env (rv : rvalue) = + match rv with + | `Immediate lit -> + typecheck_literal env lit + | #lvalue as lv -> + typecheck_lvalue env lv + +let typecheck_rvalues env = + List.iter (typecheck_rvalue env) + +let typecheck_label env l = + if not (label_is_declared env l) then unknown_label l + +let typecheck_labels env = + List.iter (typecheck_label env) + +let typecheck_instruction env ins = + match ins with + | Call (rv1, rvs, _) -> + typecheck_rvalues env (rv1 :: rvs) + | Ret | Comment _ | Exit -> + () + | Assign (lv, _, rvs) -> + typecheck_lvalue env lv; + typecheck_rvalues env rvs + | Jump l -> + typecheck_label env l + | ConditionalJump (_, rvs, l1, l2) -> + typecheck_rvalues env rvs; + typecheck_label env l1; + typecheck_label env l2 + | Switch (rv, ls, lo) -> + typecheck_rvalue env rv; + Array.iter (typecheck_label env) ls; + ExtStd.Option.iter (typecheck_label env) lo + +let typecheck_labelled_instruction env (_, ins) = + typecheck_instruction env ins + +let typecheck_block env (locals, body) = + let env = declare_vars env locals in + let env = define_labels env body in + List.iter (typecheck_labelled_instruction env) body; + env + +let enrich_env_with_def env def = + match def with + | DValues (globals, _) -> + declare_vars ~on_shadowing:duplicate_global env globals + | DFunction (f, _, _) | DExternalFunction f -> + if fun_is_declared env f then duplicate_function f; + declare_fun env f + +let typecheck_def env def = + let env' = + match def with + | DValues (_, block) -> + typecheck_block env block + | DFunction (_, params, block) -> + let env = declare_vars env params in + typecheck_block env block + | DExternalFunction _ -> + env + in + with_labels ~base:env ~labelled:env' + +let typecheck env ast = + let env = List.fold_left enrich_env_with_def env ast in + List.fold_left typecheck_def env ast diff --git a/flap/src/retrolix/retrolixUtils.ml b/flap/src/retrolix/retrolixUtils.ml new file mode 100644 index 0000000..dd6106b --- /dev/null +++ b/flap/src/retrolix/retrolixUtils.ml @@ -0,0 +1,199 @@ +(** This module provides helper functions for Retrolix program + analysis and manipulation. *) + +open RetrolixAST + +module LValueOrd = struct + type t = lvalue + let compare = compare + let print = RetrolixPrettyPrinter.lvalue +end + +module LValueMap = ExtStd.Map (LValueOrd) +module LValueSet = ExtStd.Set (LValueOrd) + +module LabelOrd = struct + type t = label + let compare (Label l1) (Label l2) = String.compare l1 l2 +end + +type location = lvalue + +module LSet = Set.Make (struct + type t = location + let compare = compare +end) + +let find_default d k m = + try LabelMap.find k m with Not_found -> d + +let join rs = + List.fold_left (fun s x -> LSet.add x s) LSet.empty rs + +let string_of_register (RId r) = r + +let string_of_lvalue = function + | `Register (RId r) -> r + | `Variable (Id r) -> r + +let string_of_label (Label s) = s + +let string_of_lset s = + String.concat " " (List.map string_of_lvalue (LSet.elements s)) + +let string_of_lmap m = + String.concat "\n" ( + List.map (fun (l, s) -> + Printf.sprintf " %s : %s\n" (string_of_label l) (string_of_lset s) + ) (LabelMap.bindings m) + ) + +let register r = + `Register (RId (X86_64_Architecture.string_of_register r)) + +let global_variables p = + let translate p = + let rec program ds = + List.(concat (map definition ds)) + and definition = function + | DValues (xs, _) -> + xs + | _ -> + [] + in + program p + in + translate p + +let map_on_value lvalue rvalue = function + | Call (r, rs, b) -> + Call (rvalue r, List.map rvalue rs, b) + | Ret -> + Ret + | Assign (l, o, rs) -> + Assign (lvalue l, o, List.map rvalue rs) + | Jump l -> + Jump l + | ConditionalJump (c, rs, l1, l2) -> + ConditionalJump (c, List.map rvalue rs, l1, l2) + | Switch (r, ls, l) -> + Switch (rvalue r, ls, l) + | Comment c -> + Comment c + | Exit -> + Exit + +(** [predecessors b] returns a function [pred] such that [pred l] + returns the predecessors of [l] in the control flow graph of + the block [b]. *) +let predecessors b = + let block m (_, instructions) = + let new_predecessor prev m curr = + try + let s = LabelMap.find curr m in + let s = LabelSet.add prev s in + LabelMap.add curr s m + with Not_found -> + LabelMap.add curr (LabelSet.singleton prev) m + in + let rec traverse m = function + | (label, Jump goto_label) :: instructions -> + let m = new_predecessor label m goto_label in + traverse m instructions + | (label, ConditionalJump (_, _, l1, l2)) :: instructions -> + let m = List.fold_left (new_predecessor label) m [l1; l2] in + traverse m instructions + | (label, Switch (_, labels, default)) :: instructions -> + let labels = + (match default with None -> [] | Some x -> [x]) + @ (Array.to_list labels) + in + let m = List.fold_left (new_predecessor label) m labels in + traverse m instructions + | (ilabel, _) :: (((nlabel, _) :: _) as instructions) -> + let m = new_predecessor ilabel m nlabel in + traverse m instructions + | [ _ ] | [] -> + m + in + traverse m instructions + in + let m = block LabelMap.empty b in + fun l -> try LabelMap.find l m with Not_found -> LabelSet.empty + +let nondefault_targets insn = + match insn with + | Call _ | Ret | Assign _ | Comment _ | Exit -> + [] + | Jump l -> + [l] + | ConditionalJump (_, _, l1, l2) -> + [l1; l2] + | Switch (_, a, o) -> + ExtStd.Option.fold (fun l acc -> acc @ [l]) o (Array.to_list a) + +let instruction_targets (insns : labelled_instruction list) = + let targets _ insn next_lab = + match insn with + | Call (_, _, false) | Assign _ | Comment _ -> + next_lab + + | Call (_, _, true) | Ret | Exit -> + [] + + | Jump lab -> + [lab] + + | ConditionalJump (_, _, lab1, lab2) -> + [lab1; lab2] + + | Switch (_, laba, labo) -> + ExtStd.Option.fold (fun lab acc -> acc @ [lab]) labo (Array.to_list laba) + in + let rec loop insns = + match insns with + | [] -> + [] + | (lab, insn) :: insns -> + (lab, + insn, + targets lab insn (match insns with [] -> [] | (lab, _) :: _ -> [lab])) + :: loop insns + in + loop insns + +let map_blocks f definitions = + let definition def = + match def with + | DValues (xs, block) -> + DValues (xs, f block) + | DFunction (fn, xs, block) -> + DFunction (fn, xs, f block) + | DExternalFunction _ -> + def + in + List.map definition definitions + +let map_instructions f ((locals, insns) : block) = + (locals, List.map (fun ((l, _) as li) -> l, f li) insns) + +let transform_block f g block = + let open PPrint in + let info = f block in + if Options.get_debug_mode () then + ExtPPrint.to_channel + (!^ "Input block:" + ^//^ RetrolixPrettyPrinter.block + RetrolixPrettyPrinter.nodecorations + block); + let block = map_instructions (g info) block in + if Options.get_debug_mode () then + ExtPPrint.to_channel + (!^ "Output block:" + ^//^ RetrolixPrettyPrinter.block + RetrolixPrettyPrinter.nodecorations + block); + block + +let transform_blocks f g definitions = + map_blocks (transform_block f g) definitions diff --git a/flap/src/utilities/dict.ml b/flap/src/utilities/dict.ml new file mode 100644 index 0000000..f11ab1a --- /dev/null +++ b/flap/src/utilities/dict.ml @@ -0,0 +1,25 @@ +type ('k, 'v) dict = + ('k * 'v) list + +type ('k, 'v) t = ('k, 'v) dict + +let empty = [] + +let lookup k d = + try + Some (List.assoc k d) + with Not_found -> + None + +let insert k v d = + (k, v) :: d + +let to_list d = d + +let of_list d = d + +let equal d1 d2 = + List.for_all (fun (k, v) -> + lookup k d2 = Some v + ) d1 + && List.(length d1 = length d2) diff --git a/flap/src/utilities/dict.mli b/flap/src/utilities/dict.mli new file mode 100644 index 0000000..eb3eb8e --- /dev/null +++ b/flap/src/utilities/dict.mli @@ -0,0 +1,15 @@ +type ('k, 'v) dict + +type ('k, 'v) t = ('k, 'v) dict + +val empty : ('k, 'v) dict + +val lookup : 'k -> ('k, 'v) dict -> 'v option + +val insert : 'k -> 'v -> ('k, 'v) dict -> ('k, 'v) dict + +val to_list : ('k, 'v) dict -> ('k * 'v) list + +val of_list : ('k * 'v) list -> ('k, 'v) dict + +val equal : ('k, 'v) dict -> ('k, 'v) dict -> bool diff --git a/flap/src/utilities/digraph.ml b/flap/src/utilities/digraph.ml new file mode 100644 index 0000000..fdaf548 --- /dev/null +++ b/flap/src/utilities/digraph.ml @@ -0,0 +1,160 @@ +module type EDGE = sig + include ExtStd.PrintableType +end + +module type VERTEX = sig + include ExtStd.PrintableType + module Label : ExtStd.OrderedPrintableType + val label : t -> Label.t +end + +module Make (Edge : EDGE) (Vertex : VERTEX) = struct + module VM = ExtStd.Map(Vertex.Label) + module VPM = ExtStd.Map(ExtStd.OrderedPrintablePairs(Vertex.Label)) + + type vinfo = + { + contents : Vertex.t; + incoming : (Vertex.Label.t * Edge.t) list; + outgoing : (Vertex.Label.t * Edge.t) list; + } + + (** The type of directed graphs. *) + type t = + { + vertices : vinfo VM.t; + edges : Edge.t VPM.t; + } + + let print { vertices; edges; } = + let open PPrint in + let edge_list = + separate_map + comma + (fun (v, e) -> OCaml.tuple [Vertex.Label.print v; Edge.print e]) + in + let vinfo { contents; incoming; outgoing; } = + ExtPPrint.record + [ + "contents", Vertex.print contents; + "incoming", edge_list incoming; + "outgoing", edge_list outgoing; + ] + in + ExtPPrint.record + [ + "vertices", VM.print vinfo vertices; + "edges", VPM.print Edge.print edges; + ] + + let dump_graphviz gr oc = + let dquotes s = "\"" ^ String.escaped s ^ "\"" in + let label l = dquotes @@ ExtPPrint.to_string Vertex.Label.print l in + let dump_vertex (vl, v) = + output_string oc (label vl); + output_string oc "[label = "; + output_string oc + (dquotes @@ ExtPPrint.to_string ~width:40 Vertex.print v.contents); + output_string oc "];\n" + in + let dump_edge ((srcl, dstl), _) = + output_string oc (label srcl); + output_string oc " -> "; + output_string oc (label dstl); + output_string oc ";\n" + in + output_string oc "digraph {\n"; + List.iter dump_vertex @@ List.of_seq @@ VM.to_seq gr.vertices; + List.iter dump_edge @@ List.of_seq @@ VPM.to_seq gr.edges; + output_string oc "}\n" + ;; + + let empty = + { + vertices = VM.empty; + edges = VPM.empty; + } + + exception Vertex_already_present of Vertex.Label.t + exception Vertex_not_found of Vertex.Label.t + exception Edge_already_present of Vertex.Label.t * Vertex.Label.t + + let add_vertex gr v = + let vl = Vertex.label v in + if VM.mem vl gr.vertices + then raise (Vertex_already_present vl); + let vi = { contents = v; incoming = []; outgoing = []; } in + { gr with vertices = VM.add vl vi gr.vertices; } + + let find_vertex_info gr v = + try VM.find v gr.vertices with Not_found -> raise (Vertex_not_found v) + + let add_edge gr ~src ~dst e = + if VPM.mem (src, dst) gr.edges then raise (Edge_already_present (src, dst)); + let srci = find_vertex_info gr src in + let dsti = find_vertex_info gr dst in + let srci = { srci with outgoing = (dst, e) :: srci.outgoing; } in + let dsti = { dsti with incoming = (src, e) :: dsti.incoming; } in + { vertices = VM.(add src srci @@ add dst dsti @@ gr.vertices); + edges = VPM.add (src, dst) e gr.edges; } + + let find_vertex vl gr = + (find_vertex_info gr vl).contents + + let fold_vertices f gr acc = + VM.fold (fun _ vi acc -> f vi.contents acc) gr.vertices acc + + let fold_edges f gr acc = + VPM.fold (fun (srcl, dstl) e acc -> + let src = find_vertex srcl gr in + let dst = find_vertex dstl gr in + f ~src ~dst e acc) + gr.edges + acc + + type 'a edge_folder = Vertex.t -> Edge.t -> 'a -> 'a + + let fold_successors srcl (f : 'a edge_folder) acc gr = + let srci = find_vertex_info gr srcl in + List.fold_left + (fun acc (dstl, e) -> f (find_vertex dstl gr) e acc) + acc + srci.outgoing + + let fold_predecessors dstl f acc gr = + let dsti = find_vertex_info gr dstl in + List.fold_left + (fun acc (srcl, e) -> f (find_vertex srcl gr) e acc) + acc + dsti.incoming + + let iter_vertices f gr = + VM.iter (fun _ v -> f v.contents) gr.vertices + + let iter_edges f gr = + VPM.iter + (fun (srcl, dstl) e -> + let src = find_vertex srcl gr in + let dst = find_vertex dstl gr in + f ~src ~dst e) + gr.edges + + type edge_iter = Vertex.t -> Edge.t -> unit + + let iter_successors f gr srcl = + let srci = find_vertex_info gr srcl in + List.iter (fun (dstl, e) -> f (find_vertex dstl gr) e) srci.outgoing + + let iter_predecessors f gr dstl = + let dsti = find_vertex_info gr dstl in + List.iter (fun (srcl, e) -> f (find_vertex srcl gr) e) dsti.incoming + + let initial_vertices, terminal_vertices = + let gather proj gr = + VM.fold + (fun _ v l -> if proj v = [] then v.contents :: l else l) + gr.vertices + [] + in + gather (fun v -> v.incoming), gather (fun v -> v.outgoing) +end diff --git a/flap/src/utilities/digraph.mli b/flap/src/utilities/digraph.mli new file mode 100644 index 0000000..6c8a811 --- /dev/null +++ b/flap/src/utilities/digraph.mli @@ -0,0 +1,102 @@ +(** A module for directed graphs. + + This module, like the one in {!m Graph}, provides a functional + representation of directed graphs. + *) + +module type EDGE = sig + include ExtStd.PrintableType +end + +module type VERTEX = sig + include ExtStd.PrintableType + module Label : ExtStd.OrderedPrintableType + val label : t -> Label.t +end + +module Make (Edge : EDGE) (Vertex : VERTEX) : sig + (** The type of directed graphs. *) + type t + + (** Pretty-print the internal representation of the graph for debugging. *) + val print : t -> PPrint.document + + (** Dump the graph in the Graphviz "dot", so that it can later be displayed by + dotty and friends. *) + val dump_graphviz : t -> out_channel -> unit + + (** {2 Exceptions} *) + + exception Vertex_not_found of Vertex.Label.t + + exception Edge_already_present of Vertex.Label.t * Vertex.Label.t + + (** {2 Graph construction operations} *) + + (** The empty digraph. *) + val empty : t + + exception Vertex_already_present of Vertex.Label.t + + (** [add_vertex gr v] add the vertex [v] to the graph [gr]. This function + raises {!e Vertex_already_present} if a node with label [V.label v] has + already been added to [gr]. *) + val add_vertex : t -> Vertex.t -> t + + (** [add_edge gr ~src ~dst e] adds an edge [e] between two vertices [src] and + [dst] of [gr], identified by their labels. This function raises {!e + Vertex_not_found} when either [src] or [dst] is not already present in + [gr], and raises {!e Edge_already_present} when an edge between [src] and + [dst] has already been added. *) + val add_edge : t -> src:Vertex.Label.t -> dst:Vertex.Label.t -> Edge.t -> t + + (** {2 Graph traversal operations} *) + + (** [find_vertex vl g] finds the vertex with label [vl] in [g], or raises {! + Vertex_not_found} if [g] contains no such vertex. *) + val find_vertex : Vertex.Label.t -> t -> Vertex.t + + (** [fold_vertices f acc gr] applies [f v1 (f v2 (... acc))] to all the + vertices [vi] of [gr]. They are enumerated in no particular order. *) + val fold_vertices : (Vertex.t -> 'a -> 'a) -> t -> 'a -> 'a + + type 'a edge_folder = Vertex.t -> Edge.t -> 'a -> 'a + + (** [fold_edges f acc gr] is similar to [fold_vertices] but applies to the + edges of [gr]. *) + val fold_edges : + (src:Vertex.t -> dst:Vertex.t -> Edge.t -> 'a -> 'a) -> t -> 'a -> 'a + + val fold_successors : Vertex.Label.t -> 'a edge_folder -> 'a -> t -> 'a + + val fold_predecessors : Vertex.Label.t -> 'a edge_folder -> 'a -> t -> 'a + + (** [iter_vertices f gr] applies function [f] to every vertex of [gr], in no + particular order. *) + val iter_vertices : (Vertex.t -> unit) -> t -> unit + + type edge_iter = Vertex.t -> Edge.t -> unit + + (** [iter_edges f gr] applies function [f] to every edge of [gr], in no + particular order. *) + val iter_edges : + (src:Vertex.t -> dst:Vertex.t -> Edge.t -> unit) -> t -> unit + + (** [iter_successors f gr v] applies function [f] to every outgoing edge of + [v] in [gr], in LIFO order. This function raises {!e Vertex_not_found} when + [v] has not been added to [gr]. *) + val iter_successors : edge_iter -> t -> Vertex.Label.t -> unit + + (** [iter_predecessors f gr v] applies function [f] to every incoming edge of + [v] in [gr], in LIFO order. This function raises {!e Vertex_not_found} when + [v] has not been added to [gr]. *) + val iter_predecessors : edge_iter -> t -> Vertex.Label.t -> unit + + (** [initial_vertices gr] returns the list of all nodes of [gr] that have no + predecessors. *) + val initial_vertices : t -> Vertex.t list + + (** [terminal_vertices gr] returns the list of all nodes of [gr] that have no + successors. *) + val terminal_vertices : t -> Vertex.t list +end diff --git a/flap/src/utilities/error.ml b/flap/src/utilities/error.ml new file mode 100644 index 0000000..85ba03a --- /dev/null +++ b/flap/src/utilities/error.ml @@ -0,0 +1,33 @@ +let exit_flag = ref true + +let exit_on_error () = exit_flag := true + +let resume_on_error () = exit_flag := false + +let print_locs = ref true + +exception Error of Position.t list * string + +let print_error positions msg = + Printf.sprintf "%s%s\n" + (if !print_locs + then String.concat "\n" + (List.map (fun p -> Position.string_of_pos p ^": ") positions) + else "") + msg + +let error_alert positions msg = + if !exit_flag then ( + output_string stderr (print_error positions msg); + exit 1 + ) + else raise (Error (positions, msg)) + +let global_error kind msg = + error_alert [] (Printf.sprintf "Global Error (%s)\n %s" kind msg) + +let errorN kind poss msg = + error_alert poss (Printf.sprintf "Error (%s)\n %s" kind msg) + +let error kind pos = errorN kind [pos] +let error2 kind pos1 pos2 = errorN kind [pos1; pos2] diff --git a/flap/src/utilities/error.mli b/flap/src/utilities/error.mli new file mode 100644 index 0000000..7763b63 --- /dev/null +++ b/flap/src/utilities/error.mli @@ -0,0 +1,32 @@ +(** This module provides a uniform way of reporting (located) error messages. *) + +(** [exit_on_error ()] forces the program to stop if an error is encountered. + (This is the default behavior.) *) +val exit_on_error: unit -> unit + +(** [resume_on_error ()] makes the program throw the exception {!Error} + if an error is encountered. *) +val resume_on_error: unit -> unit + +(** The value of [print_locs] controls whether locations are printed by the + functions of this module. It is set to [true] by default. *) +val print_locs : bool ref + +exception Error of Position.t list * string + +(** [print_error positions msg] formats an error message. *) +val print_error : Position.t list -> string -> string + +(** [error k p msg] prints [msg] with [k] as a message prefix and stops + the program. *) +val error : string -> Position.t -> string -> 'a + +(** [error2 k p1 p2 msg] prints two positions instead of one. *) +val error2 : string -> Position.t -> Position.t -> string -> 'a + +(** [errorN k ps msg] prints several positions. *) +val errorN : string -> Position.t list -> string -> 'a + +(** [global_error k msg] prints [msg] with [k] as a message prefix and stops + the program. *) +val global_error : string -> string -> 'a diff --git a/flap/src/utilities/extPPrint.ml b/flap/src/utilities/extPPrint.ml new file mode 100644 index 0000000..f2470c6 --- /dev/null +++ b/flap/src/utilities/extPPrint.ml @@ -0,0 +1,25 @@ +(** This module extends the PPrint library. *) + +open PPrint + +let ribbon = 0.7 + +let to_string ?(width = 120) f x = + ignore width; + let b = Buffer.create 13 in + ToBuffer.pretty ribbon 120 b (f x); + Buffer.contents b + +let to_channel ?(channel = stdout) ?(width = 80) doc = + ignore width; + PPrint.ToChannel.pretty ribbon 80 channel doc; + print_newline () + +let ( ++ ) x y = x ^^ break 1 ^^ y + +let assoc_list ?(bind = "=") ?(sep = ",") pp_key pp_val assl = + let b = string (" " ^ bind) in + separate_map (string sep) (fun (k, v) -> pp_key k ^^ b ^/^ pp_val v) assl + +let record = + OCaml.record "" diff --git a/flap/src/utilities/extStd.ml b/flap/src/utilities/extStd.ml new file mode 100644 index 0000000..d13a2f6 --- /dev/null +++ b/flap/src/utilities/extStd.ml @@ -0,0 +1,340 @@ +(** This module extends some modules of the standard library. *) + +module Ref = struct + + let functions_of_ref r = + (fun x -> r := x), (fun () -> !r) + + let as_functions default = + functions_of_ref (ref default) + +end + +module List = struct + + include List + + exception EmptyListHasNoMin + let min_assoc_list xs = + let rec aux k' v' = function + | [] -> + (k', v') + | (k, v) :: xs -> + if v < v' then aux k v xs else aux k' v' xs + in + match xs with + | [] -> raise EmptyListHasNoMin + | (k, v) :: xs -> aux k v xs + + exception InvalidSwap + + let rec swap i x' xs = + match i, xs with + | 0, x :: xs -> + x, x' :: xs + | _, x :: xs -> + let y, xs' = swap (i - 1) x' xs in + y, x :: xs' + | _, _ -> + raise InvalidSwap + + let rec range start stop = + if stop < start then [] else start :: range (start + 1) stop + + let asymmetric_map2 f = + let rec aux accu xs ys = + match xs, ys with + | xs, [] -> + (List.rev accu, xs, []) + | [], ys -> + (List.rev accu, [], ys) + | x :: xs, y :: ys -> + aux (f x y :: accu) xs ys + in + aux [] + + let repeat k v = + let rec aux accu k = + if k = 0 then accu else aux (v :: accu) (k - 1) + in + aux [] k + + let repeatf k f = + let rec aux accu k = + if k = 0 then accu else aux (f () :: accu) (k - 1) + in + aux [] k + + let rec uniq = function + | [] -> [] + | [x] -> [x] + | x :: ((y :: _) as xs) -> if x = y then uniq xs else x :: uniq xs + + (** [index_of p l] returns the index of the first element [x] of [l] + such [p x = true]. Raise [Not_found] otherwise. *) + let index_of : ('a -> bool) -> 'a list -> int = + fun p l -> + let rec aux i = function + | [] -> raise Not_found + | x :: xs -> if p x then i else aux (succ i) xs + in + aux 0 l + + (** [all_distinct ls] returns true if all the elements of [ls] + are distinct. *) + let all_distinct ls = + let ls = List.sort Stdlib.compare ls in + let rec aux = function + | [] | [_] -> true + | x :: y :: ys -> x <> y && aux (y :: ys) + in + aux ls + + let all_equal ls = + let rec aux = function + | [] | [_] -> true + | x :: y :: ys -> x = y && aux (y :: ys) + in + aux ls + + let transpose xs = + assert (all_equal (List.map length xs)); + let rec aux rows = + match rows with + | [] -> assert false + | [] :: _ -> [] + | rows -> + List.( + let row', rows = map (fun l -> (hd l, tl l)) rows |> split in + row' :: aux rows + ) + in + aux xs + + let unique_value ls = + match uniq ls with + | [x] -> Some x + | _ -> None + + let foldmap f init = + let rec aux (accu, ys) = function + | [] -> + (accu, List.rev ys) + | x :: xs -> + let accu, y = f accu x in + aux (accu, y :: ys) xs + in + aux (init, []) + + exception FoldMap2 + + let foldmap2 f init l1 l2 = + let rec aux (accu, ys) = function + | [], [] -> + (accu, List.rev ys) + | x :: xs, z :: zs -> + let accu, y = f accu x z in + aux (accu, y :: ys) (xs, zs) + | _, _ -> + raise FoldMap2 + in + aux (init, []) (l1, l2) + + let update_assoc k v l = + let rec aux = function + | [] -> [(k, v)] + | ((k', _) as x) :: l -> if k = k' then (k, v) :: l else x :: aux l + in + aux l + + module Monad : sig + type 'a t + val return : 'a -> 'a t + val ( >>= ) : 'a t -> ('a -> 'b t) -> 'b t + val take_one : 'a list -> 'a t + val fail : 'a t + val and_try : 'a t -> 'a t -> 'a t + val run : 'a t -> 'a list + end = struct + type 'a t = 'a list + let return x = [x] + let ( >>= ) x f = List.(flatten (map f x)) + let fail = [] + let and_try a b = a @ b + let run x = x + let take_one x = x + end + + let last l = List.(hd (rev l)) + +end + +let update + (find : 'k -> 'c -> 'v) + (add : 'k -> 'v -> 'c -> 'c) + (k : 'k) (m : 'c) + (default : 'v) + (f : 'v -> 'v) +: 'c = + try + let v = find k m in + add k (f v) m + with Not_found -> + add k (f default) m + +module Random = struct + + let int_in_range start stop = + start + Random.int (stop - start + 1) + +end + +module Option = struct + + let map f = function + | None -> None + | Some x -> Some (f x) + + let iter f = function + | None -> () + | Some x -> f x + + let fold f x acc = + match x with + | None -> acc + | Some x -> f x acc + +end + +module Stdlib = struct + let ( |< ) default e x = + try e x with _ -> default + + let file_content filename = + let cin = open_in filename in + let b = Buffer.create 24 in + let rec read () = + try Buffer.add_channel b cin 1; read () with End_of_file -> () + in + read (); + close_in cin; + Buffer.contents b + +end + +module Buffer = struct + include Buffer + + let slurp ?(buffer_size = 4096) ic = + let b = Buffer.create buffer_size in + let rec loop () = + match Buffer.add_channel b ic buffer_size with + | () -> + loop () + | exception _ -> + b + in + loop () + +end + +module Unix = struct + + open Unix + + let output_and_error_of_command ?(env = Unix.environment ()) cmd = + let cin, cout, cerr = open_process_full cmd env in + let stdin = Buffer.slurp cin in + let stderr = Buffer.slurp cerr in + let status = close_process_full (cin, cout, cerr) in + status, Buffer.contents stdin, Buffer.contents stderr + + let output_of_command cmd = + let status, stdin, _ = output_and_error_of_command cmd in + status, stdin + + let string_of_process_status = function + | WEXITED k -> Printf.sprintf "exited(%d)" k + | WSTOPPED k -> Printf.sprintf "stopped(%d)" k + | WSIGNALED k -> Printf.sprintf "signaled(%d)" k + + let add_exec_bits filename = + let st = stat filename in + chmod filename (st.st_perm lor 0o111) +end + +module Hashtbl = struct + + let counting_table (type a) () : (a -> int) * (a -> unit) = + let t = Hashtbl.create 13 in + let get k = try Hashtbl.find t k with Not_found -> 0 in + let incr k = Hashtbl.replace t k (get k + 1) in + (get, incr) + +end + +module Array = struct + + let present_to_list a = + List.(rev (fold_left (fun accu -> function + | None -> accu + | Some t -> t :: accu) [] (Array.to_list a))) + +end + +module Pair = struct + + let swap (x, y) = (y, x) + +end + +module type PrintableType = sig + type t + val print : t -> PPrint.document +end + +module type OrderedPrintableType = sig + include Map.OrderedType + include PrintableType with type t := t +end + +module OrderedPrintablePairs (T : OrderedPrintableType) = struct + type t = T.t * T.t + + let compare (x1, y1) (x2, y2) = + let n = T.compare x1 x2 in + if n <> 0 then n else T.compare y1 y2 + + let print (x, y) = PPrint.OCaml.tuple [T.print x; T.print y] +end + +module Set (T : OrderedPrintableType) = + struct + module M = Set.Make(T) + include M + let print s = + let open PPrint in + surround_separate_map 2 1 + (string "{}") + (string "{") + (string "," ^^ break 1) + (string "}") + T.print + (List.of_seq @@ M.to_seq s) + end + +module Map (T : OrderedPrintableType) = + struct + module M = Map.Make(T) + include M + let print value m = + let open PPrint in + let pp (k, v) = prefix 2 1 (T.print k ^^ string " =") (value v) in + surround_separate_map 2 1 + (string "{}") + (string "{") + (string "," ^^ break 1) + (string "}") + pp + (List.of_seq @@ M.to_seq m) + end diff --git a/flap/src/utilities/graph.ml b/flap/src/utilities/graph.ml new file mode 100644 index 0000000..bbe1cee --- /dev/null +++ b/flap/src/utilities/graph.ml @@ -0,0 +1,428 @@ +(** A module for graphs. + + The implementation is based on purely functional datastructures + only: we make use of OCaml's standard modules Map and Set. + + The implementation is generic with respect to the type of labels + for nodes and for edges. The module is therefore a functor + parameterized by the two descriptions of these types and their + operations. + +*) + +(** The type for edge labels. + + We assume that there is a relatively small number of edge labels. + These labels are comparable and enumerable. + +*) +module type EdgeLabelSig = sig + include Set.OrderedType + (** [all] enumerates all the possible edge labels. *) + val all : t list + (** [to_string e] converts [e] in a human readable value. *) + val to_string : t -> string +end + +(** The type for node labels. + + Node labels must be comparable. + +*) +module type NodeLabelSig = sig + include Set.OrderedType + (** [to_string n] converts [n] in a human readable value. *) + val to_string : t -> string +end + +(** The functor is parameterized by the previous two signatures. *) +module Make (EdgeLabel : EdgeLabelSig) (NodeLabel : NodeLabelSig) = +struct + + (** A type for maps whose keys are integers. *) + module IntMap = Map.Make (struct type t = int let compare = compare end) + let int_map_update k m d f = ExtStd.update IntMap.find IntMap.add k m d f + + (** A type for maps whose keys are edge labels. *) + module EdgeLabelMap = Map.Make (EdgeLabel) + + (** A type for maps whose keys are node labels. *) + module NodeLabelMap = Map.Make (NodeLabel) + + (** Internally, each node has an identifier which is a small integer. *) + type nodeid = NodeId of int + module IdCmp = struct type t = nodeid let compare = compare end + + (** A type for maps whose keys are node identifiers. *) + module NodeIdMap = Map.Make (IdCmp) + let nodeid_map_update k m d f = + ExtStd.update NodeIdMap.find NodeIdMap.add k m d f + + (** A type for sets of node identifiers. *) + module NodeIdSet = Set.Make (IdCmp) + + (** The type for graphs. + + The datastructure maintains redundant information about the + graph using multiple maps. Each map provides a logarithmic + complexity for important services of the datastructure, namely + the computation of nodes of least [degrees] and the computation + of a node [neighbourhood]. + + A node is externally characterized by a list of node labels + while internally it is characterized by a node identifier. We + also maintain this mapping using maps, namely [node_of_label] + and [labels]. + + [next_node_id] is a counter that helps determining the identifier + for a newly created node. + *) + + type t = { + next_node_id : int; + node_of_label : nodeid NodeLabelMap.t; + labels : NodeLabel.t list NodeIdMap.t; + neighbours : NodeIdSet.t NodeIdMap.t EdgeLabelMap.t; + degrees : NodeIdSet.t IntMap.t EdgeLabelMap.t + } + + let string_of_nodeid (NodeId x) = string_of_int x + + (** [dump g] returns a text-based representation of the graph, for + debugging. *) + let dump g = + let neighbours = + EdgeLabelMap.bindings g.neighbours |> List.map (fun (c, m) -> + NodeIdMap.bindings m |> List.map (fun (id, ids) -> + Printf.sprintf "%s -%s-> %s" + (string_of_nodeid id) + (EdgeLabel.to_string c) + (String.concat "," (List.map string_of_nodeid (NodeIdSet.elements ids))) + ) + ) |> List.flatten |> String.concat "\n" + in + let degrees = + EdgeLabelMap.bindings g.degrees |> List.map (fun (c, m) -> + IntMap.bindings m |> List.map (fun (d, ids) -> + Printf.sprintf "%d =%s=> %s" + d + (EdgeLabel.to_string c) + (String.concat "," (List.map string_of_nodeid (NodeIdSet.elements ids))) + ) + ) |> List.flatten |> String.concat "\n" + in + Printf.sprintf "%s\n%s\n" neighbours degrees + + (** The empty graph. *) + let empty = + let degrees = + List.fold_left + (fun m e -> EdgeLabelMap.add e IntMap.empty m) + EdgeLabelMap.empty + EdgeLabel.all + in + let neighbours = + List.fold_left + (fun m e -> EdgeLabelMap.add e NodeIdMap.empty m) + EdgeLabelMap.empty + EdgeLabel.all + in + { + next_node_id = 0; + node_of_label = NodeLabelMap.empty; + labels = NodeIdMap.empty; + neighbours; + degrees; + } + + exception InvalidNode + exception InvalidEdge + + let defined_node g n = NodeLabelMap.mem n g.node_of_label + + exception UnboundNode of NodeLabel.t + let id_of_node g n = try + NodeLabelMap.find n g.node_of_label + with Not_found -> + raise (UnboundNode n) + + let nodes_of_id g n = NodeIdMap.find n g.labels + + let nodes g = + List.map snd (NodeIdMap.bindings g.labels) + + (** Sanity check for the data structure. *) + let sanity_check = false + exception InconsistentDegree + let check_consistent_degree g = + (** The number of neighbours of [x] is the degree of [x]. *) + let valid_degree c x ngb = + let xdegree = NodeIdSet.cardinal ngb in + NodeIdSet.mem x (IntMap.find xdegree (EdgeLabelMap.find c g.degrees)) + in + EdgeLabelMap.iter (fun c ngbs -> + NodeIdMap.iter (fun x ngb -> + if not (valid_degree c x ngb) then ( + raise InconsistentDegree + ) + ) ngbs + ) g.neighbours + + let update_neighbour update_set g id1 e id2 = + (** We focus on [e]. *) + let nbg = EdgeLabelMap.find e g.neighbours + and deg = EdgeLabelMap.find e g.degrees in + + (** What is the degree of id1? *) + let id1_nbg = try NodeIdMap.find id1 nbg with _ -> assert false in + let id1_deg = NodeIdSet.cardinal id1_nbg in + + (** Update the neighbours of id1 with update_set id2. *) + let nbg = nodeid_map_update id1 nbg NodeIdSet.empty (update_set id2) in + + (** Update the degree of id1. *) + let deg = int_map_update id1_deg deg NodeIdSet.empty (NodeIdSet.remove id1) in + let deg = + if IntMap.find id1_deg deg = NodeIdSet.empty then + IntMap.remove id1_deg deg + else + deg + in + let id1_nbg = try NodeIdMap.find id1 nbg with _ -> assert false in + let id1_deg = NodeIdSet.cardinal id1_nbg in + let deg = int_map_update id1_deg deg NodeIdSet.empty (NodeIdSet.add id1) in + + (** Finally, update the graph. *) + let neighbours = EdgeLabelMap.add e nbg g.neighbours + and degrees = EdgeLabelMap.add e deg g.degrees in + let g = { g with neighbours; degrees } in + + (** If you suspect a bug in the implementation of the graph data + structure, which is always possible. Activating sanity check + might help you to track it down. *) + if sanity_check then check_consistent_degree g; + g + + let add_neighbour = update_neighbour NodeIdSet.add + let del_neighbour = update_neighbour NodeIdSet.remove + + (** [add_node g [n1;...;nN]] returns a new graph that extends [g] with + a new node labelled by [n1;...;nN]. None of the [nI] can be used + by another node in [g]. Otherwise, [InvalidNode] is raised. + + In the sequel, the new node can be identified by any [nI]. + *) + let add_node g ns = + (** First, a fresh identifier for the node. *) + let nodeid = NodeId g.next_node_id in + let next_node_id = g.next_node_id + 1 in + + (** Second, we check that [ns] are not used by any other node. *) + if List.exists (defined_node g) ns then + raise InvalidNode; + + (** Third, update maps. *) + let node_of_label = + List.fold_left (fun m n -> NodeLabelMap.add n nodeid m) g.node_of_label ns + in + let labels = NodeIdMap.add nodeid ns g.labels in + let neighbours = + EdgeLabelMap.map (fun nbg -> + NodeIdMap.add nodeid NodeIdSet.empty nbg + ) g.neighbours + in + (** Initially, the node has a degree 0 since it has no neighbour. *) + let degrees = + EdgeLabelMap.map + (fun deg -> int_map_update 0 deg NodeIdSet.empty (NodeIdSet.add nodeid)) + g.degrees + in + { next_node_id; node_of_label; labels; degrees; neighbours } + + (** [add_edge g n1 e n2] returns a new graph that extends [g] with a + new edge between [n1] and [n2]. The edge is labelled by [e]. If [n1] + or [n2] does not exist, then [InvalidNode] is raised. *) + let add_edge g n1 e n2 = + if not (defined_node g n1 && defined_node g n2) then + raise InvalidNode; + let id1 = id_of_node g n1 and id2 = id_of_node g n2 in + let g = add_neighbour g id1 e id2 in + let g = add_neighbour g id2 e id1 in + g + + (** [neighbours g e n] returns the neighbours of [n] in [g]. *) + let neighbours g e n = + let id = id_of_node g n in + let ids = + NodeIdSet.elements (NodeIdMap.find id (EdgeLabelMap.find e g.neighbours)) + in + List.map (fun id -> NodeIdMap.find id g.labels) ids + + (** [del_node g n] returns a new graph that contains [g] minus the + node [n] and its edges. *) + let del_node g n = + let id = id_of_node g n in + let g = + EdgeLabelMap.fold (fun e nbg g -> + let nnbg = NodeIdMap.find id nbg in + NodeIdSet.fold (fun id' g -> + let g = del_neighbour g id' e id in + let g = del_neighbour g id e id' in + g + ) nnbg g + ) g.neighbours g + in + let neighbours = + EdgeLabelMap.map (fun nbg -> + NodeIdMap.remove id nbg + ) g.neighbours + in + let degrees = + EdgeLabelMap.map (fun deg -> + let deg0 = IntMap.find 0 deg in + let deg0 = NodeIdSet.remove id deg0 in + if deg0 = NodeIdSet.empty then + IntMap.remove 0 deg + else + IntMap.add 0 deg0 deg + ) g.degrees + in + let node_of_label = List.fold_left (fun node_of_label l -> + NodeLabelMap.remove l node_of_label + ) g.node_of_label (NodeIdMap.find id g.labels) + in + let labels = NodeIdMap.remove id g.labels in + { g with node_of_label; neighbours; labels; degrees } + + (** [del_edge g n1 e n2] *) + let del_edge g n1 e n2 = + let i1 = id_of_node g n1 and i2 = id_of_node g n2 in + let g = del_neighbour g i1 e i2 in + del_neighbour g i2 e i1 + + (** [edges g e] returns all the edges of kind [e] in [g]. *) + let edges g e = + let nbg = EdgeLabelMap.find e g.neighbours in + let edges = + NodeIdMap.fold (fun id ids edges -> + NodeIdSet.fold (fun id' edges -> + (NodeIdMap.find id g.labels, NodeIdMap.find id' g.labels) :: edges + ) ids edges) nbg [] + in + let edges = List.map (fun (n1, n2) -> + if n1 < n2 then (n1, n2) else (n2, n1) + ) edges + in + let edges = List.sort compare edges in + ExtStd.List.uniq edges + + let min_degree exclusion_criteria g c nc = + let cdegrees = EdgeLabelMap.find c g.degrees in + let forbidden = EdgeLabelMap.find nc g.neighbours in + let rec aux degrees = + try + let k, ids = IntMap.min_binding degrees in + let rec aux' ids = + try + let id = NodeIdSet.choose ids in + let excluded = List.exists exclusion_criteria (nodes_of_id g id) in + if not excluded + && NodeIdMap.find id forbidden = NodeIdSet.empty then + Some (k, List.hd (NodeIdMap.find id g.labels)) + else + aux' (NodeIdSet.remove id ids) + with Not_found -> + aux (IntMap.remove k degrees) + in + aux' ids + with Not_found -> None + in + aux cdegrees + + (** [are_connected g n1 e n2] *) + let are_connected g n1 e n2 = + let id1 = id_of_node g n1 in + let id2 = id_of_node g n2 in + NodeIdSet.mem id2 (NodeIdMap.find id1 (EdgeLabelMap.find e g.neighbours)) + + (** [pick_edge g e] *) + let pick_edge g e = + try + let degrees = EdgeLabelMap.find e g.degrees in + let k, ids = IntMap.max_binding degrees in + if k = 0 then None + else + let id = NodeIdSet.choose ids in + let nbg = EdgeLabelMap.find e g.neighbours in + let nbgid = NodeIdMap.find id nbg in + let id2 = NodeIdSet.choose nbgid in + Some (List.hd (nodes_of_id g id), List.hd (nodes_of_id g id2)) + with Not_found -> + None + + (** [merge g n1 n2] *) + let merge g n1 n2 = + let i1 = id_of_node g n1 and i2 = id_of_node g n2 in + let nodes1 = nodes_of_id g i1 and nodes2 = nodes_of_id g i2 in + let nbgs = + List.map + (fun e -> + (e, List.filter (fun n -> not (List.mem n1 n) && not (List.mem n2 n)) + (neighbours g e n1 @ neighbours g e n2))) + EdgeLabel.all + in + let g = del_node g n1 in + let g = del_node g n2 in + let g = add_node g (nodes1 @ nodes2) in + List.fold_left (fun g (e, nbgs) -> + List.fold_left (fun g ns -> + add_edge g n1 e (List.hd ns) + ) g nbgs + ) g nbgs + + (** [all_labels g n] *) + let all_labels g n = + let i = id_of_node g n in + nodes_of_id g i + + (** [show g labels] represents the graph [g] in the DOT format and + uses [dotty] to display it. *) + let show g labels = + let dot_node (NodeId n, ns) = + let ns = + String.concat "," (List.map (fun n -> + NodeLabel.to_string n ^ (match labels n with None -> "" | Some s -> " => " ^ s) + ) ns) + in + Printf.sprintf "n%d [label=\"%s\"];" n ns + in + let dot_nodes = + String.concat "\n" (List.map dot_node (NodeIdMap.bindings g.labels)) + in + let seen = Hashtbl.create 13 in + let dot_edge (NodeId n) c (NodeId n') = + let n, n' = min n n', max n n' in + if not (Hashtbl.mem seen (n, n')) then ( + Hashtbl.add seen (n, n') (); + Printf.sprintf "n%d -- n%d [label=\"%s\"];" n n' (EdgeLabel.to_string c) + ) else "" + in + let neighbour c (id, ids) = + String.concat "\n" (List.map (dot_edge id c) (NodeIdSet.elements ids)) + in + let dot_edges_of_kind (c, ngb) = + String.concat "\n" (List.map (neighbour c) (NodeIdMap.bindings ngb)) + in + let dot_edges = + String.concat "\n" (List.map dot_edges_of_kind (EdgeLabelMap.bindings g.neighbours)) + in + let dot = + Printf.sprintf "graph g {\n%s\n%s\n}" dot_nodes dot_edges + in + let fname, cout = Filename.open_temp_file "flap" ".dot" in + output_string cout dot; + close_out cout; + Printf.printf "Graph written in %s. (You need to install dotty to display it.)\n%!" fname; + ignore (Sys.command ("dotty " ^ fname ^ "&")) + +end diff --git a/flap/src/utilities/graph.mli b/flap/src/utilities/graph.mli new file mode 100644 index 0000000..ab76139 --- /dev/null +++ b/flap/src/utilities/graph.mli @@ -0,0 +1,99 @@ +(** A module for undirected graphs. + + This module provides a functional data structure to represent a + graph which nodes contain a set of labels and which edges can have + one label too. + + We maintain the invariant that two nodes always have different + labels: thus, nodes are identified by their labels. + +*) + +module type EdgeLabelSig = sig + include Set.OrderedType + (** [all] enumerates all the possible edge labels. *) + val all : t list + (** [to_string e] converts [e] in a human readable value. *) + val to_string : t -> string +end + +module type NodeLabelSig = sig + include Set.OrderedType + (** [to_string n] converts [n] in a human readable value. *) + val to_string : t -> string +end + +module Make (EdgeLabel : EdgeLabelSig) (NodeLabel : NodeLabelSig) : sig + + (** The type for graphs. *) + type t + + (** The empty graph. *) + val empty : t + + (** [add_node g [n1;...;nN]] returns a new graph that extends [g] with + a new node labelled by [n1;...;nN]. None of the [nI] can be used + by another node in [g]. Otherwise, [InvalidNode] is raised. + + In the sequel, the new node can be identified by any [nI]. + *) + val add_node : t -> NodeLabel.t list -> t + exception InvalidNode + exception InvalidEdge + + (** [add_edge g n1 e n2] returns a new graph that extends [g] with a + new edge between [n1] and [n2]. The edge is labelled by [e]. If [n1] + or [n2] does not exist, then [InvalidNode] is raised. *) + val add_edge : t -> NodeLabel.t -> EdgeLabel.t -> NodeLabel.t -> t + + (** [del_edge g n1 e n2] returns a new graph that restricts [g] by removing + thge edge between [n1] and [n2]. The edge is labelled by [e]. If [n1] + or [n2] does not exist, then [InvalidNode] is raised. If there is no + such edge between [n1] and [n2] then [InvalidEdge] is raised. *) + val del_edge : t -> NodeLabel.t -> EdgeLabel.t -> NodeLabel.t -> t + + (** [del_node g n] returns a new graph that contains [g] minus the + node [n] and its edges. *) + val del_node : t -> NodeLabel.t -> t + + (** [neighbours g e n] returns the neighbours of [n] in [g] + that are connected with an edge labelled by [e]. One neighbour is + characterized by all its node labels. *) + val neighbours : t -> EdgeLabel.t -> NodeLabel.t -> NodeLabel.t list list + + (** [edges g e] returns all the edges of kind [e] in [g]. + WARNING: This function is inefficient! Use it only for debugging. *) + val edges : t -> EdgeLabel.t -> (NodeLabel.t list * NodeLabel.t list) list + + (** [nodes g] returns all the nodes of [g]. *) + val nodes : t -> NodeLabel.t list list + + (** [min_degree excluded g c nc] returns a node [n] of minimal degree for [c] + that has no edge for [nc] and so that not [excluded c], or returns None + if no such node exists. *) + val min_degree : + (NodeLabel.t -> bool) + -> t -> EdgeLabel.t -> EdgeLabel.t -> (int * NodeLabel.t) option + + (** [pick_edge g c] returns an arbitrary edge for [c] or None if + there is no such edge. *) + val pick_edge : t -> EdgeLabel.t -> (NodeLabel.t * NodeLabel.t) option + + (** [merge g n1 n2] returns a new graph which is [g] in which [n1] + and [n2] have been merged. *) + val merge : t -> NodeLabel.t -> NodeLabel.t -> t + + (** [all_labels g n] returns all the node labels of node [n]. *) + val all_labels : t -> NodeLabel.t -> NodeLabel.t list + + (** [are_connected g n1 e n2] returns true iff [n1] and [n2] are connected + by [e]. *) + val are_connected : t -> NodeLabel.t -> EdgeLabel.t -> NodeLabel.t -> bool + + (** [show g labels] runs [dotty] to display the graph [g]. [labels n] may + optionally return an additional information to be display in the node + for [n]. *) + val show : t -> (NodeLabel.t -> string option) -> unit + val dump : t -> string + +end diff --git a/flap/src/utilities/int16.ml b/flap/src/utilities/int16.ml new file mode 100644 index 0000000..2769fdc --- /dev/null +++ b/flap/src/utilities/int16.ml @@ -0,0 +1,29 @@ +type t = int + +exception LiteralExceeds16bits of int + +(** [check_invariant x] ensures that the integer [x] is a valid + representation for a 16 bits signed integer. *) +let check_invariant x = + failwith "Students! This is your job!" + +(** [hi x] returns the 16 highest bits of [x]'s 32 bits. *) +let hi x = + failwith "Students! This is your job!" + +(** [low x] returns the 16 lowests bits of [x]'s 32 bits. *) +let low x = + failwith "Students! This is your job!" + +(** [of_int x] turns an OCaml integer literal into a 16 bits literal. *) +let of_int x = + check_invariant x; + x + +(** [of_int32 x] turns an OCaml integer literal into a 16 bits literal. *) +let of_int32 x = + of_int (Int32.to_int x) + +(** [to_string x] turns an integer [x] into a string. *) +let to_string x = + string_of_int x diff --git a/flap/src/utilities/int16.mli b/flap/src/utilities/int16.mli new file mode 100644 index 0000000..e48e410 --- /dev/null +++ b/flap/src/utilities/int16.mli @@ -0,0 +1,22 @@ +(** This module implements 16 bits signed integers. *) + +type t + +(** This exception is raised if a literal is too large to be + represented using only 16 bits. *) +exception LiteralExceeds16bits of int + +(** [of_int32 x] turns an OCaml integer literal into a 16 bits literal. *) +val of_int32 : Int32.t -> t + +(** [of_int x] turns an OCaml integer literal into a 16 bits literal. *) +val of_int : int -> t + +(** [hi x] returns the 16 highests bits of [x]'s 32 bits. *) +val hi : Int32.t -> t + +(** [low x] returns the 16 lowests bits of [x]'s 32 bits. *) +val low : Int32.t -> t + +(** [to_string x] turns an integer [x] into a string. *) +val to_string : t -> string diff --git a/flap/src/utilities/list.ml b/flap/src/utilities/list.ml new file mode 100644 index 0000000..31b4115 --- /dev/null +++ b/flap/src/utilities/list.ml @@ -0,0 +1,9 @@ +include Stdlib.List + +let map_fold_right + : type a b c. (a -> b -> c * b) -> a list -> b -> c list * b = + fun f xs acc -> + fold_right + (fun x (ys, acc) -> let y, acc = f x acc in y :: ys, acc) + xs + ([], acc) diff --git a/flap/src/utilities/listMonad.ml b/flap/src/utilities/listMonad.ml new file mode 100644 index 0000000..03caa18 --- /dev/null +++ b/flap/src/utilities/listMonad.ml @@ -0,0 +1,12 @@ +type 'a t = 'a list + +let pick cs = cs + +let return a = [a] + +let fail = [] + +let ( >>= ) m f = + List.(flatten (map f m)) + +let run m = m diff --git a/flap/src/utilities/listMonad.mli b/flap/src/utilities/listMonad.mli new file mode 100644 index 0000000..5ec2440 --- /dev/null +++ b/flap/src/utilities/listMonad.mli @@ -0,0 +1,93 @@ +(** + + The list monad + or "non deterministic computations in OCaml" + or "list comprehension in OCaml" + + As any monad, the purpose of the list monad is to represent in + OCaml computations that are not directly expressible in OCaml. + + OCaml is a deterministic language: there is at most one value for + each expression, i.e. at most one result for each computation. + + What if we want to represent computations that have zero, one + or many results? For instance, imagine the following algorithm: + + pick x in {1..10} + pick y in {1..10} + return (x + y) + + This algorithm is non deterministic because "pick" takes one of + the integers in the set {1..10}. Imagine that we want to know + all possible executions of this program. How to do that? + + Before answering that question, you may wonder why it would be + useful to write such a program and then ask for all its execution. + The answer is: because that is exactly the syntax of sequences + defined by comprehension! So, it is a concise and declarative way + to represent a set of values defined by means of generators, + combinaisons and filters. In other words, the previous program + represents what a mathematician would write: + + { x + y | x ∈ [1..10], y ∈ [1.10] } + + Nice, isn't it? + + Now, let us come back to monads. In OCaml, there is no "pick" + but we can program it. More generally, we can *represent* + computations that are non deterministic as terms of type ['a t]. + +*) +type 'a t +(** + + A value of type ['a t] is a computation that may produce nothing or + a value of type 'a or many values of type 'a. + +*) + +(** [pick s] is a non deterministic operation that takes one of the + element of [s]. You do not know which one. *) +val pick : 'a list -> 'a t + +(** [return x] is a non deterministic computation that evaluates + into [x]. *) +val return : 'a -> 'a t + +(** [fail] is a non deterministic computation with no result. *) +val fail : 'a t + +(** [m >>= (fun x -> e)] is a computation that first executes + [m], name its result [x] and then executes [e]. [x] may + correspond to zero, one or many values of type ['a] but + you consider it as a single potential value. +*) +val ( >>= ) : 'a t -> ('a -> 'b t) -> 'b t + +(** Now, here is how to write the previous program using these + functions: + + let allsums = + pick (range 0 10) >>= (fun x -> + pick (range 0 10) >>= (fun y -> + return (x + y) + ) + + (assuming [range start stop] is the list of integers between + [start] and [stop]). + + Finally, how to get all these integers? Just use [run]: +*) +val run : 'a t -> 'a list + +(** + + For instance, [run allsums] evaluates into: + + [0; 1; 2; 3; 4; 5; 6; 7; 8; 9; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 2; 3; 4; 5; + 6; 7; 8; 9; 10; 11; 3; 4; 5; 6; 7; 8; 9; 10; 11; 12; 4; 5; 6; 7; 8; 9; 10; + 11; 12; 13; 5; 6; 7; 8; 9; 10; 11; 12; 13; 14; 6; 7; 8; 9; 10; 11; 12; 13; + 14; 15; 7; 8; 9; 10; 11; 12; 13; 14; 15; 16; 8; 9; 10; 11; 12; 13; 14; 15; + 16; 17; 9; 10; 11; 12; 13; 14; 15; 16; 17; 18] + +*) diff --git a/flap/src/utilities/option.ml b/flap/src/utilities/option.ml new file mode 100644 index 0000000..22fadbb --- /dev/null +++ b/flap/src/utilities/option.ml @@ -0,0 +1,7 @@ +let map f = function + | None -> None + | Some x -> Some (f x) + +let destruct default f = function + | None -> default () + | Some x -> f x diff --git a/flap/src/utilities/position.ml b/flap/src/utilities/position.ml new file mode 100644 index 0000000..ac59d3d --- /dev/null +++ b/flap/src/utilities/position.ml @@ -0,0 +1,152 @@ +open Sexplib.Std +open Lexing + +type lexing_position = Lexing.position + +let lexing_position_of_sexp p = + [%of_sexp: string * int * int * int] p + |> fun (pos_fname, pos_lnum, pos_bol, pos_cnum) -> + { pos_fname; pos_lnum; pos_bol; pos_cnum } + +let sexp_of_lexing_position p = + [%sexp_of: string * int * int * int] + (p.pos_fname, p.pos_lnum, p.pos_bol, p.pos_cnum) + +type t = + { + start_p : lexing_position; + end_p : lexing_position + } [@@deriving sexp] + +type position = t + +type 'a located = + { + value : 'a; + position : t; + } [@@deriving sexp] + +let value { value = v } = + v + +let position { position = p } = + p + +let destruct p = + (p.value, p.position) + +let located f x = + f (value x) + +let located_pos f x = + f (position x) (value x) + +let with_pos p v = + { + value = v; + position = p; + } + +let with_poss p1 p2 v = + with_pos { start_p = p1; end_p = p2 } v + +let map f v = + { + value = f v.value; + position = v.position; + } + +let iter f { value = v } = + f v + +let mapd f v = + let w1, w2 = f v.value in + let pos = v.position in + ({ value = w1; position = pos }, { value = w2; position = pos }) + +let dummy = + { + start_p = Lexing.dummy_pos; + end_p = Lexing.dummy_pos + } + +let unknown_pos v = + { + value = v; + position = dummy + } + +let start_of_position p = p.start_p + +let end_of_position p = p.end_p + +let filename_of_position p = + p.start_p.Lexing.pos_fname + +let line p = + p.pos_lnum + +let column p = + p.pos_cnum - p.pos_bol + +let characters p1 p2 = + (column p1, p2.pos_cnum - p1.pos_bol) (* intentionally [p1.pos_bol] *) + +let join x1 x2 = + { + start_p = if x1 = dummy then x2.start_p else x1.start_p; + end_p = if x2 = dummy then x1.end_p else x2.end_p + } + +let lex_join x1 x2 = + { + start_p = x1; + end_p = x2 + } + +let join_located l1 l2 f = + { + value = f l1.value l2.value; + position = join l1.position l2.position; + } + +let string_of_lex_pos p = + let c = p.pos_cnum - p.pos_bol in + (string_of_int p.pos_lnum)^":"^(string_of_int c) + +let string_of_pos p = + let filename = filename_of_position p in + let l = line p.start_p in + let c1, c2 = characters p.start_p p.end_p in + if filename = "" then + Printf.sprintf "Line %d, characters %d-%d" l c1 c2 + else + Printf.sprintf "File \"%s\", line %d, characters %d-%d" filename l c1 c2 + +let pos_or_undef = function + | None -> dummy + | Some x -> x + +let cpos lexbuf = + { + start_p = Lexing.lexeme_start_p lexbuf; + end_p = Lexing.lexeme_end_p lexbuf; + } + +let with_cpos lexbuf v = + with_pos (cpos lexbuf) v + +let string_of_cpos lexbuf = + string_of_pos (cpos lexbuf) + +let joinf f t1 t2 = + join (f t1) (f t2) + +let ljoinf f = + List.fold_left (fun p t -> join p (f t)) dummy + +let join_located_list ls f = + { + value = f (List.map (fun l -> l.value) ls); + position = ljoinf (fun x -> x.position) ls + } diff --git a/flap/src/utilities/position.mli b/flap/src/utilities/position.mli new file mode 100644 index 0000000..5595396 --- /dev/null +++ b/flap/src/utilities/position.mli @@ -0,0 +1,112 @@ +(** Extension of standard library's positions. *) + +(** {2 Extended lexing positions} *) + +(** Abstract type for pairs of positions in the lexing stream. *) +type t +type position = t + +(** Decoration of a value with a position. *) +type 'a located = + { + value : 'a; + position : t; + } [@@deriving sexp] + +(** [value dv] returns the raw value that underlies the + decorated value [dv]. *) +val value: 'a located -> 'a + +(** [position dv] returns the position that decorates the + decorated value [dv]. *) +val position: 'a located -> t + +(** [destruct dv] returns the couple of position and value + of a decorated value [dv]. *) +val destruct: 'a located -> 'a * t + +(** [located f x] applies [f] to the value of [x]. *) +val located : ('a -> 'b) -> 'a located -> 'b + +(** [located_pos f x] applies [f] to the position and value of [x]. *) +val located_pos : (t -> 'a -> 'b) -> 'a located -> 'b + +(** [with_pos p v] decorates [v] with a position [p]. *) +val with_pos : t -> 'a -> 'a located + +(** [with_cpos p v] decorates [v] with a lexical position [p]. *) +val with_cpos: Lexing.lexbuf -> 'a -> 'a located + +(** [with_poss start stop v] decorates [v] with a position [(start, stop)]. *) +val with_poss : Lexing.position -> Lexing.position -> 'a -> 'a located + +(** [unknown_pos x] decorates [v] with an unknown position. *) +val unknown_pos : 'a -> 'a located + +(** This value is used when an object does not come from a particular + input location. *) +val dummy: t + +(** [map f v] extends the decoration from [v] to [f v]. *) +val map: ('a -> 'b) -> 'a located -> 'b located + +(** [iter f dv] applies [f] to the value inside [dv]. *) +val iter: ('a -> unit) -> 'a located -> unit + +(** [mapd f v] extends the decoration from [v] to both members of the pair + [f v]. *) +val mapd: ('a -> 'b1 * 'b2) -> 'a located -> 'b1 located * 'b2 located + +(** {2 Accessors} *) + +(** [column p] returns the number of characters from the + beginning of the line of the Lexing.position [p]. *) +val column : Lexing.position -> int + +(** [column p] returns the line number of to the Lexing.position [p]. *) +val line : Lexing.position -> int + +(** [characters p1 p2] returns the character interval + between [p1] and [p2] assuming they are located in the same + line. *) +val characters : Lexing.position -> Lexing.position -> int * int + +(** [start_of_position p] returns the beginning of a position [p]. *) +val start_of_position: t -> Lexing.position + +(** [end_of_position p] returns the end of a position [p]. *) +val end_of_position: t -> Lexing.position + +(** [filename_of_position p] returns the filename of a position [p]. *) +val filename_of_position: t -> string + +(** {2 Position handling} *) + +(** [join p1 p2] returns a position that starts where [p1] + starts and stops where [p2] stops. *) +val join : t -> t -> t + +(** [lex_join l1 l2] returns a position that starts at [l1] and stops + at [l2]. *) +val lex_join : Lexing.position -> Lexing.position -> t + +(** [string_of_lex_pos p] returns a string representation for + the lexing position [p]. *) +val string_of_lex_pos : Lexing.position -> string + +(** [string_of_pos p] returns the standard (Emacs-like) representation + of the position [p]. *) +val string_of_pos : t -> string + +(** [pos_or_undef po] is the identity function except if po = None, + in that case, it returns [undefined_position]. *) +val pos_or_undef : t option -> t + +(** {2 Interaction with the lexer runtime} *) + +(** [cpos lexbuf] returns the current position of the lexer. *) +val cpos : Lexing.lexbuf -> t + +(** [string_of_cpos p] returns a string representation of + the lexer's current position. *) +val string_of_cpos : Lexing.lexbuf -> string diff --git a/flap/src/utilities/stdUserInput.ml b/flap/src/utilities/stdUserInput.ml new file mode 100644 index 0000000..44d94b8 --- /dev/null +++ b/flap/src/utilities/stdUserInput.ml @@ -0,0 +1,22 @@ +let prompt = ref "" + +let set_prompt = ( := ) prompt + +let print_prompt () = + output_string stdout !prompt; + flush stdout + +let input_char = + let display_prompt = ref true in + let ask stdin = + if !display_prompt then begin + display_prompt := false; + print_prompt () + end; + let c = input_char stdin in + if c = '\n' then display_prompt := true; + String.make 1 c + in + ask + +let set_ascii () = () diff --git a/flap/src/utilities/userInput.ml b/flap/src/utilities/userInput.ml new file mode 100644 index 0000000..8c336b5 --- /dev/null +++ b/flap/src/utilities/userInput.ml @@ -0,0 +1 @@ +include StdUserInput diff --git a/flap/src/version.ml b/flap/src/version.ml new file mode 100644 index 0000000..2e6e61b --- /dev/null +++ b/flap/src/version.ml @@ -0,0 +1 @@ +let number = "19.1" diff --git a/flap/src/x86-64/retrolixToX86_64.ml b/flap/src/x86-64/retrolixToX86_64.ml new file mode 100644 index 0000000..367a516 --- /dev/null +++ b/flap/src/x86-64/retrolixToX86_64.ml @@ -0,0 +1,584 @@ +(** This module implements a compiler from Retrolix to X86-64 *) + +(** In more details, this module performs the following tasks: + - turning accesses to local variables and function parameters into stack + loads and stores ; + - generating initialization code and reserving space in the .data section for + global variables ; + - reserving space in the .data section for literal strings. + *) + +(* TODO tail recursion *) + +let error ?(pos = Position.dummy) msg = + Error.error "compilation" pos msg + +(** As in any module that implements {!Compilers.Compiler}, the source + language and the target language must be specified. *) +module Source = Retrolix +module Target = X86_64 +module S = Source.AST +module T = Target.AST + +module Str = struct type t = string let compare = Stdlib.compare end +module StrMap = Map.Make(Str) +module StrSet = Set.Make(Str) + +(** {2 Low-level helpers} *) + +let scratchr = X86_64_Architecture.scratch_register + +let scratch = `Reg scratchr +let rsp = `Reg X86_64_Architecture.RSP +let rbp = `Reg X86_64_Architecture.RBP +let rdi = `Reg X86_64_Architecture.RDI + +(** [align n b] returns the smallest multiple of [b] larger than [n]. *) +let align n b = + let m = n mod b in + if m = 0 then n else n + b - m + +(** {2 Label mangling and generation} *) + +let hash x = string_of_int (Hashtbl.hash x) + +let label_for_string_id id = + ".S_" ^ string_of_int id + +let label_of_retrolix_label (s : string) = + s + +let label_of_function_identifier (S.FId s) = + label_of_retrolix_label s + +let data_label_of_global (S.Id s) = + label_of_retrolix_label s + +let init_label_of_global (xs : S.identifier list) = + ".I_" ^ hash xs + +let label_of_internal_label_id (id : T.label) = + ".X_" ^ id + +let fresh_label : unit -> T.label = + let r = ref 0 in + fun () -> incr r; label_of_internal_label_id (string_of_int !r) + +let fresh_string_label : unit -> string = + let r = ref 0 in + fun () -> let n = !r in incr r; label_for_string_id n + +(** {2 Environments} *) + +type environment = + { + externals : S.FIdSet.t; + (** All the external functions declared in the retrolix program. *) + globals : S.IdSet.t; + (** All the global variables found in the Retrolix program, each with a + unique integer. *) + data_lines : T.line list; + (** All the lines to be added to the .data section of the complete file. *) + } + +let make_environment ~externals ~globals () = + let open T in + + let data_lines = + S.IdSet.fold + (fun ((S.Id id_s) as id) lines -> + Label (data_label_of_global id) + :: Instruction (Comment id_s) + :: Directive (Quad [Lit Mint.zero]) + :: lines + ) + globals + [] + in + + let data_lines = + S.FIdSet.fold + (fun (S.FId f) lines -> Directive (Extern f) :: lines) + externals + data_lines + in + + { + externals; + globals; + data_lines; + } + +let is_external env (f : S.rvalue) = + match f with + | `Immediate (S.LFun f) -> + S.FIdSet.mem f env.externals + | _ -> + false + +let is_global env f = + S.IdSet.mem f env.globals + +let register_string s env = + let open T in + let l = fresh_string_label () in + l, + { env with data_lines = Label l :: Directive (String s) :: env.data_lines; } + +(* The following function is here to please Flap's architecture. *) +let initial_environment () = + make_environment ~externals:S.FIdSet.empty ~globals:S.IdSet.empty () + +let register_globals global_set env = + let open T in + let globals, data_lines = + S.IdSet.fold + (fun ((S.Id id_s) as id) (globals, lines) -> + S.IdSet.add id globals, + Label (data_label_of_global id) + :: Instruction (Comment id_s) + :: Directive (Quad [Lit Mint.zero]) + :: lines + ) + global_set + (S.IdSet.empty, env.data_lines) + in + { env with globals; data_lines; } + +(** {2 Abstract instruction selectors and calling conventions} *) + +module type InstructionSelector = + sig + (** [mov ~dst ~src] generates the x86-64 assembly listing to copy [src] into + [dst]. *) + val mov : dst:T.dst -> src:T.src -> T.line list + + (** [add ~dst ~srcl ~srcr] generates the x86-64 assembly listing to store + [srcl + srcr] into [dst]. *) + val add : dst:T.dst -> srcl:T.src -> srcr:T.src -> T.line list + + (** [sub ~dst ~srcl ~srcr] generates the x86-64 assembly listing to store + [srcl - srcr] into [dst]. *) + val sub : dst:T.dst -> srcl:T.src -> srcr:T.src -> T.line list + + (** [mul ~dst ~srcl ~srcr] generates the x86-64 assembly listing to store + [srcl * srcr] into [dst]. *) + val mul : dst:T.dst -> srcl:T.src -> srcr:T.src -> T.line list + + (** [div ~dst ~srcl ~srcr] generates the x86-64 assembly listing to store + [srcl / srcr] into [dst]. *) + val div : dst:T.dst -> srcl:T.src -> srcr:T.src -> T.line list + + (** [andl ~dst ~srcl ~srcr] generates the x86-64 assembly listing to store + [srcl & srcr] into [dst]. *) + val andl : dst:T.dst -> srcl:T.src -> srcr:T.src -> T.line list + + (** [orl ~dst ~srcl ~srcr] generates the x86-64 assembly listing to store + [srcl | srcr] into [dst]. *) + val orl : dst:T.dst -> srcl:T.src -> srcr:T.src -> T.line list + + (** [conditional_jump ~cc ~srcl ~srcr ~ll ~lr] generates the x86-64 assembly + listing to test whether [srcl, srcr] satisfies the relation described by + [cc] and jump to [ll] if they do or to [lr] when they do not. *) + val conditional_jump : + cc:T.condcode -> + srcl:T.src -> srcr:T.src -> + ll:T.label -> lr:T.label -> + T.line list + + (** [switch ~default ~discriminant ~cases ()] generates the x86-64 assembly + listing to jump to [cases.(discriminant)], or to the (optional) [default] + label when discriminant is larger than [Array.length cases]. + + The behavior of the program is undefined if [discriminant < 0], or if + [discriminant >= Array.length cases] and no [default] has been given. *) + val switch : + ?default:T.label -> + discriminant:T.src -> + cases:T.label array -> + unit -> + T.line list + end + +module type FrameManager = + sig + (** The abstract data structure holding the information necessary to + implement the calling convention. *) + type frame_descriptor + + (** Generate a frame descriptor for the function with parameter [params] and + locals [locals]. *) + val frame_descriptor : + params:S.identifier list -> + locals:S.identifier list -> + frame_descriptor + + (** [location_of fd v] computes the address of [v] according to the frame + descriptor [fd]. Note that [v] might be a local variable, a function + parameter, or a global variable. *) + val location_of : frame_descriptor -> S.identifier -> T.address + + (** [function_prologue fd] generates the x86-64 assembly listing to setup + a stack frame according to the frame descriptor [fd]. *) + val function_prologue : frame_descriptor -> T.line list + + (** [function_epilogue fd] generates the x86-64 assembly listing to setup a + stack frame according to the frame descriptor [fd]. *) + val function_epilogue : frame_descriptor -> T.line list + + (** [call fd ~kind ~f ~args] generates the x86-64 assembly listing to setup + a call to the function at [f], with arguments [args], with [kind] + specifying whether this should be a normal or tail call. *) + val call : + frame_descriptor -> + kind:[ `Normal | `Tail ] -> + f:T.src -> + args:T.src list -> + T.line list + end + +(** {2 Code generator} *) + +(** This module implements an x86-64 code generator for Retrolix using the + provided [InstructionSelector] and [FrameManager]. *) +module Codegen(IS : InstructionSelector)(FM : FrameManager) = + struct + let translate_label (S.Label l) = + label_of_retrolix_label l + + let translate_variable fd v = + `Addr (FM.location_of fd v) + + let translate_literal lit env = + match lit with + | S.LInt i -> + T.Lit i, env + + | S.LFun f -> + T.Lab (label_of_function_identifier f), env + + | S.LChar c -> + T.Lit (Mint.of_int @@ Char.code c), env + + | S.LString s -> + let l, env = register_string s env in + T.Lab l, env + + let translate_register (S.RId s) = + X86_64_Architecture.register_of_string s + + let translate_lvalue fi lv = + match lv with + | `Variable v -> + translate_variable fi v + | `Register reg -> + `Reg (translate_register reg) + + let translate_rvalue fi rv env = + match rv with + | `Immediate lit -> + let lit, env = translate_literal lit env in + `Imm lit, env + | (`Variable _ | `Register _) as lv -> + translate_lvalue fi lv, env + + let translate_rvalues fi rvs env = + List.fold_right + (fun rv (rvs, env) -> + let rv, env = translate_rvalue fi rv env in + rv :: rvs, env) + rvs + ([], env) + + let translate_label_to_operand (S.Label l) = + `Imm (T.Lab l) + + let translate_cond cond = + match cond with + | S.GT -> T.G + | S.LT -> T.L + | S.GTE -> T.GE + | S.LTE -> T.LE + | S.EQ -> T.E + + let translate_instruction fd ins env : T.line list * environment = + let open T in + begin match ins with + | S.Call (f, args, is_tail) -> + let kind = if is_tail then `Tail else `Normal in + let f, env = translate_rvalue fd f env in + let args, env = translate_rvalues fd args env in + FM.call fd ~kind ~f ~args, + env + + | S.Assign (dst, op, args) -> + let dst = translate_lvalue fd dst in + let args, env = translate_rvalues fd args env in + let inss = + match op, args with + | S.Add, [ srcl; srcr; ] -> + IS.add ~dst ~srcl ~srcr + | S.Sub, [ srcl; srcr; ] -> + IS.sub ~dst ~srcl ~srcr + | S.Mul, [ srcl; srcr; ] -> + IS.mul ~dst ~srcl ~srcr + | S.Div, [ srcl; srcr; ] -> + IS.div ~dst ~srcl ~srcr + | S.And, [ srcl; srcr; ] -> + IS.andl ~dst ~srcl ~srcr + | S.Or, [ srcl; srcr; ] -> + IS.orl ~dst ~srcl ~srcr + | S.Copy, [ src; ] -> + IS.mov ~dst ~src + | _ -> + error "Unknown operator or bad arity" + in + inss, env + + | S.Ret -> + FM.function_epilogue fd @ insns [T.Ret], + env + + | S.Jump l -> + insns + [ + T.jmpl ~tgt:(translate_label l); + ], + env + + | S.ConditionalJump (cond, args, ll, lr) -> + let cc = translate_cond cond in + let srcl, srcr, env = + match args with + | [ src1; src2; ] -> + let src1, env = translate_rvalue fd src1 env in + let src2, env = translate_rvalue fd src2 env in + src1, src2, env + | _ -> + failwith "translate_exp: conditional jump with invalid arity" + in + IS.conditional_jump + ~cc + ~srcl ~srcr + ~ll:(translate_label ll) ~lr:(translate_label lr), + env + + | S.Switch (discriminant, cases, default) -> + let discriminant, env = translate_rvalue fd discriminant env in + let cases = Array.map translate_label cases in + let default = ExtStd.Option.map translate_label default in + IS.switch ?default ~discriminant ~cases (), + env + + | S.Comment s -> + insns + [ + Comment s; + ], + env + + | S.Exit -> + IS.mov ~src:(liti 0) ~dst:rdi + @ FM.call fd ~kind:`Normal ~f:(`Imm (Lab "exit")) ~args:[], + env + end + + + let translate_labelled_instruction fi (body, env) (l, ins) = + let ins, env = translate_instruction fi ins env in + List.rev ins @ T.Label (translate_label l) :: body, + env + + let translate_labelled_instructions fi env inss = + let inss, env = + List.fold_left (translate_labelled_instruction fi) ([], env) inss + in + List.rev inss, env + + let translate_fun_def ~name ?(desc = "") ~params ~locals gen_body = + let open T in + + let fd = FM.frame_descriptor ~params ~locals in + + let prologue = FM.function_prologue fd in + + let body, env = gen_body fd in + + Directive (PadToAlign { pow = 3; fill = 0x90; }) :: Label name + :: (if desc = "" + then prologue + else Instruction (Comment desc) :: prologue) + @ body, + env + + let translate_block ~name ?(desc = "") ~params (locals, body) env = + translate_fun_def + ~name + ~desc + ~params + ~locals + (fun fi -> translate_labelled_instructions fi env body) + + let translate_definition def (body, env) = + match def with + | S.DValues (xs, block) -> + let ids = ExtPPrint.to_string RetrolixPrettyPrinter.identifiers xs in + let name = init_label_of_global xs in + let def, env = + translate_block + ~name + ~desc:("Initializer for " ^ ids ^ ".") + ~params:[] + block + env + in + def @ body, env + + | S.DFunction ((S.FId id) as f, params, block) -> + let def, env = + translate_block + ~desc:("Retrolix function " ^ id ^ ".") + ~name:(label_of_function_identifier f) + ~params + block + env + in + def @ body, env + + | S.DExternalFunction (S.FId id) -> + T.(Directive (Extern id)) :: body, + env + + let generate_main _ p = + let open T in + + let body = + List.rev + [ + Directive (PadToAlign { pow = 3; fill = 0x90; }); + Label "main"; + Instruction (Comment "Program entry point."); + Instruction (T.subq ~src:(`Imm (Lit 8L)) ~dst:rsp); + ] + in + + (* Call all initialization stubs *) + let body = + let call body def = + match def with + | S.DValues (ids, _) -> + let l = init_label_of_global ids in + Instruction (T.calld ~tgt:(Lab l)) :: body + | S.DFunction _ | S.DExternalFunction _ -> + body + in + List.fold_left call body p + in + + let body = + T.insns + [ + T.calld ~tgt:(Lab "exit"); + T.movq ~src:(liti 0) ~dst:rdi; + ] + @ body + in + + Directive (Global "main") :: List.rev body + + (** [translate p env] turns a Retrolix program into a X86-64 program. *) + let translate (p : S.t) (env : environment) : T.t * environment = + let env = register_globals (S.globals p) env in + let pt, env = List.fold_right translate_definition p ([], env) in + let main = generate_main env p in + let p = T.data_section :: env.data_lines @ T.text_section :: main @ pt in + T.remove_unused_labels p, env + end + +(** {2 Concrete instructions selectors and calling conventions} *) + +module InstructionSelector : InstructionSelector = + struct + open T + + let mov ~(dst : dst) ~(src : src) = + failwith "Students! This is your job!" + + let bin ins ~dst ~srcl ~srcr = + failwith "Students! This is your job!" + + let add ~dst ~srcl ~srcr = + failwith "Students! This is your job!" + + let sub ~dst ~srcl ~srcr = + failwith "Students! This is your job!" + + let mul ~dst ~srcl ~srcr = + failwith "Students! This is your job!" + + let div ~dst ~srcl ~srcr = + failwith "Students! This is your job!" + + let andl ~dst ~srcl ~srcr = + failwith "Students! This is your job!" + + let orl ~dst ~srcl ~srcr = + failwith "Students! This is your job!" + + let conditional_jump ~cc ~srcl ~srcr ~ll ~lr = + failwith "Students! This is your job!" + + let switch ?default ~discriminant ~cases () = + failwith "Students! This is your job!" + + end + +module FrameManager(IS : InstructionSelector) : FrameManager = + struct + type frame_descriptor = + { + param_count : int; + (** Number of parameters. *) + locals_space : int; + (** Amount of space dedicated to local variables in the stack frame. *) + stack_map : Mint.t S.IdMap.t; + (** Maps stack-allocated variable names to stack slots expressed as + frame-pointer relative offsets. *) + } + + (** [empty_frame fd] returns [true] if and only if the stack frame described + by [fd] is empty. *) + let empty_frame fd = + fd.param_count = 0 && fd.locals_space = 0 + + (** [stack_usage_after_prologue fd] returns the size, in bytes, of the stack + space after the function prologue. *) + let stack_usage_after_prologue fd = + Mint.size_in_bytes + + (if empty_frame fd then 0 else 1) * Mint.size_in_bytes + + fd.locals_space + + let frame_descriptor ~params ~locals = + (* Student! Implement me! *) + { param_count = 0; locals_space = 0; stack_map = S.IdMap.empty; } + + let location_of fd id = + failwith "Students! This is your job!" + + let function_prologue fd = + (* Student! Implement me! *) + [] + + let function_epilogue fd = + (* Student! Implement me! *) + [] + + let call fd ~kind ~f ~args = + failwith "Students! This is your job!" + + end + +module CG = + Codegen(InstructionSelector)(FrameManager(InstructionSelector)) + +let translate = CG.translate diff --git a/flap/src/x86-64/x86_64.ml b/flap/src/x86-64/x86_64.ml new file mode 100644 index 0000000..3df4d9f --- /dev/null +++ b/flap/src/x86-64/x86_64.ml @@ -0,0 +1,33 @@ +(** The (subset of) x86-64 assembly language. *) + +module AST = X86_64_AST + +let name = "x86-64" + +type ast = AST.t + +let no_parser () = + Error.global_error + "during source analysis" + "There is no parser for X86-64 in flap." + +let parse _ _ = + no_parser () + +let parse_filename _ = + no_parser () + +let extension = + ".s" + +let executable_format = + false + +let parse_string _ = + no_parser () + +let print_ast ast = + X86_64_PrettyPrinter.(to_string program ast) + +include X86_64_Typechecker +include X86_64_Interpreter diff --git a/flap/src/x86-64/x86_64_AST.ml b/flap/src/x86-64/x86_64_AST.ml new file mode 100644 index 0000000..c793904 --- /dev/null +++ b/flap/src/x86-64/x86_64_AST.ml @@ -0,0 +1,299 @@ +(** The abstract syntax tree for X86-64 programs. *) + +type reg = X86_64_Architecture.register + +type label = string + +type lit = Mint.t + +type scale = + [ `One | `Two | `Four | `Eight ] + +type imm = + | Lit of lit + | Lab of label + +type address = + { + offset : imm option; + base : reg option; + idx : reg option; + scale : scale; + } + +type dst = + [ `Addr of address | `Reg of reg ] + +type src = + [ dst | `Imm of imm ] + +type suffix = + [ `b | `w | `l | `q ] + +type condcode = + | E (* equal *) + | NE (* not equal *) + | S (* negative *) + | NS (* not negative *) + | G (* greater *) + | GE (* greater or equal *) + | L (* lower *) + | LE (* lower or equal *) + | A (* above *) + | AE (* above or equal *) + | B (* below *) + | BE (* below or equal *) + +type instruction = + | Add of { s : suffix; src : src; dst : dst; } + | Sub of { s : suffix; src : src; dst : dst; } + | Imul of { s : suffix; src : src; dst : dst; } + | Idiv of { s : suffix; src : src; } + | And of { s : suffix; src : src; dst : dst; } + | Or of { s : suffix; src : src; dst : dst; } + | Xor of { s : suffix; src : src; dst : dst; } + | Not of { s : suffix; dst : dst; } + | Lea of { s : suffix; src : address; dst : dst } + | Cmp of { s : suffix; src1 : src; src2 : src; } + + | Inc of { s : suffix; dst : dst; } + | Dec of { s : suffix; dst : dst; } + + | Push of { s : suffix; src : src; } + | Pop of { s : suffix; dst : dst; } + | Mov of { s : suffix; src : src; dst : dst; } + + | CallD of { tgt : imm; } + | CallI of { tgt : dst; } + | Ret + | JmpD of { tgt : imm; } + | JmpI of { tgt : dst; } + | Jcc of { cc : condcode; tgt : imm; } + + | Cmov of { cc : condcode; s : suffix; src : reg; dst : dst; } + | Ct of { s : [ `w | `l | `q ]; } + + | Comment of string + +type directive = + | Section of string + | Extern of string + | Global of string + | String of string + | Quad of imm list + | PadToAlign of { pow : int; fill : int; } + +type line = + | Directive of directive + | Label of label + | Instruction of instruction + +type t = + line list + +let int_of_scale s = + match s with + | `Zero -> 0 + | `One -> 1 + | `Two -> 2 + | `Four -> 4 + | `Eight -> 8 + +(* Helper functions *) + +let lit i = + `Imm (Lit i) + +let liti i = + lit (Mint.of_int i) + +let addr ?offset ?idx ?(scale = `One) ?base () = + { + offset; + base; + idx; + scale; + } + +let addq ~src ~dst = + Add { s = `q; src; dst; } + +let subq ~src ~dst = + Sub { s = `q; src; dst; } + +let imulq ~src ~dst = + Imul { s = `q; src; dst; } + +let idivq ~src = + Idiv { s = `q; src; } + +let andq ~src ~dst = + And { s = `q; src; dst; } + +let orq ~src ~dst = + Or { s = `q; src; dst; } + +let xorq ~src ~dst = + Xor { s = `q; src; dst; } + +let notq ~dst = + Not { s = `q; dst; } + +let leaq ~src ~dst = + Lea { s = `q; dst; src; } + +let incq ~dst = + Inc { s = `q; dst; } + +let decq ~dst = + Dec { s = `q; dst; } + +let cmpq ~src1 ~src2 = + Cmp { s = `q; src1; src2; } + +let pushq ~src = + Push { s = `q; src; } + +let popq ~dst = + Pop { s = `q; dst; } + +let pushr ~reg = + Push { s = `q; src = `Reg reg; } + +let popr ~reg = + Pop { s = `q; dst = `Reg reg; } + +let movq ~src ~dst = + Mov { s = `q; src; dst; } + +let calld ~tgt = + CallD { tgt; } + +let calli ~tgt = + CallI { tgt; } + +let calldi ~tgt = + match tgt with + | `Imm tgt -> + calld ~tgt + | #dst as tgt -> + calli ~tgt + +let calll ~tgt = + calld ~tgt:(Lab tgt) + +let jmpd ~tgt = + JmpD { tgt; } + +let jmpi ~tgt = + JmpI { tgt; } + +let jmpdi ~tgt = + match tgt with + | `Imm tgt -> + jmpd ~tgt + | #dst as tgt -> + jmpi ~tgt + +let jmpl ~tgt = + jmpd ~tgt:(Lab tgt) + +let jcc ~cc ~tgt = + Jcc { cc; tgt; } + +let jccl ~cc ~tgt = + jcc ~cc ~tgt:(Lab tgt) + +let cmovq ~cc ~src ~dst = + Cmov { s = `q; cc; src; dst; } + +let cqto = + Ct { s = `q; } + +let insns = + List.map (fun i -> Instruction i) + +let string s = + Directive (String s) + +let text_section = + Directive (Section "text") + +let data_section = + Directive (Section "data") + +(* Compute labels referenced from an assembly file. *) + +module Lab = struct type t = label let compare = Stdlib.compare end +module LabMap = Map.Make(Lab) +module LabSet = Set.Make(Lab) + +let referenced_labels_imm imm refs = + match imm with + | Lit _ -> refs + | Lab l -> LabSet.add l refs + +let referenced_labels_addr addr refs = + ExtStd.Option.fold referenced_labels_imm addr.offset refs + +let referenced_labels_dst (dst : dst) refs = + match dst with + | `Addr addr -> referenced_labels_addr addr refs + | `Reg _ -> refs + +let referenced_labels_src (src : src) = + match src with + | #dst as dst -> referenced_labels_dst dst + | `Imm imm -> referenced_labels_imm imm + +let referenced_labels_ins ins refs = + match ins with + | Add { src; dst; } | Sub { src; dst; } | Imul { src; dst; } + | And { src; dst; } | Or { src; dst; } | Xor { src; dst; } + | Mov { src; dst; } + -> + referenced_labels_src src @@ referenced_labels_dst dst refs + | Not { dst; } | Inc { dst; } | Dec { dst; } | Pop { dst; } | Cmov { dst; } -> + referenced_labels_dst dst refs + | Idiv { src; } | Push { src; } -> + referenced_labels_src src refs + | Cmp { src1; src2; } -> + referenced_labels_src src1 @@ referenced_labels_src src2 refs + | Lea { src; dst; } -> + referenced_labels_addr src @@ referenced_labels_dst dst refs + | CallD { tgt; } | JmpD { tgt; } | Jcc { tgt; } -> + referenced_labels_imm tgt refs + | CallI { tgt; } | JmpI { tgt; } -> + referenced_labels_dst tgt refs + | Ret | Comment _ | Ct _ -> + refs + +let referenced_labels_directive d refs = + match d with + | Quad imms -> + List.fold_left (fun refs imm -> referenced_labels_imm imm refs) refs imms + | Global l -> + LabSet.add l refs + | Section _ | Extern _ | String _ | PadToAlign _ -> + refs + +let referenced_labels_line refs line = + match line with + | Directive d -> + referenced_labels_directive d refs + | Label _ -> + refs + | Instruction ins -> + referenced_labels_ins ins refs + +let referenced_labels_prog p = + List.fold_left referenced_labels_line LabSet.empty p + +let remove_unused_labels p = + let refs = referenced_labels_prog p in + let useful line = + match line with + | Label l -> LabSet.mem l refs + | Directive _ | Instruction _ -> true + in + List.filter useful p diff --git a/flap/src/x86-64/x86_64_Architecture.ml b/flap/src/x86-64/x86_64_Architecture.ml new file mode 100644 index 0000000..631e202 --- /dev/null +++ b/flap/src/x86-64/x86_64_Architecture.ml @@ -0,0 +1,189 @@ +type register = + | RAX + | RBX + | RCX + | RDX + | RSP + | RBP + | RSI + | RDI + | R8 + | R9 + | R10 + | R11 + | R12 + | R13 + | R14 + | R15 + | RIP + +(** All registers. *) +let all_registers : register list = + [ + RAX; + RBX; + RCX; + RDX; + RSP; + RBP; + RSI; + RDI; + R8; + R9; + R10; + R11; + R12; + R13; + R14; + R15; + RIP; + ] + +(** Hardware registers that can be used by register allocation. *) +let allocable_registers : register list = + [ + RAX; + RBX; + RCX; + RDX; + RSI; + RDI; + R8; + R9; + R10; + R11; + R12; + R13; + R14; + ] + +(** Registers used as effective arguments for functions. *) +let argument_passing_registers : register list = + [ + RDI; + RSI; + RDX; + RCX; + R8; + R9; + ] + +(** Registers that must be preserved through function calls. *) +let callee_saved_registers : register list = + [ + RBX; + RSP; + RBP; + R12; + R13; + R14; + ] + +(** Registers that are *not* preserved by function calls. *) +let caller_saved_registers : register list = + [ + RAX; + RDI; + RSI; + RDX; + RCX; + R8; + R9; + R10; + R11; + ] + +(** Registers that are preserved by function calls and allocable.*) +let allocable_callee_saved_registers = + List.(filter (fun r -> mem r allocable_registers) callee_saved_registers) + +(** The register that holds the value returned by a function. *) +let return_register : register = + RAX + +(** A register that is never used by the register allocator. *) +let scratch_register : register = + R15 + +(** A human representation of register identifier. *) +let string_of_register r = + match r with + | RAX -> + "rax" + | RBX -> + "rbx" + | RCX -> + "rcx" + | RDX -> + "rdx" + | RSP -> + "rsp" + | RBP -> + "rbp" + | RSI -> + "rsi" + | RDI -> + "rdi" + | R8 -> + "r8" + | R9 -> + "r9" + | R10 -> + "r10" + | R11 -> + "r11" + | R12 -> + "r12" + | R13 -> + "r13" + | R14 -> + "r14" + | R15 -> + "r15" + | RIP -> + "rip" + +let register_of_string s = + match s with + | "rax" -> + RAX + | "rbx" -> + RBX + | "rcx" -> + RCX + | "rdx" -> + RDX + | "rsp" -> + RSP + | "rbp" -> + RBP + | "rsi" -> + RSI + | "rdi" -> + RDI + | "r8" -> + R8 + | "r9" -> + R9 + | "r10" -> + R10 + | "r11" -> + R11 + | "r12" -> + R12 + | "r13" -> + R13 + | "r14" -> + R14 + | "r15" -> + R15 + | "rip" -> + RIP + | _ -> + invalid_arg ("register_of_string: " ^ s) + +(** Registers are numbered, RAX being 0 and R15 being 15. *) +let register_number r = + (* TODO: is this reasonable? *) + assert Obj.(is_int @@ repr r); + (Obj.magic r : int) diff --git a/flap/src/x86-64/x86_64_Initialization.ml b/flap/src/x86-64/x86_64_Initialization.ml new file mode 100644 index 0000000..eafaa84 --- /dev/null +++ b/flap/src/x86-64/x86_64_Initialization.ml @@ -0,0 +1,6 @@ +open Optimizers + +(** Register some compilers that have X86_64 as a target or source language. *) +let initialize () = + Languages.register (module X86_64); + Compilers.register (optimizing_compiler (module RetrolixToX86_64)) diff --git a/flap/src/x86-64/x86_64_Interpreter.ml b/flap/src/x86-64/x86_64_Interpreter.ml new file mode 100644 index 0000000..45205cd --- /dev/null +++ b/flap/src/x86-64/x86_64_Interpreter.ml @@ -0,0 +1,42 @@ +(** This module implements the interpreter for X86-64 programs. *) + +open Error +open X86_64_AST + +let error msg = + global_error "X86-64 execution" msg + +type runtime = unit + +type observable = { + exit_status : Unix.process_status; + stdout : string; + stderr : string +} + +let initial_runtime () = () + +let show_runtime _ = () + +let evaluate _ (ast : t) = + (* 1. Generate a temporary .s file. + 2. Call gcc to generate an executable linked with runtime.o + 3. Execute this program, capturing its stdout/stderr + *) + let fn = Filename.temp_file "flap" ".s" in + let oc = open_out fn in + PPrint.ToChannel.compact oc (X86_64_PrettyPrinter.program ast); + close_out oc; + (), + { + exit_status = Unix.WEXITED 0; + stdout = Printf.sprintf "Generated assembly file in %s\n" fn; + stderr = ""; + } + +let print_observable (_ : runtime) (obs : observable) = + Printf.sprintf + "Process exited with status %s.\n\nSTDOUT:\n\n%s\nSTDERR:\n%s\n\n" + (ExtStd.Unix.string_of_process_status obs.exit_status) + obs.stdout + obs.stderr diff --git a/flap/src/x86-64/x86_64_PrettyPrinter.ml b/flap/src/x86-64/x86_64_PrettyPrinter.ml new file mode 100644 index 0000000..ee1c14c --- /dev/null +++ b/flap/src/x86-64/x86_64_PrettyPrinter.ml @@ -0,0 +1,199 @@ +(** This module offers a pretty-printer for X86-64 programs. *) + +open PPrint + +open X86_64_AST + +let string = PPrint.string + +let tab = + string "\t" + +let quote s = + string "\"" ^^ s ^^ string "\"" + +let commas docs = + separate (string ", ") docs + +let reg r = + string ("%" ^ X86_64_Architecture.string_of_register r) + +let label l = + string l + +let mint n = + string (Mint.to_string n) + +let int i = + string @@ string_of_int i + +let int32 i = + string "%" ^^ string @@ Int32.to_string i + +let imm ?(dollar = true) ie = + let d = + match ie with + | Lit n -> + string (Mint.to_string n) + | Lab l -> + label l + in + (if dollar then string "$" else empty) ^^ d + +let address { offset; base; idx; scale; } = + let map f o = + match o with + | None -> empty + | Some x -> f x + in + let pp idx = + string "," ^^ reg idx ^^ string "," ^^ int (int_of_scale scale) + in + map (imm ~dollar:false) offset + ^^ parens (map reg base ^^ map pp idx) + +let suffix s = + string (match s with `b -> "b" | `w -> "w" | `l -> "l" | `q -> "q") + +let condcode cc = + match cc with + | E -> string "e" + | NE -> string "ne" + | S -> string "s" + | NS -> string "ns" + | G -> string "g" + | GE -> string "ge" + | L -> string "l" + | LE -> string "le" + | A -> string "a" + | AE -> string "ae" + | B -> string "b" + | BE -> string "be" + +let operand ?(dollar = true) o = + match o with + | `Imm ie -> + imm ~dollar ie + | `Addr a -> + address a + | `Reg r -> + reg r + +let instruction i = + let ins ?cc ?s ins ops = + let cc = + match cc with + | None -> empty + | Some cc -> condcode cc + in + let s = + match s with + | None -> empty + | Some s -> suffix s + in + string ins ^^ cc ^^ s + ^^ (if ops = [] then empty else string " " ^^ commas ops) + in + match i with + | Add { s; src; dst; } -> + ins "add" ~s [operand src; operand dst] + | Sub { s; src; dst; } -> + ins "sub" ~s [operand src; operand dst] + | Imul { s; src; dst; } -> + ins "imul" ~s [operand src; operand dst] + | Idiv { s; src; } -> + ins "idiv" ~s [operand src] + + | And { s; src; dst; } -> + ins "and" ~s [operand src; operand dst] + | Or { s; src; dst; } -> + ins "or" ~s [operand src; operand dst] + | Xor { s; src; dst; } -> + ins "xor" ~s [operand src; operand dst] + | Not { s; dst; } -> + ins "not" ~s [operand dst] + + | Lea { src; dst; } -> + ins "lea" [address src; operand dst] + + | Cmp { s; src1; src2; } -> + ins "cmp" ~s [operand src1; operand src2] + + | Inc { s; dst; } -> + ins "inc" ~s [operand dst] + | Dec { s; dst; } -> + ins "dec" ~s [operand dst] + + | Push { s; src; } -> + ins "push" ~s [operand src] + | Pop { s; dst; } -> + ins "pop" ~s [operand dst] + | Mov { s; src; dst; } -> + ins "mov" ~s [operand src; operand dst] + + | CallD { tgt; } -> + ins "call" [imm ~dollar:false tgt] + | CallI { tgt; } -> + string "call *" ^^ operand tgt + | JmpD { tgt; } -> + ins "jmp" [imm ~dollar:false tgt] + | JmpI { tgt; } -> + string "jmp *" ^^ operand tgt + | Ret -> + ins "ret" [] + + | Jcc { cc; tgt; } -> + ins "j" ~cc [imm ~dollar:false tgt] + | Cmov { cc; s; src; dst; } -> + ins "cmov" ~cc ~s [reg src; operand dst] + + | Ct { s; } -> + let f, t = + match s with + | `w -> "w", "d" + | `l -> "l", "q" + | `q -> "q", "o" + in + string ("c" ^ f ^ "t" ^ t) + + | Comment s -> + string "/* " ^^ string s ^^ string " */" + +let directive d = + let needs_tab, k, s = + match d with + | Section s -> + false, s, empty + | Extern s -> + true, "extern ", string s + | Global s -> + true, "globl ", string s + | String s -> + true, "string ", quote (string (String.escaped s)) + | Quad ns -> + true, + "quad ", + separate (string ", ") (List.map (imm ~dollar:false) ns) + | PadToAlign { pow; fill; } -> + false, + "p2align ", + separate (comma ^^ space) [int pow; int fill] + in + (if needs_tab then tab else empty) ^^ string ("." ^ k) ^^ s + +let line li = + match li with + | Directive d -> + directive d + | Label l -> + label l ^^ string ":" + | Instruction i -> + tab ^^ instruction i + +let program ast = + separate_map hardline line ast ^^ hardline + +let to_string f x = + let b = Buffer.create 13 in + ToBuffer.pretty 0.5 80 b (f x); + Buffer.contents b diff --git a/flap/src/x86-64/x86_64_Typechecker.ml b/flap/src/x86-64/x86_64_Typechecker.ml new file mode 100644 index 0000000..30113fe --- /dev/null +++ b/flap/src/x86-64/x86_64_Typechecker.ml @@ -0,0 +1,9 @@ +(** There is no typechecker for x86-64 programs in flap. *) + +type typing_environment = unit + +let initial_typing_environment () = () + +let typecheck () _ = () + +let print_typing_environment () = "" diff --git a/flap/tests/01-Parsing-no-positions/01-constructor-application.bad.expected b/flap/tests/01-Parsing-no-positions/01-constructor-application.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/01-constructor-application.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/01-constructor-application.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/01-constructor-application.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..8e5b2e5 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/01-constructor-application.bad.parsing-no-positions.hopix @@ -0,0 +1,2 @@ +fun f = True + diff --git a/flap/tests/01-Parsing-no-positions/01-constructor-application.good.expected b/flap/tests/01-Parsing-no-positions/01-constructor-application.good.expected new file mode 100644 index 0000000..d4a9baa --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/01-constructor-application.good.expected @@ -0,0 +1 @@ +fun f _ = True diff --git a/flap/tests/01-Parsing-no-positions/01-constructor-application.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/01-constructor-application.good.parsing-no-positions.hopix new file mode 100644 index 0000000..050c32f --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/01-constructor-application.good.parsing-no-positions.hopix @@ -0,0 +1,2 @@ +fun f _ = True + diff --git a/flap/tests/01-Parsing-no-positions/02-app2.bad.expected b/flap/tests/01-Parsing-no-positions/02-app2.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/02-app2.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/02-app2.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/02-app2.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..4462a01 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/02-app2.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +val drama = eats cat mouse \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/03-app2-2.bad.expected b/flap/tests/01-Parsing-no-positions/03-app2-2.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/03-app2-2.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/03-app2-2.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/03-app2-2.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..0eaf872 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/03-app2-2.bad.parsing-no-positions.hopix @@ -0,0 +1,2 @@ +let h2o = h (o o) +let h2obis = h [o, o] \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/04-app2-3.bad.expected b/flap/tests/01-Parsing-no-positions/04-app2-3.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/04-app2-3.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/04-app2-3.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/04-app2-3.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..2d456ef --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/04-app2-3.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = f (, 2) \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/05-app3.bad.expected b/flap/tests/01-Parsing-no-positions/05-app3.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/05-app3.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/05-app3.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/05-app3.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..f3ebe01 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/05-app3.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +le app3 = f x y z \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/06-lexer-var-id-1.bad.expected b/flap/tests/01-Parsing-no-positions/06-lexer-var-id-1.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/06-lexer-var-id-1.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/06-lexer-var-id-1.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/06-lexer-var-id-1.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..a951bb0 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/06-lexer-var-id-1.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let YouShouldNeverUseThis_Ugly_Way_of_Identifying_THINGS = 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/06-lexer-var-id-1.good.expected b/flap/tests/01-Parsing-no-positions/06-lexer-var-id-1.good.expected new file mode 100644 index 0000000..957c961 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/06-lexer-var-id-1.good.expected @@ -0,0 +1 @@ +let youShouldNeverUseThis_Ugly_Way_of_Identifying_THINGS = 0 diff --git a/flap/tests/01-Parsing-no-positions/06-lexer-var-id-1.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/06-lexer-var-id-1.good.parsing-no-positions.hopix new file mode 100644 index 0000000..22519c5 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/06-lexer-var-id-1.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let youShouldNeverUseThis_Ugly_Way_of_Identifying_THINGS = 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/07-lexer-var-id-2.bad.expected b/flap/tests/01-Parsing-no-positions/07-lexer-var-id-2.bad.expected new file mode 100644 index 0000000..ba85cad --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/07-lexer-var-id-2.bad.expected @@ -0,0 +1,2 @@ +Error (during lexing) + unexpected character. diff --git a/flap/tests/01-Parsing-no-positions/07-lexer-var-id-2.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/07-lexer-var-id-2.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..11a5653 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/07-lexer-var-id-2.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let ?this_is_far_better_way_to_name_things_2_the_revenge = 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/07-lexer-var-id-2.good.expected b/flap/tests/01-Parsing-no-positions/07-lexer-var-id-2.good.expected new file mode 100644 index 0000000..8de8f59 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/07-lexer-var-id-2.good.expected @@ -0,0 +1 @@ +let this_is_far_better_way_to_name_things_2_the_revenge = 0 diff --git a/flap/tests/01-Parsing-no-positions/07-lexer-var-id-2.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/07-lexer-var-id-2.good.parsing-no-positions.hopix new file mode 100644 index 0000000..670e4ba --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/07-lexer-var-id-2.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let this_is_far_better_way_to_name_things_2_the_revenge = 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/08-lexer-all-id-1.bad.expected b/flap/tests/01-Parsing-no-positions/08-lexer-all-id-1.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/08-lexer-all-id-1.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/08-lexer-all-id-1.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/08-lexer-all-id-1.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..b8a76f7 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/08-lexer-all-id-1.bad.parsing-no-positions.hopix @@ -0,0 +1,2 @@ +fun fine (x y) = 0 +let fine = 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/08-lexer-all-id-1.good.expected b/flap/tests/01-Parsing-no-positions/08-lexer-all-id-1.good.expected new file mode 100644 index 0000000..ec781fc --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/08-lexer-all-id-1.good.expected @@ -0,0 +1,2 @@ +fun fine (x, y) = 0 +let fine = 0 diff --git a/flap/tests/01-Parsing-no-positions/08-lexer-all-id-1.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/08-lexer-all-id-1.good.parsing-no-positions.hopix new file mode 100644 index 0000000..df50ca7 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/08-lexer-all-id-1.good.parsing-no-positions.hopix @@ -0,0 +1,2 @@ +fun fine (x, y) = 0 +let fine = 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/09-lexer-constr-id-1.bad.expected b/flap/tests/01-Parsing-no-positions/09-lexer-constr-id-1.bad.expected new file mode 100644 index 0000000..4a7550d --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/09-lexer-constr-id-1.bad.expected @@ -0,0 +1 @@ +let x = True < > diff --git a/flap/tests/01-Parsing-no-positions/09-lexer-constr-id-1.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/09-lexer-constr-id-1.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..6eb14f7 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/09-lexer-constr-id-1.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = True <> \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/09-lexer-constr-id-1.good.expected b/flap/tests/01-Parsing-no-positions/09-lexer-constr-id-1.good.expected new file mode 100644 index 0000000..f4c4941 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/09-lexer-constr-id-1.good.expected @@ -0,0 +1 @@ +let x = True diff --git a/flap/tests/01-Parsing-no-positions/09-lexer-constr-id-1.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/09-lexer-constr-id-1.good.parsing-no-positions.hopix new file mode 100644 index 0000000..467de38 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/09-lexer-constr-id-1.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = True \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/10-lexer-constr-id-2.bad.expected b/flap/tests/01-Parsing-no-positions/10-lexer-constr-id-2.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/10-lexer-constr-id-2.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/10-lexer-constr-id-2.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/10-lexer-constr-id-2.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..6dc477c --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/10-lexer-constr-id-2.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = Cons (0, Nil : 1) \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/10-lexer-constr-id-2.good.expected b/flap/tests/01-Parsing-no-positions/10-lexer-constr-id-2.good.expected new file mode 100644 index 0000000..b614545 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/10-lexer-constr-id-2.good.expected @@ -0,0 +1 @@ +let x = Cons(0, Nil(1)) diff --git a/flap/tests/01-Parsing-no-positions/10-lexer-constr-id-2.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/10-lexer-constr-id-2.good.parsing-no-positions.hopix new file mode 100644 index 0000000..af45253 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/10-lexer-constr-id-2.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = Cons (0, Nil (1)) \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/100-ref-2.bad.expected b/flap/tests/01-Parsing-no-positions/100-ref-2.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/100-ref-2.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/100-ref-2.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/100-ref-2.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..3e5ab9b --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/100-ref-2.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let ill_typed = ref 0 * \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/100-ref-2.good.expected b/flap/tests/01-Parsing-no-positions/100-ref-2.good.expected new file mode 100644 index 0000000..72b444d --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/100-ref-2.good.expected @@ -0,0 +1 @@ +let ill_typed = (ref 0 * 1) diff --git a/flap/tests/01-Parsing-no-positions/100-ref-2.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/100-ref-2.good.parsing-no-positions.hopix new file mode 100644 index 0000000..9bd8d13 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/100-ref-2.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let ill_typed = ref 0 * 1 \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/101-ref-3.bad.expected b/flap/tests/01-Parsing-no-positions/101-ref-3.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/101-ref-3.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/101-ref-3.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/101-ref-3.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..3c09487 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/101-ref-3.bad.parsing-no-positions.hopix @@ -0,0 +1,3 @@ +let main = + let x = ref 0 + 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/101-ref-3.good.expected b/flap/tests/01-Parsing-no-positions/101-ref-3.good.expected new file mode 100644 index 0000000..595476e --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/101-ref-3.good.expected @@ -0,0 +1 @@ +let main = let x = (ref 0) ; 0 diff --git a/flap/tests/01-Parsing-no-positions/101-ref-3.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/101-ref-3.good.parsing-no-positions.hopix new file mode 100644 index 0000000..5893d86 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/101-ref-3.good.parsing-no-positions.hopix @@ -0,0 +1,3 @@ +let main = + let x = ref 0; + 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/102-ref-4.bad.expected b/flap/tests/01-Parsing-no-positions/102-ref-4.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/102-ref-4.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/102-ref-4.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/102-ref-4.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..21918da --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/102-ref-4.bad.parsing-no-positions.hopix @@ -0,0 +1,2 @@ +let main = + let y = ref (\x -> x) \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/102-ref-4.good.expected b/flap/tests/01-Parsing-no-positions/102-ref-4.good.expected new file mode 100644 index 0000000..447ae72 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/102-ref-4.good.expected @@ -0,0 +1 @@ +let main = let y = (ref (\ x -> x)) ; y diff --git a/flap/tests/01-Parsing-no-positions/102-ref-4.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/102-ref-4.good.parsing-no-positions.hopix new file mode 100644 index 0000000..37ed173 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/102-ref-4.good.parsing-no-positions.hopix @@ -0,0 +1,3 @@ +let main = + let y = ref (\x -> x); + y \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/103-ref-5.bad.expected b/flap/tests/01-Parsing-no-positions/103-ref-5.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/103-ref-5.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/103-ref-5.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/103-ref-5.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..d537989 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/103-ref-5.bad.parsing-no-positions.hopix @@ -0,0 +1,3 @@ +let main = + val y = ref "foo"; + ref "bar" \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/103-ref-5.good.expected b/flap/tests/01-Parsing-no-positions/103-ref-5.good.expected new file mode 100644 index 0000000..9e3e1b1 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/103-ref-5.good.expected @@ -0,0 +1 @@ +let main = let y = (ref "foo") ; ref "bar" diff --git a/flap/tests/01-Parsing-no-positions/103-ref-5.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/103-ref-5.good.parsing-no-positions.hopix new file mode 100644 index 0000000..19ac311 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/103-ref-5.good.parsing-no-positions.hopix @@ -0,0 +1,3 @@ +let main = + let y = ref "foo"; + ref "bar" \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/104-assignment.bad.expected b/flap/tests/01-Parsing-no-positions/104-assignment.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/104-assignment.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/104-assignment.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/104-assignment.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..05627a1 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/104-assignment.bad.parsing-no-positions.hopix @@ -0,0 +1,2 @@ +let main = + x = 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/104-assignment.good.expected b/flap/tests/01-Parsing-no-positions/104-assignment.good.expected new file mode 100644 index 0000000..55517fb --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/104-assignment.good.expected @@ -0,0 +1 @@ +let main = x := 0 diff --git a/flap/tests/01-Parsing-no-positions/104-assignment.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/104-assignment.good.parsing-no-positions.hopix new file mode 100644 index 0000000..c1262ee --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/104-assignment.good.parsing-no-positions.hopix @@ -0,0 +1,2 @@ +let main = + x := 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/105-assignment-2.bad.expected b/flap/tests/01-Parsing-no-positions/105-assignment-2.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/105-assignment-2.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/105-assignment-2.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/105-assignment-2.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..b31dbfc --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/105-assignment-2.bad.parsing-no-positions.hopix @@ -0,0 +1,2 @@ +let main = + (ref 0) := diff --git a/flap/tests/01-Parsing-no-positions/105-assignment-2.good.expected b/flap/tests/01-Parsing-no-positions/105-assignment-2.good.expected new file mode 100644 index 0000000..83830a5 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/105-assignment-2.good.expected @@ -0,0 +1 @@ +let main = (ref 0) := 1 diff --git a/flap/tests/01-Parsing-no-positions/105-assignment-2.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/105-assignment-2.good.parsing-no-positions.hopix new file mode 100644 index 0000000..ec265cd --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/105-assignment-2.good.parsing-no-positions.hopix @@ -0,0 +1,2 @@ +let main = + (ref 0) := 1 \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/106-assignment-3.bad.expected b/flap/tests/01-Parsing-no-positions/106-assignment-3.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/106-assignment-3.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/106-assignment-3.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/106-assignment-3.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..6f29ae2 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/106-assignment-3.bad.parsing-no-positions.hopix @@ -0,0 +1,2 @@ +let main = + := 3 \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/106-assignment-3.good.expected b/flap/tests/01-Parsing-no-positions/106-assignment-3.good.expected new file mode 100644 index 0000000..8ba66a9 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/106-assignment-3.good.expected @@ -0,0 +1 @@ +let main = (f 0) := 3 diff --git a/flap/tests/01-Parsing-no-positions/106-assignment-3.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/106-assignment-3.good.parsing-no-positions.hopix new file mode 100644 index 0000000..ad53614 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/106-assignment-3.good.parsing-no-positions.hopix @@ -0,0 +1,2 @@ +let main = + f 0 := 3 \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/107-assignment-4.bad.expected b/flap/tests/01-Parsing-no-positions/107-assignment-4.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/107-assignment-4.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/107-assignment-4.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/107-assignment-4.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..d042451 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/107-assignment-4.bad.parsing-no-positions.hopix @@ -0,0 +1,2 @@ +let main = + \ -> x := 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/107-assignment-4.good.expected b/flap/tests/01-Parsing-no-positions/107-assignment-4.good.expected new file mode 100644 index 0000000..2a6f5ee --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/107-assignment-4.good.expected @@ -0,0 +1 @@ +let main = \ x -> (x := 0) diff --git a/flap/tests/01-Parsing-no-positions/107-assignment-4.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/107-assignment-4.good.parsing-no-positions.hopix new file mode 100644 index 0000000..2dc6b1a --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/107-assignment-4.good.parsing-no-positions.hopix @@ -0,0 +1,2 @@ +let main = + \x -> x := 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/108-type-ascription-1.bad.expected b/flap/tests/01-Parsing-no-positions/108-type-ascription-1.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/108-type-ascription-1.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/108-type-ascription-1.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/108-type-ascription-1.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..adaec38 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/108-type-ascription-1.bad.parsing-no-positions.hopix @@ -0,0 +1,2 @@ +let main = + match you { (me : int) -> me } \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/108-type-ascription-1.good.expected b/flap/tests/01-Parsing-no-positions/108-type-ascription-1.good.expected new file mode 100644 index 0000000..6cad84f --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/108-type-ascription-1.good.expected @@ -0,0 +1 @@ +let main = match (you) { | (me : int) -> me } diff --git a/flap/tests/01-Parsing-no-positions/108-type-ascription-1.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/108-type-ascription-1.good.parsing-no-positions.hopix new file mode 100644 index 0000000..7d3d72e --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/108-type-ascription-1.good.parsing-no-positions.hopix @@ -0,0 +1,2 @@ +let main = + match (you) { (me : int) -> me } \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/109-type-ascription-2.bad.expected b/flap/tests/01-Parsing-no-positions/109-type-ascription-2.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/109-type-ascription-2.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/109-type-ascription-2.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/109-type-ascription-2.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..4b468dd --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/109-type-ascription-2.bad.parsing-no-positions.hopix @@ -0,0 +1,2 @@ +let main = + 0 : int \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/109-type-ascription-2.good.expected b/flap/tests/01-Parsing-no-positions/109-type-ascription-2.good.expected new file mode 100644 index 0000000..2ad927b --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/109-type-ascription-2.good.expected @@ -0,0 +1 @@ +let main = (0 : int) diff --git a/flap/tests/01-Parsing-no-positions/109-type-ascription-2.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/109-type-ascription-2.good.parsing-no-positions.hopix new file mode 100644 index 0000000..4678569 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/109-type-ascription-2.good.parsing-no-positions.hopix @@ -0,0 +1,2 @@ +let main = + (0 : int) \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/11-lexer-constr-id-3.bad.expected b/flap/tests/01-Parsing-no-positions/11-lexer-constr-id-3.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/11-lexer-constr-id-3.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/11-lexer-constr-id-3.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/11-lexer-constr-id-3.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..96dc759 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/11-lexer-constr-id-3.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = (0,) \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/11-lexer-constr-id-3.good.expected b/flap/tests/01-Parsing-no-positions/11-lexer-constr-id-3.good.expected new file mode 100644 index 0000000..ef0986e --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/11-lexer-constr-id-3.good.expected @@ -0,0 +1 @@ +let x = (0, 1) diff --git a/flap/tests/01-Parsing-no-positions/11-lexer-constr-id-3.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/11-lexer-constr-id-3.good.parsing-no-positions.hopix new file mode 100644 index 0000000..741b5f7 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/11-lexer-constr-id-3.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = (0, 1) \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/110-type-ascription-3.bad.expected b/flap/tests/01-Parsing-no-positions/110-type-ascription-3.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/110-type-ascription-3.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/110-type-ascription-3.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/110-type-ascription-3.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..d520d90 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/110-type-ascription-3.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let main = (\x => x : int -> int) \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/110-type-ascription-3.good.expected b/flap/tests/01-Parsing-no-positions/110-type-ascription-3.good.expected new file mode 100644 index 0000000..610596d --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/110-type-ascription-3.good.expected @@ -0,0 +1 @@ +let main = (\ x -> x : int -> int) diff --git a/flap/tests/01-Parsing-no-positions/110-type-ascription-3.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/110-type-ascription-3.good.parsing-no-positions.hopix new file mode 100644 index 0000000..78aa8ca --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/110-type-ascription-3.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let main = (\x -> x : int -> int) \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/111-deref-1.bad.expected b/flap/tests/01-Parsing-no-positions/111-deref-1.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/111-deref-1.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/111-deref-1.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/111-deref-1.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..6caa58e --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/111-deref-1.bad.parsing-no-positions.hopix @@ -0,0 +1,2 @@ +let main = + ! \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/111-deref-1.good.expected b/flap/tests/01-Parsing-no-positions/111-deref-1.good.expected new file mode 100644 index 0000000..f960efc --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/111-deref-1.good.expected @@ -0,0 +1 @@ +let main = (! x) diff --git a/flap/tests/01-Parsing-no-positions/111-deref-1.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/111-deref-1.good.parsing-no-positions.hopix new file mode 100644 index 0000000..862890e --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/111-deref-1.good.parsing-no-positions.hopix @@ -0,0 +1,2 @@ +let main = + ! x \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/112-deref-2.bad.expected b/flap/tests/01-Parsing-no-positions/112-deref-2.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/112-deref-2.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/112-deref-2.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/112-deref-2.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..7d8e7a0 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/112-deref-2.bad.parsing-no-positions.hopix @@ -0,0 +1,2 @@ +let double = + ! (! ) \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/112-deref-2.good.expected b/flap/tests/01-Parsing-no-positions/112-deref-2.good.expected new file mode 100644 index 0000000..cc49756 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/112-deref-2.good.expected @@ -0,0 +1 @@ +let double = (! ((! x))) diff --git a/flap/tests/01-Parsing-no-positions/112-deref-2.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/112-deref-2.good.parsing-no-positions.hopix new file mode 100644 index 0000000..6a71f5a --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/112-deref-2.good.parsing-no-positions.hopix @@ -0,0 +1,2 @@ +let double = + ! (! x) \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/113-deref-3.good.expected b/flap/tests/01-Parsing-no-positions/113-deref-3.good.expected new file mode 100644 index 0000000..7f72862 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/113-deref-3.good.expected @@ -0,0 +1 @@ +let main = (((! f)) 0); ((! (g 0))) diff --git a/flap/tests/01-Parsing-no-positions/113-deref-3.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/113-deref-3.good.parsing-no-positions.hopix new file mode 100644 index 0000000..3573a4c --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/113-deref-3.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let main = !f (0); ! (g (0)) \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/114-while-1.bad.expected b/flap/tests/01-Parsing-no-positions/114-while-1.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/114-while-1.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/114-while-1.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/114-while-1.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..e93c6fd --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/114-while-1.bad.parsing-no-positions.hopix @@ -0,0 +1,2 @@ +let main = + while True { nothing (0) } \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/114-while-1.good.expected b/flap/tests/01-Parsing-no-positions/114-while-1.good.expected new file mode 100644 index 0000000..dd6a89e --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/114-while-1.good.expected @@ -0,0 +1 @@ +let main = while (True) { nothing 0 } diff --git a/flap/tests/01-Parsing-no-positions/114-while-1.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/114-while-1.good.parsing-no-positions.hopix new file mode 100644 index 0000000..1906855 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/114-while-1.good.parsing-no-positions.hopix @@ -0,0 +1,2 @@ +let main = + while (True) { nothing (0) } \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/115-while-2.bad.expected b/flap/tests/01-Parsing-no-positions/115-while-2.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/115-while-2.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/115-while-2.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/115-while-2.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..2a0a5a0 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/115-while-2.bad.parsing-no-positions.hopix @@ -0,0 +1,5 @@ +let main = + while (True) { + while (!x >? 0) + x := !x - 1 + } \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/115-while-2.good.expected b/flap/tests/01-Parsing-no-positions/115-while-2.good.expected new file mode 100644 index 0000000..bca6f3e --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/115-while-2.good.expected @@ -0,0 +1,2 @@ +let main = + while (True) { while (((! x) >? 0)) { x := ((! x) - 1) } } diff --git a/flap/tests/01-Parsing-no-positions/115-while-2.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/115-while-2.good.parsing-no-positions.hopix new file mode 100644 index 0000000..4321253 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/115-while-2.good.parsing-no-positions.hopix @@ -0,0 +1,6 @@ +let main = + while (True) { + while (!x >? 0) { + x := !x - 1 + } + } \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/116-for-1.bad.expected b/flap/tests/01-Parsing-no-positions/116-for-1.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/116-for-1.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/116-for-1.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/116-for-1.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..84a0595 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/116-for-1.bad.parsing-no-positions.hopix @@ -0,0 +1,2 @@ +let main = + for i from 0 to 10 { nothing (0) } \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/116-for-1.good.expected b/flap/tests/01-Parsing-no-positions/116-for-1.good.expected new file mode 100644 index 0000000..4c9eec9 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/116-for-1.good.expected @@ -0,0 +1 @@ +let main = for i from (0) to (10) { nothing 0 } diff --git a/flap/tests/01-Parsing-no-positions/116-for-1.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/116-for-1.good.parsing-no-positions.hopix new file mode 100644 index 0000000..cc92bb1 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/116-for-1.good.parsing-no-positions.hopix @@ -0,0 +1,2 @@ +let main = + for i from (0) to (10) { nothing (0) } \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/117-for-2.bad.expected b/flap/tests/01-Parsing-no-positions/117-for-2.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/117-for-2.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/117-for-2.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/117-for-2.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..1b0f1f5 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/117-for-2.bad.parsing-no-positions.hopix @@ -0,0 +1,2 @@ +let main = + for x from (0 to 100) { y := x * 2 + !y } \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/117-for-2.good.expected b/flap/tests/01-Parsing-no-positions/117-for-2.good.expected new file mode 100644 index 0000000..b7621ab --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/117-for-2.good.expected @@ -0,0 +1 @@ +let main = for x from (0) to (100) { y := ((x * 2) + (! y)) } diff --git a/flap/tests/01-Parsing-no-positions/117-for-2.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/117-for-2.good.parsing-no-positions.hopix new file mode 100644 index 0000000..7fe5461 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/117-for-2.good.parsing-no-positions.hopix @@ -0,0 +1,2 @@ +let main = + for x from (0) to (100) { y := x * 2 + !y } \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/118-do-while-1.bad.expected b/flap/tests/01-Parsing-no-positions/118-do-while-1.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/118-do-while-1.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/118-do-while-1.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/118-do-while-1.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..24d81b9 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/118-do-while-1.bad.parsing-no-positions.hopix @@ -0,0 +1,2 @@ +let main = + do { nothing (0) } until True diff --git a/flap/tests/01-Parsing-no-positions/118-do-while-1.good.expected b/flap/tests/01-Parsing-no-positions/118-do-while-1.good.expected new file mode 100644 index 0000000..676d218 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/118-do-while-1.good.expected @@ -0,0 +1 @@ +let main = (nothing 0); while (True) { nothing 0 } diff --git a/flap/tests/01-Parsing-no-positions/118-do-while-1.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/118-do-while-1.good.parsing-no-positions.hopix new file mode 100644 index 0000000..7b53d29 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/118-do-while-1.good.parsing-no-positions.hopix @@ -0,0 +1,2 @@ +let main = + do { nothing (0) } until (True) diff --git a/flap/tests/01-Parsing-no-positions/119-do-while-2.bad.expected b/flap/tests/01-Parsing-no-positions/119-do-while-2.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/119-do-while-2.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/119-do-while-2.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/119-do-while-2.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..bb891e6 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/119-do-while-2.bad.parsing-no-positions.hopix @@ -0,0 +1,6 @@ +let main = + do { + do + x := !x - 1 + while (!x >? 0) + } while (True) diff --git a/flap/tests/01-Parsing-no-positions/119-do-while-2.good.expected b/flap/tests/01-Parsing-no-positions/119-do-while-2.good.expected new file mode 100644 index 0000000..42c29fb --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/119-do-while-2.good.expected @@ -0,0 +1,3 @@ +let main = + while (((! x) >? 0)) { x := ((! x) - 1) }; + while (True) { while (((! x) >? 0)) { x := ((! x) - 1) } } diff --git a/flap/tests/01-Parsing-no-positions/119-do-while-2.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/119-do-while-2.good.parsing-no-positions.hopix new file mode 100644 index 0000000..a99dca9 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/119-do-while-2.good.parsing-no-positions.hopix @@ -0,0 +1,6 @@ +let main = + do { + while (!x >? 0) { + x := !x - 1 + } + } until (True) diff --git a/flap/tests/01-Parsing-no-positions/12-lexer-label-id-1.bad.expected b/flap/tests/01-Parsing-no-positions/12-lexer-label-id-1.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/12-lexer-label-id-1.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/12-lexer-label-id-1.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/12-lexer-label-id-1.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..9222bdb --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/12-lexer-label-id-1.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = t.Some_label \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/12-lexer-label-id-1.good.expected b/flap/tests/01-Parsing-no-positions/12-lexer-label-id-1.good.expected new file mode 100644 index 0000000..e8bf89b --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/12-lexer-label-id-1.good.expected @@ -0,0 +1 @@ +let x = t.some_label diff --git a/flap/tests/01-Parsing-no-positions/12-lexer-label-id-1.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/12-lexer-label-id-1.good.parsing-no-positions.hopix new file mode 100644 index 0000000..c8dcec7 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/12-lexer-label-id-1.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = t.some_label \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/12-lexer-label-id-2.bad.expected b/flap/tests/01-Parsing-no-positions/12-lexer-label-id-2.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/12-lexer-label-id-2.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/12-lexer-label-id-2.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/12-lexer-label-id-2.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..6f12ecb --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/12-lexer-label-id-2.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = { Some_other_label_l33t_AND_GL0RI0US = 0 } \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/12-lexer-label-id-2.good.expected b/flap/tests/01-Parsing-no-positions/12-lexer-label-id-2.good.expected new file mode 100644 index 0000000..ae50301 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/12-lexer-label-id-2.good.expected @@ -0,0 +1 @@ +let x = {some_other_label_l33t_AND_GL0RI0US = 0} diff --git a/flap/tests/01-Parsing-no-positions/12-lexer-label-id-2.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/12-lexer-label-id-2.good.parsing-no-positions.hopix new file mode 100644 index 0000000..1d025e2 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/12-lexer-label-id-2.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = { some_other_label_l33t_AND_GL0RI0US = 0 } \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/13-type-con-id-1.bad.expected b/flap/tests/01-Parsing-no-positions/13-type-con-id-1.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/13-type-con-id-1.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/13-type-con-id-1.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/13-type-con-id-1.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..f0156c6 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/13-type-con-id-1.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +type Dungeons = CASTLE \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/13-type-con-id-1.good.expected b/flap/tests/01-Parsing-no-positions/13-type-con-id-1.good.expected new file mode 100644 index 0000000..d28a213 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/13-type-con-id-1.good.expected @@ -0,0 +1 @@ +type dungeons = CASTLE diff --git a/flap/tests/01-Parsing-no-positions/13-type-con-id-1.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/13-type-con-id-1.good.parsing-no-positions.hopix new file mode 100644 index 0000000..6811098 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/13-type-con-id-1.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +type dungeons = CASTLE \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/14-type-con-id-2.bad.expected b/flap/tests/01-Parsing-no-positions/14-type-con-id-2.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/14-type-con-id-2.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/14-type-con-id-2.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/14-type-con-id-2.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..69134a2 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/14-type-con-id-2.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +type that_s_A_GREAT_TYPE = justKO diff --git a/flap/tests/01-Parsing-no-positions/14-type-con-id-2.good.expected b/flap/tests/01-Parsing-no-positions/14-type-con-id-2.good.expected new file mode 100644 index 0000000..6d4e347 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/14-type-con-id-2.good.expected @@ -0,0 +1 @@ +type that_s_A_GREAT_TYPE = JustOK diff --git a/flap/tests/01-Parsing-no-positions/14-type-con-id-2.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/14-type-con-id-2.good.parsing-no-positions.hopix new file mode 100644 index 0000000..e222139 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/14-type-con-id-2.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +type that_s_A_GREAT_TYPE = JustOK diff --git a/flap/tests/01-Parsing-no-positions/15-int-literal-1.bad.expected b/flap/tests/01-Parsing-no-positions/15-int-literal-1.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/15-int-literal-1.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/15-int-literal-1.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/15-int-literal-1.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..8329071 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/15-int-literal-1.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/15-int-literal-1.good.expected b/flap/tests/01-Parsing-no-positions/15-int-literal-1.good.expected new file mode 100644 index 0000000..b6a2459 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/15-int-literal-1.good.expected @@ -0,0 +1 @@ +let x = 0 diff --git a/flap/tests/01-Parsing-no-positions/15-int-literal-1.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/15-int-literal-1.good.parsing-no-positions.hopix new file mode 100644 index 0000000..b5368df --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/15-int-literal-1.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/16-int-literal-2.bad.expected b/flap/tests/01-Parsing-no-positions/16-int-literal-2.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/16-int-literal-2.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/16-int-literal-2.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/16-int-literal-2.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..24685ce --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/16-int-literal-2.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = --0 \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/16-int-literal-2.good.expected b/flap/tests/01-Parsing-no-positions/16-int-literal-2.good.expected new file mode 100644 index 0000000..b6a2459 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/16-int-literal-2.good.expected @@ -0,0 +1 @@ +let x = 0 diff --git a/flap/tests/01-Parsing-no-positions/16-int-literal-2.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/16-int-literal-2.good.parsing-no-positions.hopix new file mode 100644 index 0000000..1d5f923 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/16-int-literal-2.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = -0 \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/17-int-literal-3.bad.expected b/flap/tests/01-Parsing-no-positions/17-int-literal-3.bad.expected new file mode 100644 index 0000000..b5997c4 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/17-int-literal-3.bad.expected @@ -0,0 +1,2 @@ +Global Error (during parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/17-int-literal-3.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/17-int-literal-3.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..cc4866f --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/17-int-literal-3.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = 1234432112341234123412324321232431 \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/17-int-literal-3.good.expected b/flap/tests/01-Parsing-no-positions/17-int-literal-3.good.expected new file mode 100644 index 0000000..07d6776 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/17-int-literal-3.good.expected @@ -0,0 +1 @@ +let x = 12344321 diff --git a/flap/tests/01-Parsing-no-positions/17-int-literal-3.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/17-int-literal-3.good.parsing-no-positions.hopix new file mode 100644 index 0000000..921f22f --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/17-int-literal-3.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = 12344321 \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/18-int-literal-4.bad.expected b/flap/tests/01-Parsing-no-positions/18-int-literal-4.bad.expected new file mode 100644 index 0000000..b5997c4 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/18-int-literal-4.bad.expected @@ -0,0 +1,2 @@ +Global Error (during parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/18-int-literal-4.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/18-int-literal-4.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..ee29e71 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/18-int-literal-4.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = 0xcafeBABEBABEcafecafeBABE \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/18-int-literal-4.good.expected b/flap/tests/01-Parsing-no-positions/18-int-literal-4.good.expected new file mode 100644 index 0000000..c89ef90 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/18-int-literal-4.good.expected @@ -0,0 +1 @@ +let x = 3405691582 diff --git a/flap/tests/01-Parsing-no-positions/18-int-literal-4.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/18-int-literal-4.good.parsing-no-positions.hopix new file mode 100644 index 0000000..6ec7aec --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/18-int-literal-4.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = 0xcafeBABE \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/19-int-literal-5.bad.expected b/flap/tests/01-Parsing-no-positions/19-int-literal-5.bad.expected new file mode 100644 index 0000000..b5997c4 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/19-int-literal-5.bad.expected @@ -0,0 +1,2 @@ +Global Error (during parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/19-int-literal-5.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/19-int-literal-5.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..bcf2b6f --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/19-int-literal-5.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = 0o10101010101010101010101010101010101010101010101010101010101010101010101010101010 \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/19-int-literal-5.good.expected b/flap/tests/01-Parsing-no-positions/19-int-literal-5.good.expected new file mode 100644 index 0000000..7769519 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/19-int-literal-5.good.expected @@ -0,0 +1 @@ +let x = 2130440 diff --git a/flap/tests/01-Parsing-no-positions/19-int-literal-5.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/19-int-literal-5.good.parsing-no-positions.hopix new file mode 100644 index 0000000..e314b22 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/19-int-literal-5.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = 0o10101010 \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/20-int-literal-6.bad.expected b/flap/tests/01-Parsing-no-positions/20-int-literal-6.bad.expected new file mode 100644 index 0000000..b5997c4 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/20-int-literal-6.bad.expected @@ -0,0 +1,2 @@ +Global Error (during parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/20-int-literal-6.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/20-int-literal-6.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..48963c2 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/20-int-literal-6.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = 0xffffffffffffffffffffffffffffffffffffffff \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/20-int-literal-6.good.expected b/flap/tests/01-Parsing-no-positions/20-int-literal-6.good.expected new file mode 100644 index 0000000..eb881b8 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/20-int-literal-6.good.expected @@ -0,0 +1 @@ +let x = 2739128 diff --git a/flap/tests/01-Parsing-no-positions/20-int-literal-6.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/20-int-literal-6.good.parsing-no-positions.hopix new file mode 100644 index 0000000..b6c9ea2 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/20-int-literal-6.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = 0o12345670 \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/21-char-literal-1.bad.expected b/flap/tests/01-Parsing-no-positions/21-char-literal-1.bad.expected new file mode 100644 index 0000000..ba85cad --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/21-char-literal-1.bad.expected @@ -0,0 +1,2 @@ +Error (during lexing) + unexpected character. diff --git a/flap/tests/01-Parsing-no-positions/21-char-literal-1.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/21-char-literal-1.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..759a1e2 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/21-char-literal-1.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let c = '' \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/21-char-literal-1.good.expected b/flap/tests/01-Parsing-no-positions/21-char-literal-1.good.expected new file mode 100644 index 0000000..360f4d9 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/21-char-literal-1.good.expected @@ -0,0 +1 @@ +let c = 'a' diff --git a/flap/tests/01-Parsing-no-positions/21-char-literal-1.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/21-char-literal-1.good.parsing-no-positions.hopix new file mode 100644 index 0000000..67e678f --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/21-char-literal-1.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let c = 'a' \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/22-char-literal-2.bad.expected b/flap/tests/01-Parsing-no-positions/22-char-literal-2.bad.expected new file mode 100644 index 0000000..903fcc0 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/22-char-literal-2.bad.expected @@ -0,0 +1,2 @@ +Error (during lexing) + diff --git a/flap/tests/01-Parsing-no-positions/22-char-literal-2.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/22-char-literal-2.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..16c9114 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/22-char-literal-2.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = '\300' \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/22-char-literal-2.good.expected b/flap/tests/01-Parsing-no-positions/22-char-literal-2.good.expected new file mode 100644 index 0000000..c8065bf --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/22-char-literal-2.good.expected @@ -0,0 +1 @@ +let x = '\000' diff --git a/flap/tests/01-Parsing-no-positions/22-char-literal-2.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/22-char-literal-2.good.parsing-no-positions.hopix new file mode 100644 index 0000000..a3c8be5 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/22-char-literal-2.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = '\000' \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/23-char-literal-3.bad.expected b/flap/tests/01-Parsing-no-positions/23-char-literal-3.bad.expected new file mode 100644 index 0000000..ba85cad --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/23-char-literal-3.bad.expected @@ -0,0 +1,2 @@ +Error (during lexing) + unexpected character. diff --git a/flap/tests/01-Parsing-no-positions/23-char-literal-3.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/23-char-literal-3.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..00c0ac7 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/23-char-literal-3.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = '\p' \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/23-char-literal-3.good.expected b/flap/tests/01-Parsing-no-positions/23-char-literal-3.good.expected new file mode 100644 index 0000000..6fe8a65 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/23-char-literal-3.good.expected @@ -0,0 +1 @@ +let x = '\t' diff --git a/flap/tests/01-Parsing-no-positions/23-char-literal-3.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/23-char-literal-3.good.parsing-no-positions.hopix new file mode 100644 index 0000000..0219bf7 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/23-char-literal-3.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = '\t' \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/24-char-literal-4.bad.expected b/flap/tests/01-Parsing-no-positions/24-char-literal-4.bad.expected new file mode 100644 index 0000000..ba85cad --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/24-char-literal-4.bad.expected @@ -0,0 +1,2 @@ +Error (during lexing) + unexpected character. diff --git a/flap/tests/01-Parsing-no-positions/24-char-literal-4.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/24-char-literal-4.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..ab197e1 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/24-char-literal-4.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = '\0z64' \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/24-char-literal-4.good.expected b/flap/tests/01-Parsing-no-positions/24-char-literal-4.good.expected new file mode 100644 index 0000000..b1302a0 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/24-char-literal-4.good.expected @@ -0,0 +1 @@ +let x = 'd' diff --git a/flap/tests/01-Parsing-no-positions/24-char-literal-4.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/24-char-literal-4.good.parsing-no-positions.hopix new file mode 100644 index 0000000..0119112 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/24-char-literal-4.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = '\0x64' \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/25-char-literal-5.bad.expected b/flap/tests/01-Parsing-no-positions/25-char-literal-5.bad.expected new file mode 100644 index 0000000..ba85cad --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/25-char-literal-5.bad.expected @@ -0,0 +1,2 @@ +Error (during lexing) + unexpected character. diff --git a/flap/tests/01-Parsing-no-positions/25-char-literal-5.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/25-char-literal-5.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..140d537 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/25-char-literal-5.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = ''' \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/25-char-literal-5.good.expected b/flap/tests/01-Parsing-no-positions/25-char-literal-5.good.expected new file mode 100644 index 0000000..14e2055 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/25-char-literal-5.good.expected @@ -0,0 +1 @@ +let x = '\'' diff --git a/flap/tests/01-Parsing-no-positions/25-char-literal-5.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/25-char-literal-5.good.parsing-no-positions.hopix new file mode 100644 index 0000000..8eb8b25 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/25-char-literal-5.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = '\'' \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/26-char-literal-6.bad.expected b/flap/tests/01-Parsing-no-positions/26-char-literal-6.bad.expected new file mode 100644 index 0000000..ba85cad --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/26-char-literal-6.bad.expected @@ -0,0 +1,2 @@ +Error (during lexing) + unexpected character. diff --git a/flap/tests/01-Parsing-no-positions/26-char-literal-6.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/26-char-literal-6.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..c8621f3 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/26-char-literal-6.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = '\\r' diff --git a/flap/tests/01-Parsing-no-positions/26-char-literal-6.good.expected b/flap/tests/01-Parsing-no-positions/26-char-literal-6.good.expected new file mode 100644 index 0000000..1e1287d --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/26-char-literal-6.good.expected @@ -0,0 +1,2 @@ +let x = '\r' +let y = '\b' diff --git a/flap/tests/01-Parsing-no-positions/26-char-literal-6.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/26-char-literal-6.good.parsing-no-positions.hopix new file mode 100644 index 0000000..d135541 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/26-char-literal-6.good.parsing-no-positions.hopix @@ -0,0 +1,2 @@ +let x = '\r' +let y = '\b' \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/27-string-literal-1.bad.expected b/flap/tests/01-Parsing-no-positions/27-string-literal-1.bad.expected new file mode 100644 index 0000000..f4ba87a --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/27-string-literal-1.bad.expected @@ -0,0 +1,2 @@ +Error (during lexing) + Unterminated string. diff --git a/flap/tests/01-Parsing-no-positions/27-string-literal-1.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/27-string-literal-1.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..d6a30bd --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/27-string-literal-1.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let s = " This is exciting. No, not exciting. What do I mean? Worrying. \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/27-string-literal-1.good.expected b/flap/tests/01-Parsing-no-positions/27-string-literal-1.good.expected new file mode 100644 index 0000000..ad1ac81 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/27-string-literal-1.good.expected @@ -0,0 +1,2 @@ +let s = + " This is exciting. No, not exciting. What do I mean? Worrying." diff --git a/flap/tests/01-Parsing-no-positions/27-string-literal-1.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/27-string-literal-1.good.parsing-no-positions.hopix new file mode 100644 index 0000000..0b8e3c9 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/27-string-literal-1.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let s = " This is exciting. No, not exciting. What do I mean? Worrying." \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/28-string-literal-2.bad.expected b/flap/tests/01-Parsing-no-positions/28-string-literal-2.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/28-string-literal-2.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/28-string-literal-2.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/28-string-literal-2.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..8ad0098 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/28-string-literal-2.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let s = "\nDon't "panic.\nNot the end of the world.\nWell, it could be the end of the world but one thing at a time.\n" \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/28-string-literal-2.good.expected b/flap/tests/01-Parsing-no-positions/28-string-literal-2.good.expected new file mode 100644 index 0000000..68e7d10 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/28-string-literal-2.good.expected @@ -0,0 +1,2 @@ +let s = + "\nDon't panic.\nNot the end of the world.\nWell, it could be the end of the world but one thing at a time.\n" diff --git a/flap/tests/01-Parsing-no-positions/28-string-literal-2.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/28-string-literal-2.good.parsing-no-positions.hopix new file mode 100644 index 0000000..6ea39ca --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/28-string-literal-2.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let s = "\nDon't panic.\nNot the end of the world.\nWell, it could be the end of the world but one thing at a time.\n" \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/29-string-literal-3.bad.expected b/flap/tests/01-Parsing-no-positions/29-string-literal-3.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/29-string-literal-3.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/29-string-literal-3.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/29-string-literal-3.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..6399964 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/29-string-literal-3.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let = "Python\b\b\b\b\b\bOCaml rocks!\n" \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/29-string-literal-3.good.expected b/flap/tests/01-Parsing-no-positions/29-string-literal-3.good.expected new file mode 100644 index 0000000..db9815b --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/29-string-literal-3.good.expected @@ -0,0 +1 @@ +let s = "Python\b\b\b\b\b\bOCaml rocks!\n" diff --git a/flap/tests/01-Parsing-no-positions/29-string-literal-3.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/29-string-literal-3.good.parsing-no-positions.hopix new file mode 100644 index 0000000..5c2d21f --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/29-string-literal-3.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let s = "Python\b\b\b\b\b\bOCaml rocks!\n" \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/30-string-literal-4.bad.expected b/flap/tests/01-Parsing-no-positions/30-string-literal-4.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/30-string-literal-4.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/30-string-literal-4.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/30-string-literal-4.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..da6c948 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/30-string-literal-4.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let s "This one is a \"Nightmare\"! \0x4A \\ \r \0x2e ' \032" \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/30-string-literal-4.good.expected b/flap/tests/01-Parsing-no-positions/30-string-literal-4.good.expected new file mode 100644 index 0000000..bd63144 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/30-string-literal-4.good.expected @@ -0,0 +1 @@ +let s = "This one is a \"Nightmare\"! J \\ \r . ' " diff --git a/flap/tests/01-Parsing-no-positions/30-string-literal-4.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/30-string-literal-4.good.parsing-no-positions.hopix new file mode 100644 index 0000000..e438ccd --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/30-string-literal-4.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let s = "This one is a \"Nightmare\"! \0x4A \\ \r \0x2e ' \032" \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/31-type-definition-sum-1.bad.expected b/flap/tests/01-Parsing-no-positions/31-type-definition-sum-1.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/31-type-definition-sum-1.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/31-type-definition-sum-1.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/31-type-definition-sum-1.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..7e3bde7 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/31-type-definition-sum-1.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +type unit = \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/31-type-definition-sum-1.good.expected b/flap/tests/01-Parsing-no-positions/31-type-definition-sum-1.good.expected new file mode 100644 index 0000000..5d00f0b --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/31-type-definition-sum-1.good.expected @@ -0,0 +1 @@ +type unit = Unit diff --git a/flap/tests/01-Parsing-no-positions/31-type-definition-sum-1.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/31-type-definition-sum-1.good.parsing-no-positions.hopix new file mode 100644 index 0000000..9922db8 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/31-type-definition-sum-1.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +type unit = Unit \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/32-type-definition-sum-2.bad.expected b/flap/tests/01-Parsing-no-positions/32-type-definition-sum-2.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/32-type-definition-sum-2.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/32-type-definition-sum-2.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/32-type-definition-sum-2.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..c9c8605 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/32-type-definition-sum-2.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +type color = Red | Black | \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/32-type-definition-sum-2.good.expected b/flap/tests/01-Parsing-no-positions/32-type-definition-sum-2.good.expected new file mode 100644 index 0000000..15f2c38 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/32-type-definition-sum-2.good.expected @@ -0,0 +1 @@ +type color = Red | Black | White diff --git a/flap/tests/01-Parsing-no-positions/32-type-definition-sum-2.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/32-type-definition-sum-2.good.parsing-no-positions.hopix new file mode 100644 index 0000000..a649e91 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/32-type-definition-sum-2.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +type color = Red | Black | White \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/33-type-definition-sum-3.bad.expected b/flap/tests/01-Parsing-no-positions/33-type-definition-sum-3.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/33-type-definition-sum-3.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/33-type-definition-sum-3.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/33-type-definition-sum-3.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..2147b71 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/33-type-definition-sum-3.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +type option = None | Some (A) \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/33-type-definition-sum-3.good.expected b/flap/tests/01-Parsing-no-positions/33-type-definition-sum-3.good.expected new file mode 100644 index 0000000..90669ff --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/33-type-definition-sum-3.good.expected @@ -0,0 +1 @@ +type option<`a> = None | Some (`a) diff --git a/flap/tests/01-Parsing-no-positions/33-type-definition-sum-3.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/33-type-definition-sum-3.good.parsing-no-positions.hopix new file mode 100644 index 0000000..7cfdbe6 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/33-type-definition-sum-3.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +type option<`a> = None | Some (`a) \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/34-type-definition-sum-4.bad.expected b/flap/tests/01-Parsing-no-positions/34-type-definition-sum-4.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/34-type-definition-sum-4.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/34-type-definition-sum-4.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/34-type-definition-sum-4.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..7d90d94 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/34-type-definition-sum-4.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +type pair<`a `b> = Pair(`a, `b) \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/34-type-definition-sum-4.good.expected b/flap/tests/01-Parsing-no-positions/34-type-definition-sum-4.good.expected new file mode 100644 index 0000000..44ce62c --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/34-type-definition-sum-4.good.expected @@ -0,0 +1 @@ +type pair<`a, `b> = Pair (`a, `b) diff --git a/flap/tests/01-Parsing-no-positions/34-type-definition-sum-4.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/34-type-definition-sum-4.good.parsing-no-positions.hopix new file mode 100644 index 0000000..7c8b5e9 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/34-type-definition-sum-4.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +type pair<`a, `b> = Pair(`a, `b) \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/35-type-definition-sum-5.bad.expected b/flap/tests/01-Parsing-no-positions/35-type-definition-sum-5.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/35-type-definition-sum-5.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/35-type-definition-sum-5.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/35-type-definition-sum-5.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..504e69f --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/35-type-definition-sum-5.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +type triple<`a, `b, > = Triple (`a, `b, `c) \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/35-type-definition-sum-5.good.expected b/flap/tests/01-Parsing-no-positions/35-type-definition-sum-5.good.expected new file mode 100644 index 0000000..de8c33a --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/35-type-definition-sum-5.good.expected @@ -0,0 +1 @@ +type triple<`a, `b, `c> = Triple (`a, `b, `c) diff --git a/flap/tests/01-Parsing-no-positions/35-type-definition-sum-5.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/35-type-definition-sum-5.good.parsing-no-positions.hopix new file mode 100644 index 0000000..2900644 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/35-type-definition-sum-5.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +type triple<`a, `b, `c> = Triple (`a, `b, `c) \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/36-type-definition-sum-6.bad.expected b/flap/tests/01-Parsing-no-positions/36-type-definition-sum-6.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/36-type-definition-sum-6.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/36-type-definition-sum-6.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/36-type-definition-sum-6.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..a26d526 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/36-type-definition-sum-6.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +type list[`a] = Nil | Cons (`a, list[`a]) \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/36-type-definition-sum-6.good.expected b/flap/tests/01-Parsing-no-positions/36-type-definition-sum-6.good.expected new file mode 100644 index 0000000..def13b9 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/36-type-definition-sum-6.good.expected @@ -0,0 +1 @@ +type list<`a> = Nil | Cons (`a, list<`a>) diff --git a/flap/tests/01-Parsing-no-positions/36-type-definition-sum-6.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/36-type-definition-sum-6.good.parsing-no-positions.hopix new file mode 100644 index 0000000..594b113 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/36-type-definition-sum-6.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +type list<`a> = Nil | Cons (`a, list<`a>) \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/37-type-definition-sum-7.bad.expected b/flap/tests/01-Parsing-no-positions/37-type-definition-sum-7.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/37-type-definition-sum-7.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/37-type-definition-sum-7.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/37-type-definition-sum-7.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..4b5f962 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/37-type-definition-sum-7.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +type closure<`env, `a, `b> = Closure (`env, `env => `a => `b) \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/37-type-definition-sum-7.good.expected b/flap/tests/01-Parsing-no-positions/37-type-definition-sum-7.good.expected new file mode 100644 index 0000000..ad7fc89 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/37-type-definition-sum-7.good.expected @@ -0,0 +1,3 @@ +type closure<`env, `a, `b> = + + Closure (`env, `env -> (`a -> `b)) diff --git a/flap/tests/01-Parsing-no-positions/37-type-definition-sum-7.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/37-type-definition-sum-7.good.parsing-no-positions.hopix new file mode 100644 index 0000000..d0551dd --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/37-type-definition-sum-7.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +type closure<`env, `a, `b> = Closure (`env, `env -> `a -> `b) \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/38-type-definition-record-1.bad.expected b/flap/tests/01-Parsing-no-positions/38-type-definition-record-1.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/38-type-definition-record-1.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/38-type-definition-record-1.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/38-type-definition-record-1.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..6fd7bd8 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/38-type-definition-record-1.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +type people = { age : int; name : string; firstname : string } \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/38-type-definition-record-1.good.expected b/flap/tests/01-Parsing-no-positions/38-type-definition-record-1.good.expected new file mode 100644 index 0000000..21433bf --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/38-type-definition-record-1.good.expected @@ -0,0 +1,3 @@ +type people = + { + age : int , name : string , firstname : string } diff --git a/flap/tests/01-Parsing-no-positions/38-type-definition-record-1.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/38-type-definition-record-1.good.parsing-no-positions.hopix new file mode 100644 index 0000000..63cebd7 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/38-type-definition-record-1.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +type people = { age : int, name : string, firstname : string } \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/39-type-definition-record-2.bad.expected b/flap/tests/01-Parsing-no-positions/39-type-definition-record-2.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/39-type-definition-record-2.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/39-type-definition-record-2.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/39-type-definition-record-2.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..995aff8 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/39-type-definition-record-2.bad.parsing-no-positions.hopix @@ -0,0 +1,2 @@ +type position = { offset : int } +type located<`a> = { value = `a, position = position } \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/39-type-definition-record-2.good.expected b/flap/tests/01-Parsing-no-positions/39-type-definition-record-2.good.expected new file mode 100644 index 0000000..8d9fb7d --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/39-type-definition-record-2.good.expected @@ -0,0 +1,6 @@ +type position = + { + offset : int } +type located<`a> = + { + value : `a , position : position } diff --git a/flap/tests/01-Parsing-no-positions/39-type-definition-record-2.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/39-type-definition-record-2.good.parsing-no-positions.hopix new file mode 100644 index 0000000..509f588 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/39-type-definition-record-2.good.parsing-no-positions.hopix @@ -0,0 +1,2 @@ +type position = { offset : int } +type located<`a> = { value : `a, position : position } \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/40-type-definition-record-3.bad.expected b/flap/tests/01-Parsing-no-positions/40-type-definition-record-3.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/40-type-definition-record-3.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/40-type-definition-record-3.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/40-type-definition-record-3.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..f3ff3ce --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/40-type-definition-record-3.bad.parsing-no-positions.hopix @@ -0,0 +1,8 @@ +type bool = True | False + +type collection<`t, `a> = { + empty : `t; + add : `a * `t -> `t; + map : (`a -> `a) -> `t -> `t; + split : (`a -> bool) -> `t * `t +} \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/40-type-definition-record-3.good.expected b/flap/tests/01-Parsing-no-positions/40-type-definition-record-3.good.expected new file mode 100644 index 0000000..2f0b7a4 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/40-type-definition-record-3.good.expected @@ -0,0 +1,10 @@ +type bool = + + True | False +type collection<`t, `a> = + { + empty : `t + , add : (`a * `t) -> `t + , map : (`a -> `a) -> (`t -> `t) + , split : (`a -> bool) -> (`t * `t) + } diff --git a/flap/tests/01-Parsing-no-positions/40-type-definition-record-3.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/40-type-definition-record-3.good.parsing-no-positions.hopix new file mode 100644 index 0000000..c8cc117 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/40-type-definition-record-3.good.parsing-no-positions.hopix @@ -0,0 +1,8 @@ +type bool = True | False + +type collection<`t, `a> = { + empty : `t, + add : `a * `t -> `t, + map : (`a -> `a) -> `t -> `t, + split : (`a -> bool) -> `t * `t +} \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/41-external-definition-1.bad.expected b/flap/tests/01-Parsing-no-positions/41-external-definition-1.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/41-external-definition-1.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/41-external-definition-1.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/41-external-definition-1.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..104250c --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/41-external-definition-1.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +extern print_string : string -> \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/41-external-definition-1.good.expected b/flap/tests/01-Parsing-no-positions/41-external-definition-1.good.expected new file mode 100644 index 0000000..495739e --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/41-external-definition-1.good.expected @@ -0,0 +1 @@ +extern print_string : string -> unit diff --git a/flap/tests/01-Parsing-no-positions/41-external-definition-1.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/41-external-definition-1.good.parsing-no-positions.hopix new file mode 100644 index 0000000..81f286a --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/41-external-definition-1.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +extern print_string : string -> unit \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/42-external-definition-2.good.expected b/flap/tests/01-Parsing-no-positions/42-external-definition-2.good.expected new file mode 100644 index 0000000..f8d6dec --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/42-external-definition-2.good.expected @@ -0,0 +1 @@ +extern concat : [`a](list<`a> * list<`a>) -> list<`a> diff --git a/flap/tests/01-Parsing-no-positions/42-external-definition-2.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/42-external-definition-2.good.parsing-no-positions.hopix new file mode 100644 index 0000000..44ec99d --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/42-external-definition-2.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +extern concat : [`a] list<`a> * list<`a> -> list<`a> \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/43-external-definition-3.bad.expected b/flap/tests/01-Parsing-no-positions/43-external-definition-3.bad.expected new file mode 100644 index 0000000..9e54c9b --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/43-external-definition-3.bad.expected @@ -0,0 +1 @@ +extern superman : [`a, `b]`a -> `b diff --git a/flap/tests/01-Parsing-no-positions/43-external-definition-3.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/43-external-definition-3.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..071cf9a --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/43-external-definition-3.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +extern superman : [`a, `b] `a -> `b \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/43-external-definition-3.good.expected b/flap/tests/01-Parsing-no-positions/43-external-definition-3.good.expected new file mode 100644 index 0000000..9e54c9b --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/43-external-definition-3.good.expected @@ -0,0 +1 @@ +extern superman : [`a, `b]`a -> `b diff --git a/flap/tests/01-Parsing-no-positions/43-external-definition-3.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/43-external-definition-3.good.parsing-no-positions.hopix new file mode 100644 index 0000000..57a925b --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/43-external-definition-3.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +extern superman : [`a, `b] `a -> `b diff --git a/flap/tests/01-Parsing-no-positions/44-value-definition-1.bad.expected b/flap/tests/01-Parsing-no-positions/44-value-definition-1.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/44-value-definition-1.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/44-value-definition-1.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/44-value-definition-1.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..0d7a029 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/44-value-definition-1.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +val x = 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/44-value-definition-1.good.expected b/flap/tests/01-Parsing-no-positions/44-value-definition-1.good.expected new file mode 100644 index 0000000..b6a2459 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/44-value-definition-1.good.expected @@ -0,0 +1 @@ +let x = 0 diff --git a/flap/tests/01-Parsing-no-positions/44-value-definition-1.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/44-value-definition-1.good.parsing-no-positions.hopix new file mode 100644 index 0000000..b5368df --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/44-value-definition-1.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/45-value-definition-2.bad.expected b/flap/tests/01-Parsing-no-positions/45-value-definition-2.bad.expected new file mode 100644 index 0000000..ba85cad --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/45-value-definition-2.bad.expected @@ -0,0 +1,2 @@ +Error (during lexing) + unexpected character. diff --git a/flap/tests/01-Parsing-no-positions/45-value-definition-2.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/45-value-definition-2.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..7f03d2a --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/45-value-definition-2.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let inconsistency : [`a] ``a = 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/45-value-definition-2.good.expected b/flap/tests/01-Parsing-no-positions/45-value-definition-2.good.expected new file mode 100644 index 0000000..6ace6e5 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/45-value-definition-2.good.expected @@ -0,0 +1 @@ +let inconsistency : [`a]a = 0 diff --git a/flap/tests/01-Parsing-no-positions/45-value-definition-2.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/45-value-definition-2.good.parsing-no-positions.hopix new file mode 100644 index 0000000..129ff94 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/45-value-definition-2.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let inconsistency : [`a] a = 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/46-value-definition-3.bad.expected b/flap/tests/01-Parsing-no-positions/46-value-definition-3.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/46-value-definition-3.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/46-value-definition-3.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/46-value-definition-3.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..975d410 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/46-value-definition-3.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let minux = \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/46-value-definition-3.good.expected b/flap/tests/01-Parsing-no-positions/46-value-definition-3.good.expected new file mode 100644 index 0000000..9c5ae48 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/46-value-definition-3.good.expected @@ -0,0 +1 @@ +let minux = 0 diff --git a/flap/tests/01-Parsing-no-positions/46-value-definition-3.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/46-value-definition-3.good.parsing-no-positions.hopix new file mode 100644 index 0000000..826d210 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/46-value-definition-3.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let minux = 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/47-instanciation.bad.expected b/flap/tests/01-Parsing-no-positions/47-instanciation.bad.expected new file mode 100644 index 0000000..07b9b49 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/47-instanciation.bad.expected @@ -0,0 +1 @@ +let x = id < > diff --git a/flap/tests/01-Parsing-no-positions/47-instanciation.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/47-instanciation.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..be28a47 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/47-instanciation.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = id<> \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/47-instanciation.good.expected b/flap/tests/01-Parsing-no-positions/47-instanciation.good.expected new file mode 100644 index 0000000..74a9ed1 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/47-instanciation.good.expected @@ -0,0 +1 @@ +let x = id < `a > diff --git a/flap/tests/01-Parsing-no-positions/47-instanciation.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/47-instanciation.good.parsing-no-positions.hopix new file mode 100644 index 0000000..a8ca18a --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/47-instanciation.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = id<`a> \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/48-instanciation-2.bad.expected b/flap/tests/01-Parsing-no-positions/48-instanciation-2.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/48-instanciation-2.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/48-instanciation-2.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/48-instanciation-2.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..161f439 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/48-instanciation-2.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = plus \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/48-instanciation-2.good.expected b/flap/tests/01-Parsing-no-positions/48-instanciation-2.good.expected new file mode 100644 index 0000000..79c6570 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/48-instanciation-2.good.expected @@ -0,0 +1 @@ +let x = plus < int > diff --git a/flap/tests/01-Parsing-no-positions/48-instanciation-2.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/48-instanciation-2.good.parsing-no-positions.hopix new file mode 100644 index 0000000..c4723e9 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/48-instanciation-2.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = plus \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/49-instanciation-3.bad.expected b/flap/tests/01-Parsing-no-positions/49-instanciation-3.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/49-instanciation-3.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/49-instanciation-3.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/49-instanciation-3.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..baa4b41 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/49-instanciation-3.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = concat \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/49-instanciation-3.good.expected b/flap/tests/01-Parsing-no-positions/49-instanciation-3.good.expected new file mode 100644 index 0000000..d5badae --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/49-instanciation-3.good.expected @@ -0,0 +1 @@ +let x = concat < int > diff --git a/flap/tests/01-Parsing-no-positions/49-instanciation-3.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/49-instanciation-3.good.parsing-no-positions.hopix new file mode 100644 index 0000000..a293bb4 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/49-instanciation-3.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = concat \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/50-instanciation-4.bad.expected b/flap/tests/01-Parsing-no-positions/50-instanciation-4.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/50-instanciation-4.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/50-instanciation-4.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/50-instanciation-4.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..8fd6b88 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/50-instanciation-4.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = id int> \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/50-instanciation-4.good.expected b/flap/tests/01-Parsing-no-positions/50-instanciation-4.good.expected new file mode 100644 index 0000000..bf6c773 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/50-instanciation-4.good.expected @@ -0,0 +1 @@ +let x = id < (int -> int) > diff --git a/flap/tests/01-Parsing-no-positions/50-instanciation-4.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/50-instanciation-4.good.parsing-no-positions.hopix new file mode 100644 index 0000000..45e51b4 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/50-instanciation-4.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = id int> \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/51-instanciation-5.bad.expected b/flap/tests/01-Parsing-no-positions/51-instanciation-5.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/51-instanciation-5.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/51-instanciation-5.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/51-instanciation-5.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..48cbfed --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/51-instanciation-5.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = map \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/51-instanciation-5.good.expected b/flap/tests/01-Parsing-no-positions/51-instanciation-5.good.expected new file mode 100644 index 0000000..92b60b1 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/51-instanciation-5.good.expected @@ -0,0 +1 @@ +let x = map < int, string > diff --git a/flap/tests/01-Parsing-no-positions/51-instanciation-5.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/51-instanciation-5.good.parsing-no-positions.hopix new file mode 100644 index 0000000..ff7877a --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/51-instanciation-5.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = map \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/52-instanciation-6.bad.expected b/flap/tests/01-Parsing-no-positions/52-instanciation-6.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/52-instanciation-6.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/52-instanciation-6.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/52-instanciation-6.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..c1805d3 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/52-instanciation-6.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = map int> \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/52-instanciation-6.good.expected b/flap/tests/01-Parsing-no-positions/52-instanciation-6.good.expected new file mode 100644 index 0000000..a18eb74 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/52-instanciation-6.good.expected @@ -0,0 +1 @@ +let x = map < int, (int -> int) > diff --git a/flap/tests/01-Parsing-no-positions/52-instanciation-6.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/52-instanciation-6.good.parsing-no-positions.hopix new file mode 100644 index 0000000..d78c12c --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/52-instanciation-6.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = map int> \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/53-instanciation-7.bad.expected b/flap/tests/01-Parsing-no-positions/53-instanciation-7.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/53-instanciation-7.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/53-instanciation-7.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/53-instanciation-7.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..f884439 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/53-instanciation-7.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = map \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/53-instanciation-7.good.expected b/flap/tests/01-Parsing-no-positions/53-instanciation-7.good.expected new file mode 100644 index 0000000..f9c09db --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/53-instanciation-7.good.expected @@ -0,0 +1 @@ +let x = map < list, (int * int * int) > diff --git a/flap/tests/01-Parsing-no-positions/53-instanciation-7.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/53-instanciation-7.good.parsing-no-positions.hopix new file mode 100644 index 0000000..a69401a --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/53-instanciation-7.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = map , int * int * int> \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/54-constructor-1.bad.expected b/flap/tests/01-Parsing-no-positions/54-constructor-1.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/54-constructor-1.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/54-constructor-1.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/54-constructor-1.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..7dd252c --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/54-constructor-1.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = [True] \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/54-constructor-1.good.expected b/flap/tests/01-Parsing-no-positions/54-constructor-1.good.expected new file mode 100644 index 0000000..f4c4941 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/54-constructor-1.good.expected @@ -0,0 +1 @@ +let x = True diff --git a/flap/tests/01-Parsing-no-positions/54-constructor-1.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/54-constructor-1.good.parsing-no-positions.hopix new file mode 100644 index 0000000..467de38 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/54-constructor-1.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = True \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/55-constructor-2.bad.expected b/flap/tests/01-Parsing-no-positions/55-constructor-2.bad.expected new file mode 100644 index 0000000..10e168b --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/55-constructor-2.bad.expected @@ -0,0 +1 @@ +let y = Cons < >(0, Nil < int >) diff --git a/flap/tests/01-Parsing-no-positions/55-constructor-2.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/55-constructor-2.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..9fdf354 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/55-constructor-2.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let y = Cons <> (0, Nil) \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/55-constructor-2.good.expected b/flap/tests/01-Parsing-no-positions/55-constructor-2.good.expected new file mode 100644 index 0000000..24c7f05 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/55-constructor-2.good.expected @@ -0,0 +1 @@ +let y = Cons < int >(0, Nil < int >) diff --git a/flap/tests/01-Parsing-no-positions/55-constructor-2.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/55-constructor-2.good.parsing-no-positions.hopix new file mode 100644 index 0000000..d3b41b1 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/55-constructor-2.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let y = Cons (0, Nil) \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/56-constructor-3.bad.expected b/flap/tests/01-Parsing-no-positions/56-constructor-3.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/56-constructor-3.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/56-constructor-3.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/56-constructor-3.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..0b48d33 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/56-constructor-3.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = pair, string> (Pair (0, "Wou!"), "Wouha!") \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/56-constructor-3.good.expected b/flap/tests/01-Parsing-no-positions/56-constructor-3.good.expected new file mode 100644 index 0000000..ed12096 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/56-constructor-3.good.expected @@ -0,0 +1,6 @@ +let x = + pair < + pair, + string + > + (Pair < int, string >(0, "Wou!"), "Wouha!") diff --git a/flap/tests/01-Parsing-no-positions/56-constructor-3.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/56-constructor-3.good.parsing-no-positions.hopix new file mode 100644 index 0000000..f893180 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/56-constructor-3.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = pair, string> (Pair (0, "Wou!"), "Wouha!") \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/57-constructor-4.bad.expected b/flap/tests/01-Parsing-no-positions/57-constructor-4.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/57-constructor-4.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/57-constructor-4.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/57-constructor-4.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..1224b80 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/57-constructor-4.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let some = Some () \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/57-constructor-4.good.expected b/flap/tests/01-Parsing-no-positions/57-constructor-4.good.expected new file mode 100644 index 0000000..206fc71 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/57-constructor-4.good.expected @@ -0,0 +1 @@ +let some = Some < int >(73) diff --git a/flap/tests/01-Parsing-no-positions/57-constructor-4.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/57-constructor-4.good.parsing-no-positions.hopix new file mode 100644 index 0000000..463220d --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/57-constructor-4.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let some = Some (73) \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/58-record-1.bad.expected b/flap/tests/01-Parsing-no-positions/58-record-1.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/58-record-1.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/58-record-1.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/58-record-1.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..8019d13 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/58-record-1.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let start = { x = 0, } \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/58-record-1.good.expected b/flap/tests/01-Parsing-no-positions/58-record-1.good.expected new file mode 100644 index 0000000..9d33b7a --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/58-record-1.good.expected @@ -0,0 +1 @@ +let start = {x = 0, y = 0} diff --git a/flap/tests/01-Parsing-no-positions/58-record-1.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/58-record-1.good.parsing-no-positions.hopix new file mode 100644 index 0000000..371210d --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/58-record-1.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let start = { x = 0, y = 0 } \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/59-record-2.bad.expected b/flap/tests/01-Parsing-no-positions/59-record-2.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/59-record-2.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/59-record-2.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/59-record-2.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..66f50a1 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/59-record-2.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let name = { fst = "My"; snd = "Precious" } \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/59-record-2.good.expected b/flap/tests/01-Parsing-no-positions/59-record-2.good.expected new file mode 100644 index 0000000..c6cc5bc --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/59-record-2.good.expected @@ -0,0 +1 @@ +let name = {fst = "My", snd = "Precious"} < string, string > diff --git a/flap/tests/01-Parsing-no-positions/59-record-2.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/59-record-2.good.parsing-no-positions.hopix new file mode 100644 index 0000000..4a41cda --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/59-record-2.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let name = { fst = "My", snd = "Precious" } \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/60-record-3.bad.expected b/flap/tests/01-Parsing-no-positions/60-record-3.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/60-record-3.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/60-record-3.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/60-record-3.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..beaab28 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/60-record-3.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let what_s_in_the_box = { box = } \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/60-record-3.good.expected b/flap/tests/01-Parsing-no-positions/60-record-3.good.expected new file mode 100644 index 0000000..0d6a46b --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/60-record-3.good.expected @@ -0,0 +1 @@ +let what_s_in_the_box = {box = "Mystery"} diff --git a/flap/tests/01-Parsing-no-positions/60-record-3.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/60-record-3.good.parsing-no-positions.hopix new file mode 100644 index 0000000..1788ead --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/60-record-3.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let what_s_in_the_box = { box = "Mystery" } \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/61-record-projection-1.bad.expected b/flap/tests/01-Parsing-no-positions/61-record-projection-1.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/61-record-projection-1.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/61-record-projection-1.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/61-record-projection-1.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..905b5ca --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/61-record-projection-1.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = p.X \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/61-record-projection-1.good.expected b/flap/tests/01-Parsing-no-positions/61-record-projection-1.good.expected new file mode 100644 index 0000000..751a65c --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/61-record-projection-1.good.expected @@ -0,0 +1 @@ +let x = p.x diff --git a/flap/tests/01-Parsing-no-positions/61-record-projection-1.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/61-record-projection-1.good.parsing-no-positions.hopix new file mode 100644 index 0000000..3baf2d6 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/61-record-projection-1.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = p.x \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/62-record-projection-2.bad.expected b/flap/tests/01-Parsing-no-positions/62-record-projection-2.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/62-record-projection-2.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/62-record-projection-2.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/62-record-projection-2.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..976e15c --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/62-record-projection-2.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let y = { x = 0, y = 1 }. \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/62-record-projection-2.good.expected b/flap/tests/01-Parsing-no-positions/62-record-projection-2.good.expected new file mode 100644 index 0000000..24e31d1 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/62-record-projection-2.good.expected @@ -0,0 +1 @@ +let y = {x = 0, y = 1}.y diff --git a/flap/tests/01-Parsing-no-positions/62-record-projection-2.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/62-record-projection-2.good.parsing-no-positions.hopix new file mode 100644 index 0000000..eeb4149 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/62-record-projection-2.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let y = { x = 0, y = 1 }.y \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/63-record-projection-3.bad.expected b/flap/tests/01-Parsing-no-positions/63-record-projection-3.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/63-record-projection-3.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/63-record-projection-3.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/63-record-projection-3.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..d6dfa9e --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/63-record-projection-3.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let you_silly_boy = "I am not a record".33 \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/63-record-projection-3.good.expected b/flap/tests/01-Parsing-no-positions/63-record-projection-3.good.expected new file mode 100644 index 0000000..c63de02 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/63-record-projection-3.good.expected @@ -0,0 +1 @@ +let you_silly_boy = "I am not a record".song diff --git a/flap/tests/01-Parsing-no-positions/63-record-projection-3.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/63-record-projection-3.good.parsing-no-positions.hopix new file mode 100644 index 0000000..a923d3d --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/63-record-projection-3.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let you_silly_boy = "I am not a record".song \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/65-sequence-1.bad.expected b/flap/tests/01-Parsing-no-positions/65-sequence-1.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/65-sequence-1.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/65-sequence-1.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/65-sequence-1.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..585c105 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/65-sequence-1.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = sing (0); eat (0); drink (0); song ( \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/65-sequence-1.good.expected b/flap/tests/01-Parsing-no-positions/65-sequence-1.good.expected new file mode 100644 index 0000000..d895c09 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/65-sequence-1.good.expected @@ -0,0 +1 @@ +let x = (sing 0); ((eat 0); ((drink 0); (song 0))) diff --git a/flap/tests/01-Parsing-no-positions/65-sequence-1.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/65-sequence-1.good.parsing-no-positions.hopix new file mode 100644 index 0000000..1d991f5 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/65-sequence-1.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = sing (0); eat (0); drink (0); song (0) \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/66-sequence-2.bad.expected b/flap/tests/01-Parsing-no-positions/66-sequence-2.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/66-sequence-2.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/66-sequence-2.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/66-sequence-2.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..1f926c2 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/66-sequence-2.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = (foo (0); bar (0)); baz (0)) \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/66-sequence-2.good.expected b/flap/tests/01-Parsing-no-positions/66-sequence-2.good.expected new file mode 100644 index 0000000..2ce0a5a --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/66-sequence-2.good.expected @@ -0,0 +1 @@ +let x = ((foo 0); (bar 0)); (baz 0) diff --git a/flap/tests/01-Parsing-no-positions/66-sequence-2.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/66-sequence-2.good.parsing-no-positions.hopix new file mode 100644 index 0000000..cd7e8a3 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/66-sequence-2.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = (foo (0); bar (0)); baz (0) \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/67-sequence-3.bad.expected b/flap/tests/01-Parsing-no-positions/67-sequence-3.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/67-sequence-3.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/67-sequence-3.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/67-sequence-3.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..b530fc5 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/67-sequence-3.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +val x = foo (0); (bar (0); baz (0)) \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/67-sequence-3.good.expected b/flap/tests/01-Parsing-no-positions/67-sequence-3.good.expected new file mode 100644 index 0000000..7c916e0 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/67-sequence-3.good.expected @@ -0,0 +1 @@ +let x = (foo 0); ((bar 0); (baz 0)) diff --git a/flap/tests/01-Parsing-no-positions/67-sequence-3.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/67-sequence-3.good.parsing-no-positions.hopix new file mode 100644 index 0000000..e3a046f --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/67-sequence-3.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = foo (0); (bar (0); baz (0)) \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/68-local-definition.bad.expected b/flap/tests/01-Parsing-no-positions/68-local-definition.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/68-local-definition.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/68-local-definition.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/68-local-definition.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..5f0dccd --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/68-local-definition.bad.parsing-no-positions.hopix @@ -0,0 +1,3 @@ +let main = + let x = 0;; + x \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/68-local-definition.good.expected b/flap/tests/01-Parsing-no-positions/68-local-definition.good.expected new file mode 100644 index 0000000..6595b9c --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/68-local-definition.good.expected @@ -0,0 +1 @@ +let main = let x = 0 ; x diff --git a/flap/tests/01-Parsing-no-positions/68-local-definition.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/68-local-definition.good.parsing-no-positions.hopix new file mode 100644 index 0000000..f463924 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/68-local-definition.good.parsing-no-positions.hopix @@ -0,0 +1,3 @@ +let main = + let x = 0; + x \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/69-local-definition-2.bad.expected b/flap/tests/01-Parsing-no-positions/69-local-definition-2.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/69-local-definition-2.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/69-local-definition-2.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/69-local-definition-2.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..23a0f68 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/69-local-definition-2.bad.parsing-no-positions.hopix @@ -0,0 +1,6 @@ +let main = + let me = 0 + let you = 0; + play me; + play you; + you \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/69-local-definition-2.good.expected b/flap/tests/01-Parsing-no-positions/69-local-definition-2.good.expected new file mode 100644 index 0000000..1afc20c --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/69-local-definition-2.good.expected @@ -0,0 +1,2 @@ +let main = + let me = 0 ; let you = 0 ; (play me); ((play you); you) diff --git a/flap/tests/01-Parsing-no-positions/69-local-definition-2.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/69-local-definition-2.good.parsing-no-positions.hopix new file mode 100644 index 0000000..5ad647a --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/69-local-definition-2.good.parsing-no-positions.hopix @@ -0,0 +1,6 @@ +let main = + let me = 0; + let you = 0; + play me; + play you; + you \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/70-local-definition-3.bad.expected b/flap/tests/01-Parsing-no-positions/70-local-definition-3.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/70-local-definition-3.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/70-local-definition-3.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/70-local-definition-3.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..352105d --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/70-local-definition-3.bad.parsing-no-positions.hopix @@ -0,0 +1,2 @@ +let main = + fun f x = x; diff --git a/flap/tests/01-Parsing-no-positions/70-local-definition-3.good.expected b/flap/tests/01-Parsing-no-positions/70-local-definition-3.good.expected new file mode 100644 index 0000000..5bfa63d --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/70-local-definition-3.good.expected @@ -0,0 +1 @@ +let main = fun f x = x ; f 0 diff --git a/flap/tests/01-Parsing-no-positions/70-local-definition-3.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/70-local-definition-3.good.parsing-no-positions.hopix new file mode 100644 index 0000000..aba7a12 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/70-local-definition-3.good.parsing-no-positions.hopix @@ -0,0 +1,3 @@ +let main = + fun f x = x; + f 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/71-local-definition-4.bad.expected b/flap/tests/01-Parsing-no-positions/71-local-definition-4.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/71-local-definition-4.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/71-local-definition-4.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/71-local-definition-4.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..8847cf2 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/71-local-definition-4.bad.parsing-no-positions.hopix @@ -0,0 +1,4 @@ +let main = + fun ping _ = pong 0 + or pong _ = ping 0; + ping 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/71-local-definition-4.good.expected b/flap/tests/01-Parsing-no-positions/71-local-definition-4.good.expected new file mode 100644 index 0000000..9f71bdb --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/71-local-definition-4.good.expected @@ -0,0 +1 @@ +let main = fun ping _ = (pong 0) and pong _ = (ping 0) ; ping 0 diff --git a/flap/tests/01-Parsing-no-positions/71-local-definition-4.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/71-local-definition-4.good.parsing-no-positions.hopix new file mode 100644 index 0000000..de7f0e1 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/71-local-definition-4.good.parsing-no-positions.hopix @@ -0,0 +1,4 @@ +let main = + fun ping _ = pong 0 + and pong _ = ping 0; + ping 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/72-local-definition-5.bad.expected b/flap/tests/01-Parsing-no-positions/72-local-definition-5.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/72-local-definition-5.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/72-local-definition-5.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/72-local-definition-5.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..e7282ec --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/72-local-definition-5.bad.parsing-no-positions.hopix @@ -0,0 +1,5 @@ +let bonneteau = + fun h (x, y) = g x + and g x = f (x, x, x); + and f (x, y, z) = y; + f (1, 2, 3) \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/72-local-definition-5.good.expected b/flap/tests/01-Parsing-no-positions/72-local-definition-5.good.expected new file mode 100644 index 0000000..86d8f42 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/72-local-definition-5.good.expected @@ -0,0 +1,6 @@ +let bonneteau = + fun h (x, y) = (g x) + and g x = (f (x, x, x)) + and f (x, y, z) = y + ; + f (1, 2, 3) diff --git a/flap/tests/01-Parsing-no-positions/72-local-definition-5.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/72-local-definition-5.good.parsing-no-positions.hopix new file mode 100644 index 0000000..41ff1e6 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/72-local-definition-5.good.parsing-no-positions.hopix @@ -0,0 +1,5 @@ +let bonneteau = + fun h (x, y) = g x + and g x = f (x, x, x) + and f (x, y, z) = y; + f (1, 2, 3) \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/73-lambda-1.bad.expected b/flap/tests/01-Parsing-no-positions/73-lambda-1.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/73-lambda-1.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/73-lambda-1.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/73-lambda-1.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..bf998ee --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/73-lambda-1.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let id = \x . x \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/73-lambda-1.good.expected b/flap/tests/01-Parsing-no-positions/73-lambda-1.good.expected new file mode 100644 index 0000000..a222185 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/73-lambda-1.good.expected @@ -0,0 +1 @@ +let id = \ x -> x diff --git a/flap/tests/01-Parsing-no-positions/73-lambda-1.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/73-lambda-1.good.parsing-no-positions.hopix new file mode 100644 index 0000000..27f8709 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/73-lambda-1.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let id = \x -> x \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/74-lambda-2.bad.expected b/flap/tests/01-Parsing-no-positions/74-lambda-2.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/74-lambda-2.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/74-lambda-2.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/74-lambda-2.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..9ce018f --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/74-lambda-2.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let k = \(x y) -> x \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/74-lambda-2.good.expected b/flap/tests/01-Parsing-no-positions/74-lambda-2.good.expected new file mode 100644 index 0000000..20d4f1b --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/74-lambda-2.good.expected @@ -0,0 +1 @@ +let k = \ (x, y) -> x diff --git a/flap/tests/01-Parsing-no-positions/74-lambda-2.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/74-lambda-2.good.parsing-no-positions.hopix new file mode 100644 index 0000000..da357e8 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/74-lambda-2.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let k = \(x, y) -> x \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/75-lambda-3.bad.expected b/flap/tests/01-Parsing-no-positions/75-lambda-3.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/75-lambda-3.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/75-lambda-3.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/75-lambda-3.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..a9b76e2 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/75-lambda-3.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let k3 = \(x, y z) -> x \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/75-lambda-3.good.expected b/flap/tests/01-Parsing-no-positions/75-lambda-3.good.expected new file mode 100644 index 0000000..00eb918 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/75-lambda-3.good.expected @@ -0,0 +1 @@ +let k3 = \ (x, y, z) -> x diff --git a/flap/tests/01-Parsing-no-positions/75-lambda-3.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/75-lambda-3.good.parsing-no-positions.hopix new file mode 100644 index 0000000..0b446ca --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/75-lambda-3.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let k3 = \(x, y, z) -> x \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/76-lambda-4.bad.expected b/flap/tests/01-Parsing-no-positions/76-lambda-4.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/76-lambda-4.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/76-lambda-4.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/76-lambda-4.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..7fdfd9c --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/76-lambda-4.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let zero = \__ -> 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/76-lambda-4.good.expected b/flap/tests/01-Parsing-no-positions/76-lambda-4.good.expected new file mode 100644 index 0000000..7cc83af --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/76-lambda-4.good.expected @@ -0,0 +1 @@ +let zero = \ _ -> 0 diff --git a/flap/tests/01-Parsing-no-positions/76-lambda-4.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/76-lambda-4.good.parsing-no-positions.hopix new file mode 100644 index 0000000..1a76fda --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/76-lambda-4.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let zero = \_ -> 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/77-application-1.bad.expected b/flap/tests/01-Parsing-no-positions/77-application-1.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/77-application-1.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/77-application-1.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/77-application-1.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..0906a98 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/77-application-1.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let = id \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/77-application-1.good.expected b/flap/tests/01-Parsing-no-positions/77-application-1.good.expected new file mode 100644 index 0000000..673eca8 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/77-application-1.good.expected @@ -0,0 +1 @@ +let zero = id 0 diff --git a/flap/tests/01-Parsing-no-positions/77-application-1.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/77-application-1.good.parsing-no-positions.hopix new file mode 100644 index 0000000..7ee62ef --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/77-application-1.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let zero = id 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/78-application-2.bad.expected b/flap/tests/01-Parsing-no-positions/78-application-2.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/78-application-2.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/78-application-2.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/78-application-2.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..452e909 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/78-application-2.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let compose = ((id id) (id id) id \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/78-application-2.good.expected b/flap/tests/01-Parsing-no-positions/78-application-2.good.expected new file mode 100644 index 0000000..308f961 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/78-application-2.good.expected @@ -0,0 +1 @@ +let compose = ((id id) (id id)) id diff --git a/flap/tests/01-Parsing-no-positions/78-application-2.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/78-application-2.good.parsing-no-positions.hopix new file mode 100644 index 0000000..a2193cb --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/78-application-2.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let compose = ((id id) (id id)) id \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/79-application-3.bad.expected b/flap/tests/01-Parsing-no-positions/79-application-3.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/79-application-3.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/79-application-3.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/79-application-3.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..e486dca --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/79-application-3.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let beta = (\x - x) 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/79-application-3.good.expected b/flap/tests/01-Parsing-no-positions/79-application-3.good.expected new file mode 100644 index 0000000..e43c770 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/79-application-3.good.expected @@ -0,0 +1 @@ +let beta = (\ x -> x) 0 diff --git a/flap/tests/01-Parsing-no-positions/79-application-3.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/79-application-3.good.parsing-no-positions.hopix new file mode 100644 index 0000000..02de3d9 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/79-application-3.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let beta = (\x -> x) 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/80-application-4.bad.expected b/flap/tests/01-Parsing-no-positions/80-application-4.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/80-application-4.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/80-application-4.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/80-application-4.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..078c81c --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/80-application-4.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let eta = \f -> \x -> \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/80-application-4.good.expected b/flap/tests/01-Parsing-no-positions/80-application-4.good.expected new file mode 100644 index 0000000..bf57bfb --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/80-application-4.good.expected @@ -0,0 +1 @@ +let eta = \ f -> (\ x -> (f x)) diff --git a/flap/tests/01-Parsing-no-positions/80-application-4.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/80-application-4.good.parsing-no-positions.hopix new file mode 100644 index 0000000..01e2a2e --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/80-application-4.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let eta = \f -> \x -> f x \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/81-application-5.bad.expected b/flap/tests/01-Parsing-no-positions/81-application-5.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/81-application-5.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/81-application-5.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/81-application-5.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..35fb031 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/81-application-5.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let omega = \x -> \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/81-application-5.good.expected b/flap/tests/01-Parsing-no-positions/81-application-5.good.expected new file mode 100644 index 0000000..822cb1a --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/81-application-5.good.expected @@ -0,0 +1 @@ +let omega = \ x -> (x x) diff --git a/flap/tests/01-Parsing-no-positions/81-application-5.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/81-application-5.good.parsing-no-positions.hopix new file mode 100644 index 0000000..ce64b5b --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/81-application-5.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let omega = \x -> x x \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/82-application-6.bad.expected b/flap/tests/01-Parsing-no-positions/82-application-6.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/82-application-6.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/82-application-6.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/82-application-6.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..1f19b71 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/82-application-6.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let bad_man = _0 \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/82-application-6.good.expected b/flap/tests/01-Parsing-no-positions/82-application-6.good.expected new file mode 100644 index 0000000..cb717f6 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/82-application-6.good.expected @@ -0,0 +1 @@ +let bad_man = 0 0 diff --git a/flap/tests/01-Parsing-no-positions/82-application-6.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/82-application-6.good.parsing-no-positions.hopix new file mode 100644 index 0000000..c4d5026 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/82-application-6.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let bad_man = 0 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/83-application-7.bad.expected b/flap/tests/01-Parsing-no-positions/83-application-7.bad.expected new file mode 100644 index 0000000..f4ba87a --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/83-application-7.bad.expected @@ -0,0 +1,2 @@ +Error (during lexing) + Unterminated string. diff --git a/flap/tests/01-Parsing-no-positions/83-application-7.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/83-application-7.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..4a35c99 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/83-application-7.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let invalid = "This is crazy" (0, 1, 3, "Stop this madness!) \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/83-application-7.good.expected b/flap/tests/01-Parsing-no-positions/83-application-7.good.expected new file mode 100644 index 0000000..9f33874 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/83-application-7.good.expected @@ -0,0 +1 @@ +let invalid = "This is crazy" (0, 1, 3, "Stop this madness!") diff --git a/flap/tests/01-Parsing-no-positions/83-application-7.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/83-application-7.good.parsing-no-positions.hopix new file mode 100644 index 0000000..2863571 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/83-application-7.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let invalid = "This is crazy" (0, 1, 3, "Stop this madness!") \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/84-infix-application-1.bad.expected b/flap/tests/01-Parsing-no-positions/84-infix-application-1.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/84-infix-application-1.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/84-infix-application-1.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/84-infix-application-1.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..9b0b593 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/84-infix-application-1.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let toto = 0 ++ 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/84-infix-application-1.good.expected b/flap/tests/01-Parsing-no-positions/84-infix-application-1.good.expected new file mode 100644 index 0000000..383f7a1 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/84-infix-application-1.good.expected @@ -0,0 +1 @@ +let toto = (0 + 0) diff --git a/flap/tests/01-Parsing-no-positions/84-infix-application-1.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/84-infix-application-1.good.parsing-no-positions.hopix new file mode 100644 index 0000000..41bb124 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/84-infix-application-1.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let toto = 0 + 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/85-infix-application-2.bad.expected b/flap/tests/01-Parsing-no-positions/85-infix-application-2.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/85-infix-application-2.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/85-infix-application-2.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/85-infix-application-2.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..8e40722 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/85-infix-application-2.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let harder_than_you_think = a * a / / b * b + c * c \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/85-infix-application-2.good.expected b/flap/tests/01-Parsing-no-positions/85-infix-application-2.good.expected new file mode 100644 index 0000000..3e65fb5 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/85-infix-application-2.good.expected @@ -0,0 +1 @@ +let harder_than_you_think = (((a * a) + (b * b)) + (c * c)) diff --git a/flap/tests/01-Parsing-no-positions/85-infix-application-2.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/85-infix-application-2.good.parsing-no-positions.hopix new file mode 100644 index 0000000..7de3890 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/85-infix-application-2.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let harder_than_you_think = a * a + b * b + c * c \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/86-infix-application-3.bad.expected b/flap/tests/01-Parsing-no-positions/86-infix-application-3.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/86-infix-application-3.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/86-infix-application-3.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/86-infix-application-3.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..2ba22c4 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/86-infix-application-3.bad.parsing-no-positions.hopix @@ -0,0 +1,2 @@ +let arithmetic_complexity = + 1 + 2 * 3 / 4 / 5 - 6 - 7 + 8 + 9 * 10 - \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/86-infix-application-3.good.expected b/flap/tests/01-Parsing-no-positions/86-infix-application-3.good.expected new file mode 100644 index 0000000..d6b4af9 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/86-infix-application-3.good.expected @@ -0,0 +1,2 @@ +let arithmetic_complexity = + (((((1 + (((2 * 3) / 4) / 5)) - 6) - 7) + 8) + (9 * 10)) diff --git a/flap/tests/01-Parsing-no-positions/86-infix-application-3.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/86-infix-application-3.good.parsing-no-positions.hopix new file mode 100644 index 0000000..9ca5b3d --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/86-infix-application-3.good.parsing-no-positions.hopix @@ -0,0 +1,2 @@ +let arithmetic_complexity = + 1 + 2 * 3 / 4 / 5 - 6 - 7 + 8 + 9 * 10 \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/87-infix-application-4.bad.expected b/flap/tests/01-Parsing-no-positions/87-infix-application-4.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/87-infix-application-4.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/87-infix-application-4.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/87-infix-application-4.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..71cae37 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/87-infix-application-4.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let cycle_of_life = lion eats giraffe eats grass eats lion ++ \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/87-infix-application-4.good.expected b/flap/tests/01-Parsing-no-positions/87-infix-application-4.good.expected new file mode 100644 index 0000000..f125965 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/87-infix-application-4.good.expected @@ -0,0 +1,2 @@ +let cycle_of_life = + (((((lion eats) giraffe) eats) grass) eats) lion diff --git a/flap/tests/01-Parsing-no-positions/87-infix-application-4.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/87-infix-application-4.good.parsing-no-positions.hopix new file mode 100644 index 0000000..a926d3a --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/87-infix-application-4.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let cycle_of_life = lion eats giraffe eats grass eats lion \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/88-case-1.bad.expected b/flap/tests/01-Parsing-no-positions/88-case-1.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/88-case-1.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/88-case-1.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/88-case-1.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..162954f --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/88-case-1.bad.parsing-no-positions.hopix @@ -0,0 +1,7 @@ +let style_evaluation = + match (hair_color) { + | Red => Good + | Yellow => Good + | Brown => Good + | _ => Good + } \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/88-case-1.good.expected b/flap/tests/01-Parsing-no-positions/88-case-1.good.expected new file mode 100644 index 0000000..26e1a1b --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/88-case-1.good.expected @@ -0,0 +1,4 @@ +let style_evaluation = + match (hair_color) { + | Red -> Good | Yellow -> Good | Brown -> Good | _ -> Good + } diff --git a/flap/tests/01-Parsing-no-positions/88-case-1.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/88-case-1.good.parsing-no-positions.hopix new file mode 100644 index 0000000..8602f2c --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/88-case-1.good.parsing-no-positions.hopix @@ -0,0 +1,7 @@ +let style_evaluation = + match (hair_color) { + | Red -> Good + | Yellow -> Good + | Brown -> Good + | _ -> Good + } \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/89-case-2.bad.expected b/flap/tests/01-Parsing-no-positions/89-case-2.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/89-case-2.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/89-case-2.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/89-case-2.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..0f9cb4d --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/89-case-2.bad.parsing-no-positions.hopix @@ -0,0 +1,4 @@ +let what_is_in_the_box = + match (box) { + { box = } -> box + } \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/89-case-2.good.expected b/flap/tests/01-Parsing-no-positions/89-case-2.good.expected new file mode 100644 index 0000000..f99ea21 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/89-case-2.good.expected @@ -0,0 +1 @@ +let what_is_in_the_box = match (box) { | {box = box} -> box } diff --git a/flap/tests/01-Parsing-no-positions/89-case-2.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/89-case-2.good.parsing-no-positions.hopix new file mode 100644 index 0000000..1ee8812 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/89-case-2.good.parsing-no-positions.hopix @@ -0,0 +1,4 @@ +let what_is_in_the_box = + match (box) { + { box = box } -> box + } \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/90-case-3.bad.expected b/flap/tests/01-Parsing-no-positions/90-case-3.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/90-case-3.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/90-case-3.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/90-case-3.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..41314ff --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/90-case-3.bad.parsing-no-positions.hopix @@ -0,0 +1,7 @@ +let menu = + match (choice) { + | Coffee | Tea -> OK + | Chocolate -> OK + | Beer -> AreYouSure + | _ -> + } \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/90-case-3.good.expected b/flap/tests/01-Parsing-no-positions/90-case-3.good.expected new file mode 100644 index 0000000..4bb6573 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/90-case-3.good.expected @@ -0,0 +1,7 @@ +let menu = + match (choice) { + | (Coffee | Tea) -> OK + | Chocolate -> OK + | Beer -> AreYouSure + | _ -> KO + } diff --git a/flap/tests/01-Parsing-no-positions/90-case-3.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/90-case-3.good.parsing-no-positions.hopix new file mode 100644 index 0000000..a2262b2 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/90-case-3.good.parsing-no-positions.hopix @@ -0,0 +1,7 @@ +let menu = + match (choice) { + | Coffee | Tea -> OK + | Chocolate -> OK + | Beer -> AreYouSure + | _ -> KO + } \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/91-case-4.bad.expected b/flap/tests/01-Parsing-no-positions/91-case-4.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/91-case-4.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/91-case-4.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/91-case-4.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..52318d4 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/91-case-4.bad.parsing-no-positions.hopix @@ -0,0 +1,4 @@ +let nest = + match (bird) { + Nest (Some (bird)) -> bird + | Nest (None) -> nothing diff --git a/flap/tests/01-Parsing-no-positions/91-case-4.good.expected b/flap/tests/01-Parsing-no-positions/91-case-4.good.expected new file mode 100644 index 0000000..e5893ca --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/91-case-4.good.expected @@ -0,0 +1,4 @@ +let nest = + match (bird) { + | Nest(Some(bird)) -> bird | Nest(None) -> nothing + } diff --git a/flap/tests/01-Parsing-no-positions/91-case-4.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/91-case-4.good.parsing-no-positions.hopix new file mode 100644 index 0000000..d47a83c --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/91-case-4.good.parsing-no-positions.hopix @@ -0,0 +1,5 @@ +let nest = + match (bird) { + Nest (Some (bird)) -> bird + | Nest (None) -> nothing + } \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/92-case-5.bad.expected b/flap/tests/01-Parsing-no-positions/92-case-5.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/92-case-5.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/92-case-5.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/92-case-5.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..e526b7e --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/92-case-5.bad.parsing-no-positions.hopix @@ -0,0 +1,5 @@ +let main = + match (some_value) { + | Some ({ box = _; other_box = (Some (_) & got_you) }) -> got_you + | None -> None + } \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/92-case-5.good.expected b/flap/tests/01-Parsing-no-positions/92-case-5.good.expected new file mode 100644 index 0000000..c345ec8 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/92-case-5.good.expected @@ -0,0 +1,5 @@ +let main = + match (some_value) { + | Some({box = _, other_box = (Some(_) & got_you)} ) -> got_you + | None -> None + } diff --git a/flap/tests/01-Parsing-no-positions/92-case-5.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/92-case-5.good.parsing-no-positions.hopix new file mode 100644 index 0000000..2f50dd9 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/92-case-5.good.parsing-no-positions.hopix @@ -0,0 +1,5 @@ +let main = + match (some_value) { + | Some ({ box = _, other_box = (Some (_) & got_you) }) -> got_you + | None -> None + } \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/93-case-6.bad.expected b/flap/tests/01-Parsing-no-positions/93-case-6.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/93-case-6.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/93-case-6.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/93-case-6.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..50f9df0 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/93-case-6.bad.parsing-no-positions.hopix @@ -0,0 +1,5 @@ +let omg = + match (some_value) { + | "Some string" -> 0 + 'a' -> 2 + } \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/93-case-6.good.expected b/flap/tests/01-Parsing-no-positions/93-case-6.good.expected new file mode 100644 index 0000000..bd415c9 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/93-case-6.good.expected @@ -0,0 +1,2 @@ +let omg = + match (some_value) { | "Some string" -> 0 | 0 -> 1 | 'a' -> 2 } diff --git a/flap/tests/01-Parsing-no-positions/93-case-6.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/93-case-6.good.parsing-no-positions.hopix new file mode 100644 index 0000000..f86e092 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/93-case-6.good.parsing-no-positions.hopix @@ -0,0 +1,6 @@ +let omg = + match (some_value) { + | "Some string" -> 0 + | 0 -> 1 + | 'a' -> 2 + } \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/94-case-7.bad.expected b/flap/tests/01-Parsing-no-positions/94-case-7.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/94-case-7.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/94-case-7.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/94-case-7.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..0add8b9 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/94-case-7.bad.parsing-no-positions.hopix @@ -0,0 +1,4 @@ +let mono = + match (p) { + | (x y) -> x + y + } \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/94-case-7.good.expected b/flap/tests/01-Parsing-no-positions/94-case-7.good.expected new file mode 100644 index 0000000..8530ead --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/94-case-7.good.expected @@ -0,0 +1 @@ +let mono = match (p) { | (x, y) -> ((x + y)) } diff --git a/flap/tests/01-Parsing-no-positions/94-case-7.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/94-case-7.good.parsing-no-positions.hopix new file mode 100644 index 0000000..a3c6e6b --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/94-case-7.good.parsing-no-positions.hopix @@ -0,0 +1,4 @@ +let mono = + match (p) { + | (x, y) -> x + y + } \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/95-case-8.bad.expected b/flap/tests/01-Parsing-no-positions/95-case-8.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/95-case-8.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/95-case-8.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/95-case-8.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..3baac70 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/95-case-8.bad.parsing-no-positions.hopix @@ -0,0 +1,2 @@ +let polybox = + match x { { box = y } -> y } diff --git a/flap/tests/01-Parsing-no-positions/95-case-8.good.expected b/flap/tests/01-Parsing-no-positions/95-case-8.good.expected new file mode 100644 index 0000000..ab1bdc0 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/95-case-8.good.expected @@ -0,0 +1 @@ +let polybox = match (x) { | {box = y} < int > -> y } diff --git a/flap/tests/01-Parsing-no-positions/95-case-8.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/95-case-8.good.parsing-no-positions.hopix new file mode 100644 index 0000000..cf27826 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/95-case-8.good.parsing-no-positions.hopix @@ -0,0 +1,2 @@ +let polybox = + match (x) { { box = y } -> y } diff --git a/flap/tests/01-Parsing-no-positions/96-if-then-else.bad.expected b/flap/tests/01-Parsing-no-positions/96-if-then-else.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/96-if-then-else.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/96-if-then-else.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/96-if-then-else.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..32434e6 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/96-if-then-else.bad.parsing-no-positions.hopix @@ -0,0 +1,2 @@ +let main = + if True then { 0 } else { 1 } \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/96-if-then-else.good.expected b/flap/tests/01-Parsing-no-positions/96-if-then-else.good.expected new file mode 100644 index 0000000..0ebadd4 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/96-if-then-else.good.expected @@ -0,0 +1 @@ +let main = if (True) then { 0 } else { 1 } diff --git a/flap/tests/01-Parsing-no-positions/96-if-then-else.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/96-if-then-else.good.parsing-no-positions.hopix new file mode 100644 index 0000000..c98c356 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/96-if-then-else.good.parsing-no-positions.hopix @@ -0,0 +1,2 @@ +let main = + if (True) then { 0 } else { 1 } \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/97-if-then-else-2.bad.expected b/flap/tests/01-Parsing-no-positions/97-if-then-else-2.bad.expected new file mode 100644 index 0000000..0bc1944 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/97-if-then-else-2.bad.expected @@ -0,0 +1,2 @@ +let main = + if (failure 0) then { print error_message } else { () } diff --git a/flap/tests/01-Parsing-no-positions/97-if-then-else-2.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/97-if-then-else-2.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..a15dcda --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/97-if-then-else-2.bad.parsing-no-positions.hopix @@ -0,0 +1,4 @@ +let main = + if (failure 0) then { + print error_message + } \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/97-if-then-else-2.good.expected b/flap/tests/01-Parsing-no-positions/97-if-then-else-2.good.expected new file mode 100644 index 0000000..ccd0cf1 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/97-if-then-else-2.good.expected @@ -0,0 +1,3 @@ +let main = + if (failure 0) then { print error_message } + else { exit EXIT_FAILURE } diff --git a/flap/tests/01-Parsing-no-positions/97-if-then-else-2.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/97-if-then-else-2.good.parsing-no-positions.hopix new file mode 100644 index 0000000..9ef21a1 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/97-if-then-else-2.good.parsing-no-positions.hopix @@ -0,0 +1,6 @@ +let main = + if (failure 0) then { + print error_message + } else { + exit EXIT_FAILURE + } \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/98-if-then-else-3.bad.expected b/flap/tests/01-Parsing-no-positions/98-if-then-else-3.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/98-if-then-else-3.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/98-if-then-else-3.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/98-if-then-else-3.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..e03cbcd --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/98-if-then-else-3.bad.parsing-no-positions.hopix @@ -0,0 +1,5 @@ +let sequence = + if (x =? 0) then { foo 0 + } else { if (x ? 0) { baz 0 + } else { live 0 } } } \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/98-if-then-else-3.good.expected b/flap/tests/01-Parsing-no-positions/98-if-then-else-3.good.expected new file mode 100644 index 0000000..39107b6 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/98-if-then-else-3.good.expected @@ -0,0 +1,7 @@ +let sequence = + if ((x =? 0)) then { foo 0 } + else + { + if ((x ? 0)) then { baz 0 } else { live 0 } } + } diff --git a/flap/tests/01-Parsing-no-positions/98-if-then-else-3.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/98-if-then-else-3.good.parsing-no-positions.hopix new file mode 100644 index 0000000..47e320a --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/98-if-then-else-3.good.parsing-no-positions.hopix @@ -0,0 +1,5 @@ +let sequence = + if (x =? 0) then { foo 0 + } else { if (x ? 0) then { baz 0 + } else { live 0 } } } \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/98-if-then-else-4.bad.expected b/flap/tests/01-Parsing-no-positions/98-if-then-else-4.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/98-if-then-else-4.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/98-if-then-else-4.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/98-if-then-else-4.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..bf7fb40 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/98-if-then-else-4.bad.parsing-no-positions.hopix @@ -0,0 +1,2 @@ +let inner = + if (x =? 0) { if (y =? 1) { 0 } else { 1 } else { 2 } \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/98-if-then-else-4.good.expected b/flap/tests/01-Parsing-no-positions/98-if-then-else-4.good.expected new file mode 100644 index 0000000..a181c17 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/98-if-then-else-4.good.expected @@ -0,0 +1,3 @@ +let inner = + if ((x =? 0)) then { if ((y =? 1)) then { 0 } else { 1 } } + else { 2 } diff --git a/flap/tests/01-Parsing-no-positions/98-if-then-else-4.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/98-if-then-else-4.good.parsing-no-positions.hopix new file mode 100644 index 0000000..e0aaa35 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/98-if-then-else-4.good.parsing-no-positions.hopix @@ -0,0 +1,2 @@ +let inner = + if (x =? 0) then { if (y =? 1) then { 0 } else { 1 } } else { 2 } \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/99-ref-1.bad.expected b/flap/tests/01-Parsing-no-positions/99-ref-1.bad.expected new file mode 100644 index 0000000..a632411 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/99-ref-1.bad.expected @@ -0,0 +1,2 @@ +Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing-no-positions/99-ref-1.bad.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/99-ref-1.bad.parsing-no-positions.hopix new file mode 100644 index 0000000..037f61a --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/99-ref-1.bad.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = ref \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/99-ref-1.good.expected b/flap/tests/01-Parsing-no-positions/99-ref-1.good.expected new file mode 100644 index 0000000..98bc2c7 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/99-ref-1.good.expected @@ -0,0 +1 @@ +let x = ref 0 diff --git a/flap/tests/01-Parsing-no-positions/99-ref-1.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/99-ref-1.good.parsing-no-positions.hopix new file mode 100644 index 0000000..a9747c1 --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/99-ref-1.good.parsing-no-positions.hopix @@ -0,0 +1 @@ +let x = ref 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing-no-positions/999-slam.good.expected b/flap/tests/01-Parsing-no-positions/999-slam.good.expected new file mode 100644 index 0000000..58a5fcb --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/999-slam.good.expected @@ -0,0 +1,100 @@ +let x = 0 +let f = \ x -> x +fun g x = x +fun h (x, y) = ((x + i y)) and i z = (h (z, z)) +fun arithmetic + (x, y, z) = + ((((x + (y * z)) + ((x + y) * z)) + (z * (x + y)))) + +let some_Int = 12345 +let some_other_Int = 3405691582 +let some_other_other_Int = 1354 +let yet_another_Int = 30344 +let some_char = 'a' +let some_other_char = '@' +let some_other_other_char = '\170' +let yet_another_char = '\t' +let some_String = + "N'oubliez pas, car votre vie en d\233pend. Ne clignez pas des yeux. N'y pensez m\234me pas. Clignez et vous \234tes morts. Ils sont rapides, bien plus rapides que vous ne le croyez. Ne leur tournez pas le dos. Ne regardez pas ailleurs. Et surtout, ne clignez pas. Bonne chance." +let some_other_String = + "\n\n\t Le Docteur : Vous avez d\233truit l'inscription la plus ancienne de l'univers.\n\n\t River Song : Tu m'y as oblig\233e, tu ne r\233pondais pas au t\233l\233phone.\n\nOups\b\r\n" +let yet_another_String = "Say \"Hello!\"" +type int_list = + + INil | ICons (int, int_list) +type list<`a> = + + Nil | Cons (`a, list<`a>) +type llist<`a> = + + LNil | LCons (`a, unit -> llist<`a>) +type marthe_exp = + + EInt (int) + | EAdd (marthe_exp, marthe_exp) + | ESum (marthe_exp, marthe_exp) + | EVar (string) + | ESum (string, marthe_exp, marthe_exp, marthe_exp) + +type box = + { + what_s_in_the_box : int } +type person = + { + name : string , age : int } +type closure<`env, `a, `b> = + { + code : (`env * `a) -> `b , env : `env } +type container_functions<`e, `c, `b> = + { + map : (`e -> `a * `c) -> `c + , fold : (`e -> unit * `c) -> unit + , weird : `e -> ((`c * `e) -> `b) + } +let id : [`a]`a -> `a = \ x -> x +let id_int = id < int > +let stable = id < int > 37 +let compose : [`a, `b, `c](`a -> `b * `b -> `c) -> (`a -> `c) = + \ (f, g) -> (\ x -> (f (g x) : `c)) +let id_id_id = compose < int, int, int > (id, id) +let id_id_id_2 = + compose < (int -> int), (int -> int), (int -> int) > (id, id) +let an_empty_list = Nil < int > +let a_cool_list = + Cons < int >(1, Cons < int >(1, an_empty_list)) +let a_person = {name = "Luke", age = 28} +let a_name = a_person.name +let main = + (start_with_this 0); ((do_that ("foo", "bar")); (conclude 0)) +let computation = let y = 42 ; let z = 13 ; compute 0 +fun : [`a]list<`a> -> int len + l = + (match (l) { + | Nil < `a > -> 0 | Cons < `a >(x, xs) -> ((1 + len < `a > xs)) + }) + +fun fact + n = + (if ((n =? 0)) then { 1 } + else + { + if ((n =? 1)) then { 1 } + else { if ((n =? 2)) then { 2 } else { (fact ((n - 1)) * n) } } + }) + +fun ifact + n = + (let accu = (ref 1) ; + let k = (ref n) ; + while + (((! k) + >? + 0)) + { (accu := ((! accu) * (! k))); (k := ((! k) - 1)) }; + ((! accu))) + +fun ifact2 + n = + (let accu = (ref 1) ; + for k from (1) to (n) { accu := ((! accu) * k) }; ((! accu))) + diff --git a/flap/tests/01-Parsing-no-positions/999-slam.good.parsing-no-positions.hopix b/flap/tests/01-Parsing-no-positions/999-slam.good.parsing-no-positions.hopix new file mode 100644 index 0000000..e7e158f --- /dev/null +++ b/flap/tests/01-Parsing-no-positions/999-slam.good.parsing-no-positions.hopix @@ -0,0 +1,126 @@ +{* #* #* *# #* *# #* #* *# *# *# #* #* *# #* *# #* #* *# *# *# #* *# #* *# ** *} +{******************************************************************************} +{* THE HOPIX PARSING GREAT SLAM *} +{******************************************************************************} +{* #* #* *# #* *# #* #* *# *# *# #* #* *# #* *# #* #* *# *# *# #* *# #* *# ** *} + +let x = 0 + +let f = \x -> x + +fun g x = x + +fun h (x, y) = x + i y +and i z = h (z, z) + +fun arithmetic (x, y, z) = + x + y * z + (x + y) * z + z * (x + y) + +let some_Int = 12345 +let some_other_Int = 0xCAFEBABE +let some_other_other_Int = 0b00010101001010 +let yet_another_Int = 0o73210 + +let some_char = 'a' +let some_other_char = '\064' +let some_other_other_char = '\0xaa' +let yet_another_char = '\t' + +let some_String = + "N'oubliez pas, car votre vie en d\233pend. Ne clignez pas des yeux. N'y pensez m\234me pas. Clignez et vous \234tes morts. Ils sont rapides, bien plus rapides que vous ne le croyez. Ne leur tournez pas le dos. Ne regardez pas ailleurs. Et surtout, ne clignez pas. Bonne chance." + +let some_other_String = + "\n\n\t Le Docteur : Vous avez d\233truit l'inscription la plus ancienne de l'univers.\n\n\t River Song : Tu m'y as oblig\233e, tu ne r\233pondais pas au t\233l\233phone.\n\nOups\b\r\n" + +let yet_another_String = "Say \"Hello!\"" + +type int_list = INil | ICons (int, int_list) + +type list<`a> = +| Nil +| Cons (`a, list<`a>) + +type llist<`a> = +| LNil +| LCons (`a, unit -> llist<`a>) + +type marthe_exp = +| EInt (int) +| EAdd (marthe_exp, marthe_exp) +| ESum (marthe_exp, marthe_exp) +| EVar (string) +| ESum (string, marthe_exp, marthe_exp, marthe_exp) + +type box = { what_s_in_the_box : int } + +type person = { name : string, age : int } + +type closure <`env, `a, `b> = { code : `env * `a -> `b, env : `env } + +type container_functions<`e, `c, `b> = { + map : (`e -> `a) * `c -> `c, + fold : (`e -> unit) * `c -> unit, + weird : `e -> `c * `e -> `b +} + +let id +: [`a] `a -> `a += \x -> x + +let id_int = id + +let stable = id (37) + +let compose +: [`a, `b, `c] (`a -> `b) * (`b -> `c) -> (`a -> `c) += \(f, g) -> \x -> (f (g x) : `c) + +let id_id_id = compose (id, id) + +let id_id_id_2 = compose int, int -> int, int -> int> (id, id) + +let an_empty_list = Nil + +let a_cool_list = Cons (1, Cons (1, an_empty_list)) + +let a_person = { name = "Luke", age = 28 } + +let a_name = a_person.name + +let main = + start_with_this (0); + do_that ("foo", "bar"); + conclude (0) + +let computation = + let y = 42; + let z = 13; + compute (0) + +fun : [`a] list<`a> -> int +len l = match (l) { +| Nil<`a> -> 0 +| Cons<`a> (x, xs) -> 1 + len<`a> (xs) +} + +fun fact n = + if (n =? 0) then { 1 } + else { if (n =? 1) then { 1 } + else { if (n =? 2) then { 2 } + else { fact (n - 1) * n } } } + +fun ifact n = + let accu = ref 1; + let k = ref n; + while (!k >? 0) { + accu := !accu * !k; + k := !k - 1 + }; + !accu + +fun ifact2 (n) = + let accu = ref 1; + for k from (1) to (n) { + accu := !accu * k + }; + !accu diff --git a/flap/tests/01-Parsing/01-constructor-application.bad.expected b/flap/tests/01-Parsing/01-constructor-application.bad.expected new file mode 100644 index 0000000..d00824e --- /dev/null +++ b/flap/tests/01-Parsing/01-constructor-application.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 6-7: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/01-constructor-application.bad.parsing.hopix b/flap/tests/01-Parsing/01-constructor-application.bad.parsing.hopix new file mode 100644 index 0000000..8e5b2e5 --- /dev/null +++ b/flap/tests/01-Parsing/01-constructor-application.bad.parsing.hopix @@ -0,0 +1,2 @@ +fun f = True + diff --git a/flap/tests/01-Parsing/01-constructor-application.good.expected b/flap/tests/01-Parsing/01-constructor-application.good.expected new file mode 100644 index 0000000..d4a9baa --- /dev/null +++ b/flap/tests/01-Parsing/01-constructor-application.good.expected @@ -0,0 +1 @@ +fun f _ = True diff --git a/flap/tests/01-Parsing/01-constructor-application.good.parsing.hopix b/flap/tests/01-Parsing/01-constructor-application.good.parsing.hopix new file mode 100644 index 0000000..050c32f --- /dev/null +++ b/flap/tests/01-Parsing/01-constructor-application.good.parsing.hopix @@ -0,0 +1,2 @@ +fun f _ = True + diff --git a/flap/tests/01-Parsing/02-app2.bad.expected b/flap/tests/01-Parsing/02-app2.bad.expected new file mode 100644 index 0000000..baac959 --- /dev/null +++ b/flap/tests/01-Parsing/02-app2.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 0-3: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/02-app2.bad.parsing.hopix b/flap/tests/01-Parsing/02-app2.bad.parsing.hopix new file mode 100644 index 0000000..4462a01 --- /dev/null +++ b/flap/tests/01-Parsing/02-app2.bad.parsing.hopix @@ -0,0 +1 @@ +val drama = eats cat mouse \ No newline at end of file diff --git a/flap/tests/01-Parsing/03-app2-2.bad.expected b/flap/tests/01-Parsing/03-app2-2.bad.expected new file mode 100644 index 0000000..3e35be5 --- /dev/null +++ b/flap/tests/01-Parsing/03-app2-2.bad.expected @@ -0,0 +1,2 @@ +Line 2, characters 15-16: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/03-app2-2.bad.parsing.hopix b/flap/tests/01-Parsing/03-app2-2.bad.parsing.hopix new file mode 100644 index 0000000..0eaf872 --- /dev/null +++ b/flap/tests/01-Parsing/03-app2-2.bad.parsing.hopix @@ -0,0 +1,2 @@ +let h2o = h (o o) +let h2obis = h [o, o] \ No newline at end of file diff --git a/flap/tests/01-Parsing/04-app2-3.bad.expected b/flap/tests/01-Parsing/04-app2-3.bad.expected new file mode 100644 index 0000000..a201f71 --- /dev/null +++ b/flap/tests/01-Parsing/04-app2-3.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 11-12: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/04-app2-3.bad.parsing.hopix b/flap/tests/01-Parsing/04-app2-3.bad.parsing.hopix new file mode 100644 index 0000000..2d456ef --- /dev/null +++ b/flap/tests/01-Parsing/04-app2-3.bad.parsing.hopix @@ -0,0 +1 @@ +let x = f (, 2) \ No newline at end of file diff --git a/flap/tests/01-Parsing/05-app3.bad.expected b/flap/tests/01-Parsing/05-app3.bad.expected new file mode 100644 index 0000000..bf607d6 --- /dev/null +++ b/flap/tests/01-Parsing/05-app3.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 0-2: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/05-app3.bad.parsing.hopix b/flap/tests/01-Parsing/05-app3.bad.parsing.hopix new file mode 100644 index 0000000..f3ebe01 --- /dev/null +++ b/flap/tests/01-Parsing/05-app3.bad.parsing.hopix @@ -0,0 +1 @@ +le app3 = f x y z \ No newline at end of file diff --git a/flap/tests/01-Parsing/06-lexer-var-id-1.bad.expected b/flap/tests/01-Parsing/06-lexer-var-id-1.bad.expected new file mode 100644 index 0000000..7657d2d --- /dev/null +++ b/flap/tests/01-Parsing/06-lexer-var-id-1.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 4-56: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/06-lexer-var-id-1.bad.parsing.hopix b/flap/tests/01-Parsing/06-lexer-var-id-1.bad.parsing.hopix new file mode 100644 index 0000000..a951bb0 --- /dev/null +++ b/flap/tests/01-Parsing/06-lexer-var-id-1.bad.parsing.hopix @@ -0,0 +1 @@ +let YouShouldNeverUseThis_Ugly_Way_of_Identifying_THINGS = 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing/06-lexer-var-id-1.good.expected b/flap/tests/01-Parsing/06-lexer-var-id-1.good.expected new file mode 100644 index 0000000..957c961 --- /dev/null +++ b/flap/tests/01-Parsing/06-lexer-var-id-1.good.expected @@ -0,0 +1 @@ +let youShouldNeverUseThis_Ugly_Way_of_Identifying_THINGS = 0 diff --git a/flap/tests/01-Parsing/06-lexer-var-id-1.good.parsing.hopix b/flap/tests/01-Parsing/06-lexer-var-id-1.good.parsing.hopix new file mode 100644 index 0000000..22519c5 --- /dev/null +++ b/flap/tests/01-Parsing/06-lexer-var-id-1.good.parsing.hopix @@ -0,0 +1 @@ +let youShouldNeverUseThis_Ugly_Way_of_Identifying_THINGS = 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing/07-lexer-var-id-2.bad.expected b/flap/tests/01-Parsing/07-lexer-var-id-2.bad.expected new file mode 100644 index 0000000..bffbae1 --- /dev/null +++ b/flap/tests/01-Parsing/07-lexer-var-id-2.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 4-5: Error (during lexing) + unexpected character. diff --git a/flap/tests/01-Parsing/07-lexer-var-id-2.bad.parsing.hopix b/flap/tests/01-Parsing/07-lexer-var-id-2.bad.parsing.hopix new file mode 100644 index 0000000..11a5653 --- /dev/null +++ b/flap/tests/01-Parsing/07-lexer-var-id-2.bad.parsing.hopix @@ -0,0 +1 @@ +let ?this_is_far_better_way_to_name_things_2_the_revenge = 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing/07-lexer-var-id-2.good.expected b/flap/tests/01-Parsing/07-lexer-var-id-2.good.expected new file mode 100644 index 0000000..8de8f59 --- /dev/null +++ b/flap/tests/01-Parsing/07-lexer-var-id-2.good.expected @@ -0,0 +1 @@ +let this_is_far_better_way_to_name_things_2_the_revenge = 0 diff --git a/flap/tests/01-Parsing/07-lexer-var-id-2.good.parsing.hopix b/flap/tests/01-Parsing/07-lexer-var-id-2.good.parsing.hopix new file mode 100644 index 0000000..670e4ba --- /dev/null +++ b/flap/tests/01-Parsing/07-lexer-var-id-2.good.parsing.hopix @@ -0,0 +1 @@ +let this_is_far_better_way_to_name_things_2_the_revenge = 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing/08-lexer-all-id-1.bad.expected b/flap/tests/01-Parsing/08-lexer-all-id-1.bad.expected new file mode 100644 index 0000000..f33d742 --- /dev/null +++ b/flap/tests/01-Parsing/08-lexer-all-id-1.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 12-13: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/08-lexer-all-id-1.bad.parsing.hopix b/flap/tests/01-Parsing/08-lexer-all-id-1.bad.parsing.hopix new file mode 100644 index 0000000..b8a76f7 --- /dev/null +++ b/flap/tests/01-Parsing/08-lexer-all-id-1.bad.parsing.hopix @@ -0,0 +1,2 @@ +fun fine (x y) = 0 +let fine = 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing/08-lexer-all-id-1.good.expected b/flap/tests/01-Parsing/08-lexer-all-id-1.good.expected new file mode 100644 index 0000000..ec781fc --- /dev/null +++ b/flap/tests/01-Parsing/08-lexer-all-id-1.good.expected @@ -0,0 +1,2 @@ +fun fine (x, y) = 0 +let fine = 0 diff --git a/flap/tests/01-Parsing/08-lexer-all-id-1.good.parsing.hopix b/flap/tests/01-Parsing/08-lexer-all-id-1.good.parsing.hopix new file mode 100644 index 0000000..df50ca7 --- /dev/null +++ b/flap/tests/01-Parsing/08-lexer-all-id-1.good.parsing.hopix @@ -0,0 +1,2 @@ +fun fine (x, y) = 0 +let fine = 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing/09-lexer-constr-id-1.bad.expected b/flap/tests/01-Parsing/09-lexer-constr-id-1.bad.expected new file mode 100644 index 0000000..4a7550d --- /dev/null +++ b/flap/tests/01-Parsing/09-lexer-constr-id-1.bad.expected @@ -0,0 +1 @@ +let x = True < > diff --git a/flap/tests/01-Parsing/09-lexer-constr-id-1.bad.parsing.hopix b/flap/tests/01-Parsing/09-lexer-constr-id-1.bad.parsing.hopix new file mode 100644 index 0000000..6eb14f7 --- /dev/null +++ b/flap/tests/01-Parsing/09-lexer-constr-id-1.bad.parsing.hopix @@ -0,0 +1 @@ +let x = True <> \ No newline at end of file diff --git a/flap/tests/01-Parsing/09-lexer-constr-id-1.good.expected b/flap/tests/01-Parsing/09-lexer-constr-id-1.good.expected new file mode 100644 index 0000000..f4c4941 --- /dev/null +++ b/flap/tests/01-Parsing/09-lexer-constr-id-1.good.expected @@ -0,0 +1 @@ +let x = True diff --git a/flap/tests/01-Parsing/09-lexer-constr-id-1.good.parsing.hopix b/flap/tests/01-Parsing/09-lexer-constr-id-1.good.parsing.hopix new file mode 100644 index 0000000..467de38 --- /dev/null +++ b/flap/tests/01-Parsing/09-lexer-constr-id-1.good.parsing.hopix @@ -0,0 +1 @@ +let x = True \ No newline at end of file diff --git a/flap/tests/01-Parsing/10-lexer-constr-id-2.bad.expected b/flap/tests/01-Parsing/10-lexer-constr-id-2.bad.expected new file mode 100644 index 0000000..baedb40 --- /dev/null +++ b/flap/tests/01-Parsing/10-lexer-constr-id-2.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 21-22: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/10-lexer-constr-id-2.bad.parsing.hopix b/flap/tests/01-Parsing/10-lexer-constr-id-2.bad.parsing.hopix new file mode 100644 index 0000000..6dc477c --- /dev/null +++ b/flap/tests/01-Parsing/10-lexer-constr-id-2.bad.parsing.hopix @@ -0,0 +1 @@ +let x = Cons (0, Nil : 1) \ No newline at end of file diff --git a/flap/tests/01-Parsing/10-lexer-constr-id-2.good.expected b/flap/tests/01-Parsing/10-lexer-constr-id-2.good.expected new file mode 100644 index 0000000..b614545 --- /dev/null +++ b/flap/tests/01-Parsing/10-lexer-constr-id-2.good.expected @@ -0,0 +1 @@ +let x = Cons(0, Nil(1)) diff --git a/flap/tests/01-Parsing/10-lexer-constr-id-2.good.parsing.hopix b/flap/tests/01-Parsing/10-lexer-constr-id-2.good.parsing.hopix new file mode 100644 index 0000000..af45253 --- /dev/null +++ b/flap/tests/01-Parsing/10-lexer-constr-id-2.good.parsing.hopix @@ -0,0 +1 @@ +let x = Cons (0, Nil (1)) \ No newline at end of file diff --git a/flap/tests/01-Parsing/100-ref-2.bad.expected b/flap/tests/01-Parsing/100-ref-2.bad.expected new file mode 100644 index 0000000..a6ded8b --- /dev/null +++ b/flap/tests/01-Parsing/100-ref-2.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 23-23: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/100-ref-2.bad.parsing.hopix b/flap/tests/01-Parsing/100-ref-2.bad.parsing.hopix new file mode 100644 index 0000000..3e5ab9b --- /dev/null +++ b/flap/tests/01-Parsing/100-ref-2.bad.parsing.hopix @@ -0,0 +1 @@ +let ill_typed = ref 0 * \ No newline at end of file diff --git a/flap/tests/01-Parsing/100-ref-2.good.expected b/flap/tests/01-Parsing/100-ref-2.good.expected new file mode 100644 index 0000000..72b444d --- /dev/null +++ b/flap/tests/01-Parsing/100-ref-2.good.expected @@ -0,0 +1 @@ +let ill_typed = (ref 0 * 1) diff --git a/flap/tests/01-Parsing/100-ref-2.good.parsing.hopix b/flap/tests/01-Parsing/100-ref-2.good.parsing.hopix new file mode 100644 index 0000000..9bd8d13 --- /dev/null +++ b/flap/tests/01-Parsing/100-ref-2.good.parsing.hopix @@ -0,0 +1 @@ +let ill_typed = ref 0 * 1 \ No newline at end of file diff --git a/flap/tests/01-Parsing/101-ref-3.bad.expected b/flap/tests/01-Parsing/101-ref-3.bad.expected new file mode 100644 index 0000000..cd08bb1 --- /dev/null +++ b/flap/tests/01-Parsing/101-ref-3.bad.expected @@ -0,0 +1,2 @@ +Line 3, characters 1-2: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/101-ref-3.bad.parsing.hopix b/flap/tests/01-Parsing/101-ref-3.bad.parsing.hopix new file mode 100644 index 0000000..3c09487 --- /dev/null +++ b/flap/tests/01-Parsing/101-ref-3.bad.parsing.hopix @@ -0,0 +1,3 @@ +let main = + let x = ref 0 + 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing/101-ref-3.good.expected b/flap/tests/01-Parsing/101-ref-3.good.expected new file mode 100644 index 0000000..595476e --- /dev/null +++ b/flap/tests/01-Parsing/101-ref-3.good.expected @@ -0,0 +1 @@ +let main = let x = (ref 0) ; 0 diff --git a/flap/tests/01-Parsing/101-ref-3.good.parsing.hopix b/flap/tests/01-Parsing/101-ref-3.good.parsing.hopix new file mode 100644 index 0000000..5893d86 --- /dev/null +++ b/flap/tests/01-Parsing/101-ref-3.good.parsing.hopix @@ -0,0 +1,3 @@ +let main = + let x = ref 0; + 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing/102-ref-4.bad.expected b/flap/tests/01-Parsing/102-ref-4.bad.expected new file mode 100644 index 0000000..cd62654 --- /dev/null +++ b/flap/tests/01-Parsing/102-ref-4.bad.expected @@ -0,0 +1,2 @@ +Line 2, characters 23-23: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/102-ref-4.bad.parsing.hopix b/flap/tests/01-Parsing/102-ref-4.bad.parsing.hopix new file mode 100644 index 0000000..21918da --- /dev/null +++ b/flap/tests/01-Parsing/102-ref-4.bad.parsing.hopix @@ -0,0 +1,2 @@ +let main = + let y = ref (\x -> x) \ No newline at end of file diff --git a/flap/tests/01-Parsing/102-ref-4.good.expected b/flap/tests/01-Parsing/102-ref-4.good.expected new file mode 100644 index 0000000..447ae72 --- /dev/null +++ b/flap/tests/01-Parsing/102-ref-4.good.expected @@ -0,0 +1 @@ +let main = let y = (ref (\ x -> x)) ; y diff --git a/flap/tests/01-Parsing/102-ref-4.good.parsing.hopix b/flap/tests/01-Parsing/102-ref-4.good.parsing.hopix new file mode 100644 index 0000000..37ed173 --- /dev/null +++ b/flap/tests/01-Parsing/102-ref-4.good.parsing.hopix @@ -0,0 +1,3 @@ +let main = + let y = ref (\x -> x); + y \ No newline at end of file diff --git a/flap/tests/01-Parsing/103-ref-5.bad.expected b/flap/tests/01-Parsing/103-ref-5.bad.expected new file mode 100644 index 0000000..a946aa7 --- /dev/null +++ b/flap/tests/01-Parsing/103-ref-5.bad.expected @@ -0,0 +1,2 @@ +Line 2, characters 8-9: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/103-ref-5.bad.parsing.hopix b/flap/tests/01-Parsing/103-ref-5.bad.parsing.hopix new file mode 100644 index 0000000..d537989 --- /dev/null +++ b/flap/tests/01-Parsing/103-ref-5.bad.parsing.hopix @@ -0,0 +1,3 @@ +let main = + val y = ref "foo"; + ref "bar" \ No newline at end of file diff --git a/flap/tests/01-Parsing/103-ref-5.good.expected b/flap/tests/01-Parsing/103-ref-5.good.expected new file mode 100644 index 0000000..9e3e1b1 --- /dev/null +++ b/flap/tests/01-Parsing/103-ref-5.good.expected @@ -0,0 +1 @@ +let main = let y = (ref "foo") ; ref "bar" diff --git a/flap/tests/01-Parsing/103-ref-5.good.parsing.hopix b/flap/tests/01-Parsing/103-ref-5.good.parsing.hopix new file mode 100644 index 0000000..19ac311 --- /dev/null +++ b/flap/tests/01-Parsing/103-ref-5.good.parsing.hopix @@ -0,0 +1,3 @@ +let main = + let y = ref "foo"; + ref "bar" \ No newline at end of file diff --git a/flap/tests/01-Parsing/104-assignment.bad.expected b/flap/tests/01-Parsing/104-assignment.bad.expected new file mode 100644 index 0000000..d28dc15 --- /dev/null +++ b/flap/tests/01-Parsing/104-assignment.bad.expected @@ -0,0 +1,2 @@ +Line 2, characters 4-5: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/104-assignment.bad.parsing.hopix b/flap/tests/01-Parsing/104-assignment.bad.parsing.hopix new file mode 100644 index 0000000..05627a1 --- /dev/null +++ b/flap/tests/01-Parsing/104-assignment.bad.parsing.hopix @@ -0,0 +1,2 @@ +let main = + x = 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing/104-assignment.good.expected b/flap/tests/01-Parsing/104-assignment.good.expected new file mode 100644 index 0000000..55517fb --- /dev/null +++ b/flap/tests/01-Parsing/104-assignment.good.expected @@ -0,0 +1 @@ +let main = x := 0 diff --git a/flap/tests/01-Parsing/104-assignment.good.parsing.hopix b/flap/tests/01-Parsing/104-assignment.good.parsing.hopix new file mode 100644 index 0000000..c1262ee --- /dev/null +++ b/flap/tests/01-Parsing/104-assignment.good.parsing.hopix @@ -0,0 +1,2 @@ +let main = + x := 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing/105-assignment-2.bad.expected b/flap/tests/01-Parsing/105-assignment-2.bad.expected new file mode 100644 index 0000000..39295c9 --- /dev/null +++ b/flap/tests/01-Parsing/105-assignment-2.bad.expected @@ -0,0 +1,2 @@ +Line 3, characters 0-0: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/105-assignment-2.bad.parsing.hopix b/flap/tests/01-Parsing/105-assignment-2.bad.parsing.hopix new file mode 100644 index 0000000..b31dbfc --- /dev/null +++ b/flap/tests/01-Parsing/105-assignment-2.bad.parsing.hopix @@ -0,0 +1,2 @@ +let main = + (ref 0) := diff --git a/flap/tests/01-Parsing/105-assignment-2.good.expected b/flap/tests/01-Parsing/105-assignment-2.good.expected new file mode 100644 index 0000000..83830a5 --- /dev/null +++ b/flap/tests/01-Parsing/105-assignment-2.good.expected @@ -0,0 +1 @@ +let main = (ref 0) := 1 diff --git a/flap/tests/01-Parsing/105-assignment-2.good.parsing.hopix b/flap/tests/01-Parsing/105-assignment-2.good.parsing.hopix new file mode 100644 index 0000000..ec265cd --- /dev/null +++ b/flap/tests/01-Parsing/105-assignment-2.good.parsing.hopix @@ -0,0 +1,2 @@ +let main = + (ref 0) := 1 \ No newline at end of file diff --git a/flap/tests/01-Parsing/106-assignment-3.bad.expected b/flap/tests/01-Parsing/106-assignment-3.bad.expected new file mode 100644 index 0000000..beb8055 --- /dev/null +++ b/flap/tests/01-Parsing/106-assignment-3.bad.expected @@ -0,0 +1,2 @@ +Line 2, characters 2-4: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/106-assignment-3.bad.parsing.hopix b/flap/tests/01-Parsing/106-assignment-3.bad.parsing.hopix new file mode 100644 index 0000000..6f29ae2 --- /dev/null +++ b/flap/tests/01-Parsing/106-assignment-3.bad.parsing.hopix @@ -0,0 +1,2 @@ +let main = + := 3 \ No newline at end of file diff --git a/flap/tests/01-Parsing/106-assignment-3.good.expected b/flap/tests/01-Parsing/106-assignment-3.good.expected new file mode 100644 index 0000000..8ba66a9 --- /dev/null +++ b/flap/tests/01-Parsing/106-assignment-3.good.expected @@ -0,0 +1 @@ +let main = (f 0) := 3 diff --git a/flap/tests/01-Parsing/106-assignment-3.good.parsing.hopix b/flap/tests/01-Parsing/106-assignment-3.good.parsing.hopix new file mode 100644 index 0000000..ad53614 --- /dev/null +++ b/flap/tests/01-Parsing/106-assignment-3.good.parsing.hopix @@ -0,0 +1,2 @@ +let main = + f 0 := 3 \ No newline at end of file diff --git a/flap/tests/01-Parsing/107-assignment-4.bad.expected b/flap/tests/01-Parsing/107-assignment-4.bad.expected new file mode 100644 index 0000000..8ab51d8 --- /dev/null +++ b/flap/tests/01-Parsing/107-assignment-4.bad.expected @@ -0,0 +1,2 @@ +Line 2, characters 4-6: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/107-assignment-4.bad.parsing.hopix b/flap/tests/01-Parsing/107-assignment-4.bad.parsing.hopix new file mode 100644 index 0000000..d042451 --- /dev/null +++ b/flap/tests/01-Parsing/107-assignment-4.bad.parsing.hopix @@ -0,0 +1,2 @@ +let main = + \ -> x := 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing/107-assignment-4.good.expected b/flap/tests/01-Parsing/107-assignment-4.good.expected new file mode 100644 index 0000000..2a6f5ee --- /dev/null +++ b/flap/tests/01-Parsing/107-assignment-4.good.expected @@ -0,0 +1 @@ +let main = \ x -> (x := 0) diff --git a/flap/tests/01-Parsing/107-assignment-4.good.parsing.hopix b/flap/tests/01-Parsing/107-assignment-4.good.parsing.hopix new file mode 100644 index 0000000..2dc6b1a --- /dev/null +++ b/flap/tests/01-Parsing/107-assignment-4.good.parsing.hopix @@ -0,0 +1,2 @@ +let main = + \x -> x := 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing/108-type-ascription-1.bad.expected b/flap/tests/01-Parsing/108-type-ascription-1.bad.expected new file mode 100644 index 0000000..7267a77 --- /dev/null +++ b/flap/tests/01-Parsing/108-type-ascription-1.bad.expected @@ -0,0 +1,2 @@ +Line 2, characters 7-10: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/108-type-ascription-1.bad.parsing.hopix b/flap/tests/01-Parsing/108-type-ascription-1.bad.parsing.hopix new file mode 100644 index 0000000..adaec38 --- /dev/null +++ b/flap/tests/01-Parsing/108-type-ascription-1.bad.parsing.hopix @@ -0,0 +1,2 @@ +let main = + match you { (me : int) -> me } \ No newline at end of file diff --git a/flap/tests/01-Parsing/108-type-ascription-1.good.expected b/flap/tests/01-Parsing/108-type-ascription-1.good.expected new file mode 100644 index 0000000..6cad84f --- /dev/null +++ b/flap/tests/01-Parsing/108-type-ascription-1.good.expected @@ -0,0 +1 @@ +let main = match (you) { | (me : int) -> me } diff --git a/flap/tests/01-Parsing/108-type-ascription-1.good.parsing.hopix b/flap/tests/01-Parsing/108-type-ascription-1.good.parsing.hopix new file mode 100644 index 0000000..7d3d72e --- /dev/null +++ b/flap/tests/01-Parsing/108-type-ascription-1.good.parsing.hopix @@ -0,0 +1,2 @@ +let main = + match (you) { (me : int) -> me } \ No newline at end of file diff --git a/flap/tests/01-Parsing/109-type-ascription-2.bad.expected b/flap/tests/01-Parsing/109-type-ascription-2.bad.expected new file mode 100644 index 0000000..d28dc15 --- /dev/null +++ b/flap/tests/01-Parsing/109-type-ascription-2.bad.expected @@ -0,0 +1,2 @@ +Line 2, characters 4-5: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/109-type-ascription-2.bad.parsing.hopix b/flap/tests/01-Parsing/109-type-ascription-2.bad.parsing.hopix new file mode 100644 index 0000000..4b468dd --- /dev/null +++ b/flap/tests/01-Parsing/109-type-ascription-2.bad.parsing.hopix @@ -0,0 +1,2 @@ +let main = + 0 : int \ No newline at end of file diff --git a/flap/tests/01-Parsing/109-type-ascription-2.good.expected b/flap/tests/01-Parsing/109-type-ascription-2.good.expected new file mode 100644 index 0000000..2ad927b --- /dev/null +++ b/flap/tests/01-Parsing/109-type-ascription-2.good.expected @@ -0,0 +1 @@ +let main = (0 : int) diff --git a/flap/tests/01-Parsing/109-type-ascription-2.good.parsing.hopix b/flap/tests/01-Parsing/109-type-ascription-2.good.parsing.hopix new file mode 100644 index 0000000..4678569 --- /dev/null +++ b/flap/tests/01-Parsing/109-type-ascription-2.good.parsing.hopix @@ -0,0 +1,2 @@ +let main = + (0 : int) \ No newline at end of file diff --git a/flap/tests/01-Parsing/11-lexer-constr-id-3.bad.expected b/flap/tests/01-Parsing/11-lexer-constr-id-3.bad.expected new file mode 100644 index 0000000..a201f71 --- /dev/null +++ b/flap/tests/01-Parsing/11-lexer-constr-id-3.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 11-12: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/11-lexer-constr-id-3.bad.parsing.hopix b/flap/tests/01-Parsing/11-lexer-constr-id-3.bad.parsing.hopix new file mode 100644 index 0000000..96dc759 --- /dev/null +++ b/flap/tests/01-Parsing/11-lexer-constr-id-3.bad.parsing.hopix @@ -0,0 +1 @@ +let x = (0,) \ No newline at end of file diff --git a/flap/tests/01-Parsing/11-lexer-constr-id-3.good.expected b/flap/tests/01-Parsing/11-lexer-constr-id-3.good.expected new file mode 100644 index 0000000..ef0986e --- /dev/null +++ b/flap/tests/01-Parsing/11-lexer-constr-id-3.good.expected @@ -0,0 +1 @@ +let x = (0, 1) diff --git a/flap/tests/01-Parsing/11-lexer-constr-id-3.good.parsing.hopix b/flap/tests/01-Parsing/11-lexer-constr-id-3.good.parsing.hopix new file mode 100644 index 0000000..741b5f7 --- /dev/null +++ b/flap/tests/01-Parsing/11-lexer-constr-id-3.good.parsing.hopix @@ -0,0 +1 @@ +let x = (0, 1) \ No newline at end of file diff --git a/flap/tests/01-Parsing/110-type-ascription-3.bad.expected b/flap/tests/01-Parsing/110-type-ascription-3.bad.expected new file mode 100644 index 0000000..fe691fa --- /dev/null +++ b/flap/tests/01-Parsing/110-type-ascription-3.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 15-16: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/110-type-ascription-3.bad.parsing.hopix b/flap/tests/01-Parsing/110-type-ascription-3.bad.parsing.hopix new file mode 100644 index 0000000..d520d90 --- /dev/null +++ b/flap/tests/01-Parsing/110-type-ascription-3.bad.parsing.hopix @@ -0,0 +1 @@ +let main = (\x => x : int -> int) \ No newline at end of file diff --git a/flap/tests/01-Parsing/110-type-ascription-3.good.expected b/flap/tests/01-Parsing/110-type-ascription-3.good.expected new file mode 100644 index 0000000..610596d --- /dev/null +++ b/flap/tests/01-Parsing/110-type-ascription-3.good.expected @@ -0,0 +1 @@ +let main = (\ x -> x : int -> int) diff --git a/flap/tests/01-Parsing/110-type-ascription-3.good.parsing.hopix b/flap/tests/01-Parsing/110-type-ascription-3.good.parsing.hopix new file mode 100644 index 0000000..78aa8ca --- /dev/null +++ b/flap/tests/01-Parsing/110-type-ascription-3.good.parsing.hopix @@ -0,0 +1 @@ +let main = (\x -> x : int -> int) \ No newline at end of file diff --git a/flap/tests/01-Parsing/111-deref-1.bad.expected b/flap/tests/01-Parsing/111-deref-1.bad.expected new file mode 100644 index 0000000..3e63559 --- /dev/null +++ b/flap/tests/01-Parsing/111-deref-1.bad.expected @@ -0,0 +1,2 @@ +Line 2, characters 3-3: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/111-deref-1.bad.parsing.hopix b/flap/tests/01-Parsing/111-deref-1.bad.parsing.hopix new file mode 100644 index 0000000..6caa58e --- /dev/null +++ b/flap/tests/01-Parsing/111-deref-1.bad.parsing.hopix @@ -0,0 +1,2 @@ +let main = + ! \ No newline at end of file diff --git a/flap/tests/01-Parsing/111-deref-1.good.expected b/flap/tests/01-Parsing/111-deref-1.good.expected new file mode 100644 index 0000000..f960efc --- /dev/null +++ b/flap/tests/01-Parsing/111-deref-1.good.expected @@ -0,0 +1 @@ +let main = (! x) diff --git a/flap/tests/01-Parsing/111-deref-1.good.parsing.hopix b/flap/tests/01-Parsing/111-deref-1.good.parsing.hopix new file mode 100644 index 0000000..862890e --- /dev/null +++ b/flap/tests/01-Parsing/111-deref-1.good.parsing.hopix @@ -0,0 +1,2 @@ +let main = + ! x \ No newline at end of file diff --git a/flap/tests/01-Parsing/112-deref-2.bad.expected b/flap/tests/01-Parsing/112-deref-2.bad.expected new file mode 100644 index 0000000..5c5b98b --- /dev/null +++ b/flap/tests/01-Parsing/112-deref-2.bad.expected @@ -0,0 +1,2 @@ +Line 2, characters 6-7: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/112-deref-2.bad.parsing.hopix b/flap/tests/01-Parsing/112-deref-2.bad.parsing.hopix new file mode 100644 index 0000000..7d8e7a0 --- /dev/null +++ b/flap/tests/01-Parsing/112-deref-2.bad.parsing.hopix @@ -0,0 +1,2 @@ +let double = + ! (! ) \ No newline at end of file diff --git a/flap/tests/01-Parsing/112-deref-2.good.expected b/flap/tests/01-Parsing/112-deref-2.good.expected new file mode 100644 index 0000000..cc49756 --- /dev/null +++ b/flap/tests/01-Parsing/112-deref-2.good.expected @@ -0,0 +1 @@ +let double = (! ((! x))) diff --git a/flap/tests/01-Parsing/112-deref-2.good.parsing.hopix b/flap/tests/01-Parsing/112-deref-2.good.parsing.hopix new file mode 100644 index 0000000..6a71f5a --- /dev/null +++ b/flap/tests/01-Parsing/112-deref-2.good.parsing.hopix @@ -0,0 +1,2 @@ +let double = + ! (! x) \ No newline at end of file diff --git a/flap/tests/01-Parsing/113-deref-3.good.expected b/flap/tests/01-Parsing/113-deref-3.good.expected new file mode 100644 index 0000000..7f72862 --- /dev/null +++ b/flap/tests/01-Parsing/113-deref-3.good.expected @@ -0,0 +1 @@ +let main = (((! f)) 0); ((! (g 0))) diff --git a/flap/tests/01-Parsing/113-deref-3.good.parsing.hopix b/flap/tests/01-Parsing/113-deref-3.good.parsing.hopix new file mode 100644 index 0000000..3573a4c --- /dev/null +++ b/flap/tests/01-Parsing/113-deref-3.good.parsing.hopix @@ -0,0 +1 @@ +let main = !f (0); ! (g (0)) \ No newline at end of file diff --git a/flap/tests/01-Parsing/114-while-1.bad.expected b/flap/tests/01-Parsing/114-while-1.bad.expected new file mode 100644 index 0000000..d49e133 --- /dev/null +++ b/flap/tests/01-Parsing/114-while-1.bad.expected @@ -0,0 +1,2 @@ +Line 2, characters 8-12: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/114-while-1.bad.parsing.hopix b/flap/tests/01-Parsing/114-while-1.bad.parsing.hopix new file mode 100644 index 0000000..e93c6fd --- /dev/null +++ b/flap/tests/01-Parsing/114-while-1.bad.parsing.hopix @@ -0,0 +1,2 @@ +let main = + while True { nothing (0) } \ No newline at end of file diff --git a/flap/tests/01-Parsing/114-while-1.good.expected b/flap/tests/01-Parsing/114-while-1.good.expected new file mode 100644 index 0000000..dd6a89e --- /dev/null +++ b/flap/tests/01-Parsing/114-while-1.good.expected @@ -0,0 +1 @@ +let main = while (True) { nothing 0 } diff --git a/flap/tests/01-Parsing/114-while-1.good.parsing.hopix b/flap/tests/01-Parsing/114-while-1.good.parsing.hopix new file mode 100644 index 0000000..1906855 --- /dev/null +++ b/flap/tests/01-Parsing/114-while-1.good.parsing.hopix @@ -0,0 +1,2 @@ +let main = + while (True) { nothing (0) } \ No newline at end of file diff --git a/flap/tests/01-Parsing/115-while-2.bad.expected b/flap/tests/01-Parsing/115-while-2.bad.expected new file mode 100644 index 0000000..8e68832 --- /dev/null +++ b/flap/tests/01-Parsing/115-while-2.bad.expected @@ -0,0 +1,2 @@ +Line 4, characters 6-7: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/115-while-2.bad.parsing.hopix b/flap/tests/01-Parsing/115-while-2.bad.parsing.hopix new file mode 100644 index 0000000..2a0a5a0 --- /dev/null +++ b/flap/tests/01-Parsing/115-while-2.bad.parsing.hopix @@ -0,0 +1,5 @@ +let main = + while (True) { + while (!x >? 0) + x := !x - 1 + } \ No newline at end of file diff --git a/flap/tests/01-Parsing/115-while-2.good.expected b/flap/tests/01-Parsing/115-while-2.good.expected new file mode 100644 index 0000000..bca6f3e --- /dev/null +++ b/flap/tests/01-Parsing/115-while-2.good.expected @@ -0,0 +1,2 @@ +let main = + while (True) { while (((! x) >? 0)) { x := ((! x) - 1) } } diff --git a/flap/tests/01-Parsing/115-while-2.good.parsing.hopix b/flap/tests/01-Parsing/115-while-2.good.parsing.hopix new file mode 100644 index 0000000..4321253 --- /dev/null +++ b/flap/tests/01-Parsing/115-while-2.good.parsing.hopix @@ -0,0 +1,6 @@ +let main = + while (True) { + while (!x >? 0) { + x := !x - 1 + } + } \ No newline at end of file diff --git a/flap/tests/01-Parsing/116-for-1.bad.expected b/flap/tests/01-Parsing/116-for-1.bad.expected new file mode 100644 index 0000000..7a06983 --- /dev/null +++ b/flap/tests/01-Parsing/116-for-1.bad.expected @@ -0,0 +1,2 @@ +Line 2, characters 13-14: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/116-for-1.bad.parsing.hopix b/flap/tests/01-Parsing/116-for-1.bad.parsing.hopix new file mode 100644 index 0000000..84a0595 --- /dev/null +++ b/flap/tests/01-Parsing/116-for-1.bad.parsing.hopix @@ -0,0 +1,2 @@ +let main = + for i from 0 to 10 { nothing (0) } \ No newline at end of file diff --git a/flap/tests/01-Parsing/116-for-1.good.expected b/flap/tests/01-Parsing/116-for-1.good.expected new file mode 100644 index 0000000..4c9eec9 --- /dev/null +++ b/flap/tests/01-Parsing/116-for-1.good.expected @@ -0,0 +1 @@ +let main = for i from (0) to (10) { nothing 0 } diff --git a/flap/tests/01-Parsing/116-for-1.good.parsing.hopix b/flap/tests/01-Parsing/116-for-1.good.parsing.hopix new file mode 100644 index 0000000..cc92bb1 --- /dev/null +++ b/flap/tests/01-Parsing/116-for-1.good.parsing.hopix @@ -0,0 +1,2 @@ +let main = + for i from (0) to (10) { nothing (0) } \ No newline at end of file diff --git a/flap/tests/01-Parsing/117-for-2.bad.expected b/flap/tests/01-Parsing/117-for-2.bad.expected new file mode 100644 index 0000000..6eb3876 --- /dev/null +++ b/flap/tests/01-Parsing/117-for-2.bad.expected @@ -0,0 +1,2 @@ +Line 2, characters 16-18: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/117-for-2.bad.parsing.hopix b/flap/tests/01-Parsing/117-for-2.bad.parsing.hopix new file mode 100644 index 0000000..1b0f1f5 --- /dev/null +++ b/flap/tests/01-Parsing/117-for-2.bad.parsing.hopix @@ -0,0 +1,2 @@ +let main = + for x from (0 to 100) { y := x * 2 + !y } \ No newline at end of file diff --git a/flap/tests/01-Parsing/117-for-2.good.expected b/flap/tests/01-Parsing/117-for-2.good.expected new file mode 100644 index 0000000..b7621ab --- /dev/null +++ b/flap/tests/01-Parsing/117-for-2.good.expected @@ -0,0 +1 @@ +let main = for x from (0) to (100) { y := ((x * 2) + (! y)) } diff --git a/flap/tests/01-Parsing/117-for-2.good.parsing.hopix b/flap/tests/01-Parsing/117-for-2.good.parsing.hopix new file mode 100644 index 0000000..7fe5461 --- /dev/null +++ b/flap/tests/01-Parsing/117-for-2.good.parsing.hopix @@ -0,0 +1,2 @@ +let main = + for x from (0) to (100) { y := x * 2 + !y } \ No newline at end of file diff --git a/flap/tests/01-Parsing/118-do-while-1.bad.expected b/flap/tests/01-Parsing/118-do-while-1.bad.expected new file mode 100644 index 0000000..1a037fb --- /dev/null +++ b/flap/tests/01-Parsing/118-do-while-1.bad.expected @@ -0,0 +1,2 @@ +Line 2, characters 27-31: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/118-do-while-1.bad.parsing.hopix b/flap/tests/01-Parsing/118-do-while-1.bad.parsing.hopix new file mode 100644 index 0000000..24d81b9 --- /dev/null +++ b/flap/tests/01-Parsing/118-do-while-1.bad.parsing.hopix @@ -0,0 +1,2 @@ +let main = + do { nothing (0) } until True diff --git a/flap/tests/01-Parsing/118-do-while-1.good.expected b/flap/tests/01-Parsing/118-do-while-1.good.expected new file mode 100644 index 0000000..676d218 --- /dev/null +++ b/flap/tests/01-Parsing/118-do-while-1.good.expected @@ -0,0 +1 @@ +let main = (nothing 0); while (True) { nothing 0 } diff --git a/flap/tests/01-Parsing/118-do-while-1.good.parsing.hopix b/flap/tests/01-Parsing/118-do-while-1.good.parsing.hopix new file mode 100644 index 0000000..7b53d29 --- /dev/null +++ b/flap/tests/01-Parsing/118-do-while-1.good.parsing.hopix @@ -0,0 +1,2 @@ +let main = + do { nothing (0) } until (True) diff --git a/flap/tests/01-Parsing/119-do-while-2.bad.expected b/flap/tests/01-Parsing/119-do-while-2.bad.expected new file mode 100644 index 0000000..8e68832 --- /dev/null +++ b/flap/tests/01-Parsing/119-do-while-2.bad.expected @@ -0,0 +1,2 @@ +Line 4, characters 6-7: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/119-do-while-2.bad.parsing.hopix b/flap/tests/01-Parsing/119-do-while-2.bad.parsing.hopix new file mode 100644 index 0000000..bb891e6 --- /dev/null +++ b/flap/tests/01-Parsing/119-do-while-2.bad.parsing.hopix @@ -0,0 +1,6 @@ +let main = + do { + do + x := !x - 1 + while (!x >? 0) + } while (True) diff --git a/flap/tests/01-Parsing/119-do-while-2.good.expected b/flap/tests/01-Parsing/119-do-while-2.good.expected new file mode 100644 index 0000000..42c29fb --- /dev/null +++ b/flap/tests/01-Parsing/119-do-while-2.good.expected @@ -0,0 +1,3 @@ +let main = + while (((! x) >? 0)) { x := ((! x) - 1) }; + while (True) { while (((! x) >? 0)) { x := ((! x) - 1) } } diff --git a/flap/tests/01-Parsing/119-do-while-2.good.parsing.hopix b/flap/tests/01-Parsing/119-do-while-2.good.parsing.hopix new file mode 100644 index 0000000..a99dca9 --- /dev/null +++ b/flap/tests/01-Parsing/119-do-while-2.good.parsing.hopix @@ -0,0 +1,6 @@ +let main = + do { + while (!x >? 0) { + x := !x - 1 + } + } until (True) diff --git a/flap/tests/01-Parsing/12-lexer-label-id-1.bad.expected b/flap/tests/01-Parsing/12-lexer-label-id-1.bad.expected new file mode 100644 index 0000000..a81b254 --- /dev/null +++ b/flap/tests/01-Parsing/12-lexer-label-id-1.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 10-20: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/12-lexer-label-id-1.bad.parsing.hopix b/flap/tests/01-Parsing/12-lexer-label-id-1.bad.parsing.hopix new file mode 100644 index 0000000..9222bdb --- /dev/null +++ b/flap/tests/01-Parsing/12-lexer-label-id-1.bad.parsing.hopix @@ -0,0 +1 @@ +let x = t.Some_label \ No newline at end of file diff --git a/flap/tests/01-Parsing/12-lexer-label-id-1.good.expected b/flap/tests/01-Parsing/12-lexer-label-id-1.good.expected new file mode 100644 index 0000000..e8bf89b --- /dev/null +++ b/flap/tests/01-Parsing/12-lexer-label-id-1.good.expected @@ -0,0 +1 @@ +let x = t.some_label diff --git a/flap/tests/01-Parsing/12-lexer-label-id-1.good.parsing.hopix b/flap/tests/01-Parsing/12-lexer-label-id-1.good.parsing.hopix new file mode 100644 index 0000000..c8dcec7 --- /dev/null +++ b/flap/tests/01-Parsing/12-lexer-label-id-1.good.parsing.hopix @@ -0,0 +1 @@ +let x = t.some_label \ No newline at end of file diff --git a/flap/tests/01-Parsing/12-lexer-label-id-2.bad.expected b/flap/tests/01-Parsing/12-lexer-label-id-2.bad.expected new file mode 100644 index 0000000..4f69c79 --- /dev/null +++ b/flap/tests/01-Parsing/12-lexer-label-id-2.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 10-44: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/12-lexer-label-id-2.bad.parsing.hopix b/flap/tests/01-Parsing/12-lexer-label-id-2.bad.parsing.hopix new file mode 100644 index 0000000..6f12ecb --- /dev/null +++ b/flap/tests/01-Parsing/12-lexer-label-id-2.bad.parsing.hopix @@ -0,0 +1 @@ +let x = { Some_other_label_l33t_AND_GL0RI0US = 0 } \ No newline at end of file diff --git a/flap/tests/01-Parsing/12-lexer-label-id-2.good.expected b/flap/tests/01-Parsing/12-lexer-label-id-2.good.expected new file mode 100644 index 0000000..ae50301 --- /dev/null +++ b/flap/tests/01-Parsing/12-lexer-label-id-2.good.expected @@ -0,0 +1 @@ +let x = {some_other_label_l33t_AND_GL0RI0US = 0} diff --git a/flap/tests/01-Parsing/12-lexer-label-id-2.good.parsing.hopix b/flap/tests/01-Parsing/12-lexer-label-id-2.good.parsing.hopix new file mode 100644 index 0000000..1d025e2 --- /dev/null +++ b/flap/tests/01-Parsing/12-lexer-label-id-2.good.parsing.hopix @@ -0,0 +1 @@ +let x = { some_other_label_l33t_AND_GL0RI0US = 0 } \ No newline at end of file diff --git a/flap/tests/01-Parsing/13-type-con-id-1.bad.expected b/flap/tests/01-Parsing/13-type-con-id-1.bad.expected new file mode 100644 index 0000000..95f0a11 --- /dev/null +++ b/flap/tests/01-Parsing/13-type-con-id-1.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 5-13: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/13-type-con-id-1.bad.parsing.hopix b/flap/tests/01-Parsing/13-type-con-id-1.bad.parsing.hopix new file mode 100644 index 0000000..f0156c6 --- /dev/null +++ b/flap/tests/01-Parsing/13-type-con-id-1.bad.parsing.hopix @@ -0,0 +1 @@ +type Dungeons = CASTLE \ No newline at end of file diff --git a/flap/tests/01-Parsing/13-type-con-id-1.good.expected b/flap/tests/01-Parsing/13-type-con-id-1.good.expected new file mode 100644 index 0000000..d28a213 --- /dev/null +++ b/flap/tests/01-Parsing/13-type-con-id-1.good.expected @@ -0,0 +1 @@ +type dungeons = CASTLE diff --git a/flap/tests/01-Parsing/13-type-con-id-1.good.parsing.hopix b/flap/tests/01-Parsing/13-type-con-id-1.good.parsing.hopix new file mode 100644 index 0000000..6811098 --- /dev/null +++ b/flap/tests/01-Parsing/13-type-con-id-1.good.parsing.hopix @@ -0,0 +1 @@ +type dungeons = CASTLE \ No newline at end of file diff --git a/flap/tests/01-Parsing/14-type-con-id-2.bad.expected b/flap/tests/01-Parsing/14-type-con-id-2.bad.expected new file mode 100644 index 0000000..284a80a --- /dev/null +++ b/flap/tests/01-Parsing/14-type-con-id-2.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 27-33: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/14-type-con-id-2.bad.parsing.hopix b/flap/tests/01-Parsing/14-type-con-id-2.bad.parsing.hopix new file mode 100644 index 0000000..69134a2 --- /dev/null +++ b/flap/tests/01-Parsing/14-type-con-id-2.bad.parsing.hopix @@ -0,0 +1 @@ +type that_s_A_GREAT_TYPE = justKO diff --git a/flap/tests/01-Parsing/14-type-con-id-2.good.expected b/flap/tests/01-Parsing/14-type-con-id-2.good.expected new file mode 100644 index 0000000..6d4e347 --- /dev/null +++ b/flap/tests/01-Parsing/14-type-con-id-2.good.expected @@ -0,0 +1 @@ +type that_s_A_GREAT_TYPE = JustOK diff --git a/flap/tests/01-Parsing/14-type-con-id-2.good.parsing.hopix b/flap/tests/01-Parsing/14-type-con-id-2.good.parsing.hopix new file mode 100644 index 0000000..e222139 --- /dev/null +++ b/flap/tests/01-Parsing/14-type-con-id-2.good.parsing.hopix @@ -0,0 +1 @@ +type that_s_A_GREAT_TYPE = JustOK diff --git a/flap/tests/01-Parsing/15-int-literal-1.bad.expected b/flap/tests/01-Parsing/15-int-literal-1.bad.expected new file mode 100644 index 0000000..6d082d3 --- /dev/null +++ b/flap/tests/01-Parsing/15-int-literal-1.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 7-7: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/15-int-literal-1.bad.parsing.hopix b/flap/tests/01-Parsing/15-int-literal-1.bad.parsing.hopix new file mode 100644 index 0000000..8329071 --- /dev/null +++ b/flap/tests/01-Parsing/15-int-literal-1.bad.parsing.hopix @@ -0,0 +1 @@ +let x = \ No newline at end of file diff --git a/flap/tests/01-Parsing/15-int-literal-1.good.expected b/flap/tests/01-Parsing/15-int-literal-1.good.expected new file mode 100644 index 0000000..b6a2459 --- /dev/null +++ b/flap/tests/01-Parsing/15-int-literal-1.good.expected @@ -0,0 +1 @@ +let x = 0 diff --git a/flap/tests/01-Parsing/15-int-literal-1.good.parsing.hopix b/flap/tests/01-Parsing/15-int-literal-1.good.parsing.hopix new file mode 100644 index 0000000..b5368df --- /dev/null +++ b/flap/tests/01-Parsing/15-int-literal-1.good.parsing.hopix @@ -0,0 +1 @@ +let x = 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing/16-int-literal-2.bad.expected b/flap/tests/01-Parsing/16-int-literal-2.bad.expected new file mode 100644 index 0000000..e9d41a9 --- /dev/null +++ b/flap/tests/01-Parsing/16-int-literal-2.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 8-9: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/16-int-literal-2.bad.parsing.hopix b/flap/tests/01-Parsing/16-int-literal-2.bad.parsing.hopix new file mode 100644 index 0000000..24685ce --- /dev/null +++ b/flap/tests/01-Parsing/16-int-literal-2.bad.parsing.hopix @@ -0,0 +1 @@ +let x = --0 \ No newline at end of file diff --git a/flap/tests/01-Parsing/16-int-literal-2.good.expected b/flap/tests/01-Parsing/16-int-literal-2.good.expected new file mode 100644 index 0000000..b6a2459 --- /dev/null +++ b/flap/tests/01-Parsing/16-int-literal-2.good.expected @@ -0,0 +1 @@ +let x = 0 diff --git a/flap/tests/01-Parsing/16-int-literal-2.good.parsing.hopix b/flap/tests/01-Parsing/16-int-literal-2.good.parsing.hopix new file mode 100644 index 0000000..1d5f923 --- /dev/null +++ b/flap/tests/01-Parsing/16-int-literal-2.good.parsing.hopix @@ -0,0 +1 @@ +let x = -0 \ No newline at end of file diff --git a/flap/tests/01-Parsing/17-int-literal-3.bad.expected b/flap/tests/01-Parsing/17-int-literal-3.bad.expected new file mode 100644 index 0000000..b5997c4 --- /dev/null +++ b/flap/tests/01-Parsing/17-int-literal-3.bad.expected @@ -0,0 +1,2 @@ +Global Error (during parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/17-int-literal-3.bad.parsing.hopix b/flap/tests/01-Parsing/17-int-literal-3.bad.parsing.hopix new file mode 100644 index 0000000..cc4866f --- /dev/null +++ b/flap/tests/01-Parsing/17-int-literal-3.bad.parsing.hopix @@ -0,0 +1 @@ +let x = 1234432112341234123412324321232431 \ No newline at end of file diff --git a/flap/tests/01-Parsing/17-int-literal-3.good.expected b/flap/tests/01-Parsing/17-int-literal-3.good.expected new file mode 100644 index 0000000..07d6776 --- /dev/null +++ b/flap/tests/01-Parsing/17-int-literal-3.good.expected @@ -0,0 +1 @@ +let x = 12344321 diff --git a/flap/tests/01-Parsing/17-int-literal-3.good.parsing.hopix b/flap/tests/01-Parsing/17-int-literal-3.good.parsing.hopix new file mode 100644 index 0000000..921f22f --- /dev/null +++ b/flap/tests/01-Parsing/17-int-literal-3.good.parsing.hopix @@ -0,0 +1 @@ +let x = 12344321 \ No newline at end of file diff --git a/flap/tests/01-Parsing/18-int-literal-4.bad.expected b/flap/tests/01-Parsing/18-int-literal-4.bad.expected new file mode 100644 index 0000000..b5997c4 --- /dev/null +++ b/flap/tests/01-Parsing/18-int-literal-4.bad.expected @@ -0,0 +1,2 @@ +Global Error (during parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/18-int-literal-4.bad.parsing.hopix b/flap/tests/01-Parsing/18-int-literal-4.bad.parsing.hopix new file mode 100644 index 0000000..ee29e71 --- /dev/null +++ b/flap/tests/01-Parsing/18-int-literal-4.bad.parsing.hopix @@ -0,0 +1 @@ +let x = 0xcafeBABEBABEcafecafeBABE \ No newline at end of file diff --git a/flap/tests/01-Parsing/18-int-literal-4.good.expected b/flap/tests/01-Parsing/18-int-literal-4.good.expected new file mode 100644 index 0000000..c89ef90 --- /dev/null +++ b/flap/tests/01-Parsing/18-int-literal-4.good.expected @@ -0,0 +1 @@ +let x = 3405691582 diff --git a/flap/tests/01-Parsing/18-int-literal-4.good.parsing.hopix b/flap/tests/01-Parsing/18-int-literal-4.good.parsing.hopix new file mode 100644 index 0000000..6ec7aec --- /dev/null +++ b/flap/tests/01-Parsing/18-int-literal-4.good.parsing.hopix @@ -0,0 +1 @@ +let x = 0xcafeBABE \ No newline at end of file diff --git a/flap/tests/01-Parsing/19-int-literal-5.bad.expected b/flap/tests/01-Parsing/19-int-literal-5.bad.expected new file mode 100644 index 0000000..b5997c4 --- /dev/null +++ b/flap/tests/01-Parsing/19-int-literal-5.bad.expected @@ -0,0 +1,2 @@ +Global Error (during parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/19-int-literal-5.bad.parsing.hopix b/flap/tests/01-Parsing/19-int-literal-5.bad.parsing.hopix new file mode 100644 index 0000000..bcf2b6f --- /dev/null +++ b/flap/tests/01-Parsing/19-int-literal-5.bad.parsing.hopix @@ -0,0 +1 @@ +let x = 0o10101010101010101010101010101010101010101010101010101010101010101010101010101010 \ No newline at end of file diff --git a/flap/tests/01-Parsing/19-int-literal-5.good.expected b/flap/tests/01-Parsing/19-int-literal-5.good.expected new file mode 100644 index 0000000..7769519 --- /dev/null +++ b/flap/tests/01-Parsing/19-int-literal-5.good.expected @@ -0,0 +1 @@ +let x = 2130440 diff --git a/flap/tests/01-Parsing/19-int-literal-5.good.parsing.hopix b/flap/tests/01-Parsing/19-int-literal-5.good.parsing.hopix new file mode 100644 index 0000000..e314b22 --- /dev/null +++ b/flap/tests/01-Parsing/19-int-literal-5.good.parsing.hopix @@ -0,0 +1 @@ +let x = 0o10101010 \ No newline at end of file diff --git a/flap/tests/01-Parsing/20-int-literal-6.bad.expected b/flap/tests/01-Parsing/20-int-literal-6.bad.expected new file mode 100644 index 0000000..b5997c4 --- /dev/null +++ b/flap/tests/01-Parsing/20-int-literal-6.bad.expected @@ -0,0 +1,2 @@ +Global Error (during parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/20-int-literal-6.bad.parsing.hopix b/flap/tests/01-Parsing/20-int-literal-6.bad.parsing.hopix new file mode 100644 index 0000000..48963c2 --- /dev/null +++ b/flap/tests/01-Parsing/20-int-literal-6.bad.parsing.hopix @@ -0,0 +1 @@ +let x = 0xffffffffffffffffffffffffffffffffffffffff \ No newline at end of file diff --git a/flap/tests/01-Parsing/20-int-literal-6.good.expected b/flap/tests/01-Parsing/20-int-literal-6.good.expected new file mode 100644 index 0000000..eb881b8 --- /dev/null +++ b/flap/tests/01-Parsing/20-int-literal-6.good.expected @@ -0,0 +1 @@ +let x = 2739128 diff --git a/flap/tests/01-Parsing/20-int-literal-6.good.parsing.hopix b/flap/tests/01-Parsing/20-int-literal-6.good.parsing.hopix new file mode 100644 index 0000000..b6c9ea2 --- /dev/null +++ b/flap/tests/01-Parsing/20-int-literal-6.good.parsing.hopix @@ -0,0 +1 @@ +let x = 0o12345670 \ No newline at end of file diff --git a/flap/tests/01-Parsing/21-char-literal-1.bad.expected b/flap/tests/01-Parsing/21-char-literal-1.bad.expected new file mode 100644 index 0000000..b55d156 --- /dev/null +++ b/flap/tests/01-Parsing/21-char-literal-1.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 8-9: Error (during lexing) + unexpected character. diff --git a/flap/tests/01-Parsing/21-char-literal-1.bad.parsing.hopix b/flap/tests/01-Parsing/21-char-literal-1.bad.parsing.hopix new file mode 100644 index 0000000..759a1e2 --- /dev/null +++ b/flap/tests/01-Parsing/21-char-literal-1.bad.parsing.hopix @@ -0,0 +1 @@ +let c = '' \ No newline at end of file diff --git a/flap/tests/01-Parsing/21-char-literal-1.good.expected b/flap/tests/01-Parsing/21-char-literal-1.good.expected new file mode 100644 index 0000000..360f4d9 --- /dev/null +++ b/flap/tests/01-Parsing/21-char-literal-1.good.expected @@ -0,0 +1 @@ +let c = 'a' diff --git a/flap/tests/01-Parsing/21-char-literal-1.good.parsing.hopix b/flap/tests/01-Parsing/21-char-literal-1.good.parsing.hopix new file mode 100644 index 0000000..67e678f --- /dev/null +++ b/flap/tests/01-Parsing/21-char-literal-1.good.parsing.hopix @@ -0,0 +1 @@ +let c = 'a' \ No newline at end of file diff --git a/flap/tests/01-Parsing/22-char-literal-2.bad.expected b/flap/tests/01-Parsing/22-char-literal-2.bad.expected new file mode 100644 index 0000000..f1e915d --- /dev/null +++ b/flap/tests/01-Parsing/22-char-literal-2.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 8-14: Error (during lexing) + diff --git a/flap/tests/01-Parsing/22-char-literal-2.bad.parsing.hopix b/flap/tests/01-Parsing/22-char-literal-2.bad.parsing.hopix new file mode 100644 index 0000000..16c9114 --- /dev/null +++ b/flap/tests/01-Parsing/22-char-literal-2.bad.parsing.hopix @@ -0,0 +1 @@ +let x = '\300' \ No newline at end of file diff --git a/flap/tests/01-Parsing/22-char-literal-2.good.expected b/flap/tests/01-Parsing/22-char-literal-2.good.expected new file mode 100644 index 0000000..c8065bf --- /dev/null +++ b/flap/tests/01-Parsing/22-char-literal-2.good.expected @@ -0,0 +1 @@ +let x = '\000' diff --git a/flap/tests/01-Parsing/22-char-literal-2.good.parsing.hopix b/flap/tests/01-Parsing/22-char-literal-2.good.parsing.hopix new file mode 100644 index 0000000..a3c8be5 --- /dev/null +++ b/flap/tests/01-Parsing/22-char-literal-2.good.parsing.hopix @@ -0,0 +1 @@ +let x = '\000' \ No newline at end of file diff --git a/flap/tests/01-Parsing/23-char-literal-3.bad.expected b/flap/tests/01-Parsing/23-char-literal-3.bad.expected new file mode 100644 index 0000000..b55d156 --- /dev/null +++ b/flap/tests/01-Parsing/23-char-literal-3.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 8-9: Error (during lexing) + unexpected character. diff --git a/flap/tests/01-Parsing/23-char-literal-3.bad.parsing.hopix b/flap/tests/01-Parsing/23-char-literal-3.bad.parsing.hopix new file mode 100644 index 0000000..00c0ac7 --- /dev/null +++ b/flap/tests/01-Parsing/23-char-literal-3.bad.parsing.hopix @@ -0,0 +1 @@ +let x = '\p' \ No newline at end of file diff --git a/flap/tests/01-Parsing/23-char-literal-3.good.expected b/flap/tests/01-Parsing/23-char-literal-3.good.expected new file mode 100644 index 0000000..6fe8a65 --- /dev/null +++ b/flap/tests/01-Parsing/23-char-literal-3.good.expected @@ -0,0 +1 @@ +let x = '\t' diff --git a/flap/tests/01-Parsing/23-char-literal-3.good.parsing.hopix b/flap/tests/01-Parsing/23-char-literal-3.good.parsing.hopix new file mode 100644 index 0000000..0219bf7 --- /dev/null +++ b/flap/tests/01-Parsing/23-char-literal-3.good.parsing.hopix @@ -0,0 +1 @@ +let x = '\t' \ No newline at end of file diff --git a/flap/tests/01-Parsing/24-char-literal-4.bad.expected b/flap/tests/01-Parsing/24-char-literal-4.bad.expected new file mode 100644 index 0000000..b55d156 --- /dev/null +++ b/flap/tests/01-Parsing/24-char-literal-4.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 8-9: Error (during lexing) + unexpected character. diff --git a/flap/tests/01-Parsing/24-char-literal-4.bad.parsing.hopix b/flap/tests/01-Parsing/24-char-literal-4.bad.parsing.hopix new file mode 100644 index 0000000..ab197e1 --- /dev/null +++ b/flap/tests/01-Parsing/24-char-literal-4.bad.parsing.hopix @@ -0,0 +1 @@ +let x = '\0z64' \ No newline at end of file diff --git a/flap/tests/01-Parsing/24-char-literal-4.good.expected b/flap/tests/01-Parsing/24-char-literal-4.good.expected new file mode 100644 index 0000000..b1302a0 --- /dev/null +++ b/flap/tests/01-Parsing/24-char-literal-4.good.expected @@ -0,0 +1 @@ +let x = 'd' diff --git a/flap/tests/01-Parsing/24-char-literal-4.good.parsing.hopix b/flap/tests/01-Parsing/24-char-literal-4.good.parsing.hopix new file mode 100644 index 0000000..0119112 --- /dev/null +++ b/flap/tests/01-Parsing/24-char-literal-4.good.parsing.hopix @@ -0,0 +1 @@ +let x = '\0x64' \ No newline at end of file diff --git a/flap/tests/01-Parsing/25-char-literal-5.bad.expected b/flap/tests/01-Parsing/25-char-literal-5.bad.expected new file mode 100644 index 0000000..b55d156 --- /dev/null +++ b/flap/tests/01-Parsing/25-char-literal-5.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 8-9: Error (during lexing) + unexpected character. diff --git a/flap/tests/01-Parsing/25-char-literal-5.bad.parsing.hopix b/flap/tests/01-Parsing/25-char-literal-5.bad.parsing.hopix new file mode 100644 index 0000000..140d537 --- /dev/null +++ b/flap/tests/01-Parsing/25-char-literal-5.bad.parsing.hopix @@ -0,0 +1 @@ +let x = ''' \ No newline at end of file diff --git a/flap/tests/01-Parsing/25-char-literal-5.good.expected b/flap/tests/01-Parsing/25-char-literal-5.good.expected new file mode 100644 index 0000000..14e2055 --- /dev/null +++ b/flap/tests/01-Parsing/25-char-literal-5.good.expected @@ -0,0 +1 @@ +let x = '\'' diff --git a/flap/tests/01-Parsing/25-char-literal-5.good.parsing.hopix b/flap/tests/01-Parsing/25-char-literal-5.good.parsing.hopix new file mode 100644 index 0000000..8eb8b25 --- /dev/null +++ b/flap/tests/01-Parsing/25-char-literal-5.good.parsing.hopix @@ -0,0 +1 @@ +let x = '\'' \ No newline at end of file diff --git a/flap/tests/01-Parsing/26-char-literal-6.bad.expected b/flap/tests/01-Parsing/26-char-literal-6.bad.expected new file mode 100644 index 0000000..b55d156 --- /dev/null +++ b/flap/tests/01-Parsing/26-char-literal-6.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 8-9: Error (during lexing) + unexpected character. diff --git a/flap/tests/01-Parsing/26-char-literal-6.bad.parsing.hopix b/flap/tests/01-Parsing/26-char-literal-6.bad.parsing.hopix new file mode 100644 index 0000000..c8621f3 --- /dev/null +++ b/flap/tests/01-Parsing/26-char-literal-6.bad.parsing.hopix @@ -0,0 +1 @@ +let x = '\\r' diff --git a/flap/tests/01-Parsing/26-char-literal-6.good.expected b/flap/tests/01-Parsing/26-char-literal-6.good.expected new file mode 100644 index 0000000..1e1287d --- /dev/null +++ b/flap/tests/01-Parsing/26-char-literal-6.good.expected @@ -0,0 +1,2 @@ +let x = '\r' +let y = '\b' diff --git a/flap/tests/01-Parsing/26-char-literal-6.good.parsing.hopix b/flap/tests/01-Parsing/26-char-literal-6.good.parsing.hopix new file mode 100644 index 0000000..d135541 --- /dev/null +++ b/flap/tests/01-Parsing/26-char-literal-6.good.parsing.hopix @@ -0,0 +1,2 @@ +let x = '\r' +let y = '\b' \ No newline at end of file diff --git a/flap/tests/01-Parsing/27-string-literal-1.bad.expected b/flap/tests/01-Parsing/27-string-literal-1.bad.expected new file mode 100644 index 0000000..1325f08 --- /dev/null +++ b/flap/tests/01-Parsing/27-string-literal-1.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 71-71: Error (during lexing) + Unterminated string. diff --git a/flap/tests/01-Parsing/27-string-literal-1.bad.parsing.hopix b/flap/tests/01-Parsing/27-string-literal-1.bad.parsing.hopix new file mode 100644 index 0000000..d6a30bd --- /dev/null +++ b/flap/tests/01-Parsing/27-string-literal-1.bad.parsing.hopix @@ -0,0 +1 @@ +let s = " This is exciting. No, not exciting. What do I mean? Worrying. \ No newline at end of file diff --git a/flap/tests/01-Parsing/27-string-literal-1.good.expected b/flap/tests/01-Parsing/27-string-literal-1.good.expected new file mode 100644 index 0000000..ad1ac81 --- /dev/null +++ b/flap/tests/01-Parsing/27-string-literal-1.good.expected @@ -0,0 +1,2 @@ +let s = + " This is exciting. No, not exciting. What do I mean? Worrying." diff --git a/flap/tests/01-Parsing/27-string-literal-1.good.parsing.hopix b/flap/tests/01-Parsing/27-string-literal-1.good.parsing.hopix new file mode 100644 index 0000000..0b8e3c9 --- /dev/null +++ b/flap/tests/01-Parsing/27-string-literal-1.good.parsing.hopix @@ -0,0 +1 @@ +let s = " This is exciting. No, not exciting. What do I mean? Worrying." \ No newline at end of file diff --git a/flap/tests/01-Parsing/28-string-literal-2.bad.expected b/flap/tests/01-Parsing/28-string-literal-2.bad.expected new file mode 100644 index 0000000..1b19126 --- /dev/null +++ b/flap/tests/01-Parsing/28-string-literal-2.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 24-25: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/28-string-literal-2.bad.parsing.hopix b/flap/tests/01-Parsing/28-string-literal-2.bad.parsing.hopix new file mode 100644 index 0000000..8ad0098 --- /dev/null +++ b/flap/tests/01-Parsing/28-string-literal-2.bad.parsing.hopix @@ -0,0 +1 @@ +let s = "\nDon't "panic.\nNot the end of the world.\nWell, it could be the end of the world but one thing at a time.\n" \ No newline at end of file diff --git a/flap/tests/01-Parsing/28-string-literal-2.good.expected b/flap/tests/01-Parsing/28-string-literal-2.good.expected new file mode 100644 index 0000000..68e7d10 --- /dev/null +++ b/flap/tests/01-Parsing/28-string-literal-2.good.expected @@ -0,0 +1,2 @@ +let s = + "\nDon't panic.\nNot the end of the world.\nWell, it could be the end of the world but one thing at a time.\n" diff --git a/flap/tests/01-Parsing/28-string-literal-2.good.parsing.hopix b/flap/tests/01-Parsing/28-string-literal-2.good.parsing.hopix new file mode 100644 index 0000000..6ea39ca --- /dev/null +++ b/flap/tests/01-Parsing/28-string-literal-2.good.parsing.hopix @@ -0,0 +1 @@ +let s = "\nDon't panic.\nNot the end of the world.\nWell, it could be the end of the world but one thing at a time.\n" \ No newline at end of file diff --git a/flap/tests/01-Parsing/29-string-literal-3.bad.expected b/flap/tests/01-Parsing/29-string-literal-3.bad.expected new file mode 100644 index 0000000..a5cedba --- /dev/null +++ b/flap/tests/01-Parsing/29-string-literal-3.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 4-5: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/29-string-literal-3.bad.parsing.hopix b/flap/tests/01-Parsing/29-string-literal-3.bad.parsing.hopix new file mode 100644 index 0000000..6399964 --- /dev/null +++ b/flap/tests/01-Parsing/29-string-literal-3.bad.parsing.hopix @@ -0,0 +1 @@ +let = "Python\b\b\b\b\b\bOCaml rocks!\n" \ No newline at end of file diff --git a/flap/tests/01-Parsing/29-string-literal-3.good.expected b/flap/tests/01-Parsing/29-string-literal-3.good.expected new file mode 100644 index 0000000..db9815b --- /dev/null +++ b/flap/tests/01-Parsing/29-string-literal-3.good.expected @@ -0,0 +1 @@ +let s = "Python\b\b\b\b\b\bOCaml rocks!\n" diff --git a/flap/tests/01-Parsing/29-string-literal-3.good.parsing.hopix b/flap/tests/01-Parsing/29-string-literal-3.good.parsing.hopix new file mode 100644 index 0000000..5c2d21f --- /dev/null +++ b/flap/tests/01-Parsing/29-string-literal-3.good.parsing.hopix @@ -0,0 +1 @@ +let s = "Python\b\b\b\b\b\bOCaml rocks!\n" \ No newline at end of file diff --git a/flap/tests/01-Parsing/30-string-literal-4.bad.expected b/flap/tests/01-Parsing/30-string-literal-4.bad.expected new file mode 100644 index 0000000..7328421 --- /dev/null +++ b/flap/tests/01-Parsing/30-string-literal-4.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 60-61: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/30-string-literal-4.bad.parsing.hopix b/flap/tests/01-Parsing/30-string-literal-4.bad.parsing.hopix new file mode 100644 index 0000000..da6c948 --- /dev/null +++ b/flap/tests/01-Parsing/30-string-literal-4.bad.parsing.hopix @@ -0,0 +1 @@ +let s "This one is a \"Nightmare\"! \0x4A \\ \r \0x2e ' \032" \ No newline at end of file diff --git a/flap/tests/01-Parsing/30-string-literal-4.good.expected b/flap/tests/01-Parsing/30-string-literal-4.good.expected new file mode 100644 index 0000000..bd63144 --- /dev/null +++ b/flap/tests/01-Parsing/30-string-literal-4.good.expected @@ -0,0 +1 @@ +let s = "This one is a \"Nightmare\"! J \\ \r . ' " diff --git a/flap/tests/01-Parsing/30-string-literal-4.good.parsing.hopix b/flap/tests/01-Parsing/30-string-literal-4.good.parsing.hopix new file mode 100644 index 0000000..e438ccd --- /dev/null +++ b/flap/tests/01-Parsing/30-string-literal-4.good.parsing.hopix @@ -0,0 +1 @@ +let s = "This one is a \"Nightmare\"! \0x4A \\ \r \0x2e ' \032" \ No newline at end of file diff --git a/flap/tests/01-Parsing/31-type-definition-sum-1.bad.expected b/flap/tests/01-Parsing/31-type-definition-sum-1.bad.expected new file mode 100644 index 0000000..e5bd27c --- /dev/null +++ b/flap/tests/01-Parsing/31-type-definition-sum-1.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 11-11: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/31-type-definition-sum-1.bad.parsing.hopix b/flap/tests/01-Parsing/31-type-definition-sum-1.bad.parsing.hopix new file mode 100644 index 0000000..7e3bde7 --- /dev/null +++ b/flap/tests/01-Parsing/31-type-definition-sum-1.bad.parsing.hopix @@ -0,0 +1 @@ +type unit = \ No newline at end of file diff --git a/flap/tests/01-Parsing/31-type-definition-sum-1.good.expected b/flap/tests/01-Parsing/31-type-definition-sum-1.good.expected new file mode 100644 index 0000000..5d00f0b --- /dev/null +++ b/flap/tests/01-Parsing/31-type-definition-sum-1.good.expected @@ -0,0 +1 @@ +type unit = Unit diff --git a/flap/tests/01-Parsing/31-type-definition-sum-1.good.parsing.hopix b/flap/tests/01-Parsing/31-type-definition-sum-1.good.parsing.hopix new file mode 100644 index 0000000..9922db8 --- /dev/null +++ b/flap/tests/01-Parsing/31-type-definition-sum-1.good.parsing.hopix @@ -0,0 +1 @@ +type unit = Unit \ No newline at end of file diff --git a/flap/tests/01-Parsing/32-type-definition-sum-2.bad.expected b/flap/tests/01-Parsing/32-type-definition-sum-2.bad.expected new file mode 100644 index 0000000..d8dae9c --- /dev/null +++ b/flap/tests/01-Parsing/32-type-definition-sum-2.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 26-26: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/32-type-definition-sum-2.bad.parsing.hopix b/flap/tests/01-Parsing/32-type-definition-sum-2.bad.parsing.hopix new file mode 100644 index 0000000..c9c8605 --- /dev/null +++ b/flap/tests/01-Parsing/32-type-definition-sum-2.bad.parsing.hopix @@ -0,0 +1 @@ +type color = Red | Black | \ No newline at end of file diff --git a/flap/tests/01-Parsing/32-type-definition-sum-2.good.expected b/flap/tests/01-Parsing/32-type-definition-sum-2.good.expected new file mode 100644 index 0000000..15f2c38 --- /dev/null +++ b/flap/tests/01-Parsing/32-type-definition-sum-2.good.expected @@ -0,0 +1 @@ +type color = Red | Black | White diff --git a/flap/tests/01-Parsing/32-type-definition-sum-2.good.parsing.hopix b/flap/tests/01-Parsing/32-type-definition-sum-2.good.parsing.hopix new file mode 100644 index 0000000..a649e91 --- /dev/null +++ b/flap/tests/01-Parsing/32-type-definition-sum-2.good.parsing.hopix @@ -0,0 +1 @@ +type color = Red | Black | White \ No newline at end of file diff --git a/flap/tests/01-Parsing/33-type-definition-sum-3.bad.expected b/flap/tests/01-Parsing/33-type-definition-sum-3.bad.expected new file mode 100644 index 0000000..f33d742 --- /dev/null +++ b/flap/tests/01-Parsing/33-type-definition-sum-3.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 12-13: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/33-type-definition-sum-3.bad.parsing.hopix b/flap/tests/01-Parsing/33-type-definition-sum-3.bad.parsing.hopix new file mode 100644 index 0000000..2147b71 --- /dev/null +++ b/flap/tests/01-Parsing/33-type-definition-sum-3.bad.parsing.hopix @@ -0,0 +1 @@ +type option = None | Some (A) \ No newline at end of file diff --git a/flap/tests/01-Parsing/33-type-definition-sum-3.good.expected b/flap/tests/01-Parsing/33-type-definition-sum-3.good.expected new file mode 100644 index 0000000..90669ff --- /dev/null +++ b/flap/tests/01-Parsing/33-type-definition-sum-3.good.expected @@ -0,0 +1 @@ +type option<`a> = None | Some (`a) diff --git a/flap/tests/01-Parsing/33-type-definition-sum-3.good.parsing.hopix b/flap/tests/01-Parsing/33-type-definition-sum-3.good.parsing.hopix new file mode 100644 index 0000000..7cfdbe6 --- /dev/null +++ b/flap/tests/01-Parsing/33-type-definition-sum-3.good.parsing.hopix @@ -0,0 +1 @@ +type option<`a> = None | Some (`a) \ No newline at end of file diff --git a/flap/tests/01-Parsing/34-type-definition-sum-4.bad.expected b/flap/tests/01-Parsing/34-type-definition-sum-4.bad.expected new file mode 100644 index 0000000..76bf247 --- /dev/null +++ b/flap/tests/01-Parsing/34-type-definition-sum-4.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 13-15: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/34-type-definition-sum-4.bad.parsing.hopix b/flap/tests/01-Parsing/34-type-definition-sum-4.bad.parsing.hopix new file mode 100644 index 0000000..7d90d94 --- /dev/null +++ b/flap/tests/01-Parsing/34-type-definition-sum-4.bad.parsing.hopix @@ -0,0 +1 @@ +type pair<`a `b> = Pair(`a, `b) \ No newline at end of file diff --git a/flap/tests/01-Parsing/34-type-definition-sum-4.good.expected b/flap/tests/01-Parsing/34-type-definition-sum-4.good.expected new file mode 100644 index 0000000..44ce62c --- /dev/null +++ b/flap/tests/01-Parsing/34-type-definition-sum-4.good.expected @@ -0,0 +1 @@ +type pair<`a, `b> = Pair (`a, `b) diff --git a/flap/tests/01-Parsing/34-type-definition-sum-4.good.parsing.hopix b/flap/tests/01-Parsing/34-type-definition-sum-4.good.parsing.hopix new file mode 100644 index 0000000..7c8b5e9 --- /dev/null +++ b/flap/tests/01-Parsing/34-type-definition-sum-4.good.parsing.hopix @@ -0,0 +1 @@ +type pair<`a, `b> = Pair(`a, `b) \ No newline at end of file diff --git a/flap/tests/01-Parsing/35-type-definition-sum-5.bad.expected b/flap/tests/01-Parsing/35-type-definition-sum-5.bad.expected new file mode 100644 index 0000000..653fc59 --- /dev/null +++ b/flap/tests/01-Parsing/35-type-definition-sum-5.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 20-21: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/35-type-definition-sum-5.bad.parsing.hopix b/flap/tests/01-Parsing/35-type-definition-sum-5.bad.parsing.hopix new file mode 100644 index 0000000..504e69f --- /dev/null +++ b/flap/tests/01-Parsing/35-type-definition-sum-5.bad.parsing.hopix @@ -0,0 +1 @@ +type triple<`a, `b, > = Triple (`a, `b, `c) \ No newline at end of file diff --git a/flap/tests/01-Parsing/35-type-definition-sum-5.good.expected b/flap/tests/01-Parsing/35-type-definition-sum-5.good.expected new file mode 100644 index 0000000..de8c33a --- /dev/null +++ b/flap/tests/01-Parsing/35-type-definition-sum-5.good.expected @@ -0,0 +1 @@ +type triple<`a, `b, `c> = Triple (`a, `b, `c) diff --git a/flap/tests/01-Parsing/35-type-definition-sum-5.good.parsing.hopix b/flap/tests/01-Parsing/35-type-definition-sum-5.good.parsing.hopix new file mode 100644 index 0000000..2900644 --- /dev/null +++ b/flap/tests/01-Parsing/35-type-definition-sum-5.good.parsing.hopix @@ -0,0 +1 @@ +type triple<`a, `b, `c> = Triple (`a, `b, `c) \ No newline at end of file diff --git a/flap/tests/01-Parsing/36-type-definition-sum-6.bad.expected b/flap/tests/01-Parsing/36-type-definition-sum-6.bad.expected new file mode 100644 index 0000000..23d88be --- /dev/null +++ b/flap/tests/01-Parsing/36-type-definition-sum-6.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 9-10: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/36-type-definition-sum-6.bad.parsing.hopix b/flap/tests/01-Parsing/36-type-definition-sum-6.bad.parsing.hopix new file mode 100644 index 0000000..a26d526 --- /dev/null +++ b/flap/tests/01-Parsing/36-type-definition-sum-6.bad.parsing.hopix @@ -0,0 +1 @@ +type list[`a] = Nil | Cons (`a, list[`a]) \ No newline at end of file diff --git a/flap/tests/01-Parsing/36-type-definition-sum-6.good.expected b/flap/tests/01-Parsing/36-type-definition-sum-6.good.expected new file mode 100644 index 0000000..def13b9 --- /dev/null +++ b/flap/tests/01-Parsing/36-type-definition-sum-6.good.expected @@ -0,0 +1 @@ +type list<`a> = Nil | Cons (`a, list<`a>) diff --git a/flap/tests/01-Parsing/36-type-definition-sum-6.good.parsing.hopix b/flap/tests/01-Parsing/36-type-definition-sum-6.good.parsing.hopix new file mode 100644 index 0000000..594b113 --- /dev/null +++ b/flap/tests/01-Parsing/36-type-definition-sum-6.good.parsing.hopix @@ -0,0 +1 @@ +type list<`a> = Nil | Cons (`a, list<`a>) \ No newline at end of file diff --git a/flap/tests/01-Parsing/37-type-definition-sum-7.bad.expected b/flap/tests/01-Parsing/37-type-definition-sum-7.bad.expected new file mode 100644 index 0000000..f405ee0 --- /dev/null +++ b/flap/tests/01-Parsing/37-type-definition-sum-7.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 49-50: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/37-type-definition-sum-7.bad.parsing.hopix b/flap/tests/01-Parsing/37-type-definition-sum-7.bad.parsing.hopix new file mode 100644 index 0000000..4b5f962 --- /dev/null +++ b/flap/tests/01-Parsing/37-type-definition-sum-7.bad.parsing.hopix @@ -0,0 +1 @@ +type closure<`env, `a, `b> = Closure (`env, `env => `a => `b) \ No newline at end of file diff --git a/flap/tests/01-Parsing/37-type-definition-sum-7.good.expected b/flap/tests/01-Parsing/37-type-definition-sum-7.good.expected new file mode 100644 index 0000000..ad7fc89 --- /dev/null +++ b/flap/tests/01-Parsing/37-type-definition-sum-7.good.expected @@ -0,0 +1,3 @@ +type closure<`env, `a, `b> = + + Closure (`env, `env -> (`a -> `b)) diff --git a/flap/tests/01-Parsing/37-type-definition-sum-7.good.parsing.hopix b/flap/tests/01-Parsing/37-type-definition-sum-7.good.parsing.hopix new file mode 100644 index 0000000..d0551dd --- /dev/null +++ b/flap/tests/01-Parsing/37-type-definition-sum-7.good.parsing.hopix @@ -0,0 +1 @@ +type closure<`env, `a, `b> = Closure (`env, `env -> `a -> `b) \ No newline at end of file diff --git a/flap/tests/01-Parsing/38-type-definition-record-1.bad.expected b/flap/tests/01-Parsing/38-type-definition-record-1.bad.expected new file mode 100644 index 0000000..3d7bbf9 --- /dev/null +++ b/flap/tests/01-Parsing/38-type-definition-record-1.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 25-26: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/38-type-definition-record-1.bad.parsing.hopix b/flap/tests/01-Parsing/38-type-definition-record-1.bad.parsing.hopix new file mode 100644 index 0000000..6fd7bd8 --- /dev/null +++ b/flap/tests/01-Parsing/38-type-definition-record-1.bad.parsing.hopix @@ -0,0 +1 @@ +type people = { age : int; name : string; firstname : string } \ No newline at end of file diff --git a/flap/tests/01-Parsing/38-type-definition-record-1.good.expected b/flap/tests/01-Parsing/38-type-definition-record-1.good.expected new file mode 100644 index 0000000..21433bf --- /dev/null +++ b/flap/tests/01-Parsing/38-type-definition-record-1.good.expected @@ -0,0 +1,3 @@ +type people = + { + age : int , name : string , firstname : string } diff --git a/flap/tests/01-Parsing/38-type-definition-record-1.good.parsing.hopix b/flap/tests/01-Parsing/38-type-definition-record-1.good.parsing.hopix new file mode 100644 index 0000000..63cebd7 --- /dev/null +++ b/flap/tests/01-Parsing/38-type-definition-record-1.good.parsing.hopix @@ -0,0 +1 @@ +type people = { age : int, name : string, firstname : string } \ No newline at end of file diff --git a/flap/tests/01-Parsing/39-type-definition-record-2.bad.expected b/flap/tests/01-Parsing/39-type-definition-record-2.bad.expected new file mode 100644 index 0000000..da37b0f --- /dev/null +++ b/flap/tests/01-Parsing/39-type-definition-record-2.bad.expected @@ -0,0 +1,2 @@ +Line 2, characters 27-28: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/39-type-definition-record-2.bad.parsing.hopix b/flap/tests/01-Parsing/39-type-definition-record-2.bad.parsing.hopix new file mode 100644 index 0000000..995aff8 --- /dev/null +++ b/flap/tests/01-Parsing/39-type-definition-record-2.bad.parsing.hopix @@ -0,0 +1,2 @@ +type position = { offset : int } +type located<`a> = { value = `a, position = position } \ No newline at end of file diff --git a/flap/tests/01-Parsing/39-type-definition-record-2.good.expected b/flap/tests/01-Parsing/39-type-definition-record-2.good.expected new file mode 100644 index 0000000..8d9fb7d --- /dev/null +++ b/flap/tests/01-Parsing/39-type-definition-record-2.good.expected @@ -0,0 +1,6 @@ +type position = + { + offset : int } +type located<`a> = + { + value : `a , position : position } diff --git a/flap/tests/01-Parsing/39-type-definition-record-2.good.parsing.hopix b/flap/tests/01-Parsing/39-type-definition-record-2.good.parsing.hopix new file mode 100644 index 0000000..509f588 --- /dev/null +++ b/flap/tests/01-Parsing/39-type-definition-record-2.good.parsing.hopix @@ -0,0 +1,2 @@ +type position = { offset : int } +type located<`a> = { value : `a, position : position } \ No newline at end of file diff --git a/flap/tests/01-Parsing/40-type-definition-record-3.bad.expected b/flap/tests/01-Parsing/40-type-definition-record-3.bad.expected new file mode 100644 index 0000000..30f8531 --- /dev/null +++ b/flap/tests/01-Parsing/40-type-definition-record-3.bad.expected @@ -0,0 +1,2 @@ +Line 4, characters 12-13: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/40-type-definition-record-3.bad.parsing.hopix b/flap/tests/01-Parsing/40-type-definition-record-3.bad.parsing.hopix new file mode 100644 index 0000000..f3ff3ce --- /dev/null +++ b/flap/tests/01-Parsing/40-type-definition-record-3.bad.parsing.hopix @@ -0,0 +1,8 @@ +type bool = True | False + +type collection<`t, `a> = { + empty : `t; + add : `a * `t -> `t; + map : (`a -> `a) -> `t -> `t; + split : (`a -> bool) -> `t * `t +} \ No newline at end of file diff --git a/flap/tests/01-Parsing/40-type-definition-record-3.good.expected b/flap/tests/01-Parsing/40-type-definition-record-3.good.expected new file mode 100644 index 0000000..2f0b7a4 --- /dev/null +++ b/flap/tests/01-Parsing/40-type-definition-record-3.good.expected @@ -0,0 +1,10 @@ +type bool = + + True | False +type collection<`t, `a> = + { + empty : `t + , add : (`a * `t) -> `t + , map : (`a -> `a) -> (`t -> `t) + , split : (`a -> bool) -> (`t * `t) + } diff --git a/flap/tests/01-Parsing/40-type-definition-record-3.good.parsing.hopix b/flap/tests/01-Parsing/40-type-definition-record-3.good.parsing.hopix new file mode 100644 index 0000000..c8cc117 --- /dev/null +++ b/flap/tests/01-Parsing/40-type-definition-record-3.good.parsing.hopix @@ -0,0 +1,8 @@ +type bool = True | False + +type collection<`t, `a> = { + empty : `t, + add : `a * `t -> `t, + map : (`a -> `a) -> `t -> `t, + split : (`a -> bool) -> `t * `t +} \ No newline at end of file diff --git a/flap/tests/01-Parsing/41-external-definition-1.bad.expected b/flap/tests/01-Parsing/41-external-definition-1.bad.expected new file mode 100644 index 0000000..0326ca1 --- /dev/null +++ b/flap/tests/01-Parsing/41-external-definition-1.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 31-31: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/41-external-definition-1.bad.parsing.hopix b/flap/tests/01-Parsing/41-external-definition-1.bad.parsing.hopix new file mode 100644 index 0000000..104250c --- /dev/null +++ b/flap/tests/01-Parsing/41-external-definition-1.bad.parsing.hopix @@ -0,0 +1 @@ +extern print_string : string -> \ No newline at end of file diff --git a/flap/tests/01-Parsing/41-external-definition-1.good.expected b/flap/tests/01-Parsing/41-external-definition-1.good.expected new file mode 100644 index 0000000..495739e --- /dev/null +++ b/flap/tests/01-Parsing/41-external-definition-1.good.expected @@ -0,0 +1 @@ +extern print_string : string -> unit diff --git a/flap/tests/01-Parsing/41-external-definition-1.good.parsing.hopix b/flap/tests/01-Parsing/41-external-definition-1.good.parsing.hopix new file mode 100644 index 0000000..81f286a --- /dev/null +++ b/flap/tests/01-Parsing/41-external-definition-1.good.parsing.hopix @@ -0,0 +1 @@ +extern print_string : string -> unit \ No newline at end of file diff --git a/flap/tests/01-Parsing/42-external-definition-2.good.expected b/flap/tests/01-Parsing/42-external-definition-2.good.expected new file mode 100644 index 0000000..f8d6dec --- /dev/null +++ b/flap/tests/01-Parsing/42-external-definition-2.good.expected @@ -0,0 +1 @@ +extern concat : [`a](list<`a> * list<`a>) -> list<`a> diff --git a/flap/tests/01-Parsing/42-external-definition-2.good.parsing.hopix b/flap/tests/01-Parsing/42-external-definition-2.good.parsing.hopix new file mode 100644 index 0000000..44ec99d --- /dev/null +++ b/flap/tests/01-Parsing/42-external-definition-2.good.parsing.hopix @@ -0,0 +1 @@ +extern concat : [`a] list<`a> * list<`a> -> list<`a> \ No newline at end of file diff --git a/flap/tests/01-Parsing/43-external-definition-3.bad.expected b/flap/tests/01-Parsing/43-external-definition-3.bad.expected new file mode 100644 index 0000000..9e54c9b --- /dev/null +++ b/flap/tests/01-Parsing/43-external-definition-3.bad.expected @@ -0,0 +1 @@ +extern superman : [`a, `b]`a -> `b diff --git a/flap/tests/01-Parsing/43-external-definition-3.bad.parsing.hopix b/flap/tests/01-Parsing/43-external-definition-3.bad.parsing.hopix new file mode 100644 index 0000000..071cf9a --- /dev/null +++ b/flap/tests/01-Parsing/43-external-definition-3.bad.parsing.hopix @@ -0,0 +1 @@ +extern superman : [`a, `b] `a -> `b \ No newline at end of file diff --git a/flap/tests/01-Parsing/43-external-definition-3.good.expected b/flap/tests/01-Parsing/43-external-definition-3.good.expected new file mode 100644 index 0000000..9e54c9b --- /dev/null +++ b/flap/tests/01-Parsing/43-external-definition-3.good.expected @@ -0,0 +1 @@ +extern superman : [`a, `b]`a -> `b diff --git a/flap/tests/01-Parsing/43-external-definition-3.good.parsing.hopix b/flap/tests/01-Parsing/43-external-definition-3.good.parsing.hopix new file mode 100644 index 0000000..57a925b --- /dev/null +++ b/flap/tests/01-Parsing/43-external-definition-3.good.parsing.hopix @@ -0,0 +1 @@ +extern superman : [`a, `b] `a -> `b diff --git a/flap/tests/01-Parsing/44-value-definition-1.bad.expected b/flap/tests/01-Parsing/44-value-definition-1.bad.expected new file mode 100644 index 0000000..baac959 --- /dev/null +++ b/flap/tests/01-Parsing/44-value-definition-1.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 0-3: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/44-value-definition-1.bad.parsing.hopix b/flap/tests/01-Parsing/44-value-definition-1.bad.parsing.hopix new file mode 100644 index 0000000..0d7a029 --- /dev/null +++ b/flap/tests/01-Parsing/44-value-definition-1.bad.parsing.hopix @@ -0,0 +1 @@ +val x = 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing/44-value-definition-1.good.expected b/flap/tests/01-Parsing/44-value-definition-1.good.expected new file mode 100644 index 0000000..b6a2459 --- /dev/null +++ b/flap/tests/01-Parsing/44-value-definition-1.good.expected @@ -0,0 +1 @@ +let x = 0 diff --git a/flap/tests/01-Parsing/44-value-definition-1.good.parsing.hopix b/flap/tests/01-Parsing/44-value-definition-1.good.parsing.hopix new file mode 100644 index 0000000..b5368df --- /dev/null +++ b/flap/tests/01-Parsing/44-value-definition-1.good.parsing.hopix @@ -0,0 +1 @@ +let x = 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing/45-value-definition-2.bad.expected b/flap/tests/01-Parsing/45-value-definition-2.bad.expected new file mode 100644 index 0000000..c84840f --- /dev/null +++ b/flap/tests/01-Parsing/45-value-definition-2.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 25-26: Error (during lexing) + unexpected character. diff --git a/flap/tests/01-Parsing/45-value-definition-2.bad.parsing.hopix b/flap/tests/01-Parsing/45-value-definition-2.bad.parsing.hopix new file mode 100644 index 0000000..7f03d2a --- /dev/null +++ b/flap/tests/01-Parsing/45-value-definition-2.bad.parsing.hopix @@ -0,0 +1 @@ +let inconsistency : [`a] ``a = 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing/45-value-definition-2.good.expected b/flap/tests/01-Parsing/45-value-definition-2.good.expected new file mode 100644 index 0000000..6ace6e5 --- /dev/null +++ b/flap/tests/01-Parsing/45-value-definition-2.good.expected @@ -0,0 +1 @@ +let inconsistency : [`a]a = 0 diff --git a/flap/tests/01-Parsing/45-value-definition-2.good.parsing.hopix b/flap/tests/01-Parsing/45-value-definition-2.good.parsing.hopix new file mode 100644 index 0000000..129ff94 --- /dev/null +++ b/flap/tests/01-Parsing/45-value-definition-2.good.parsing.hopix @@ -0,0 +1 @@ +let inconsistency : [`a] a = 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing/46-value-definition-3.bad.expected b/flap/tests/01-Parsing/46-value-definition-3.bad.expected new file mode 100644 index 0000000..e5bd27c --- /dev/null +++ b/flap/tests/01-Parsing/46-value-definition-3.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 11-11: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/46-value-definition-3.bad.parsing.hopix b/flap/tests/01-Parsing/46-value-definition-3.bad.parsing.hopix new file mode 100644 index 0000000..975d410 --- /dev/null +++ b/flap/tests/01-Parsing/46-value-definition-3.bad.parsing.hopix @@ -0,0 +1 @@ +let minux = \ No newline at end of file diff --git a/flap/tests/01-Parsing/46-value-definition-3.good.expected b/flap/tests/01-Parsing/46-value-definition-3.good.expected new file mode 100644 index 0000000..9c5ae48 --- /dev/null +++ b/flap/tests/01-Parsing/46-value-definition-3.good.expected @@ -0,0 +1 @@ +let minux = 0 diff --git a/flap/tests/01-Parsing/46-value-definition-3.good.parsing.hopix b/flap/tests/01-Parsing/46-value-definition-3.good.parsing.hopix new file mode 100644 index 0000000..826d210 --- /dev/null +++ b/flap/tests/01-Parsing/46-value-definition-3.good.parsing.hopix @@ -0,0 +1 @@ +let minux = 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing/47-instanciation.bad.expected b/flap/tests/01-Parsing/47-instanciation.bad.expected new file mode 100644 index 0000000..07b9b49 --- /dev/null +++ b/flap/tests/01-Parsing/47-instanciation.bad.expected @@ -0,0 +1 @@ +let x = id < > diff --git a/flap/tests/01-Parsing/47-instanciation.bad.parsing.hopix b/flap/tests/01-Parsing/47-instanciation.bad.parsing.hopix new file mode 100644 index 0000000..be28a47 --- /dev/null +++ b/flap/tests/01-Parsing/47-instanciation.bad.parsing.hopix @@ -0,0 +1 @@ +let x = id<> \ No newline at end of file diff --git a/flap/tests/01-Parsing/47-instanciation.good.expected b/flap/tests/01-Parsing/47-instanciation.good.expected new file mode 100644 index 0000000..74a9ed1 --- /dev/null +++ b/flap/tests/01-Parsing/47-instanciation.good.expected @@ -0,0 +1 @@ +let x = id < `a > diff --git a/flap/tests/01-Parsing/47-instanciation.good.parsing.hopix b/flap/tests/01-Parsing/47-instanciation.good.parsing.hopix new file mode 100644 index 0000000..a8ca18a --- /dev/null +++ b/flap/tests/01-Parsing/47-instanciation.good.parsing.hopix @@ -0,0 +1 @@ +let x = id<`a> \ No newline at end of file diff --git a/flap/tests/01-Parsing/48-instanciation-2.bad.expected b/flap/tests/01-Parsing/48-instanciation-2.bad.expected new file mode 100644 index 0000000..b118ebb --- /dev/null +++ b/flap/tests/01-Parsing/48-instanciation-2.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 18-21: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/48-instanciation-2.bad.parsing.hopix b/flap/tests/01-Parsing/48-instanciation-2.bad.parsing.hopix new file mode 100644 index 0000000..161f439 --- /dev/null +++ b/flap/tests/01-Parsing/48-instanciation-2.bad.parsing.hopix @@ -0,0 +1 @@ +let x = plus \ No newline at end of file diff --git a/flap/tests/01-Parsing/48-instanciation-2.good.expected b/flap/tests/01-Parsing/48-instanciation-2.good.expected new file mode 100644 index 0000000..79c6570 --- /dev/null +++ b/flap/tests/01-Parsing/48-instanciation-2.good.expected @@ -0,0 +1 @@ +let x = plus < int > diff --git a/flap/tests/01-Parsing/48-instanciation-2.good.parsing.hopix b/flap/tests/01-Parsing/48-instanciation-2.good.parsing.hopix new file mode 100644 index 0000000..c4723e9 --- /dev/null +++ b/flap/tests/01-Parsing/48-instanciation-2.good.parsing.hopix @@ -0,0 +1 @@ +let x = plus \ No newline at end of file diff --git a/flap/tests/01-Parsing/49-instanciation-3.bad.expected b/flap/tests/01-Parsing/49-instanciation-3.bad.expected new file mode 100644 index 0000000..e4bc144 --- /dev/null +++ b/flap/tests/01-Parsing/49-instanciation-3.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 19-20: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/49-instanciation-3.bad.parsing.hopix b/flap/tests/01-Parsing/49-instanciation-3.bad.parsing.hopix new file mode 100644 index 0000000..baa4b41 --- /dev/null +++ b/flap/tests/01-Parsing/49-instanciation-3.bad.parsing.hopix @@ -0,0 +1 @@ +let x = concat \ No newline at end of file diff --git a/flap/tests/01-Parsing/49-instanciation-3.good.expected b/flap/tests/01-Parsing/49-instanciation-3.good.expected new file mode 100644 index 0000000..d5badae --- /dev/null +++ b/flap/tests/01-Parsing/49-instanciation-3.good.expected @@ -0,0 +1 @@ +let x = concat < int > diff --git a/flap/tests/01-Parsing/49-instanciation-3.good.parsing.hopix b/flap/tests/01-Parsing/49-instanciation-3.good.parsing.hopix new file mode 100644 index 0000000..a293bb4 --- /dev/null +++ b/flap/tests/01-Parsing/49-instanciation-3.good.parsing.hopix @@ -0,0 +1 @@ +let x = concat \ No newline at end of file diff --git a/flap/tests/01-Parsing/50-instanciation-4.bad.expected b/flap/tests/01-Parsing/50-instanciation-4.bad.expected new file mode 100644 index 0000000..8b8a9f1 --- /dev/null +++ b/flap/tests/01-Parsing/50-instanciation-4.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 16-17: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/50-instanciation-4.bad.parsing.hopix b/flap/tests/01-Parsing/50-instanciation-4.bad.parsing.hopix new file mode 100644 index 0000000..8fd6b88 --- /dev/null +++ b/flap/tests/01-Parsing/50-instanciation-4.bad.parsing.hopix @@ -0,0 +1 @@ +let x = id int> \ No newline at end of file diff --git a/flap/tests/01-Parsing/50-instanciation-4.good.expected b/flap/tests/01-Parsing/50-instanciation-4.good.expected new file mode 100644 index 0000000..bf6c773 --- /dev/null +++ b/flap/tests/01-Parsing/50-instanciation-4.good.expected @@ -0,0 +1 @@ +let x = id < (int -> int) > diff --git a/flap/tests/01-Parsing/50-instanciation-4.good.parsing.hopix b/flap/tests/01-Parsing/50-instanciation-4.good.parsing.hopix new file mode 100644 index 0000000..45e51b4 --- /dev/null +++ b/flap/tests/01-Parsing/50-instanciation-4.good.parsing.hopix @@ -0,0 +1 @@ +let x = id int> \ No newline at end of file diff --git a/flap/tests/01-Parsing/51-instanciation-5.bad.expected b/flap/tests/01-Parsing/51-instanciation-5.bad.expected new file mode 100644 index 0000000..b30a070 --- /dev/null +++ b/flap/tests/01-Parsing/51-instanciation-5.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 17-18: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/51-instanciation-5.bad.parsing.hopix b/flap/tests/01-Parsing/51-instanciation-5.bad.parsing.hopix new file mode 100644 index 0000000..48cbfed --- /dev/null +++ b/flap/tests/01-Parsing/51-instanciation-5.bad.parsing.hopix @@ -0,0 +1 @@ +let x = map \ No newline at end of file diff --git a/flap/tests/01-Parsing/51-instanciation-5.good.expected b/flap/tests/01-Parsing/51-instanciation-5.good.expected new file mode 100644 index 0000000..92b60b1 --- /dev/null +++ b/flap/tests/01-Parsing/51-instanciation-5.good.expected @@ -0,0 +1 @@ +let x = map < int, string > diff --git a/flap/tests/01-Parsing/51-instanciation-5.good.parsing.hopix b/flap/tests/01-Parsing/51-instanciation-5.good.parsing.hopix new file mode 100644 index 0000000..ff7877a --- /dev/null +++ b/flap/tests/01-Parsing/51-instanciation-5.good.parsing.hopix @@ -0,0 +1 @@ +let x = map \ No newline at end of file diff --git a/flap/tests/01-Parsing/52-instanciation-6.bad.expected b/flap/tests/01-Parsing/52-instanciation-6.bad.expected new file mode 100644 index 0000000..b30a070 --- /dev/null +++ b/flap/tests/01-Parsing/52-instanciation-6.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 17-18: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/52-instanciation-6.bad.parsing.hopix b/flap/tests/01-Parsing/52-instanciation-6.bad.parsing.hopix new file mode 100644 index 0000000..c1805d3 --- /dev/null +++ b/flap/tests/01-Parsing/52-instanciation-6.bad.parsing.hopix @@ -0,0 +1 @@ +let x = map int> \ No newline at end of file diff --git a/flap/tests/01-Parsing/52-instanciation-6.good.expected b/flap/tests/01-Parsing/52-instanciation-6.good.expected new file mode 100644 index 0000000..a18eb74 --- /dev/null +++ b/flap/tests/01-Parsing/52-instanciation-6.good.expected @@ -0,0 +1 @@ +let x = map < int, (int -> int) > diff --git a/flap/tests/01-Parsing/52-instanciation-6.good.parsing.hopix b/flap/tests/01-Parsing/52-instanciation-6.good.parsing.hopix new file mode 100644 index 0000000..d78c12c --- /dev/null +++ b/flap/tests/01-Parsing/52-instanciation-6.good.parsing.hopix @@ -0,0 +1 @@ +let x = map int> \ No newline at end of file diff --git a/flap/tests/01-Parsing/53-instanciation-7.bad.expected b/flap/tests/01-Parsing/53-instanciation-7.bad.expected new file mode 100644 index 0000000..b30a070 --- /dev/null +++ b/flap/tests/01-Parsing/53-instanciation-7.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 17-18: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/53-instanciation-7.bad.parsing.hopix b/flap/tests/01-Parsing/53-instanciation-7.bad.parsing.hopix new file mode 100644 index 0000000..f884439 --- /dev/null +++ b/flap/tests/01-Parsing/53-instanciation-7.bad.parsing.hopix @@ -0,0 +1 @@ +let x = map \ No newline at end of file diff --git a/flap/tests/01-Parsing/53-instanciation-7.good.expected b/flap/tests/01-Parsing/53-instanciation-7.good.expected new file mode 100644 index 0000000..f9c09db --- /dev/null +++ b/flap/tests/01-Parsing/53-instanciation-7.good.expected @@ -0,0 +1 @@ +let x = map < list, (int * int * int) > diff --git a/flap/tests/01-Parsing/53-instanciation-7.good.parsing.hopix b/flap/tests/01-Parsing/53-instanciation-7.good.parsing.hopix new file mode 100644 index 0000000..a69401a --- /dev/null +++ b/flap/tests/01-Parsing/53-instanciation-7.good.parsing.hopix @@ -0,0 +1 @@ +let x = map , int * int * int> \ No newline at end of file diff --git a/flap/tests/01-Parsing/54-constructor-1.bad.expected b/flap/tests/01-Parsing/54-constructor-1.bad.expected new file mode 100644 index 0000000..e9d41a9 --- /dev/null +++ b/flap/tests/01-Parsing/54-constructor-1.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 8-9: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/54-constructor-1.bad.parsing.hopix b/flap/tests/01-Parsing/54-constructor-1.bad.parsing.hopix new file mode 100644 index 0000000..7dd252c --- /dev/null +++ b/flap/tests/01-Parsing/54-constructor-1.bad.parsing.hopix @@ -0,0 +1 @@ +let x = [True] \ No newline at end of file diff --git a/flap/tests/01-Parsing/54-constructor-1.good.expected b/flap/tests/01-Parsing/54-constructor-1.good.expected new file mode 100644 index 0000000..f4c4941 --- /dev/null +++ b/flap/tests/01-Parsing/54-constructor-1.good.expected @@ -0,0 +1 @@ +let x = True diff --git a/flap/tests/01-Parsing/54-constructor-1.good.parsing.hopix b/flap/tests/01-Parsing/54-constructor-1.good.parsing.hopix new file mode 100644 index 0000000..467de38 --- /dev/null +++ b/flap/tests/01-Parsing/54-constructor-1.good.parsing.hopix @@ -0,0 +1 @@ +let x = True \ No newline at end of file diff --git a/flap/tests/01-Parsing/55-constructor-2.bad.expected b/flap/tests/01-Parsing/55-constructor-2.bad.expected new file mode 100644 index 0000000..10e168b --- /dev/null +++ b/flap/tests/01-Parsing/55-constructor-2.bad.expected @@ -0,0 +1 @@ +let y = Cons < >(0, Nil < int >) diff --git a/flap/tests/01-Parsing/55-constructor-2.bad.parsing.hopix b/flap/tests/01-Parsing/55-constructor-2.bad.parsing.hopix new file mode 100644 index 0000000..9fdf354 --- /dev/null +++ b/flap/tests/01-Parsing/55-constructor-2.bad.parsing.hopix @@ -0,0 +1 @@ +let y = Cons <> (0, Nil) \ No newline at end of file diff --git a/flap/tests/01-Parsing/55-constructor-2.good.expected b/flap/tests/01-Parsing/55-constructor-2.good.expected new file mode 100644 index 0000000..24c7f05 --- /dev/null +++ b/flap/tests/01-Parsing/55-constructor-2.good.expected @@ -0,0 +1 @@ +let y = Cons < int >(0, Nil < int >) diff --git a/flap/tests/01-Parsing/55-constructor-2.good.parsing.hopix b/flap/tests/01-Parsing/55-constructor-2.good.parsing.hopix new file mode 100644 index 0000000..d3b41b1 --- /dev/null +++ b/flap/tests/01-Parsing/55-constructor-2.good.parsing.hopix @@ -0,0 +1 @@ +let y = Cons (0, Nil) \ No newline at end of file diff --git a/flap/tests/01-Parsing/56-constructor-3.bad.expected b/flap/tests/01-Parsing/56-constructor-3.bad.expected new file mode 100644 index 0000000..7ebbf51 --- /dev/null +++ b/flap/tests/01-Parsing/56-constructor-3.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 22-23: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/56-constructor-3.bad.parsing.hopix b/flap/tests/01-Parsing/56-constructor-3.bad.parsing.hopix new file mode 100644 index 0000000..0b48d33 --- /dev/null +++ b/flap/tests/01-Parsing/56-constructor-3.bad.parsing.hopix @@ -0,0 +1 @@ +let x = pair, string> (Pair (0, "Wou!"), "Wouha!") \ No newline at end of file diff --git a/flap/tests/01-Parsing/56-constructor-3.good.expected b/flap/tests/01-Parsing/56-constructor-3.good.expected new file mode 100644 index 0000000..ed12096 --- /dev/null +++ b/flap/tests/01-Parsing/56-constructor-3.good.expected @@ -0,0 +1,6 @@ +let x = + pair < + pair, + string + > + (Pair < int, string >(0, "Wou!"), "Wouha!") diff --git a/flap/tests/01-Parsing/56-constructor-3.good.parsing.hopix b/flap/tests/01-Parsing/56-constructor-3.good.parsing.hopix new file mode 100644 index 0000000..f893180 --- /dev/null +++ b/flap/tests/01-Parsing/56-constructor-3.good.parsing.hopix @@ -0,0 +1 @@ +let x = pair, string> (Pair (0, "Wou!"), "Wouha!") \ No newline at end of file diff --git a/flap/tests/01-Parsing/57-constructor-4.bad.expected b/flap/tests/01-Parsing/57-constructor-4.bad.expected new file mode 100644 index 0000000..7ebbf51 --- /dev/null +++ b/flap/tests/01-Parsing/57-constructor-4.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 22-23: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/57-constructor-4.bad.parsing.hopix b/flap/tests/01-Parsing/57-constructor-4.bad.parsing.hopix new file mode 100644 index 0000000..1224b80 --- /dev/null +++ b/flap/tests/01-Parsing/57-constructor-4.bad.parsing.hopix @@ -0,0 +1 @@ +let some = Some () \ No newline at end of file diff --git a/flap/tests/01-Parsing/57-constructor-4.good.expected b/flap/tests/01-Parsing/57-constructor-4.good.expected new file mode 100644 index 0000000..206fc71 --- /dev/null +++ b/flap/tests/01-Parsing/57-constructor-4.good.expected @@ -0,0 +1 @@ +let some = Some < int >(73) diff --git a/flap/tests/01-Parsing/57-constructor-4.good.parsing.hopix b/flap/tests/01-Parsing/57-constructor-4.good.parsing.hopix new file mode 100644 index 0000000..463220d --- /dev/null +++ b/flap/tests/01-Parsing/57-constructor-4.good.parsing.hopix @@ -0,0 +1 @@ +let some = Some (73) \ No newline at end of file diff --git a/flap/tests/01-Parsing/58-record-1.bad.expected b/flap/tests/01-Parsing/58-record-1.bad.expected new file mode 100644 index 0000000..baedb40 --- /dev/null +++ b/flap/tests/01-Parsing/58-record-1.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 21-22: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/58-record-1.bad.parsing.hopix b/flap/tests/01-Parsing/58-record-1.bad.parsing.hopix new file mode 100644 index 0000000..8019d13 --- /dev/null +++ b/flap/tests/01-Parsing/58-record-1.bad.parsing.hopix @@ -0,0 +1 @@ +let start = { x = 0, } \ No newline at end of file diff --git a/flap/tests/01-Parsing/58-record-1.good.expected b/flap/tests/01-Parsing/58-record-1.good.expected new file mode 100644 index 0000000..9d33b7a --- /dev/null +++ b/flap/tests/01-Parsing/58-record-1.good.expected @@ -0,0 +1 @@ +let start = {x = 0, y = 0} diff --git a/flap/tests/01-Parsing/58-record-1.good.parsing.hopix b/flap/tests/01-Parsing/58-record-1.good.parsing.hopix new file mode 100644 index 0000000..371210d --- /dev/null +++ b/flap/tests/01-Parsing/58-record-1.good.parsing.hopix @@ -0,0 +1 @@ +let start = { x = 0, y = 0 } \ No newline at end of file diff --git a/flap/tests/01-Parsing/59-record-2.bad.expected b/flap/tests/01-Parsing/59-record-2.bad.expected new file mode 100644 index 0000000..689e01c --- /dev/null +++ b/flap/tests/01-Parsing/59-record-2.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 23-24: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/59-record-2.bad.parsing.hopix b/flap/tests/01-Parsing/59-record-2.bad.parsing.hopix new file mode 100644 index 0000000..66f50a1 --- /dev/null +++ b/flap/tests/01-Parsing/59-record-2.bad.parsing.hopix @@ -0,0 +1 @@ +let name = { fst = "My"; snd = "Precious" } \ No newline at end of file diff --git a/flap/tests/01-Parsing/59-record-2.good.expected b/flap/tests/01-Parsing/59-record-2.good.expected new file mode 100644 index 0000000..c6cc5bc --- /dev/null +++ b/flap/tests/01-Parsing/59-record-2.good.expected @@ -0,0 +1 @@ +let name = {fst = "My", snd = "Precious"} < string, string > diff --git a/flap/tests/01-Parsing/59-record-2.good.parsing.hopix b/flap/tests/01-Parsing/59-record-2.good.parsing.hopix new file mode 100644 index 0000000..4a41cda --- /dev/null +++ b/flap/tests/01-Parsing/59-record-2.good.parsing.hopix @@ -0,0 +1 @@ +let name = { fst = "My", snd = "Precious" } \ No newline at end of file diff --git a/flap/tests/01-Parsing/60-record-3.bad.expected b/flap/tests/01-Parsing/60-record-3.bad.expected new file mode 100644 index 0000000..c7ab1d9 --- /dev/null +++ b/flap/tests/01-Parsing/60-record-3.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 32-33: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/60-record-3.bad.parsing.hopix b/flap/tests/01-Parsing/60-record-3.bad.parsing.hopix new file mode 100644 index 0000000..beaab28 --- /dev/null +++ b/flap/tests/01-Parsing/60-record-3.bad.parsing.hopix @@ -0,0 +1 @@ +let what_s_in_the_box = { box = } \ No newline at end of file diff --git a/flap/tests/01-Parsing/60-record-3.good.expected b/flap/tests/01-Parsing/60-record-3.good.expected new file mode 100644 index 0000000..0d6a46b --- /dev/null +++ b/flap/tests/01-Parsing/60-record-3.good.expected @@ -0,0 +1 @@ +let what_s_in_the_box = {box = "Mystery"} diff --git a/flap/tests/01-Parsing/60-record-3.good.parsing.hopix b/flap/tests/01-Parsing/60-record-3.good.parsing.hopix new file mode 100644 index 0000000..1788ead --- /dev/null +++ b/flap/tests/01-Parsing/60-record-3.good.parsing.hopix @@ -0,0 +1 @@ +let what_s_in_the_box = { box = "Mystery" } \ No newline at end of file diff --git a/flap/tests/01-Parsing/61-record-projection-1.bad.expected b/flap/tests/01-Parsing/61-record-projection-1.bad.expected new file mode 100644 index 0000000..a7aa603 --- /dev/null +++ b/flap/tests/01-Parsing/61-record-projection-1.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 10-11: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/61-record-projection-1.bad.parsing.hopix b/flap/tests/01-Parsing/61-record-projection-1.bad.parsing.hopix new file mode 100644 index 0000000..905b5ca --- /dev/null +++ b/flap/tests/01-Parsing/61-record-projection-1.bad.parsing.hopix @@ -0,0 +1 @@ +let x = p.X \ No newline at end of file diff --git a/flap/tests/01-Parsing/61-record-projection-1.good.expected b/flap/tests/01-Parsing/61-record-projection-1.good.expected new file mode 100644 index 0000000..751a65c --- /dev/null +++ b/flap/tests/01-Parsing/61-record-projection-1.good.expected @@ -0,0 +1 @@ +let x = p.x diff --git a/flap/tests/01-Parsing/61-record-projection-1.good.parsing.hopix b/flap/tests/01-Parsing/61-record-projection-1.good.parsing.hopix new file mode 100644 index 0000000..3baf2d6 --- /dev/null +++ b/flap/tests/01-Parsing/61-record-projection-1.good.parsing.hopix @@ -0,0 +1 @@ +let x = p.x \ No newline at end of file diff --git a/flap/tests/01-Parsing/62-record-projection-2.bad.expected b/flap/tests/01-Parsing/62-record-projection-2.bad.expected new file mode 100644 index 0000000..b3ba720 --- /dev/null +++ b/flap/tests/01-Parsing/62-record-projection-2.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 25-25: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/62-record-projection-2.bad.parsing.hopix b/flap/tests/01-Parsing/62-record-projection-2.bad.parsing.hopix new file mode 100644 index 0000000..976e15c --- /dev/null +++ b/flap/tests/01-Parsing/62-record-projection-2.bad.parsing.hopix @@ -0,0 +1 @@ +let y = { x = 0, y = 1 }. \ No newline at end of file diff --git a/flap/tests/01-Parsing/62-record-projection-2.good.expected b/flap/tests/01-Parsing/62-record-projection-2.good.expected new file mode 100644 index 0000000..24e31d1 --- /dev/null +++ b/flap/tests/01-Parsing/62-record-projection-2.good.expected @@ -0,0 +1 @@ +let y = {x = 0, y = 1}.y diff --git a/flap/tests/01-Parsing/62-record-projection-2.good.parsing.hopix b/flap/tests/01-Parsing/62-record-projection-2.good.parsing.hopix new file mode 100644 index 0000000..eeb4149 --- /dev/null +++ b/flap/tests/01-Parsing/62-record-projection-2.good.parsing.hopix @@ -0,0 +1 @@ +let y = { x = 0, y = 1 }.y \ No newline at end of file diff --git a/flap/tests/01-Parsing/63-record-projection-3.bad.expected b/flap/tests/01-Parsing/63-record-projection-3.bad.expected new file mode 100644 index 0000000..3ddda1e --- /dev/null +++ b/flap/tests/01-Parsing/63-record-projection-3.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 40-42: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/63-record-projection-3.bad.parsing.hopix b/flap/tests/01-Parsing/63-record-projection-3.bad.parsing.hopix new file mode 100644 index 0000000..d6dfa9e --- /dev/null +++ b/flap/tests/01-Parsing/63-record-projection-3.bad.parsing.hopix @@ -0,0 +1 @@ +let you_silly_boy = "I am not a record".33 \ No newline at end of file diff --git a/flap/tests/01-Parsing/63-record-projection-3.good.expected b/flap/tests/01-Parsing/63-record-projection-3.good.expected new file mode 100644 index 0000000..c63de02 --- /dev/null +++ b/flap/tests/01-Parsing/63-record-projection-3.good.expected @@ -0,0 +1 @@ +let you_silly_boy = "I am not a record".song diff --git a/flap/tests/01-Parsing/63-record-projection-3.good.parsing.hopix b/flap/tests/01-Parsing/63-record-projection-3.good.parsing.hopix new file mode 100644 index 0000000..a923d3d --- /dev/null +++ b/flap/tests/01-Parsing/63-record-projection-3.good.parsing.hopix @@ -0,0 +1 @@ +let you_silly_boy = "I am not a record".song \ No newline at end of file diff --git a/flap/tests/01-Parsing/65-sequence-1.bad.expected b/flap/tests/01-Parsing/65-sequence-1.bad.expected new file mode 100644 index 0000000..29c93e2 --- /dev/null +++ b/flap/tests/01-Parsing/65-sequence-1.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 44-44: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/65-sequence-1.bad.parsing.hopix b/flap/tests/01-Parsing/65-sequence-1.bad.parsing.hopix new file mode 100644 index 0000000..585c105 --- /dev/null +++ b/flap/tests/01-Parsing/65-sequence-1.bad.parsing.hopix @@ -0,0 +1 @@ +let x = sing (0); eat (0); drink (0); song ( \ No newline at end of file diff --git a/flap/tests/01-Parsing/65-sequence-1.good.expected b/flap/tests/01-Parsing/65-sequence-1.good.expected new file mode 100644 index 0000000..d895c09 --- /dev/null +++ b/flap/tests/01-Parsing/65-sequence-1.good.expected @@ -0,0 +1 @@ +let x = (sing 0); ((eat 0); ((drink 0); (song 0))) diff --git a/flap/tests/01-Parsing/65-sequence-1.good.parsing.hopix b/flap/tests/01-Parsing/65-sequence-1.good.parsing.hopix new file mode 100644 index 0000000..1d991f5 --- /dev/null +++ b/flap/tests/01-Parsing/65-sequence-1.good.parsing.hopix @@ -0,0 +1 @@ +let x = sing (0); eat (0); drink (0); song (0) \ No newline at end of file diff --git a/flap/tests/01-Parsing/66-sequence-2.bad.expected b/flap/tests/01-Parsing/66-sequence-2.bad.expected new file mode 100644 index 0000000..61bb7f6 --- /dev/null +++ b/flap/tests/01-Parsing/66-sequence-2.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 35-36: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/66-sequence-2.bad.parsing.hopix b/flap/tests/01-Parsing/66-sequence-2.bad.parsing.hopix new file mode 100644 index 0000000..1f926c2 --- /dev/null +++ b/flap/tests/01-Parsing/66-sequence-2.bad.parsing.hopix @@ -0,0 +1 @@ +let x = (foo (0); bar (0)); baz (0)) \ No newline at end of file diff --git a/flap/tests/01-Parsing/66-sequence-2.good.expected b/flap/tests/01-Parsing/66-sequence-2.good.expected new file mode 100644 index 0000000..2ce0a5a --- /dev/null +++ b/flap/tests/01-Parsing/66-sequence-2.good.expected @@ -0,0 +1 @@ +let x = ((foo 0); (bar 0)); (baz 0) diff --git a/flap/tests/01-Parsing/66-sequence-2.good.parsing.hopix b/flap/tests/01-Parsing/66-sequence-2.good.parsing.hopix new file mode 100644 index 0000000..cd7e8a3 --- /dev/null +++ b/flap/tests/01-Parsing/66-sequence-2.good.parsing.hopix @@ -0,0 +1 @@ +let x = (foo (0); bar (0)); baz (0) \ No newline at end of file diff --git a/flap/tests/01-Parsing/67-sequence-3.bad.expected b/flap/tests/01-Parsing/67-sequence-3.bad.expected new file mode 100644 index 0000000..baac959 --- /dev/null +++ b/flap/tests/01-Parsing/67-sequence-3.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 0-3: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/67-sequence-3.bad.parsing.hopix b/flap/tests/01-Parsing/67-sequence-3.bad.parsing.hopix new file mode 100644 index 0000000..b530fc5 --- /dev/null +++ b/flap/tests/01-Parsing/67-sequence-3.bad.parsing.hopix @@ -0,0 +1 @@ +val x = foo (0); (bar (0); baz (0)) \ No newline at end of file diff --git a/flap/tests/01-Parsing/67-sequence-3.good.expected b/flap/tests/01-Parsing/67-sequence-3.good.expected new file mode 100644 index 0000000..7c916e0 --- /dev/null +++ b/flap/tests/01-Parsing/67-sequence-3.good.expected @@ -0,0 +1 @@ +let x = (foo 0); ((bar 0); (baz 0)) diff --git a/flap/tests/01-Parsing/67-sequence-3.good.parsing.hopix b/flap/tests/01-Parsing/67-sequence-3.good.parsing.hopix new file mode 100644 index 0000000..e3a046f --- /dev/null +++ b/flap/tests/01-Parsing/67-sequence-3.good.parsing.hopix @@ -0,0 +1 @@ +let x = foo (0); (bar (0); baz (0)) \ No newline at end of file diff --git a/flap/tests/01-Parsing/68-local-definition.bad.expected b/flap/tests/01-Parsing/68-local-definition.bad.expected new file mode 100644 index 0000000..0dc486d --- /dev/null +++ b/flap/tests/01-Parsing/68-local-definition.bad.expected @@ -0,0 +1,2 @@ +Line 2, characters 12-13: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/68-local-definition.bad.parsing.hopix b/flap/tests/01-Parsing/68-local-definition.bad.parsing.hopix new file mode 100644 index 0000000..5f0dccd --- /dev/null +++ b/flap/tests/01-Parsing/68-local-definition.bad.parsing.hopix @@ -0,0 +1,3 @@ +let main = + let x = 0;; + x \ No newline at end of file diff --git a/flap/tests/01-Parsing/68-local-definition.good.expected b/flap/tests/01-Parsing/68-local-definition.good.expected new file mode 100644 index 0000000..6595b9c --- /dev/null +++ b/flap/tests/01-Parsing/68-local-definition.good.expected @@ -0,0 +1 @@ +let main = let x = 0 ; x diff --git a/flap/tests/01-Parsing/68-local-definition.good.parsing.hopix b/flap/tests/01-Parsing/68-local-definition.good.parsing.hopix new file mode 100644 index 0000000..f463924 --- /dev/null +++ b/flap/tests/01-Parsing/68-local-definition.good.parsing.hopix @@ -0,0 +1,3 @@ +let main = + let x = 0; + x \ No newline at end of file diff --git a/flap/tests/01-Parsing/69-local-definition-2.bad.expected b/flap/tests/01-Parsing/69-local-definition-2.bad.expected new file mode 100644 index 0000000..3048ef7 --- /dev/null +++ b/flap/tests/01-Parsing/69-local-definition-2.bad.expected @@ -0,0 +1,2 @@ +Line 3, characters 2-5: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/69-local-definition-2.bad.parsing.hopix b/flap/tests/01-Parsing/69-local-definition-2.bad.parsing.hopix new file mode 100644 index 0000000..23a0f68 --- /dev/null +++ b/flap/tests/01-Parsing/69-local-definition-2.bad.parsing.hopix @@ -0,0 +1,6 @@ +let main = + let me = 0 + let you = 0; + play me; + play you; + you \ No newline at end of file diff --git a/flap/tests/01-Parsing/69-local-definition-2.good.expected b/flap/tests/01-Parsing/69-local-definition-2.good.expected new file mode 100644 index 0000000..1afc20c --- /dev/null +++ b/flap/tests/01-Parsing/69-local-definition-2.good.expected @@ -0,0 +1,2 @@ +let main = + let me = 0 ; let you = 0 ; (play me); ((play you); you) diff --git a/flap/tests/01-Parsing/69-local-definition-2.good.parsing.hopix b/flap/tests/01-Parsing/69-local-definition-2.good.parsing.hopix new file mode 100644 index 0000000..5ad647a --- /dev/null +++ b/flap/tests/01-Parsing/69-local-definition-2.good.parsing.hopix @@ -0,0 +1,6 @@ +let main = + let me = 0; + let you = 0; + play me; + play you; + you \ No newline at end of file diff --git a/flap/tests/01-Parsing/70-local-definition-3.bad.expected b/flap/tests/01-Parsing/70-local-definition-3.bad.expected new file mode 100644 index 0000000..39295c9 --- /dev/null +++ b/flap/tests/01-Parsing/70-local-definition-3.bad.expected @@ -0,0 +1,2 @@ +Line 3, characters 0-0: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/70-local-definition-3.bad.parsing.hopix b/flap/tests/01-Parsing/70-local-definition-3.bad.parsing.hopix new file mode 100644 index 0000000..352105d --- /dev/null +++ b/flap/tests/01-Parsing/70-local-definition-3.bad.parsing.hopix @@ -0,0 +1,2 @@ +let main = + fun f x = x; diff --git a/flap/tests/01-Parsing/70-local-definition-3.good.expected b/flap/tests/01-Parsing/70-local-definition-3.good.expected new file mode 100644 index 0000000..5bfa63d --- /dev/null +++ b/flap/tests/01-Parsing/70-local-definition-3.good.expected @@ -0,0 +1 @@ +let main = fun f x = x ; f 0 diff --git a/flap/tests/01-Parsing/70-local-definition-3.good.parsing.hopix b/flap/tests/01-Parsing/70-local-definition-3.good.parsing.hopix new file mode 100644 index 0000000..aba7a12 --- /dev/null +++ b/flap/tests/01-Parsing/70-local-definition-3.good.parsing.hopix @@ -0,0 +1,3 @@ +let main = + fun f x = x; + f 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing/71-local-definition-4.bad.expected b/flap/tests/01-Parsing/71-local-definition-4.bad.expected new file mode 100644 index 0000000..da5cb32 --- /dev/null +++ b/flap/tests/01-Parsing/71-local-definition-4.bad.expected @@ -0,0 +1,2 @@ +Line 3, characters 12-13: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/71-local-definition-4.bad.parsing.hopix b/flap/tests/01-Parsing/71-local-definition-4.bad.parsing.hopix new file mode 100644 index 0000000..8847cf2 --- /dev/null +++ b/flap/tests/01-Parsing/71-local-definition-4.bad.parsing.hopix @@ -0,0 +1,4 @@ +let main = + fun ping _ = pong 0 + or pong _ = ping 0; + ping 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing/71-local-definition-4.good.expected b/flap/tests/01-Parsing/71-local-definition-4.good.expected new file mode 100644 index 0000000..9f71bdb --- /dev/null +++ b/flap/tests/01-Parsing/71-local-definition-4.good.expected @@ -0,0 +1 @@ +let main = fun ping _ = (pong 0) and pong _ = (ping 0) ; ping 0 diff --git a/flap/tests/01-Parsing/71-local-definition-4.good.parsing.hopix b/flap/tests/01-Parsing/71-local-definition-4.good.parsing.hopix new file mode 100644 index 0000000..de7f0e1 --- /dev/null +++ b/flap/tests/01-Parsing/71-local-definition-4.good.parsing.hopix @@ -0,0 +1,4 @@ +let main = + fun ping _ = pong 0 + and pong _ = ping 0; + ping 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing/72-local-definition-5.bad.expected b/flap/tests/01-Parsing/72-local-definition-5.bad.expected new file mode 100644 index 0000000..3883e18 --- /dev/null +++ b/flap/tests/01-Parsing/72-local-definition-5.bad.expected @@ -0,0 +1,2 @@ +Line 4, characters 2-5: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/72-local-definition-5.bad.parsing.hopix b/flap/tests/01-Parsing/72-local-definition-5.bad.parsing.hopix new file mode 100644 index 0000000..e7282ec --- /dev/null +++ b/flap/tests/01-Parsing/72-local-definition-5.bad.parsing.hopix @@ -0,0 +1,5 @@ +let bonneteau = + fun h (x, y) = g x + and g x = f (x, x, x); + and f (x, y, z) = y; + f (1, 2, 3) \ No newline at end of file diff --git a/flap/tests/01-Parsing/72-local-definition-5.good.expected b/flap/tests/01-Parsing/72-local-definition-5.good.expected new file mode 100644 index 0000000..86d8f42 --- /dev/null +++ b/flap/tests/01-Parsing/72-local-definition-5.good.expected @@ -0,0 +1,6 @@ +let bonneteau = + fun h (x, y) = (g x) + and g x = (f (x, x, x)) + and f (x, y, z) = y + ; + f (1, 2, 3) diff --git a/flap/tests/01-Parsing/72-local-definition-5.good.parsing.hopix b/flap/tests/01-Parsing/72-local-definition-5.good.parsing.hopix new file mode 100644 index 0000000..41ff1e6 --- /dev/null +++ b/flap/tests/01-Parsing/72-local-definition-5.good.parsing.hopix @@ -0,0 +1,5 @@ +let bonneteau = + fun h (x, y) = g x + and g x = f (x, x, x) + and f (x, y, z) = y; + f (1, 2, 3) \ No newline at end of file diff --git a/flap/tests/01-Parsing/73-lambda-1.bad.expected b/flap/tests/01-Parsing/73-lambda-1.bad.expected new file mode 100644 index 0000000..f33d742 --- /dev/null +++ b/flap/tests/01-Parsing/73-lambda-1.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 12-13: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/73-lambda-1.bad.parsing.hopix b/flap/tests/01-Parsing/73-lambda-1.bad.parsing.hopix new file mode 100644 index 0000000..bf998ee --- /dev/null +++ b/flap/tests/01-Parsing/73-lambda-1.bad.parsing.hopix @@ -0,0 +1 @@ +let id = \x . x \ No newline at end of file diff --git a/flap/tests/01-Parsing/73-lambda-1.good.expected b/flap/tests/01-Parsing/73-lambda-1.good.expected new file mode 100644 index 0000000..a222185 --- /dev/null +++ b/flap/tests/01-Parsing/73-lambda-1.good.expected @@ -0,0 +1 @@ +let id = \ x -> x diff --git a/flap/tests/01-Parsing/73-lambda-1.good.parsing.hopix b/flap/tests/01-Parsing/73-lambda-1.good.parsing.hopix new file mode 100644 index 0000000..27f8709 --- /dev/null +++ b/flap/tests/01-Parsing/73-lambda-1.good.parsing.hopix @@ -0,0 +1 @@ +let id = \x -> x \ No newline at end of file diff --git a/flap/tests/01-Parsing/74-lambda-2.bad.expected b/flap/tests/01-Parsing/74-lambda-2.bad.expected new file mode 100644 index 0000000..f33d742 --- /dev/null +++ b/flap/tests/01-Parsing/74-lambda-2.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 12-13: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/74-lambda-2.bad.parsing.hopix b/flap/tests/01-Parsing/74-lambda-2.bad.parsing.hopix new file mode 100644 index 0000000..9ce018f --- /dev/null +++ b/flap/tests/01-Parsing/74-lambda-2.bad.parsing.hopix @@ -0,0 +1 @@ +let k = \(x y) -> x \ No newline at end of file diff --git a/flap/tests/01-Parsing/74-lambda-2.good.expected b/flap/tests/01-Parsing/74-lambda-2.good.expected new file mode 100644 index 0000000..20d4f1b --- /dev/null +++ b/flap/tests/01-Parsing/74-lambda-2.good.expected @@ -0,0 +1 @@ +let k = \ (x, y) -> x diff --git a/flap/tests/01-Parsing/74-lambda-2.good.parsing.hopix b/flap/tests/01-Parsing/74-lambda-2.good.parsing.hopix new file mode 100644 index 0000000..da357e8 --- /dev/null +++ b/flap/tests/01-Parsing/74-lambda-2.good.parsing.hopix @@ -0,0 +1 @@ +let k = \(x, y) -> x \ No newline at end of file diff --git a/flap/tests/01-Parsing/75-lambda-3.bad.expected b/flap/tests/01-Parsing/75-lambda-3.bad.expected new file mode 100644 index 0000000..8b8a9f1 --- /dev/null +++ b/flap/tests/01-Parsing/75-lambda-3.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 16-17: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/75-lambda-3.bad.parsing.hopix b/flap/tests/01-Parsing/75-lambda-3.bad.parsing.hopix new file mode 100644 index 0000000..a9b76e2 --- /dev/null +++ b/flap/tests/01-Parsing/75-lambda-3.bad.parsing.hopix @@ -0,0 +1 @@ +let k3 = \(x, y z) -> x \ No newline at end of file diff --git a/flap/tests/01-Parsing/75-lambda-3.good.expected b/flap/tests/01-Parsing/75-lambda-3.good.expected new file mode 100644 index 0000000..00eb918 --- /dev/null +++ b/flap/tests/01-Parsing/75-lambda-3.good.expected @@ -0,0 +1 @@ +let k3 = \ (x, y, z) -> x diff --git a/flap/tests/01-Parsing/75-lambda-3.good.parsing.hopix b/flap/tests/01-Parsing/75-lambda-3.good.parsing.hopix new file mode 100644 index 0000000..0b446ca --- /dev/null +++ b/flap/tests/01-Parsing/75-lambda-3.good.parsing.hopix @@ -0,0 +1 @@ +let k3 = \(x, y, z) -> x \ No newline at end of file diff --git a/flap/tests/01-Parsing/76-lambda-4.bad.expected b/flap/tests/01-Parsing/76-lambda-4.bad.expected new file mode 100644 index 0000000..43cf843 --- /dev/null +++ b/flap/tests/01-Parsing/76-lambda-4.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 13-14: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/76-lambda-4.bad.parsing.hopix b/flap/tests/01-Parsing/76-lambda-4.bad.parsing.hopix new file mode 100644 index 0000000..7fdfd9c --- /dev/null +++ b/flap/tests/01-Parsing/76-lambda-4.bad.parsing.hopix @@ -0,0 +1 @@ +let zero = \__ -> 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing/76-lambda-4.good.expected b/flap/tests/01-Parsing/76-lambda-4.good.expected new file mode 100644 index 0000000..7cc83af --- /dev/null +++ b/flap/tests/01-Parsing/76-lambda-4.good.expected @@ -0,0 +1 @@ +let zero = \ _ -> 0 diff --git a/flap/tests/01-Parsing/76-lambda-4.good.parsing.hopix b/flap/tests/01-Parsing/76-lambda-4.good.parsing.hopix new file mode 100644 index 0000000..1a76fda --- /dev/null +++ b/flap/tests/01-Parsing/76-lambda-4.good.parsing.hopix @@ -0,0 +1 @@ +let zero = \_ -> 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing/77-application-1.bad.expected b/flap/tests/01-Parsing/77-application-1.bad.expected new file mode 100644 index 0000000..a5cedba --- /dev/null +++ b/flap/tests/01-Parsing/77-application-1.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 4-5: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/77-application-1.bad.parsing.hopix b/flap/tests/01-Parsing/77-application-1.bad.parsing.hopix new file mode 100644 index 0000000..0906a98 --- /dev/null +++ b/flap/tests/01-Parsing/77-application-1.bad.parsing.hopix @@ -0,0 +1 @@ +let = id \ No newline at end of file diff --git a/flap/tests/01-Parsing/77-application-1.good.expected b/flap/tests/01-Parsing/77-application-1.good.expected new file mode 100644 index 0000000..673eca8 --- /dev/null +++ b/flap/tests/01-Parsing/77-application-1.good.expected @@ -0,0 +1 @@ +let zero = id 0 diff --git a/flap/tests/01-Parsing/77-application-1.good.parsing.hopix b/flap/tests/01-Parsing/77-application-1.good.parsing.hopix new file mode 100644 index 0000000..7ee62ef --- /dev/null +++ b/flap/tests/01-Parsing/77-application-1.good.parsing.hopix @@ -0,0 +1 @@ +let zero = id 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing/78-application-2.bad.expected b/flap/tests/01-Parsing/78-application-2.bad.expected new file mode 100644 index 0000000..98480ce --- /dev/null +++ b/flap/tests/01-Parsing/78-application-2.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 33-33: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/78-application-2.bad.parsing.hopix b/flap/tests/01-Parsing/78-application-2.bad.parsing.hopix new file mode 100644 index 0000000..452e909 --- /dev/null +++ b/flap/tests/01-Parsing/78-application-2.bad.parsing.hopix @@ -0,0 +1 @@ +let compose = ((id id) (id id) id \ No newline at end of file diff --git a/flap/tests/01-Parsing/78-application-2.good.expected b/flap/tests/01-Parsing/78-application-2.good.expected new file mode 100644 index 0000000..308f961 --- /dev/null +++ b/flap/tests/01-Parsing/78-application-2.good.expected @@ -0,0 +1 @@ +let compose = ((id id) (id id)) id diff --git a/flap/tests/01-Parsing/78-application-2.good.parsing.hopix b/flap/tests/01-Parsing/78-application-2.good.parsing.hopix new file mode 100644 index 0000000..a2193cb --- /dev/null +++ b/flap/tests/01-Parsing/78-application-2.good.parsing.hopix @@ -0,0 +1 @@ +let compose = ((id id) (id id)) id \ No newline at end of file diff --git a/flap/tests/01-Parsing/79-application-3.bad.expected b/flap/tests/01-Parsing/79-application-3.bad.expected new file mode 100644 index 0000000..fe691fa --- /dev/null +++ b/flap/tests/01-Parsing/79-application-3.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 15-16: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/79-application-3.bad.parsing.hopix b/flap/tests/01-Parsing/79-application-3.bad.parsing.hopix new file mode 100644 index 0000000..e486dca --- /dev/null +++ b/flap/tests/01-Parsing/79-application-3.bad.parsing.hopix @@ -0,0 +1 @@ +let beta = (\x - x) 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing/79-application-3.good.expected b/flap/tests/01-Parsing/79-application-3.good.expected new file mode 100644 index 0000000..e43c770 --- /dev/null +++ b/flap/tests/01-Parsing/79-application-3.good.expected @@ -0,0 +1 @@ +let beta = (\ x -> x) 0 diff --git a/flap/tests/01-Parsing/79-application-3.good.parsing.hopix b/flap/tests/01-Parsing/79-application-3.good.parsing.hopix new file mode 100644 index 0000000..02de3d9 --- /dev/null +++ b/flap/tests/01-Parsing/79-application-3.good.parsing.hopix @@ -0,0 +1 @@ +let beta = (\x -> x) 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing/80-application-4.bad.expected b/flap/tests/01-Parsing/80-application-4.bad.expected new file mode 100644 index 0000000..2d8402c --- /dev/null +++ b/flap/tests/01-Parsing/80-application-4.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 21-21: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/80-application-4.bad.parsing.hopix b/flap/tests/01-Parsing/80-application-4.bad.parsing.hopix new file mode 100644 index 0000000..078c81c --- /dev/null +++ b/flap/tests/01-Parsing/80-application-4.bad.parsing.hopix @@ -0,0 +1 @@ +let eta = \f -> \x -> \ No newline at end of file diff --git a/flap/tests/01-Parsing/80-application-4.good.expected b/flap/tests/01-Parsing/80-application-4.good.expected new file mode 100644 index 0000000..bf57bfb --- /dev/null +++ b/flap/tests/01-Parsing/80-application-4.good.expected @@ -0,0 +1 @@ +let eta = \ f -> (\ x -> (f x)) diff --git a/flap/tests/01-Parsing/80-application-4.good.parsing.hopix b/flap/tests/01-Parsing/80-application-4.good.parsing.hopix new file mode 100644 index 0000000..01e2a2e --- /dev/null +++ b/flap/tests/01-Parsing/80-application-4.good.parsing.hopix @@ -0,0 +1 @@ +let eta = \f -> \x -> f x \ No newline at end of file diff --git a/flap/tests/01-Parsing/81-application-5.bad.expected b/flap/tests/01-Parsing/81-application-5.bad.expected new file mode 100644 index 0000000..edba7ab --- /dev/null +++ b/flap/tests/01-Parsing/81-application-5.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 17-17: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/81-application-5.bad.parsing.hopix b/flap/tests/01-Parsing/81-application-5.bad.parsing.hopix new file mode 100644 index 0000000..35fb031 --- /dev/null +++ b/flap/tests/01-Parsing/81-application-5.bad.parsing.hopix @@ -0,0 +1 @@ +let omega = \x -> \ No newline at end of file diff --git a/flap/tests/01-Parsing/81-application-5.good.expected b/flap/tests/01-Parsing/81-application-5.good.expected new file mode 100644 index 0000000..822cb1a --- /dev/null +++ b/flap/tests/01-Parsing/81-application-5.good.expected @@ -0,0 +1 @@ +let omega = \ x -> (x x) diff --git a/flap/tests/01-Parsing/81-application-5.good.parsing.hopix b/flap/tests/01-Parsing/81-application-5.good.parsing.hopix new file mode 100644 index 0000000..ce64b5b --- /dev/null +++ b/flap/tests/01-Parsing/81-application-5.good.parsing.hopix @@ -0,0 +1 @@ +let omega = \x -> x x \ No newline at end of file diff --git a/flap/tests/01-Parsing/82-application-6.bad.expected b/flap/tests/01-Parsing/82-application-6.bad.expected new file mode 100644 index 0000000..835010d --- /dev/null +++ b/flap/tests/01-Parsing/82-application-6.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 14-15: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/82-application-6.bad.parsing.hopix b/flap/tests/01-Parsing/82-application-6.bad.parsing.hopix new file mode 100644 index 0000000..1f19b71 --- /dev/null +++ b/flap/tests/01-Parsing/82-application-6.bad.parsing.hopix @@ -0,0 +1 @@ +let bad_man = _0 \ No newline at end of file diff --git a/flap/tests/01-Parsing/82-application-6.good.expected b/flap/tests/01-Parsing/82-application-6.good.expected new file mode 100644 index 0000000..cb717f6 --- /dev/null +++ b/flap/tests/01-Parsing/82-application-6.good.expected @@ -0,0 +1 @@ +let bad_man = 0 0 diff --git a/flap/tests/01-Parsing/82-application-6.good.parsing.hopix b/flap/tests/01-Parsing/82-application-6.good.parsing.hopix new file mode 100644 index 0000000..c4d5026 --- /dev/null +++ b/flap/tests/01-Parsing/82-application-6.good.parsing.hopix @@ -0,0 +1 @@ +let bad_man = 0 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing/83-application-7.bad.expected b/flap/tests/01-Parsing/83-application-7.bad.expected new file mode 100644 index 0000000..5a58af3 --- /dev/null +++ b/flap/tests/01-Parsing/83-application-7.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 60-60: Error (during lexing) + Unterminated string. diff --git a/flap/tests/01-Parsing/83-application-7.bad.parsing.hopix b/flap/tests/01-Parsing/83-application-7.bad.parsing.hopix new file mode 100644 index 0000000..4a35c99 --- /dev/null +++ b/flap/tests/01-Parsing/83-application-7.bad.parsing.hopix @@ -0,0 +1 @@ +let invalid = "This is crazy" (0, 1, 3, "Stop this madness!) \ No newline at end of file diff --git a/flap/tests/01-Parsing/83-application-7.good.expected b/flap/tests/01-Parsing/83-application-7.good.expected new file mode 100644 index 0000000..9f33874 --- /dev/null +++ b/flap/tests/01-Parsing/83-application-7.good.expected @@ -0,0 +1 @@ +let invalid = "This is crazy" (0, 1, 3, "Stop this madness!") diff --git a/flap/tests/01-Parsing/83-application-7.good.parsing.hopix b/flap/tests/01-Parsing/83-application-7.good.parsing.hopix new file mode 100644 index 0000000..2863571 --- /dev/null +++ b/flap/tests/01-Parsing/83-application-7.good.parsing.hopix @@ -0,0 +1 @@ +let invalid = "This is crazy" (0, 1, 3, "Stop this madness!") \ No newline at end of file diff --git a/flap/tests/01-Parsing/84-infix-application-1.bad.expected b/flap/tests/01-Parsing/84-infix-application-1.bad.expected new file mode 100644 index 0000000..835010d --- /dev/null +++ b/flap/tests/01-Parsing/84-infix-application-1.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 14-15: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/84-infix-application-1.bad.parsing.hopix b/flap/tests/01-Parsing/84-infix-application-1.bad.parsing.hopix new file mode 100644 index 0000000..9b0b593 --- /dev/null +++ b/flap/tests/01-Parsing/84-infix-application-1.bad.parsing.hopix @@ -0,0 +1 @@ +let toto = 0 ++ 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing/84-infix-application-1.good.expected b/flap/tests/01-Parsing/84-infix-application-1.good.expected new file mode 100644 index 0000000..383f7a1 --- /dev/null +++ b/flap/tests/01-Parsing/84-infix-application-1.good.expected @@ -0,0 +1 @@ +let toto = (0 + 0) diff --git a/flap/tests/01-Parsing/84-infix-application-1.good.parsing.hopix b/flap/tests/01-Parsing/84-infix-application-1.good.parsing.hopix new file mode 100644 index 0000000..41bb124 --- /dev/null +++ b/flap/tests/01-Parsing/84-infix-application-1.good.parsing.hopix @@ -0,0 +1 @@ +let toto = 0 + 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing/85-infix-application-2.bad.expected b/flap/tests/01-Parsing/85-infix-application-2.bad.expected new file mode 100644 index 0000000..ffc0414 --- /dev/null +++ b/flap/tests/01-Parsing/85-infix-application-2.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 36-37: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/85-infix-application-2.bad.parsing.hopix b/flap/tests/01-Parsing/85-infix-application-2.bad.parsing.hopix new file mode 100644 index 0000000..8e40722 --- /dev/null +++ b/flap/tests/01-Parsing/85-infix-application-2.bad.parsing.hopix @@ -0,0 +1 @@ +let harder_than_you_think = a * a / / b * b + c * c \ No newline at end of file diff --git a/flap/tests/01-Parsing/85-infix-application-2.good.expected b/flap/tests/01-Parsing/85-infix-application-2.good.expected new file mode 100644 index 0000000..3e65fb5 --- /dev/null +++ b/flap/tests/01-Parsing/85-infix-application-2.good.expected @@ -0,0 +1 @@ +let harder_than_you_think = (((a * a) + (b * b)) + (c * c)) diff --git a/flap/tests/01-Parsing/85-infix-application-2.good.parsing.hopix b/flap/tests/01-Parsing/85-infix-application-2.good.parsing.hopix new file mode 100644 index 0000000..7de3890 --- /dev/null +++ b/flap/tests/01-Parsing/85-infix-application-2.good.parsing.hopix @@ -0,0 +1 @@ +let harder_than_you_think = a * a + b * b + c * c \ No newline at end of file diff --git a/flap/tests/01-Parsing/86-infix-application-3.bad.expected b/flap/tests/01-Parsing/86-infix-application-3.bad.expected new file mode 100644 index 0000000..0638350 --- /dev/null +++ b/flap/tests/01-Parsing/86-infix-application-3.bad.expected @@ -0,0 +1,2 @@ +Line 2, characters 42-42: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/86-infix-application-3.bad.parsing.hopix b/flap/tests/01-Parsing/86-infix-application-3.bad.parsing.hopix new file mode 100644 index 0000000..2ba22c4 --- /dev/null +++ b/flap/tests/01-Parsing/86-infix-application-3.bad.parsing.hopix @@ -0,0 +1,2 @@ +let arithmetic_complexity = + 1 + 2 * 3 / 4 / 5 - 6 - 7 + 8 + 9 * 10 - \ No newline at end of file diff --git a/flap/tests/01-Parsing/86-infix-application-3.good.expected b/flap/tests/01-Parsing/86-infix-application-3.good.expected new file mode 100644 index 0000000..d6b4af9 --- /dev/null +++ b/flap/tests/01-Parsing/86-infix-application-3.good.expected @@ -0,0 +1,2 @@ +let arithmetic_complexity = + (((((1 + (((2 * 3) / 4) / 5)) - 6) - 7) + 8) + (9 * 10)) diff --git a/flap/tests/01-Parsing/86-infix-application-3.good.parsing.hopix b/flap/tests/01-Parsing/86-infix-application-3.good.parsing.hopix new file mode 100644 index 0000000..9ca5b3d --- /dev/null +++ b/flap/tests/01-Parsing/86-infix-application-3.good.parsing.hopix @@ -0,0 +1,2 @@ +let arithmetic_complexity = + 1 + 2 * 3 / 4 / 5 - 6 - 7 + 8 + 9 * 10 \ No newline at end of file diff --git a/flap/tests/01-Parsing/87-infix-application-4.bad.expected b/flap/tests/01-Parsing/87-infix-application-4.bad.expected new file mode 100644 index 0000000..7328421 --- /dev/null +++ b/flap/tests/01-Parsing/87-infix-application-4.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 60-61: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/87-infix-application-4.bad.parsing.hopix b/flap/tests/01-Parsing/87-infix-application-4.bad.parsing.hopix new file mode 100644 index 0000000..71cae37 --- /dev/null +++ b/flap/tests/01-Parsing/87-infix-application-4.bad.parsing.hopix @@ -0,0 +1 @@ +let cycle_of_life = lion eats giraffe eats grass eats lion ++ \ No newline at end of file diff --git a/flap/tests/01-Parsing/87-infix-application-4.good.expected b/flap/tests/01-Parsing/87-infix-application-4.good.expected new file mode 100644 index 0000000..f125965 --- /dev/null +++ b/flap/tests/01-Parsing/87-infix-application-4.good.expected @@ -0,0 +1,2 @@ +let cycle_of_life = + (((((lion eats) giraffe) eats) grass) eats) lion diff --git a/flap/tests/01-Parsing/87-infix-application-4.good.parsing.hopix b/flap/tests/01-Parsing/87-infix-application-4.good.parsing.hopix new file mode 100644 index 0000000..a926d3a --- /dev/null +++ b/flap/tests/01-Parsing/87-infix-application-4.good.parsing.hopix @@ -0,0 +1 @@ +let cycle_of_life = lion eats giraffe eats grass eats lion \ No newline at end of file diff --git a/flap/tests/01-Parsing/88-case-1.bad.expected b/flap/tests/01-Parsing/88-case-1.bad.expected new file mode 100644 index 0000000..4536094 --- /dev/null +++ b/flap/tests/01-Parsing/88-case-1.bad.expected @@ -0,0 +1,2 @@ +Line 3, characters 11-12: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/88-case-1.bad.parsing.hopix b/flap/tests/01-Parsing/88-case-1.bad.parsing.hopix new file mode 100644 index 0000000..162954f --- /dev/null +++ b/flap/tests/01-Parsing/88-case-1.bad.parsing.hopix @@ -0,0 +1,7 @@ +let style_evaluation = + match (hair_color) { + | Red => Good + | Yellow => Good + | Brown => Good + | _ => Good + } \ No newline at end of file diff --git a/flap/tests/01-Parsing/88-case-1.good.expected b/flap/tests/01-Parsing/88-case-1.good.expected new file mode 100644 index 0000000..26e1a1b --- /dev/null +++ b/flap/tests/01-Parsing/88-case-1.good.expected @@ -0,0 +1,4 @@ +let style_evaluation = + match (hair_color) { + | Red -> Good | Yellow -> Good | Brown -> Good | _ -> Good + } diff --git a/flap/tests/01-Parsing/88-case-1.good.parsing.hopix b/flap/tests/01-Parsing/88-case-1.good.parsing.hopix new file mode 100644 index 0000000..8602f2c --- /dev/null +++ b/flap/tests/01-Parsing/88-case-1.good.parsing.hopix @@ -0,0 +1,7 @@ +let style_evaluation = + match (hair_color) { + | Red -> Good + | Yellow -> Good + | Brown -> Good + | _ -> Good + } \ No newline at end of file diff --git a/flap/tests/01-Parsing/89-case-2.bad.expected b/flap/tests/01-Parsing/89-case-2.bad.expected new file mode 100644 index 0000000..4536094 --- /dev/null +++ b/flap/tests/01-Parsing/89-case-2.bad.expected @@ -0,0 +1,2 @@ +Line 3, characters 11-12: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/89-case-2.bad.parsing.hopix b/flap/tests/01-Parsing/89-case-2.bad.parsing.hopix new file mode 100644 index 0000000..0f9cb4d --- /dev/null +++ b/flap/tests/01-Parsing/89-case-2.bad.parsing.hopix @@ -0,0 +1,4 @@ +let what_is_in_the_box = + match (box) { + { box = } -> box + } \ No newline at end of file diff --git a/flap/tests/01-Parsing/89-case-2.good.expected b/flap/tests/01-Parsing/89-case-2.good.expected new file mode 100644 index 0000000..f99ea21 --- /dev/null +++ b/flap/tests/01-Parsing/89-case-2.good.expected @@ -0,0 +1 @@ +let what_is_in_the_box = match (box) { | {box = box} -> box } diff --git a/flap/tests/01-Parsing/89-case-2.good.parsing.hopix b/flap/tests/01-Parsing/89-case-2.good.parsing.hopix new file mode 100644 index 0000000..1ee8812 --- /dev/null +++ b/flap/tests/01-Parsing/89-case-2.good.parsing.hopix @@ -0,0 +1,4 @@ +let what_is_in_the_box = + match (box) { + { box = box } -> box + } \ No newline at end of file diff --git a/flap/tests/01-Parsing/90-case-3.bad.expected b/flap/tests/01-Parsing/90-case-3.bad.expected new file mode 100644 index 0000000..fa1aa4b --- /dev/null +++ b/flap/tests/01-Parsing/90-case-3.bad.expected @@ -0,0 +1,2 @@ +Line 7, characters 2-3: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/90-case-3.bad.parsing.hopix b/flap/tests/01-Parsing/90-case-3.bad.parsing.hopix new file mode 100644 index 0000000..41314ff --- /dev/null +++ b/flap/tests/01-Parsing/90-case-3.bad.parsing.hopix @@ -0,0 +1,7 @@ +let menu = + match (choice) { + | Coffee | Tea -> OK + | Chocolate -> OK + | Beer -> AreYouSure + | _ -> + } \ No newline at end of file diff --git a/flap/tests/01-Parsing/90-case-3.good.expected b/flap/tests/01-Parsing/90-case-3.good.expected new file mode 100644 index 0000000..4bb6573 --- /dev/null +++ b/flap/tests/01-Parsing/90-case-3.good.expected @@ -0,0 +1,7 @@ +let menu = + match (choice) { + | (Coffee | Tea) -> OK + | Chocolate -> OK + | Beer -> AreYouSure + | _ -> KO + } diff --git a/flap/tests/01-Parsing/90-case-3.good.parsing.hopix b/flap/tests/01-Parsing/90-case-3.good.parsing.hopix new file mode 100644 index 0000000..a2262b2 --- /dev/null +++ b/flap/tests/01-Parsing/90-case-3.good.parsing.hopix @@ -0,0 +1,7 @@ +let menu = + match (choice) { + | Coffee | Tea -> OK + | Chocolate -> OK + | Beer -> AreYouSure + | _ -> KO + } \ No newline at end of file diff --git a/flap/tests/01-Parsing/91-case-4.bad.expected b/flap/tests/01-Parsing/91-case-4.bad.expected new file mode 100644 index 0000000..8bfa741 --- /dev/null +++ b/flap/tests/01-Parsing/91-case-4.bad.expected @@ -0,0 +1,2 @@ +Line 5, characters 0-0: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/91-case-4.bad.parsing.hopix b/flap/tests/01-Parsing/91-case-4.bad.parsing.hopix new file mode 100644 index 0000000..52318d4 --- /dev/null +++ b/flap/tests/01-Parsing/91-case-4.bad.parsing.hopix @@ -0,0 +1,4 @@ +let nest = + match (bird) { + Nest (Some (bird)) -> bird + | Nest (None) -> nothing diff --git a/flap/tests/01-Parsing/91-case-4.good.expected b/flap/tests/01-Parsing/91-case-4.good.expected new file mode 100644 index 0000000..e5893ca --- /dev/null +++ b/flap/tests/01-Parsing/91-case-4.good.expected @@ -0,0 +1,4 @@ +let nest = + match (bird) { + | Nest(Some(bird)) -> bird | Nest(None) -> nothing + } diff --git a/flap/tests/01-Parsing/91-case-4.good.parsing.hopix b/flap/tests/01-Parsing/91-case-4.good.parsing.hopix new file mode 100644 index 0000000..d47a83c --- /dev/null +++ b/flap/tests/01-Parsing/91-case-4.good.parsing.hopix @@ -0,0 +1,5 @@ +let nest = + match (bird) { + Nest (Some (bird)) -> bird + | Nest (None) -> nothing + } \ No newline at end of file diff --git a/flap/tests/01-Parsing/92-case-5.bad.expected b/flap/tests/01-Parsing/92-case-5.bad.expected new file mode 100644 index 0000000..9d2c653 --- /dev/null +++ b/flap/tests/01-Parsing/92-case-5.bad.expected @@ -0,0 +1,2 @@ +Line 3, characters 19-20: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/92-case-5.bad.parsing.hopix b/flap/tests/01-Parsing/92-case-5.bad.parsing.hopix new file mode 100644 index 0000000..e526b7e --- /dev/null +++ b/flap/tests/01-Parsing/92-case-5.bad.parsing.hopix @@ -0,0 +1,5 @@ +let main = + match (some_value) { + | Some ({ box = _; other_box = (Some (_) & got_you) }) -> got_you + | None -> None + } \ No newline at end of file diff --git a/flap/tests/01-Parsing/92-case-5.good.expected b/flap/tests/01-Parsing/92-case-5.good.expected new file mode 100644 index 0000000..c345ec8 --- /dev/null +++ b/flap/tests/01-Parsing/92-case-5.good.expected @@ -0,0 +1,5 @@ +let main = + match (some_value) { + | Some({box = _, other_box = (Some(_) & got_you)} ) -> got_you + | None -> None + } diff --git a/flap/tests/01-Parsing/92-case-5.good.parsing.hopix b/flap/tests/01-Parsing/92-case-5.good.parsing.hopix new file mode 100644 index 0000000..2f50dd9 --- /dev/null +++ b/flap/tests/01-Parsing/92-case-5.good.parsing.hopix @@ -0,0 +1,5 @@ +let main = + match (some_value) { + | Some ({ box = _, other_box = (Some (_) & got_you) }) -> got_you + | None -> None + } \ No newline at end of file diff --git a/flap/tests/01-Parsing/93-case-6.bad.expected b/flap/tests/01-Parsing/93-case-6.bad.expected new file mode 100644 index 0000000..0a36a97 --- /dev/null +++ b/flap/tests/01-Parsing/93-case-6.bad.expected @@ -0,0 +1,2 @@ +Line 4, characters 6-8: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/93-case-6.bad.parsing.hopix b/flap/tests/01-Parsing/93-case-6.bad.parsing.hopix new file mode 100644 index 0000000..50f9df0 --- /dev/null +++ b/flap/tests/01-Parsing/93-case-6.bad.parsing.hopix @@ -0,0 +1,5 @@ +let omg = + match (some_value) { + | "Some string" -> 0 + 'a' -> 2 + } \ No newline at end of file diff --git a/flap/tests/01-Parsing/93-case-6.good.expected b/flap/tests/01-Parsing/93-case-6.good.expected new file mode 100644 index 0000000..bd415c9 --- /dev/null +++ b/flap/tests/01-Parsing/93-case-6.good.expected @@ -0,0 +1,2 @@ +let omg = + match (some_value) { | "Some string" -> 0 | 0 -> 1 | 'a' -> 2 } diff --git a/flap/tests/01-Parsing/93-case-6.good.parsing.hopix b/flap/tests/01-Parsing/93-case-6.good.parsing.hopix new file mode 100644 index 0000000..f86e092 --- /dev/null +++ b/flap/tests/01-Parsing/93-case-6.good.parsing.hopix @@ -0,0 +1,6 @@ +let omg = + match (some_value) { + | "Some string" -> 0 + | 0 -> 1 + | 'a' -> 2 + } \ No newline at end of file diff --git a/flap/tests/01-Parsing/94-case-7.bad.expected b/flap/tests/01-Parsing/94-case-7.bad.expected new file mode 100644 index 0000000..726e72d --- /dev/null +++ b/flap/tests/01-Parsing/94-case-7.bad.expected @@ -0,0 +1,2 @@ +Line 3, characters 7-8: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/94-case-7.bad.parsing.hopix b/flap/tests/01-Parsing/94-case-7.bad.parsing.hopix new file mode 100644 index 0000000..0add8b9 --- /dev/null +++ b/flap/tests/01-Parsing/94-case-7.bad.parsing.hopix @@ -0,0 +1,4 @@ +let mono = + match (p) { + | (x y) -> x + y + } \ No newline at end of file diff --git a/flap/tests/01-Parsing/94-case-7.good.expected b/flap/tests/01-Parsing/94-case-7.good.expected new file mode 100644 index 0000000..8530ead --- /dev/null +++ b/flap/tests/01-Parsing/94-case-7.good.expected @@ -0,0 +1 @@ +let mono = match (p) { | (x, y) -> ((x + y)) } diff --git a/flap/tests/01-Parsing/94-case-7.good.parsing.hopix b/flap/tests/01-Parsing/94-case-7.good.parsing.hopix new file mode 100644 index 0000000..a3c6e6b --- /dev/null +++ b/flap/tests/01-Parsing/94-case-7.good.parsing.hopix @@ -0,0 +1,4 @@ +let mono = + match (p) { + | (x, y) -> x + y + } \ No newline at end of file diff --git a/flap/tests/01-Parsing/95-case-8.bad.expected b/flap/tests/01-Parsing/95-case-8.bad.expected new file mode 100644 index 0000000..a946aa7 --- /dev/null +++ b/flap/tests/01-Parsing/95-case-8.bad.expected @@ -0,0 +1,2 @@ +Line 2, characters 8-9: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/95-case-8.bad.parsing.hopix b/flap/tests/01-Parsing/95-case-8.bad.parsing.hopix new file mode 100644 index 0000000..3baac70 --- /dev/null +++ b/flap/tests/01-Parsing/95-case-8.bad.parsing.hopix @@ -0,0 +1,2 @@ +let polybox = + match x { { box = y } -> y } diff --git a/flap/tests/01-Parsing/95-case-8.good.expected b/flap/tests/01-Parsing/95-case-8.good.expected new file mode 100644 index 0000000..ab1bdc0 --- /dev/null +++ b/flap/tests/01-Parsing/95-case-8.good.expected @@ -0,0 +1 @@ +let polybox = match (x) { | {box = y} < int > -> y } diff --git a/flap/tests/01-Parsing/95-case-8.good.parsing.hopix b/flap/tests/01-Parsing/95-case-8.good.parsing.hopix new file mode 100644 index 0000000..cf27826 --- /dev/null +++ b/flap/tests/01-Parsing/95-case-8.good.parsing.hopix @@ -0,0 +1,2 @@ +let polybox = + match (x) { { box = y } -> y } diff --git a/flap/tests/01-Parsing/96-if-then-else.bad.expected b/flap/tests/01-Parsing/96-if-then-else.bad.expected new file mode 100644 index 0000000..59a1c0f --- /dev/null +++ b/flap/tests/01-Parsing/96-if-then-else.bad.expected @@ -0,0 +1,2 @@ +Line 2, characters 5-9: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/96-if-then-else.bad.parsing.hopix b/flap/tests/01-Parsing/96-if-then-else.bad.parsing.hopix new file mode 100644 index 0000000..32434e6 --- /dev/null +++ b/flap/tests/01-Parsing/96-if-then-else.bad.parsing.hopix @@ -0,0 +1,2 @@ +let main = + if True then { 0 } else { 1 } \ No newline at end of file diff --git a/flap/tests/01-Parsing/96-if-then-else.good.expected b/flap/tests/01-Parsing/96-if-then-else.good.expected new file mode 100644 index 0000000..0ebadd4 --- /dev/null +++ b/flap/tests/01-Parsing/96-if-then-else.good.expected @@ -0,0 +1 @@ +let main = if (True) then { 0 } else { 1 } diff --git a/flap/tests/01-Parsing/96-if-then-else.good.parsing.hopix b/flap/tests/01-Parsing/96-if-then-else.good.parsing.hopix new file mode 100644 index 0000000..c98c356 --- /dev/null +++ b/flap/tests/01-Parsing/96-if-then-else.good.parsing.hopix @@ -0,0 +1,2 @@ +let main = + if (True) then { 0 } else { 1 } \ No newline at end of file diff --git a/flap/tests/01-Parsing/97-if-then-else-2.bad.expected b/flap/tests/01-Parsing/97-if-then-else-2.bad.expected new file mode 100644 index 0000000..0bc1944 --- /dev/null +++ b/flap/tests/01-Parsing/97-if-then-else-2.bad.expected @@ -0,0 +1,2 @@ +let main = + if (failure 0) then { print error_message } else { () } diff --git a/flap/tests/01-Parsing/97-if-then-else-2.bad.parsing.hopix b/flap/tests/01-Parsing/97-if-then-else-2.bad.parsing.hopix new file mode 100644 index 0000000..a15dcda --- /dev/null +++ b/flap/tests/01-Parsing/97-if-then-else-2.bad.parsing.hopix @@ -0,0 +1,4 @@ +let main = + if (failure 0) then { + print error_message + } \ No newline at end of file diff --git a/flap/tests/01-Parsing/97-if-then-else-2.good.expected b/flap/tests/01-Parsing/97-if-then-else-2.good.expected new file mode 100644 index 0000000..ccd0cf1 --- /dev/null +++ b/flap/tests/01-Parsing/97-if-then-else-2.good.expected @@ -0,0 +1,3 @@ +let main = + if (failure 0) then { print error_message } + else { exit EXIT_FAILURE } diff --git a/flap/tests/01-Parsing/97-if-then-else-2.good.parsing.hopix b/flap/tests/01-Parsing/97-if-then-else-2.good.parsing.hopix new file mode 100644 index 0000000..9ef21a1 --- /dev/null +++ b/flap/tests/01-Parsing/97-if-then-else-2.good.parsing.hopix @@ -0,0 +1,6 @@ +let main = + if (failure 0) then { + print error_message + } else { + exit EXIT_FAILURE + } \ No newline at end of file diff --git a/flap/tests/01-Parsing/98-if-then-else-3.bad.expected b/flap/tests/01-Parsing/98-if-then-else-3.bad.expected new file mode 100644 index 0000000..beb889f --- /dev/null +++ b/flap/tests/01-Parsing/98-if-then-else-3.bad.expected @@ -0,0 +1,2 @@ +Line 3, characters 23-24: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/98-if-then-else-3.bad.parsing.hopix b/flap/tests/01-Parsing/98-if-then-else-3.bad.parsing.hopix new file mode 100644 index 0000000..e03cbcd --- /dev/null +++ b/flap/tests/01-Parsing/98-if-then-else-3.bad.parsing.hopix @@ -0,0 +1,5 @@ +let sequence = + if (x =? 0) then { foo 0 + } else { if (x ? 0) { baz 0 + } else { live 0 } } } \ No newline at end of file diff --git a/flap/tests/01-Parsing/98-if-then-else-3.good.expected b/flap/tests/01-Parsing/98-if-then-else-3.good.expected new file mode 100644 index 0000000..39107b6 --- /dev/null +++ b/flap/tests/01-Parsing/98-if-then-else-3.good.expected @@ -0,0 +1,7 @@ +let sequence = + if ((x =? 0)) then { foo 0 } + else + { + if ((x ? 0)) then { baz 0 } else { live 0 } } + } diff --git a/flap/tests/01-Parsing/98-if-then-else-3.good.parsing.hopix b/flap/tests/01-Parsing/98-if-then-else-3.good.parsing.hopix new file mode 100644 index 0000000..47e320a --- /dev/null +++ b/flap/tests/01-Parsing/98-if-then-else-3.good.parsing.hopix @@ -0,0 +1,5 @@ +let sequence = + if (x =? 0) then { foo 0 + } else { if (x ? 0) then { baz 0 + } else { live 0 } } } \ No newline at end of file diff --git a/flap/tests/01-Parsing/98-if-then-else-4.bad.expected b/flap/tests/01-Parsing/98-if-then-else-4.bad.expected new file mode 100644 index 0000000..e247f7b --- /dev/null +++ b/flap/tests/01-Parsing/98-if-then-else-4.bad.expected @@ -0,0 +1,2 @@ +Line 2, characters 14-15: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/98-if-then-else-4.bad.parsing.hopix b/flap/tests/01-Parsing/98-if-then-else-4.bad.parsing.hopix new file mode 100644 index 0000000..bf7fb40 --- /dev/null +++ b/flap/tests/01-Parsing/98-if-then-else-4.bad.parsing.hopix @@ -0,0 +1,2 @@ +let inner = + if (x =? 0) { if (y =? 1) { 0 } else { 1 } else { 2 } \ No newline at end of file diff --git a/flap/tests/01-Parsing/98-if-then-else-4.good.expected b/flap/tests/01-Parsing/98-if-then-else-4.good.expected new file mode 100644 index 0000000..a181c17 --- /dev/null +++ b/flap/tests/01-Parsing/98-if-then-else-4.good.expected @@ -0,0 +1,3 @@ +let inner = + if ((x =? 0)) then { if ((y =? 1)) then { 0 } else { 1 } } + else { 2 } diff --git a/flap/tests/01-Parsing/98-if-then-else-4.good.parsing.hopix b/flap/tests/01-Parsing/98-if-then-else-4.good.parsing.hopix new file mode 100644 index 0000000..e0aaa35 --- /dev/null +++ b/flap/tests/01-Parsing/98-if-then-else-4.good.parsing.hopix @@ -0,0 +1,2 @@ +let inner = + if (x =? 0) then { if (y =? 1) then { 0 } else { 1 } } else { 2 } \ No newline at end of file diff --git a/flap/tests/01-Parsing/99-ref-1.bad.expected b/flap/tests/01-Parsing/99-ref-1.bad.expected new file mode 100644 index 0000000..e5bd27c --- /dev/null +++ b/flap/tests/01-Parsing/99-ref-1.bad.expected @@ -0,0 +1,2 @@ +Line 1, characters 11-11: Error (parsing) + Syntax error. diff --git a/flap/tests/01-Parsing/99-ref-1.bad.parsing.hopix b/flap/tests/01-Parsing/99-ref-1.bad.parsing.hopix new file mode 100644 index 0000000..037f61a --- /dev/null +++ b/flap/tests/01-Parsing/99-ref-1.bad.parsing.hopix @@ -0,0 +1 @@ +let x = ref \ No newline at end of file diff --git a/flap/tests/01-Parsing/99-ref-1.good.expected b/flap/tests/01-Parsing/99-ref-1.good.expected new file mode 100644 index 0000000..98bc2c7 --- /dev/null +++ b/flap/tests/01-Parsing/99-ref-1.good.expected @@ -0,0 +1 @@ +let x = ref 0 diff --git a/flap/tests/01-Parsing/99-ref-1.good.parsing.hopix b/flap/tests/01-Parsing/99-ref-1.good.parsing.hopix new file mode 100644 index 0000000..a9747c1 --- /dev/null +++ b/flap/tests/01-Parsing/99-ref-1.good.parsing.hopix @@ -0,0 +1 @@ +let x = ref 0 \ No newline at end of file diff --git a/flap/tests/01-Parsing/999-slam.good.expected b/flap/tests/01-Parsing/999-slam.good.expected new file mode 100644 index 0000000..58a5fcb --- /dev/null +++ b/flap/tests/01-Parsing/999-slam.good.expected @@ -0,0 +1,100 @@ +let x = 0 +let f = \ x -> x +fun g x = x +fun h (x, y) = ((x + i y)) and i z = (h (z, z)) +fun arithmetic + (x, y, z) = + ((((x + (y * z)) + ((x + y) * z)) + (z * (x + y)))) + +let some_Int = 12345 +let some_other_Int = 3405691582 +let some_other_other_Int = 1354 +let yet_another_Int = 30344 +let some_char = 'a' +let some_other_char = '@' +let some_other_other_char = '\170' +let yet_another_char = '\t' +let some_String = + "N'oubliez pas, car votre vie en d\233pend. Ne clignez pas des yeux. N'y pensez m\234me pas. Clignez et vous \234tes morts. Ils sont rapides, bien plus rapides que vous ne le croyez. Ne leur tournez pas le dos. Ne regardez pas ailleurs. Et surtout, ne clignez pas. Bonne chance." +let some_other_String = + "\n\n\t Le Docteur : Vous avez d\233truit l'inscription la plus ancienne de l'univers.\n\n\t River Song : Tu m'y as oblig\233e, tu ne r\233pondais pas au t\233l\233phone.\n\nOups\b\r\n" +let yet_another_String = "Say \"Hello!\"" +type int_list = + + INil | ICons (int, int_list) +type list<`a> = + + Nil | Cons (`a, list<`a>) +type llist<`a> = + + LNil | LCons (`a, unit -> llist<`a>) +type marthe_exp = + + EInt (int) + | EAdd (marthe_exp, marthe_exp) + | ESum (marthe_exp, marthe_exp) + | EVar (string) + | ESum (string, marthe_exp, marthe_exp, marthe_exp) + +type box = + { + what_s_in_the_box : int } +type person = + { + name : string , age : int } +type closure<`env, `a, `b> = + { + code : (`env * `a) -> `b , env : `env } +type container_functions<`e, `c, `b> = + { + map : (`e -> `a * `c) -> `c + , fold : (`e -> unit * `c) -> unit + , weird : `e -> ((`c * `e) -> `b) + } +let id : [`a]`a -> `a = \ x -> x +let id_int = id < int > +let stable = id < int > 37 +let compose : [`a, `b, `c](`a -> `b * `b -> `c) -> (`a -> `c) = + \ (f, g) -> (\ x -> (f (g x) : `c)) +let id_id_id = compose < int, int, int > (id, id) +let id_id_id_2 = + compose < (int -> int), (int -> int), (int -> int) > (id, id) +let an_empty_list = Nil < int > +let a_cool_list = + Cons < int >(1, Cons < int >(1, an_empty_list)) +let a_person = {name = "Luke", age = 28} +let a_name = a_person.name +let main = + (start_with_this 0); ((do_that ("foo", "bar")); (conclude 0)) +let computation = let y = 42 ; let z = 13 ; compute 0 +fun : [`a]list<`a> -> int len + l = + (match (l) { + | Nil < `a > -> 0 | Cons < `a >(x, xs) -> ((1 + len < `a > xs)) + }) + +fun fact + n = + (if ((n =? 0)) then { 1 } + else + { + if ((n =? 1)) then { 1 } + else { if ((n =? 2)) then { 2 } else { (fact ((n - 1)) * n) } } + }) + +fun ifact + n = + (let accu = (ref 1) ; + let k = (ref n) ; + while + (((! k) + >? + 0)) + { (accu := ((! accu) * (! k))); (k := ((! k) - 1)) }; + ((! accu))) + +fun ifact2 + n = + (let accu = (ref 1) ; + for k from (1) to (n) { accu := ((! accu) * k) }; ((! accu))) + diff --git a/flap/tests/01-Parsing/999-slam.good.parsing.hopix b/flap/tests/01-Parsing/999-slam.good.parsing.hopix new file mode 100644 index 0000000..e7e158f --- /dev/null +++ b/flap/tests/01-Parsing/999-slam.good.parsing.hopix @@ -0,0 +1,126 @@ +{* #* #* *# #* *# #* #* *# *# *# #* #* *# #* *# #* #* *# *# *# #* *# #* *# ** *} +{******************************************************************************} +{* THE HOPIX PARSING GREAT SLAM *} +{******************************************************************************} +{* #* #* *# #* *# #* #* *# *# *# #* #* *# #* *# #* #* *# *# *# #* *# #* *# ** *} + +let x = 0 + +let f = \x -> x + +fun g x = x + +fun h (x, y) = x + i y +and i z = h (z, z) + +fun arithmetic (x, y, z) = + x + y * z + (x + y) * z + z * (x + y) + +let some_Int = 12345 +let some_other_Int = 0xCAFEBABE +let some_other_other_Int = 0b00010101001010 +let yet_another_Int = 0o73210 + +let some_char = 'a' +let some_other_char = '\064' +let some_other_other_char = '\0xaa' +let yet_another_char = '\t' + +let some_String = + "N'oubliez pas, car votre vie en d\233pend. Ne clignez pas des yeux. N'y pensez m\234me pas. Clignez et vous \234tes morts. Ils sont rapides, bien plus rapides que vous ne le croyez. Ne leur tournez pas le dos. Ne regardez pas ailleurs. Et surtout, ne clignez pas. Bonne chance." + +let some_other_String = + "\n\n\t Le Docteur : Vous avez d\233truit l'inscription la plus ancienne de l'univers.\n\n\t River Song : Tu m'y as oblig\233e, tu ne r\233pondais pas au t\233l\233phone.\n\nOups\b\r\n" + +let yet_another_String = "Say \"Hello!\"" + +type int_list = INil | ICons (int, int_list) + +type list<`a> = +| Nil +| Cons (`a, list<`a>) + +type llist<`a> = +| LNil +| LCons (`a, unit -> llist<`a>) + +type marthe_exp = +| EInt (int) +| EAdd (marthe_exp, marthe_exp) +| ESum (marthe_exp, marthe_exp) +| EVar (string) +| ESum (string, marthe_exp, marthe_exp, marthe_exp) + +type box = { what_s_in_the_box : int } + +type person = { name : string, age : int } + +type closure <`env, `a, `b> = { code : `env * `a -> `b, env : `env } + +type container_functions<`e, `c, `b> = { + map : (`e -> `a) * `c -> `c, + fold : (`e -> unit) * `c -> unit, + weird : `e -> `c * `e -> `b +} + +let id +: [`a] `a -> `a += \x -> x + +let id_int = id + +let stable = id (37) + +let compose +: [`a, `b, `c] (`a -> `b) * (`b -> `c) -> (`a -> `c) += \(f, g) -> \x -> (f (g x) : `c) + +let id_id_id = compose (id, id) + +let id_id_id_2 = compose int, int -> int, int -> int> (id, id) + +let an_empty_list = Nil + +let a_cool_list = Cons (1, Cons (1, an_empty_list)) + +let a_person = { name = "Luke", age = 28 } + +let a_name = a_person.name + +let main = + start_with_this (0); + do_that ("foo", "bar"); + conclude (0) + +let computation = + let y = 42; + let z = 13; + compute (0) + +fun : [`a] list<`a> -> int +len l = match (l) { +| Nil<`a> -> 0 +| Cons<`a> (x, xs) -> 1 + len<`a> (xs) +} + +fun fact n = + if (n =? 0) then { 1 } + else { if (n =? 1) then { 1 } + else { if (n =? 2) then { 2 } + else { fact (n - 1) * n } } } + +fun ifact n = + let accu = ref 1; + let k = ref n; + while (!k >? 0) { + accu := !accu * !k; + k := !k - 1 + }; + !accu + +fun ifact2 (n) = + let accu = ref 1; + for k from (1) to (n) { + accu := !accu * k + }; + !accu diff --git a/flap/tests/Makefile b/flap/tests/Makefile new file mode 100644 index 0000000..4a5fd80 --- /dev/null +++ b/flap/tests/Makefile @@ -0,0 +1,67 @@ +FLAP?=../_build/default/src/flap.exe +JALONS=\ + 01-Parsing.results \ + 01-Parsing-no-positions.results +EXTS=parsing.hopix parsing-no-positions.hopix + +.PHONY: all clean test FAKE +.PRECIOUS: %.output %.expected %.score + +all: all.results + +clean: + @rm -f all.results $(JALONS) + @find \( -name "*.output" -or -name "*.score" \) -exec rm {} \; + +test: clean + @$(MAKE) -s all + +FAKE: + +$(FLAP): FAKE + @cd .. && dune build --display=quiet + +all.results: $(JALONS) + @cat $^ > $@ + @echo -ne "\033[1mTotal: " + @cat $@ | cut -d: -f2 | \ + awk -F "/" \ + '{ score += $$1; all += $$2 } END { print score "/" all }' + @echo -ne "\e[0m" + +.SECONDEXPANSION: +%.results: $$(subst .expected,.score,$$(wildcard %/*.expected)) + @echo -n "$*: " > $@ + @awk '{ score += $$1; all += 1 } END { print score "/" all }' $^ >> $@ + @echo -e "\033[1m`cat $@`\e[0m" + +%.score: %.output %.expected + @diff -uwB $^ 1>/dev/null 2>&1 && echo 1 > $@ || echo 0 > $@ + @if [ `cat $@` -ne 0 ]; then \ + echo -e "\e[32m[OK] `basename $@ .score`\e[0m"; \ + else \ + echo -e "\e[31m[KO] `basename $@ .score`\e[0m"; \ + diff -uwB $^; exit 0; \ + fi + +%.output: %.parsing.hopix $(FLAP) + @$(FLAP) -s hopix --verbose true --dry true --unsafe true --loc true \ + $< >$@ 2>&1; exit 0 + +%.output: %.parsing-no-positions.hopix $(FLAP) + @$(FLAP) -s hopix --verbose true --dry true --unsafe true --loc false \ + $< >$@ 2>&1; exit 0 + +%.output: %.eval.hopix $(FLAP) + @$(FLAP) -s hopix --run true --dry true --unsafe true --sexp-in true \ + $< >$@ 2>&1; exit 0 + +%.output: %.typing.hopix $(FLAP) + @$(FLAP) -s hopix --run false --dry true --unsafe false --sexp-in true \ + --types true --loc false $< >$@ 2>&1; exit 0 + +%.output: %.retrolix $(FLAP) + @$(FLAP) -s retrolix -t elf --run true -VV true $< >$@ 2>&1; exit 0 + +%.output: %.hobix $(FLAP) + @$(FLAP) -s hobix -t fopix -r true $< >$@ 2>&1; exit 0 diff --git a/flap/tests/README.md b/flap/tests/README.md new file mode 100644 index 0000000..7e20c75 --- /dev/null +++ b/flap/tests/README.md @@ -0,0 +1,11 @@ +# The Flap Compiler Test Suite + +This test suite contains a variety of files designed to exercise each pass of +the flap compiler. + +To run all the test suite, simply run `make` in its top-level directory. + +Use `make PASS.results` to only run the tests contained in the directory `PASS`, +e.g., use `make 01-Parsing.results` to only run the parsing tests. + + diff --git a/jalons/jalon-1.pdf b/jalons/jalon-1.pdf new file mode 100644 index 0000000000000000000000000000000000000000..89459eca3a154fbf4a60c6a384e24e9227e303db GIT binary patch literal 448492 zcma&MQ;aTL)U8?eF59+kzGb^=muC;J{mCR(Wn{_jjl{ua< z$P@r#bWHSYFl2K}!)q`sEQE}Nc7~QPyu2_BGA6cW&gO)yY)o8)|JQ+G5VNp$HgP0m z5VJOLHUXFz*%_O_@bkksIXjvd*uc1NY-?>NZnebw?)Dl|d#tT*!3!gT2_#7sJM;6z zOS{}BC#NQ=!n=iZ7DS4~yysUTpZdykbN~n7MyVytzQ%=a6ZMIKnmhk?0J9cO50Y)e812nTN{%bmM2bEenwBBD59Q|OBau+^mw?eb?x{px^Z-JZvQAmbMT-I zZw>-_KW#4{J-_H9(D=OP@#I~UV_a4ZgNM||r!&>{>|Fa)#NSOZq!lGhe_YlP4Z4z_ z9;1A6T1_5(%EH8z`Bpv~%FmMVM(=vM{T-r@jlK_uZsE~hz#kWWx(geCN%7N`Gm9(LlzwMd@;(6?L?C-aGTz3q&~dQCJ*bYJ}qw`042@mt zE1BMJH)>hy{k~q%i3gRJV-0_7mo!IE*H;OO; z7rLxd4rk^=DjyHn#F6n;$9RmG(P^-_S8 z(UrR2`^>nEz~(-bL`+U*S{nQ)w8gIqH79ZPv1q)+Lwi zyCyl)jO8czWA%69M^x}L%~asis3$O0-@xW2(HWgQKN|*FQOl|Vm80;VI{Ze@5R-VI z0+aUavsz!gl;BoGwTZkoYq#w4GsfjA7iDRwRwaU#)XVV;>VTlyY3Pdiv&-gkA$4G{vmmm{Q3ZFZ$}I@TpaTLcKkDnuZcF+i;wg>di~P)hE#z>2B$mDk zJ-GQGEGY11JcDpMXp-Z;v+?TaI8!otIlhClpr?Wi~C-Wk2v>|gT zZc08^8;%}pHW*O#iQ=zIX zSC}i!vs9mX{#5PYBfr*je{IOi*van+{T7`(!AcaN*|_DszC& z4jZ}fa0h5z_Xu=Un>gm^yQpY%wn@%oU|IFC=tq(%3H&3UxZe^ysGn=udG~syK3+8% z|59Q9G`^Z7;=FWB6zsJc6s7gH7x~5yeku~# zi%Z;~0nAmHa9IZ^dm_-2zFDfM)C_ycD(z!1*HdX}N2W_cUlNX(GABmpj(UdZD{X#% zh^2>UgPcLNN(#!?0DJ3cVJy&?dIzx#!PV7{hgy_duX*YDNYwG%a6z2BeJY^xkoGP- zA@)j%v8O5WL9tu1EGM%yw1D6hJBGjzsEe$D>-2lFVmLRj2F*ITf3G4h9+; z&kF_ij0<^h=}>BC(OxpR8VIhtOHRK{awqMcy!k}^+z+~#7oLH&W07`j4BnO3lEs(#qUbihuPL^q`>qIq+2dG8tOFU!VQa8KQYTp@bVXC5ePntH3wR zu>H|dQ_fu4KR&Z-@#9V?^6hm4EM%oSONXx zW&h?}X9&bgd2(6C=BthS$PYndA_F>MqIFxS3LenAW40Pjb$GBN{iH>z7!%OCbvT5{ z{I-$!o<^tK2|Wy$R538_H-*WRd=Fq~lyRbt}RLvG>eAp3)z zWX>)9)QCa%>nl`=TU7d(dx}}cU23AVZ<4U*PdY$6#8|&nIc8B0QwObTp^uah8CiGu zR(S^|i2P9U9O{Re94`7j-W!5u;8Bu33g40iO3=5t`;1L$$RzAb-v zzp3Q#_b;U^dusgG5tw5fRvRIj;={iS|7MEuHiC$k`=~?g1Vdeoo~5@DwrHNtr7eA5 z78S4%S6&)Cw#41$E?t7BR0M*0zGxVEDcB3~`{vE%I*N!AW_ZHWc-i-L2t}-LEaS@N z7E~l28V2*q=jZ0yY94hF0MJ*=KMV!{$y~k=p)Lo=7F{GB-P8Q_-ujxx=~FeQV@~HK z%Eb&R$D5Z24qPEty_fQXMMsP`8_p1M4i~{W12N#rrFaRV7^*hUOI0cQJIku*Odwne zIFf9+uyV>PGbrWp7n>=td>LWHIpMz9hl;Y<7#JY79S`kjWX z7J^FcAI7a`wPYerU}f_O4X-!4uH2O+HT5H`>5HWIfYE{Ym;Q+mzHV1C*YpL1ZIG2N>Edw5Stj0B8OtOV>!Z~(l-jOIW)>uw%~a`0xx zyg%**7W-^WIX^Bi%Bl&9$UY(k;L4@p73WPG+2N^CNoU4@V$*Fi@OOputHY3Mxkn>= z9CF9WZ#5ZAO`YoNX@bmlf3wY;v0F9E#yaKo*m`xheMfim8BMhDwy6RBn6SQ6U(B;| zy|SBO24Z&(fkto-^0~h$E*Fy%4Qmzen9B|MUb08a9vq=RA0}hD+qbZ$r#dt5A*jsJ zYIfI}rG2x7TT2bOf!vD?D2&V^6SW~{++RQE2M87j>5oq3?BKx{R@wN#D$k^1WQ7_h z7~LVZ?N^2=FazQvNi}VZF)o5B&f#&uo}U-s?bPsk>R00VbhWoDW-N~vat<0v92rO^ z@XHh}7l)toj%toQr_%ot>dWwPb?`F&281s5#F*H0-dqs6EwLF|yU0*?l;pqI#v1^G z$LqA+|JA-&=Piy@2RS_y@ zb(EzsYk}S9>^P>yB|Ik|eIaIbpEk&T8*!(#P|XiH0z;7I5(3}8n1&5j6%%r9VLNd@ zsDhD$Z|F8=lz`iC&r-mL8(MJ6K&<3ReDA}{)LZg!I`z?h8XxDs3*s`LRLr!}?JB^M z2AO^~-s+}O>o9>gzs~}4zqsrdUI1o5AFn>e_cC@jJOv6lT$_>?3lpVh5jcW#K+-%I zfQ`xNrnUkjHaAz0`lu`AI?(fJJf945GF|b2D&IhDT-qvXBf=~Bj_Grsc1ltyc5LY`Rf54#iWOL&6O#}kRVxq))%OUz_xSY z2po&~B4duc97mv=nK75|2sd3jUJIg7g~VG9uFTl`Hkh5gpNj=timWTQ&vY()lJE<# zw{%K-2uecDVMPGOpJOA5@K7_Lr19xStlxS7=j{1#lJ31NA6|1i%Wkk4KDPb)k{t9P zbpQQm*XwQ|_7N~9g=jkA)aIl@`Hv*F<|f^4-1^jm{;@v(tZz`$wZNuiX^BB5iw~rv zJ&uBBt;lrbtiB2-wVkv$wH*vxfJKGgD>w;vam>BC`7P#f@5|Jm4E> zuq5D?t2`<4#}Nx+(F00keb@QX4xbP5GF%J z5#9vEVd!vDu-aIV3MuJ>PaefmoydPuxHIc4JF67f0M8^^%=K0zNJT*Sr)F~mv{W`3&*X#h+x+sCy zFG&zLn8$x54$xgvLN&C_+Jo;#^i;Oz{Xo}3+|cN4!a z1({cn$n=LJJBbHd=o^*`Z5T{_kRZO!guxk)F%J1u-ES#7Y1asR2_)24C9|g3MD}w# zF`00xv)27`nnLxO;Wj5#+ryYI{fondCP7NvmIY7$kWs6u~no1FZPH$Uph8Tv5o>}GWH&SzFHF|I(F6mA*fD!z;79onsx z9Xxjm8ESe7PA@e;(xkFbJ$^3D8SDmoqIE z3S?krhM&^@yz*%rDa{4{vQ!{j`sqO=X-RZelH2GiOx%&(#~(xPe)b;BDHSHU+I5yj zP_prjc3qD?@w@Ro>~=bsg#R}P;p9FwCA2$2_~~F%gfivRdo>BQm4r)u5t4nSQk+En zcN~grv==BBfVpG4#|(Oj#K_A zLgd8HzDzeqtsC@E)33(n*a1(c%24~|`HPwJ<817$X^*$AMab%+wF6?e3S(kx{QnS}|GNK^_OP@5uh@r$k%{qt7yDdmZ#!+WBm2JU z<^Q8zE=Tl28Ovr_+#1e4cjj&{uVs)UCy{QN#tC;6rIsBT|Mh_l(908yNUDBX=){OD z=^MT=tpD5`R&sab=}#n>vA=(Rc(_^zUqu-}I!utGw<8CT44;!Gff-1Wr%sNm3YM}6 zmqGcg&8%K}bVZl2phpl&U7b#wcIKG9d>qeWEViZ!@OSE47sRKioB+5MvgA#Z2t{EF z1g7_)M*=n>6h{J&XLfX_6F1*&jDN!yrgV#57qL|PamdGreFCvK)Q9spq7Dz%?N06+ zia5ynXLQxP1`zj9G{wMe7`ZDs(IhM^xV*c!k7UH~$BTrKSrkn9AN0bDef0R|jdLL* zWfM#tT3EChbf#?9<@2)_IqY>)@C{AVOpu0U=?Mz@7#Yu(rkB45*YigQ&zANf+)vUt4m) zK}0aVuVcu-&Xe~D@J5N1SchUE!p{2mMY|;CA<)=ft~tS)03-AmvW35?k6k-*`{C0n zn3pW6&j;L7({09K^INuTiZA;SxdG`ZAeC;w8z5dkL61*iC(E-LdatKZWif8m%AFkj>;R+Enn`C(>rzw@%7R(L)>3iNronzr>qa(1XiVLw2 zSFxAsxx|DAVqpcaUjc3xg4 zEJxYqN?dntc}P-8!VU^jO3kiO%jW7nAYiiw2o79A_aNI3Y6Pa>xd1U>7^5LUf$){g zQ}VHE0d$*=&RL^Z*PZTMeTx$tiU?*~WnXjTwjV6F@-u`=@~@ z3n5WQ4ws9pR@6YzWfS1K8PRH>x-moOo-N@5UXM;Yk&{3^sI z^28_Z%%vUX|8A-R{T+~U>x}s1#?ZJqnA%}=V2&ihV1Z!|7tg8lASn=2X#>9h&i8{V zCqpA)4niw(`lJzoqdt@c0>gCkYjj|myJKXt<w^WowSY{mbJ0_BPY%@Khg0X>tDOLZ|JdzP0Cl{JN zA(&_|PEtGOG3hRWnfRyL-k4ENNi);>a-Ll43e$LHsCC|$h~}0{pnSuki9=-DZO5S7 z%E96eSMma)#be1Pt*6(P=3<#7)5|JFF0bfk2{}D+?kiBt+}5i%3=0~2VlpjwtZEgR z^kDbEYt}ke(Z^kc4**L8`6I5z%gcUd8SEFVQfS8Db)N=89_I~)XXEF#qV#r<*BU2c z5=I&HsT}cqohtXy!xzpa;<&7VHXdIUKRKIItPoajNo307XRG;l@0l9O)totm^Mq|2 zYmwG{|5dv|jp2Uk&y>NkoaAeSJEm~5@9}zG@-B^PYcvue&^{fnm3Zl(8@`F@by4no zDINP$h6AWDcY7>IWx2zY&jdQzdP{o$@yz&+WCKrFDkq&tW29_(14!rdWKL7D3Ar%w zgR_3Ji~llBTx6vEmAeEw zpbx)TupW}hQG+8M^qT!_$BWv_#(4I>49VIrb-KhutD;m}935MG0)*#du3|OEdJqNEEn# zL-u$3P3^8Oa;j~`W)@g4&B_Xwzz_HEXk`=}Ks9bfe{;gvEkpdeWU0vWn;~Q*rwh*| z!iqb&KQ3iu>&cASrT53l#|VkwFpR}@0&GM%!j~tjuyo3vbjXie*=B(9cb#@mLUPo$ zPB|CHhfl4rN2(BOJGDRaeH^h(JNfLdvV#{T&mvSTCHvF#X=(GiE4`OW*AKTn(C@Bb?1{Ms zLO8U?r{B0~WD)ew)`*2EOOi{HI|=wQ>Fn4jS{$S(FstX`(}9{9#`mu7uhw<4L|e_S zqI-7c?#b>5JBiadla9#*=;c3#ID@*hQpTBH{Pn~BG(fX+ZxSPuZ+wAUVLf7@f-9?M zv}OCTty^qOCtnOYj56RtnZoYy#?t7h2|O-lNHyan6<)=!lT@aQmqV)g8xLkbY_PSa z1uxOw=r%nQ%{#|BA=avQDu5Ul|Cs;LZ>O0spRf9g3+p*$C;~K;B)vT*aoYR7K^0OD zq)X)6{50Gq3-j@PE}t2CWJH{ur}}h#psU02v=KA_unl%^tSJ-Y<0SvF$3ho4PgCU8 zolP;UDR*(GK%@xjY+imL& zOd@t>k<>98i}Q0syz2@{T69r$wlBHnfh%?65pSIQAx9c6mXSz-@+Wx z_My(s#{LnCQZBNZ`rvbySIaBL7os%WUnBiu7!?Ksf9s^L{!uBy3>nm!C5ncRSMV&d z`0~N1CI0e{+OuN=sxFj?xF$$xkeyhcKVtaZ)AE?YPr zIgRElAmZ{Dxpuk%dY2_I?0Sel(5KsnHjjfVb{pTS>Vc4tXeq21hPvi|r z{Nd2`n*;ox(xY8+xPi%~Z9+-D&Z*gTv3Gq8o*naO4esI7@K?+pXfKF;h_{bSdr~nlt59CxwtXHoT zrpvi2>>rL>%JHn~l7PK|&td*YG%Ws<8^M7poP6K6;~hM)YSzXNA##z3XV6uxpNc?? z0ZziztR(8|7QTl9_8E}=Eu3)YP}3J$(g`MG)GrXGAu{Iwst7pP{y!7}8x!mQt|FNJ ztLd~gg55y=w> z7M&jX5>6|NlVH!sWewrgGPp^PW7xG7Eh{yMZW!CBGN|)LFexe7s5NfPV?nG&j6y?` zA*e+q1W{w?s{XA?rPbVe3l&owAtJWm4Q~)9ipLzhd!4j^iWRwO-o63(DHF*i=6$$t zCF$tDM8ohRoWQ5sB04`xK8I8M~* zR?N?wR}zSe0OdzGtnFv7V#&ym;d>K@0H>L0>ZZlpx9w)_VfXq@ZpBU8g>NTJ~$9KZLe%)ITX}y zvFq)Bj4=}^RqV4Nclka}(?X7T!v=!@50uf2VU+oZp32C`=0gVttX-6)k}{%9Cdv&! zR-}HyEI-m|8Yc);LGX}uKi+EkqG+l_1U5~(xJ>wxV9i@|o z<4Xk&2t}^-K6dJhol`qysm}8ko5e|ee(lHRd|0BV?Y)Zu_XC^;U#v8unrqL4yiB4hfZOpzw;hybz;r65x>R3Ko~7Neg`>P2 zIx@EF6TvJ7GFzhAsnkkam<$I{rCn?TGExOZM!wvv<(UJJv-_4wke#V@1);hNj@mW- zEOu(uYKIRJOKEcup+xfVf8Gvdf}ny;|>%*L#c5b1H#xi!g#qit<0RTOhR2`#i?jvqveeP zz9XgGK~89mopw$-m!>30!jozTbBZp9{=wYFKQ(th4j7=(@3*o{DU8)dXm~IFn z#DRN7rpPo}`Wwt6JnS6PE-2=mZZ=i)z9R%rC+cCrKSg|PT>gQB{9pWh*`1gukck+| z&bz~}3lN8+ESM|hl>9mU8o5W;{u+6A3NCMRh2wCVzW)*`=`;EG#1*}I4AQvX%YuPs z#T1#V8AsuqNGn-f3Vi%7p=#tTezywwb9|E+5J#I}=H#YmT#y^ima}2Kd!rIXGd^`y z(;-^s1zNE}sQ8eJnIXz*Z^D6nvY`(Z(Z&{OaPZq$ zm92hr?SJmQW(0OB{RMm(@6JKbxWk;eiKsn@Nx_Gp1%S_E{G!@H2|}($aQVFZo{W)O zfjT9J(jqyJfkSDY5zAJwsq^0LGVy?J6om%>Km1U)gM8Ya5yU_qBYmlxZ|ya{w2{q1 zE>236@KjfB2?vRx68-sf7e(%B=ps}jpeV_RWFCmaS$CxT>?VkF?o!H!C5bSCj+|^s zxa@N%gYXkZpr0?~he z20g+Klcu%>&Ru;a`aQ|crkRWp9bNTv*UXEF@6Pe7mEL3?Z?n{fj(Uu9bfUN99@~6k zM<8V&>tFp=-(D45?&=Mc_TlUte-0uHw>h}9?93^f4b_e+=R;GP6GEQvGF;g9-S&Aw z|4jde&4XKws?C~dtyukImAV4df&T6+q1wT1pgbj=r48MmE#bkWb*o9Fo!ZNVyus!W zv5S^d+2F{gZl})IGza-qbj=JN)000GOGClea|$w!3kc;s13u9qVv?flM(PmNbk~m^ zTvpx&(IBauYQhk;GOQPJ+K%)F!!CG55*&ucf!?c4fCgTZbl z%YxXWKj`Cas;pimk6VH)jfUK`Z_UoqK_8qNBCR5xI9)Z@Y$3o~E;;@P%QhwqQ*rdd zWa|d6esyeKTAT1V7=LFYhoiptt9hEbm`O5(XBqSBO(6HHE<=o-ZIowm;o&y7XP`P< z;6vv(wjU2AgDv%&x+OC38w!(KZxESi2ivOj1Btt zC4GI~ltW<;?Wpf%6*(;L-}}L1>cc&Cl<&b&9{>}_c#6a!+gO>at*cvl&7;sw-{&$X zEl2@2no@Zz6~dXl(%ikJ@0Ie$LtW=TGoYkPJ9RUACi?g~hpxGo*4PWAO-xO5+JRN# zofp5@t0n{*{3py-Ibn>b{WyOK73-^-cScC)#Y<@ zfT_`ptjkL5)qS%&L@6?JDm3Y^!YWf7I&*Yx<+Trr^>;Dras)^!QL)f6tU!LRymLZq zJvLpuNF)Sl(-${kk>IR&L5r<>!;V_1Kln!%5zZUzF z;c=hp`UbCQ9B@MCnGUIw)n|n{UUR_~_Yqp)=3M>l=2;?y!Uk>WA5o2lTdrf`>Kd)w z_b?sL8{6t>9$R`I<`Jj47+G=kke`z?vNBe`%kE%{bG($28`%nHG?kdi=e@M5`Z|lc z7S~=x8wlq&@hbXwwA2=B$chlf1VN5fvvPa-IEex=A2=|9R(}@bRi7Q8bXGX%!g0VV zhRyyw@>@$a)#WIt1bZLl#DPHPfsiJHTWTy_GiZRKgj)px;v8r|y`(B;U=v#Oy>x3HVAP=e$h% z#8^{EWIZt#-2_7}NG+JJJ|KFXNI!@KM^0r^o61O!vf0Uy(Y^W@BW#4d?PkiJ))Qg~8>gve*9}(-X4@hl>1W$)M zXeNQ#_eZKvL`3;4Ni&#~LT2UOV*3hcE}<_vP<57{et?4Bj8sRKT~ye|a0AXhzU-Ve zg<)k2O1br7++IOW(&+OPfOQ8WCq2-=7|_ zu`%n5i|A3%rM$S)XXa1=ufN*YKT=V4Sa%->1hR2xt9~9t# zUn>cSvY@a*PE5CA{}c-5en&VmMs9>!!Xbl{9$-SKDwy+>vCG-JsI?m@LAFd4fu?1I zI=@l<1&~0VYx5_=FLYDZQaoleX{P~OvuXz$x>z!kq9F-C-_D_-W>kz|Wn|Mw1k*bg zF7jp$5yIYg>ci{gfx%44!-oFr`~HRHkUP@-UzH%!e>TwnI}^-A$jrpa`acO_WlThb}SCjl>{h46P8ex64wHRK9MxW$5&QHetg@YsHiH#6hVW)jgv)z1XV5l(jpQba@9@p zo*{ivEd8n;LVx6Q5C#Qqn29GqCU%cRG0%RMfb@YlL9g+qeu};sY>Nn{fP9rd?b%vd z>py6K{kE3o=Tj16W`>7@SBA#><5xy@f>u@@7gr zgESx)5KB$4E)WEo$&wg7&f{7A6;~hat@<58K}ej*T|Hnbr%HZpnc z-vEA*{|uVu|2Q%?x)poXQ?@a%IW)Y!-&HbVu_8GX(BW`wC|0g#Z*&5Yg8GfU4uyKL zONX9A5<~#n0QRd1DRK5y`evi@9fI>6BA~l_sB5kV$Gp_y2I`)Q@+ZL1K!Ef%BkY^s zfj&FFmml^e)_`F5i%-u#9F6m}MqTSIkkOh{Z zub;Q|&jn2V;)B8W`tO(~!~|D+L%;;Zt!xh8_Ce}g9G^fiH`fM#G$qvFfwIR4=Jmp& zp#>@KISfJP#=mgt7eUXCe#N4IxQBb^Lvt5)!>|NPzwCzYkwky(hT!v9-Z%{NexWR% z5XOM=K!0$UnZ1L+FL1cIe&~$!-zDH!SsOW=8<<&S+>Q&)kn*{jZbS@h|RzZ?@2rFT(BbR`<_Lho#kuRAQvMw{mxV`C$TIVP6| z5M0%hwQtAx(KA6$$Ztpdmy5giRm1PFubcxA;u#EUkWN-3(-91-d<_Eq1Nu9gCY;cK z&_AV!{!03HJg@svV;cAr`xkVgIEK~Qd5&n-Rk6QW%9}j%v)p>wq=?%OHq})5)(0aJ z{=QnfS|d1+iU565>14HG0a?@j*0$`p0|jQ9Q!U^}mA{X#re1y%WATXMR-;C!hi^O+ zs>u0j4v!P^P^n#5ArP$pCTDA4$MiPr(aARjad!#k4T+yS!O^KopB)33#7K#3I=SQ6 z$`YKCT&yNf;iCviXgcg2s*=X4_f@sOsc+^M(fcMy@6r#i{(&QzL*so8kiU;&2Er^B z5l}YMrCRxMS5b@pbB{}OAZTpGL3}g1k*_!l7*C0D zq}}c7HvMj>jgo}$n*yIGP%_k(7F}bR&Ec!)H$J|AG8n+n+6{!UMhEJ^qUp`7k$(B`if8@F zI<`b?J(%Q0XzY=E&sZdUC=zPTy0oUPi|Q)cioHTjvg&ULU|icqdkQv2ujWBvD_N)& z_D1F615%4pyb7k@?;M)TPuSTAI?AH`J4!i=soFA}{|?)%rtunnJ6*%L$DDJ-#h1;7 zReSZ;jC4fVTQR6n>_ZC>%t}*k=YwhrD>~uCkUQ*RIjGsmSI}{Gy9R+AbYw}@!EaCM^6{bb1Z)dy zW@E|&C}z}s*6i^qquDZw8#aD*q{ebWN|H;E3XW)nH-H9VbZM+GdJP| zZ$(eDgZgyYix5*U?HI_k?CqHy+nSjrilN8VgFL}$$ zXcL_#RgN#PCyeq5k6IYUH)~BeVRHMLH?DEazaLwx&N?Jj-Bymm+jz7fABq}evI5{F zZ4M!~0w;6QpWZBCvLUS@_W^84H8rN+{Jpk6<`cmaL9u@pln7@E$d76T`sedQUkwm~ zw$3pm!?xRTY-@}-4HSl0mH;AVy-}GX6#Q8*-TN}|fk+ef;v58BFJL4pHj=WAvO6Z( z_dh0ITTtr4FJ~A z5^2U2unJhY@Tq8gJ%sq#%HI5ZQ!ClgRSM==o9=zOX7Cds$#Rx}mP`)y4)!U=W$-k) z$qJ)sLw;ydELzJl@AT^7ANo(&NZg|_gh2)H|Bb?@XJ z4>BanH7Bn>8wWe?WPpnQ(rTPM9h^(;j{C9`fzI*=6Y82aM+el<$rYi-WEfVZLvW+3 zwjcq0HL#D(&$QS#&E6wO_wtlwv~r#})kigc2*@Fg3(KQFWPZbjjw$z*s8leaYd?_;yCvY^5J%KJ(Gn*QNs{SKYFD@JW;1ShOU&lyK}mQhC{w+T zT#`xI%vOYPBVu2PO&miK>a+wDb{A=D*VS1eN*w*63mDjrKTMIM`h^l;L>^6avX$)X zH{9~Mro5}jfzF%kLxRM_9f!8bCya1Pb-#5Zc?Hv5;4$NzHVEvAWn|#0ov!%Va+4bz z)m-LaV85ATRpfu<1@NAg3tTm0Sx=kHkR-E#Sgj-I2TQAv{?WFuf|`@$XOD?Q;(9O_+B1*hU+p27{UbQI4p0>F03mt# zEQ+Uo!TMU5-y4pzJg`Xjy>K|Q+>=u6QwaAU=S5j9o2a)N6uB4zTxOF5WIV5p`n zs?#W6#(0A6Vz3@Zf$VU}s3_jcyJn(%Ri}(z`Pp%Y!7bg-EywZ4Hx^3W>jw>yVr(vf zm0PfMw%zEQ)G&ZH8l$SxIH_4F$3G8knHCEYFzjNo5Xp%2N z)i#>B#ud~50E%XGQj+!spm5YM%=g(>Y?)P;Q%MKOhVL5+X-PKJ(+&6q!>6}FM0Sy%TcS^XeJlKwIWRVYP3HVgJ!qRrlP_f zm%J-cl|`B^+_qSti%w*)|Ei*Rw?uX|k6Tfwh_KUN0f%H-e9}73`Fo%tP23FHerk_3 zQFx)jiDdcbk=G;mQw@???+QU^{42u?X2PF%k_D}+O>B+^gKCY3f7a0iLo{?}@7_4%Qt03kzxbgj{S9&+zoTv~MvD8#N zlUhkpiyOE-ZK@loIbM(d^5VpzH(5X`L5z4Fk_Xv340nuS|9QzxI-8rOL7#Kg7i5t4 zZU=Pd3N~T+o7gT?m$0s8f)6A0kT;?{WS^7axpR_xJdDOy1v_x!^tdds6kR73KsB96 zG=xN+q@T4QWX-8RNoc93F)m*0aC7K59e!p~6DK!^im#Gq8%+g+Kt^ay`gTB6hCO8& zyJrMH?#Kc;TbN%RPeEe1WfaqT=w!f%4wHL6IY|J!rJ|RhAbJ+IoCsR7b$9!dp)pNE z7*-($(DIK;4uo@XO!?T}3T!qxy{;e1{aScanqBy3IKHXWq|P`>_qpKcY+?pOHmX{Y z@kBhoEea^u!53hPq^e&QDuQ_3+};`#Lot^5)2$b#aeoBHYY8_kuV&4((f1tZEwgMM{)F_J^=fvTOkR=Q6SvgVA7|oZi8{0AzRbg^k>?p zc@0Tgi&HWPL^b02H17m>0EU}6hKG`>sPHTJrh=MXz~OjgmxJijlD#2wM_}v0%~4G5 z?i`T?dKUstm&I@wAP@J{u->TEv61Uuoto5f$?Eh+tid-exu&@2e)>c?T}Q2Q{$M(* zUCt#B#ab9>016^s4U*n5fb!7DR)eN@Y1}r3g?&_$1%v--k0WVTd;~dgx^lrURTCRl zpR*Qm31j?8Y;KAdYfMJ2sQd^($xoLhwM zQ7*yiK3t*r5P8v_lABhn-B(FU`);(f$qzijWX#(!b_cRk(xD6Z{6;qdRV)%JF>tg? zmLb4jeBD>h5j0mo0Y}oJv1X^s^Pxn$e*q?G8U)Q76T%AKxKGF<6l}Zuu&MFapBqnn zef!7ak@>1V=;yk!j;iMr7bR%ePu&n{q&hrvRq-W}Ut2P(+J9BJY4})bjs+@d;Xlit}S8Vu}fDUd@`5tm-Q0*Mo8fi#* zShp~d0V^zX)~b2CQvM)g8pZif@h0-07+5I_5qCnwoDB!1P_QTy5i2%_&TmnD9>FTF z5?@h{-KF{}Vu5hG>U*~th0xQ*=k2^#8+_85Xq5^?iMpUY7j;69(&u7TCMTO#_z|*b zzMJg>FBE(%6Fhbr43Q@Cyds8-Z&KJ9v>akou~swk;>S+YL9mhgo~|Q#6KsS63+c!M zpckc#BsP;5@ETWd#Z|e@?S6}@e97}9S8-b7FDb3I)wCDY?EYIhsFv9CBI5qP`W1_y z+(3OeSKG|kI${9;!DR$GAtj;=P zBqLTqVa880w}S|YvOc;pUzoVV2eVT<`x$Rgh)PC|yEc)07A0o4xJR<++_es(w3ba+ z83iT{;;&)|`aZ4Ta>S$uk^%_|FtFLtYI~J8J?NBW^$)QX*LKQ;@BB0kUN z!#cMSmI;H2_2+&Z3oH*do`Z*S2u;kN%vkEoGW9~3QSbh^%hzvha)RBtDd1h7+rot~ zRc&!uzr4E_#~}KIfFp0EOG||Tb?sy&fJHsr_`-Q;rwh6XrvC&0 zwJupsq*X6OUO7^)M*@hUNufkM=D4o}G_fw$1Z0<9;nR|bIF!k3M9uwRJkhk&OkR5i z^8w#u3(WUoMr*UcbL8q-69kSsG7~d&Q&dvp+5$yylUe>qaGiee&L;D&D#DzYnH6#| z#qpaO)Lq$@H5EfAm-r>?fs5!b>3z9VQRF9SV~V z_DC0kPw}pqqzq&-ruP2Y;?eOQic#4q$ zUQK$sEqGwWhBA(kyQav-C0mrc&r7KQVLap!ThqFA)G@9l)!NYB(dxNr_XNegK-zr&82M^ee4t_w*iQE*`XDa_ZjTrPhKe-}RCRIL=WeuCK46 z7y`X-NgV&jC-D*xg9O$VaDm^YZ&Jn-23VWteeG63{LHj)$lN&D7rTTI>Y{V3#97r5 zp6Ux|Z3Cb3=K30bkGEbUZp(6@@v1rxr}xU@GLJ|-_;MuUcEI`JAYo*aU4DK5sfY>(TLe zXyls@d{(1JwswzXZ7pAY{xM5M*d~eLce!KWH6a68qmT= zpSH8#^vxEMbVLPUxzs499Y!GpzCNjG^cS8LNHEm3wDP@Q`{II_O7)*t2>wpiYs zfv5F&oT+{fw@cR~>s@ZASyU)_li6MON5U1~hWm!Gr_mr>|4NcRI1?3gXGRATK92f~ zr4#jNk#*?3)j0jOth*Q`ItJk5C7;8T> zkO4~k!d6?2<(Y5w>5%%{_q()?U(lGx9W;j=e=V-=P3XUSC)38Xw^TlM**`h-*4y zvav2EUX#}DJWavWQG=z$VgFuL0MDfYstVtW943^F zU%G_^!V38KAhH=a3Xy;n)$4*227Y!tN_?Td>lfTEGL+wg0gk_9Ui86xoK1gG}6vZjdW7d>{qjRf>he{Mck8k)R>z z>ur+-SqOGplfc==#0Qnw8&*T@Hq+I$u%stqFgJ~AjP#d?WiTxI?mSkT5R4V3h0-+5 zTUWZ*e!cot5!9~BTwU(@=1(Fq1wXx;q#G_&D~c(I)5>R`#<9m{^WIt>GBsQ^-{)oWjUv%Zyp31OT*msm8;BplvByB@!(_JexJQqqu@>*hM7VsmN2S z?9U;kNqZ10>L#GTmzatxa|m}+LM2}P+^((tni3H!>_z9yvN;QPM<2n>SrG~sxBhe4 zlny-g(4`)A!LeO6p{Qf1JGnLwhsE^bnYb5=Ck9*YW6ohp@$+?#8URJ5!{c`C9DENBPRdp9+!0 z$Z3-KB+;;_vtBp^mW%i?G@t!L+$KYwF>UrB%aZiv&L1?yYkrZD>3aSU;%tFWtm0=` z<4_1gg%Ak-WI|3;c_}uPCY&yL@C^)E4xXl-pV;yc3_N@cJ}SxKjbvMpcp?jK-ZSCb z96|TzqHMmj-totsu!lUQ5(_a$KaiXBRJc}JuOWi-fICAOCndvHWLG-M; zAPl%ERx>bSB@L!kzMinNQ|^Lw2SA=q*d4E$(Svi+Tj(Xd4$$swInQN(r^teVX<3V- zF;8KX2=1a+inF+3L15LY{l-PdTfWjJ;Ae-S6TM6JVvK`7TcCRdbQihlQk3}Q5b0$X z$bWB^5=%=9+j6o$St&M=O#r7!*w01XD;gy8gH3Z^25fv4Qhh?j9AX<>(mD;7b@9)OpKd50T@V#c(uyqD zAb7pA7V@Z9tz!tICqe{^C>!xBVz<{~U6=ea5vycBd&IgFXhfFOzh9OSXGU=}=+d-J z1kQGF?zw3aRj8J(lxmuW(#1iYGG9eK8&I7Eb)2(ga~52{bofeb6i`;|3#2YZLHnv+ zUNZ8nPBAMpG^Km7-yvLRjLvb7?=o!yO2yP)@e`ASM~l}}z-OA3dfF38YllkFdoK3I z`O#F&syxX?4c|g9Cthq+^_$T-?;R!)VH)8Iyv8FmhCdxi!$nKpgCTF~*pw4u*BpW{ z+joRve2S0PaIcf{>MelDf*TR&mKBhaP0YZc$9Mnciy0r=$rsRssq`* zb+Deu7>K0C77%p^@(V&>c;f^lt2EYR)v&q%;V?e%My0$6 zHR05hYT8Y-jju#(rX%P*pJ;EocH(A?Z$uoVz*c94ZZTyCq9~*npjGz0L>O=0kbAab zTG%5@Q}F6pw5)E2f=M!(K`Vr4v6lx^-0f?k+IgieK-xm0W)d;0=Ut>|gd|j?+hoZUq zlBoaC6^X=~>G?A(e6rq7H?lNhggGO)G+onZ64rJk{tcDDbr zTs^J;sY>pfPLd;QV{3GkpPyA|zofBc_|Mvv+_(L%3|g#PL1?-cTp#UishPYe@W$M& zt^FL(Ru~2E$_@%mwFHw~k9YLW zxeu}YoqN)ZB=rCe7o(4P5hEe&nWs};bGK}!P?>78h30py91V;e2+9njIymt#kuxt2 zX76GPq8Wi2Bvdw|#%TzgeX%ZP4)@0x(sGMKi%b}ATbDkpYVy#t7o%3(C?7i%Gj>qL z4$rOf`%JQeQ9KLNyrx_5_Gxi1g0Wrl(^*!}&fm;z(tXdPcx&1FwI;9QV``%DpD-z0 z1#)1+v7e!d`(jrNR^c?Cr;0pesH-ZmUu5$>Gax5yW$3m_cT=6s<0r;XBirW|Cu3uM z4<74wyt_sl@}$ZhXw^t7c13AeZLhvgl1klFrV{@?WScE5IAM>myByj6S>{u1MToun ztzM7;I?r5orYPm|p3B~?{38d6V=EPxgG9Wn*-mr=DB(iWEQQ|_xC=B7vdP`PBCkPc z85Zx%xiS=jV{#ZZ#x)AiPF_D9-rYpH(6(^JspC;3Q4@`T!oQ8|e%kz6J;hQt=)C8+ z2B@>EN<*^T2+u__X;wX7S#D{84+7$at5{Wv?F%ky#mcn$I)cWij?`4Bp7q#1ZfG(kaxc8@dZl z&$b14&QsGIuql)ezy^opH=r2t%X34W7v_CAo5R51Zq@;cvtEXC;x-me3kn8ghaPr) zCWYmh`29|y$3Bv0myVe$m!>PrG54uW(yZ=eeyB44u9K8s{MzLw9`u9gMGSJK6luVE z=#5lXdY5C@$ttJeZYbCL&j5SqlUKRp_&YB_dHuB4CAl5VT`oOa&jfpKzWG9Ocb~2%v3s$9ZW=_!nmG{NWeaS;zA#q1YoYns#+{ZMi`nR}*Y9|Ug-u#-_Wko5#uDj#-CB}gYr1fY@U$-R|=a*}0%E)l*hEs~Z8otI>K&@dQzb9$@66*d;hgC9) zKs*`=y$@v-W$Si52sELKQiFO_XXr?e2=|tH6JU_bqXXF-3r(?@HsO1kJ-32NifHld zO-g-^X8tutG^KZ6c&?G79Hn7HMaZmYu$3( z;h7p5v1alslmcAQm5~0Cbf^PE(AJCQv^_$FcZe7cyhg^7W~nPk2aLo{PV= z1{Fcu7r+CRa+PY_mvZn-ytM2wt+Q!FHLNH6NS7&5ap_fRP6oD zY^9@%?^1&WQtGk~!FDzjseUJEM}!_{Dds<5*$$`f@AMBVqK9POaR#-_s4bD~yyNK4O8Gu7WqpHciWmZQ9$p_e-&id^C;~RrAD`Mt^6MFU)4_1wF z;QOw*%4RfN6z?#Yk8g!eWIW^#PO@_I^OUrf1RFG}Xbjqe6igvb$*e4FdjpqKtW9A@ zdL?w?yV2nA7V6#VE|I0J`p?mp-?>APO=q)n^5eBOzXpx4Xp}GTP9xI(o?;Wz$vSs9&7M=RjeWI0lx|qoa)4|GoDxH(5!Dy;FNCIDdriWDzaF5+OfOGH;@E zH*+arx`l)w4U>G6no!-ZTW|9!fPbB>*lAh+Sc0O&AcUqO&tn*4JvzTn=o!y@iKvJH za+|r|9s1C6XWPT=hg##Og!s6W*yEauE>p2Ivy@#57uyBX(Qnoc?uyKZ_(gq`!PnpS zaPWoYJBJdco?>LPYjFBWom@0f(=>emc#`u|!=IPAeQj#2lQ&4hKL~81a=j zKX&z8BUHrvVDzd6Jm0UsCYqdw(2-S-hTXPEqFlO-piDn6RKlLXG&Ia5=Z~^zZe>`^ z+FE77T0mjowyPDSuILF~bCkpv2oWpQD@nF|@^Cn%c~hZHI@;%TUqECMI44?^8Sj=7 zwxQD$c_*gHji*Xx;J7B=KP0EH;Yvmdt8ccBfLOh%V{av{BRyGxUDGL#jH8HxJU@#* zo_?~V3-pr-q_{bGOwwcb=x^vA9X@4tw{*k_b578~F7Y9>C6M4`wkz@o`Msg({zJ%V zyukvxW+|mpv7@sVsbkpLhYSD6xk?eretWzu6uPn;LV5=2LJP{LtzZXR;MYra0L8Rx zd`B%YgY}o(nh??4(xOUJKKMPU*?vjlBpr|Zf!w}~PP>OaF2a%Qmd6Df{nPC@<-qMH z5oT$h>6z*L2=|C5d|+WLj8iwk>aAt~MDi|XE=lXgelh7|5hV~fxaFYZ2Z(j2F;;OKyt5I~CD;4hfWr(biTKBpWWxR$G-_q6~kQ5~#jXL&f z&kb%$XG(%o;QR8R(X#EA=9^c$v4!*6$LvveeHU^d4tXXoN@tLnrX2)DW&AX1Tc$2o zrm6Wwdpz(n%SyR_pMa=)>$ua7i7Av(?z*~0;gKkw$B%0ca_Fivw=-lZc3p{S!QKyX8j)EyBgG)c$qJ`t0(HZZiVvbXl z6*QYQ|E8zbqM~3^zQ++-Y_@p!mlw(;aS#5@847R0SREKku^bzj+hir;xS%mMA-vZL zHl$WC)J4(Cj0t+iB&P=ubEy|D4tITTOiQ;iSo`?jLoTFazE>0|Kgbk|Dd(v2OOkc$ z2oZF6NNq(Xj0deyHY<&C>e6D5lBpYqdB24Zz8K*bzb<$B@497Mg>y18tNTWj!3x1% zB|*-cQN2(IV^%pEsGU$tRdqis7(2lKst`UZr8lhHQv}H<94ZKi34I%V0rl?nsXX18 zinY9~Q%MfMOQ{#C4E=?tU(UmV9A)yz1S8iS0z46Q47%@TurpNQR^vvG&2udIQ zz**3eQ*Dp3s3j??Gs3B}EM3n5e%Uf4f6~^bGQ;<}Vc&{$N@y9}Dfsfs z>|v}o`!Ohqmk;A=7dGr2j-5~;&+#c-i6PMcH<&-yQU4n(IqENEYIRrDC+bM#yZQ;= zu$U65vbV!iFi_ktb<$oVQTD+!A>|>D#A$RB@wDr!A%>Pe3rPGurC1gB^wF*t z+HF#zHpj1DB&Y?VV+-B(;R*Jg7&UAZkCrr1TOG&RtzV4es!q^ogDv-U2|Ap6d%9g) zf&$FuraeQ^3_wJ;ym_mem&@$vOuFXQvV3P&b2+oN<#wLxghjp&F&W#W4Pbu)pMN*b zbw1C~QoE^=8g$VQsB{9ex;K}&H^=ZQMc*QY-{m`SDuSpQLR{4(3( zHAGV9;a>fhZRe5fu}&S4*{o~joriPR{auCIww1jlnES+4?pf$si2gRHQSZZ!trYB% z3gsWlnn1bsPR)~x6d?FM@d)?Ttcc%}p{o3FD7$@I|C2Wa^X z@%mU2Oar{mHaX=#=?#skO6(+AX@*ZK$hG*Q&fw<#m$Oepv)$&0OB7^QjQf+U68L&^ z!+OxQl#Irj8zZs62<@bd&FOSUawDGE&)-QKct4-q!}fAj%{URLDUeBAfNr8iJRE3& zT7#van{PieCJ5On{H8`mX9T;W!QxTnu|LfoQ5I4U_(kS)DSlSekroT?f8x)~+%d6* zm0R}?YIJ#$g7p#{r#}C*J5!kC4u;8?{vx+p;)phhH6Co0;hbE)MJg}0JQN<}fyK*1 zS$g5Ah2ln&nQPen?A#g}Z<{R>>_1r!w!9_?LmW@7=yMXA?JOHhHix?#AMqKRSTR53 z`x5&5x75Py9CKXJ1pWaHsghe1G04GXo_??26ME?2eOldMTOpnSy{N84wL3kT6}edtYBHVwxpFql-o zTI>J#nqUb3EW9IE>n35uo>ca3;z;mtCF8!vZ3!8uG9FVKw%q6HQ3aMv^HUpjzxld_@7-BnEU5S|MoNLp|go?DvRHCJVNy$gY%$0K=j|JbjjI}1eOD($* zt>BY)SVLXLL;B~rq~-*dIg0B-8u4NOv>!k0b7yL-(0Mg61EM6nB1;4XXrlDl-uML2 zOUx%8EHxo~n#0Ao@9R12!{mPAav*GpIp}$BRTww>KZvH-;8b$S!dM&Lu`L<|kXMO0 z7@Hc&IzVH_YVJw%Fqvvhoty< zRhYnzqrCN-u8x1P7WjACNqZxM(2QH;v7Iw|ZYsr!o)k9s2wuP)E*)MuyTQ0kZ{Lrb zJ{*28VbKV6*W}O~Ov54%U;bNxcbbd+GW=9}`8quXOpGK~XfW?biMQ7!e5J3acr}NU zCOvkIHLOw91){mVtN!$;gw3n551Ot?Qvv((OT}Cb%SQCNi41Q;@ji6DscO$FXt0}J zhX#iE!%FNI%DUYVpO_kZ{*OOtNj1%p#%Z^z))_3L6mcd_GSwH$G({9s<{Q1x%~E>3 z4)`C6g$ys&tM&0=d!SIq-S+V!lbW$;(ZRG&yB~9g7Q?z;M8*tdw*87$%7_=asf)3Q z=4FFNSsz!I#v7qFCUu*ukIR$C<)rysi2fa^^Z+A_jJ{9jDU_lgrM1QE(f5P5NqTM4pe`lvewIpdYXnX3zumCLrN zx1K$ZkY`;3NH*l}>{+lA=8`*?);)zr3+x6fj}2d9YVrl}v;Bj0Tag)Ttb2V8F%o5C z{oEZp-gt!YuN+DO$|h`5lklp^2~yAF!Er(PNEpuZ9e%yn%($L2RtNufh}P?L?C-zG ztuPXyorjo@7_+|ketT;^_aj$Aducf%v5tT`Lv6xcu^S3yn1!yKCQ-8HtDY^&FsNij ze4QCjN=uQR@h7BsE<6AAyPM@$86q=2L)ZscEleMCD1NfF{Sv?$;Xo9fVw%gsaiw5k z2U*p5&a~Q=?kC8`;WNs2__O>RgHYUJHwkY4mv`jY&%&FYc`@9XsyiOVn9104Od%=> zv0!Bm?xB7~L)0);Qq>FYzY@=_al&>*JHaG4b=$1-#bqSHt_Q_ccLUbqFFa-}$u_xfVd=eV+IG}{-55;$ zo{C<;a?UDpvAeU@PL`%|rN9yXU>2m+Fx_ecs_Fo-7NVK#-e+1(tUx7?)vL94-U3of9WjQhs5RlTOLBu{TfU&| z;yBwY`4vN?E|s<{TK(_ZjmRe%oIq`U zc^WA*b=Oo*;Gl`14%n%(1UPwJuCFfuJLdIRB9J(rT(Y#UT7OS8x3kE%%1<-OTFw40 zj#=_sS;PXr--sLEZ>X3@)Z~%;p4(Qwq+UO4KZ%CEOzkEXDl60}X9Q7kreKBlpPkU#%QlT>d%=EC zGDA*|G{Bg=BFNtV@@i0)E^STi0uR(qUf8y)$$0(^34A;JDNTQNyvH85I0D)M>ceMZ zAShbzuqf13cBh$h#EoBh_Iun1e|fn!v51S{-&Ax?s7IaQBzfw?!7 zZ{NM}-i(fTq>Uy4H+rEhj)@E&%HF}Ws9&Z#YhevV@^E3Bf**~$44a4))T1U3Z}x2m zkAK}MHjc+*ePG)#&M@zQ5-C z>f}MBAgXB+9NUxFCHAO(2PXROpVPp7lgBOPt*mPUrLYbISbTLwE54*66~Yd30h`0uz>6*)%eCO$mW#LMT8@8RCWZ{OU!Vty-djZ`uY8cb3MC|hq} zSnNAHp7k8h3@aghBRObZH+%F9{SnD>6QeG|391V>V)b0$(mbhMX-8_d?Z6Fb&6KL@ z8wp44LpiyOP&twrVgsUUtE_u+iI6j-0M97XOK%K$dPhfbt{{k>Rgul73V#!rML7&T zNZqSAaoChS9dAG%CY?2!URP2i_=e<-+ii7m$x$gtQ3a;rJKG;7J4Vqrveh!39<(+h z#WQ5ruJqk8+mLxc&{X;BIFDMBtIST_u-{5M)E6@$1fOm50z3hf5dq1Yo}ce{*%qtS z^45{DEOtjrZsw4ml6_!<)_-#*XXaLebXFuNemiFsWjHukSHMa*h(&Pkn?Q&Sm));8 z*L{+hO%D_V9~IZ6HdM!0({!UQ30t9vz6tA^qTFGqR>p9p{5s4FLS2A)j8ye9dw!6r z+UHLQbs{Y;rS0A%D~-rM^GfYH+PA_*qj z_b^tZQ>N9-k$iT8HzLT4hu;P{wZ73CGy5VnqT*Azx69Ip5YdLcD2jW`AdV;Sv^8f9sq^f$xZM5nE0O4=nPq3r+!#`Ps%2#Rm=U3WB1|mX#7ZA+(15#ZbianlpBe zg#|VJkS`mO|X!_Xu~;ZTiiA<6eFrL zC|bnXEkVwSoWj2}e-$HPsB69;FE{{diWKv+x}H%$jg@yzv>V4nel5d8{q65B+600P z%gcn%SY%Nr900e(@syIgUh8{Qqu9866Uku`C{osqu3>;+<#`beH+nS8xO!Ws z=$IX?V*Fa+Y6S(hcIBDH=fNS_sCwb2i&1=s4I1>SBi!|_2J{`3R=L#!K}ay9zKDx;3Uu5C#Q%ovoboQW7&NeyM5_}7}Z5v@P`Iit{{ zhL3nee4}&9lmM@~xQTNm49`@OM&@x8xmf_wOX`nv4CfxCT&AVlB$UE6)6sI@%J&Cv z1>!+de+8>tJLmY<&@)04<8i<~o+ z;JQrFv91f>;KKBm2NwMH5l0_J2`3PrnFEi?IYgBeVhP9Dig&n=FEzr6D4Xl4g$REc6%jU za)fUcaK|KfLj;r^h(<=kD95*c96!=36n;KJ50wcLk0#1wC}i7OA!wga&TlIldDfo1bs5-c|iQ@xUa&b~ZK@mJ)L7j9%X5Fso081A%=p+hF6T zf+O;Gu${fW;w)gD(sB-qv!HXnC6ACA3s4jih_~v?Ty1a>?v(%+eNM{C!}@&Y3Idwm>e<2QDr|xGvjZ72?^ct zN`q*(42a?-Ny0#j#nWg1gCWL0o;#(}F4-4chfGc4Qk|P0KPD5D9p zm8-5`y;qnn#FxA`PGQ3<^JLi|g?3AD-foK%c0$<4epR{YXUzqC8ta}$Hvr!6`VkAa z2e_m+7#1jK9X$vP6x4b)HxhrLW@o^g^C8p5;jx<_teQR>q12sg`${2Z)!o$U;B`4& zd*jOu{?yrKvig$k%;sAC0HHMV!&kxQW^1YOA)ziTMd3G{Bfi+&rV}l8#XESSi^Mdq zOqcE6(T3g^XG3aqJQt3-_zadNM^F z;#Bvx>+WcFnc?KZUhh!lhAvne+?v_nLIUE9d)~FZw!bfr;=?&DSCGI6metm7j|bzJ zsy$gsg5fsy!}9D7Fo~ zKWW#*9dzLjIm+~U_k*~C(slJN*eBDHNW-f8gLwR=6PKP=PIntBG)Lt#!nORQDCGQA z)c$csPqr$DutWpu@D0TS>rjPf$8))5yAe;$9|n^R>jkfFIL5XP3coy%WuTNVU!h@6 z%_USlnE34Xc9~^5W^~-IA&{6dv=5{y(lt@{@pBoUq4_d{G)rpH)}y7hgXC*(e2*s7 zC2rWXv-hO=X1&|MP_KhE`ZWimr%0&B|=hY4TGQDEx^h1lkkv1UcnROL?A$$r%JkzzJQ$(BWbiMVD#R~~L3$lH+r=V`_1 zCFMta1Hg0WzPB{=seV{iDPL-yK(&f@u~lHZ-SezWyr{rY9aA2)*^B#S1?;~>DIN}@ zh;h(s?=%JO>hS4D3AaD5gWklC<`&R`4%Qf6Q(d*R3k1L80f6x``{R1UBWmfLxkT5r zxHbJp3JlCjAW|VD__yAyspk7KE1PECP)BQAj@tnKyZ-P|fNKeaumtnc=`tX25QP-p zL)q$z#)~vJatKXDxl4jHCY#*S`?fvdM&YapEUCI`_!U|Is`Sc5H?R9p?DV7c%8vJp#*5lt9>anf}Ps?>;OSrP$ zt=&gluX$Euc2F_nG3b@ZHmfJC6|`6&x-5x8`x6m1Sb{;Fm-5A=FM*(1SI_ozF;|K@zrAMv1p zsh`|jqDL(rQ2SCIm%Su7_2Oib*8QqI{oh4&!j-jbFI5E7K^=U@CN_+pV3A!p+R zL}UJ_Hu=70k++=Yk#mtt{nhSm@8$(=q@d%PIk)^8ZJ=OE+SikU_KrD|tqYTz?;&=5dzjR8tO4!gUs) zYlf@ufZov%$FRxae;72ssJ1Gi&0tDJb~|Twip3@!`N!aar}h9zvPN#CO7G}FFuhF` zyDrFCa98B*>&|;!KQo*2+Cn^nsqZN0Ki&*HnO=KOl2>kEoFaWC)%VXXf7vNIf<2p|k97_@`|g|9x2! zRHfshV|k59snNd6j9IDlc0VO%r==67!5>wGRyHR8+%7P0m6MZ%@R@!4D3QidAcCkQ z${A}QxX2zxI$hR39dP`@9fo4iulDECnz15^hI(!u@ae|*nY5AI7WcHI1U#oM!Wjub z5{eLPmN`f+M5%W4t4Y(YQ}tkX9Z5ff$m-VEb@;K@r1=hCVn&I*9acxE060OKtE?X* zK8kPYtSsdt(M7&B$aRB}r4!9NcytAmi3nEhJdoxs29QI#J0_>^TZcniDZxQN;GYvU zwguT~2C}SAisW-RA$f$v;=Awpv0&)(SQmq zU;vaGWJzqXT;Zpl$7JxP=zgb|9@sZiWpd!dB9tO#f1sXE@Dn|kD|a4 zdiIm$=-<4F$gWr%=4Ow%tj+o&MK(;z7Gyn4=t_u^9g4l&Ri>d;Dj!b4?@vyB za{WrPA#L`oFr#W6Vt6T2RpP{Rl@cR)u~-|tbRxS^F;-U~_8;}E zf_y3nQ*|*t&jlByP%nV=Ux`ItZZg*0ot(||LCG_PqJ_0ajvsVyBvu)zB$ZoQo+LSk z%kMmpg*Y)*cy{g>%mU8NyThbuz{q6?QL1CCN?Y#!R&zNGg*}3It7ll&juBRV(}EJV zS$mNb1;>jEze!f(H5cKi=Odz=9 z@+{)OIZfPeM&ix9%Z%(s&*kIx=fJv#Wf)|Ns^G513U~`Kc|F5eitDnT{nL$nAoOdi z^?(#rb8t*g6c{OgMc@IboFkJDxKD|Q!@tyTn$w)0%Vs0owDYA}Bp-~$+u?t6Tp@ae z0HUs!eBWDD<#HWsjaI#Rp16C9ml-bAFlf^UWjyevwHd-?jmDfx{wK&WE{FTu#9l?9 zhX(NBBv~gxWou*-<)qFxUGgE+D<$=*%7~2KB22Loigf!ij#=25z+OT;2%hxEP(yl_ zV2l*c9`{?5N)60m4}>mGu-^=cPy1DRA$h38cim<8ChDKE;OuzbNNwm2Vi|JQc9o)* zmIK(LrpJ}edo>BudZdB;ZU07=H(h7C+rBUT=4;PG?0}(S2aF|tHaYl zazi}EQt7f$YS8Y<^imWH={P`hzV#KPS$A#a!D_0N;-z}PnMCAmDTqU!sc-5T*a)Qm zc)$3`u39_gCNGu$KtIw#`of6CQKE$*O}op{m28;0LPCUKtSC2zz~sR6U82axj^kIj z;v>r_YZoE2SJ>4W$=)82L)Ui=H_Vo)ip{rjE-7}B{1|)y3Z7)W`wUok^7}kskMntm z$KGl|`w$@8yvJhlyWzC3QT}VItY!dwTb?SwX*ZLS*Gg%CPqvuSFpaVlscQSDJwC?o zjAWDBH3AUbk?fx%O5;T=>pdV#ZFz7!qUxSMF`qq~8XTc*ol*bp@Jo92^NS&x&oi$c z+k~fjz^%S%Up81ZgK11 zPw-z`3$ajqc3WO17oSeD)vvzAKLe{#{DoesDP1q;k?UoyBUySc_(qYiBXDzxUes`9 ztam5yq1mpa97w!Z+Q2FW7G$UKb};&TSD6x+-ke*DeX8-UD5kPhSk`dz?=Q1CglIsD z=-X?}tdqBLG4+FHh?+ff()^L_Uv@aIJU)!5)(Q!)NdP0NXza3DrRQJq=qxZrcLvh% z0Q?c(8svs;3^%W-GOQk%HJbcXPUNia@YPcH)C8_ zmT<-@E!U}87i*1hvraw2PPpky)Tyc=&NU%bljm>GHny59I|)5(YC2&PF~-|276qHx zRDPVwX%DDBdY-Z|88nS7f~G)bx7jh(OzqY1VvLoR8Ud{i#Fuzc|9W}8eW&)OaEHZv zRT-&>1anbGzGlt;A#%d}00(n5a>T+z+20PG2BaG~ZR_h&7$6r4I`N0cD-oOJ@t!T0 zcX6F<69qOKh=6-no3^0H_MF)n;}N#4=>xM(HfO#AiOLpu;GLZ=y*EqH;`mH3TOiQY zikq`8_O8ypci0QcLj=Ry&~K!vBJ*OV)Uz^ZGPMgucn#N}%re)oFy%Be`~sGh*1w445!zi!TCyF#2)FZiIF@zxWMJf9_coQ*B3bcm0#D! ze-Sc11)I$bNI+nv54poiVYriFYS8G^B=#=28(Bf2**Y;G?W);22S5`Ba^o8-ZI4g ze;W#5ahIl2ZDQ=zFWflenK2;gOQYnyI1BKCm~p=?_+ZV`oW7{;^=XvuAE%Y@A6{Yc zv;^ay)KasLKJ8$4i4`V|uZuZ6v7FJlz-lYg2@xT97VWvC$}z$GQw2-Gc2bzHnddu7 zMrmTiOhp|vWk>D4i((1Qc>2uOin#$|f4%}kROmxU(F4lur-A~omz7AGCt`Lhe_$~X zp3-4(a+2l6rs@Rz?7QJMVAVDOIrb6B1CZXjb$jYX`Y~|{P*S)#_oAuhj(Hi!D2|zj zE0BF!wS%yN?(K@OdB6u5%{}gS^HYku5gGA3-zk2*DZ||!wU}84RyS#N8u8c%ZW$(S zx~i{G^D;7XJbJrwm2o&oBvyTG8!P1$E$gCzZ8{A#F`g`EOb4*Yexrz6#RaZ5pK;F9Z?}6kfGHL*6KupE|F17Rpj;D5){yP-cbxI|3t8Hz zvoS5>sw11h{xJgSH*R?+$?K86+uno1HTv^3FWRRxxP2Z|ky!nZF=>(eTO$bx-3YYh z1O{BYxZH4)#WN8olg-(zk>@jHAOCN6K62dNc=e3bJ!Ro7nopOH6~bU_3U12Tv=?~B z4+-49CR3@e7!?e-YJKVeG^jNqTbT?LMv<>L~m3OcKTA}95K@hV+@#>rV(H%88*O<#X&hTc zl1@O_LP|<)b(DX53(j?~g+aWUj`dye&J8@V~+;`>5J_5Ynwv-`Ba?xEPQZ;q);P71a?-( zAL(+>vgF@>dxGS!VI!EYC4ekTT_QS}Kc;krZO2E!x_~!^R*T=l1ViFY&Ye4__fp(e zG9S*D-CDqLB(d0Pc4UY7i`OdxMkTXLzc`&FFaqv=v!w?`80}%Cl3uq{tOPLH{Z4)> z=Kg;MK7A%J4dWI@FWsej#!!9$ATW9AS4$AS@CFoo`B zPohSWZrHEC;_M#(Ma2zDx&7Ra4H>t38YcF;OzX9Ek!sbelc~I>;B-CMs1H=az#fQ0cTX!gZmrgemn4 zk?Y^V9dpC)=du|O@@uR;M= z(mx-MjdsuDViF~=^ijA=m-DqZvg-E>b+ODR)Yy{+STVvZ8fYLV1Vxo=!%sE)>? zsD1$;)vuWyjXD5&{7+PmNke0T4Nzy2}- zQhzK@FD^=6KQ-!Yo-nqUKrJ#_ToOsSEBm-~;tUciQPEz|(hTizV*4%rYHN#cL8myE zGrZp^f=r1wLqFBjgx+c22I}yKK-(UJ_VBLb)b(I_8dVlf<>`0VS}n3Wv(UOn44rz zrR}DyPG$UHihgeADlzQ|6D8(^G7a}2+eDz{h&n`u zcedLzwGbEjDJSt*8?9HmJghEk-g>)64s?(;QF^(Y@rqcxkRm6_oxBRw$6LBU#~IbeKboHKs>rm#ee;FLOW!W2X;Ia;*Hn*On5mdxEoePC?6t#~)ws>Ga~boC_%mb7|EAT>tbOE2 z`m-bD87*=XR=D+n z30u#`AQykt8VH7_Tjv>{Y5z^LRJ zp}XA13FXK$;+v5IJ~k_obL}ymC65UCtPHsmcFo!HtiPAw2rE(B^2V zg#6G~4+|aUjRgEfO-x-jTFjkfTGhWry?Q%?h^@ z$57Amu<-l&zIhiRn-45OkHv5-*P+Mno3mA; z3;Mr*)z7J~Wx1C6ZgOy&a5}(pviYCaV#+@3iD9A}7*@^t_G`qJaR@vg1BBXDd?@kuX8?UU2^ z32ps){To@;;5o>%iS2uT8cm#$AKFSl8K%4FbcySI9O0kbU7Fkv;da_>dL8(Tm~JSr z?fxeo)nhnq==x83_i4SPuawwua`06EYG1v7;{ii_Vum|{nv+H}vdlA0{T}`ZHWqI^cB169xmsbI=ap9hU$dkPvzYwRJ+{j`HPtI>#4$>)QV7LK3-XOA!@wB(} zo|_)nd8;<|x|y(5+2LY;&Tdaid)}?Hzslr$SwUYh>%amXpUI%wJ*-)``<9~Y>=eCf z0Tpyq=Vn6Lz(7G*giBzUFQ=*7FnLl7wT-DlaI+w00LxxE`D*-;b>_e#eO2V!3XW7f z2~fLwNd~pIK#J7VsFgp6*s)az5v2zNuE>x7jJmUDwAHX&NPU(sfZgdR@N3HG)M$#F z-lgUxj0?u`K8nW-7f>(oh-$rmj6jF-;*ND0ELHfd;L#1eyu4GHLaweq#tC6#U`25 zjb)Z@=LX)JIDc_oT$;hP7fz6R--tyL1`V*V3Xs083>`Ryhd|8N*r|82>ASJNEs=}r za4f2-BSAr{Bl49r>O+8^gN0Hb_;J_T=uu!M?<&&yXONX_3eW^=_1PJ7N(5{&~115 z@^N-bt`xdJqI8Hrye^6=IS~ZA8lF1-c!E_y9^$U_RNJ7iU&^e5zB5TfmK|Pdx%&2t zC+F?6ljt77qV7rRC$@M)0ObJ_Cl1cNkw2Fm5sM2P&qb}I-@hj3O0XeV(Kd$s5w% z>Kk*l5p2j{bN^_>j96=&M5M zqRKmo4+b4Be~m!`doAuqZXTw|_$PvPlnK}py0AwD38`9cau=vUMG1Tgyl8W`^s}dx z>NwOgLh&wSiW)-|ob~0rv*0qZUoTx)F&*R4mNGk~fa=#48o<8S|-MiNOww znwDfb)bu1&Y7$rfFvIJ*xuzaK~1sVji0C5o2NqI#g3z(PfnQi9X ziePa?(o~|Ntk)otm2X?YYK z)em^{#X!vZ)39VSTpavg0EyHMBP)&WBT8$?K z#)eFd>2qgop#~n4T0Ny=wJ$_Y90Qi*8SZq1^khmRKM5RZ^oj?nC*dU=OT(eXjJ3%D z(z=}<<~zzog?^p_RE(Uf*eb)WC6drDhU1_55m}MG5Z+uef8W5!W&CNhveO7H-f^aX zIeeTp3~Wr`EYsRpWQj|wjTuKVZdGDRhAfFFIZI`FFe;e7Q0%L1WEb5h;OUSD)!BL&^n;iqUsJnMVLPH_bmA~c{9#5MmkTx=Q z`q;^fq-fbylV63k;ASgg{h}&rEWhK7I%ncvu`CEwutRxha(r2^H*q>Zqc+P2;y`EW zZS2q(tI6z;J3^c<3ui;L4BDQ4H6f1fjjf}|<74bT00AgG30;8UNt zJ!)>Y2q0swZPch6J{$E82ogrM%&|doa7=o>$>Mtf)v<*u%*d_7z?qlRpgi+_dJ2Vh z(&3RS1qdH@ymkWWu}>63Sha&>6A47OWUL{^FvP%G_kR`wfIBA6f{jXt2fC)?|K z?Nh6_I#I!nL! zv(&Xc{v46y`ur8i3(y3|>;S@b(j&n~w>Mf7oI6{SmVV~`@zT6>wOLD)0#!7xoX!+k>kxA-Izg{K3)qAXW`n#_yc*9o zUXSCin@U?;c5d_jow*vlyztn%0YrF#q&e_4#Zl~VNmwbY|K|nhRVG|7D=hpZX^gq# zQ4T!x4Q@`NcTr7U*qS2FJz95|^kK?e0Zq$?GOgKuySiv!J)EJxlj_e*x7LLB;@|iw zj8m!B%r8=ldr$#a{FkRM3Cf;MGOIhwlz>_AIt8z+Dg1uFa^QFwxi)hO#3Q4@H{0#`u>HHl8p1(6!tP@%t zOkyHsLA1gQD82S_oXAB}u}Xa}IXV29or$DZK?mPU}Xtria_*~YeSU|?g) zx}OsJ3vpo3cmx~T>h(kMcOB{?hlDAQSv%-(&g{Gxp~t6#sYoh~Ph`nMd7{;PB-45? zDoY!VNGC~FXHA+YiD(a#-x>qJyz%{%OmvEZL@UpEDRp{Ut>Hx`q#(fIAX80XrG!cJ z39gj{!D4-AuVVv6N_g}%%Aq(cQ8{a}-F%LgAL%6I&=8pjMwPq+*i=jxdjA2+==3Xd z8`gD;*U~S%kSW4#%EzqP;Hh_#hfVzu8~WeToZ^EmCx&DZ{LnydR+4u}*x_jAu@V-H zX__RZkzAkVVn4`m!@Gn)4YVHgdmWP<0d9ESzS*g_SW&Y4@!+IB_S+w{#bQH8M0Ks1 zER;JBOl=}T7rFqc`{oV!VbQuWH!8eu6&Y#5xa3*sh`-9=8dtFCRqU?J><(=5-a<-2|&0#)@qMD`{o0O`eb_GubMh6g~C z)6`3wnA;4^6VVG>82}m>85tXgv!k4NetctbS8jS7a~yczxfOsSox_iW3rHh9z5QSu zFj0Uz|0rw;#o!t+9+(Te!jl6a15icG4^Y&L+}zWcxD1|ses+5iPU1U($m(wYz{1k@ z;HwObn)f?T%CAur17J~%Z1u%fZZ#Evm|NMOB?t#tV0ZUs$O1CIu?-jlm^RvG8sNnY zKsBFCKvq;o6O^E$I={4BXy&h?#>mLP!0!ETdw6AerQ{;uaPW!h2%vxqmw$0) z4FBkb4d9o00KYa+dE5#FHNRS^_0fs(@k<}KnaSDV@q66H*K4Ef^-VTSPIk_ZDk20!Q#0U?;oXz@9L>#7 z;{@cCv}AZy`Qnr>#9XZ2?2j>*E6nWete@y_1vw4b6!5;$ApnC@6JR=@2$iilm6e_K z=fEc9?cCci4gcw}&E5IH8-HbMYm-~k1)94UnW0>_qMCw*1XF)VX1EiA=#T7 z8yJmUU))!ILacs%m5Lw! zMA{q@nw@~s$kbUfwBO9jzH6mfG5kXGR^~Q9-|KOGvKIcc@l)Y?{IuAUJZ@-#x#@`? z{$6<6OpPtToNNFb9KQ~KeC9X&Ui_fnA+&yqTGCPia`8`o$9HOp?b+eo<;7W?{=r#5 z21jR>2Y=&_c>ri`?*6EE;mJ~g*FF&-1C#nDw;u^Wj&_bufaz=8gCCn?aVN0^{!%|e zIe?;bKLm1Qf5k()VHkttFKnOViJzEufar%`L7i#p#dO^*SK)_tP}qIF;AO+aUqEH zAJ`0jv?n*Z&oSp~zTtcL-!Z70U)$FNn_vA~_)a*#E`GKVz;g@B-#A1@zrWvOR_XlX zoZrB{CLF&zKSdc$A;f?2kKXdnuFZbqg5g8ye*N*IoW94L`3HA?|HX?uzGiNTSCP-( z>WqGCoJaW8zx3HLmi88Z``q^QHAXfTcCpG0EkEvef5pSI6Pk)jy5N?^o`=2+f8X9; z{XBnH{J-w99`QGbh+b~>o^0@yO3e=r!5EsH9DS?9Q&4F6a6&FA)gDJ zU31kKw`4r6b*Kpi{ya$}clBH`Mw%YtK2t@Av{k#%qA%9i$96ytEr8AVK%OXr?=Gr< zmp^_Ii^&u#*8OFgsW#MOSS@Es7M4ekL>pkW#GzbpJP~#5n-gtvI|I=J2uZg?Ewz-F zhdlBi?gcb6%^}JFYu+9v&r$u!>4Qt9q5RDLdzrE&o8PAe5&aof>c7ldaB ziemqF+!d`qel|eve+dG07ezpfPPdSi1Jyg%s@7-RZ_He@`*(C@q@|i~%V3jdR=R{L z6II-lsYVYA;Ze`Tfr@*J_|&~)rs+eFg`^`fqy`cs2A|cY^ByB zpsyjb9>~MpHPm*~%R74+X~hlc%kuTy&X}V945Qk}Bl7uSyHSy- zQvQQw_NQz^;y68F`>kPjZD7|>>>JHAm7NJgw~l#TVqp?tXjM~RVy$8D-|2W+gbdTo zA1eLvCcTZ?v26-clrsH{kVbfp#Q9?51kgfq$supBsU>o;0N!{v6K{5`MjZdV5?i>n z1@F=$*Xg6#HG!#yKALXqR=&4JVXSuk91}u`wj7RVl5~pPK`k+QZIBY_DoSE*#3r&% z09n*&KKXtMiniIX=5dEjf?n}&WLD|{WxatKz*K6kUsi5(t`0)GZ%pmbc#9pu&%nT{ zP|m~f5;M4}S!zThj_R`z%Dv0VS=c!t@!40_6%`XDCE5?8IUCS>m>F(r(;NGAx3yE- zT36CKtGELVzz;wk_w@$Bo?Vd%RI%VhgLa?xcB@O?Uy#r)v_juh?xeVNht^lJIt$$F zJ*b7upaZgk_&E5uBwFnX*}jYrr*eYiE94islNT3lRBVwJ1w&(rnqXi$N9{tMNtsN7 zY*G0;bF8=fS5xBLTVF3V zi^?z(aZX}F&1K7}R(HXrh*@^~UHKTKGlz0h5Cq`O5b|D`$tj(9EZ6tUV4bhw9hMk~ zuz^iO(9u`I9@8F)vgNIGY7Z9Q;yWDd8s71LX8pVA{A z9XttY?%GEI|6EGHkdy(Te!tL-3xTajqAdJ?)*l^Yt*xS&CV(+#f$OW8M-RyxR9A}A znTW3kw@O)2d9G4rZ3E}PXfBO+6?q`~YR3~2i{kZ?n@o5!0cJ|3X?Gran7Na>Dy$Wg z_Y?c}Tu#Z|*(Rvp#bJ?ZcD`8}4|d_#oVZToM-mYXvZN#5A7L66{R_|nhv+r(w1zbJ zi#&A+eB0?~^_DNOeVod%zk*nYmC=T7-f-xtXLYaklC$otrc^C-mGV@lfk;ZIb`r=W zxE88LuH@85Tm;|PZ%0I{Eu|Sx{G1dp*c{C0ES}Ap44MkU+tn8dP`H_ypUjEKD%#b# zY~mcIY~wMro300$@L##~lHPCRD$QqK;wHB1A2C`$&}ER)h6RR0Hp*ySKKY-iqlECR z?alMRjU~Vx1X@H|f@QtdD5#<*w&Hz1aFHIaEG>3@7e+!9y$oMGnjH8^;~|-j#9i^T zz*dm)mV)a#h=fa6mKuE8yy78&nj2EUWnVga#H^F}9Hz7Vxg_!P7NBLw@;}d+cTL(W zfFfV2x8XAN^bjHp(Z=BP|F^&FEUk5yMmor70t}Ba3k7jfwt0~k$i{N*FFQ%^<#Dz< zUS++?mik=;OKss_i+j~4Ha@xzoeF9M;3w7Z6U%~Skj%9=S#;n=>=?*drM~0(Nr%@^ za;Ohp=OzxP+~w+=W?pn_=B0K1^xz#eJWn8Y4H{Z{MCw#4e9@s?B*$>mD!>|7j|5$L zBG+im7K&Tg2cm#FW!!oDn<#xZpJNS0O;M;7P#;dW`ku0fj&ZgA*`N7P4Sj!yRt7eH2XaD*Q3)muGey0l zsqX2r#wilrCoQIMjPTO&$nkz;nqdmJOq9)?aPQ3!-Q2@hQRS^D-sE+B2;s+wXbTf? zjuC;tobw;2`m>l3RV<-d#*@k6v{X>r$;aB1QJIH(miZmwkHA+#UiDasgQ^3FC7Rvz z>KhhUTcX`hnsM5W;_ZcmHn_#cSrNYuP3h+?%)_o2EgB=4#`GRnK6=?}6%5g54%!W$ z1HaMldAc$-kOg1(<~#diGTSYg$n0d$Z8~1O7znqodd8riXA)UJ8Px#blq0aP?kCCs zO*QtsBIzWn()ejrl;jZ$>K&%REhvZyog>6^=l0te#Lt8iR0ecgV?DjOKq!}Fd=Ly7B}UPdTa>{OK!1u?JPI-eX<7C~e& zED%#F9m0`O5K9tQq#8YzyL&U4f?U{beg26r;maVj2ggK%;9h1Adi#oem?FT}q?l=$ z%)=0><0f_}mJ<8P?NQL68|mK#2AvS>4v83qzo7UAs2@QJlXD7>Y`Q`nUc9$#aOR0k zc;RKJ+Y`(>ESaI#@=kW>h%R8syh669s^)2WL|>%l;1IWI8ap9cy9ReBbRS$vgGz#w zp#mI3W~`fhhnvAl(diZizoj`f*ZZ-1xp6DzN)ZXy*1 zjy9o?=~=D!VvUD-AjU4z%@J!&>@n{cSv&Dq|aBW&G_Ng^~ z0W7%1QX*3B>js^7x*sFuQIg~}AwSfRkNh<;pwq`Fjy7EGa#94 z8(I=8k8b%5&WYPU@dL7;C_`%V6jkGZ_iTVJ;Vv}$u_DZ<8XT%ijFPT8lmItaYbF7>yf`s2(O4ta|W zbypH)*~jZ%r_2q(iH>s&UisK35M0ZLwhrduqz6n6(gFK?Fokx@n+dmhSx$1g^uTh&8Po$$*}uhwyz3Nc=_89^%Jy-z3TPa zN~8FyM>nqH4gyEWvC5~w=qwqArqriJOjHP?IcYpQ z%ZHq758}c)>ly8wF;=`Wp~Z}w`amMZFL6-jC2{L*fjJ0TGn^YMfoz3BM!J@r{$We~ z^XJt{id!d$yp=H6gVZaC5~*;>Itcn_LBFXn<5hAys59TfL3Bk_o>J|0e9e0D${Ml0@=H%#NVDDVU3YTbmiRbSc zKBPl+lMl_#3W~6kpmrtwk>2oiamLtMCtAJ+Z!D@FXw{j?8QoC#THYM560-73wk-U) zgUMaZ>lh22N;!SmK;VH&+RKW3tdK5n(yV-WIkDoqu;;Qn!NL*U_%!XDa@3;lu&Y-o z2EI(DmSwl;Zy@V@Zeq-4oIZV6WX@?M)}-p?b)(ZWoQy&P0C6L3gS(U~&ScvCTfVyL-T^l$EhOSxQQlm4c>R!pg}H%JItaLlvp!!)*YYfFKx_l9rm(a znoh&U!MhK(370Pa+wUx^p-@g%(oLiuIzH~M?kW)%qEH|P;HblGn}?^OOeKs|$_APf zfjM`e*)71viGv4j;(Q`WzZ69gxCc&}v3DBO!|5Y5$vcIY9(H&mpUm)V$w?Bvlr9il z!1vdO;0DI+aK5egaBW_}*~sjR)_7dt22Lzb*@goTX9;}x2J$5dxW&l#WPzB|W`|E} zUtIcDO{*~JbRx_asB2wzCg&C9Yta`MoUG}-7NJ9}=U<)Pzd!G#Vy4NLE3I0?DI(vJ2*_3GX9542Z}lJe$XI|8Y4kfIg`a zC!jj}C?F;wV7FfxvPa}W$^KmOr=Qc`Bo%p@ zL7Tu=xN%Q4NvXHy5-vxz`M5%(2J!!Xrby>G>zJfr&pCH|2+7K9#6KThZT9iV`HcNj0!p;mPBYt_-UU=I1kb`cN2V^m z>sQV&8WqY?@{lSOokhSmCaCwHZ-?|y$#{AaGCaqfohs}~=Fvt-^7`iEZHY)1*G*1U zU3(!ZP17YFCPm9Y=Dd!MX{-*;LA9(?c)9s+i8Kj92LhwSTNzSXS0*4L0;ES-X#?xY zU%7`!Q?TQ_v$y8JniaxS=x-R;AO>5Ed>97Dwidl-^Vq25rF>xm%8_kssKW-4X0 zO#VbwqNWS8u4VgruWSNc5tQ`z*rTUu95~60<2hD&gJ^0W&gZKT=BXY90x zU7;a?P4YHmosl69*H7CvFC#huUA-pvZaI*L6Kay~FR~+uOO9`{HQNX$rpo0E zP@CwKlAIWggoSniX;Ya?T3AXkUn1nOWBJF zmMp(B@my@@@D{fqjB4TA;Ko$-TT0Ce^)pUzAm@+XOu9C#jlxgM$QG3e9(NDC^)4{O zPJMYW{YBb7ECnZl8v`h<)A1mUVJT<9Prv{7V4NC#&E0(YOz$S-B+UP4}p% znMf`x{ZgYma}EaWveUcmM!A~Zd*%=c|r(B_;DEAR$deCnvih%R~=3?hv* zqdC#H+Z~qKctWImMlFvgb zMvqK{=$h%)ZhM+F-!zwT*lg@5C_OcKiwKb0{G=5f@7o>;pJ2xGlhv37IOC{fsu$UM zTbV0U&ca}KR8im^OcSN?ET(+L6?oG+ZfMbN;bI}om*+133_1oPxvG<4zu*)=F_PA?R zoLU0ZNbPE82IFlA_9|zLxhG_2ODq($_OAhB(g>N-Skush954vQ zDN}2OI_X_oB(NhQm(gxcc3%q%;OM+v*tI9cZ-8uoD0>v@2#O+f(!(y%t0^v_ABp~$ zsw~Ui1CO8v_KxahD65;g(yWOg*rT+|14_03m2Y|CzB_wp;l(Ro21emYZl* ze6Igzm3R+J5!QCc-oOukHMWEq&A}*F_;g>VNd+~tFf>~(t8guF>_JCLsaPow3o*4J zS9(Nz(9?6cz`}THfBR%xU#^y=&!T6AJ(qqIF`ni<77*trUpm+%%wOIiYO=Y>rvFCq z97f#*M%s1XxSJupcTL4~2Gpmlbq7 z!%)`RR@yl3_sv3DqjL_iy>*4~uX{v!`(5;{atk8TBK2giZ{kM#E&9>Ys&H zU|j#YLuj;D>yP>{rAkp~#W-=T%N+FEKd;_z!dko| z*y;!&rV0;QjiHM-rcRYZW^ z+=ZLJ0q-N}D`uM_f$$!$K>%;0Zzr;lc@$|CBrm_wxI4pL%~PMge=N#KP=Sebm2D;lxjUDnNZ_P>LaCCf zSkvG`vGb??K~nZ^L+sjTky)$MWKE+ufl(eZsEM%o+UO!V{#^Kz?I~wu>2};X%R|h% zOl9$KEqah1i?b(Bth=}A2|7P;mt^mj4SWYLA~Q+39U4e888^)0Qz_3j4QuQ8aMaJ2 zI4@BCr1Wb$3MXhvlE#E**Ph$j*6>~Tm{JDO$3s{#Y)7dgj2~TY|IiCzJ1Y`isxQ`Y znzIANFA8wpdPAE?$#bOZ{J0z4Di#q26!VH_%srl_fd#8~|pj zEC|l@!(yh@lupkHEDjR*!2fLbo`I_oj~OXIbagak^sf@&>IAp`<&zTu^d#(&@u26F z{n|Np!0G7M*^mCpplmNhTtj$}hWIdKl3Mx1%0 zjb=Nt;8T&MqoFrep8nwy@8}zO;%lk@}XTyGe)o=>+S9At0V-Zu zNc8y&ZRt`VzXMl@#uy^-UTTeQt_LaKef)-ygrb?z$bPd{yySJ@8){0}fIz)Cm5;?O z-Q5}X<^nBo%M11{R#n=T5P{yPkXH4KMRBWvr}T}VVf~`$`~NC9toSeozz77-xo+-1 zubK7QNhY0RL~XkAH?`;5OPSpcQvdCqPdaAfb0sv_!(j2jZ~{Fz5=&%lf>rRF?At=I zswm9xK1E4zPCfY?mYcLsk!h)Dq3a+oGKy2+U1L_iEF_<^qW=!=vJ=TyW!L8c+ZbA4(pa)zr623b|^sy&< za1^4G`;dm1tUg^id(0c~@nlzRbeZ5b1=2)su(=1uBC(VX-*)VM&2}|`*r|mEP&{U# zFf2~%^%|xWKbs|AT4kZgd$=V#iN5{>d<{(vtV!fP?lyzPFHL^g>*e96F0PE+Ycq`V0t0`_pq?y79(>5f?-Z6&&Y#KTW`HKk_nXM$5Q^Zri?qWSmPpGq^Fs?0 zN-*QuZrlxaWX`x2aVBkBe#Go_=VEQRDM-8J!atG)uzR~hCd>P23anV(VYRJ&swf{Y zpD}Hudsjrmkn?XYH0h`2l&*sJggQN3cF=M_x&_=5dC$vc*SBYAa)`(2T^O(m!_SOs z)8vH~<#M*#%qe?!G?~BWX(90;*x=!rcQ@@6y;4*Sa*`3CwHWfrY^?`3CNuxG?IZdW zK0;@PR~^^03`p@yS;9``KeRNGHdx3w92Tz%^?dsibhE7F#mobUu)UIUe|VpSVe@JO z1+=Lo4TsciVMhO4&Z3#{NJcKX?_7F=o8nY!1A|^C@lXB&nnV5&C5Rj?wkmwaFIduU zfLdp&<6=XH@=1*y<31gMfdB+mo`*hAV$)w43BM_aVUVtS23ho3_!g3)meN{`&BnCI zgMb#Z7Jm%QNI@?H#@y-K32y!*ReQ)`6xz|!isF5N z_S_+!9=7ad$&8=tOdq&lcb9Np_ROurDNduAqUi zGOI@~8gBfoJztIZceMm}_8n&1=SwgN5cD^n&k%&(mkYrebmD9@kdTitbRwmh2>Dlf z9ic}$!Zkv+;Oct4fF_l3$wVnKO;=(lOW2L2;vs>|V_Uh-))W>3=Tf%68ZH(p6Ki*p z*F2UPsKY-ERXN5@;t-tT%uqEe&xbA9Vw(&OBQ0EbU|MsF>;$&er;-@edzKp4r(XB{FK(C+{=PcIgPrCp(Qr>I@SDVce=~;oIa`Kkw0q9H;x0ydyGPvM{}6 zU0Es;5-maNo?|htrdyb*yZ@~Vn_MsDSOz~06%#b%v>vRsnQjRgkudtAeoCH=h@N2g zW=5o&8g?qJ=?mYVZKtyV$kAMl8zyO?`020nDn5iQ zG9V71?b$A4F>4ZEpn=_}H~hGD z5<8ZKY80?_U^4)u2++P6{@}c6Q13WqS{Ih8@fNpWt8W@iaAGRrJV`p;cV6Y*939C+ zK`+Fz9d}*RFLyf)Y$0=BwCfmI+n9%HhIguL5!Ml(lv5(yGOdV7y}YxMU*tf2Gc(VO zycrui3k9CxI0rk@3M9Z@phfwRa#?3E+Sp2Pb617$`=z;~AFt zR*FWdSsk5qb41UI!M}s!P?%^+q&KhnBEC=)r(g_?2Twvb^gd+>4UwJ5!DJcbxCI6V zdLooCob`N zt`nTXf*@#t`e^(1z|nkK3e1dys!XSmd`|FYr_wB1fnmf2*lD0*s7I!~FU!M1QI&hi z4rN2sJQ7wfyDU156sjjJA)>UL>+WPa5ht9MvWBOw*Rq|Mni~=vC-sttWp1732C1U& zopy>_d_~0kC5A7k{}|nS%Jbe>tE!H+jFko<=@EEH;k7>Pg?Zxmlz97=;Di8({_ds* z)4lL}Ooa;SIAV}i_^0>6Z$vQHf(fFl$9~Pc@#=z4 z8`S_kSRx*MhF%^()Ddpd2^NmtKb6;|r9gX6n3QJ^yF)XF|9s4JvVBro*2wIKRX_46oiR3H(QpR;%CuEjeX;x&+L;!MZA&z|1d!S4l4 zPG84p648!q@t5ovx6k_daeas`CvVS%nW8o-1Qs=;DGZsw=q?MOM@J**2yTv47Y`HT z0PYQ)mIohE&xBtxe2T-`fwj)aIECmj)Gz7YM`ZRr1-xnN&O=P}2RdC4z&=W5E^wCe zPsNX_$(dFC-V>db%J3z`;q-dBvS`UagTtXp{2B)ibCtGFi$ z14;Py@i9tSDQ;~+-DLd&w_!Tn}R@!Fg(6$BCaazJJbV<6~2aTdkj`CJdW_SVO2UT zo$u}>^`%R67n9XDSL`ov20zcwvKu#+WSo(R?=*5lQM3fuO#f-ptMdlG(a(yCL>7_J z4bvV~7^3^A!DwB47GCi^xA8M&QaINkTtV6c{deSN1rMQNDFf8_wjQkVD2 z>=ax&^M0dn3SpIw*3Qk6^Ga`C^B=2b)~ia*T5Tx7;pm#KL!!ln%X--k{;)iDx_eml z+I{A2=$=*EpWsfDmO?W5tRf8X0+2OgC+Up3Kvm2RyczDVDX4Pj zr#0mBxr8TkN~6hooU3nhJIjAd?Zd0FWPBy=PhEFJrf6m(Z5Es*RUg`U*DUgd^ieE- z?zw5n-SS3VgTx;3lsSgB+c!%t2FSp9&9FZ;6fWku*($yJVSY(rZ2YKP+D;DW>uNO6 zHRR50TcI$SJW$@uLyH7kgikxfK`G^HyOT$x(7!Mbu2ron<5O;)J{G4|oJzrm@QGgv zwLYs_e%i>~-g7Zt>egiMeB##31e_~XdJ}0a?p!J~a5xVB7i0Gn97?pU3plo&tk||~ zJ6W-9+qP|+E4FRhw(XPsaBkJTwI6Oj%&x9}?(XU_#{9okW#~qbxXG0zX#ZD*@g@X0 zSPvl!9s|$oh(8D+ng*qUZ$bTU-d$lA4CyX#G+A3Iga~?8$geC|Q$Igs1aE83RE3Pf2)BU9eAPi`-ip%pY_HGabA!9r{tp^eMH5#b$j zHel^5-wqHa%L(~1OVjj)%qS_Ks7Od#BJh)L7ter}WnL@8C+Ose-GSwntp7dRzT%QCCZ?uL9+@|+B6p|)i;WJXFke<^Nx zl--HU6+gn!AxQB|$DK?S9*)j33eAD>CIrDh{i8&%TCshOYIx=(IlmgJ28#G5r1_|_ zh1mm8bEw4ve~wQ0J>Xyk8RG65RhVhXB>i9`$bEoqzxkDuyyxJs+GlKhYF`FbC$ekl z%`UKS^x=f@@BG^$dg)@(9DR-5%Gj`#X`pfMTWEYTx-48^DKS5QbXx+)zO%+6;i0Rd zlWVzQ{O8(BcNt6dG8QVCgr-qP;y|+XTLD!(xaK?_*58G>k0VB1?Ft{qww;n5t!W1Y zLf;H=inNFJB~k!DB7fiLF~&UM&&lVESNyYFlr(Ayo9y$GQ|S8bC=G9y^1bO(*RsX=m_|=al2B8cI@t^;no1K| z^DA;rEt_q3IUT=zD9z9UK5UyR9d;dHITEHGrfcl;w?ZZr9qeqXHx#<3)$@e2=9Lu~ zVRtjUG~IOVS#d&_Ik}2hY>bZ{Ly$$qi*O4TsP2xs{{{kXV~-iQboUS$KdM0GI#}Ev zd%ITLNv4KqvqL(~=9oGfbqeRGm6g{fAn4y^~}4=ZU> z@(Zm9#W^xs9>NJ8E%U4Po|(c)m(<{q)HhBF2oHnEpq9Z3)9v`8!>F`IH#7y}oQx{HfbW9eP{kQSz(*R zF8oAxJ(@qf^88-U$8f2}$;5(H=5RY^fm&~Bi`5N8$!0#IPO%08e@Y@SzdkI`Zy2)5 z!E%SDocNmMr*1|F9frE5-BPY!Q$nM^y-n$BUKyp^TBMf+66^W zaN`FlXy8VmS;L-zucotr2uJluV+nJtW){GAP5y${(Bgw&s|gTWl_lM};S&4{E~gNY>DN)+A@0)T(R1 zc2yjW=kX4LYf(t+uw|ad-buq^&#k4ChTba{8Cg6L1Bv=3260a61(!13+4oh_jY*@P zfZgxMMA$5rgFx|(0Xj+o;WXXM@B!D(@GD#H*4JF+VM` zSG{EJz?D%Zpm&4a9nRZniv!(KeBEq%3Ob=pTRZ= znH&kR%ZOp$mERM5s*JF18%`+A_o?ew6fbuY(2`vB&ybg+aL-V;8CvkW@$)whxEmcZ z6MO}nvUSAR5bKj9W>z~KPyS>3wJ@QHKq$o@s!S(BfOl|<=9N`EfX7k>+pYW#raxhPlSd53)IEITI*TxiOgTnRr5y0 z6trC(d1;Y0w=Ci|8zl>pP#*G9E{8^BGynG;D{>4hW=O(;0*a8~cRbQHM_A=YAS(v| zR2i(~I4)TPL$#HGY~tIjNaG7lR`ei%SMWFZ?e)1O$80y84U!4RXR3o~UJ0Pf=>gG1 zWTP@^ynrc%2%2>xd}Kmq5$jRpz(WL81w+0 z)2u>mhi#?%QkRGhrjb);MP(-%IAfs;aDL{_etlADto)t(1bT-+El&fm-GpOP*k?=G zEr%xKh&2iYel(5zf`pD77W?7hm~nt*_2Rc&MxvEMYurD z316|QK&HiE5-z4O!+VV=&J!iC&3(> zVlacg@Cz!qq6xvEfV5Wq|n2uTIlfI8eSgjhxt zRjD-Vu4^ca*tn3$ZLrjrah>!{kYu46*VRkXxjCI_`4_p9b^W7M2>zBGIiion6#^De zH>DeZT>82Tc#}ZY=>R9Y0<=#ABa&J149~!Z-9OO-b~7=soMpk$WJTGl4a}7_=a%h# zQi&{k9+IE?m3s?8up@Sq{&bP2A5SL_CvdTBN7{qBf8L746Jtn$ow7}poKFTlKUBl^ zinnsy>8PA-799eNv`d?bA=+k~5wQ?w=kUdweIN|-3x+Af%Fjqxt zC)pm}H-SYa%MO2Oz9T><85wr^nJQ?Fham55nKAW?mEjQE#A!BRE%5L4C28Xk1w#zO zdd5zQz{oYN^L;B`U0t5vHNG$n@VI?@tbhr2(9vWp!hK12J_-w{gtp|};$Smdqx=0@ zXE}A(;Ip2N2n~d7Xlr9Bj@@d&?Zh!6Z!&$|n9C?M^tkM9v5otrMUS=KXv7nSqs@kQ zcNTjZB<#x#NA=_Mw#~IX4}R0Lzr7h7zvxE<{^Kp?)2m@Ww^uebtXR1xK1)&S&@h!! zF}lQwZP0E*L0RAc*g0i=GhLt#w~91GpwfFdeD;a69TE!?5}s|Y=1KJepGN2O?e=ct zHi_!Oe@HuxA(Zh{$;9)Lo&y7q?ajPt<>*wE&yu)vOF{h{y=#ubZZLZf$a}%u3jt*o z1ous>M?>s>b$qsTdjQ;-m0%`M;~WfH^v?8?KkKwrx1B?>tYsF#i>6EfgWTLNC#0S) zn^;GSPQcI{(b%Y>oZj1$%rzpVx(p#{M?YTMqg&!BTff%NkB)w4srTHxvFoHU=VTw1 z(S`&{r&ojB@oY-eP=GymFL@XX*tfm^Ef1eSPW{GfP!A8=#I6}fsuhtnR~nFInd2PX zhkoSO2J0bXqS4^K-|wv}a=Zw+{+C$UP3PYzMv^b1z<`G+E@jjTGb6qS_u&URn83M?9iyzOS=QC#GM3CNXYw8_7O_v! zz>pUdq%diLK|PFqi`r!w$>Ij}Rd$gw1sFS3Hl-YyG%X&=_B-U{E%BC?ZNDH_fxzIR zv1J`&f?9f!;PAii=@3kM<&`HZ{4`}J+h?#d>{&MKh08+}`kgq1Bvw|5L!Z0{Y>dp? zwW)PehkJtC8!1F0ZIw7~y3*!1c%eMCm7^1YgJFpNz!chQ22_l(LQ1XrE#r`b|AFOC z1{z`R9nH0OIjCnPiumO2x&;V%L-+*-AQXPN073Z0o(nQS06{{QX+%8RW z9@a!0HhE}i1UM-fPaPuEi%SkNvW_Uj#N1;~pB!j~4{hu@QQ!arELF1Y1k#sG_;MO1 zvll4>dKm2FxI4?OYD>kZ2A6tYVEkt{(Da$vc?Jgl;xFaWx^$o*DO$0=1541c_8PJo z(LSq3IT6vVW1Qh4!=2+1J|*$cdTL-Psh z>~<*N%(?Rq=A}M1o%|F~$~!g+r){NIc6Jd9GH-+2rKTG4`SJbe&F+;`o_j&N)qtLA zU&7j%_BS^AkxcaVi}h8G0@@5k3|vMPaCapT83Fg2Shq}xETeG=f*tc=6#pA1xt%bY z0DM&}tfKBE(2{Vc?YxF2{bsChUf!V)S5!d^zm$b4+NMQ4J{ME1akU>z2;D&4X}YR7 z3&vLFFBQJh+Ok-NabM1In=~5?G{20b=NN|xiC0WR_71U~7CD+TZwF04*Nrhg`T$jv z4pn)}RlqXV*b|<JUF8V1tM(kPiw7Tn7c zShD>?u`6kx3rkwx3s|{3sw6}W>K%i%ET7KJDS;K1p;_b$ooh3KLsGt&3s-o9!mYi? zD+zQdq@OK%ZbIk$Gv%eq`%R-pbi40)4Iq*d5E|hWR)-Av9G<^#5rT}0;OQGD6 z;%qH0IiY+cGQjs7cjIVkoLRy=IInAM#9fL<8hwSebRwq;<+s7%X%iICJp@=2XFWO3 zNnUp**GCu~Onr)B3Vhgorli)oDm~^H&Yo}1x`)Ul-@e+a2=s|19wLI?iRzd^xIWn_nRx$ue-rj zm9!p;OEnQpL+~uY+2fUDvUPGk_qu33)v}q2`ShUDxK|)OZ{M+ zt?Ne8cHvv$019~*Cw{!QeLC7!Q{I6nH$9?2>%Wg`qNcgU6!%+Pj@M#uTdaOorTixZ zKgeBINn(IviEzu13Dq88FDyFBwiSJ*dZm7O!wLat(NnzC9n@WlxX>jQEaCSp5YNTf z=E&c1mvwbZR%oGzj|U+uh#f38G5XrlAKn?M)Q!2RAYLOM9Ol+QQW(aeOSj03pzBnQ zb0(6ajcq0)5EL~l7S#(|+=SW%iUSVa{lL=Yfr(oV9o=pv_ao?u2B<`p7go_7r7kIg z>>~EyyA+Zr$#JH|nNA*-6xicRJtIeEHy zuSj0+pW@kTUTYS_7~ZH;(s&+Uut69vgy=j`1@P9DRk|St<%E$E3!mue?((#b^R>IO zFY|1zd!-QXC{I05RQ5hboQKY&$9tm0?#60XbF-x_HBL)Es5>3Pnz(Mv<&BIZ-)BwEYLJYUF% z_otdVSU7!ZVa9qp4{iF1dSig!zIAUx95EJCjL31^DQ0JN6Bj$sBfUAz~1EX%A0Z2YdpzWB3ijK9d# zx?3r>m$$UvlUafy5ZcDDX>!f)pX{XqRQ>o&bZyQOH`ewIF2D|Ur#ku`Q?_7v<+Y`6 zqu|wT`6%Gs4O_+v#;JZ>Tc1?~09Xi-SzCxAmp&t6=NntLb_NMz`Na=4M@fUCczj*h zVx-!(v%j|g%fU|T!Xc^g0UC&apxn$)WDi)Ai@Q1>EiBtCr6nB;z0G*&AC24IZY(m` zQ2-cHWr2R^rg%;|nR!}Bh?4mlW8sJ(A(b} zZ+U8|{-a5EQ{Iy(G4gqhM+kcZf=V+AzaZsb`XH&+TTTRwq3i}=NkR&w&UmFlxE^EX z;wOdMauu~vc#2Oaj=fROz=ICtC4pH=s2Z&E;RF{7)s(^y*{!9v8Yy1p)i7B+w0IH- zXfr%leIwGWB7X0KXJB{BM8o1zV#AQwy&&Seg_G){Bilth4{AKor)d%FLe@cE#S;`l z`rxH$<1=r)V;o)L3)1=gyv^yL>-;C#Gs`bYU&p>gl+`-Qy=W0>)QAyE5>#sGQ>Ll~ zdeQ#P;}PN5ov8HEG*|S60+M@{f+3OWSmGW2qk+V?JhwePiE4F!g+vv|dQYpD)B1G; za3Tjp!jg2VUP}g}PWHUQD$FJPscFyfBld^iHFBb!IMK-_)emWXPD^9nGCh)#S5q}- z@_g1wppLEd9yW_faq4g3{1mQR!|?L@bUdc@r1|Egk4M=u^9T@dl#3-3PRbHU0HD2C zP4CsMI27rKnZyDsABheU$Gfnjf!IXFQme{JmyHgF#n@K4WrZ7_8m5H9rIsB-ek0S* z7z@K~6*b{f2Fh&Qn}Q?$ zDeUy^-!fM7EEYUuOb=IjZd{VoZOlG|3gfr2+N@hD*Dqd|fO3HrM%s$K*ry{uz^YN= z>P?!!#&zTEibvLbpyRMV8g=d1utvhQZxz1I9@09!1k~o<@$ZJqN6A_ha^LV^TWT5O zbz|$C04zdEO)!~yQ-OXWCBW}E01IWqzOG~zYPeZ_;7ojcQ?LlY##f7vc03Nm3$-w@ zg}%y7j}WiCUNVK`4)ixb@WpN&x1DDZC#o!KL7au_Ri4s;cSuvL!YZXt9ai*VME*rp zQWX5|O&_r223g%6C5!b{(_3bX4QCA!5TMO&pSyc5VZ~jr?zN$_=_Ba+HmdiM^mPNr z)uAKak*)`od$W@--EY&Rlcnu`;9~|2Ip1$*uJBXA7Kg650Z7a)t>;`9y!t4es1GbFKCMieSBJF?4IT5Q>nDq9%52zXQj8MKuNTxMg1t%;^)P zl9QQoZhN4vpZl~B{0k+s*ScL`$V*x}FrToi$(GqMXCAbS_!j!Nnw_7@_(xfV1d>Z% zDbUnG*22X=BB$`P->n%<2^*%VBdX@0l}=J9x@Hp^#KLz!+Q0FA2F^2t8NJee6HGNp5edi%Xr**K{ssh!GB+B6Pa;yAisvvO5-lJBNW2a0 zuKYH-ctj-V72A38+8|k0nC))A(&K8;Q5U6(N}1Xdo28&l|K{?z*@^sz(PQVNoZ~CX z#}^{meK0^Kysn-jNlB`5D)RiJtqQTJP~5^_5aJn>sacm}_RLr(`%e?Ax}+HyG%|`6 zp~#h7BS%XO8S_IP>r;Ue{b)OU@I?1XhJN50k(rZ!tOmP6Rb&C(tIqL~RGvG9z*4mh zrqd2srAXL*bIQBP+IKkcQ-51c<3Jj;oh30!Pz&cdr`(LRBe=OSzL40@x40FXhF<{{ z@Nr(;Wt@Cnd-o)9jgK{A=6Iou5053+v+K5&n5jJw*ztKKKNwlD#_PDM77mSPlbWT| zg3e&Jsts$0XDbvuIsT^p)_rJ{ZpM=VO1R1pgFrr52|ZQ8a$DCYCviM@CrJVLWsR3hm9YQAVmdSp2* z7mz;}b8D5n=ftlTMA_#iipyugp)a#QGCwB+^jX{-lzc$^gFnApz)7;JI%!vVGHHxM z<}o%6VhA;x%o!PA{`&BxQg;DxV7&p9QueMJ7IWscx>7nY4Rb$J^6&xfO1n;dCt5Lk zj43iW8?8RndBv0-casEq`o!dIxCdH$`~VJJjQ}O>FR?(=d{KaH>S3J_k%Fn zK9Xe5Z(cDY3Chq&0RS?m{;XcyQb!p!8;`3?N}iRBr7pTa?9rkg=9&8ek+&ZlFM>c} zEHEDxDlqPYCEzj;p~=lw^ah6uZLuubT)5vRMIu4sue_Q+oBVW|6$wP`UeUF&?8nhSoMlk>P?EeVR(|x5`(cpHC;w#l3%b?%xs7iRdj_?Pf{^JErX7L|&@xC^jH}9Zw+v(w9OSoew zk(?tG4h5LnkLh05!c&Qed?<>l`a@{_>EA!1_cqppVPD7xOhj+yeNy#l@NRyge7hSO z!V^$?baiH!l-H8aDOX3*TM?cxuO#%mCAL)o^Gd5Ei3j>!uEw?ei(&gE4qX>-&>i0A zly5>`RjH?*$=;ukT+^hcFFvv}Dr2q5{enFn7C>+tDPZq;Q?<31xz&wQX8AVRAb-yE zpU*G^qBsPsjNJjRc5tB#(!;XaHmCST5GgEOlTE58(ly13?1>3?ZUD~>@oW^#;R%`G zEgvq&`gS-e>`gsvubGSGgW!Ei@nv#y%N(Mm#!KOw$Qt>3$FGLAg}+ynzUHk0Kjrl` z@fWbied^KXePXuqGkb9H?lNZ^$UK6#8^LI`ZEeb_`i@|%ZEYBM`#}MPD?vAt-g6V1 zzY*n-Oq>AW4$Q3)De!3dz*utYcc8XHDFv>=-l^+|54da5R|3hJL=hJ#q zhsVnxq8bA4cT~x!iiBC)Q&}VV;J$$i(82v`hZYAqdQh$E+O}BymL+TAr zFrZa2ys*H8r8^b{g-TPI>rV{8Ct&kUp6y?2Gb_@A2=u{0ru(wGlEy&Lk1TmS8VC&N zTla{KTrhA;Fv2KAVsEGK4TRe(4^pqm%(P)nuwriAW)2d^@NcrGBMVk*=y7l`G~Pb6 zs_mFtnrUi@&E;EQXmV5}4bYa7xh1)`Yyk7#b(kR{ZEAWh8%S!`8}j{@=GS^5m7EA{_(-_05(V&Wso9dEk8nSu?#4A*DkY_~OTy;91#`6Wc9SW!_f^YT<14yERr zzAr(;63<#Ca2>?@6^0Xd9unq_A};oEK4KiAIo~SIz26p?-@T-%@|=)IT-hnDo(a00q>N$`XSUuO1E99`7a%O?XGFFg#;*3cz^ zs;^~`$#f+3R>qZh7O8GqkgIFhtWYB4-?B#O8eV7j&&g+}v;eq(#HVM5wyNvECt#q% zVst99!3vy7-Qj}h+v9W?J+|f4AJGb*Y3wQhuAETg$Md=sP^^pe3R#r;Tz3%bW(8Q= zJ{}^T$s?V5+^cIPT_!4Cs5z;?fc2Do$kALPgwyy5w>H7g15(0v4+rVK`k-zM)wZ)3 z=f|EDpsexbr}VwXLBZojtY?R}q-b}Gsv<@9<~uEt*`qY14%C+c{&T0)lyUs$WPEv3 zVG*f&14oGr1YsPqX)eEEgCLWNqU#>{*3}-oH58NacIKzA4)zyI5VJJ5i}oTtYUXZb zsbN;rZWG$-J+F#kcik7OS`oBOf&4g1jD{S4-S6ucc%hK31T(Vztf*gWO{^ffDdjA4 zp^s?f@W|9I#o6F0W$`etJ5oVG7CyWYSJoXbgN+SDJ0M;JYg2k{?*2hkv$sck)VjMB z=90Zjr{)CNl<)7GFhCuyToj4^5f{@M%2i8d)L-TlC|I7RhpM%))Z>PfCT!(;#`O09 zm^u5@go58mqeAf}Oe*Z+T;7zv1zkuqrF_Tb6z*0?A9oBOJ-d|+C*j7SvTGb zb13Itk6B6x5AHQf!g=`ZVMOH--} zXUeEwlO}`QjcQ-ZPq1Dv%AYL-@qTO(ni=x*`irLUlR(OG1nz~L!%nuw-MWFn@6ncX z!+y7WAm%s{flMqH6Q57Y6E6sHowjr-dfa@k!j5^e*`6d{&^`sD<=1Gaf)8D_I>xSn zfluqUc2ZfxpH9yI44*~UI^fdeaN;M4xZ_+xEjFToZ{@wk+R9CHvFTyC?SarheF&Am zc~&T!aFC!Jbnq_1EbY6nxKI-58_;zNmZnC*0hmX|fOeXgT$Is-^yjR@mugrUKQ!7% zPCdk3H?|R-p>`D_#`Rr{G^8G&o^RTskFN&QCcgn>=-uH=l7GX^h62**?VbEHJ+d7f zY?gSiaf=VAKrpgB0CEZ5$d&vl;zR4;^_08LOO7b8#n1YEj^2mhl@7Sj>2eU3qD-Ap zt-Rc0{0_fTFw}+V2iB^s#g)|z=!VRCcKLh+@*l?&#WSj%=lwh?7K(iMIVet(V1hmg z#p1W{JVT)u75!D6t}US_Y!Fw0UZI#7El}gu)@dZfk9u5esKiuqI#drW3IRmicF`pj zve71I?OBD4^=Zx=7NJ@P^VD8RtBJe7ADu)ZOP_%~aZ)#VK_ouaAdn6eUcDL4I|oeS zyp+^kh1`G5LtWP$sI3M#@$Oe%ru4G#exm>8<%gq}{CPQh-%V=}s3yMEE5gL}igX|E zLjo0?y%#t9e)73=ac@Z-INk``_Whf0VQP@ch`D(H)+wZwE4wN}-09&B*c@Us(ayat zoV!9#|IsSy({2#F=*RoDj_6@Eo?c8g;`0QM)p8NgblXK#At2h-(oP|&uugP=X|5E_ zW8re!%S3g%+N2=KqkItQ{cNhJUxjI*%%6`%j|%dB@Nv>m*SK>AK#_D%@y)lH}@-sUwT5fj2C&aY0U`LHC)5@%E=cdnO_zmCx?X!$TkZ<(J_r#NKg9o zt*Y(A<$+cO8$ofmMuU)S1ZR&77;;@d?ePnaXYpeMTxGigj6)c`z6kDoIgC9c}651XQUWpl9sL=Et?R5Pv^1 zDM;sqsD0cAzYQUoKnj3bo_uH>1KF1yk zIoaqATaYX!+m&@{M^XlC_Cg|5;54G#E%9_&BHTxV6K zG7I(-A55lDa;Ar&Z2S{l4o!2G1SI*YZt_oLO?g5eNO{09DDJ0}k}+3Tv;ferrjj;n zEnHLhsRisx!qa}&j^X2X>m5bI8$?;E-{x6sx8vRCHwES1K%@9bL*Yhc*LSSFw7SE_ z*_q4(N{JE&)lnq9WxJb>$5JxFIiJe#QS-=Cvp}KtDFcq3!42y?D7^{sejOU&*!@MI zB5#hNFkQ?ci+SfgT`gY`ZxN+q5_%Lo_M~`F=CQtA5c0vR-R;9{3w_hIDUE8l*zsr! zy9|}ggxU#ZOiti2z_v5DY0dN6gcWe^bFLbK_8Ww_lkX&kSzpza^=58BOIIEFMw>aA z%qX*PxtjJwNq$mGHac9@z0L2esQ%MdSZ#9%>vKi+Us!*t6TeNH-p^Mxf7oID zEkW9}$NKeXQg*Sh7KlJKxkmJAow6>%G)?HqX+rxMsSlt)*T686I^0EZ7E*fz?0JR@ zOwuucTtk^T%`BWOKGo`aaqSonpKPIG9_a;r#B!0kql zKt2?hEGgc&xrt70ha1hBL>n*!#`k_US=c`slLS9iQv82@f8^Up>m?vwe$Ge%X4}ij zD*FP9*-3Es*BZ`CLA4s3)o}+G9)2?@oi{flJjltFSjqTlzIwx<1XCW){w;!@ZTE1x zw>Z2_e`E^HRhsVhwLv=#)4hJdPm!DXaLG&0tOZMF>ffV&k;V>n|tB&c418`|Mo-CIU>sQ`T1UB-x$z-XT{&fbj zQ|;VJDnVTWAhYd&?`R}w79||eSyMOOFXk7bN}cjGe=#lbcxd0HPRy729q+w-T2b7X z@BJ$ytd5x=aiAe$2KUz6=bG)vr-b*c&yF(|xJ|Bh6949!)}V!51f7JQzwu{mW~G$$ zD41`-IxZo%R8@PWaX5m{UGyPamQtWg9E_3E)S$~hV6FQM9r9~)ULv}19;Jp%ch^HF z|L#xhK50!-&AOF3;#%G@lMN#do5f{Xh;Dgk$f?Yd0@oaHzcw0qrZIF+-kDK_hatJl z&%(f5pJ`YU3~lo5hJiWnW|oFrQ7LX-P(-3pyOHQpx6rcZ8PQMp0D#H1u>Obb<+PDVSh!dqmy?n`<}MX7eup2_ zMk86Wo~|!&zoE6K(Ay%&jkAp<`|?771evhaFamxumI=77TOIQpxLqbBHCOe-f|D0P z;A7bjJs-F+LAlN=88AL^VN_q+kkM9*iOl1&dFjhJ^!I`$!pW-@2e4xmTj?$PHHLpb zj&7plG%!315XSZc&bPmol$)hQd!X4ymQMcHJcCT9lF}q_=*6l`sry z+&c9k2itPc#Y>hpqIDY!MAz|HCJ)P&{qt0~h%2I{<0NMYThe?gH?dI831XRXoe|a~ zdx}34zpmRr1b}2TAc*dg{oI;Ej-BH1XX0VmpZlT<5XbFhWQ)Y(*E}DVVsBe02jY`{`zZn&E(w$W^=(%ofNegfwf{VpaA@KX z4l9ikCilCY!?2HE+wmrFf$uINE7v^WPDdRNR`;|fh>;a^ZrtL0qN zkbOaGGgWB5Uo_I}kr8F&Zoa{sFvc2hzg@cSU2iGtB0FPO_}2sEc~a4}uQmn0MG6Rf28&m&BUqn`Y7fnN3VdaQ0y9xq3?;9E z&sPA>vHd99gjX8_nCWM9SQeUo#W6D$mKRGdFwOn}g29}c8;b*E|j*8Qf`rYhTVYXwONL6|{-z!hCEu54n9EB_=mU9DKnoxCS zPG!ozjbI|1!twh^W7qABsBnHC&dh59JRR?ZE34BNL}YBBH>6&NT55v}QF3i~UKvC$ z6zrC@n=x#wd70QbcW%gdzQDn}WFcJTbd6BrXVqx1f(0@Tjm@LyO}jV;Al?ejdy2oe z#R)A3_Udg)HJA1=bz@fsCh-o0U~lXY|I5|`(zJME1Pj|wwUYb@xt?=`LlIovfvx!A zyLU61O7kmieOqQB1A3tsD%W17T#=+%7thd4B`mq?9-<@uHxacDPpr_K3G3C}RUH8} zNI_+?SoFbra$Oy3$S;KShQY**?p3XqA6Mu(sQN8+F5=HG$-?I_85U1yrX-FgfJe4o zzr$G4+^WJ@FB#139Av^)v?=tRB`{@;ig+p#Ob6|aE+Be!W0QNgF7pa&H_EUHOep3y z^O07quaIv!4m1;R)!HGsFhUdEJuq2eQJL&LPZA4^vQELLkLc@fZm7emw_=7s9^AQa zyjk7{6t0t-3hpYHk5>7<_8YGd)xMj9of*yUd;>^pY2CUCh59(tScABMRWG33Dt1;d zU&zwX&2|3E{Qxz zmeO{1NFnPar(V}*&?4MtIsoTOY!Bk59sL1PmmylTQ`<7jJak*qM$%TdyfVE0Q2q+_ z7Vx%1qK9=t88)pqF8@`kFU8szh;smZkuz-Y#<*5>v=P1sPB~}`>T@P$PYj{Es!M@H zCqPfjx@YcCpBrsmSjX04DO7lhv_&~#Ie*yK`g9HWtkcVpA$< zD+paBblISnT$O7>R4%Y#TlTGRj@K+%9aPW=0a$&?^TJ-#>bn>tlm|%%BHr=aI13i8 zO8^|9(9}+lv-R+d1z^LV5ryE83OHq-$E~G36MOMEfoaaF1pn^Od_m3Z5({Ipb5>IQ zTH&DbCReh?jOqiHuou?mkxr-|RLqe`Qw=0d1+aOdL-|di|9p>xtq9NUtm^=P#)3Y` z{0<9{ffz?6ac5VdA_P{^wT3J?0Ln(_%Q1Y9j5@=A^lKsFt_Uq9BuQE`#J4=q%sP+M z>@$%&J%uI}X6lZ22My^_Xkrix%0v?vSTxWmF5QL`k#z02##VfvY>5N9n_Ykm<%zT2R%*8pA&FJT; z*-?D^Z}+6Nn*prfna?m4&jh2FIMAFnHN77EpBwNjs?mc`HpHxOWQ5s3n;sQhA?ves zYXk|!w2lDcL|xL@tKw5nt?+}HB@NL7n4EUrKyIT7YyPg0mHB=o*kdWGq))ob4~pUa z(>(*o0MeqghvT}M|6P9Vf{41g|L5e?YHK=+?_mXicg3!LSlR-j;gfraAFi_iK z1}w|L^G|pg=mx&iJto1B14zzlI-zSiZHCe6kUU!s)#mn!Nw^w4z;=jB-t*C2vU`4(f&1Ha z-PNZ@Ip?*<=}9s3U-<#nRsEOjQfecS)CIqcEWLHV$3a||ev;27xR&Rb#hC-$fem!{A6o%)cPsvYo$6k*xS;2Hsk@472{4(>N|OXrwdUL4(bqTdX#M zrHwy=U{{CG#nb%dzAkiEsh(;dwng5yV&)DlX(@e?9KwH_cd*cB12K03yqY*jDzGfF z`(!2u;jJB0W(UbAv2p}5(>oemhhAG2r2uhufCtDVboOu6yCg$?WhY*SJ>bs6%SI5v z%__EFy16@&rmm7A28138!Z-b(f^%B<12xps^gRud*leKinoYyK8W66g8n_xaFyQGVFYpu!z=L# z@sVE0xDvv;d8mzb%wY6$4D|E^@d;3Cz_8d;)>Xl<*#21ntYS=lS@8#AIXr&h z{{Fvp0erAVuytSdXuyyf0L;8X|N2UrI7EK^TlBaVd%GeQX1iBA;A)wvYX2lW3PIN9 zn&;yZlNjISS4pW4(_+5004D$m;6hv0X}Fz9K(OUu00~Y^PQR+?htN4}etkn&dXNlE zwG03&X@GHlXTOMqumU80X$4sko$!QfLwyo5P0c?aKMRCKMOB2NzzAq@f6)K|{+a_A zP)d&b>LmLwee-eu2Qe}hP6AD0ITXP-``HBcL%hW?yV3g&eeP+D_a+Da z6k8Xo2=9ts(ggv4ViFV6l=bj1H8tf_A_EuW{Nt&_sX5W}NRgS&1(0QZ*#pR1^UN=` zs~c=z&-zVXT8Me83;lTp!N0xi}wWQ z>tSN^l`133uOg@{ERnAAZg^W|ZfwO{VJLHQy8o*BnEM10RLlW*3G-{^z?lFHjKoE# z{efOnQ}-@&@%vEX)qjZPrvle*X;O7og3U-Upnj^2LNydz>iME^v);jJ2i&Kbb$9D2FSf-ZEXce3YG%LFXxE7I|4er z)wj!quxoY$^62!_agYlU6A!CrWpnt-u#dL^a$UPbQYB*rfc>i&k^e_A%8NwDzshZ2L}g$-q5Ap6$Aa2x)xje2?L#_lB5uqtWfxIRQZlTtYfWbU~ORq zrLX%31ao->tF?#03+5Ld47xl0$}lv{pV~tT!Y^lPeefC&^v~Jh5hQJOb>Qoa5d4qd z_HOJM-QeKhC!oyL&*W&2H8wVYN8wK>1||l;AY(nfH$Rc1ClMJH@&x?x z&!9KE^fwrv+vGQxI>6(xZ{Q_>$3#ybJgCZ#e-s{6)ejgS%IYVq55n5_f0m!$h2s;p z9_SS3_fEv#Bin1=#V6kAW8X&$m%;n4^B44YgZaI$Y(-Bq;ec=ZtFPFruG-k#_VFM2 zsm<4es|#BKMzEOYV_FRuypOQEf$zJAn;xfc0si+~qFvjyfB;t7>qcrk$VO>A977}H zZ#VtV@$twP`I65p%6So;sQZ^tA+KYsK)#Le-7Xhc;%5eFst@>KC}Crn}r@GbKp zQyu3qwXo#IGdL~ky)0`&d|iLrNI6b*|L8{c(iqi(TIYC9bAXVe4N*(MqeWXo&~F@I zI!rpP{{cQg!M{Wif$?lrIu*ZknPs1{E+Wb!$?QChV&>WOw%9g&fXeu>5JyM%VieXOd%k* z>*cEG5}D`WU13vpAdrTni1qrGdri{>eN4BK5f1%3{pp6--=03v%Xb{S&~29Piq<1I zJ#&%<^3+#>J+Cowr1G11^9C8XEX*NSBRa z1-Z+G#C>{;0RQ>P4zbP=Qvy{t66R55nmn%-zyMKPvTpE=<>05%>D1im)dSPr#G+9` zbuL*6qK_jLFc%N1l%K#7e39mvvxZlkeoAJ|+jOVDvLRm{*%OEMZesk0@&!E6JGP?5 zFNAt^Su3>R%~7QlK9S5VRIvbh#isu8mLmQqn;4@+v}E~*3!+oTg>}NkqmsdspHWkW zOceC2u?&QeS=h@sH*C+*y?N|LlGSxBF84@ekoLj}MPeXC(eF!@jxJ#y_G4@?!?0~~ znX1J8G{t)MkW1D>#_NK}sqVjcC<`ve5^1vhjODgwMryTFQWibTyQseWmXzVc z{(@XA$MUNlX>u2D3t^)BZW&e)Vrn87t+EgzoZ^AXzOfyd{sOj7Cm{3H#k$B%~YRq)-NdI1k*X$zn-!^C8&LZXF z2p|?~ruR~XH&%8b@9XRIpQtZkiBWZeW{%dYduX8lY$dF(?T6BEH3 ziOqaZ`2vS}PbB6wH+o1!kSceSlA;T9&Ry2>M3orw7>C`^q zqQ0=2&r|wF(=D@utsKuktOfQ5s;+<7V>~{GOlR-Ty!12|VuCx461(<*59zj1C5S6P zE-<(-tu#BHr9o+cy9_>FflyshVO-+JYPP3HG3f}-R7iW`!)?46BmXvwA#-CTL6fH@ zK#dHR{(_R6a#FK}yCZP*Q)BIGK}l|xso;rS2kaEVM3$F--j>MbuLE(pdU!*>#7BW0 zI32oQiAT5z37CC}+`akv7z`$~gh_9K6jDrtXFA%Fu@eK^(()|xHKX~_8%ZV&&cv}HuSuoU7(GE3zJ7r!x?xerR{taxZcQbhaV984j;~M| zB3eTANFW@?N7^>z%pEpeg6x3F-QNP|o6HD#v!(T@1bwukj!G%wv0D^kIl!zkG$5PZ ze5 zEZ?@}YNQ*R`k{s6CAxE6S+Qm^KOz)?R(4g14OJrU`FStVMXmjT#OR2K;gGfC7ql|_ ziT0PC18jbxJ}=2iB8PNmSc#2F1dd8iG#pO1OKmi9CeEA^MvTL%WfyU|N@nrj?JtX3 z&51{9=OPF2ErhIJ&F1lM2(MmE5*f+T7WVIqnfBcZ9)oi$`ho@g5=YrcbAy!8iuG-W z$18?@pAOPrzbA5r&5yTw#YeNdqkM++e$fU$p zb9~g-$=VnS9k1N{v`Ozs zRS*&hVGhf2Q&QS~o)NT#G!>`oKm%!Sf_`GwtFrluTjzf>s6nBA zLQCmZ$_>qiz`{HyM z$dn9ju&T|JfXjo^Vh53-u1zBM$+NICfllu7dd6~jbm8p!W)=KibBQe90l&sWZhAPH zSs7J_=cRLIOPLDJ<>XAZgOq?Q40jouj{niNH{?g-Z{52;6!RsjPt5j9-KHnyYgl-Q za}PHP$nwd}k1@&0z4dm!Pj5w%UcQX`FNOF8Z+!*FRp)hEqlK*@Hl%zWJC1rsPjcPw zW7{Hmy#BZ^!H0}WxKSmV#c~Zol%~v!&5y+gUr?oXd%N(lG|9xH7SSSZm=`&nCX0{{ zmFW&G?ej0f(4xL02@0t3e;tly^_%YQy>h(0P3W+&-uD{ggNV^)nDEM_iWn-y*8j|+49)}v}itHSjefA6Vjv-Vj)xr5> zRU6abcxQz+^#(*WvDfbg@Na4Wk<+J==f9YbM)FlvZU*Y5Y6%Qei~?lEuoWDTH2fKb z!0nGty+;rBR`gqj_Z9hT6S#+XIB%S=rse*4{LlrLpf|!#dWWwij&X5h5-s zXOl1Dpj29U+pDNM!J`QwJVCHeDe#5R>U**JI@~!$NEoRZlwI&3i;)Fepbr*+n3e4$ki@LpF6Q-&|{$qR6xO*15~4`~WN+$#AM2wybYw=ism(={Yf z+_kX;8`;5^qA{P=*3E#P&ICz!Bene4^?hLM%vbY%O$Qywh57f zIW}97q^yL5z?UUQTf;~;61m<1U&V38{gT$|n3j1}J|>RjT%Fu&wzY$! zUj%GurRMFKZ$Z>ltLMfwS+TJysje~PUIJR<83@>NTr<_9Ry5N92aA^fynL) zg}s3&Qmgp``&~(FFX3}XGKOkhxbDw*5h#6N>v4HT6E~1xc&2j0aFO_0aYEURpk+eD z1ZX*Wtz-a_?GT~^X73dCut6J`dYPrpI+ty1x2aQ4;d|1@5sEsS)-?XDG7lsOznN&n;evR)?-Kn*UgIOK5J;{th@Bhk|KQ{j^z8QdsEUUvb=k|nv*DO?$QbqE_#!ry%{;tm*}xAec?h|}Axo1`mfZg~W2IWbP+_I|FABYgeMX54qw z(n8x6n5Wlw;qneGc}}Y)M~{xyFw~47Eitc8-D18_qP>T|?yHYyGYJH9?$8e7{mB&3 zUm?MB*azMnhp_^((s&j&5BF9li)GP^j%bHx2N6~52Ki9$ZzLtplk!f*&dNDDExX-b z#8`x<-A@s(JR>xTleIqc-ObkOC#r)w0`6&62sOPMj)Ajp``)f%AsJ{^HFI7qEAy>x zl3ch4;R+igWNh1_&O2y$attACyfXR%BAU}WL5?O~x0pWUq;f+;SQdkf)VEf%cy^$} zgETn)vj7eHNll=5PkLa&6Zw|RW{A_-TPX3f-^{S$utbJ(gNw{#=r{71k-l-K52%z&m`zv#JYjr4O5Tj<}a+N?JQ z-mRYPfN~Dtzx@?O_M1n9%G{dhLd`i_f37D)2r-P{t<7!(BeHW zkJN0#_t0h5KA1ykFUq%*gIzB+tP3U%Nbq*eg z^iFMChx2YpdH4Pp4{QpT%$dUqD%S&bWu~3tOwFc&%rr0<1ld33231(1K89S*(PBz z|BCAux#g*)LJ*62^!?oxD!qPst%_J02Lc@Dwf6{l&K-_~A7(%oNZjb$AZTm_fkD5w z$c^_>%oq!XViQjf4P1j&?HQuX)CXF5xz4Y2Za!r`TjxIfi@}{a$@u%k`QIq*hH7dt z%fPdUe@~6#!ilSJx>3w0d52{r4u&Ofj808@q1FN{$`cwG`aq|du<(gvfIHNfRrO@b zV9>jT)J|G1GXLXaR5XjgH?iw&NJq82wtJZ(<^syc=>~_d_f?aiNlVAXVH_RhymF2^ z1jgw+@;HGpv9fK z=8YweQJu^dA*UUF5e7>~<`eUJUgq^t-^9t?(REO)CJB3c$IGr?>W)l4(~x~e=KU2K zs;;7^h;@>~yL-a}JUE~*Ww0RHZFb5?kh`b*5tOD+u$;mmZC!OKXMdP%W-6w}*gbyl z8eiv4JkZ($qb6p}26?INL`SobFs+4w$)g!qJQxLbh0^0Uk*SxpYi!18BC&jO>k-PJ zLnC<}9n1{9eA+j?Cg>HF={@1So5N2k$9*%ZKr8=LBwp%Af377}Z;N~svYtI~0fm63 zFgfbFJ~#x$Sn#`&yPTO)PKtw#-E+`B=+?^k>$SqIhS?owAasAwOEYBqZ;L9A9Zm#4 z)-$_+NIH+jW|R4wEhjuK#YnLB=n>%>mH4OVE~Q*66hB=kO!q@M8l}LT%4by+n`id^ zkVgZdwqQuMiEv&`=7z54s}qy$BV+@)Phj!p8rzdE+M<#@KGMd}Z?wHUZLATbu_?~|vhAz6< z>%P*QXLhT-Ajm?R1Ny9dwxakMXs_#(%v4iGnxRpK=%!GHv0>7~GnRhw@Zz(Ws*cm< znQ4>KzUt@xFb@WwcegLEn5G(SQtWVMt`f2oD+$|!7l97cR=#eDfEuN6;XK%(8NTFN z=eO1fzDn(jF&^)c=PT$qV-+CN^VN&8u}UXlP|n^e-wPk2bccLZJj!sy;e~6n9c6oy ztQ*p>XtNRCMV3ga*Uu?%W5j0D5_I3@*n|&wt)lYevWe3qr}oScdD>3m*Dj^1JxodQ z4viTKj3zKcPl+i;vSpnuW7aU11TT~sMqH5%b#2zP^WJ0m zL88V28p+fe*E3LTioPFviznhDgm$Ws*CeSJHhZeiZ(njn4Y)Tpm~|N7#57B9??pLM zF_mNz#5py(J8&J{p>GPMQ~T@2I02bTX`$)jIez)d6%pcjvE11+8EFL71=eu`DP=BYrr5>Iz2o)uC!St<>Vn6Z0I-e6 zvLEhC-*_ZRWI2aL7ImidBUYq$O?qE=SC4sTwUgdLizl*`#G|Ho@9Uwmu5~AWuy_uQ zPvHOR4lH0U(?MmcboHxewU8e4k_dsn!_ArC@ub0CPiN_4RqTz7siDdGgjF=To+93S z*ZZpAczfzHQ^%HyH3BXLqaJoHDi3SV51J)bM+_TOIA?FPNS!~E^^@661{6E(g*&8X zyIk)VdWn#;2yze$)AJ>LAnz&Sp?>&7IoSa__z2%X0}A$#B~qp5ON}mOpvpF*ux+Q8 z@u_PqGq_0@1gS!eYub0w`8KV?GcKMUYP#jY=rAA{qve9yVCI=~8aDExj5o zrLES^;qTpDj_t!g<5mQI8ucQ!@PA^H2O(JV6i0^nMjy|FKP(`cev!dgrM#RZl60j4 z+jC^YR1VV;zA=1Jgq2Eq&4n*aFVq(=b-l zsI6wSn)0`~f*lQu6n>L8RMEDO=?QxAY-B|m(e|dw04<43W;fF!zLC~tt&JEX1I(rI zA{ZZhEN))%jR9Lzn*d*cMTq-MeM{DbgQ^}60^N@Z8V7T)2E|{;{RQ@3{B}e7X4EnZ zf`@mXf?r$=ut2~5f{R0oV)b@4G%ec>elw=z((8s}^M?}20HYTmzupGe1_C!4XpJr3 zR&z4?6h4K$j^`3p4ue5x4YG3P3*<=p5=f zeooGqH5Sk4X-G_v=v)#osm%r-VL&wdOk-weH-ChmJ-M0t9e0s@+1kAGG6GHY$M=Ms z;Q5^6?#|}du*b0CQ3-uY9y>AuB>DXIF3~QzVhPSTB}=xl2&q;|Lr04KA_wb6mb=B{ zulAS(vsR;Q%A+LytcUe7$HmeJm#aU1=BK?~M@byC=hML9Jhdm-d`5k7%DUz>=;z0{n zzOvHfi~}|LS20ErRON~q_UIY*v|^|xST=$W5Dw4YJbk#^jHjamU&L!76Hwd6Y0L5= zODvCYEI~r-G?b}J6^qg5l?5zYB|)5E>o>OLGTDuAe$!W(z+%|pTats+M=$;U#W~wv zubi=JI<%#zZxLRU>#~IHFFY_ zT8qbUBgOPRv)q>0ST88rnp1v} z&4i>@ad?W&3yeX&E`8g@$P}^Wf-{Dv9ReFxZG1TXtyHv34!V80E9mEpLNVmD(JYFU zj?ZXaUooZU?`R9fVSG@lX5X#DAj?w)##8OE{CRvsqbtJ0Mh@xfMtpSc>PbW2zIjq@v5>Uu-jF(*7S`oihT{uxU7@$D!e_RL*L{?+ z?#Y4t;y@R!g8(Om1bK6qJ|CzHs6M7#k{P?c4X(XUd2vPpiFy%2-|2jxEBWoUd|x}2 zR$BbvI07RiE0rLDT$CY4MT%TnlkL@(CYas;@X-FDp4qokBh74l(*^G%>{X;lA?~V; z1hPuF`D?mxPF;wYbwc8rLINaFVaVlV5N5eAGA=YZ<)y*O1g{#*`OXddcEE*J`e+AG z&XtMgx{O3-)srdMJtN<*nf zAROt#(DzM3%m{%g&5Uq73+`xh!%>Y9_iqn8O`txJbl9jeto&n~cukDeg*e2f9+wu) z#w@O*@4i}I5GFL;ZpBm21j=I4)RG`q=i@9}sda0zPVF#Ddmwpvb)V#>0jpDcZLI6U zNtg4PCRqfNVf7PWAT<1!Vj{05jOPx=H(ex-8P3go&v)ZcUF_+2 zN?qwcIWueZ;~GmF+qqR6l}qGe(mLE1ddP+O{Uj5c@NxvbEMGbpIcBMTT~~VidfORW zQmG(LlB>^oOYS9wG9}MLE<)+6fjl;Y7*(NWNxsG9Y2+W+UiK+H6G%I*B_W>ocqP+G zIE(9v#(WM(T1`DakyB6@sS<(HW1p}tmj_s%v%Nk~4Zrpm_Za&ZzeyaSL?qm&tx+Iq z_Xl!peO)uKJRZsa1X_Q?tjY{~A+gk(h7PHT>DV_Zqc%B*OHoJ_qpTH1ElzAm$Wnkc zA+oJ}cb;S~6>%&lnX2(i2q)0zy||0*u%L)=Iz+VcKq1lMjy>b&Ie71OgO~t458dK# zrcKES$GS1-0bDsGoyG9UVd2gyJLmMrxE3xa)9 zqSYsQt7N0w8A2vHScAE!NEX$-LKf&nTxKMkWQMcxag0s;h zFE&&&T@pMEa&Sgn%N!n#_1z6Z()9;7m6C5}_a2|&n{M_tnsXsIJ|79}1)GZ9Dk#}0 zJ3Q%PVNn$HQrWF;*F&{c_cNb?BW+I`J{0rqZwPAB8+!icbe%!=>SUU&_l@!{z=I^; z5Hckjwdhb-!qkzBxeOcQ59CqSdD?PrS>pwg`vO<5c*y#s`o4GQ*;k+mol7hsj!9Qz zjUU~loX>OheSYU+k0e?hdP=EpyR!}Umu_nFldb-pQ0@XSRn!mo3`6jPT#NiibM+ET zoeXoQKM7Px2m7GC(}a^NPvwYA>5t&$FTK-t+Hn}2%e|}T6NI7zyZ9bS8IP_@LT!=vb9UvBCQ6@ z^K+BOMxBlbf|z%P&QUw)pGee4=+X1w(+8ESjkVKMk=@75?l|ddQ-lZ;-?@Z$lp1Ra zvD;*T1p9)10(UL;U&c3)&+c!kJWs6P&*g*7rArGe*Om*>N_IwmxOtN7VMv%6EC z(s)iFffoul?d)KcZ9VJN9Xf5dMd|3$(S{jOG%l>O<#dzwIg7?yrIlDRrNh>Owf|1p zo3rha+awXKyJ`Iit;~!g%$nk@zNYPE6-X2+1gi-qFM#iBESIVYk#*h@Bhu{$1Nez; zExT=m8PZr6H$Ds58Rm6FqvpE{e_j>8ma;)?brGIVrDO@x7Me|5Ir$3#32zGt8Kjn& zNy_)`Tf!E~9Lo9O#_fRseCW6OeT9-9j4r1n1Ly4g;uc3C1y#BEL+a;*+`E2VJUFl5 zSv)V;p<&+@J^Z&sFivB2@(n=KGg}>czvR z;46vgf(Ex)^Xqt-P7d)l@81r@aU`D3>k_`%)0ZJEQp~QH*E;f#rCk+@I*l)tU)LAu z-zkr)LNf#VVSNdo(mXL9?jQ(xKmWQVvZeDaF^NoO4dE5XJ#OSDK3i!|IB-EYFLbUf z>AtVH&1r%K_Y#$C0smYerK4eKGdIH7yx=v-MK%O|kt=#$Q!f-jpmvdlDhaOtX73Hx#cQ`pu68Y4~6FrDven6sCR#cqB<4N)2-ge@Um zkTaxhXc-L@@)ijKsV#Ba!3Q>99Mq13siN(%9%rbf;1*H@AWG|{bU?ysW6yDDpkSik z3Ryk0MR#K`gv5J9r3oY;S1kQ<;k7`Vzbsr)y-Sy(8`rXj*FM&AIpeg&8SO9Of^xFA zm?0Iu4w4l|xi9AihkicMIo?p{cDIvCrX9au>BY4h-{d8!K#D@Sr;YWdp!lJrlQ(^- zcy=X42E}{6MG+V>sW=YmvSW{SB8747>+MzmCXbSuVtZMM-FSkVsoZ{`!7b8q+t=2q zx~TTUuDX4j1ME2<6-NzRqrtLsIBhFhnVCN9@a50 zp4~(pxXC?$P(8900Zt1^XR&Jdpi?E<%lmFDub*jYYjYY(mPzb{L=H1sqW!uZ+#1Xs zAVuz!IiO5JyFsS$Lu9fc#uc#$lNs^r@}9wi3Q}={E%eLJOE5LS=}!2~V;uK}{eyJ5 zaC0a4H2Yos^|U+kb2;wdV<=ScA@fYOLh~P|FF2Prh4i%>E@*$Q8JA|B@5Ao;PlHmn zU=+z-JB+#ip#B!3>?^*s-l)c!FEsyn8a?(#Ow=ON1DQ9Q>&&!v9J+;=!Z9O|C1L!4 zyR^Ip-@{_H_8GO}Y)=w*@PI5^33HmU0OUMEa+>A6vf(pAbV9Jq3Q<{a{I^rHt}X04 zXH~|nYOhEF1Ox3(Z(asEVTR>u*AyNF#|~23t)(EZTXR>B>YiA&e-5x`JOJ7~r;) z+DisSdGD9t;7$DQ?v}lV^~Jbb^J~ln<*@~ZWiz%Vdl`bE0k?(@ep(?_C3?FbQK~cY zEQ&Rdl8XjvNzKcM8TVIMR;Q_4u@aLT<4gmx|G)(fDhDT8Dt?!mbM;27S|YUq1^iL* zJt?1en8d_fZ^PpwRx;`AC+Nsr^Luxuj>jKteskxT95vt@%`lbe(l*{gOo5F|DhiED zKVo#PX}dk%YzK>R&8%^{#TGi+cfihm{&d^Ui@3@|a(9R&;8@)KB6i&;L(B_kpA@{0 z5M87j=mH%Skp(B)m@w;8kJv&jnk}D~atwQ0_)T@%8iWw1G+3S9U^~ZHLl%p#Uv7oM zKi|_%<;B~4L`59bE*?iE$nmK$e3Q6tZZtDFL=CWY$woTDln3<%!QxRV>kW5c6{u#9%(ahWa(6Bko#>W-;H@XkCVF!NTL1`Jgu7QE4YNJ z{i>9pe0V!kK+8Yz+!J3tx994R1N-S9t@+o%3DW?@E#tc`i;g)yY$QRGi$ewD6nEov zG55qbfggTJ@1NqvTqU1|_k!E$MeaoP6oR_B^?8^*JP#g+UaEWsVwuQPQ$Bb1y)7ko z^L6Xj|0-zf`emyw&Q29bLGQZddvPW9b*DwG@cdWRiel_V7K0{%u#qdKi5edhFJvB2 zAquKX20f9)9e+p-UkAfaM=b4f|7-`=H*_vU-fDQ(>tv0^ex-ygfngVPB~k-X#;6<1 zGc5isJ7N(K5O+`@-tpD&^3Er)dw2bEc*DS%UXkj~EB2IH3iogr0$awuIAvro z=5(X*WOO6w8@S%vNnx3DZ>(K2st_hV!oi3Y>gXkYGLB6TpvQoT+SZoq0hyxf=Y=sg z{hN6n_9FP!6&russVfk@>Wl?R~En^r^#M!(%gwYQ5SW8B9#Nm*i8~()`Xd8Z#e-wY)rfp{WCBB7D%;^^`5< zY(&CwTj*IaZH-}q0yRKnad`9lF{Br>@@aYQ0>1|up`Pr_{i@( zbGZ<0%p3L&MHIgRajr~5rILjpbgNnRi(!(>@vVu@HPwgf8w)Igkn*a*_2m7BP{j*o z(v!!<9^4zG#J}zOYlgRC#<=nj-9}fSU{pV{ZI#FqB~jo$u&1%1Ii-?Ax}5kgs818X zZk%X2r%Y41gn2cn9Y_E0ft^Emt4#x&i6{^a-TOI3A*hzlBNt%^*%CW2^p0)+z(r{? zlaMb*0K#%fV22cY^=miF_Koz-yFFMRP87WcCHD(;C5oX*sN{2QPwJfKRI^~U8(WZM zI2Mz({&-vftGk3)7-G0r?~>{9v>CpEm5}_CO7Y!roYTc2pnXs@BDKUBTfGNnm2xW} zt{WTtt2qwX|N2gGgP>B%iUSHQ_5vZ>%4cEIz9T=u%+0*XvSV(95~h#jU(JUNHlBUf zvp$pl#r5z(j6%T>f<`V{Kn~Wra4FbAAnSHzRyHGq2=6lp9}jujl_@Jj^y7rbd)M< zf7(ZYInp93EM_>lXo@92$X{5MmXFfV46Tk}o>vd;Nv48b+mZ1;Ua(uA2>QUqq#A`6 zP+p3N>r|L%2AC1g?xJIkt7`ntpBfqU?kWwnxVOB0^QJDV?2kc0zw**3R_}Dg)UbpW z3Wg+46|Ju<6Fw~S^w562_H)blA5RhHf4*`KXJi_d$lfK7`odbk{4{jnZGp)8%`^ZX z$1x_LN1q<8?l(FdoaZk;SHBfxukhH&1Zz?xReW6z$ua9nikOM4mI5f>vnY^#p3pI- zDyZOfVnUZ3ml7E7g;Vb5U`f9oSrE` z*HpIweIu)h z&PH*aJ~vyZIOPQkr{ROn%ljg9GB@xn2XlQ%kJ-~Q6w*J@Nj;Qjt-&`ZGFd$8=Ep2& zYOX$hV0>DBDA_e5KbYgzKxoO$BJO;O92t4|x(OL=u*!otCNfPeLyf&C=763cO#b3M zO5i?b=*3cCs--m7FG{ty?HP;(Z!8wcyHs}eS~#J-i9vZQgz2|-;c|Z3CxcOO=?M+e zuC!HB_&kdtowkmY>r1u2CTWQL*}nb$>u}Az9Mi0yx-rY`1;7n9clunefgiE`!kD!z ze@M~Vs%aDw(k)Z!3JK&c=|r7gw|b5i|?qO1M%2!11FRab_3IBNc+0MEa7 zVbvFb+NiEO!`wrMsn`bAdaSw!sH9m>P5H_38HWgNMi#%y_Q(D2(5^lmt~*!_D2kB= zVlxk2x*V*}XDL$lex1EaTZMy9Va?V660ap9F@LWtbvW zi#UTX$Qm= zeZOns@JXqZeO@J;E(N>B)02N$1%=SPdhFOSW=QryC#-vEEj3X7=?U7x;bNX1Lh!c4 zV!TlrP8K^|on~ECZkT+vLF}UEDa4|MT|IAOl8C{F!(bFiL==vk2z0r{e(4SVyudkS z5$=dXV;>>RChsv9K)Y9C}x5`E9v- zjU2=kvaMH$2%m-i@N?~Rr@j^4QEm8k=ILBokCDJg@hMS!6V47I?`?zWA|#rYk;mrI^nw*T>5%K4^0lLJ|1Vi7j3=9;>5Ev4FJRaevs?CdF-lpe z%1EF*uLb1vQz*$aJi6GGUv#zg#GExvhthlmtT%$m48Y^*F{~$K{pP2lY=Z0ZR$t6b zc?sG=A!~IRXyTxA>=w{&X49zg>J-3-gnx*EW4^a=`+R9#RH;Z*xPm3(pvRrZw$*Yt zybdfiHI%I5AHcF{+_eYM9~}~F%7n9F%D7Ra@oj65NI#3Yx9=vOdrtDb0rm}cmzO}v zz)Q}RjuX=gQU)n7u5P!d+9geT9lAVHwj<79%R3gtJVv62f8`?bOnLQmt2iLPKD-2{ z@S({VXOM>FcHt!FSyrR@?CUSmR{RA-ky18v3krXL56P+)mkbs98t$! zhwzpWn$V|r+2~pnv+otuW`qgc=MrC&ydu8T5Q${-W#xKeHXOdhNJUR03QKyMWuA4; zld6#s!?n*cd=_b!WB~@UEBTyc@Pro%@+Q=aKphGO$Q4_b zU>WMPR~bIahT4x$p75@9h3*rTp=pfJw+Ce*Qo{8ptvMncrO@`QFvmtl7XO8=7X_FQr>&e4y#vFIs zNydyu@bzek1a<#hg> zT3Yu8V$w#=3KEG;@HF?Y&mp~+>^<5O9dRdeqAvL`hw-4gdy$mfyT2&e;Mv%VdDMb0 z#lJ^*&u(#+e9{7`+x%gPLg-v1!)eSrI`=g>(Vfqrn%2vIYCbloC}i0ll{evbvN$C* zE>OyTWyXxBE;Op1;Y+MZ&|K0ff|P*{!LjtO&qh04J&Cetv8eVgvCN859RK5im1WJD zG`=b#v24YZX}V&2-<`n8=;pZcay0(QTEHJIe#LYik$4Q&2T zgg?XpJ{Ck;dw%q;shJ3Rbu$RGZE&=Lr95u{EuLffq68XMS#n!taxm7;tI(^5R9F)d zzCw{Yu5crLFb@u5ECG!|YZJ z{oGWnh%$pgyzTPxt>G8&44nNY_fEpySJ;)b99s+LK?%!EnRh-muFxW>Ff<-ahCHUr@h21fDthPlpI#d!<6tX=jp4wxIPj z5bGm?)H3J#`S+37G)6x>nZ9e^Ah0ZCNPqgY+bx)C79T#<^j<)WE%}Uam^*B^`GlZ@ z!Fz*&)3W&k`jRRUW*F>!x~@I7b`DynuA48_z27|zqQO+!=Nr`$+_mJ8jjrSYvghC0%yFS^`| z*P!?cEW7aN&ArS5)3acLS`)F4Xnm-4td^?-Eh{1ThFw7SiH4K|E5vf7w1w$pESE;p zdq03MG@|2T*{fVN*?d5bb@NgHZ-lu|aOj=|_YN73-k3&gLfR;`Z7*^17f@Shl3UDN z97cIZ^nF$!g*Wrj-PGGV>dhL8I{`6JpCIpD998s%5~GH8{F!OubY~eVHH5j)%bgfH zw>{G|`6q{LbO8scQTl}x1kRE@+2;o5i8nb}Oq9I37)b8)MP%DktmFjHXxt1{dFd%8 zF$iHRPE-ufEp<~2jKe2zl0dqLYQRqqR`qoJmROHqD-Rb$nV$|lLs+OFzuq!#JuIF{ zqaA!Ldt=6~by9)j1Sry6JLft*IN7Ch2D}iz>u{c$&PsOuQpcy(ECcc>pnEz*r*gT- z;ab9)Zoj$k`dE3NtqTSJtlL7odEy8>8?j1eY_6`%?pkM$jNG`O+-p;3Xgv%QhREZ- z$rG^%MpZFa9V`eYtgYSRFMo}*^K16unC(wACm#K2mm}?#amiHDu)>0Fnxn0w~r`);xG0CqXg3JVWT?fyRsf(?;&z_pbGLU(U zBTz~|Cf0F`X5PsB9SvsFg$1zmI9SL&k3H$W!E7Zsm{gRYfu!tuxh&)gk^4XX2aLsH z>54R))ut9VEmN=CWH2Q%F4oTn6y^3jqEt9wWZLGFZjt)dwwDiz%d=pq_QY2Ro@^nx zDh_sy(&(Q0W6n=i5K5tiyo9U7fJ>N8`I}-)W2J`XyTI=f(lcO5Gvz_tiCBhE_afYw zG76Fzg0tmh^L(_h#AZ_iTjGY(&0vQKl<>uw4#7O}GwymK`Rc{FhNfAHfpC;m5FMA= zNE5mF5!H!Se336`$W&Av@)~AC5n#I{9JB`Te8`67LGu>|$I|7*DcnjKXRqVs(Rh!h zsEIBb9g45`g*R*PV4T7kCWqsKb&z6t`60Q%sAHOyhZ|4n`C@_KzwuTQ zHqd?y$mADgl)Dn`lpy9k*6RK?$>U?@D4|6OdLaw(R;BOzZ0WViVt0IQBAcbgVW{F( zNJ%!o(WJ#tW^jgrw%}oDgRgV6ERmpDdpUY zN-te%peNoI+Sm82-qo#YYx&jYFtfXa=u%8S5zW_EL$>3y*^}f7S8W3))PU*WQ60!XvJ;unS zi#E6xf%yQW;KcX+EqyN57Yx!)aYt%C`ePcH|Nciut6}Sguf$t$>q7X=pt`u4&CJiq z%(Efj+p#GgtHVK@0Ge7iP;0_=2ic#Sa;RusVrh5yzPY(M*t#oW5h%UBP;*bi$rUFcGQp`lZ+Z^`pAPYPsdWWk`x z*;pU#nH%ke8i`94XHMz*uLN_m{6%J|Fz!Sy3AdUB&l!#QEl(?Y)KaFxJ`;I38n*9c z2{_l$*$RU0`=>HN55>xG;NF`Rs{we`LZos_!Qmx-$~rWpURlxA9$J(kFMd(_Zp0w<=D zZXqMShfjJRVZC8T6lQ1RES5?bwcs9G@KJb9ysm$Li!9rvFzI<*zG)m38Wb{s#$UIr zt#K|h1>TwhsI_QI?}ypaG027d07qJ1JndW2hNte@iBlW5hX#qSrvt^D0qR5X0WrLZ zX{Y5Ya#b6U7x!!a@1RLNU$O@jc5#PpvX(#j(V1rHcr(+Nn1@A5p64lh4K}m0TAaQ{ z5>>%|j1_wYN()~4)+IG!M61EjaR{R+2Ts3}l}kI*CRQ(GIC>JqKFlajH6;H8b4k-FF8;8|HN9yS=_C8IMjyF3Yu;=F4{dZVP(y z2g%+sn7hu%$lx^(Ad_!y$Q58$n4}MMbAz}CDS#r30f_mP8?Y(v1fx)Ki+n093!Au? zJNw=HbfJOGjw)vZI2P8s470JdrNhwNwR6c?x^k5m%;?(e6#NtH^Y#CcNq*8MGFc@C zytMj*anr>9rK_z_>5}=#vk#TMH3}ZZzH+yTKE~g3868=XfmSA+PTl08cwixr(&bMwtl8KV%2lp&lxyEzc}r zM>6yKtB@Ga*>+URm7kij%(!(dG!_KEL(Fqal1{jNL;IVDnwr$(|#3-8sDZ7yDNV@XP%YmirVonyypnmz_`RmM4V;I35@&X2WkF$pB zUvG8Ivn19#({l#}nCFXDi8G_V?V;b#jv$Yc)=(P*LVTkg@4dhiS~BI&x;>mH!(uL} z8m7pBcDwBaZ>bWI%LJ2kd0ZnScM2|fzhaQdQi z&A^5y0xQE^hs91HqEdIx?)ErQn@&s@eH^e+Ci3Z1uqt6GCJnup62sa0Y2hPml+--7 zj(X)JLicikynOth@MQNa$e}N9PSuCb0pX;acqN8MZ@l^mpfu#g&+trAjU;Y&=J z2)R1lEnNxGM^`3vK~Sx43x@XOj|F}evo~Lz{w-An|00P!<%(`z2`vMSnt7DW@vIin z_%3yL8#t+5%bb01Q(k6ls-8tZSlHOt7)06Lh%)*0oZiIUu-$lfF-r-VoH20MSr8j^ ziV~TBUTW5612DpfzmI~@GcB^W$LYahi zwL@ImqrYyYd98HZ4uh3x2dkcD!A2auy|RUmKoow4a3}XVNSvp%l*h#5**6s39d`A9 zM`#R0o;B9j`Wh!0`AKP*FpBRrXM&Qw#lS&57gEHT~IW^p|EF$lg)-Kew9&`EznR5 zwdg?CeCg7|x9q)qGuiNJS0O~8&l3&ybcX;)hxWlpJAkh zhW(Q4;&=ljAO9bBK62dNorvW3!ix_(`Ot}jXG18@IGWc>w`&U+(#m=ggh)K~z}dhB&&(ui#nIVqufg)K%i;0>oY@B{pJ>=Ff@TIfc^u_LRp^^+ zKy6BZOk;3C#b$?Xld~)Y^%neW{2PSq?qe^Bm52~p?@YhM00;rvr)jNG?mgMAYP#OpPpO@{T9nw~}+2rzg z!b@a8L0epw-wRo&QAsqfdT_t7R^lI09b_vipGAM>xL-?gQ1A;UnP3 zj`YIf7zH6CT3@i+b{4DkV7S59mz&J_PzWoU@t=-v2(+uG;?206K=H4tcCW~8uf8P> z$U$_99|ZQrPB$Cl*18y^bCkgYqM%Tt+*7(p`sN6WbyD6=g&42e@apPcQ->#f*~OSv zQqwg*9&F7A+jEu0D~*_d7C3Ra?n9A@Uu$<@H-H}BRi4|W-i&Ui3uDN(cdjbbR^28p z075-tW{&fIkLCF|j@lPDkzJgrz*fz5!sw-30z*3YnDNvIwOK~9++ocrT-2{Np=wDH z^PTWzzAiC%3pIOh+D~|2 z=?6rUz7Pb)CW4c{i544AbhQhz8B6^2HVrt%s|iNl%(;78E7C~o>gPh(ehNl)k69{6 z0rNBYdCfc6Y zVB%vF&auHOs8&Q40Vv#)HaZ)+(&jcGm2u2(e+g!&Rqtk92N)QgH-Jcy>OH5Y=fA@z zKQn?->3>ESajMOXC4`N?W^L^8n<7ZPqJ|RjBNnE-+nxMaRSqX1l!*zl#F+wJt;YW2 zM5!G^D#~3mALguY>b(Ol-47?zmFUqd#Bgp-^P>mvw?Y~VM>Kt-p55k`H zBa;K8LoW5Q7RmK?^n~ib-Nwq zr)PUeJ2Df|=@zZGgI{ueva*UCMW-Le1%yGt8v_KyULFw-Y^#?d4C!I40Vp$J0xqP2 z{MX}CkNwvgkjepzEL2Hcju-QX&&WGvg-9V3GoL6R38&6N8aXYrm87h}P4Q1txSRWL z-$CEG0F#vfmzMJGtD*06oOvVuQon%0*v~U;GDK zNGSxk(In|cDYi~4md1S6ZOLirb&`5Yr}tV98Ll#S69Y>r`&KB6R6dT{HEi8hY&$YX zP>%0OOHpb2Q=(bYh5{SDde*l`y&opKiO-js4}glOhBHNOuZ=m^Y9RJ6d(D6Aay5Hb z+(!e<^u686-D`||7d)1%E8(XrdW4Qb8uqMGj_ifDhjRmV+C z;rQyto$F4a8nCxzE-ZP2yX|f}26hQ09c2KuXbs1z>oHB;&}DUdhg>8np1RtYAx9W~ z6lDLq$gt>$NmZ$4Ig)e7?hf7*{$us73&9M>yN9}+4_CuQuKIHEidCha_fSRsT>4RH z)rE|6T^g=uD4*}C&X2fb_jZ@?@%Az8?i*JU6%iBlOykt^ukUa#iQSD&lLuj{;wyMr zSI@58pZWo+Bt1SM9OnG<)WoPgo{~hMs{sN z>m=D!^sd5#@e2?w_?|k*!VK!80k|9hNpSnE1qZG%645-0KRijol1G7hCw(unk9f3S z3fZ`;#|DyjjnWRU;Ntk;rrekv0=|5QaWM*|L=l-ASbLyuZeS2gZNA+fw%8~U;a)%Q ziQY5#ebmsCpgTI1AT+v7DYf#_h!XT7SgH-Sog+(1h9^BwyHI=V9p7|DP8<{j^+e3t z>lrF3CXoq?fXOL7;biFAQkkT>3$@xN@D0T)mqYiM+?|DSDTB7PN0n-a(Guu;ApF$= z?0}FcshLjMl_bF(1$u77j}fJW0ABY>XpSIsXv$7TxV?I&&hK3aJG`&6@^rH{+T590 z_AQ&%A{|S5N5`a#Wk|qztHVVuM8h3JTbIf?;Sz~tJ-L_sOdV#sGXFi9%{_BJ(T${6j+1I&4U5J1Syezpu_wrnaf)E4oPS>yh4| zI+=kdVqIrNSA#wM5w_OWP9Ktz1uYp81@+Hw` z*L=!_(4CKueZU&uPO>51x&DXH_XP!Ti$o>PndtmA4mg145q&qKp^2ZAI}bcmJk_rl z${YgRftcZuIXOj9N`RAUBVm)n2r|q&K8}5S$pptep(C7onvl?*4et)NF)m>?UGeH6 zycdDNPt(1?UN(v=>~*lSecbZY)YOK<5h%LeXBIt)ZWP>;lJ`D8Ww8wvDGqyn&y;0^ zF7Sj$<_t=pZTuXRBH92R$FWA+XrY*VokKW0i^2d08mNj3dGaowz;mzGSS;{-s}O@( zPY;B|inUwVeR1X^-iLnp#WJ zkrctmfc(B%|HN3+ zYLjSs6Q_rs=dJ%BoD4t;g1@M_JzPfm{%=6TXTRq44PeB}7<=n6&MFwEp0@hsa3<|gqUnes9Xrr)# zgn$4!yTYwB0N4HtqcRoV41R5fV~=Q1Qk^hhcp>l#Zy;H)yN(?X&`*iCZC8;u)XJrg zX9nIbpCUU5J9=G#(FW|`mugrYZ&$z!*omtAM#nZMH2qk_G$d-b2|QIDjRoUB{o^NR z8Zq~O$vbh#fEr2s;p(`mu~8Gx;j8g_v>a4K+#OR~~RU3?8u{4DU*W0w+ zR%**d9XiGEn7?qh<#LgxjDpsL@lDnYiQa-#kl`bg!4B<0uoBsAk!MP5X@CL7@)=qn zxwq}{f);}dD#dg{dF5$JOtgM`&43Bya7TUHaQGzgZ<% zxkv5yRvQjKTggHO^4iQ{(-D??o}C8Y4#mOP6PJ;(ZvJXLnV`uFGl{y}gV%&!*H12C z9$FG#9j^263$$AkhBd(=!l+q85fdx-K%gnV{UBmU=T|zVdK-+>dhiF2F($U`KhL?{ z-UR1A{T%XGxpAW;eJ;4TT2pO?@wZgoSfpZP2 z;!T`&?6#@T3*#&4Ez%EosLoQWL8eNpftqkyh*1JZtiwizcj*NIiELg!m>c_Eq~!ojc|~FF*`3?`>>q z!`PE;9XXJp`f{OUQWRsHe^7?jn!AJ2aGd?h>_0CR&vMh+#I3L1CDlW z7_fz8dBzRExuT^8vZn<;yd1?DxJ24hFf&1ZKE7^wDe(_@;evDqQ>zQ|n5eED@^b|tM)!;(-XTNtI1 z!$OsU%4)dnaNC~*sXI@g+inUs2ZkY%_WDkovQ z#$#j?K~3yx)la`%>pGU|NJ;L}hP0uInVCXgz&q%aaDXDR`-G;r6T&3tx^)7~i1(bM zaKSsMIm|-jUMK=Ej`OR+{H%OH7G3ZpJ$FS3o+IK}5G3v1;%Ae=MuD`&9>?U#CZ$u$ zd@U_oQH~cDEXrW?$oMz?*&3ug!a%li@WG_HH=N>THK9MIacTYf;hPE>3pA7hMHnU3 zHp~GT4*bcr6ZPaNAO|VE;h<7gBdjwR*8Sm zY|e&?wt#v=f5>RxX}86Q^fzn2?JsTEYLoGp5oqIK6pCwBTn_$W74Q zqtu7^MI}A^ZM#L}W-8LpoImSKgz~+LAmI+%P$%1FjR2EV=>&s@f?|>Z$)KEhqle=g z=oEgRUPcTAQZ0|I9C+cqN-#akE_Z#6&@i53jQCWGH~()ez9QYNut3^8 zNbK>(V-1yV0T8-j!M|!lXy62jRnl%|`5hJh`D@(8SC2@=o8+w3Su{Q`rIlpf9M(gg)dVJt>~SpIwEaR}lo&7))( zpsab8v$xr2UCK-QmFX2XRh3k!jM9o%fzw|}q*tVY3d+a^pKUAh^VWH8!@dR#TQ&W) zr6$DTK1f(0JH$`UWeG^{5sBL?J#y{%l_mT|*!5ChkdpGan^Y%ax)P%KshSS^O~_I; z>{tmZG>K%JTcKkWx83<7qj4xrJ8#hC0M^C>4s;VEk~(_xgvz&L>mc%TE-<$TD#{Ed zS1rrg#-qTBW~s1fhucmzRSF~OHGMXGM*l{=_1K7_NBt`!$9*FCubR>il769c^7B^H zC`5m_cu+38r`dlhGnhgwhg3>Dh``}OB7)zC%R6-iSsOfGl*tx6JNtIYJ$-^{aXyE; z;6`3aVsuT%0J|qMCRF8|`e0Q-_uTEzVc`(9LcRvXBAdkL_9cyFPbk>-;RL@7+&33EXNb?7BfN1p3!MHpElZ?}mW8blL2 zaWe-*hfhZh`M60#2rqsmp3mKRjV@Yhh@{G)+zgJ+z&< z1SkmEF5>LJ-*062=A_02bauOP62wwAhWgxc#PcKg-zG#9{i!N@3c&r1X9TO+#ZJIb zc?<#*graAg;6#SikuI#dOF5EbFhbBQvf1?cLQ&5Lz6ZO^ zrSGvkXB?veA+EKgyshDf>npS`(WeS-hLT-rf3%zcQT;D|*Rhui0@^e1*&~1g#gQ#T z%7lqugKzbu2H{l7OC)Kc5z?wrEDu(dV=lEk$$A1OOMS@K@x=(zn0lBWM)djI+nlJk zqdBSqsT!rR`UuPvb8P|8zd9ITMZ*K`Dy|G%i3(EGeeo7he0f72hdEQmFgyGW~LbI#0p#Dm>&NbwgZ@I9fGYmQhq)GEal1z+kicw4l1lVaq#{?X2^EzyM!4Pn6 z0bZh(^=N;tVu556+g&GXg_D+6ORTJ8*E&IY!@9WM8HWV2+ikWyf$700zP3laQ(jgf z9Pd+rp7EF}!(Nk6vTmOziMoTDTX1Wq5R*EL z>Dto#cv%GuVz!?VNGY^am zAAfjY(bkHP5mY2*e%^?R%)&v2Re7J=vt-`VkW2`}&7&n0bG{zV%cp0J)?Que+ABB! zbMr{>@Wbz`RsLT*0^9$^Bd{~E{;!9?M8L?&z{dH%%m0T*U|?it{{Q6>+MJw=?b7IQ zvT~fGBW<=?Z&a+eTo-Yj$1c||*IQ#^ZJwn6b~Bin@7T}gnk-d$TYPrB^uP432#J+c z3Xqvv*uf&VwmRk+7nmJ^jZczqY+|lOqH(e_FfNhU=yfz`7Emjkf^T2dKKQUO4kfU=6BQhm-1Q`N%3y~_Os zh>D1+$_AnlP?6M8fdN!50g)`LsQmp_0^RUEWGw+5tMcFYU3qi;!lofBqbjW^p%@vy zdw~HU_rsnaTYt1&_ZblXiGaP+o97jn%DuM!p#UgowYPKFGc)|BPAp}0adpjaac3-X zuYU*0uM93??%UoO!@hfS0owTgv5cG}&tkr_OKkt@i*3!R z`GWae>i)vl&xy5v&saRsyZJLCyz@_LU~v8+Q&*K!K-aT2Hah`sVs2!3b9G{Lv~vN& z{4MzS29%=w0YQL-w{vm+)DXVqk(K=^pYj(#Z~5iQtc`B1jsNVCn;M^8Ucc;lKJmxd z7}}j#UtAx4*F_8XXOzI+(|exvF*h}TiIbC)(38@Y7D|zSN%C-WaemF+t}k@Cw|^h~ zu;;~>)3Ey|CE)fCk3jwVCaFlzsR-|>xgobSYwx>3Zu!1Wit0%sANrHCwc_@2hbY;hYEUhXCLL^2Z}XgYkp@8_MdlEbY6T z3w`(GUgrjwj<(JY=uI{4p99ZsYf8XI*grgmdVcx63;m-UU~~YGp_SF)qx|b&v;Q+r zYh-Q$xBrp;i8$t${SyS6^ixZ{bkdi-xv}N}EEQnp0Q2xllebj(?b~Sgt0KL%G$OV$ zhA#fr|N6X}6>Cjp%l-3v^K)7P_!X6C^hA?@9h| zzzQG4M#dHZ|JYNU)XiPwhPUI#6JO)ER}SELy2i%e%&Vj_vK4oJ6SMz|zCr(7=r{J| z9Od^2%s+&bWX1TjvX4E==eWA`oQR%^k{nL|j2PU1$H&IUkYn!?(57r`{_IQS8?pg- ze+c0H0(NG1kC;IA_AU>g=^NYwKe%+@%>IIpb(i=N5ecyU|337Ikdgfde)}TwX5s!w znV5kvczzN8$h}AUsDI$aG5@Z3{v6hRh^yK;Hnf3RX=M5DKK@RL%#II@FA9dWYaG}d>AvSL%Ba0SMuUp9bR=M>1u#KiXg5Un2Ttj_Qq{n&o_ zPx`pw0f2b@$?T_~U&(j~)hc2PNPP`IluP1`b)L&kFupSvBM_$e%Qo#BM4Vb90)RjR z`hXWFps!6xJ6^sMfp2^*5<|ROJoe0g^%y;@DoNUnj>*r$qDaVCGHc}O(30ueP!u)= zWn4&da>`VPxsrAh*M$HSuzArAEU&yHO>*A_dgKUKX>By8LY(QdjVy)S8b1yjf&-Ug zyI5A>E*~F)@$ik7iJN73teq@*oK$WJvV%Y*VY3C4w z(8KVA;IjVm@)+1-#eb2U5JTX}Pi_)~Jb+a@i}jQArpBnzX3pL>)3)2W)6>!P#%+H( zVLl0YgQdy(k~?&PTAb<4vzutF>VL-|=~%OpC+2gTmDWy&=g>0309mAYudo5dudJXU zjYWnHLmZ?BPs3}KU8m>gc2`VTN0#-SS{`}s!uX`{No-4^G1nQ;4(n!r`#o%fw&USnK zR-D*S%5HPDE)rRjrsYtfM#low={oo4pZNUX? zkWoN4ghzFI^pTYoseoqyciiR{UN;rTjyf!4&!2Il_2v+JbETbzN8X(mTuYq}jT;yv zDfiW!Q*!Ro({C?fFaODXfH2l!Aq?bh8MM4Wru)>LA zrY$M1hM;LX=9C+&?}1lcN(YbSmq}!y+));QE}A!W_R@N)IkRQxyS<5bl>8InSCh-! zOh6Y)r)?9EZ}Ez|jr|z&=^C>$Ax}BX3$u!jtSH#2s%$}OM?W(9Fd(Sg3@EU}CvbA7 zd5>^G_@PLDK? zSWKOACUY@BbaEn-lA@O_?mz60-$fsxjeNJOm`JhuN;nB+erRZ&hZfk=+^k!UiRnQB zh)4c-G24K_`46|3<4O~Q%}lC^MW8Ix$`r12z%)wrqw5)T=)9+Q8aA&^(Y=R|L}*9X z*Fx$ZKKy92*k`U#f0JKT31s@FP+Tl5l}t z&TAZ_Vcu2#4V|dUNkqA0n@$2_JG88mXG0k6FfO^=bE0ykf#1>`mv6Q{UtvTmHN&5S z2?W1)Kp20i%h}FqPHe#j?vpa{v(-8WYIySvDAMefAI1-ltM-~tt^s-3L>&T4H0j@> z-P~=}FwNR`0c2_`C@Xg>P0w(35u zYS~OX-6z`?dz~2Q-k|Ff9&;vVl+mJHNDrkr1>sy!I(YE&YjV1G6@lBeh#Tg_1 z6i14#k4uUV6D@WZ(?y`t-AtrW8neH1=qeI%4U~+cCrqLvhoaPD3?P;${DqKP=JBSB zw6Bptc$Ojsh=2e=SlF)Yoq{Q92WKQ4DA`gt&AdQMZ5 zloC*=05m+Wizbx9tO~I~_J!#xZY#VH8L^^s+VRS!>K%GUaNs0RDm0Zzy#tKey5{#J zPd}Y!;C=DNwI4=T55_=@xw2{mJ3U*QwtYxj&Ab}^yw}eHG&kQH3zl7 zLv&DKd1scrbdGh-55&kRb&4%z`&?T38R+~|h=87{6(X2-;fS$?ZyOfL9xEMJA%gyT zNRsegv7$O+*S`cIpFK>vR|xTDTV}iU&}jx^gAfEN$@4D*YEY#M`VitOgCVa9JyAg8 z3p5j9o-vz)^vVoO1^V+KRpsNF3@sux+&O5(Wka3$A_%F&R)3+NI2^$y(kr$G@a#NH zY@*Vm)F%b-rXh@z%cZ>kX6rMZ zbErS<0x(Yg2t_h9?)ZeHFU4HbMB1u@?M1|&G-hkvCj=CPR+-Ncb}KzY81r+8c+}rw z=MyV)Ii#h`|B|OdDkj(a?(J4;$bTbBW2(!oRbJ3OA7>i zuZ6v!2`$@@ABZ|u=IO9gVQve^%Xs?b2NP~3y&VnF!si~$y;65E74162J~Om2>zWCJ z-g-cgs1Z8ja$~F^x+!cheDf^@a^-mAX}a-*y*;q$W6^*+aC1mX-V@Z2$I_s5QHrPb zO~UW`?9`q>lOU3-D|&VGu6UO$=#opT#EiPLK}dQn`My{`Vjy?-ppQc@ta`1j2_g^r z)~^Iws0GXf57AT|$gQ!TZ7awQfNG^1Kk@F#XT?g5NPDfQI-t;xij*ExUkjTm!a6?7Zxw1^=So~KB$^{NX z-VjqCifD?Y3QW`L-YlW99?PPMNS$>+QtA;n(T8|pOM2wx{w*J41LNnN`N@}&!YdO{ zBl4qgKeExsr?GReGy?BT`wqh(4r30oR8^niRWaT~4R?x9u&2-g2|Ye`;jVc5__ofm zgm!BW3M49Hjs`vb#^apsdS9I~~@i2pc_-lpuE$oD3HO8i&8kxai+*Cv-2@AYpT z;O7NkCYim?!$>iRn%>C-Z%eSRs?GmeasFuh?4L5Ea7Y=_8Y)gy&Z**E*&t>yQO4es z;F{YN0x%#K@Vgh*(y|x4(5VEUun0`-R-gm;M|-6ptjZUzg6I6CoGfND0H9BkclKgs z!Viwvs*Tk4l16!$Ck`#9UduxA??~~@OWW`VXs8kN55x_$4^Xw-qlN0S!vrHXA3sUK zk=OFDw2ogCxV8ZaJh@dP0R=+F_x+h6k-3Mo($$6j43bZLu_G8mi1zN{8`i)nHi@l)}uc+)8!R4S17V#`y4QU|SAH%JUr zA=Zq82319zU(HT*a!S}hRabffk%QF;A=6458f5Hr$Ezec?WfzO(|f{9b~2r6i%G9) z_riLr!aqptUXj_f>@>5Dh>Uq;Sr?NsZmBu$d9@?|aDZL}bhLA~M&C7ZE!dmA&^^BMCBbpv*~!A@zp^?6-iFm`AY?_A2qMSf^p(_>Wz ze62^X8z^zB^R_Q#{JoRc_oarMmO@xX$HBA{Xq;dX_e@w~kq@mLv>Or?69n28==F3j zz_lNcQL5A8kP%=<+c`KVqq6JCQ-4FrO`HO~L;Rn}hp9^{u-2f@HioHb?+P{9`Gd7I zCX4SMnP`+z1U*|;4Lpp#x^C-6cDJ1m&Nay67x}lj^U#*QQk_| zV=gSA*iaeEXy<1HG3_I5G%pRCK82CGjdB@fWKIpKjyO`v&VMbFR+KjG)d-?ngIgvg zUPO(UK7UtVPNTvTKIbo`$t!GYILKSG_(K59{&m^?+K;fbo%Jj+uiQm(;LeQZDh?MW zRg-s5Y4qm@;*{G0v-Ht=Zy9JEE(T~UC(cxRs3fjtEMkmH$qAIVs$oxGXpv@liW8|WOQKjJY;8V+`t)xYH}%Sls( zfd*6(2=~-5Ic=T0NL90%n z39~~*hU7APk?X;PXd_1yvMlOMz^0~XZ5YRiX|D0?K^?O)WSZm{dWP^+Q8=HgWiM?U zocAn=)zm!OaaW#5-~iW6aG$pzd$|%Aa_f;(HejPccgO%~l|+F(FFQyd#H)LYCiUyDL?G{C&6OHfe?Sn4QPk)}BO8K4`g#Eed0qU2X0QzV!0jM$DFxMPC>w3*!Y|LwC zt!sM%?~sY~#`k&{Fe}JFh`1y4>zvy8p|NE7Xx-426JT!>X%fjVS}NEv>Izfs$>keZ zQYTr()fXVWMW<4>el;C5b7_gUWP2qKAVUH_!R$d3U3uG@${|q>3XUCOTCDQ1L^Jfg za1tv~N68MVM08)j9gv76Fl{s)(+4|3~TK8B-uPnAfg+9rS zb_LQs);tTWdW5DA%005az|YlUA(JGCI@ZGC(I$W~17~Hy$#oy8)6U?>)6d(}61}cs zBXr=3NC}mz+fiM>U}Q$>}T<-Ul;>%Ie`-?Dydlq$H9> z=IM4V2j}qCL@7c^XepqA>)TMMIy+soIvd*6hGwGL-v>`3MTigT;+`>8{@#yY4G|mr ztW{jS1U=;r5z4w)I4o=Z5kp9H+KbFUeh%$-UK@AjwwuYdu9&PNoIv#OHKl~9uN1{L zY}*AGm!$Mpb7g|>)9wZ(ftEZA8-HOn1*Bd^IUz6%JJZzoiL7l7xCc((Nun+mC*oL+ z;PsM0wCjNLYF;LPSU9cB&|KR95{mdNz_U=zlFS!P+1{`Tp_dpB>D-0#+k-sy^$e9g!|bF!1^8f;h#Ni0U#3Fau((S} zRGKep(>6Q=3c6af4VfVQ(%$SskjsLMqqdPOMA#Vvla(3Qh(2IA-Yt*T0jap0<~N(D zlJXAlkJKoNM$Bkp`G97GobiMQAuYGdQg196QzOZE{Aazhqo|wUC38>=D`kMOc9RA%; zxNz`6D_pl9k>^|;wG)o$t4lUd3i9i7D>vy#mre}&P}^eXQL7X2ZY`#%jM!Z=q@Vya z_Uns|g_}g^`0_gx7V{dQy&w|LUllhw5~6%6`f--IKL^2jJPx~7?n?oU5Q9@afVBU1WYuX54dfWodDLVdK*kQ>k5Q7^Ey-2>NG4xe3GI+u*~FU zzVB{K{1h`$_B*gBR_s!4RQaC^p@jN$&or8tdC z`Tbh@8Qp-G^00Zwo}c2OYQTN=TBd9hk|}w2K*p(v5zY^XotLhNpsP?xmDC;>=jxYa zgu{U3db6-<6kbGjX2&$>#i>_>2rY@So?;h{Lqt;ZX2X1fUZ+dYq%gN6&pQ0sjM3gR zb$|t3jU3@wD9>g07c1_tt&;v&!F~StBfR&gp9M?M!-EsVE38njS8b^oF?CD*)SVCyN$s3W zR(JYuqcI%DMq^aT%;PaydzDwHY}m6({H01R)t(8&{S@L>z~>;5>fc^^C%r33YkuJZ zF6{C|$sOX@e2a%zEm;SWee%y*+s>TzT}7=po2dOn_DO{L-!v!mjlEk7d>6^M4Jq=V3Tv7-F}4*hoMAM zE0|e_yFaScPp}R-!>td8&-5wo7#okUL`R0)=F9h55e;Z5mQY}thAiwL#WvF+_ff86 zW)7#(VMf}ouCLQu<|dhg{C^#k`GA;A&fOLP6Pjw99R){S`Znd_Ph>Z)(6!3=Ga(&E z%DEVF;c7`L-8dS{vFlf6yyo6xMwhR}dGI-U6MEul?~t`+@FoVGPUa%rNuWB}PLOG! zo02sKf226!q1zvgAV8B9O;S4I2wCr|d3!oN3|7XoZ$SV3G-UllS_IE$c;aE1iX^Vj z;n+)UC7O)Hq_cqnowNM!@h%nB2vcO>(AXoJoYUQs^~^3i?Dw6K6Lfzo`X*qmDoe-} zTgPL|fv|<`p=Abh=ahsz>xPLZy9h_g?E_jtUbvGS2hmoLwPi?Rk>tF=T2r3Y^E^k4 zY+Cxjx7K%@G|;X>t~`aPY=N@;?t&6UDM&arYJDh9HZR0j8*gD1UZYP3WA5p-%-zjn zGnw4c;F$P?o|tTTj69i&Xay<`Pksw;8@Sp4j0M5>hFPv9-J?aMmCp6gBi zx{7p2^u){%)GpgF7jxOvUsoOVMfDv(8^Iujt>s(xVGsLbR_By0MPIhAZRO47Ox*ex zmPs$zKP$UiPBt=Qt-XY3*Lak0gSD$+aAZFW`CR1o1sUnyAbv?~9^6KA#-7rux||Uh z&~B|ZW=SH(D=6|iN0j%G8IVZOIfqTi82EzkHd^PsR_qeFdB*8=C_XkP<3aG+}cnKYC#k#tGl&`o49QGdlY zhM~#I$qv5iAH-Q(H+|kr5-!2>9k5C5SbYPaBvgf=@lpL;&P1*%Bu~Mk#}l>w^lQTi zx_1%1qdTz=f+0oqxWR;;n`wTz^0ery+bU~#=F@jjig9MA=b<00k>n_P4UaGS#)~@i~R&y#?78apNkQenJtKdVUlGCo4JG zLk(n$qwNQ;75RaPWW*Ds0d zRc|*L`6l+Ug43z^TGDKh&x`2zqs1bY`Iq0*aO6quZ6aWDlZs#VFN-F^R(|B%u3eSM zlU1shop0jRS>+y$87Ta_-?+u?muuuYBCTLA-O!#~}ZSqU}xasI!{} zKg?Ucp`zh{@6g7TN%a+JcqX`7!sD^pet3mp3ct zRPHB*1_3`6MSjh#d61AyD6oirh?xjB4AP1MivZ8R_V&TL&In%ZX6HK1(3|~pDYait zzQICfr)z9-c)MY>vO;mMSY}q}C@RC-QPs4r66#0s$vL`ZI4v5F%qDF5OyrQkY*Q|C zLA%rpo3`qFYgRW1N~h@}ZoZ@~rT>}1j!so)cbFyGQZ*S0@u(9l*||!go6R-SI}Wlr z;nEcDH3Fo1hN?*X2UirgqVsi;V2soHJNfs?F7@?NeZme*k*UWtP7352k`{QrR|q?* z6ZsX-Lx5&eimr`i)cTwF`FL<2)|SSPLR>8{hvdmRS*ndt@NthgCi4=Qc=jF?>4MKX8- ze2mi`V`xos@8IPE-?e)O=LKfNmdiv12F4s^t*=Z56iDaO5l!-T;0VfS`|!Mq#(+I^2g!;#H>lg)_{kPH zOu07wLQvFLo>AUrDb_L|jq4f;gt_v3Vt zx8xK4oLZH=wr=gJs4$1`hU3P0dCyLo|Y1zpb}x#=XoZck2JhzO5)orOQ0e zUc2Ln^9Lb(ccCrztB0_HQ~;R!A?fGVe-M3Pb2XJ#W9yV&{Oj{~i&n5O#}H{7VErk| zQiUs}HAi1N(rl*MkBK z{IL1EttP#3WN@;g1++`Qi%^JBk4dZC^44OzURpyASJ{knl$E43w(cG7&{zC6TFR8t zW(S|HVu_Q?pB%sbhefwPbCSsuho?qeA9bY`VrQC^At&RQ8ndCItADcbl7(y0%t-Yk z>)yZsirjdrD`y5K8x@&ePi$-c7l*M~Mfuv9w>`wwss0~m=kiso-plxqh5v379$`qFDZYW7NgVq`; z=|VR+Eqc6nGd2|ozOr>bXV7=oIymMEd-C36i>(WeF{0Pa!;v5yR9P*LYq7rfIvw8r zKh89!OSgHd`!XBH&7a&nDtyxH_p#KpCd@=4V&BG;wu74`7&*|!R(*!2I)n;Ix1!oy zRWqSPO7Bihbb2dQ%?OKQ(X}6&9NzgR zkA%!e!YUf2r+jW{gilwS|*)&aYSl|4e`7pGR2bnUIy4vv|XgVUaA18QY z>@sRmg#|&ELUm1uKy$gC?A-ewg*`CmN%084rzNr3FANdJHyT}uR$Ca10?<^Z(h6(T zo{XrFrIL;TAl3rrD~}#*;tPpBh6|`GNoHIh%l_uxC{J;`b=o$3O&*6D!>!|vB8wnB z+#s)Yp19^{*PBJ8IJy^Io*l_v-^eF;JSBkMLwNQZUZANiB=SV&%fEcHVYx`E&`S=zvOFqwAuC0!FPXNSApQmPh*f z7F;e>*miGW5;Sfx=l#b+nEvT_F-<|qM!ibF@uGGHIqk}#hUm0IY+T9a2AN5kk((56 z$uj*H$;TIVXa1JKymb6in*uT|n9IGM93RpDK zj$^*DCSsv@GJ1wUcIvz!Hx_SDo)t>hN=ME_aE)objbu1J#jET)yCXOjDbN)YuZ2&7 zXXVcWq*4~6ot(6kpSl;yfyY$>coAjwkW_El$wYG=k~*wCje*qLL)Pt+7Yo(=6`Z%thKUbbr#)|;>4=A#>hIz@rFN72E8`avc3qHr~S^C~YcrK>g_y;yryMjdW zJUlHrGs+bGR-+CW<#l8|rYXz#w_lW@3VM`0Dd@?NY5XOu*Q%B&kE5Z~(D~T3rLtEV z;<^Xe&}9+`u;Ay*D=`1if!F@81Us6yRr;o!l+Tf0yFVFUn&G@YOKHTRo5!%vf{of@ za)~CbwG({c*zg(e$j|84oe+fYRvXaDQgyrXH zo(&_Bt&(RSD}lA34+EdodsK_pl{rfD_WB?*ZAmfGZ?2s1RaKNlIWj8c)Wa?gJBhY*sPWeV+?d=Y( zmyZM^Yp-^5g5w|~!(!4KSp%uQbn`y(=(pwDvK&IMERE>^2$yIWZ$DdHOex-vAAE4m zpw(fcQv9oGeWt&*IwtXQ8fMiAhqj;MKJ}U9HV#bbxBg@~pfikeV8O z8mP!jSqR9I|BE!DVkV@?#bRYOf+RZadh{8+xe^Z7Cz=2MCm zOQY4(!s2#P5!_JSv(IlBu*?SjM<8IYO*dEX$JEFx9Y(b3K+!Yvb_8$nj|aDH+wq$V z$MYWC5(C8-X5|5w$f0<=l6=<*!ZwFKb?ne~(JH|t){E8+x0*9LSW_OBvZu6YuZ0CSgy{Qr zl2|>co0$k)AUVP0_{AF%vEOMkBN2r4wP%MZZS2u7)+;_U8mfT@U~C16SHg*;BAiyb z9YRW4MeGsSMD8)=*Tf^VAD6Lbt!Hc**H*3-^PkQc2c&M1Rg4pPB1$(S#PJC!C#p7K zOZeEBP1)^GWDI#}Jc7tb1KCMkNF$-f-X0ZRw3Z?_H4PGDV`Q|xgF^HBbZ=ffr<|rA zt+UpJXi}%^lU|s^`zJia*S7qI_vcN85{Lua88VuqntP>@iuIm*FO`tcyu9$o9pTs= z?{;dahZ5QizF&1qT2d88K(Wx2BvD0Gs4;LdA70&ue}qKzQQQ%WM)qE zk@zTqJs;l%f#db4wi*#wbWs@Q=$XBnq#otnyTBCgtDL>*Q{Z`11f?n~t z(o#ZTdgja}9*wHd@%Bb6xH`b%aqhbv)y9pciU;N}fvy$xNJsdeZBPG70w&pwKBn+e zFr~(xO56{q{LS~3NVDEOnC;V!{Hc7cNY7x0f6cEwcQ&Tg-aUbMTW&+Z#ao~|QfVtC zdcb4A*9c~<^#?oj;wVh(Qbo8+n9~+ka{`UKR!kH6K+!F|llqnK!?8M3mEJws0V2VK zQG#tUZR>MW*VwO{=M(5A+@3B$$UZJ_()cdn?OKaz0f>URHunADG_*}FDzXjv@<>qw z2+DuXrbM!a7uNbaAdfdUl^aA%+8rNos?Z|6gV$?hq&-QE$kqqMlawu}C>wIHFbJQF!xRX~*I9wvB!g<$#tV#|^h3m}TYxNLU41q-w3o!+7v9;tfQSr%N8Om^*aKdJ#I^hXX3uL8l;?5? z)1~P9iMQRvKUtYyH-2R!9di~S`T1%hFO5#8xeZQVnjA*+b3v}2!4o;WfSCn&GVaxA5RvD?Xh-WGV{Vru!ii*+szIp-t5OkNjzmDc))8W zf^!23Q=v)^J;4;z0$G39_HhEw_kHq(=f`fukYDMZJo(Mp>$T|eOn2YZk)$8c0Q}*C zvUT&OXFt*0zLN<0bZ{gX#)9dLX^7mI$o)Z-IAMA(ygSD(3r%YDTj{y{O{PL$fR zihe5N=tdEvP;*#FQW=Lx<;MXKl;mEAkSBQRN&adw2EqEFmc5AZX_%~eFK!8b! zNF7A}6TdfGYCO))J?Q1s%7Ilkp~7>~vXytFhFH+E&Cs=!*}y?#QadQ(kTID;2v65M z!Dy01j=Sya!Up+=tTcxwYEVTug8>XD$34C=`bSddGLqkpTngDQVe;pwX>FdXP)E^v z(G$Wg7-50ENH=Kk3;|oh=qZIXTboc97yY2l1Wzya1V8Px(viT_z1lfPg2@))FWm2x zx3n{-wKQtrjBYoA#6|-4)rh2>S0>%XgUEbdkd@;$_71#A3obkmlcVqIB`**dDR7`Z z+r#zRoKaLfh!C{*4oN3F=c}0UEm$D zUT38W<-D)XT!(-463h-trdtM_GT!6FfUFmXYCKE%b5~3ay500%1cYup0PyZJMJ#|i ziPl2T!Zaj0Kb1HC8je$?i$zdTIsRrPi=Pa-c{pg3kcdRwlpHdOTvadEww+gfs&;yY zV*q`ly>A1H(N2wWpIM#W35+}mB6zkf+bw;wz}lmt^Q1I~VT1O!9=@oi+}dKqd?=Wl zE*0hcIBlcA*R6evJ zTlkFyh#)q^WxG9l#$X&ZIIz8GJUG_Q8lb}~|C+~yop1#Znd_Wxxvt=Sq9ZI9gIK35 zsi+eTseCoawclP&YLXmVq?{6~V6y zJMg1}ut@q=IiyN?5j%4fWo$Rgf`*Qrmt%zbTcf&ys10+Nhi^7%Eg8gOSUQ)NAoBz& zuX>#OW?7>$63;XqWv0r-*hKHH_h^^G@$>ls8dncf1Uzt0A3BQ)j4yCiVU6|Z!OlR& z)Y=SRhSov;*miUY_t2ss1h1+RN2|d&KMAke!fNTVkO4<$Y4nV23r=9ARckM3x(^*8 zyWSaOb+H>#U0D$u1*9IUvHid-9Y%-A(b*JCS|qb#bqFz8T&rh-q^f;zw8-<)i+@#Q zGSac0%y4uZ(5;nr-78SH*Vz)3_iW){j|>5tFvRReq)45Tv~LtS4XX383Z7*NWz-q& zAk$Fdd$nk!HjkXqxg!Bk#D^}TG*Xx$E^s>(UyXML=mJ%-WM456+;}^0obW>Ud?nf| zPb@0X36foD%HG!&t3B+dw*d*QlD(mdqYEB_v~C8pnfEWb`WQ zrmS6rsUyIu99Jy}Hgawzc^^};e{>-}bE@wC2_!h?=J~v8DteE>&5pB1#=)z~l!@uA|G8VRe%hr&p4RDjH=RR+by*IB8Nd!2LUsfCR{7=Fx zIu$Tf1cIah$2ZLu<)u?@$yuFbqS!%O!v5&ALF;DXu@l`4o)*U)q zpVWD`$LQz_NLzo*OAsil@i=ysE4^PYrG!`he>t{Jg7aY-QC=cc+Z1}~YUX2JHPRDc`z=X?9E;n9U+ zUzz5R@u2Zpd_&w4MZz+&gc{L{*wk{&>ZULH6&<_;Lft#<7BSB*VI=TnzJjlT}pVXhm88|cM>`%5v2FYdj1asaaff#zzss zprK${12v8&fHC8yI>N0_csf+gT(W4kTq-c1R~e6X600m(WcDEAn>gAJe9j`)bnQ@~ zYWcsri^SrU{TXka@DbT>?g~c2PFQzag_ZMFFIsL9uQshfYdI_MG~6NNZbPqX6W3us zvzSUxxn*U-88Z-UIoY`y`o|4i_xh+l*=z26a7hkKLx}Q)Dab7DfO1S(jMat$h{4KF z`;D3~+0E3r4t0WkWb^tHRMkk?j5b$hC2>a8hd?IL#VP(?Z!~3acdHMjDYjACmI+zL zY15_HkDyt>t_YBq*mVlU0Sr(!j(%+A9((TO-hv6q7lqSN?|nLd(OzvVJ{%;+?ueyW zR_l|3JpkHM9B)w%#;3wc_~_!58ohgC?K;C^5JH{L$iO=G^07ZiyefZQ%lEfu21muV zhLh#;Y`-?d(VXB{GjMIkpe010jFMkpO1oQyT%>bQ|D1j(B@4TA6oU@_Wo3XNUTRp8 zoklkof)L4;6mcPUAr9W_S5N#|-@%Q=ZN4uqo$OW4V1`U~0j*reoURFMx?Tk~a?5S# z9j^Uz$<_@#80lZB_?j}pX-)by9mLa!k?b5p6H?OFxjJ{BYbo|4_x&FU!X6AY50o@lH%L3d8; zS6am-$mt3!&O7nsERU<}I;1~MnhJ<6lO^~8zF#V!mL$~F03DVgklaXxM7 z@(PCazsptB4gD`EdgUwk#XU~hn-x@NWS^Stu%s)>20znk1k4NBQT8=X>fp%=kv45z z2ZNuDa-lSTnmBsiYMOM2r8LhPHtN%Ei^V~ht78R`fFq|rw-tt7d!Z{8x$AKsJ?fah z#6yMD!zBWiJIjvRN@|boiIbc2zzWH|rpkB7Kl*x8h?Y}Ss-PF!B+Fs?VCb*2wNhJB zH1w5E1QIT-32)+Vgznb_np`$uLK9EGAD^76=Q!d*EL#$Q%H^2Qi%TU0dW94!th!#c zdaZ>NH%r&wR;P)9qSj|jmKC_Vx@0M%w`-n;p5MC4?R#Uyd$kODdVY`s3+`m+TXV|Q zU~`C6A%SW$k>~`Hzaxt|W3?ltNt_7@zKQ4VlFlr9Fu_))c}#EWg;&HgEO7%ZNENmC z2A7HohDc80x|uMT5V|W*Bjr(|6Vx?IP)OQmU$Pr<-OM_prtl-h*>42zC!D}}&ff~* zGZ1mF-%5I=#nHA{bV1xaz-(pT*b}m*sIjzCpXvbnBrC~c3lqon`jZHzr9hHBTlN-1 zqt86Ol=FKxn%k97o2SQ`KinL+UuWE*IiE+ddxTpuU3Q`l`QRa+gBNb6GS>&~c}_$m z`NPv10#C;LT=D)&1`O#g$)b9TE)fjr=M4zGx=D+aaqb0fru!<4pJC6xH61<&GV=fK z&(kDs+7LCgsBM5f57nh&*e`?(_sl$H_&=E6p(FcOLx!#*B(|>n%Ys%OBsg3}gWss{ zyW20=6jdnSi7EYwfjNj65hRCaU823F-W^l}?9X0^{X5!fk!s}l+Zzk`x1n9(mY)q@N^NGcdkfzomf#w*K#4tU))={(?}7UP}tl+(2- zaWuwScYrvfV}x#jFHW0$*c3qKST@FS(-_doxcHV&$TPl24+=l$vT2Uapa^kPD8y{A zh-P0r%b+fgO7F1R6Y&oMyUO8u4yt?e?+`A8rtN?Zr6RIxGk!8evIMh~!3UK|(p1$h znFvQrqI*n%D2(K!AntY6I3pR1I~D&8yCoCK>Aan~i2CE>dg9Mu;+L)u+GU?N1;Ng8 zJIhqEv{XI&wHj_M@h){y-*uL&eK-5}8$%m0E57}zLS8-LH?nTP*DSj_5QfjKKT;s9 zD2gpdyFL4JDASAPn|;m|qsM-L>D==(N3jHMuy=12783`>vn@_B{RQS?qDbT;0eoA= zWfF_ZJ-Qm>WI<}FD(EcKFiVHJGag^~t)?T1Vu#5nP;nq(b^*aLfPJrqz-$QimV?|HK#)o^ z{dLAVd}<5y_&_CHR$EB^QOgt0GUgDnhjizF)?KWd6_VuXxmKcWFqn-e^hlm0$+Zv!6VxVlZy^ z#G^k1z5T`HL$*$fOfgE^w#Xl4-rBZ@hyK@3Jm!LJO)Sut>OrS3f53EDi^r5KHCd7H zD^N=3q(YYTK&uCa!aYJP_SA}&&ty6A*Wp0bvOMU0ir`*e3YRZKW%LHX<(;_9*;XPt z0W?J^j-|Bk2IMncs!4R&0LYs*mJQL{^kUCwK!0_y#r}70lw}7t%b=<_O zkPjaf7_I~x&k4W&kX@|fZ$+Hg!n5jLOP(^Ke}`cW^o~Oe%V~RR%@9sDYjbUD8$E+q zfayX})k6&nlgwj@#lQ;IoK{T>PB1L9Ygq_(-ZcwHNi!NzUi`g4-|`H1zUM=qXJC{C zVP232ejn0ZWgBt%INGvTHve7)Urf>)^C!3VHSSI~)nW_T=!|MJc?$_TR^6Z_1f*Hm zl=YZ_YzPOjxDrwN!d(Jf++>r_-NFkH^+|&suIqYnDscMAon@L%GlW_AnZP=vp79$@ z<(=um%#oWoSa3DCYw^1yia+r2uqA3eFl8y^-NN?WVV{b^sx1Ss1a}MR85zmx%qm?= zA3A-iVncRisNAmCW8|Rp$~@x)m;@m?Fk4t+Sf%6rK+RKSPy!NHwE1Z*eDd`JL0Okc zkE%dcb8FcJErXswx-{^8G|jbQrW5(hhve@Da-*iwXMU14qN~Z`26@^l{W`KZ_+js_ zKemVo1UpVNOP<$+ojzQ zTxI3M*uBd1js{8%N4R0H2I3B+Up<&M9$?kW;kr;PNi?b!>ntU@7MyQ-xX|p`%B+@P zjlUET>rNS*5y)4OVf@Zsg}?nhhTXK&u~Z!jd0(-B548E!H9^G?3MBW(MTYVt6$*~D z5t593uYSNGSG*F~IQp6X0-^GqYXR&ah^|O>C%KsRj6Whz4t6r4#jfu4J310B*BiF7 z?}ummxisfdZ{ek@@(m0g9ZO0Pixc!7wPrDfhO)jAj_-1JDiFoF zanh|fG!OP--^VV?kRKSxVXHpubH-!f9aBT5d4i*qb^qtV%B0pb3MuU!+$9H^Z}ri4 zHz@M@Y{GgJ16t9J9T5B`he0sx3b1NjBTA>TtA=&^ZM^-m8H|kV7 zru?b`3^H~fRxmFg^U&-4QOkZ_OI$7F9t7jq5XZX!;rM#mQp)sYt}PCluuJ~MqxDu3 z=P`+hE*PB)vsEFWN_rTVy#{T@{;QZoaPy(m>vo6j^%SU5?5$83TfgsA{ZRhsf_?-u z^=6%JH;hZFvSBoL#f-4;>ZgccX*~O*?j$1Aw7X=Y!rpyIP02^P%&CQHESQFq%>%F^ zX2bp+u%MVv&qOwD*nNC%p_fRc%J4Yz#Kl$Mibp@yI8M8E4GY{!oA?vCC7vs`>F_OJ z;!E+AcbpEMJ{*NuW&gI*2}v6IiI=8^82Qq^^U^^i1318|OBMOL{vjtrq|No-ZcAFo z@ua(!Xsi&1w=p$72J29U^kxsG2Fzx>3+;3w2hlySHKk_gQ1xyl6JDw6n;s5g20 zl5cf+wn{pa(SsT+0m8Fozj?dWycX&S5X2r}ImFX;bk-_{Q!U^Er*5nLuQGE337KE% zQWO zDwk`ka6v<13mW+gNsyD5FGoqJ9i7o7&D5>QxxNVfsX~Jto73`=gnooe4%2cmx(~z# z#y0pBg zq3mL@9I#0T&UxYp0*~s7uez{v`|-gJ!H)=Ja}2!o$}>s9$r0C^IJ1v>1u}12)S&;s z-t9-}!Al3|Ih@dg0-InsxysoD&tIQTI}ke_@Q#|oF+!g>zf%zPm6!~;Zf&BFPNA*D zg~E(@<4Fr$sVYmN;(?Z`!t(kZV+)8{d$jveZ%rr?djk`3r(w;NS{gl>fDlU|_Qz4) z5TSxExC~w;COy2aMG#Ote?^v|I)=&%O;>ARQ-bEOlV=dQN{(II*ZHlhX$=B#Pm>(e zy&m`5d0Q>VkJ)3~-7POC?jS!wkVGBUjNme2Q$mH1CJ1vXuaoqpDsk22G*uECENd2_ ze0$464@dwUY+GtB-fzKJpZ6kT7(DKA?NZr?Z=CG;j7Hm$Uc2Ydb=% z#FjKa<#2WXp&h@v?hT&N`rE{>wM(VSg;51Urh5wUgPk>nu>E>k9S`yKYhS5EJ{IrL z#@WzAMWl=UW8$}=EAZiR*1n4NN;AU>o5=qVjUCss7i|2UpCAdx3Ll6GTiAD0+?^5lG|%T5FBu> z=vvtLrJYnh1`E+AZ($L_SfY1Xft=@vDtI5%H?NMM1ub&*4j#(?VcjFg<6*bfny%BI zEExx9zL_@4kg7^2U-Yr@d`VEDTj>vtoL`~c5E(ZT?a6g*&O7iim;JucW01JJWg6O( zKGV5}{TfDY0deQeQc^*S@y>}bVEn22rB%(m;1fuzcV@aKB80`0Z$T_}B5x-)2vzZl zh8jWps4dYvG>>ec+p$xhT4$D^h;fgHmt3>LR~4Q(LJ5 zsMUA5-M2LhZa~8nT=eOYH-q~a2WGq&{UW8p(LH`?1^93!xKFR~h5s9>5OK95u}Un+ zKTw5w(parH8A84fx=WDnk3!K+-%{#h*&JSo0+b%_g`&)wX9ARF7Zr|$rab<*!3N}s>p{(|Wj_i_r*Qc=e{dtv z<@gp{O59O;E^UHjb8*Yq$l$H%lOP4@fmZ9$m>R$$oej)QT%7BP ziL-I`N#Fe@YfD_$vS^{tPEtbul0pui4yKMM;`LkHuDK>^d=3kd*ji0T+~lolL*4$2 zekzdZf3KWQ-j35}r@D#k%rTxKfJTxgLd5|ny?!dB zQZqN3<*N~}7R`9d>C7jWFC(R-lYQv^Gf3!T^vAHideEGdo>& z2|b@xc)^nlNZkQ~&j|`ZND_Syz&g4F$LNZQcpK(5+#I-stH28l?Q?7rtZoDDjeKtB zc{KAn^4`WpV8FkvW$a^42tc?Py#^~XyLA!D z6u~0{0%qHwHfw^OMAYhBA;wxhM+FK2Rk{tWTZ@WTT3Y~U{-G<0oOHg@r@eH5N&6q@ zFY`0RzG~)AzI5~Y3$r2Kqo!=P>DawS;eIBun}3~dm)12rwmvfd6mwGB*c*Mv6qlp|KzObTIQ!+`uW+50B;m_)HDpxvyg^f`DvGJ_vS( z903nrf6O2t0TC5Ez3-V2---k)bTjTBQ5Y-muLtevHUI&{pJJ#C`pk&d)`kX*cv4(xZ}bnFv|V7~|nLWH$KpK#D`%DdbShM4>5Bs5If=eLiMiv$VJ zecSF=yDbT27T^b$7l30l9>Hn_I{-%?QG(Dfa|o-!FViO=!~lSRUV!sCgQJnqGZ$hu9xk?wj%$<%P~fm9vy=(>o`@=iV{|V6%TWPe5EAzW^HK z82|<_H9Rg44?#kNbq?hF>>r575h134Fd!ZR5=^5WfSB)y77Sol$|g&@5PQHolHSyX zqHilg1SlZyNp84>IwsBlgsN|4Dvj}Zh;u&7hxi!&*(HH#_jD>i)Rl2;v*PF zW==SxfpzfncxAjBVX3+mTIn*ZJyIHKE0^XF{e`4WwN{lRA5#g`-6UL(JEbTQR{NI8 z37QiTD%V{pUSsBSQ$Nq6&M@$A^j3Dtv=^v*q%ALp3mmpu3#3>IHQ<7+wQR?Z%pAe67=4NKbc04yQEM zD!}m*^R}JY8}*SSZE0J!e!f1xbF-Z*sKQ%wn*ZPE>DkIaC@06cLdd(z#}i=452O~V z8No+3?L%jiDzAUDqVzi6MhEyLc|EIwFkRky^GiW}tc_;cI^WjT*LsGR;yAJ)QY|*q z!q+jo_!0HM`&N3wDk&u-F*t&7Zr&(ub=#lCZ_yL2N;_pa$vVykJ{(3!$quo0E+-pa zVl@^EezcL)rM6T*x+U2zU5}vyW)7|XN6Hn;ic20}TYm4-%iX_jPY_Ve1)H}$4jJ|W z*A|vU&mCPD4(wT6*Lb`O6td3x#fu|z@^hFqi-gEbTgJinp%2Wp)F5)ViXVu+&&{Sw zpER?wE>^K{irmELz2{hW1Vp)gEMjYPZTtAT?k{PKx_nk`H^%arB0#fxrPUfIK%tRU zEEl;I(;4-{J(f!pguIYT&tP4WhF3*&rug=F=lrqB2g8$unbpoVJ>n=n&qRaT{^Q4Q|K;o<$*Mx0-(2S zii`GmGckTU!BO?wzU{EcbqN(4(^KCHZ>KOpjWmUIFRQpZxXp+nlg~)fv%z+ElJQ)f zN9YC`gcqb&=hmO;VAPVGQm%JBiU@0uCrh!FG~cA$-|EW1sFx{>)7Z`2Ucm27dpB>> z8(h>Q&T;73Alc^HFDQom7Ye2pS~XagU4>xN_Z68EtMgcj?)P;orpn_T$}h9z!6{C) zZ#B-+QBWw@eO9dy&N1EX>S?pYn8Y2j@Dkw$Kf*neJ?O`EEUnhH#cDyZogax;J3Q7Y ze^$mkCZwZ9wTDi=YIzND9u(fTU2pV`n~jy-MQ-n_gD~C1cF*r-E=&rUKx@gaA{;HLdCI1k8 zIxNzl@+4z>QY;xbOKGe;${RM71c(lcg_2^GQ`3vmkI+xQGaRXy*;ZH}4t7tuaF~9w zH8Ai(%F+0|-Rwn~G7|2>LHc+rG!WG>a=-oEzR;5=9CA@eTp zOKmaE-ucN9O(Mrm!xA$v`I+~14TnCts%e;2mtBEW$D{c>Q|u*aTNi1i@|2889RENX zqp^#1_Q`F!t%;V5f0*)WyOovaA--Xe#lrlx?`3#VFw=AlWVZo1aeNw9khO3bF0Xur zpEG$ezN$y|O(y{RVB)~W?^nEcx8*5SyHmVIviM@OjYuFL-ZxPu^kijfq@>btO~1;` z1$E1o*8mZaW8PJ1Upu1a=F_gY)RBNSd%*!?$Hb(T>@g`blvhzep$b}BgNUb5(TAI( z6w@|2ACtX~C*<1VTg!NvbjtixK~`gMYSOTz-F3yLRA=zy*EY1S3fh+=$cM_(E73xY zbBt@lo3DYZ%TgwXw`Wk$rShlpADx$;OIt{oSESMcbEH%8%B!jnZ%18O!KfN{uY1bm z(4_Z#SdDn34T~C$Bn`X=#?F2QkLg??zvrSW5|`7Z-YqysR73HcX|STUF3W4qK^W1~ z5l|o1<6tY*qGIJ$9j>XH45(8`3Y?_D%<8TWjTs1!S&#l(eYx(yg!%{T1%Ix8g}V{&GvkJDygpkDufD2YyG|?X1|o zOEE@T8Wo<4!B~I%4r}?&Q0$F+P9_$1unx3}6I%K_`AExL6kG`-0~&sBo0)kMcgW9D z!}jwlA|>8D%XZIqv87SDL3KmcPga2Ewbb@~l7IGjGLwbO{GficE0hknPG}{Zw1;_0 zq_#_24O#t~R!7vwEdC9SL#s={EPAsE_jsSGBh2;W%t)w(4cGr?Cf$pZ8w<^85?b^uQXJhQX4()K}V3=rq!!u0}{PFyA1 z_|;e)1usa8~gVh z)buw`F`}oZ%4>7t+U?GXk9JYv@CiC{gIE_*{`u%l*8ljrSPriP)sHXLU6o1Gc>nfj zFYlvUWu=776t)MS&ZA=6|EeR9^XT?&YV;3%1?>_o&!K(x?I_2Z6g`b|wh6dz)$FC> zJB;ud`380+Ue*L!+HhfZM?gILAr&KZh+SI)8C)^m~C4IP| z4TD32<=BdKlLWgpB;AJpI&I_F$NJPmSoL;r$=uIClvYi*>?}NZib}^SwtPD3NiQ*C zl{Spf8g_u-=+u<9_@*Cg#`)arV5vFJ3xpqGHi09nX{oAh1pyr;VK(o4EAe^MEfMIh z(PW4GC|cI^AGH1!PlmqZ4XO!We-C%Dy-1Ic>`ufjZ)j(J(yN<+5-!@TNN%-OP5+OW zVW1<;SEEu1$;!g^5nUS>EfM!6h@i0YLzK@Y(@crQqx6HUqPC0V2Q& zz(E0a2BoO|gXjf7&kSp?u7FMe=QF=Rm$SEcG-#){2CN7s#^69q0lFnQx;{JCHa5I| zWBW#i@3ryoU=q@Qtfl}0I;R0RacOV%{96JE z9KPA60aR`4f86ov5A5AhF>N7jfn71-TK9MXH~{nn*xkGKEPu<{v>Z$W_)7zIYj$#S zf205k+FtG*5KWAqUSG{x9$elGT-}-sT^+xw_-wVg-2>X1vVj4@O~*_WJ1R7GUEKRfwu$uf2EAAZ-3J3 z8aq3g`X{#GjsZb3gJ}lB@J{jaZULJ5O!oB)PG|(3r{!<5^y<=r;>tFp#P6@eM_<^foLgM)uk8mvnOFbb%3>8)7iT8-PyFnx z?&>VKMXBAHq2(ugi~kfV&-B12Jz%3FNYL10y2ROAq7%p+-QS;vPhVd^4UTrtUvY3f zX=!kT`5oN;?>1}%nc-g*7_(pZ9so8}N=jB&+p=GG+n>f{Kus>~jX)cK9G-3fXLfdH zeG<2OI)}%5fG^JeXj{6;7fdv z*@9R6VffjCAMn6pi*LbwJeMB=2brB;0ze1&(_g`yoNWV(qt{Q4uQ8yUl|y)-HM;|_ zUD1MY;`z;^_?#>L$G)}?ekg~`v|mA?ZKIE?Ze~eatJs#2YR*Nfc+Hz z$%A7cbD%73FRy<;q4xotAX=LpnqFL*+(F=aC`^w)?T_+fq8zKex@#e7htlL+u!p%U?2FVjbGrP8=POjft#;lO*n?D-|+!J zy4`pAxIJU1AATo?;9!p6A4VuR25LJ0<^2M>)BW&O|CYI#2l@+tceq}#b)5h^x7l9| zKJW~sHU9gy$g1)t@OyubBY^a`ctM8%$PZ>aJcrm@0rIY2Js!OJ=&l|9^+SNMALJx( zo#OBs?0b1@o_#%@?%dx40KB3zeu50WI)5AJ^)LJd&VdJ?e>-D&|GvPvz65vqxvuV~5BOzJWCXuUjYs7E3pos!7VQ7?oj>7E zTJZjK{}tX=QqmO956zCw9T2Jv;G^#p>9Mt|SuL;LH8|9*7=-dp$^>)!_h5FmhG zK)SdX)Ksbv;%la@qM9Hx;lfH23vjgn&ZFo%f|5~sePL$=bTKF^RiI&M;Vl7YThY|m zT_CC8Me#=`pA2a2;Y3_q>t;DMHSBMiXMz+0V^++tM<895oJQQFk%TKf=}@4NV1pp& zn~j{g6gj4V`ImxJLDwB$qVpr_6H)MDd#7^?#A=sK-Vt$JHgVb<5tt(U!=Vd&$=DUI zoKw(yz%bHLj;15ZZaYzqv_JkUn~6~7x-!qVTiiZwE6jJ#RlI2~ut%}R8=eUg#G-*! zk`*>5zz(-D3D4cNAnKRPc?KoRc#6`S-rT%Vs3m3R*S+wd+H~d!IAHA*0I=gtYQ0Qm zacbbV47k+*4LK+OOb$ghT|+z{(fF>=MGR9w8>eU=N;aO#Uvj66I^H|ByzE!lT$s^B zJvPK!t@LSx!^Lp{&b|+g!cpm>Jo$B$L=zBZ1>sQw((Dzs2>T5i2AM)eRS1b2&|M+y z$2@(||oyQ3Ui;C17bq{{=%pyubF0 z`k|Z4mT4sl7T45-0DDtN@%`IH%@xK`7Eh_;MDEX<*)g6;XRW--xb`9xLKAPzVww50 zH$LwiElwEfqZR5BeIa}M!Ni+ky`pjI>sVqtLx0mD4Z3Qp@_J*u?o!;-T-f4cCl zEYb5K;N8x;peSEE_<#gmJAInM(FBs>)a>DVNt_Q#+mS;;zJ!5( zZYAwa2!s_Oesh~t`33TF5=54yCuX`o5XMQY@KGdBGzKg{!&; zS4db>z{L9&fQ$+fbAXZnS9jXEOviJ68^hFp> zEajqQ@B`na6}}9h_N;M*3`^yW^X@Ymx@}4t9C%qW@QG8&y`TX|&DfI&f0Vps6Xqr9 z{Wf(QLC<YM%_VqyWHF;TzWzZfY{r zESm`02>VnaGkUJ7*;bjf$AL{q8Rz9qUjj3;nn5KC zNA;S@s_PUYBe$SLF2a0%t527?`>AS71D7IaKQ)N)k4%88ZXh!#18&# z*vF7xRDid+0o#GKoVg)@((l9@x7A;pdrfbINK}1Wa*o}_G|NO}Lw!Fu6iaF)4O^Xs zEMClDVLIkyat_r;$pL-WfpH^Ec`stetT+DjMQaQ*DE=qQdpIA?=>mO4Y*fvz0t;ei z`seMh*`;W2Ay~ul5Z&O_+U{W^M~%Octx&d9^Ga`gY#(P#NudmZbZzmF$V*XK|M9?k zd}pArEl$0`GcOyrGs@0;>7s;3N#Wa#^`@y5Vyac>mV%Xmi(*8;ZHiE`@b-pO)+MVI z_ZYiH3i46y?Lf`;gpfwy3%0=a$Yf%U#tkuKXLxGHP_KHqx0R!6w?FcZxf()n%rQ>G zW-QvN0_U&IEq}Dw*9*4%Bavf$`S@wEpn~{)?pwuF*=S|Cc*NF$Ad8-9zDVJOFoEI(>&S}hAn`z_K^0^Dx;29w=n`BSF{$m%-8qNkp`U+yN zcdkvm4ijIlb4Zxlza@8eSccL<%Xor(1#O3=q&pGD&NAxvD|J3kse0AXY53&`PM%0! zVvtMcC(jDmFAt$WY$E>{eVWa>Reid6#-Q6cMlZm!1V;eeyu~V5hT=WHcv((4i?l1i!uH@R5#Dr&X;(zGmK6+^j(X0cERxF z)C6lBpF-zq-=7TjAjr6`-3Q@UkoL+#D)O+XI|zt3)vJRDqyE4QtFvTzV>Lp z`^DkS=sXmr0P&nCuyl>YOO=*Yvd*anHHO$>C(q_G>WZTG!ibYAL!^CE$~ zn-WP@PcBMxi6oe>*DZbz#^h4K)8=*ml^4}Mb5g{AU*+rLBGCMo>rYZKyhM_PXtngN zLb~3H6Hjew$OgWGmiRd_;&L{&L@C_S&4|hLJwgnSfm%4yq4O<@0U5?NIcKLrqZ#Ff zy%!O1{G0`^ySdj$wH42`?wuaKlVQIMBw=iG8$92z>_H)s0a-~SMMD@SievqkZ=(o# z75a?&VtcwWL{MM+QJ~bT=#v3gK_z|4Z;4No5IpnKD{Yv^H9qZ%eC_>$)h=+v-1izh z_5u3_YwRH$8$kQSPnsA_ikhM8jHZAw;|dsWocfmktKxcl|@G|OExBa^dy!Y&172M`Xs&4HT^o(u+tcD zI&%%hw9{xx>bY2w4xPDkYL}s9_T^iSk`Q-_Y%g91FT^>GTIbG&%6?QAHWX3qSUMW( z`J>$q4>CQ;hp%Vji>lB0{qpsaGJSg?n?lVL%jz_+v*Er3+b^gXnsHmH&z{%QxR3}b z<9T5)XT!4x&eA~%vqECn3_s5ZV(S)DUnSlREIQn{S|u5Q-(<>Ld4qn4uN@3~ONo(i zn=gl&^LKr2=kwz|OtuQ6T#wd6S8gmyq`i$Nxt&U&&thg!z4Ae&Vv zovj$@v6SxsF=an$U=^UVS_u^;&f|wz?9a5mM)-({MS8QX-7775V7^;KGO>4J zC8PDQPpj}f5hsc_X(SP0w+utZ1f`y?b>tYuA$W~wRp zG+2=N!hQ)k*L&D@?`q-sE2_{m*;~p3lVn*ViIlo4Sj1j1Wl4~WJO@{CR>dG}-20$# z%kTQ&UC{bQItBL{5WqCkUaM?=U@P3}L6ngkPxat^MbXH$sk1!u27!ik-N3hBS+?lI zc(-%i`@@02cg$Tt@x&7$c^L6D$w6L39_nh<$Mfk0-xT+}m$w6H?~6ITU&*+Z1h5CP z(f8Y8#&ZQ|QO^^X8#)ce)0}jWeK?9wSmQk8u&!^Z3>Ewa@fsocM-W=pzC(l}enfzD zd(3!jf<9}FQ(Vna)E!Cj<{9diai!waum;&@zXFBX=G@iZ*6hx~)XCdIQcG+(sy>d^ z(Oi`ltiN{(slG~${h=lg5+Qh1lwj@HfP-FUUKPSQv0$*&JCmL#(;;b^yEg9oJU;dP zzP^n~Y0&!GgQ@PFNYts0ZTRG<`Uvjv_}6vruy-*>%OsN*riIG4D@?Fot9shEvOG_^ zw19LoqCUAQM87mD&FSfX%t>#r^)h&1L0&e~4#6f<^Dil9qn5}2KzK^)YFX*~Da7|O zD00~(HrjVw^3zm%z|j5y0Vp&fVp{XC5K)AYgh+I$uYLS7$36u4hYP8IReuN{#K z#jL|924{)k88zpAEi+o}4=hKs_{e)ln&Mhl5F_||a`JCQdDTxG)ar&4t~y8V*4rN2 zy(J$Lw9l6+ z7{?j)N1~r1zTEK9!Y-ZSg<(<*)y2cD%#C8WA zed+u7C9o_14J~5{-RE8W-gE!Ft4o{`$4fci!0V7@G$b|b#|vbd_1h?-p^Y$$IvY_Z z`h?jMMB}Rt5jyv)eq_FfrLeefXdj^u3Q)M*gROSen;s`}$UZtFkrry;!8RpmLt%^* zLj;tCdge9g#&rE~)USMyDBwV9?}3}PxfYdp+P1D9T zK#*Ehe3Hudo%=^Qw>Oj*Tftm@{-v0kX}?xQxIVXur7hbq=fMCp9!=qd4m;#H1ra{@ z%^y$%)u%8=jXQqpT90-XutD{u%3m4~{yC0Eu8xS2Y7tO4@jbuc!bl9`{WRo)f6d~D zeD0-r^!YZO8jjq{IO1NE;NC)APLPBp2!DxRr#7-^6e_W!M7Qg^=*b5 z0&^s#WzICyZP;z@qUXh|hc-d)oqq$pkS8RXj$}#fA)Ak%?7L0vRN~lL6;Ejc?~hVG z6IG7k_mr}l?;8yDHm|0Qkw*)F?{eUa%@y5uCy=7lj~6cP=G)YGHk#2Vwn=`*FnTo1 zg%=}4ad0@Ry{RuxUZbp)q_^9Qp~ntzaX|U>Ch){vS{30i3}-@Cj;lnZVy*TO;q1D{2$R&7vMr@c)$(?l(ICHI#(S8 zVySWoX}1ExWh{Vz%lt~3-8HPlMLn7@&b+v7|F~49=cZ#gOPDCS@}`g3KWX@0%E(*M z`v~#&%LFFgI(kAO#-hQ6x;d)w1ypAD5T6L=EGojTVSZuCD%_kW7FxEK#zl~uz09*Z z$)*T0%N|iYYtmuP?CT+Mgs_m0wtQ~z73iN;1GX;cJDPmo#H@{qTn&bs|D?J!s6mlG z2+s|jQ?6{zY)-XKaq}ED4-z$C?kLqsAmf!dkShBT(yS2tDeT75G+KEgx?pU8M~O z*-N@3N*fCO_XBL%XYvTg*)qB2_2hhvr9@N-3K={3uk|EXdADET%L?-oY*ObMJ44_^ zd30-Sr<>|{U}0A2xttW3)$F}^+D)fiPW8Bsn`}5{o%pB21$ zw*Ui&oG;9r&J2j~Fw^#BLY@X+XB`Ex+@^{LlDoP!kv{bG+$tU;^LQ5JzV-kH)99(z zr>jZtD7#XI<=lk`RvO5Z_e1#o1+QP0QI=7F97AnR};Vpf<+CEv%SR7cW!ZLRGi-5m*Ys)3m z_dOqJ=kQ$Dj-4b-T_meRbuz7*3ygyt`+-*$EoiGQ!n1-g@|UXIeYy~6_|&zs{JQi4 zTTVL{Q+>z-e)h5aQt@RsGijwxE6mOl62Q*L_l?<<(e(2|?At9WuDmqe&G);q8y!>( z&*3R&WH^`1n@%u{anQWq=DxzcZLHpr8ePWu)t6C^-ck}pVpIBUF^4kg78wNtt<>^p zpl=19X1KQ;g_(5roo`YeJ$&wu~n%ynk0PRWTC)%!|mo^GIr8N zDqGLo_ipE(Y_RGcjwMaRP#{|J#8ecf%KP=N&BR1u5}vL>h6_IjLrXu0HGlR;B}0He zqRKL#*O-BqYS1LwP8=n>e)a!UFuak{JNwE@_GJa#wwY7aa$v;Bk{{N-pJ-ym_q)%cZhF!H{4x!azLaAI!m3e{v-M(oM421KK8;LR0&ZAnpvRsjkxFuIF} z_T+Pk#Y9r2@)eJcC7|Q#=Y%uQoDTsO83WomY&*Nf*{th;Y@F$@jlrgw;39%mt z;l8Jo0($`qhMO54x-F&~vGn8dS1Fip<*$Y&IFV_(5mz^MT2Fu3ysSY`7>nYg+H7kD z7Cr=;M6M=>Js*uY`?{}~^Aieo(W4rQZ~Mq-l&VN9LoyG z?0lZeZ0;O>dHHjpMY@F_NX9ISkW8O|4#tA9v@?U--)>*p6M*0I4l>H}OjM~Zeo5t1 z-?BqlDB)AF9-`G4tfa9ON+fOXI_)0$1R zRpx~;rFr(6{)zSasxauWcB(1ak`s$0_mzR^3vhQ`V+hzpDO+WSap5n=f~fR3-1ETNhY#Cl ztSsn2j6u#?`V#zbE*i`<_kd*bCWibaM?zVq!MR%jo1HG#2Ai895$fdrmt^^+WC#|# zw{|DLb~zHS*QC+3)s%k@hdFXe-1u&P%e6#qGz7d&A4{=!13K?0kvL0WFvYvjOJt35FxT;=K5Gm@f2a{2hhCD=ubs5;I3iPj3^Rt zdslHeuW{`g`)uM{w)g6d8?Jmz4pRbT`h8)6ItEdNVQ*(PB8-O|dkf z(Q`{&D^ua?)UOJ=Nz`4ump~U?4Wti}(_v|xXWO;ZN9xkXlnZ@XE=vWK*<_~7dvqiF z3d{>5l|=V^2EGs&BU*GevQT?@Jx^*hjb<}k`#s<*ZYfs?;bb+ZWBFgmh~)LqSu zp;fAyL}{1#EQ~@WuQ8jygRkO`tJ(sJ*ov&e;lQ+|=U@=VoM2U}Ge0C1WvM(>XT6L0 z2$4hjE=9Ww@-2XbpJ9b^gCo#=C7=1E@cf~1xA5h|)Q&!Tg`)#CcXXYhRbC`Ah^nS+ zc?Y6!3`Xlr@*`1iH{r=_>EVk9AM^`$9*`gKD0-L`X7i{qC3#Zo-%zNeeeK1^`{N+&Dh9+5@}AcykBH440B%u@*Cvk-f*x0d9Z7D$z-aFRCeC5 zdfnjS*`hXoGB_q>k819Cuy}h{&U&9p6$HNnD(JU8`W%35x4EMX*Mjh}nUeS%l{h4i z+7pS^D{(HDaellDL)7_}pv2N@GNl@7dk^`05)4e8pWAra7Rgr)g+Um2~@%nOH z4zQz48A~ZSpZAp*eKh1%$+~(sS>0^!O!G;>wmO7Jw!3Ph4xQMEzcN-EOLR(5K_G~l zT;VbEQb?#sqZ8(nS$KNYKxZ~|nkiH|-2wi2kUERWf#IRujKV{#PZl)ckX8ywF!akb zt4jrSn(n6wy+GwBPcY$g6=7r7@E=VjzbVB|R)3(UF40ujl$xzQ@jGN2ulx>SMrhQMk?vFEP8}Fd+ZrW@P zaeT(#beU6xaF0@4pSq~j+(4uZ@#r3OHWTCL*pWWdlfRew ze;s68IEwW?qtVEaic{ZA*#H_9k8g;SQnNp|O-^|StoP@6J+!}+sXp`HP{xbf*nN^T zN#;`?CLhN&L%%J}mVoJIC|pu>)f2~^e_MgB(@W%tZH!4ZPT}Oy+~sdzgV1ip)Y!Gk z2L+Vf)e81@7%kNF7rSU8k$QhBtWsSe!kQ2DarAb;gKXLy^?j$c`KQ{8NriZ~QN#xl zxZ4NH`H%v~iD>H)zLWykt-hJVfku{;BiN38QYTXgV*JWQnWItYR|JjuGImo5c}# zvAw__{wOWW6LsW6cd5l^sU_QnMyST&PTZ#|N8A^Jl3_okL!+CkmD){RFB7w6s@y&O z`yGd2VW2r^X3OKq88>F~J*02a_@s!580aL~x3bJfdykZQGRF1ElIk-2ZTNj-gXbX_ zU3bS~ ziVIp0#fp+FI%U10P|=w?(@3ZR#s&E4{Rs+-06~0l`thb>*MQ7dbQc7Pae~jJ&kn`7 z5Ge$_xbZkTtE!>^^(pmiZdVJO=b!lc65{-%Qg@db1l!kcp}C~k-U~{=3z^H$9nm#? zX*HEAT)Vyd!il)l!L@T3!^vZqvuP(mDf`wD_*TWEdY3WeW?7CO1QWO8;1WsR-AHr> zFHe+a2{5}&7e8q7(oD=@M7?Z;=89oksl|<~h>2>q{t(Gxu(%`u&YjsX`?*)dJ@VcEneKwPyk_7#?hp7 zjF>Zj3{lRdkguM1ldd!N5zDdF+Jl@Y2S_S!ASfA+Wq=GiL?a@cz|NrL2sU|UeO%Id z7ux&Ly$1i|3ORQ(oN3^d{AobMnA`zmGQFAysQW?JU1e2LgSQ54BrHr*wJhBi+p)T+ z1!>S}#T-O!ScDXMm3c^RLN)ZFn?^h#x#F%jlYOaJsl;6cORQs-^J$z zl!nO0#3G=#CB4t6$s%>Mz{|FXAz0?=G;EcC3I355&WBb=kNC{~FE z-qfiQ2Ye9;+RJ3~dvsl>Wi3^9?WP5Qtt<3Oj3-LYQ5x-I?jYNARYG~T-_}s#O_ONL4MAkbw zC9$Y*FC(Azz#}T5?<5$`n$VkkI;6FjDWW{<5>YFuMjG$|9NT!>jmRESZQ<4ZJYwif zRP;|f5v~DlrJg)nn> zmA0K1xZ+xSCejKV=k&R560K}6VQ+SzlxMzop0%@=|IB$sVoXC*dLEp^EzC#XWM6kF zj3P7LTvmj)muLG?<3k~N;Q8aI43i0&PZmQ}z~*Yjy}(wap(Ymfu3gyMZd7>55*&p< z@;v#M3Jj0euwD+?Pzj{(d|n+#zqP!!Cz!``z+Fi)ghhK zRn`>K8KjGECIkDqKJ0IaTZ#p_01t`2AX8ppZYXa1r{0a1iLtu$s<#2Y1lOM*`b>KV z7G?Sy!QzuiEbIh_#1IR==v&$iUzQhP#jphrz3FA5nTWz3i~CWH=XS}PtWxn{ zXSv#BPr~7ossVDHnDryk@Gpd>H^)NusVC&jvQz=2n5c>v4FSv57#d0m8OJ4<{PZcNi1BlFkLuGW3#_CKAocWXTRul5ri} zcU$i@Ye+M^;-=s?+*KW2MIHx3nO-cCP)5)^WfO|GYTsricpYMjYga9W3H+pk-XJym z5X(y8Whbdfj=r+O?iAqTzdrE3SKI36^FASZn!*Dh0(vz?7Mtbr@W@rV)xf+zrX~;c@db zqDGTq^~55bdBmlO>oa%c5gEJB?h(3a=iul@E!NB2}Tr`o~ADf3%`Vkj< zyovGi1>S611hXyDaMmNZ1|Kfv1jzF3NFJ{ho$fz*loQ202Ii|wrx75p`qEIZfZPN4hf$Wl9xWt7PMK9ebJ+&jFs5qYuLPPBfF{`W9fD2RcNX$hr`jEcCV>ev~ z)X_RV_&OW7A9x^OG4~~@ZZvzRGb}(Hg&RWXn$h>Aev->GWyq6KqH0<*^klXm*w<8s z7#&+TTO0Y=h(j?Y`^~Z7k{hKrQVh`=yb;M>XzUK#?c0>Yt9j;|%0)&oQvzoAY9#rG zcUjUIcyvO6#!s2FX4YouBzvx(ARan0Kig#&6OQX8YDFS-Tp`Rb2u?;sGG2y%xB86C zluk0id|FM0@N-xgJ}3ULWaAzl!M<2%!nww}!!YnCW|QqNsC~^Me+;6b@24przk5d| z!BJ6ZQi_+v;OA}6QlF=Ub^3{-aZs!E4~1%ubL>`j)W2BJgxAkpb5gy*HKHD0St}@*8`L2AfOmgdj64ywdA!}#z zSb)^l>e{xLd#v{>Lk(+{h>DUS(`0)M&S$lfr<)%a!@Zwu2$F`r9$LRbdlIR*P*{F? zR&%hSF}drd`@YB%Ysq?Qp5)+oTrcyUk?auQE*XNmRxVK}8Zy9MZ4^M0{Y@)=I^3Dy z79SUt zqJ+w}o3(HIiNgoBm2&Ttr9WUPHb!EkI5&PRovTr9ft{O1i0Y&PG5I`v(JIi^yaZ zu4kquY?L%m5R1Fya`ifJ#1f#eZIf(@25!nJ(3XEN%qGtgqcKlWjKed_L!y-MyUG^4c=xqWf~L5<=+q%P}6tFt;j~ zz1B%;7bjt!CD!{k_7_hPy~WwHO7U5XHH!?&EqoVGOvty*#-+~z>v(lhF#aNr?IPKJ zy!Q8;9|>wku_qKlEC^s8$rA6(KL2zSNXo|tNsQ@KdYcyF^S7W`8V;OjH<51dyIo$T z3B<>cPk->oXbb9QwTbAbg0s@V`@~e}ZPxZHe9)HR$0P+P=Q!Z7l`p?{$VnbMJ6W)g z#1P6)m)Nmq2XgUKvPCC8KTn2-&M!BA=)S43#9_LY;^N?;DcG_zpUDmo)2r<$wX_}A zermAbhh3#z3*n)O&mo00G7=>(a#)Si?m34>uu;b&8*XTvBTxzDGXx4V{w9^jR{p*< z608WCp4`xV?zNfky;qkd*evz<32uCvWLZZmCb>^asTV5Q7|3dCcmwr*QdiRoH_18D zKM@m)zBv^XN}JGOWuT91D1#I;>&V_COcl1@8hh79)|_-%v_@6`o`q!pmy6xlZcxTy zm}yrP>j(w18XjTIL@Tzap$W1&;r-8f+6Yc70Et4A({=9TO(DDTkWjF$*QYP|hXo6e zl@+`uL~{Cua=eW&y5b?oh!L@2VdJ6Y0|LuqHzf<|dbw;P3!|colFfqeGGeQsA2%=t ztb-N9ez`(aOJhewJSKDpsHl9IlY<&BDnNj3tNl#c(U86&+12lech8tIZLv zcKw6yo20g<*#m7hKNZb0qi}+sr3cW}PICg_;8~&H--<7GEg-PX07xvCaMbr&uM|%? z5&WQ0-wCF6Vm*gI@eH>Hbe!L!$)S7c-;4faRB~HhA>VlvE-Hh6a^B0-KUas9cbsX~ zRI=Z2^$(5pm<)9xqRBN>!7}c4Y#jM6{N%ugBxf+JK6UW(>;~YtZJoLzIDr)`ZDO&-BnE^n?LXR@32wj3B1H)sR=j z&?vuaJ&*916MdFT<)P5Lc?LdpK=|-*Tz+f4BN3%i?q(fj-pDTEGKfR6K7v9pCV0K@ zhQH2Bxje>hE=m)boC;C*XsXH^Qn>B9U6tx zbIGZC$+s81kBrNdh-GF)18-5^jV?-YuZ^^Qye7$M7*&Pmw}*uJYC1a-kI=?R9z*uN zW%QYd{W;!W6a>)&%aG~SCmRqbOX>-vyr&;{7w*pe zsV4*>jSu6=+M8KE!>dog`o)iQn5 zl-igc0Uuh^X>$t-stN)~>`dSBoyp>y;lDv^UAad*m`ko|CC*i6a!D?E`e@Vp1ne8} z*rnuf1=I<+iXPFok`ghv+X`gz-n(j{%0H25K z(IfLv2lAgCaH+Z$hLh(SpX=3sAW@o zN>#BPLWn5r>ojcpNY`D%2mX)m`@TYWp}O;P)R|avWRZminz@1IkelD8qFqWQeNry) zR?EusF&liB>U~Pb-j^+O3?A2~5^}Ht{8VYoIHLv#yUy5qvSE&_k^{(6pauAz9=G}O z(Cgt|p^t<72duJd#3eua5$aNBBp0ROE>=srB;vzAd5cx?70WMl5IHxPe1$6ad;Qi+ z%~nTH|6x=nYHm#%F4)_5X&ElhCv`NyT7emTPNgAfJ%W|!Iu5ZRva0F%78nSK&EFrG z(6vtXbQD*Bh9OaD`xAr*4sNVX`&%*&i8)&Ci?s~@WN+JKXnnW(CB#-?o~^6(ePjt*_OE> zkRSWb^;3|WNeA6f2{~dImuf&T?j!vXf9n+sW@r zEmmK;VW3^8O>*6;0_7qAhpViKByxx{ZFqQDHeL(<5?7SLuTHsy)r?r;e*9UAcgB&; z6@m}4kKc|V{RHl9u}_L0@_rv(yg6gUtp!h1qXe&H2KTm?4dpcmMv1T6DXN{TaTMZG zGSg_KY(5r>iwMS0O5yfvtob|t%c=KpdS7?c?fu56R!!NF=`Lx>RT72zvwxH_Zq)Ee zOp=}&d6EiAPxQ}kwzFFoM6o~Wxa36+u|+bqWgh&H-1K2P zR!R~#*~cd*?JQb4Fj?ktbHvKbA~u0-ey>#;``{v!bu6S{CbU;giIvi&NDB(^QiTVd zgwnt15}t@!8Kxm+;g{#2jq_}8Oiawlqofj?7x*gtMr$Z}!V2;nKTPkn%)+dTQzPO}8;cFx&<=9&$1JkyJLojB-T7t?4ma zh?EjNhS=p$YHQinJDx7!NnhlB5Hiqc)mvcpreD}P7uqlo7$|=pr}CIKrGe(zFkVaF z>V1;f3YV*!9|-r-sEf|)3T|biDJxqqHEDRh?@&V(G&-VSYO@M4wC|e6STyDVHXXC# ziJ6G%@+B)47Ko!=W#aZs)Xbk2_5cTz{7CuZ4Ryy}6I4_OuI#jPP1!8i#dzm>HkUyt zI7>r!slpvB*5M2YAr93jte#_b;;Z~}qVI8;>W%U3T8q`8`O`I=F^X5nG=5Ij)vOc` z+p-G8VQ8cW$cYxq1nas8(UE(BRFgz`?-!NgO=vJ}MpMx@X5!2Xgm{d!+Qr((G@3`(MAmSuI!`Qjb!+_X|=|>vd4Iv1-)pQ&Q!8ydqknf(2z6+?g8A8 z1Y-@SgSz_JH_%5sTD1aTXgolbN++mLi{E&k7B%|>bB+0#kXFr)RA_uY7&#c z1cchhIpz0~4`Jpw>$8w;2(3QH{N}~=xc5eGie~2lXSxrM2RkLz`q)cPokVu7Hc2H4 zjCc}})4X27V}c z`lJ^#82P2oSzk-8wuXbqFD7tm}G2-pYRM zzT|CtSHdq=>Z3$4@=>`|U|MZHAcSdNK1oGi!Zr+Q6 z&zb4i*z?kiDx>J*;LKYPJzWjkBC=i{G?7q#P`{P>20}-1)kvO;gw>!!ex4+ax}dxf z9PZiNV#t^652J1SO=d+QEz88wDP9wABjq|9`c%WU&BcXsA*vz?1zmR9uUOtnDavnM zWr?i6S${XSNkXW_0yC{H`$H+N!T=UYc|q0Yn=ge$KrGG*%VcN z1IfOydQp+FObeAyjv+`+_ezRmo;8K^&VyuK{-N31I^$WQ4-&7EWF0xmDCnE{PO}2D z7u?@TYvzSz5FpdOXjqK%Y0ND5H>!4gtyojfqY}ZgGwhSok+h0ac?5p1RYgH4Yu4$z zbj136Q0@~H6)IMZ@`h}-oBE@t{P|{V_yq%IHl1cQ;{sE8O{S?UC90_ionYfzyK$^G zX9eG)QPJG({ifrrUx1Z0kxDu9Y&A$w$@34nb;-@+KwP4e&U{y`R1*wzSQnaU1UrgkD)9`4_j$ zP!BPPdb)}EF&Fx5G2@*&%=XNDwQ1IZY(w!;{a!ds-u@%ArIdVtF$p6CNeUzi#p#=% zKq2_rTanfP$xOk%_ntq$t($-iiQi(~}aH*8%TJ zP$>CJ^Op|<9mo^v$4?$LvrCCUoWPh>0|7(A)te!*%LYoDc4ju@2rW`07q<$e<0tp; zcER(eqQEUQerL|sZul4iat%zV8r+EybkOaWdGpc^I2Fh>3$)-s%YB^Jif>qDwOJ0K zcv~+HU4XN78t!^}cVv2yX+iu==2T#q`w#R@Oy)xLSItIerN}QFV|i!V2J$MKvlO<- zl%>@s&A}(Q*H>QWMv~&BFRNKzZ~P3z4cMm=ShBiK+@G(r<(<2~$d~mAPZ4G7M4P^b z`rqulQF$TWkH{qGqY#6&Cw$LF8DKu{LPPp0V0WmABQel~W@;|u|4yk9@+GltxA4^V zO^@IM+ibn9JSyo-NWQKpdkSUSth0+Xoe*>+4`-SvU&6fwZI)o=Gr0-a z)`;VXs%rTr^f8C<3l2E*GV52k+W1kwbknX9Czrh7Y&LP}=DgxA7{CphBRT~P>#SW` z`q~HuqfjQudtpXT!(_Wb8?J7-COAeU<0>H!CkwJ@Bi8(AuteL9swf9AqU7(se?tp7 z%_-h)fG+C+Lm(SJhUH3P{6@PE0z)$4{b9;SwB=tPoPsRE577!w56fjQTSHdNpfx$Q zJ@>5{NIqKGNQqZME-TcfP9fi3Q1-9;Oo;XWFe}MbX{yci`|elLm|a^q^|ot9V38h1 zT{0x6D(`z6UkHn}U^ppy4c3-a=|O@xhJxW>(Alfz$@T5Gu8)cQ=|yh912HpHua|Yb zKt4Nzh22S!Z$H}(l!rVK_tlB~ll}F-$W#B~s@}pv-SwC;KI_M^>p&XvZE`5u=4g)p zrTdd~e2r{~C*OO(rDeZ&5cZQvdiB~HSTqjLTuc1k7hI=&EXISQZ$|W!i_?T6rAS|; zEBAOk_0FvjJ5bjUh|km9sL1*#YFu@N^^Wr1J$bv8#ojGVY-IX7pLY){469?QN)sB? zaY7bd>yvJlH^HOtM@>WOs19|0n-G>u^KzYVttW$HaV7LKxgwXKTABHN352|t_ObuL z?Tu4y#QX;L*H-orHkk;AL4Z3Q*GB@~U7i_4#S&?LZ`<~YR31&=1isHGFQ2UjUOWP3 zirGK?@Ds3c_~^DooD#<$!Ow-|!8Fpztsm1yyYNMBvSd2G#96|De(Zj99yOX`+=LP^ zj&H5Hb=HPQodd0ZvQe|l0ARVtLI-sLLx{Z8X)=w0F3Aum-1S9oG6 zp_11+We^k5orP+h^|VH(&jVcR8|<{JTK)F|AYIeu?iJ&3hfYl|{FH&sQ z{$HTs@;xt4!cN9Oc8A;vD7EDjYEtsL6HodtVgN4OS7puiPvQs)*pyKv-i%_t} z$d1k0FO2+0O*FmsP?-e&8x!mq zfwW+@KGXx*2y_7aC*Zo>bIi8RI8Bv-4WOt6!`JMBY{1qQ_SvBB6BDcr<4slfb@J>l zm;R_qEUEB+W{rOaNIb^KsZygz3|Vwf5&NJ&QFi8 z9Lj!&n+VAb7~MB9!IDyb5vW+XXL(zJ&4Tx&BHslaQN3{SPuNNlrhc0}-jr~DQXd5? zC(ChYk}8qqG5oZJ_6P@O-!1GY+&jqVu}~eMGQ_9BgjR^VFX9UsXx!`l$)6QyUODqg88yXQgB;tML`IFN#!rm zpB{DE?V9!cQ#14lTZIPBA2w%fWw1fl;OqXTH0)QDmx5#r#l=@9_L>GbXDVHN>|hy7 zFBis)EU09%Gi z)wfs1VewTl=QZHT?1<=Oh~)V(3el@+!Bx;)?`0#n)aWrV_fR)Xf(s-*i&U z9STd57DHNxZLjNeb)Xfkav+&}G>CEdI3t+;31 zxBmus_DzJU)>>G*JoJ>j7pcZX{K>~SAV+)*KA4@rZR|T01`Jg-Hm{+pRR=)#DHmBF zqz>?!a1P;-BKpRaxmT$_A7Xbu2IM?Y`II^6sL z+)g84t&Fm2<@#7ExB+nBLmW~!gJJhV?}SD|7r~p-n<9orgQhPg;1ccE$9QfzA`x|VX_%40s^!U(l6->H zg#eyR*Pn;;P1KPoZrRX3@S7Fn7By+*dx8@F+`j7mOQ8Oi`meq=@JYdOY+CF3a(6wn1X4RjWVPYib2H=2_W{4L&fy&*6NujZ`V3HPfuK4nN z5=czWZbdgfkPV@@N9KAMGt+Gef)qtJv2+>xc~!?}A;z|Z!g-b}fD)!~3`86$rTgH| z=s$5Iou)#^ySzlK$a9nU;&2mp3FeW|GK?YH&J~6^C9fkS2g2peX7pt+yihyhJCa~s z<~k0|1f1Cp`HJx&~G+4`jfQa!uzpmQz-!+UOTLSVoc+kztK9z4RJo!}bSIQDoX zQ_;%z?fvDE=WR42-xhQ3mMpkciFBnz3#I-`#G{ObwSV!mmG{*=jy2q5u;P$RS+^BO}pdPFYXJZ_Ortj?) zepIXEk-?rfB@qrcQX>A7)_Qv?ZqcYuM%PvRM!G4Hdefu3UqAit4+^UhrK@IYAejo- zh0n;~@Yh%T&Su2@z1g`K1|wOssL^)ITM@@Bu%JzY-9;T%oojejK~8Rhh}el~T8Ber{j!PfOt=vW7X~ zMBPgDSSuaG%p$5A)gCz~{=PLc+(hHA%~VH~fFUgxqkZvsJe%VjyjoTJeNzS~;ovz6 z^L!?^#)XUcxTT&J3g>)+QA)YV0Cn8L|knSlLl{QYy5$&CfH=+KQOyk zL>hNGor6&O6K`-s=FHT+zZ_C`YBV7hGSCTC%I{drU4>j(TaOKn`#$*qIC15Moqni> zk&A7Y%QNGjp)hMVK>mYNdNP9@rhm#PgVX92AgL^cvY)h^8qf37XzA28r8AP-WcWt{ z3?ms)V1p(PI~B;J@gRMdG7GxDH)<)V`Ayh{P6;=1FlL2rv{>GA5%KW|Gaq;r zuC#CHJ2ssPF$!>6(o-)xt$gr`U+4Z!tERK6Qy3AF0Gz++Y7;Y~eKVHVB<)Cdw?%vD+S45An!! z#Ve)(`C1Ty$eqe5IARy28t;VBwBft0BYjKn4xL+-pdMBqkPm(0P>$h#3m<6NXD4vkBRRQNgt?2^a?BY35AV`ONG&OsY@0Bai0 zOa}rvDFQ26Di0f6ROMdIWOKri6mVU1F3-^2f^?!Doy^~eL#HF=zs4@2T|NgEtph7g zZtJ%(pTL)t7j3S&Nw4#(yUkBm1pnGDG=>I zi=bQ<8!)u;Xu{ zdSTc%8pykZZVKO;N+3MPn4TI4U_-|xkP}KDT>0%kIGEzLUMdhK! z#XvE72B=k0Cjw-XAbSTCcu&lq(;!^MX8TZc?x665qgJ>POtc0jDq2a*-(dxWo67@g zJs~oS-HxZ}X@E1&q)4(6cc}gKL?&|V!_y5?N+KX}KQVs#hPx)(m<|Rs`ws2rlXgFu z3AUhI=QfvobaYlk=1zF(wMqCp}KvZR%z{o`+_=AWYsva?uNN=!QzeN*`g$j+eDYofCmT8vxu_= zl5n7o;GpK_@I%gaTlKoD*v2zIcDQ0vxYl4rMF2v~O#8|C0LA0FKFfxC&dO~ym4@U`s2-egLbLU2VJ8~+sWXyS7k^9a^NR7*3520*a(BWKiWaFa7{zc zZVv?p;fu0RbE!fSBJz{6yXD^%?Sbz$Q@6>Jv&{ZQNUT~q7Dz8f(CXYjS~N*3GMjLGKvN|oM+7Ub%-LzmH_pd}NjAc*+hJ68hTFL6kFeYr~=(Jt|cYa|)>f%?EKn zY27aCt;C|alcZ4Q{fUWkhX;s3SDX!5ng;P@Q`9^o0|v}i#V#i9cIiYFrY=dSoOUof z5|zx5Ff^QANm29Z6q^!V>`h=DCb&Ufu<%{kn^^Yss|}ynzc=lq)?+;;C}WR>D^>kjN)T>PjQSUZFoSH% z-{W<98*}Qw!l_%_53B_-Bg;$oZ#yjee2SzBpOA0Fm!5B{+=B9nh1H1+^t1qajXJWN zoyIwsDqj^i?E;+nnF%y}S2JO&7}1bkY&YlEX5-u7o|N&aYOnW#Gng8h7@><+|GH zk;>eoaO{%wA~eA`cx0{Bt;aBU0HYbTzjZKH7@p$zZQ&X6i|{*noK9SLkW_l?5Tm5~ zCO7kSXnH7L?Ue}t^!QxQTIkp*X(YkM5gocHrac086r|5_E4~3nCGY02*6Q6mk=DS4bJxY>9fl^QC=_7R6s27U;?Zt&;6Gu3F3 zP~N~Z{_{{7?3#5b1;bkoNkpt?o-J_esWbj`S5^$|%g#TCK|r3%wT$5ozDF-*OFTS7 z8{oiERE9!Pq*lDMlSpLy;VU0S_n2odpDFCeFw>{DuYZgaPPIC7`DI3>`OwmRNp?5#^r zxS9}I0W7rVkJ;adtakn$o-qyLJp#z(SSes#TROAt+) zN^J(2wq>etE=7@iklAbgA+GwcjYfSMN>l&>GosTHEj+pV*oO~d`uS`#LEzXZl*Ajr zHuUh;l)@XDcu)a>OzS_oZQexNc`dC2E)-mAUN3hrq<*$Hsd-X!EG+J7Xn6!O_c_C^fT`TisGW3ow_WG&;(Krr=?;<=nVS*$>s)tfp%RGpVt9l!@Rw8_Cz}YpgedLKAB@=vb+|NVG1~Z4>jXN%8X+S0o9G@jE@! zqsYyN1%I-|vqu_;1jcU`0@eWOMO-V>H9R*V8hnIy2QM81@?k-gyBcKfEN!x&^m z;}=3ILk3|&NuhzttV-R+7Ef&Mwd@Y?IoY0hMR}Pw3%9X4I;y(b3TH94Q+#Vl#Q(>} zBv+~D@~BUoTF^GM5N}ICUPZqSt)2rAK4x5U3EliKUJI19fKDw85Z>Z$>x)tFE_z3S ztwl1;iFI^fV5O}qZ3bV`um3GlBL4C01YrQsi!P(Vz5wh_G(Z!epQUNG8b6l6mD|7kf3EY`UKC`miegb1$>(1kcNl)dp=R)>|7_x?^;>vkK62L=U^>cext zh58*-JwzRKec|-Z^+NDPloQl$^`1(ft8hJqe7mI%6La|ShEWzCvSgcN8Gi?*hN^}0 zf#@GDn5*0&Hwwjs-&exGG`FLKKKyp z#ta#_d9@-;}6t0!Zf+kT{hvZ^#YgN3D*Imn7^r0!G@NGwX||0MB0^LcRRXbr`;#rV>cl z&+y@)GTbf*j$w=ArMGZK9H;BWOg(U{-R z;cRw^HM@b->Owh28m$JuXaoy8o>Kkm7+qZ8Y;h1VS1R}vNO}ywh3ob|?;v3*0i;Z_ z1LXBgD$N+|mO{OQ!@$J}sh}RZw$rMcNk2@^0&1v9k5nY;4_14J$Ar^UT8S8Q`8{@Q zsI5$Dv2dl1;jeW_^(xw9P9&qWu!=S3oU`W(9fb3{^0KieWERG)rNUIltejw$bGI?& zu%M{;9~UUvs-o-84<26!ugjyUk$i;9jAWX9nj|%JW91HB4rmiR;B3^1VxBi@m+}26 ziAg3G4W*320H$icD9VZjMAOSti`|f}CdDP3;TzcNv67 z)I!U4_@s=~f(@iBYXOGGcoY3ym{)U4fz%^n#Z=z<`wk;$GY%?*^`;0x_ZUpONv4}_ z046oA&6%;Jq-1xO7L>XDFo4!80hXWe;oj881)mDeHoIKvp7=tHoSNEj(2`w7z=9rQ1=OH#e3z}C%rSN^$Ywvuct^k;?72yj-t+CRGFW~Ss6QAwDAwGh5=DTK)v9^SUy1Ie z_Kq|hHGCD+2H@W5k1yGmJPb|svWV6hf0<2C%qGwak!~e?awLX7q%p?O6b-G;Q73I2 zCr4mMz?Fj_#`TlN0<*{vR#FExu)@MQBI`I5!~Hg8f#3MH?Z_~`#wY_h=PhxJ-Ouz< z_OexM5&_Au%CJEnPAQw{lCiMEWvWWaaMeH^Ca3gJ=ZVV2spNG@d@W0&y|_#^U_{e* zZ5}EE_VE06!~JD(01RhJZ*>;HXxasJ?&U{m<5oP z#VF$I9O|`$8_&y&Ivo@)I`Hcj*@pc@xjD7~%;G&ME_Jgz_!Hb)ywS>x<|cZt$Sp*A zE=biQZgoT-RPvKFs7y)oi{pp;SBLhuB*6kB{PVkgN`KToMfQM1X@>iJ+20X;v)CZf zqrzvZ)oy^!aM}&t0s4%g4@w_4oiqtem;lR(VN7>B5p*Nsb6n?Hrf2{DOH$3r<&FGx zJG8+OA*4O^Or6Z-3uv!&<{&4$`SvI2!ecE}AWsD!A4)p6 z3wZqcjVUOU#q5qew0;ogpV50VV7(qOR-t0A?^onlzS%?4m?O33*UTCJ?LpRam;c4t z0uSrNp>fFZJ9WJ65WhhLD^QuYudUUlD-T(_Q3B3vttwPm$GZiyO*;|H<24-U`nR^A z(U+P-+nDjXHB%qa0mRCtaFS%7Apd*2Uoys7Q|hR?{$?%PlXrgHL9}CNXk_+R#za5f zVFj{zpLQCUp~1s?@{j^?o#d|~q-g(lE(afLh13NCt8yn4pwS1#f2Fi6WUBa19(i?Y zS7CbzFV61Fr&O5yymty+{I*Kh^telr>Q$MgUmA3oS$ywysk!@3i0(}B`4LyTT4X#Izq%L<;(uvj+O4mv|mh}A9~`Yg|`dP+H4sEC3I;w5&iN^2OAgXvH|#{3;ei?iYaiTVh^A=A63=hTE@F zzOXqyu59vJnhKK?{H{%!m99{Gf9IT`R`1~(i!2Ea2=@ zOc!&LbX;qMoE-Vf<}U@o9w>%tg#BwNKJF>2)#jl3tFFgDx*4|5Yn$rteT*G%T4)Ls z&Iz?-tJEx{TXYmt%JEd-AWR}|DOu!Gl3Rtd2W~EbjcaOj(Fx`X8J%Y?&$MkA_LF2g zV081}j6~fCih7GtQI##9-srs?zSLpcMk(-yjmwA;(gI|#xBs3c3FISio0tfFmu$zdXq~8 zJ2qv)S#wA{qtNLDUQrb%BnsiIhaU*@8olePOp=Y<271$H^~~ihFzgR_>eJDIhDgSs zs#;~$0)No8#fn<1%#c^kz~GwHi3|2pN&3emd!q|vsVx7qLh4=P$joe$l^67Q9%q7 zCAr%he>ui0b{Mz-dWaN$MPqzjv(D}Jpb_o5q&dOdOsA=FxURRa61kGu`AVP&QKPJG zyM27sxcQ|LP4-t7uGV&W43d$u_>+f-)g|m{1tWOGPZ@$aY_~!4Ez94xG)8u74Aw^m z=Ig)oACpHA8E#${xCs%8;+#tCN`s-{PBR6#g_+1o$TZaWmZmKw)i;GVfcNGh58;VL z#9<4&w7yoMgd}z_gyIdn_A&rwyYVf&2}Zktd|1s^lI{-Pz`l8GiZ`DdW16Q^1!e(0 zV@MO_fGNvEh|1h)RyBXOY#cAXq=o%Ojm z={>llwZ1?@kq}h7U{|jxFo-nc`o*+*E$?n~0_yX%_r>GF)spep%vpY!4o4!sj9BpO zlPreZ$E*K4j5K-nBa1Z>5p-1&^NdC42hpP6d?W}$)5L!&ASx8ad+Fj^Q|g(7VMDg- zp4i>L!Uy!0!zm!a6l%S`d90i|=Ufj?7BL*y4$kAUeMwnhy8coaCh{}3|75%LKZEuf z>T|i0X8Ux$4zy5#d4{*S>05bSqfF3qQ*akQE@>-uoTmlJViebF4R-$oE>W%kqNm$1 zI&`TMk~!%*Zct0hGFRrjV|2?%IB+Ql7JMuBN2pbXs<=l)8!IL4++i(yQU#N?PnsR$ z>JX$UsQq5M-P-D;`nxsH9%(!N=P#)eb@HU51W0trN0`CzyV7^4#9*C%w z#DALBt3ZWSu=g5#b~=k-(X&`y6aE`+I)9=k(QG-F=qHZB(p={!*>QfmrXGFTmNI}H z{0dY6)Fl3M7il+jy6&U(H!}m;(c9Xd;9k&$NcX2G5vVyq(saH39Rx>BjBG=ic(s*X zl{`l{R{t8?LSbc@2O^2KPM{l&VDFAs=P~TGfCl%xlSTc91S;M0U0qMRXVE1@FM7Sj z{By^E4={ha|2EqsCJQJvT)Lu5e%-36aejUykkciC4;!^q z*?!5aRfE4Lq86!kf1j<}q&X0&KKhtTYj9(;ZIYm{SzLLegOc~^{Yu)e}{t3aob`%ER2Tvs0Sj>DBpb#X z90eIhPp2vUR#aJeEks#>FPT?tZ{|?yd!8u@;$Yu`$SWW_Q9&4V4nzPZCaeY62Qt-a z+cs=K?+Bd1w^;m%Zm$lL@qkEWf0{M8pdz;|+MfZpxUvqY_3P`XV3=kLkMhf|yW1~V z%9DrAn`-Xl=%8Gh!k!@7nX$tiCa@Pd9)~A;DQICpcBjMlEA$j2CZGjQT&}xNWa5|F z9oP+^@6_QS0Lhey*x!kedGJ~hGg1aaII&QYVn<$Hb5y1cw?^erobd{ye-l~RnI>zD4ky{L< zCFsU;y2v=ENlw@>l6h0ntDXiw>!nSDe~z?0v=>M2lBPS$0bTJ|?EhF?DR45v-9J@d zUtpgywjRStXa@4CGBrcdUwOMv=P+I#P$D%Yag_Ej&F;uWDh^UELH?u3Mz;K= zPLBFx-IbSr;XB?*PUE^xzivJYn8JM)>frEe?HeR6G-S=KaVGw?ZvR;p{krPDkzioa z(Oxh;F*Ty$0N2>NE%3zeVe%#__bP0$1faR!6-FollqI!C*N1VhI;U)3ta^%cw^i{2 zB35hp^V;9)%`kMmUfBoBlZC4^sU)2T<;y)Gf&T(4(kA*E;cRf@n46 z!(8TTqS4*Q6FT74u|LFy@oK9B^_u1^1&Nl!jmzqEdGjR2@+=_Z=aDx^y^iUHcu-%t zzEBHN`KG9_>lWT`ma~<}(~Mh3!z*=@aVU}QP=)FTVpcOMs}Hq2Wx75p-f9x>Z8M4H zIv%mR8+HCc*p;jEw$--938yWs9TEyzj03b}(bfzKN%Vi|MTlIhc?cdr4t#7n*bP#8%p67J~$PTwXgpNfu|q$uRn+ zWLhI`AFN;s@UAFpGiHJ-r9yPTu&%Tg1N+EZ*6V>SBIHwraXZVAY2)365Mu=cR01qj zKj6r-*^*e|v!h=#KuZnvFI3l*4jFg=X;sKk0#ue%xp;=}L?Ws6HPKoUN({^S1lE1) zbkV=95z5toT8&Ez2Z8*+HSd zLhHwkoTLBc9!ZY<)p34LEDHmMKzD4=PiXq2fza*WVN^VS50}@@q~}LY2DW75hFr#~7+ga}%3$5bM%GJfLgXYR8ALIxY%ly|FiqoB;hR!1WU{9BxXU zJGF*Vbtejobxw$P{jqmO1WVTyV325gv}3Y?yBj$-IqZ=`Q1^p|l!Za-!1MG%*&S@oorB7j{2LwA_x8||0m=hPrZvllu292EsSiE4M)x~g?Ky&H)b+&`gV ze;9L%FQafj#!T`7=Loq+E9%Og$Ob8jfs_Z$Dt?&eQ8ujk6N7k8tfUONT<&=)F|LGB zl*VgQj-cjU{K@)5Wf?=d*rjFufeo*6%f-2|VR&MT4MBM#pUKs`EJbv=Ju+@9Nd~>Q zr!Id+N?vS^VV(WVy_K2EkVx^wtL{8f?*pSmTj%GGI)Brk%7YQsKrQSLWPvqmPjr{saO6mLWrKKIdDFXT0T6y+GJpXNzu4s&ak z!&#{TSaxL26HC*NfXGE`ubA57HfU;@8BwMfA8adJMc{w z7TDo~+Msu&aUX9ao*_2uGUacJmupCGZ)YxYhz!OTu9e4d>^bS++l z11FyZ0kWCx`GxGX!JH5>4}Gw^L;Mt|W0k2N^Uo@`N1_>q6dYtPb_zwp2a)2@6jwv} z4yKo48?yZBy_Qzy%wkm-TS}bza-hz+Qbx4YgCFZRXE#+$`Yo4;dgRX=O9;*%nuKc3 zf|!F`56<<4JP>TdeF#zjq;~sB4PPH3qpQE4@o{Mb!LEQD*7}-$*QCQ1)>9* zx~K+J6yCqHfkU%co&wCuqs~vWjyxS@hxHd&kwZnff)a7@#tJp|G`vW4w}k#*%l`x~ z2wPoF7M~0I+3f_ky%P|(K8M;yJ>SFvkCE-Gb;0KG(g5`hZkD&~+{3=tnrqTOCwhQ? zw38yPO7_cJH&e#kzWX!7lVz3aWUFrJ~Zwe2GgUbvrdo-dyT$$!PS`Bnl zNAsAhENtqRdPOOQ1D&)hpBp{^`K&X&`5s&@y`wm{b+8cUQmkNd1`M2#I{%8 z3o`niI)+)hGU&5dvYk!981Hn$&JJ<6k+-9G35VHL8NFMI<A9n0%#c+O{^Yv=~c~&lQDd)>RR7Lem|5KM=%-HiK3TR|} zNVjPS+q=ed`}-%R6TYrn4BJaul*>)FjMztMRc^mJTxvAyCpgN^Q#hMMd?ThiKg-?N zWaM;MrUx&pQINT$4$#p=M*-@dj2~djYdG2CHN;)#xFS0<$>#vO!gT}$o{FD~mlq|l zAGrS{OS#2X>Id;UGFaJ{WK82}ia|eCfvf$&>E#wE(fcp472fT15Q~r&wixv9l&{Yh2OXW~VZa%b2Y}Q~1Fy}Y zbACh?JYQv>^F9X6$M*I(~tZ^?4LWpxk~Y{J}jZ*N3Mcv6z?yYU3Na)uLk`!Bj&O(Fz9 zO}8C>2JLVd6fCW=4qGtdFt8z~`JA_)w&JMW6jSCcq$l)ja{zEM@Txa^#%Y%9wHJF4 zc9PAU;0uDm%b`D3Zsg*XUAg}Q!E=cY(@D`?M!G26%ld9dX;Pi04@4{+s98`~Ddh1k z|1JH1YfhHLYHCQvy1jN)s02D{gh%i7@FXiXz&PMNe1Mq3L9 zp#r}m7Ich$xGtiE5AAbtG2fv43Ht5B-hWDJ;6hs7MaDh-Is%H1JD{`<0@Q;$5B2as zY2h!c6@D52ZW>Yj9sgmRhfKl<(ItBZ6ZPonE)gZ2pD=H;6YOBAWrN);Hil_7G-ry30 z71m4beO*O!{g-O%zWzPWgWKC!AxOPI084c8Oe@ph@%b_y9}wZ2B)QC^TbyRN$x#P{ z(3QAm5wvB`nGd(o$`-bYB8?H$ zqRuv|3AP}{VwySX_G>Q?$aQP5}Vb)93tjZCv5)JUQ2`HaNp18Lly=JWLh&QaXoS@@hyM@^A9l#+7} zF{MuxGU+G`k6`pm$;Vp zI=$JYT(ZtcE%MS{U~&82t0mB9Srec#ycuwPqwbT5{teYQ&sbHav^ytZ^NZq&=}Y@# zs#e2T8C$N{sqAyk80KWAPT;C1%5fR(QLiv*+iC=*Nwhj83VFrBRi4@eT*?-_CcV6P zpeBdtij*-di%0Ew&_6h}uk_362RrZQ+pB^y6Vp9iMe#S_;IRhTm<5-F90MDv^lsD(HuqdsCzr|l;&C=D?q4PFt@#I zwgiW|tqO$Aycg0L#iM}&h&leH^{p_}#5b_den#tHa}WtofY;Whsy&9xyuwr7ZAeJS zs{;%X8SVV?$=g;b2mw69=&}Q||s=@?rp}wz2WXNRg;Iz#2yBUzViCnjMzC0x! ziv6=GTMmTFTlBK!ILb_j4oVSJE6@zn^(ko5^07<=BrfJtZJ&Z|!OVpekxOB61ds(q99`5^4(lLdy;7@*S8l@$&1aF` zY*|ODvRZc5nb`2l=Qez5i34qf6rru8QyQ8@GEt`lOnV{2oJ)+QSGpmCW$%U#?;t+8 zI;b`tsobBU)5N^56-#9VOA7L|Hh!OMFziOxC6FDNdQG8u)H@-NT}00WLb|*?yc zr@2`!%pA`Nma?%QMM|E{irZ_GC&kp981Nzm^jC#GIPN)qXgq{0S*x*1H&WD*52 z#MgHAil4P=2M-km(;GS6axm_`waBiQA2MNiL}G)MMyodlYp6ZRusMPoF1MFv*n++s;qBsQDFjJQY7_P<6ik=UNUP?*e1 z@O^AJfP)2Snd(E%y71wy{D*>AX5cGz(YbI_WnJ2DDOMGX^IPp=O+{ZHz>C`K$sH!n zA6e$gj-8w=xw|Sa63lj@cUU9U9g1B9<=!SN1|60$_@*o~Ap7DDo5H2X3`hfq)6^EZ zKV{iwJv+tjsT;;K1K7sx&JP*5gC9;xaiyav%A2qoNmVm)kRDy$P0K$zq+pTN%H@Wp zb^3jQ&PWk1=r)ut9KJWLO2b}f+Zf$#N(*!hc{FJ5nM4rJ=*)jCpcUPbzDTz3!I8n2 zqJY-HS*vs)0dQ$vs3TJ%I``xHY!(6Qco4gUCIYOsB-~Y3>+BS>p|4Fsrn$AuW~#!_ z6`5~%6@!I+);}dW*5HBgD$3;iBO!Gh8_+!LmbUnAB^2mr-Zj>O>|B=Dr~HR7BQ7H! zxz^*C@)q5v9dsV`vw!2LEqA}z2q;W@Ti7zZX`@M?C@WlJ90ihEE(K2UAl^OT1xI}r z!~xTMs@%`5Y5L2dUra5`S$KmylhQ|xZ`>RtXCBI)4!t#Ms8U1D!VuzmhDhm05+46fj!}QW?a~2tAs)c(NbD$p8s7X5+>a79MjVBH$^6;wAVf>>b4W~AJBb+lv>CHM|B_R<(K14c%5|G)JJH;bnzrIpRqi0Xq zlm`j0dcSgWlN;fRZ$>m?!(^Um&HS1Z1pRk{wtVHd=JC>_OK{f2tsmPaOvzQ(|kJc6%uf_wM*Qn#Ym8I*>8q*I&HC%V!XJ!uZ8Drk}<-xJOXr-r4 z3=&HHTA|8+Lhm?WSus$0r-(!*|96uE1X)X^g_mdGAkKGjChf9CXWJUUlutE=Wt|3d zot8J_M}wT05E79Ef)BYQZH_0uFpGScJ@lrW<4m(PRu?WOL`094DArCr{+{O+0m&mF zOYvIGD~`E;i%#QM^OvuStS*bD1NiEA7QUA#H0hD(WWe?z8oFYq3u_(u%(p~s|$O8D1*!wSN*u!Sq{|i zBO&h-SUvbk>m}6N0cyAl!*=hnGaV%u!xXvoR41QHpHg!Ra}hV#2{&SFhN1H7>8<31 z_vKg|Ovc50Q;f-5MQpAGK%(9!N;z(G!xu9x8_e=H_TwtTug`y(0ciQk=tUR;XXL9+@wA0meCon6~_G=j+xsF-zftz{~!hR-$VbXHC$SaAg#UF;5`pr}LYS2sEH z73U50F&b#WO+a|XOqrLXhK^vS&Nvh<3%4cOb*PvFi%>?dG7FLceqq0_PH#GYrJ2zT zg)jrNPP_Fvamzu%DfKXB5~a_bhew8LxVT0ysulL|*OMN4)6U_`fqhZ`A5T{4yXZ5Ci&+~un~0bg*%_Na@$o_ZzuDY3 zo7-J9w6{8WVNlWzo89f*{uNrhY!F&o&`2wXvUYSgI|urko10nj*WTA`pV{y4PhOA2 zl=};fTO21--U0$eH6sK@;4A>r0Rl5HG%-_M|L#Dl^;wMJ!I6BZX8Q(KSCD!pCgvt$ zC53QKpqQMRegX$0GXi@5sSTujZz9B$4fqlQ`1{T*3YIR*rO+0-wYfwk9z-YlzyMWoz zSvom@qCRUoyL`-*J&*tZMs)EpeqNNHwUf6xwqNN#C||B-AFa8&qqV<1hNA@NWjFSeopn4d;ph8y)QdC&Pc`-?AX@_t>EGnf);VoB;rKWN0&fSiYp`{ibRB zrtO06UYfzTfTv?@a{PDIPW#)S3(J!3%?SE87C_Ih-{r^rh(yrn{4-K29g1 zR!js=^#SJgPT9$RFF)`R6@FV(Ep}fjFfoiT;TV83iJ2$^bM{CCzklcCKI?Q7=~`PO zM_mOjewmkk;aFOm8eM+p=6|6UfPM_5Yam>knOnc<^HP$EQ?Tb{HYPWgA8r?ZY|~92lmK4nW_JOc>WL5YKu?YV7$UwHzhl|~WDI|Wbglr%Hv9-}O#zY~`Vi){ zi|_jo;r%C`^umKaVFPUTY`^_zX{PNaOn?1p0Lb?H2-mRxZPCUS(9M7xn}E~VUsngG z@1f_m+@C)uF+zx!hkqX1v@<3DK7VBbLm(A54D zKlt&m{l|CkZ*1gae*NrPa=-p|%|C)4Hc5;fU)YVk_x7LQ-bV*N=wI@z6u+E^znd4+ zzyEBDUn*ZAE7`aMYyz~@O>O@q@WB)qeXujKaql*Hjoll2y1$>-OMWc*Z?A}tan_28 z^;zV=pIe8F^^Q(J8td!rzte$3pZt!pzkDsfT*SN1Uwv=FS&9zQX@7Res^9u~Xue2_o+KsJ#A z)>~;QrEd=n)Xb;{vPSrz_+PI`M8cYx(O7zmD5qaio01kUCQZGUD2?)^tYd7*fGnYK z!|qz#H^iFadJFVOlF!naX^#3jk7XKI^*I0N0;ltLn|EiUTLd|Jw+)5F(Osga7Jk@1 zzmd!&&{lgZ0WXrs%$h~^F3FBklFrilB5(yQolR2aZx=}&MS)72BA~xzjXH~eoiwCE z;#4EwA+Lmt&@VBptJ#(J>LIm6)W%rZ#Eh>bFzfC}HK0Zh&9rDJJ0qk``itkhl~g~I zW%-}7+(a<7#k!1hP#rkbh8M=0QIoCLEFW&oY+gT^qxyg4#6 zcHKGkHU^}~oN#R~h99XB_eFT1S=n(LtDunx+=c&mVKHLvrl*y&=Q7e(P<`-bXoWZJ zT)=CpzC8RhH{{&5AdW*wiS|cQH!bDBN8#;hJ!Le1WK%dlCn2Ta-tCAJ4>K1BXADJd%u_(XvK-Xt zP>w$vDqtap@G{zNCh+#~Eeu*>V{Hu42wpxzH)n3i!p;V~#gdgmk(_k?NIu;U5 zLm9sTX0suf$91t>4z-KDN_W}%bj4airl^m_a-4F|KO87*N!MttyA`Hh-Jg5~(Io%) zCNHO;A}7$#D7kE+s*1`oEhGp;Vy0GNBzQc8LH`|*lBQ2lCYHF6TAf6T#W~8->ORh@ zV-=Qx*XtfhnU8y~7pGB2PN^ozW53=bW_HCXrUwx{$iwm!T2W~(s6zs~C&}(GYD?A)s zVEy6Tx8)7Tp6U2=x>5&OPKLpwN@{(f$P=X5FN@iGU#A1N)@;UZ;p>-Z*4Eb8jXRwV!Ud*y zw$ai>HP@vv?Y$CvtnLB|*3#PGIYgG=Ze$S<(wq8=4vC?y0G|(8L`{TSXpbu6uw0)e zQ>wQQJl0d(?!jKqoHqAW!t3$xF=xdEpH60QaM-zz?f1aW^n9P(Rtj{$uj#Gbz-ypvR9m;uD&>oPWpP6#@#25I~+J7=g$*Uw? zsg81Nzj0v8ig^!ETHr74uAhAAO$Ce^O@1s&0gWsfb4!KOoNGso7`;F^xd>N(kZ22G zdKn7E%GuDP4QGI|VXkxWJnG8#^^TF~SvP zliJVeA@PD`I$V_x2)2?FI9@%CvXm$QndxjW`wAI{iBaMK<+NvfG4*a`Pp#9hQ-k8v zV$z3vfsA**q+sigG{PU>BVSp=9#{oQ^n5lFWN%7NG@$6vl_GwU)Qc2;Fl|;FaVQHj zn7~Zy*}sJj%5YAYUoR&|)+Z8#qTRN!u6orPUADnro!&3Ui1NUQJZ@1GtN94)m{}$~ zot9#5Yv8Vij!bO%L(Fx5VeT>pP8SJ*!FAWzFO%&n^9LUepJLY^w9G%Q;3sH!M+1Xs zF9T-H`jO}o2uA35h%q~P=U_^lZ#2vkKKmI*#POBZfjCC$_=vfLqr6wY zj8nJ_p9=(8t8Hlnfu$7K9i{)0xz1bc|BM_>P&`^+0)I=ZN$Cb`IPnrqK3iA@+cwH;buAVQ_}wF^?OG$ZX|x7-lT z)Q^Y>HMl_oHP$XeO&rNQOlWMdw=5MP+LK)K#I+AAACY>QGk$M*oj-`5HWzCCU<^n# zhJk2b$wNKLk+OEpPNMn-ctNkuv0jxHEHtf+ljc{MLi^nLk}@AMgR#=#(HON=v}NO0 zUkIJu?L40rJ(_m!0bF4I7T(CfYa8aFY*F~jtb_EnF&GvLrx=wlEJ)7h9yNRQJN(v9 zj}vOZlrB$m-D}?#JC#vl?N>JJ+>qd7Ekv!4K4YE7*Ih*%ZtRE~WiTVfLCnR;?f&Mt zW$IjNiK)NpgpYZ)iM2tYBW>YEsE=d$T`@?D=otDN-KOoV=~KwQEVoU#WM?WwIZp^8 z&8rqmxW3B*n#!Y2>MpNfGIC9wkN3xYjMhwJ+xD|5uoly>Bt`OnT=d0+ z&Cmu+dc>MoFYM-E#@3Z~zS*yQJI7JzCI`O(oIuCHH(BeQ`*KMexAIGh&boru#?3}#a&@nY*rCq|Bv0_^qQ}e>TmF02-&#vyi zUG?je-c6>za){ApzPR(gg<>8o3H?B?hIyCcDbM9PNwY&_DeRC zw5{V}q;mYzF^D4=*obOor^I01XyGU7qB{ta5!>|Q{fRhXE;l@{2aohxwojHG+BY8| z9wis+j5Qf`p6pbQ0`<1OmTkw~euVUz+(14^h(RB?DWN>hg{r|NIJ&N2+N7x$Gs@di zgIzPTG#xx$UxquaZ0aOUQ$|*Aops5jVF`7U?I($v;!m(J#>q%1nNG1eY4O2RLQhaM z&sdj>@hTOM;#Zv^ofi{A?Ij$yIhWykhRq2qR`ltOz@JCm4Y`@6%$EHG`=isq>O0Rh zlis@tj%|3w=qQF#dWtFIjm64hbF_n#s7ly1Yetle$0h0&CUKU_oH(J}U$kns|IWE~pyJEX;if=L}!}UWV ze=0R=!inh`Ck9?ajhU$Ji4bo^+}jL4+~zoSbxbv}|L)<4KK`yjXLgR=xD;q5M^q&I zTO!#mu_2#i7@aq7%cXHn$fk_J$e(a0&LPR;N(|p7lQW_dm-zRQxh|?EpT>n#IL@3t zO}M7tjt_D}(~Yo6&}^sSO1lPFd&+9AggVBVP}e8Bz=sP@Xck3AkCMQ8>NeA&pT}#TK?3-^3{BdraFH8Q7l} zTbsAEh7=Cvs$#(Cgm2`S^QDKVq+PsrN4J}O<^Q$D(XA~fh(vh>LlmlBAX(X*cg($m z{BmEuD7$-GAK+zpY?RfNO>S4|!B9*t32KYw9O`9@5yXZCCsSj?C5+J(Mk*TaP=!?4 zvZl=zE)rt}HX$31F<*;lgqP5|(N1$Hk6rO8l+pbzlE*XW>mXFZ-=XA^J+E#>56hVz zG6HH;X<_c5$y}8~?{79irREKIw0Qw6&8?Rp_|@ocraV3*<7TK+K#j3$SVU10PHww` z;Xn(T(nq^;3-|@l!L&2KsECWw#KI!SG+8y3ze!?5HCKA0m*y_fu|h5bDXvkkW55PFox=Hn1{z=dsX^mST{)g zs8zG-_$k*EU}a<;gVzqLol<&lSNSp7sipkuN@m@8683$`;sU@#gyz03i) zojKPGHXi$FHRUYravz_7Q;>8*2S3bB=Re1%N_WtFGQ`zIG5)?i)@SE$Y}x3(A+Vr# z1YOgo-^3YdUs`ALnrL0$Pf}H<)_X2HLd2d9*q;cWR}=+~_kTuA)LaugYtbRHxsyT3 z?iTod6E5@ZD-OQg#3NZ3K&#O?J##A}fk*;D%5)QuvvZiKoEG#S!ilD0Sk>fwAB+RC_&=H9T72lJnqSTRSCqry;1{Hj<#nY`^J zrepHqy=%c-IQ*=LfeEgJuVbP6AJ6TXv@KRSIe%VvlaxN-2Z{EU#WZFfsoy7HA z_r&Pd5fnR&?3<(`;fTs#8pQ=I971Aml^4iB;L1n~@NGtB)!y6EtLqR1{q~d!LC89D zCFSbyn^_(t`ziY5YsBQNUUiF4B(B^!5I^}4t(aYd-%IJ@s*9PjcLCb}>S&|P+28G! zSB_5c9oNpgC9us80S2ks@Nkqsr0})znX#!icdfdgxBr03Qf*>R-{D%B86oAO&E?{p zB|+zqEKNHJ94{tM+z`M%hw0p-^CXSNoQZ-Yls#zlecL0K0Mp^F+kI*h0Si=4Sy(qn zo$VD7zd0AJ8hSC<*9pmoRwOgUecJY8C5LC42U4q#Tnb>F#rf;f@xYwGO#J8safT>g zsDu$;br!P&I-Nxb%9+b0+~xXc%yg24J{?QvNv*ui!Js$ZJy~HEh>|Y4ZZH5|;GN-k-`F>wXgHe@AU(=Y9B#@j zwPFMlWu|P9l!Scl7LNTjJjOsxpV{e-kTYB&+s-Y>y||uLI)cN6l4re8A@TFpeq8L7 zq#C2oOa*zD3VOxf4-AyKjr5;JtxvHvtzJ_J*mjynpK?twE%j9<1^4o;w>6qv^O9oK zL~{ZcG(y+o&cYpJhMJO<@E&8A6fLN820io28ZGaK#R%e>YZ5x)!2osaej!$}4*~JT zANuvi1hQQ%58c37o{c6e30jNI9lU9)Gkp+qekVyM=m@fyYZPJi_!q1?+{Bf%y?QlP zgnn>EXDTi~`+`hmimF8*Ii`r_f{iFIW?T)i1{vJ>Jm@a*GS%N`zoG}wNkkyqF7(s045q34x!prE z$zY+(VCL-)w`C}gJe|+?a;+9h*JD+OnVsg>-AF6Ec@z)cifx5cmO{e2i2Uo->)#ac zB2TnO;@5W5yZC8(3>*BdX%59J7^^l##_}Apj*>>JVzj8mHcQ0aC9B7p54@WZ1O_hf z9+=9)_}gAiCU`$p!*1#};j)wTFy0=OMVRfwoDHs}5jun39=RUaOAIGRI$=3P2%!xrYYC{z>g!B6grI^C@=jYGORS>78{zG66L!FQVeip)QJYnsWfx>NQ z#K*Ev>!@uZs8qol9f^5?P` zH*q5kG(v?^*j3?d+z?f&nxc;s;U}T5#mF-CP|l4I22d9#mb{e-)wTwCgBMmyIgfqk zY3~n4ez-!WI<&JWl$xc4NiFS5(00pOQ+Z-NUl{w18X3Wb5k0fB8^zWLj4C6q}h<(=)jfRG9qWdY&3#nMQdF zmpHf*jm)ze%|V3Cri@s_VGf9D=EjUKQ#Yw_b%gs~H>5$ce{l`^j5?t#MLC5ZKx7;8(r5x~2Ph0?7+LVv=bij@|LDH4pH_JEH_tGdP`ra53(n+|7FG9S@!e9A zJ zFwNz8h2>K^D;ekaA6a+AW3R~YjS{7CXTMZeQn;@Y%HVLbic~EMNOnfMfT7-zqb3`y z8{c)E%-g#jgPLTu7dWOsgYz{o;n)=d_j8|M82WXU;bAT3Z=}n%!7S~Xo?{}-YAq2f z5!J-!_52&5R8Pq@9l-W6w9X-ZiP)$(5ntP$)Gr}L0m(e@#QT-e(PubSFQr{@K|Uy& z)Rr2{F$f$oLSjtcp6w_e;@FOG!`%!Mck${>TE%20OqS~=cp>;kH{e8C&K8rcDquOz zr9Z5O&P>cg!Q^qMFERw2_aZT#opJy z61GPOBwjQ>?IKB5ZGbP3T_AiRP604xkLq7`5rW23#m5bTpVGtvPr#|zixQFK1qSNh z1V2__opL>8bp$Kcr{UA63v85&*|-D>D=BgIg*a)@TnK(0Xft_2O?hrOK^b|Nhxf!G za^9-Cj8deFvhgJGyovZw%bU?!u{N?=fI=X$J;_R#X-bQimjAr-8#N7HD)KT=uJla4 z&|$b(htQ|37#pM3LSaRkPHg&og;3xsZsBDTKHjuZ9>yEbF-J`m#ExR z`MOnvMpVO~&$X^eDDlrhHH8v-a(U!AGAv!vb~dn*mF;^U=%=Ed!<|O${fdu`->uFD zfOkdR^uDoyzGc=TMv;7UgU0xsv*wQk`Ahw|CFQW|~#6_ufIjPa*e0u%agf^^bI3Q)vtg5DIZLHOOjd`zD^=Y3cAxizE9g zji5Er(V0P<#-<)!I#0l&lOzIq9{J>rt?aRYm&)Ic>!R}Xk7yr}aDJ-4pHIvLsE-aR zP7#8`BMPWt5JsqCSm8Pv5@czvv3SM~j;%QEzEYSVZ_M_JDi>XhKV;de#MT?mAS?tQ zk?RgRpqbEA!|q5wN8BcT?uZ5r5S(=^d)-)-sFOMp@hgaHZtY`?J;!kydFSG3rxjNI z5{cq>x8d6L@jPOYgsX*K?l-+~!2Chp!gx(}=3gG@t@HW8TYT!SzfbiC!(hl#vrYa| zMry7#yPpO?{F|VUojvD z#~_g3WuJ~#T+Y=SyJ;C^{l0U@P}x+>Qg|_sOFRBM0+t@HPwJg9imUI?w^A7zi_CNM zX`L6~$X90vpWq$o50KA9_`xv0FgibgFf1*bK47_9od)1`;~Wc^z=Rb2{+*?iCdv)# zg3y@mu;1vfL4=J|VNjAu?R%+eYrb?Mqgqh9TB`0A?FJebXu}YVWlG+GD~jD--64&B z*gfad=!UuB_=()uIaM!fkJd6tf*_g`)y8lMoFYQC_=)*Pgm z@Mg>{9kSya{jJy|J?oChHQ;hR*X__9Hg4RrWCRIXzY2`VDN^IxopPK|7U6RW`U=rE zzoaf1zhOv`_AWttfeS}$5WiCj-NzvHu`nRLLOfAENeO--1+(%byNRxMB8WJa4UXW| z^`@ak>JpY9O6vlyuwY=>{yIaiY61Sox=1i9ouV|!pf(S+gOX70cqDvRL87asb~lci z_0T&+)C!h8=6;u|yQ3kUY7Zlqd`HzKP^=9EmJI1 zX#3?wSF7iLIzlfQ>D(mMsXq>x+#@3TQ6i6-mTco1gUP)2)jWLOwI!bUPa}Z z?Dv@w;8@$tPl6 zKI;aLx(#X~D>T$Oy8{LrGE_4=`DHq*Ag{9mtdh&6^&C0+T{_AW6WV03tCzS*0`X(* z`vgXWuUOrSLiygpFwBGCVpsDD+4nzFO3__u0QxEyOX!HTOOI>`W_zPKr;(IfPj&iM zB9R^nqt{qYImg*Zp4xD9iK=t^`Y%si=pxlIgUHY6<$#6wDzR|cL&s%Kzmcach%oO? z+q@1wH}Mi9<5L%nf~G3HXD*S5TtRkATboc+M=2rlORp8s91LQ5%Km7M_u4cZ=;9i7 zb5X$J`vht>w$T=8{+ZD8u0Q9JfFFoY6+n8W+v` zvQopId1U5nESd4kW2WaQt`SzyaAW*|&VzV?k454Wo6K zPiq0cr*P1*@wCRt9ArGd6Mcuz37To7PZA=8Te{LD8?W>s$qzlc6%1?d=}m}t3is~Z zh7d3$yB&7%XJ8s4cR6#;o>Hn>b*b?Mgghj142XBi#in`I7obcn-}C1GkQ&oUp~cMy zB0IL$N1?04=+)0OE9No<0b+plc$r?BCoe9&Y!k!iLi*Y0R~D&!jqbwlOzNnDb}79PO5~ z@m6;a^{Bp!YUW>(Kn1t+z{SRz^kQkIxSi8_uoq*r(r->S-jG3E+J@s`^tcD&cgp8a z59~Ivg2=O{JmyO|1Texn2^TTqJ&81-*gv{NMVo(^&@Y-;(-1`37YdR6(DK6>uY1e& zav&Nzo%-v_;jtF2o|}{Z@ah$9O>kDmfp2REAMuu*+!fTEnM>Lp8r1RTRtkD&NE-PT z0SLllV3YVLpG*2M5I)k9N#u;+mj6i4%@xi^6f=&71GXpDUcc75tkWm@4lVf=ULjMw zYFy`+kPrKle+F-*gj<)qprVrJn2M9ME8M+@rk{tejr!btVsV$|{kM-0ik%Gl6B>ic z)k>GotR5_uta~gnJzo*)v2SuNxxLJWVw`X!XkLY`dq{3|M}6wfGh-_Kbif7z}2 zh&g5xv?`5V$3!iU%yi5*@=>32&(e-8xt9YUQ%SaPO+JqTR4y=t#+S*$PUj(YlAbNb zu#2u=Jp0km)MF`mtR9x=1Dz!(i5~MgP%$Ag?qKZc3%DmEd*&-Nx@+;f_yzotHOQ8U zOpivBYwCc-%#w%>t@FzY??XGJ6Xjql`Qkj=#kqXUqRp}L`Lyq*syto-zjRSY5~zS5 z+`_eb*lzC+(ozVyX+UKW+SXDJ#HKkVvVK4vmYQkk6SsEP(syzpz^50lJLHchHL;B-+umy-Uvv0$gx=1YxH64WSuT=on?s!Xe3Uc2$+eS{*1F zSrz*S_&ib|vfDq{Y$D;5#nfq4oRW6g$(QBSa<*}=rs&N_4>_Wg`t3kD_oL3mrtT@R zi1@2+o{AXqododEaCr0cn!Rf(wD{DUIcHn~?N)#^bsYIoZp>O=_8B`y!Lm!Zca#hb zd!9$@N7`cH*#>{KfvWvDPc6bUG=Nt)V7?*0DmtXq*}Gfi{TEW59kYKyg;k7?HfYP*P@^q>&KTUEr2= zc|~dCiLr3)Orw!0@{^V+4+4%!!+8aNRqL_{V5eq4EwXV8mQ()Yc$K)54AHQ7BV{&8 zOZ%GZfSS=L^Ew4w`|IysdF~^e>haQYMQw-~%3-NVsbOPS%U2x5$BT#h{5qt>ehtfA zJNEKV3M@*)YN3J0eF!fT+j|aE?4SKk!)b*g5- zL?f9%MDg508c#M3zq?Z5JpQxc_v)ZHAR@In^^5(QGu9P)XWaR6{mrZY9Qb3&jk)z7a=H_4Pf>Hi zPj_~t%#VRlnKYw`sif;%ckoNEY*VnTFafxHCXnm*Hv^8to*4s9Ea_6r+pJHi&Ur}G z7}8-&l(9Yf1JOkv>Z+nQRNQ!`(U|KKicr|ol`{>i@wO*{to~GR{9gyfKRi?OkiA@O zdwy9nTsHg}u9bV{M{Rx=xM8!ps5P)ns_3hmncER26 z8-ie-H%dO~h7iJCD5*!#j5JCfUIy&DL)1frIAZ)ZZfis|0j{SE_p|*1QFZDy#v}6J zYBHKSWZpvP_FPrG_U2zcNcE1y0V>n7{dCVJ#f47!6x>M0eJjC3&L~K$TYj4QbMI>p z$ygpu@f~h5OwpiiiPb``R6lSab6|Zu)C~U-p`%6OFr_)7 zK{DoQ1wLJ+i*r8=wSP?9-0{VhTdmE6%Bnt8mrA-*KD8?@9iXT0UFiRCQrWvLo2<7q zQuet}gY2V{zijK)){RjDxpTa*32q7r*Ucw=Jj88#c@yD_RY(MX!U0zFYld@(8ySk` z)uf=$6f(@39>E@HU!XIh7Pe^h6G@{6Z+=v<@-VP?AS=cOIU&k0pArc=vBveo_9KS? z&GgNgl;_~xwD#8>m4t3WJ4Y)w_ail8mSdX`7)3YJ_8;)5ZAKfzq_vS6(1RBBHESI$oS zz1^2qhvy8Uk}n~7ft!gw;PVTDw#>~H|IK$i$u0~1Onb}Xe)0EEw?mg%{Q=xR#gvvq zGY1)u_}6I>W|&AJe|JO&vidIa7Xxp!th7PR?N_LYmnl_E)|{Le|!9{yM=pY z6(`{|E&o)>e}x&=SIev+_5gjaMYXupA;0(Qsh>mBd3$tTpn5&6HF5HoxG?>>H5%~qfU1Jm z_fpUFO^eWNNpExO1VIIUAxE8T1No?~p5_eib_>o1Is5f@AmJ$pGQg2DJi*{6IrWXe zd+uCGKKtln!SqJMnh8YxQ&>Y~Od^b^%?E_BcC{idQcoxXP*awn{A`>SO~YWi2j;S_ zUvq+ny+LkQ(!!Uj#b24&ZjkFg{B8?(m~lpTAQkEYL4`}I(URUM9-0@4Lo$fdldy_|J>QvGriN1WC zN+75}qicUwQwGp(7P^I?&vz0{-_hc0yZqRkU(Y3N40>?)kY5OQ$B zU7`3R!!#nmODIctJE-d^aIdx#fb%`bSFQ~K9Z4u!QUX=oV{qC8`QpGhDPdY=k^};! ztOs>lHE};rh_pWIxzh04F+J6~9|+;s2L!30#sSKzsBhE?s6n_Fun#*cwOaB&o^dJEx_%B?MZg@D9+6h&W}LnG|#f2a*4s>mxxYg!RICsh9?5iX4@QzRIi{!JFrp#3}&wZt`2d4Y6B z+wNamngvR}Wgi?33AEX5nf-E3ITp?X3@vVu6d&Vuv5sR<8aoSZJIA;vaaLb~>ID&jFmZ;r|LJ7`8YlVVOJszEK0xnEvmK@A~3*1k3%C1V@}^9omk za3%RKk-pa`5?S>Fm@TR=mjzS4pFp_7yFyHwY`l}~{WNr&j;JKV-PAnC@XsYn8@N+M zOqGf@rr+3k@s`m?O+S<5qD(MY1w3RV6!>g(b-E;UW^amrydNmLf+wZWS?GXkTQ?#! zIv7P$sQ<-MLN=_DpIKymcVMB!_T;gcuxSZt?}T1vQ7uNH7HJ~Jhg6^L=5Co}^i*Xr zJ`+^Lnvrea7Nt|Cu^S5f&-v)1@18#| z*k4XVj`DrBI?4ZOHF$DPLPZrW$3ID-qW*;-w0b|TsFl~)Z7hBY1pmoKY{f^EjIDoS&F~L9F}8p%X$+h410&}C%sYGVjY+1p zQK1hbXGG;%FB{FsSOM)44xDsh!fd^0zqmASatg*JU@y9CZxbfdA5#`k;gBY;Vc%>o z!z)@o>}qYF?7E?UK<}qJ+yfX=s`bL3^vp?AG4Z(kI(Uqu4ls=@pxCsn>X|-DYMMxd zz8aK#kM9n?JQHn~X>@$8N5xuIIjBCm>8^RgX-0cZe;A;X7h8~61z46phB(|=;xjj+ z=l7|^9vinSP)A*rn7Kua_hQhoqovj;I(T`Q2;PrHi8w~EgqQ9njdLKrvoCk1sHsX$ z*9^HBE_~e!P!&I4BcFC8@gfut4Lc9mXz9MU}nU&CcO{fJ@sG{iM?R{Ea#85s@`MtlqUss z?>H#BW`6M>N0b;%q=)6abS^1}W}vr!K7!rkS`#65MWSU)mZl_)nYHIj#Sf6$^;h2i ztqQ{U`h~u-|5iWl_&2vkPfg9;kEGFP{%s9nN%`g1465&zG^dwqoxz@c$ONMgyoJSyLwOouR&RB5`foXC~3i%7j zsnj~xf|T`chby&OdJ;x)!#e;Yzsb@0=I=01mmw(RomVNG*GT8zP3_8@c53t@7e<5u z)t&9u3Cd5OrPvGlf2|3@w2&${77ZYev}@x_h&dL55e3ITB#MQHb_T{jkxo``f6~iI zXUX?7STN?1sz{!ZB9dqcEclVU)IYh6?(%d@B&ddTnONi-;S?~qNw`$>UA)!4f3=qE zIRi}nvzNtW9YiU}*&MK5W*)qJXp@{hw;Q~=>zuSut(#^@%+@9Fsv(VtghWl#@D5`a z?t=*FR{3@9*4;;P{5~>uYz~rZ`U6U_)bw(7f$UF#9l?^C0n_b#D=6OzYY2?Cj_0wY zl1_SjKDxk&j8`>iu>C5|4*xKGgu)a84-0Xot3|nuv(X9{LKZuop_ZgJ*{KOstDjQeWTdV5^@=i*_ppYDy64NkQ;^wPO~&_TZPuj~wY+wPt=Yni-;> z8Zfmh)T6^wq=&5W$tW)gDlzW@9_xL-N0E<{3M1p2jx!qYx(^%rOx4invX8+wNew`z zM4W!zPr@+&mdfPFFeTn6RpfCBO=_Zb)BnAbMuI z4_BH0{ck=F#MBTRI65_2{n5nZcqGBuu|gs2OlmHAPSua23R$-rXg^(xm@YdesLC28{f8sp_#7m>`dC70M)e^FcGp-g>B9z=mH|{(Hu*eK^Q;A z3(-z>Gr~WH$XpMX-xVAvg*WTwfZ)zI!0&9p^?kbR(jo5Buc&1R7#+k&2*m@?NU)Ij z9VF17I@1#dD&!PzIr2pmlJ)!KFA{;gc& ze9|+Dn`DnM5!y^9U%Mz$)W#MXlnNhRP!dG5YDXC^uQjYPg|aEn^^K;y#^Pb4Yh9KI zxT702A&3av+L2wzs9K)p`qAXTmzEEi45!owc}Mw-pZB8~#*LhA&ZShgylNwa7UB_R zWy3x&NS3IcV_wdE?_8>Fk+2so!~o;*!AUFy5xX`2UOU0Q8N<4QaRpX#-h*bSSq z-)$n+TBcb1Zds`M_8Fz4XJ8afmw@bB2o_#_}piU^gV;i zpl1z2wZj@Z!J=9lNV{;^QPaQr#Co*+c*!G6QayM54!n_}#r zg8*V6nv^cuFIzQEUJs-|hGc4?Pos?uYn%*x=p1GP4;V8P@&QIe^tWoazd_BgqR+C= z_oLta}>r2H3g4th^&3gA9BoLn2=5-3$f#aJy>NS&*UZ)bu z4~2>2ox6Gx9yvQ-t-CN3FT?%DN=YI~Z8dvlP)E;Z$ZZkfuw_4EV#-(S&RRQ z;fPhzFQTampf@ggn)#jU zV)6SpXjS!9mKsNA%h~MQ_)bRw4x^YgCC>NQXtAcIETri1Fm_#^+qY=}PPcc^IxQgm ze%C#`xvbhtUD@q!G=eBP%TQ`9XcE+CZ#raR#}JVN``;T)r_L*JlwwUYv?V8^L@#Oo ze_;0)Q8aG;0~c>UB12cZnR<~cd~%2l)dCQ7S@ej8w@2q3kmm!q%grq}YGO zhhNGdS;;-{YJ{=XUOfiEz0_~5tDjz*lgdU(Mwxx7F&>hVopw^S^=APqaHgr(tuI4*Y68J36yU~&+&CWSmb>Sx zf(iGS7<=ejR}VU{o3^;?)_v56Gz}i9=30p=TIh~hJaK360!fPNG)36YjOu^i16GRk zPA=rz?6J>kAF~(c_lX3Hz{_oB1S)k*laet43Cr@Yxg6iyiFYH|?yOV6@A9$U$4IA} zY1n!0)Yw+P*WFCorpj|lku1<+Br2$r-hiT(Q)rJi3ZsOm&GDMdE3tsgPi`)rbJY}z z4x~Matk~`9tk=N+ZUkYQfme(Uqr;~p0^hl_T#i;Rx~EE@D&MPF-f;GLlvWYg%($#@ zUAqM&zZqHU)uhG3$&|V7B^j`rNwcZCM1=fL(>WLsBp3l{1MCg!4{5;M`Xzmxw}ju) zd!$ot=X2OnhH7rXg;Zr(Hbs)S_4$NNDBt&VfEG&pLPa}Cj8|ZwF<$kZ8yU|0 z_?zF(BxKe@XL!GKRr%n44FKbcdN23pBY=-fK7sJ8HR5;2oA$iAX-NO(K?}#{Pe0^0 z#@O0br$Lh4?-m)5 zA|;@6D?<-{jH9!}!8PvXAOJ@`wdh*+@|ODP6H#sml?4U3q(nM5JdF@L(y-R)W$$>a zCsCO5#BXB!oqc$5rIJV3*why_WL^*^rcIS7ougEye8aOhf0kHh{Tf5b#X8Dj0QM z;C#@YWt*a}U~7Z-c6hcz;pn3*CXL4acfc0rm{drMnfRWUJUbwr4!|4z{kr1ggwelO?!Q2v`82u zwhxJT0T)hof@B_l3BS&=X|lH+M7ME5{KOx2Kb0C|ueVdCqr~6&x>K^o^F~nOhx3xo zS0T%yM6|+`D(Y7(((oa*%vpe*?^MDjeV!hW=iWM z$!(y}O9r{IL@=Owwk5G?lg=P2UB6@v)@ zU+GDL7M2PLqlas4KHFuvs9gc8e6awr*7DA&Ig$fxc*u;MLvv_hwm@Uswr$%^Zfx7O z?HlLDwr$(CZQGqmSG_?G-thc@uWFy#d#yE#Yeh_@p+CNqACL#s+XlD&Kyz zE3}1lJP3c=`;L&pxDhywk{&ULs>f)^fOA08OL1T5*_d}?JI8NaO7$WeD-~tCjHn*44s-ZeqZ0_|;+04A1*#Nez zW-_JY&r)WREhrmS6n9Ds{v8E2tl8qi6uY*EKHs}71Oxs*&hVhvmKZ4zj;16`r~4H- z(>r`FTwCA_TZc~`L@F|~3L#+UR!yFW%~r_rnSUOKeUy{P*`a$~19$v24gg~&>yG-!8U#8?KXfg5vafFHp5 zioyGCNQYlIiEq``O4z5NBhcoa5R%Lg&b*7D z1nP78Jab{2OzSU`wl!F$>7MbKB3*rpzajZJd19v~ml z#2dKXR_vlXYbCrGKhcF&H}eT=r* znM{cR`hDu+Lp@Fol#AATB78DqpYr5uTJ8j!|L~k}pC}pXEYltnqirvltGD=VyR1#~ zk++uzXi*=EplUq!e04?@@4V$UGK4oe`@TP3_nOeL+C*p#cgyIKeE z2KMLk4oX&?oEqA=Jhd&kF815ehxk133p>`%6Are<)!$@!lg36d0+mH~%Je?vK>uXa zj$*>+K}~g+a7WR;Q8DkkH_Hrma1~2!mi2b|^8Hap&n)_$yAJ~FvvyIHJyceiy*zG? z&W~Lg)HrbYst0YIPOU#gEA`J9lyQHB2;iJM(FWT5Yhr`Ywd^kd;BWCoY?gn@>gjuO zqQ#w2{N;R~4`JnQ+T~rG4dpEysvtS=aek45=Lz`_^rFqr;qd%6&kNmZFuLq@OL|SP zrvO?rfi*E_*60iqrhA^$D-f!|HefTpiXo;kEZ7G9Y~V~+U1;gUQ>7Za+-cA)C1&0Gqmh4_0_I6PSWM5Gl9lI6f{0P*|CN6)jIORd98XFo|1GbKhg!54w59)rXqPn__?{>xV+OCdWrA)|8#lxU0(Sl#Ad+JJ|+8<8Ne_nMENc*i@ zKyXq^yC9z|C<^qeooU`ynoZE~`ubL131gY(7jP{QpVZasv=BDYnaoTkpvGi^Fnj6( z+%g}=7qb4Sermf4srDfbT(tHs*}ZyeVK6E!X%1k9jo-Y@Ij2Wb*h42|IZEiWjD-N# z(NeRlKV^ocx@l67I@w1b%w}R8MPT|&9zA8~w5_m8a0wed(BX*Tv&&3avH7>Njte0iNvs1t7t%b6oJa-o(()H+++h6IP%+F#5t3-q2imz0?g2{T(OppDLMMCk-=Jz$8BSlHMnyco@c+|)FLb;$!t+S4A%Goxe8R-4Dda@Sb?7#$3?@Jgkjf`_ohk z#`pL6pOdu^CgSlOTz4$r|Nb(8E8WPF@R4U#{e$&&8M`^B)8T>@JLYuPQB?BTAy2jv zO(r{#erQL?Q8d^S(J7%~uuS6jjFCGb^@`1; zRhIcrj!_J>1uqJBisLl39RHb!#BJ$*cmXC9eK-=l0bdK&?nq3|`*JrP+m3q3vs#)g z2Al0b1VvAe)2UA0O?DfLcn%2Wjk306ZS*zVI6XLwJ|5&cbV}Ud!7}DU@{5VLZp#DN zi?0vuJK~*%NM)MGMZ+J!0R>>v{+`!HkMYK!hFq2ng)}puVu8ln#jgGE(6dPgwcwE+ zKd9#o5+)Ll;;b8a)&NV+V=YvQYM*3UDfy0j7iF6yPJd{Eku&u}76Do>)=#EBxm)}t zYz7pVQ?3`sv)Jec)Mywc8EaR13%(S@+PPsfb%pVOWD@pNc=>vP;^xdwaKgMb?-0hA z=&yCqnL8iOjZ%*^N-Kgg8wHd$$ynlV(69 z+uiY!{|d-I3idWuX%F1K{a1FK-9$_AH%UQHoOTnm%=xm~6!M`fDdl82>BwyK)Fxzj zF}LkjmlgMXAVwhOST&x&F6#q?Y2qZ9%l|?E=yvz(f<%+>^rKY;CNlWH$oW0qNn<>s z*1`H%Gb*2tU89g}>aFeUfZi3gCq0kcGVW3p0v z1wMTT@e+oa>y323Os7vey=Z~xCUCePJ@8VDMXwxe6~Nal&J+KngD%fK1Qt2Jp%@{tLo#@Q=_4gVI%LGx~FWK#4w$DAy^=h@ofv4VDil9325ID z+-kGmUnt+tLd=2eck`$#@!+XP2YEYTG@Ubp`;#l5%=1%G?{*9h>5|+|Oyhhv3cn z>HVl`gxX^$y9c12ibN`B8PsxgNJ0@vJXcZbtalaOE%+#{{D!{B72ka)wZx>(7ntkR zOMapw7VZco<>iG{WCw_wvxpf7T~N^VP->1}`D*;vIIonF;u8mx3f&@=M+H>hg)?FoG{4 z^&^VN3Y3q58+I8#4$0h*GV-kS(2FZv0X{Ywi-}37a13<3d7cap3aJO7>4q!{Ek94Y zqA1aV%qoa&OGlPyfI`VE%b6`%gVWu5zw9NK`@jN@s2U23L=n-dwIZIMDU8^{xhqeI zBa?Z2RNU<_&e{FVPo83Jd_Zf;_G-)SbRk^Vs(!6rXqDJ!iT4Ysb=v~s|F7I=5AuMI*}zU;1#SCo@1G^Xn$jQB(5_*EG8nJS>QU&Lfb zXJ>#oH26?NFH4zYh8Fp9jE@OwHMiaJ%~beBx^gY zf2eF^;0B|R> z>;p56B`+DJxLa+$kIMRvE%-SihJuuHxu7=C9SPN6b0Z33eN~h{DtXgtNBAb`Kp5^f zGkMuE&riAZJ}uDo@>c60)pmTWQgcIrK{}0#7OKbNIrDraSG=>1&H|TGq@J0`{qjdi0)`db(t{72U8>e~bH@OrnmN|;ij!uI`SeP;rjKL3(WA7@v; zgzX&X09e7x-cjTe=-cNKdeBZYoHUGVUVx*U%V1K)ZrtOAJ(2W-bnTePeCA9BaP(CD zYLAq_xqHNokT%1uRSTiTSkxxI4-LMcIyVh~`uguMP{;DswcQ*h?cM>7uwoJxWQ8WC zroJLe+rn*(!s{U-OwN5Z23WV#$@=PK%b{{@cpz2|?nk%4RE${y?S(+Wmce-udkEl8 z)+4Zi2khCM}*<7e&|u91GQym2j9B)%jsx+ zaUSBVc6)?{vF4Wyq+tN91U#3dOu@9AGTTt+>Nn?p5Kw7epY@@&H}+Alwzr5%)2h%` z=6fk(noSr&YpMZVv^!cyoaeQbHe7P5CQLSN##qHKE9JiOThzAK+Pqw~2IbY&;&zOe z18&4o42Z46w5E2i-2&f+^Wy79E&zD#Al4gIeY@u@S z!iwX}A^5g6sSlU-_y|lvr1-h7dHq@CPLgnhrs2ib$9xxmzQ9hNY`rf4W)0?UFkt{KIZfI^w2+{Q{|N8MzqwevX zqqguI_QXSv=nuym{3Qc~3%Y#N)W}Yxst6Cnd`9-XJU>>E&c9eJ#U;4KuX^3WThBDb zpoee&01aX3$zYw8Xm~<@p|%dm%dG0;$M1U=pbjsOs|~^uIQE2Qa_Gsb~?5(Q^zwLG@?b+cph8?0#q1;T4|g)*MvhkIst@q$0%a zKdnvp8WjSB5Jx&1r^I)hpruz{<${P$LPs~xme2<2Ns$ijVW_)HhatGN9i`&Ga}=H{ zHS_EPaA3u#H#Z#w;z$0` zR_n6Irom5%4^$%#)uOV?)69P#^h0gBNY#EbcTZ}zi`H*CCZM;vE9uHIa;DpKD_R6n zzdv==U1$j~AJ4iO1NliOi#DN{1fvJpVfovRcfE(A7tck10+hJv0Gq}`j)Jm+EUb|w zfpP)%ZDc{S=gZXvJ8J#>(_G8nlfhXkbTlc!)<(_+byw|tXwEL&9Cw*6xyxsZ=?*{L zy405NWOXdG47+(71!iqEYtFe?56|vLylFqy)skm~v>^enhw-&e;J4J9|AkD6z$S5X zKeeIgYMO%&RjqCE6r!y6>A1J>)nvv0j{<+s?R)MBlC5^yHjUjY30@n}^$L;h8*W8Z z0ZkhNs0v*8J?ER^X5lG)XLgPo;QTw zt;`C8^3gb5vdgau1n&~QFy8(W?~t>yJ?af|Ob}u)(A#A~iSPY|iW074pg||$@Mf;d z)-&#F8m8@3vTz6dSt_c2aJs-k>^kJ}ni}tAI72QFx46N30#t&S#{PjDzkJRehkiYC zbu$wW9uer+st+H-04kuE9@8e#;~Z?zS)(jfsi6UfgLYLZZkZBUUe4nBxwq=$h}OLA z#gq06Ooty0qx~g(P)F?BiMqImb2C8UgB>q&8N3Se+5Xa8ZYFgD`I!pZ?*sz!$54^< zPfFYH2p z`E$o{y`{ee$xa_V6iQyd^zUTX{=E5>pF0n0;NfPvn%WR_%LJh_H`6v(NhFv#S7j(MX>0iR7O+h&TMgLy2}SyC^BN&f$MhYYcbzVs9PgVVFpcfAG3E^#S~6qS^^D?aTwJ z>L>7~zwDBu?16d2?+|||84rD<^|FB8%$xG@)Me)btuChVSKc4M8tf9Fx`%=w@iR1! z>%(6}=Jiz0;Sc${s(*P_Ig>pqD#;!N!E{u-F)&#NYxANSL+Cx#(*ISkVEG>f3r03} zmj5OzmG6p2;_YKnwIu_HU0ZOl_m-gVlpj)KWA6C};BQ2xtLhAw%fHH8MKY z{!Z_JECKBRw6GQ~u>O_pL}htpq!S=3)2y0lDno%Q66{Q|uo(Tz0X3{mDhFL#$7Wg=-o=o523KyMWFv4PQ#n{H=4HjKH7l zO)U!4YUCq5pa9Nn`n3%J)D*#CycmePmT_UQR#v9;L!OA;%1cdyQ&oB_UV zqPa)!tFrX5cljZ|t)T?QmVqD~fxjUW9NtGxUzf*Qa@lb{f5N+1fj-Gg2KcW5*a>cT z##jHfeZ{CKDk%YRq^||`3dCWK?oT0FgSol^|N9==-WHHv_k#ceOt`MD_Oqn;nK*p^ z8UKuG4_?^F!sL2=P4oCZiA@XG+~WKEyZ!lLqs0-hX}#5J`(q3ORB4Ut@3-3VwZ^P9 zt0$wOEvhS~DV(TrChJaMYEsg2?XTXeyW6wvcOM~52?_AJ>JD)EsSVJ~9xoL{Lz;zy zyQAJg_+^okbfuNkD_6Z;`6IpZOh7IlH}f-GWi6PZ>c?ewc0E}RTJPcjJ}&*0`hp$& zxbu${0Y)DfKnFm89vXX@|LD8?2!8S#+}A27=WjzIbMN?MAMB}_6{vRy!CPyZ2LPbH znpRAtoz>Ay0*-r7|Jmldn zY%Pc;VO=>#zz&Gu%g;>ampCn^8#p*BvpB()U-KjX*CdV&Zs*U`13!C9c0+#y$G{JF^^|UAqsrm-P>h4uC0N z_YXrC<$OOLh_e&0ef!^bPwXXt~39j4D8*3Z!!z%+!eh%0Cf!kx!o27{|4?=c>SZp$VW5gHV(kbX*j#Y z*U)cJ_icanthO)GZ~C|l*j}h-=l70pw-igi(8rqZ)$fdFzbsw96)b%7yNJ>5taS53#0D|JX!WT1FOj?_}Q$xcs_?X^a_tT5s1-}vu08p1dn#2UO99m$W>si%a^7s4@vr6saCk;8PJ5f87 zB*TOTv(6xhA}Bwle?F<;RlphxshpG}kl1&bU@nu+xq^0B>Qn6BCcPTkohX}(H|h`M z0?8=(W2**pP%~I z@r%%yCKCIMyyV!RRQvMZ(?fcZp>7MC!B zad<~Ng4rXo`h7#jvbo$W#&KJzW$lmwi07ua(e1P`PBY!Cp~4&8LD@?rKjRl!1->)0 z4<_qQ6LAi){AjbFqYGrde(XP@)Qv*!ZOsL0%U>p#vZIX$wnK1uFB>#gGP&Jc&PACh z$We0ZFBbmA#;a69QcavNSQY@}*HI8qBn@*dJI_eZf9E~?IM_tM zCEB10k>YLb2bf zgy{2v@Cr52SM{zfUY>fxb#74fSX7U+*C$1_NTZH$W1>-jbTck#ZZffT>sAx3(1Wpj z0uFpiHVu{@dBw@A9^*EBnV!%AUBuF=Kyc-#T~|T7bsd1f=wf$SH12tM_thWbGD$FzxfO(by5(mpeK~sL&xCQ5PTWWmNE{g+d7rXWfi^A|eNA>Q=xxUXg|Z0YgWRtoT{h)5ydA!oln< zFutgKC6!Ud6{#m27zc5PQq8(6YpLXO}};8;mlcrd&kP5Eof8_t_iiy@*n4lR_lB(RSFqeP0{bI%5U!f zn%PtOCZ5}(mo#qNEcp%LU|D?CZlu31L4gWhahL2=kg*;e}{>auX96Ji1wp_$L%w)UjO@x#-Bl< zRZ_xR{&mBs(~&yr<=)RI=3vDgQsMKkg0EWu1IGN$n_|x@<)OZ&c;7d z%}tRbeOhUU))}clnK{g)FUdo;%Ttn%v;v8F6_ycgX?;269CbU4=E*7=<{(C#{@s0^ zFJqi#eVuf=I?rt0ZRi|*A9uEmA<;tzsK3(|WhQN0ML3BxC)b7T)ti=)cryzPsinVo z4jn?FOg@Hw3o;trS2P0dpmqp{*cXAQ1Fj~3kGFa{EYxktIJf$Dldg#Un85ZXxM$~J z)Ek#GNs!ZyX*fOF@ZGMWialD&booZ|gRv2eJ%WG3?}Azwl=5#Q64^#*^7^K`qaxaO zQdjpj55mzor*z6VI0Z+&Q8NKg$YBYLT^^G0+F7caoX~^%6>g`!|9pQ>De>=7VJ(VS ztI1ZPYXlDhO>uz1PuCH{*w=%9kGkF1zL?|p%_y|bKG)y)2D2MqHp!x3((U_H|LFnh z6~QFD(&)Jw2IZCjMgq~Oj{!OTnnL5x0oVbb@e|bhUw2dc^60Sq#j%gm5L88csR_4l zW?F@<7@dS!JeL@PGUd8!_s4?9;-}DggNTg%S5K!KP#Q@L!iF?j;&r26a?Yq2_J}{z ziW81Q+^sBM8n`f|1?JEKKB*;)-j^kZA#m7c6g-3{2hvosdX|_7#9cdDPN!XEue8Uv zW5SERPb9me9_k{`FwUO%U}A1saJ+IEQ&i0AIY@lKtT%zy9$U&`9X&Wcu1Bs!u~^sU zm7Dg3^YO4r_i^nU8}os>{YR|?^H`$@jh@F<)YG|O2@Qk}Y1%(V{=DvOj3^3?OjjyD0#{Nt*Z!ca7L>3@!X)IqGOPp5AO_hnKcuJQLOpQ)%ptqg^^CqnzWHvcDTr zV{Q~)J#z`XdA*=*g~4v*RrI6ICbv6f6m@c?q>Q9H!r8dLJ|UB)UYT-R*sWx!Vfarx zR;9eo3?oB{CCw*xdbKb6y=qQ86gjLbFe99P$Mtp-=R^D*paK)yfk%zoGfoEdR1hF|=0@DJY|EnN#1;;CM%A zE8}^>45Imz=0B&mFM&R&W#t1UUryXBZ9HruCZzp7gW!62^Ni;j59WM6g)|o^VJZ9O zYjSe8k@jyE7n%x1XI*AN1LJ=}1!~QjNoix|vaD(lv7ZuG5d=eSkC}i>%j+k`2=JVg zhrwk!U4$vQ>%WqlI-;9rs>Qx|sxfmewQEU3rbc+VMH7-oL1WiL4>8K9COf_rO%t|S z@4WiN@V^G3g=p^;U9`bkU$;5j8EoFnP$YS%BqmJ0(E(5XB#pohsVgU!YS->C;Zn^A zg>HNxhOHi2nDd6icyXiuR()iuD@m52Bzb5lP&%KN0=35|_g*_dG+i;vi$@nx$wjV$ z*A97wc$qNmGxncEwh7+@!h)mGB9H50mHOnf=npcjL+%GAxM2L{P)lEM-a!?;bvPcnozjy7 ziat$VP2Re%3S~R*#}G7}tI{F{MdZ5Mn(smzz{e1{`QJ&J9ir@(GNXd|qld?AnLYN_ir z#(su%tjAPo>aRmvpuXo&MQT5xzcqR-fRKUg*bHMQ?{)Uvbveg~2DYsi8CLGyXfZkR zZ@?osZ(+fOWF@cG9M6Zg!7nxOd+f;=;#*{^{WK!tm9q5uJi#MKR2vZ#wz2w9GK^xY z$nUq#2In~FRh8i@qQEYV0;;%QU?O}+omf?RVueC#vnG5-cqdj!yaTaHZJ+4mH+)|o zIMT!MJ0Db+l~5_Ro1Mi8t&CWz@l+JS`3`;DF*aXjBVJrt-X(FGBhgI`V)gzCmzo81 zBOy{%W$7^{&tvkF$t_Wl0-R#2^nG16uw zd1alhPNJ+B%^nU~)$)C6-ulq=Ts8Y1nFx0};ux%Njldv_wUh>_fbf~(R)`NV>(%Gg}M=b?|bb`LbC@O{L0r@wa-dhq=G zi}H%=9!KY^`3^9ge+i2SMCbmcYk6dIa5N`voEnAdFwSW*tDt}d5l6J0@6HAlB#d(w zqd)g7(qL%jcp=`g7sQLS$n!ipfeH1Z2+$RdZlJa|-xVDS+?;tDo(#V2#WX`@UtbIW zGb)Vb@YQS?P`KeST4(ciOuNLFp|Nm+kL05C@}aZ%4_WG0zPUbIvXpbb0w|TlWu{~XxdkaqW!F=Q1co$W7rr1zxpZzLrr4TmH2?A0XB>e9y;0f z{W=dgM>mzDV3MQ+UYClNnE*ab3v`9pBjY@R8hLxgxD{ou73SEqjjc3e(5A7xSV&fs zjf7jBQoS;Jb?zV&imoWNA?vuiaYsyqLHtYO&xb?_{ zc5=@ZTv>JOHOyAeKPGt#D>x2JiC1EbM-FQ$M?D&g&<@xYjG>U*lQq*8wONBzE!e66 zABX!n%^_GM|DHuymr-&|DFzJC48;O0X;tAD{Y~yf^%LqpV^gWI(PK zH6YCvzP>1tU0qK*iuFk@-3;cPJ>A6!5JY=K@k#MX>Bx;Rf(a&l>)Nx+*;gJO4XW57 z`aXQV{Kbaz$!dr2L%Jkxiq34_JVlp()Arg1R3$7#->*Y9Rpoq6Rn_1o)u}NovFwJk z*DU?-5AMP95GTfdD9!o)ldiK0p-Vui6Or#vY)Jn)(UGK~k#rfS14%`;7Y(-X>oAnF zI`|6&YbWD8-~=J6R^r%<_hJ)*$dUPNmtl2>WL~gX_KHAuA$=d7=fP_i{6+8kR$_SU z_vwu1p`0W^qg;KwdIf~#y`_CoK*t@7X~s%D|k0*3R5CM-k~7}zUfb{ zNvzvbbci2P?{^HchbDNY_l8*i6@O_CI(wkY(nzy!D*T^l>sAwstDS!-=&v+rRZ+}? z3vbjoWubC#9h3*)5kFPhR^3$yNAa2S1;tup+FYT1C52dTQ>RC;6l!jkQwc%anI=}u zrJ=DoF!hQhU5{-!2?R!+iU0n9c-LN}UrZn(+-a`Q|V>9&#WgWuMs#(v}O|W}~?t zmTgb|8Hfdj{&PrOUs=BCBpycaoSVmS#eGypqvPFmWR!3CyFwcFp#H{(AwK3suC7p8 z9miyeP!HidCovl$NwMai+5AxCnABxz@Rvo_KMKyj^>Bea|E}|OTm6LNX1=}3EC%dhRY6hG01JR!Fm=)Z1X31H4P9|hMT{LtX^`?ZuYt8hKHg* zY-_=?3jz^~eoR+u5y%DjJu%?S%uxIRmA!x|1BdK1siL;-)(rykGC|7C=X+j-wz^Im*sS-mS$o|U)USOvr?mi@~KgCtWx ze*ujyBv6cdYf$cd(Q>pWCEw(l+BqjSKA3v4CDoO?O)-=`vFpj(z|t)hj|f)!m#*rz zu11>GFc;{YlxnhJC8@ObrmNY+Bc~z*9iroeFTii98{JcKgzDK6c{a){&w@l#T`%|_ zfsu&ttOe_zrB4Fn8*+-In5LK_SQ4W~(RYe0vhgDbv#h;1O7zzRfd*$WJ$q^7NrgX6 zY(~V%YC5R}LhL+E4>HkeHeO567ru#qcsKW@>}8DE1&zKKE03dt>8BMu0X8OvMz^RK z?7=T2p$NetMa~N{aqfnONC_cy3ojasG18WNOs?6odoViMsOCvLIOO0lR=DJ)>3O;| z%&pajOcuWSRS*9#8!z3o2JmD@RS->RKQAwo>HX{W1a2AOotivYosrN5xvBf~dHs$J zK}~CFy%&|-c0eb88>4fIl~`+^^`4ikp(;N z-)l2ycdPT16VgnRM&r7ucqbFo@%IFQPGvPdmeDlNfWa);q!>)k&7RruYw^pd{Q&7e zCtM($@X<|r z%t(!0Ns)2VZPtN6SI9CK9g#PRw%RT_ID5c@(4uMO25k;daL(HBdSH;a!KnR1H458Y ziMYyJ-tMQLs^VY8hfTD=4}t>K-AQx?%C}T!%f3?&Q?k?B| zec4T&Ax-5Lc_3Z$H2c9D`1IShgr z{Q2*>@|NqluoWjNl}~P=%wfP2=P%SOpXjD>=`5xP>uZwqP;pw1N*6Y>&<*g1))xb~ z3`yW(Hj_^#FHX(7GbWR1@zv14)vS;3><-EBC>SieMYKk19`h-{I5kQjD{kg`v^MfA zmP+b|253c~0tZZg z@4Wp;USfuhK8N||Y(M%zV#`P*?$qv_RJzrlMLM3;O#f8s&@l#;xpsZj$Ju0%ZHp#` zP9l`p9J;tsib-jwkx55DNPKW8F-K&PmGO2kNcstciH}OyVk)XSywS58Em{6UXmpy1 z92zAn|5liG&e^tl(GJ5oEA2Jh$VHgkmk`<=g++L0*3If3>m{%wl9rr=}r;C;8%E50@pUOQmRhO$H#5t~-TI=N* zVmoKzV!I?F17;X#Pu@(*=C&y89B4Z9nWphd{k*V3WaO`MW*Cmrx$1r{_=?Zxt>i3^ zl^^g&c=T)CYuO_*ju6(U+U*cGIrb|^ncH73NMLQ6D=7&g6JyW{1sT(ETARxTW880K@@gkWA*&Sza64Z;@Q@Q z8(py~@gxvF!cf%1bO0tudxlO9>Ww4$;-gpKp`r^ott4{}iu15deFVc8 znq&$>&^Bwda|i!qm*v-IZxXmt#;#Qt%yz0dwl>5+b$@16#$@QV$VGe_lIw_1 zKH>VX!#DedLj^Zl@<^U8TlYw|sROPX3Hvqw4a(ZRxk-!FwTB{vFbfLbv-zU&oqH^SWi~2S zed{IMJe~v`%M?hGO$HqRlKWyt`}W$;W5I> z;)MoRLG%}@fvIs5dCkpncwFrG@t;&M5nemTm32Gh!U_P1ni)|Z zff9~KmqL*$cqa#5c2-u+{J1bWUF!?|lD7~f6I}QRu8uIIy13rKwQg5IGfo{>bBxNa zL@M)as?*$iyJ~>A9=G4S#`2Xm7@^&vD};q+5hAOBN@)Qbv?Gp{jDo!3EpjY2e;Goz zJhD&tHPONrlp^nbEyiVxE@K5k#xvG0GekslPQT0QY(r+b>P*^gqilF20ekO8jRc&z zDy38g*@DSeFRYR2`*5I+M8J-&N2os%J)e$UyYuSr`=gnJPr)oFAImd={@RB8YoUty z2)D^}`mi?Hu3px{-@Zez`d&FgQXP{k#-)KF|G!P-^7+HY-!>jSzDrn6)TE!rVY z!|Rd*EWJ8@K_QR0pyXJJK)SWa^PJ zD&_P}HP@I@>&>#D5rzvU;p@hWf3=TbOEl-~fb;a_)o-vY*zUN;Z9KchnKh>x;9LP7 zO%+D_P}wPoS1M{Vs)Zgy35fUIpTtyQ6ygrU zAfz{DKq?Q3)*FB#(f2{0bEx-^U~6IE&(Y%K`C>dijh)5hah{4|UbZ!{(Iti*- zTFrF1!97EqXnxwWK1gnj-dvK4L7Lb~(j7q>P2Bz2o^`$xi1D8sHze1d=EVwXQzEyD z@;H+}vb()ldv-tCc_}eb_&_8Wv_+FJ1^E@B9pS!JXbT^UrpgzrC)U$UsEwkBRC3$i zvgwoWe^)taN9rz1dbJy@3xZ`5Mt4gRo)x|t-vNa6Rql>P z#=-aw8hEiQmlwSVzBU0sWX36{W$bcR@CWbbmcChdphXx$%9m#ll}e-|iQLT+=T}J8y^-<%{DNAsv45 z!(^08xlw-b14xXi4Y)_AtT(x~Peh_doZ@!Xi7$}7D^`sa5p9&DYeVYvm_9mh^On^p zF!|ZA)>(S8ehh}CD?V`Epy1@(eJ#_yFi{fZsO5%lQ`>|sH^oN5iC==`7(XmX1oSHA zBcIk|VNw@4ex#M|+MPj?!qx z_mgMZz5GzTL4Z-j8(}3bF0RUStqLqjfeoMBZ_dJG(UGZd3V7|-s5ROqTN0*e8uA6B z3ybl8}Ar|w&iIsAhKy9{>XD>0# zpS#s*;^2HFvY%;Z-&!W$co1XT2~Gd0amPj27R>{a3x*hxRO}8no~jjgbjO`IeR%!` zKa5@nlz?k9)X>AgYXf5cI2$$ST`p;)NkcW_INMb*K3XcY41zwVX<>HBkC{B;$;En` zb~ZnP;2EYy>UfGVOWO6yGRPcgYuIa?;whP|z5N;))EqC0mN{4fb!e+w%lvg2{X5Fe z`4&BX=r4Chz;lDJ(3#=s>+2scjfuC5rtAt>GDSZm{hL5}(`9~!y3w)hxr=+-Xw<;v>592&QOlo8M)4epc-@YQ<)J{659u3gB58pP} zKmI*Uwy7pY+$tNLS{%e&_qTgaDV13qJE;ja|! z3EN$ET~qMGSF@4QtUz10=xWCKw{CvIBy9U>sxnUaQa*cN%BuP3WO(fAl_x2ux`0cc zwLXYikB`Bo)l^#F5;YXog=@y20Y379G&C2@`iS1f7%SL$DFjv%_rlp#WAXq(SSxl$ z+pR60=aOOAdb1-b1HqfYj-P{<*Sv7e*5a7#D5sOhb~Q+XiLE9 zO53(oY1_7K8a_v7db?=v}9X-oZ|lj3%8l#)_L? zf_S%>-3;x@#&z2c`)G*cB9>UbN*6e5T8MeVA;zQ4d#r_$OUqDPC4KiF@lT49iVPq| z9J}}p)emh^xWb|-;}>UAK)XOrAQUK={g_ubEJXfM44kGo01#y=p9_D~7q^ZanbmX{cxPkC-Z_=Ep2 zkDgxzX9ly9h!nUJvEJI&o`wzx7t&m)rjHyj&3s4|2j2^vi^l@~=;HSGth<{RCV336 z96db<(+%IA(8d4_4bwSh+}W%&>~8ssIp!0v+&q#`H8KWvFA`UTE}v-S+?atpz|dS1 z0`Mmj|1hLZ3+uj6I8Hu|{pH=fk!#+d68DnBU6iZScj4Ic34fo__IS=%9>d+AlpKSK8JMsELT3G^8J z&T~JSgyclUKk_jMADNf^c)@u72U@WXg8$5S`NoI-(ChNUfI@sEq_o!`RL>Tb30=?VA$8gL5qfqb?V3kCg_*A1XpJT?|BfdA zPF%A5@TTQ%=D`kO=+%_?Sf=6cHn;lPfjYOPS*|QysDcx}>$J;HN@UXhRs2|d>)_)< z7k&t$Bne1}z`m6i2(s$b|6GKL5;(}Q}t*oK2dhYW%V~oGzDe+I| zS^39^dmnOCNS|H9y>Z;}a`NaiaODKt-d`~+L$)(jem?fMRC|;AIyL13`4TeiQ$AHo z>CLn$`f+cDf!*$E2!|)sc6U&EU%hB(D8+}+ov)Z45EH5ybcsczx?Cu=_K4K!VeF)X zs8ubGfA3%c$nCAkJO7j^Ymife$STd7m_|jIqG*d06cjmk!&JS>?;>m>8Q$)TOH)Mh z7<{4C^c8ImE#&ywus?8q}jYsGdiE{F9K?jG$acbrdE_(7Yv8s&6N6s&_t*EHIFMOd{+}A-tx~V zr+E%QFvm!-VX9vlOWxjTB}naF@H zQ`iAq%u*`x?{HF2^8-VIy#2F`YKz*d)h4S9;`?3`*56~oL>z<$(uVm%t_J0~3)P%t z&0;!c(7!2vY$d_W8Ifk3JlYP&7J8}{NwXL(uS-YZrr2PqFJa;_(IfV&8UGHh-Jbgd z-&u?#y3_h#!4~6+9N^k2)mMEV3v8=BZ{BkepQpvGxaf*ml^jH^v#V^ZXTfB3`*0ET zQV-IX@{16?5%JmUN*wDD6fSR6*<{oAwQ>FBlW&9vs-k{UC;h zf?Z>8^hsNj{P8GsI42e#KIb5X)V5|SYVH?9W;NKV%@)CRR?<1}tiMkw?)Rk&9Kh6i z(fCvtEI%VBU7YG-GoA0|0MaC9pjYfY%8D^}r2nbXok3Xpn6D=HCWs#Qi0+(>7yuA4 z@8ATFT>4LMimI>1`HtrK3T*QnGOEu9f8j+M$SX|69Ybf@>0U7+wdXP;SF~OO|m10Oua%YGLI!{Sba|z+o`{C z#z0Z}+)zp;c-+ZOBtG14jvS;%UB3$VM)Cj-Jxnn)Oz++7JX%eM zg!LH81f(sneg14j+CKj0kiD9bv|x5*=xt_0>9x_$bETFG#HlJG9M}ZNv85h@0|Oas zFPHIs1)Jb?eD~7xnDtl(y5eK`bs;ml6hgK>Nw!y@Q1BNmsjxezy|NHi_0n)0F>N8PsW&_cV4tp!W( zvP%OLYG>|t=j7uyG}x;f3<+xY%nMEZ{)|vhBeqfYJtq|N(#`&J_(Pj9pS|-+qIx@L zcTjwEC_XhG-p%(T!kL!alb?mi90VH~_hr$Tw9Ss~l*p=O8Q$-Ry_8gkRL+~{ECFxU zpGhW+=+MnyGFRKGEr_!EVuUf2Y0;+leVNU|^$8Mt-ESr36CBBnQP$NK?=|Tu&&KDi z`S`b!!hXev$_TQln7?|b3Qq`(|Gi#Aj`h{jKm+Nu2aX|2-)n|jrF@f1G`RzCp=;>K zQbCp3aX4em`kKD6FIjdk1(inU$?}kf6a(`r8FFV1iGoWNS1I*M#CuJ}U801925pix z5DT1v>vq^4I+r_+SMc@YiPmD+dG>hV9UrP!XMK&R1Z(sT)+DrMID?XvHH-`3Pukyb zw!A}?Z)BHR&c34hJDY%Mf~vTw9qXH3CRD^Nxm9Kj3&sTthkJYATg%!&^d9&Qy>KCV z$p_ok@L>_qD}QU1Y~YVd>FJh_a1iFdm*}SSoqB!JSeM^2};^^;@#V z(aN+b{D)4?$n;!!+EJCj$smY0;Q{N?08|8z@i>x{GQjk9xP2r;{!NJ&82rEKSAlfv z9#`8hQbe6T;3T!qWC;>U5lfUUNhzkSCFS2?shfz__WY7VMTb&jh7kEgJaRi&O*+IHc75U8dvxDv?-2XXC}V^2ZJ0Mugs_)@8! zL=wj{$SdA;Ap!2ioA9(Uy_PbX8JbE<{waMIu~Od!R`jXVnko3c#Z2aD5$9D-1)N7+ zQ}-CdWLxWct!HcA5c%EI2H5GcEN?=xlnBI+hWnps?IMyy{wX5ivYdW+=Z4p@WWR40 zgFKJON8}8LklGQaNFT`kbEyyBg!nn!Wm08gJxNqdY9R%OpphygpO58+@Pj$>*GPFq5mb4zzLu z-)ufThbyx}zTl+B9lrf)4Kw{>`8*?oHu8xRF#)F*Coi`A^OCGkI=+--w*(KO($J|; z{+%P;h&k&+{BFvVBOU(4>jmP%fl1Hlo^VSB47gYg%M@jrl5`Xinc0AM)F~Gq#sN;I z#u3!ageu4CeE$5n{H^d!3QlsQpg?IHxd%`wj@^5~c13u%mC2i(xw*YHy=U^-oZRzJ zV$2PR1Zl|Ctk{bzAVFeHs8lVwn>9cNNAa4zfRP~$6XSL1NsewU0;l81XY^nFy2UQy#n)HXul_1FE2=Zp?-qqX~~LJ zrQ0$R`$3Z5$}sB9FP(?KYOUF;;Z%%yDu?x#KxQ$6Ks>#S$&hNX&~)(;uqzT(KQ%hc7f+ht}$61Ai*`sAQM57R#`4Ytr7NPaP7SD|5VOKv3)^DZVaYmq*>n!w}?=}vv#cT z9fRr(k<;iEO{_r$v5KwdcB~ULWOX>PD(hqm7Q`yB1A{r_-)%qYKY5GR5{8I@mwnRT zN%G0Kp|=`Z%puBP+GXq1iGHVtK@k-|rRe(b@5rx~Ljee7ghtZ2YkA!${0^ z8`UcP3q3Qu|8xZix7NX@AlCi8MbWvGCWwYz9cVDjcwqWU{`p|vIp3JiUauAx`R`#PY8SU0<_0}c1D8Lyk1A8KPoQY*G!ey5hS%As#?-3x9`dJSX7 z$vI%+gU98+mix*tvNr`Ehvwp=_y0QiU*GR&PctBSmI9ZB0ksKy=aGTIdkJoKxJcdv z=X8@8zA+~^au6X=Eum2N^`7M>ST7odDuZf9;4Y~;l3lFy&`5i1;;8N8ubFwx-^=2M zUiN63x3X+LdC~7^%w4~Bs7_PB>Pwvho>y5Dui)3GniKnhEC}2xq3#@7V$uGN#|QGuJF=wX zp!hiTJVz0L&bw?ckBr;@`{zKOE^IQ)JPNdPh&p2zqTzPlz?BwhtLJsWg6tr`P5RdFo-J+HWL}@$T#re)oXJaPCnn5xBkqXKt{2$%;4J1nD8ef!w!tg)3ab^G(cHh9z_(-U8kNGDC-5hv4OLIMlN9V>C*i0@J$OD}W z-JfavNY)Z2ACwb#I)Kd#UJWQ7O#r1FW_~eVX$@$+yvm}&YQCwPY}LWp4I$IgWeMuZD-T&od>T2{if{S6#}8!()r8P_V)=c=KEpc?Uj4OcrFP8 z{;cC5#rJXI0Z!l@z(IcHv2d8z{EX04RndTB&06IU^OG`?MzTnTVGmEC8GppzUcs~$ z0WgG!ga;51zcmHVd*t`O$shLThxu(Z%r5s2%unxgXw1$|&MyG{?eD#*Rv^xf%}ybm z-xMUs`bJkEfau+)`;1KvV1X)vYD!Yt(t?Smmo*oq3Hdw*j{-fM;+WvB?_-!0?E{!# z<3HW#{hw}ZBTsQ^Oa|iQ>Md{+1xV)=-{8n2BCbch{9aglQN)KO&HYxjHM%x7e@=Cm zWHDEzCe=jYD9Anbb?>Q+|E_9+5&^LR&4U9yH`g2fXy4}9eN>tKR{0hU%#C3k!`3r7 zJAi*~XaVoZjq}x--3kDKT|+!See8w)(hxO0fzaC05!%N9*l5RpP12kjL4e-@CBDLs zd!@ftz@2^&DF9n3Izc&jJs|0PG^Q#h$j4Pgm*3xvrr&b1o74S#n^VZ*FL|lorMc;a z)q$(ue}J$s_pzyh3Nx+o7URJ)?5K;RqgPQnZEF!G(C8u*VQj0xmEc7Hqj69 zk{9=E+}+Pt+q;IJE?406jSUXK(Cca<`m3CPx;hZW8bA3y4%{#Bd(2m#18}vIlTjn` zW%RH7-1iari3xCHvuh)SgToWhbiV;JgGp@a}A`nufO9Lu??iQ_1yaefn5Gc_7Qb zx&6OrboB6#&xWU;<4^{t`$s_a&QINV>zwW10Qu^XzSd?xv2)vkUu{5F9+1C)d_MT& zB=Wcr;WB*>XZNCh<-bzs+|2)Q%4bh~tvB+v)T#`{-vE;VcyNVc(sEYDtWvOI$|?Kf zJoICgQfa)%v-{4CR4ry7+Y0hd>(jbp`Dl7Fw%odzLbU9fW?YRGSwTO_JpE$zS=O|j z++{h4d2If~{i|z_@T2t4AlHwG!TL&{9>m=umw+B{jBEd!j%dkc(Qck4aJY{r|13o7 zRfg6b7#W&J5RprJswH- z-ECQU?aGs-_xcMV*isy^p@KV{tP@b_$0y&$MCE6IFY8!TD;i4C-T2pv#K-CPCh`gO z7rH>&^>yudUKQLVVdPADk-XjrGLJdgNv+|6ZzDLs4TUnC^T`)5!r;9{8a?SUd;5ld z8$d`tHJMDVVQ9gM^~w4_aYjG-?}vx`1D59tmCmc5pLZlnGh+^|i44Ht>$s`$J*nto zlw$~SCWd+MlxKLbYeoV1Lk<`eG1Zy`Jp7M=&kfW)$&8|UaEtGhb`9wB6l9zc`1Xk;yd`o)R_6kp9P|R$Yc(pveSnVAW zB7X0n_mJ}Snl70d{!nBmK?f+S?&Jn0HzAXgO#7gf*$T;^{2b_NF_jHMs_;<;ew$yu zQZ0q)6n{_5xf8v>eU;G8#QzsV3wKDQECYzkwzDveaxV)rS?JaH@ zzkShe5_=1Yqu#*88#ICyWbY)4&%cxxLCvX%1POsJ=GH5ze6#%1X`Z#X0`{HiG1UpM z@U9qZEWb@F7e9uqz7&PX8QQ`DCM)4l{l~u&dbVGqZyHu)Lq>t|6zJjzTPn?t#OK3O z{NUMI3qvl)*Djg-pI!oW1EG|OZF8!bbNGzl|5lw6nb`WV!cAb{S(L@Rib zF-CdFkLjbpegqS6n^{jA;KZW6nMavw{zUWoiNt9@j|sH3(P43$8nmuDKPghe>Ie}sCEK3A6lEq)YR4`) ze}fjSa5%B=A+~=?76F)tB}S+3%|MZWNWS<<9_ZWOB$pkxNz`|_`8j_kJU=0&>o7Ns zW!?>b>)MS#0^sl42|g|em&i(mPz3weh@_oYwfmTWloZWkSM^@5`Ja$tifh>P?UuBD?c(g?HWTpj-E*yAdR}Cb=>P^KaBZumN zOwu_Xz$D@e;;`9Ip0eOeB>OXnpKl7L=#f+JB+?7--Z^>$Qfi46>k~?Diz^l}{?@$) z7;U=`iR>of)yWX&mZ}3x*xI(V(wEnC$MUY8fInHP5>WnYF~6YxFXaUOd~PhYR{cjT z$3=kmfcNH-C2VIK&Ej_5TPtBzzsHojySuI|24uJx7lzS1p32x&K8duZWP~%k z+J6|kb(`M&6*0#>R% rAnlZt8S~ILg-gooNs2tADx(9Hg*q)$ZDVgg%a;iJsVqC zGbt4(z9lP90W@&*$#n%zXBcEi-&$pZ@Fd46Q-7`D6KdQ*A!fqJzqll8>%M|WlvJ#h z&|RWu4vX(9ah+4 zo0gxip zCz7Mw9lTrm|5iUA?vcS9i44@ZuXeb9_<*5TpF=r$o6IT=ejm1UPq_fpfztv%A;2@2pI?IFiO3Bjb~FU z2%VVL!5{ur7xBBuQFnjrxo$u9c+!Cch_OI-Vq}dP=l2541JlVRQC77rrEl5Q>V=Dz za$?-l;&UdlE%NF+E6%JBq|CCFG+EN7ma*GLFZwu?qeSfD`pT7BaR)4&{ z13g+uII}1%?#=TXbfxku@A}$LAa$l;5A-C7$3Sm5uhrRN{0}{n|6 z$)=U~N6!gRI{xW-H9EVE0yHP^miShlxdN(~Btflfy0N2hDV${laMWywud(y~kNbXp zks&=IxV}%YDu`zICF&XVMBTOWtyKa;B!lPYkd*cb+apG4uY(He4p#E#9T2GnmRBn% zt39+K}Y7g9Oph#GNWxHCWq2j z@kh}lE0QVBpnEqnnn;ux35}99SC8?3OVt#CM7XspA$5GLmHXsiLsC4%$)~s>in+6A%?fr6L+u8QQNAwGV0z z6r=ZXM__10vdZLF_OdXv!h{mU(p$*xUU)uQz#^+Tqx^c8^Hrr;kYbFSSL2)k4=&?P zmkib$*&sgpYp=&Pe2~;%>kUaM*la|%J!(?e))Lace0Gp()>~)sSqAL0t2)W81TmM+ zs+TOsrtcE-N0+dDdb;&&MXf|@%!l;sd7Q({bf>kioK?Q5ryR463RDQ{&?~GB+w$=S zAjpq?^2lUf3!TkH%rRrSUE2mK$x>d`GkmQYGH zyq3|C8J>6*?00^2W+P`eP!`P*w1~&xf<-~ z10_=p4!_U+>zIK`uqUopnpmSgo9iw{FN{Aw^FGjq3RA*;XQJtZffs)hk+}h57I{S9 zOk#DKpv;08b=H{)^b9Nle19wj8Zg_cMBukg{`yVag%lL{6DxfQ1&ndSl2*LX@ zw(~h2x5#0geIyZPpSg=U3-QmWtF-Y}=__hfMkvO=K?gb;|w9GrMLuW{5cu$@m@ojc00+T*I&(|Tk zBWPrL&UNH)S0TfCPDtBe zHAd&Bq9vnd`jNu1C0vr|e(7QJ8mn7LCng|~Rx|K#f}<@cyMWTNJ2ll7!VIiRz&EIH zCGpG~m}vDQ_d=r2%6QjTBJ#J`?p2y)x+;H^hC5C`S_e5N+b=&o?>KqMe^zLm_j(#k zor|io-FwG#WS=cvasE?>^Xl_a25&Xl_e#7!YI!%M6K&^UDr{nP60CY`o#o4t&&||f zM5N(QQzf;w)*9X>4CJP+f-sK|5T{!*9?Fl}34<|9H6bc5YHm0kybL?!rVGG`)`Bgs z%w4)Rf_s99m7AzTfH`vrHs-cDQ2Yz`iApO@+PXP#jxlJfnXJF43^H=dB1vwk#K6>K z3#_|5Nd0gFWtw2)rJJG0V71o{XP$p&PAG_e4!Rz(&rpKDz#(>b;>rg^2ZG13q-xMm zWiIOqB-;qqA@S+ECDaU7$T>6Vp~%}#)UXHN6-izBB zV&6z^FoqYi*!=xSTn{jAKhQdvL?=S|tpxQ?6mWa|fwhOC;VA+{!jm+dKjdmge@YaK zl$CqrAWR7WoJ^%Xzt+?#BI6A4049H3YJ8d*N)0+JbM(=@oYPZRX2c%7(uvgiQ_k?P zQuOhIA0#IJ`#~@ueWQ7IH!Y|xI5vt>5!SA|WtcGu>I*S^3qU#0#wHb}1-19Y0)zF^ zM}FoARX-WisVRE5L?aMZWa}6W&FVf-i-q6XUo!Immtn`sJVxxfz|xh!{=Dl}=E@BZ zR5$7;&{fIkjQt3_b4?$D>?+Sp%B_!#zfuc^gK?EV@M$90HBP^fBFTB+a7;cxpz8w# zXFElerUsO%Uwl+Isq%6OKfhBU!Zxm3@K8 znIKx3n7$n+Z@BJr#?DVJLD{1|Zv|Sd+$P-_yPXN*YTf-zSI@u&i7kn=aD7Cgv(HGa zANX{?8r*QX-)TfGsB*Ub-fu*%DCpB8XNX|A)7Ix+w=L5A;SK5*`*H9T=duQH!*AJ_@{h0a6hwdr24*t z|0lT1W*oQ=PZ7>sIMsqUBs%_V+Ld>e(fMYPnEXZ&&hB^v-3>|eKwp|{-6AirGsKXc zAY-WsB8jPCvzW~{bk^nz9*GqF@vwzOws{ecq(;SR*iV7c^RVAqkcyk8jFW!4=6>!Y zg1w26yTKzIx&9O*t4^Nm_b1M7uM}3butUVtaOATE!f6@(tjxkhzcx_Hx_1~IVmNKh zz(Pc7S|-?e>Pz`cZuu{fng~*&d&C;XdvPwh;vdcw3kBkymliO|c?=b-XUuMb$xErI zriAD`J+-7?o;_AtLDawTrcYyw$BK^8P~jn_FM)K7rq%zw#0Qx_Cp>1%=2P&*k)8Z| z9CzHlT+32KPreito9-xrCXwe}6z`l`y0qkp3NY2v&7^O(@sY)@^ z7ePxK{T0A#jB>XI|NYU==%9O(rq^lT#(sg;uk*h;sc*lmL#eZ19wnF;@LYt-5$Ue2 z%MI27IX-sfzH@tn$*t-~7E!fW^3jJw28FG-X?l&Zg}e|g*)-0SXBxHAW&)q2DD>V< zQwkt*bjB!x>s+nc9_LZ*m_FoGdKTL1&oUqjse&Kx{?}neid<9yO|{mOvVKz92?G~r zfc|@d2ty=#Z@CuN`kz@>s@UX8G^+_lG1EIU7lA{5zn-S{jOw*y+vnyPHF*j!rp7eOak(KqS+p0#)b{ieSrI^_!M zO7;yP;+#Mjm<>I+&6=-Sr=es?!43F_u?EOG&6=!K5l^c zQa%6rTLGeXM5e#aual)%UY8wXvt3s2{BPL)s8@y6m+Nffzwfn3bOX7DsE=!#!dH~E z5?hu6?h)7B+}E}EkF>|_mVi={XEDYq;al5A;ImsyvZx0E*^nE9=*!U{svd$p^djf! zj*7}HEIpu|ZVdXPO|oRUe+}OX+0>aF9IN2M(=q{Nl-@ke@+DLEy0+)7IS-QFYQoQU z2{NE^io-uV3kIydCKJ9qaS?L5D~Bbt6vl9yl7cplY)y4q;FFLPtX{20+yOhT*dsPO z!vFTpPI{gwh(@}y=1l-9ZBQl&VCdkr)^3J|^{+O`Hiibbr}lXHlZL63C8JT4fXL!; z*xChm*E^%#6k13fDZnu3z_hgpNrkQwtXxF6)5|-Cu4xODPHcg->3A(&+=xJ)>XigW z!V6eIU5hr6uQaofd&-?K;??AfyyOSUhS4kdO20aA0i7qgITqTYjt(@@d?1Z#k^MX> zHgJdROX^*R^b0*sQJpe_>e#zjf|k*-DkDNYK9nJx936TkGJp`DO{aKT-ryrFT%+1V zbTgkJs(H8Df_QrUl`>loV}#omI@DSqrMGvIb%tEsqYiK-5}ehwg}o9}RlZoo{{Tmz z-t7hdjO%Oy%moQi`LA1^3VuSr*O!xj9$5fl~UHp|F@!W|T;a9ISA~U_wv!(V& zCnVW1t7hoZro>Rl4tIC55Y&U(%W+m&N_) zf5mAHqB7yW?mGu(chSz9r{G~TG+NrOIuf-G!4~ELAI%7z8@3~$vJNxryX|`DL^E7SHfn_;4ronQups}Q*zukL;_gJDFILjK`*JMyeA}8&=J!yy7nQYmHr~e6rvB;BC&ge>(jap`Gus zJ+Y8SZ5yzop!=RLT^oH~BiF&de(T}3Rwp+b=OFD>no+)q9v#GpbCn2dulCJdLgvA> z&79=l3yA{Pe{jG{^cuJ$zO;X{AB}Yq)4lV&f8C9bmIyvk&?~-{eL65OePf&i`Slve zM_O7WKf`r=z`;dg_LUs`XaeY!Y=$q&c(I(L(5Tw5ajq`#n5tS~wC+8So#+vy3Hn1i ztR6i+v)TGgw`{!&`4WwL&&qb_>+rY;QHQ#*26+m*jk9tUH*!50S#`fkzsD+#JXmo$d6rE}<}YEQIv8<%=txQ|gc(l{Bi zA4Z*tt*^BAqmi%fF;5p@=xM-Zgf1Q(S$yln10$)&yOLg5^Igc$(P6PjOeC3`ej?*B zJjIT0E`p&}lHDg(0wp&RXDHjzW*@~r*X{QJV?40o_2+N?<#6(&#~ZYhy+84*jNEdv zGh^I;?jm{`bK%+;1aU$o>8{^A<|TQP^-Im3j!@DPhQFOp{Vs^jiw1N#!&$cjCrD@+ z6}{H3Bb3&}=yJnh3XCr`LJVWAt~OJ}VpMeFwOgxYx{=d+uKhI_j(VB zw|<1u@NU0`&3%|Eo=;v~Lm;DBEZkFFEe?>MOudz&BOKe8+*H6tOmL$#b;!RL>Ehl3 zL!~IUYT*LnR1lrRi#$iW*jAaf&q=f}8}Z7#V%zM=oY{hmg-NDSuXP2Dc?{Zg+YwCk zQnB%EgQB2aKT*ZbE=FuLcXd%4>yXu$wx5>RdB85H7Xa5~m|nbpNp5qc%59o3>sCe? zT$oLPL~qWyxje`sLWw)?vN15rNbjpfapY*8)3ON%m%Xx|lQ$W``g)eeNZ7A9%ODn# zXFWc|YQOf|)uC?Y$g2tZjFYX42@L*BGrY$HGQMTahHP0Zu;W%@_Y6jc$xvb)<+<>#VSPzV?FDJBe6ryBYw|M+)YEW)Fgul$>?*rfta_5BIV0e25%)B zTI1z@2M9&5lVXOAEx+k?dxve;t#q5r7;)k57m#|eOufC~`pq)ejmEH=vp8xarLQ!i z3Zsbh2q<4(N(w+4DE0^079eXdLUV1}t#i+W?mqK@%=QHRZbb$+@PNb1^* zYKS}oJuNDV7qQhu^TL>A3=)E5bW)fZDo+(Wn!}DVlm8v&WOb?-sYT-9yQUB>iwm6S zOs_}3Zm6!oNcweLWhcQXVC$VEuqQ{4CxH2WB$1t*tVLv{sQxXyZ}WBT;>6WVFs+og z!k%^lgKLc3aKk*gDrI!9wSj7W{%+LK38^IXZ$th8Vix_FuTP(Jclg)`7L%Whp=12( zI9;iZ6q5d%7p@m;4(PS^#efGR_4#RENs zo4()$i{5?!wY}6oG&FN(7WUH;Q<5wLux9CK<{mqu>&jd5?j8g&kv8Lc?T)>O&rQ(xT}PjU2YXD(xk9lM@$%##Ov*_9N(b~n_R zYHanZTzK3jKO@?a$B1#hB}U5i*uB(9Ys20xOUsrW)T`Eu$Yecbi!!mn-5C;edMRNM z6Qn`L?iU{e%6<$hKBOv81v5jzi4x7s7oO%13%9AB5KjN6Dk&56Pxw)DdydR+_HqIK-hi?8vZ@%RCyXZ*bzB_r0Q*1k zS4sB3k0z+u&LhSg1QWC)@{vReQ2y)z4zwW%#yWL35(|_3a0b7C{8fSJUQ0XQ>Nu{%cigl7i`qzy0y~ok!e-F~OKTS3G&Dic zAA+iPX8nJrU)>+2B@|NfG(ifOb^s=G-nr-LuQ+caH5j4I1 z$h~uiZ~=x7=J`|jYI*mr@TPGYUCZQo-1HYgr8Q1(I1oT_BZi-Hdz{vmG0oJE*-f~u zYdGO%wCHg%S;ZMyvi<%WJtal5Ve_g2ne}=t3Db1Uq`EUYLS?5T{~9WGc5@V?;mho} zmUPPIkNuo9vU4VT%nvosdB1m-To@}q8VYnOz^8yGkX_hqFA_xcxL+bpd9PSC+do?? zRtMj>f@mZ^2KH`?si_vH-Lz;}uN0jZV^u%@v(uEnZ2`fPEHzWlG2o86Txm+j_ z$7#CuL?uu7(prqwFuxqHi_h>sqHpnK#<9KuYp-@rT(QN$z~>yqSzY_qfMk|7GINT1 zS~EfF3UZaW%J$y7Sc=A)83CD^8C{7M$w*7%P+7M)z7(XCDjSc8Pfuw4Ly7$&H#nRg zjM*m-KdI7cQj5PNitrSBfr=ehMBGk6KvLiK*6~WS-RDtjY@kQR64z#d9MS~Yy*mBK ztvhf5wT!D2lzdEX2w@c(~?XJ&lx}P#Q&%c+P>?9i$hn8mzOoo;o7Mdj*>X2#- z5jn7ph~h8kTBUR>cE~qRRlw|kt)^ie(mPau?nIlhZ{Fxt+VdqfWtKO50VnRiV!@8d zw6t`^PVF^Yx8;{kKi!{hZm{>K#zcRrQ1Y#lV9}F5i`K4%gjD))ujH=h8ZORm0#nLc zTc}zr?8MDY3%h*kBB}a>d~mPCaVX1guSQmAaKqF6l-l$1Yf76w*~fY{l2Yafh;^KR z1JbNE-i<^-YW^f`QtVgT&&y{V#EP&)-)x`%hDhueL0;OW}qzX6e-cz(X+XS3!|K=FMK4 zydI5MGpkF5Fau(#i~LU2mO-W&z@aLR|mA;jF?q};HjXMtsg$jz92dOXfpeg z2HFNb>+6vT3?b`+2Yq~3R(Ur+wzKN@J~CB~BmXrtIODFUxMhTq1AXaZTIu&HmlT@0 zD;@TVK$#{@=|StVv~-OZR};QjPikO=i84sdcr&)z7@}~Qsl>I zwk3q6rz7s)mvB5!`Wb9luPbs>bPUtMyIUea{oaJ*3{&!TBX)v}FA*0>yT;eBUWE(O z14jDXk;|VG+CU%C=b~BJuuI!Kz2@W_*Qq0K)joalk_nSa|4@?qeDQ4-jhs?d0QWbf zykwvbZdZM3Fcb9VuDnPB*^q6yLjA1XPE2FNaw?wltby-Sn?J6&He40)Lh(OwnaikN zZEkYy7xwg>LjShh5}Cqi%aGuE9I9LJ-eJZ-sGN-nD$Xs9ax&tt%SSbJoa_fKbD)Fl z%TCKWA%4EtgLo`{8pBmm;@g?Nh%jSrYEPUTwyadncSyw#>x8YSPblwTX&9AWy_=%8 z^jxgt8l)@oW-7Vj0d-;kxmmRz0ZGf%Ps5*JJx69`tXyL=nF3SVK^ehW$Qrb@f zu|cR3MG6MvE<=BwwN*M2tF~(I|noBo56VG9`glwPiiUo2=r-( zOxAu^(U*@CG6+#QgkQdp87RM~59Rl%I~bc#32^{ff;LxeuJs&cayw{lSZ8VD53Jou z|3=ji2GZb$DVt!gRpGb}foE;DJXu}FB8b1qFmydD+_ru1z%-Q9V{k07H(Gr0_RV*! zmLB~{1uM4mf@Xyc#qGp$h%GJ|CUtZ&&+) ztW&MbpKX|?Jx6`Nz9_KI!@mE+*g3`K!h{RA?yh&+UE8*8+s3Z#_O0LAwr$(CZSLB( z&v$b!{^VTzmy<~*naq<+@?b4<+N#e(+G^$`Pz1*@@jD*MrTL`vw(~lcBf7piS-b6w~RAG4v|43g+)ZpMD-()#Q z-jNv$nH*DO(YL}`V5=-!w^*f2Z+t=1!N3zF+CZDh>mM#V5?Lw5-$u^IS|ER5=~eXL z4y69QeT{uYG_Y8v+z{BdE7dahIG|W<8haFKggbT(5`|BhfQS zJVv1c%f=qAJbsB7d~tS%y;}2jYZeD+bJ7U&DyFetWdB1RMbnn$*0*0+`;yhMAS@8x zf$)q6G9O7@=Yvd>j8hw{OEn&+CfV+D}c~s?@F0+!^Yq9eyEkxA-1ngsdhcauq** zQkDF&<91ds5@N={u|gE6?iu@^kWR8h%u%@FO8UPc&r}aR@qOx=u@?x5T%_J*kY)kxRj; zyM5ZkeeH6jxrSOo0>?=D=>`81PEr3Uu&CM~x=pOpNz>*b0MC{RE*KdAfv3 zB!rxr$WOJOdrD~T$3q480%P2Xu(88QAK(#tuTkIjQMd+S)h5UA-#6>(mi*p>(|k@Q zCYxGa5wpKs9XD?B=JbvsuMkcTz(dao27Dk%1|K|6IL-4nqbAUa2&|;0976$0{gpx= zyle>e8`j6RAkegRUh2kUmP2Z6Utj}TGye3N92gNw;k|unq7GSJ!J+9bFWu8vn#GaK zu@faL5{Ww!e<+DWw=W4=(Uz0Mel#>yYfhx*{RK!fVr5Rh65TBx`zOhMrt}qrUc=SY zd(}9Z#17dMoL5{Ix9N;VCr?@PHSSB)zl6kasYk@zu@u=5t-t^MRMyon@)jS0Todf( z?3iAvmUt_w^N_Tq0H7@f@9q@qEen$XE8qZxs=h|$%AURItkFVnpXiv2!YzpGPM z2+hOOf+<4?H+yh;7;NLPH0Yo{^J6cdc?g`q6+Nt3E&3xmrzeqpq~7XX;|*Dp`=ThvJ98BmT24M>FdM7f@Y!*3 zc$;phPIBOTD=`A!O2dctQSMZh@F&{S2xkA6;fT6(S%PcqN%O>Jeua^=SB#YBI=%Kx zdEv=$b;?zfkM2^+I+x-g_s2pP)%02nUwtI!g~Ow1-dwqvWQEQ}JE%}E*$Du$DZ^zS zDs&GkAuoye%waM&3Ev%kDn<;>KFAO`IbHZ;wl+Q#$5o-BFveJ|?Vqw`uxYm%Pjs0r zlH40JkLF7Jxltm~?0{}ACbPHsRcU~V(P6D3-}Ri5UJ}QDa@k5Bv@5dbQZm0F+98jd z;Re|Py#Wtj7zRCw`NtE6NeZJ54PZkNLl>r=mf=>Bf%Fv|4p#o}qu*Fz;^4lB)-iS} zgqTTbrMuG+v$(V$8UQJ_VJs7k!Z}ckBbj>UG;QSYa`3Y;uSZjUUKyOBaDMG3YuOG} z37pw|kDPmLT8l+3ZmBQuyT<|qq1Qv)V${%oab4&`Ut z=2i>>e%Y0PjOBW{t3&qV=(gg*TP5EOLpnfWAWpCdT1x3CtnQ@#o0T#c$sx1ak+HIT z?EosL(GqZzDH&);#jdZe1GN?PanHz!Y~hSO0F!HdeYGoJ)g;Eln`>a0B0bWfdByrp z@z=DFgpET=btmFElFFfJyFhDA7CQ2^jBvUmAiC=6z5Eg8pOJtb`QEp6Y)@y>zjAU1 zZ%mkbLje}}s@aHoGGSxCgOkS|eTCXM5{T)gI4N5MO9y-o4xaZn2F~1={F(i}%)Sc(c}zzsim+-h>vah)SKbi(9He-7dw8IQxZw`XXAh{^ zE^A+Cxyet@?X&e1(-aKRnlz9?{67rBTK0i9DC?PunG*#IkgmnF653r_?$7 zpZup_BGG7BgpNG7F1YUvmy@a|rI68-r$SQu7{-*;MC7L(#EdY_9QUji!G$Lg>3RDE zey(*ryr;`I*SXY6*Qj!b`r!=p&B%7d;$2Ug^{vW6UmmJyZ=NNsLnXq@k|R3rT`mU2*TL7U8fxTygj3%Ds7(wrGHQb`g z`BbM;+y{(y)G}Hk(!QUZT9S+;B^%2|5B6VelJ>}tZ`t+&hBkX424#Xic&&;1f;mYb z;z{(vtt+`!-z+8*-T~7(BQPwonp;cx5w2OwHLIkV{^Tr6=+9sCFl1cLGZKby!+W#( zKgb5;QOi7)c8^*1uV?M)xJzB&kUE?bH43Wwu0r1Sy9pvw*4x`O3-qE_Ccck*@$Z{BjE%96ft{)56^Sk)qYY9qrc$o)YBj;F#jCifdXdcnE8Y!ok-O4AWJ1 z!F5!^rYVQsD;m2$U!mgNp9aloomRqaq?b7KH{6p*8i}UZgczR=1A(`LG*7Ot9*apYk4mD+xU3{G&%(-KZsb5gfINdlz*GZeb;g{_K|gLq+LKHHF@pq z7i1EhYCA%?fu=v9+Ml|-@-3Ojg_;OFH1IVb&AdC*g%(dECLRKand+i{n)<~c zOXL(UD@jq~5(sSlCE~~JJXa>wX0o)4mbEXUP~O!d;E7U zJk^#?YAaIQ<(*PQl`lp|7rlaEfCgJx(K)c3@1M~)l2UoJ;`<||EanaUBYhq;F6T+z zEjPR~H(a@un4awtZ)X#(Lsqkh4H&v*YOSBzT4N-nsuBvQ&nQ8fNq7BlJ4$rZtx)Y3 z-P$WN)k}4lqnC*$TsZe@a4FQY``GhGB%Q@Lf4-h-^4)4PbJlwv*4_3WjvTN(sb zqbc6lWTZO$Ux}N-$d`hzpx>O5csfd{TN){orut^_%RD`U*wV%wJVxyMYa7Dq- z&>4=degwXmNt$P@@elibga2;yVPYa7INxRB)r?T%yOw`Ed?*OGz5l{RW_gE-fEk4& z9p{KPk|2-V>d9hZ*25xpa^E+#xa5cLu+TU==SrBqh7zmmvayV3avIF{3#4*_U*mAw zqd!7HiIyblWzCfG^yyUdFbVcDa_R3l?ZOh;W(;rt=B^&2!LS$#aCn@YamcMnV%vVI zP1w7!Z-gKUCvctWRNajIhltnf19BvS$yjQ@PhgBJB!}UTf%&omOq3h}){r+ocxfF^ zye$LQyqG`z^fnj2Ka8I-%0r^Iz&Pbj;z{UMJ7R|b0TStO0$CO5`+RYy#2s7kQkT1K6z3^FYPW8(>zA!nZ{ znQ2(wH>C2Wlg*&ZI6x`I(R`0$IrYOT3D;K%AzTK9S=6c^2qKQSN_5f%CC&Omz1ZiX zhbARN_ea+X#rRLq9W62U`eqEFpqZFHajIR9`~JDYdU9GaN+$eKX3yL1NXk{@BHoQW z?4N{w$0SfR3s*8{@$K3LEon(cS5*47Zt9iHs;duWxMDJSudDldv{|}= zqHKob!YMX5uOdq@VHc34BMBd7#?09fXW8#KvJ&3soJIH=FK7Io%AM_*m#QYxsj_Xoyes2+?6Eo4 z^-gt~vRf#K=y5kOo^oP>CBknFZYS?*uE;IX9nG?^r>u4rvaVtC9rn+wsZLD&L^{#DyQTr4KQKn@->@|Aa zjqXcdp3_I=6H)+IRm6ly?(K>Y8A7u1(P5ssH`H}v(yLW9MZS2V+rW*$J?!7|H!s7g zk&ts{)vj9UU1j%nMMahgJrU&z?%BK6QELtH4J8z@odz|(zvPbS&4cIm0Y;Jm2-my| zlb1(`^uB_HBdU#vCLL9F+~7^ZXor3kXaU?<=D(|cZ8;5nPM=E*OG-bS(Qsv?+O5AU z2PQWrxQwf#A#1_GKGCo6{pP@#@O;b9nNySyvh zU39En$l%+~dl`f|(x>gAJr$1f9}nB2qzSyTthlDS05p1xZ!5mr$B51!UCY=?M3nqN z{!Qlg&q9fMHA-~RQFecZRpHXY3eEeC!Umo8&}eo@_sFv~MOYIS#9nkatfU~dcF%th z$w~o~#ZQ$~g0;|w(>xzfj7(fr#=CpZ_g4Kcfi|-kj{yvuSP`BUbmnccN$oJdsx`Zz z+)_thENH^^qJ7RXbhdvPUDJnuGkY(1)Na^y*SZDOcC(&Ue8N1iE>?7X(!udpXnAo2 zJ}GV!>E;5Pg@+%+zJRuw2L^aCgMy9L%{G~UZJW*3;^roF^=j>r2FFG{4&%v|Zkz3@ z%;=MsV~>|FjG4}dx2yvJ);2eC91+ZKY$1)qr<=3EVyTcmOMRCm8S(d%)l~On?*LX^ zEgGc5ArwvJ1$OH0{H=q#YHs+&jkrq{m4Z|cuopt(=2N+O+1v)h$>z@;XC&HzQxyC; z{J$yO-iBqw@cg)Qj4y>EN{kqk(>sH{o{pGpdCZ{#I`1}$z0nWe zVYan5lVhIB5jQdSkg=euG-xVb=?|-h5IEi7Z9%}fB_aV8G1E46>O=IXf*=YPPv*)N zIxQ)rw+t!USYI8rYfbhIM0FIzFYv0OQ(4x|F=J1Qp)j_>gIPDB*oKl>w|i#3d*okl zvFi^Q&Nfl-kh~Kk3+-Mh#p$NcId0g6zuxgqT9f`5QY|MD>9KoBhopMv=8vBe8J?aC zE5}?*q3vHhUfk5K!zR4~0}nqTwVeE|lqw49MQ2}d7mQ1_f){e@Nn7LtygPTSMF+tB z&;k%#@km_#mjHg^aNE8vpnj68W^5cJB~#+fk)Tubq!$tClbTw|8qg^iNB;LXDo*7(*`lL4|!n9fJk3M%<7 zEP(?TA0KUEn!aF@b;4L>(R@e9tU|n*8J+8fkZKL40y78>+3C8@2X66LywgDoXACYk z)V*fkJJ?7dJfeGUYGetkFxF%XyDU2oHbc;hWSwAXE@QDYSDp^p?pM;W>2pARMv(j= z%%^6zyrguyyd4b_BA;bSg@&iOD;N}w8peBSN`sd>$dvh~>p``kl$upr#or*+QZ1nG zFHXI0A~7_FvqTW}$O2SHF)Mg^O3CHmhgd8V0r3S6k-dZkbuN8a;k@FNfn_)%d;(JV z0@WK(0jo{Xi6qg)l$OVye#8vuUF-e5HW%U!39pgLZA$9}b`0d13X`Tj8#QQ~e{#45 z>Yv*KxiApDkQ8a*Qd>THeMxnCM~$QJQtBz?cNRp2t%f?$>gtx6fgU_ywIn-;|CtYk6 zo8gg!879m<&u`p$V2GA+8^(;VPGb;<%LmRBp5{DX?mxjv_iCaR;JV$33WG~72&wqK z)ZQbsu7JE_-s;POY(}4T#m>ze@aH%C3>9Q3=V<2&M6c(aMfC;#0N*IM-;8jMD-v-a z)H1M^(+=SWsI8)dvTzRCo35s9=hs@;-(xPFjEXMnelF{PHLg{-@h=LKG0@;Fn zNE$*4%{Elc9qO#2$CtZXHd?LH4Egq)X;9=@3=#yREobP$jrYQRU+eEgJ=uB; zKiRP!kuPZcl+&SO`Ijgpl7ok@nB5Yxv*t|fzn;!H8*eOY6(3(2y67ji*3Jmu%$$d7 zkinbyZb;7;?8y`=#MUtrBq|#P*@^X=p{Rr4G%LCy%))}rZGasN@2dcct_+ z9GphY6A^U@K_tKd4_c%%zYts@+TUjy-PU-pH?Yu*LSGVJ7a4VdUjW4%Ey!!XQ&ADc ztA@6jH7m%qG@b8DQkyY(ACgF5`<~s>C=5QcNM~Gv(J*n)(&JM(dmqsd3pcE%Jkkm( z)PPV4T+AST^Q6OmJ)gR_Bv+-m1{5yUs2~X`f!$h0x%fs}4NZGtvsE!8&oPn{=osA6 z;(Ckc^A=oN_?KAHHS(2$wi)1w z(?4cv7xP7HuVV9gO)R|~GHX&WS>VIpohtq@#slLNxa>w<_;#d1wLXO${^_l5?Hu5G zfN2%SX2-oEq06*zvoq1&tfR6~i5WY}nW*4|^hFeEQ`}B>x|en~S?H^fy6=10s6b$n z{U*jPVlZa?W>rZIH3OUxg)v`$#X)*z$%dA~=*cMk;Ds;J9?5^|RYbd2E|!7Q=OD(1 zmgrkR!kxt+QRz$ScJ|;f&BCKN^lI!paizOPpHH;(Z~)(UT2p;H->EN-L+qQWY$!WQ z3E5KBXLMPr#QnWwC4j50n^U!1?6ciR!}byC;j)oL&92Y$Q)3;5^{K|V(!F+ z;;@DHqDKSC%nI9XYX({gIBR0a@RHrG#yx93PEaAj4`J;pdTAYqvVg>59P!?+-l5x1 z)s~$ZLgzuF9RvL^3B{gC)e3ZKov7M%u>*Hn@D8`wEBmM&lPr#0PpHR}<3?1U5#fbs zo~cQDYq3;zI)8&m+i{U)0Cs^71BC{Zxa@T4FtT&-nSvD1+X{yO?>G69-}(g#!ha=b zrb-|`8j^)<390Wm_ISunWM>LhUq1M|5Zn>icPBH3Hl%5D&jpzB!8-o^>B2yud2P7% zmzc%a6&+%gFGc%7b-=(~0+`0BmYLe(w`awFPj?R$#A4E}jSvXuMOBMV1>^Iz8kgy4 z+3?PswHZ#gqX!xpy7#y1tz%ZG2HLVmsXL&Lo3a5#xx<2+>#GDG^CZQ&BitLDJ$h1! zjtS>!jI{VjB9k?-Z$3E;G~;~@jA}1&i z2xt-SB=!zvQFQvISMQmt!I)v@aT;N3{!1Fq^N&W?iXzI*irMGc%H5NDyMXE!9lRq) z$aHbK(aTmYL;Gr;iN`hnnOY@xY-4A)kWsq_rm2Vh!*O6BNEP?g$_GWiky}2E(tlP; z228Bn;5?6}@Ab(wJP%F?&Oc>rUJgEGdqHcsi2hCUkIMSB2WBoKiI-+~SpS14`Nz2B zxQ*zNTpBU2KwiI6>X3uStOwWjaXQNer;^%)$zJSf^UEZ0O5Hcm{w?Y^3kRh=1~{p3 z`vc#3rYQ|&&!d>Eyq z`**n3N05PY7M`5V2_c#a-*kwIxH6?F_%tB21HnC~F`W^=nC#?s;b~_W@v<3@EFfZH zj$?x04YPnoU)58V!5k`pvkRLFw3)<`ji}OK^F_}<2qdES9@KM48w7DGyH>h5$P5dc z{R85%A;+N>s1YYosd!7k{z`R7B);69_xap9D?6CiC+>Pekx;9Q6!;l+gnB9}wp(Dw zvneEy?)9T4pQcY{t!LiVo-jDCoCNYHg)Z{``oJ-GqNYcxRWdzTF{CyC<5I-4ky}@< z+F*_DgM(T@xg>1$+hQjRt8cCdkX5xqUH;&MvMJWspV73DOf_jB5U}INOZloMY#tgL zifrCxtqfNGj@QLuWyd;kqs+lsk}}Kxx=t=js%ns1GXd!o)IlHZPSTZ2|Ko;zBtP3W zySg+A^)BD)j^D)=1gn(ad&Y|#7Kf>(ub|%7JS6|2YB+^-4q|L6b(JK2Pe@b6RE*i1d@GkH^wmiea5H4Q z*0AS6gz+>FvbcvC8s!2e5RCZG{Bz=|OFu@J&D%L4= zaTRKH7E;D20jbr(-`V?7#gixo4YcJ&GGFPA!0IB5yOWq3NpZyQYI{A(Fp^NkPv`5v zx)6Q;s6181#Jcqd{!Preeq*0rUJfDzzMFFH}Pqj4V>&w&w8V%Stj@! z+?(e$eArHWZ*INCmfSW4Mb5tglSbqem%}ad_))|o=xTLxjP-qY zWod^eRnZyky~5oH4=d-PvddCV@|q%2pkQkao$%@FSE`lL=}qE3OlSK!tEyxZ>1N6yO@Jw>nrz5clHh@|+ZLVQ ziLs<)$3fRgLv~cjv89Kwt{@%53TRqfN>vc~HMI+F<&8|1kL0-Fo9n>QbK+qP&jz&& zfrB~r&<&3#ik_goSw`F}EDObDNuP&7O+|q2m2y$du=QPkpG!cseKywG8QtPaggCQ) zaefGh>t=2PSx3(0_!PCueTYV0VHjF{OoNpi07O-FCz+<(#;#?;%6XXZ z9xkkXEA_}(chpZMnsF$uq94U*bPH>#mQf*nsc<48`iONGG-pM&ca<=C8!jsB<&PfB znnA~bQN?yaUn3?SmvdZgRsN|fDkJDKS0k+Gl{X=m4A+o53^e?#JZI2%U>bS;xABBP zReah%!iA+n*sj~*asZ!Nv9*zw(mb0Eu3*}CFk&@Rg^k(i(WE|mu7d`7-exne(@?jk zdDb9@cpA>$SbW>}_A|M$22OOfV~)lr1&vek4`!=WuIPQb-ih^J_9Hb;UYBUdqJ}6B zLpX?po}Ao#l*wojlc5v^@zvRg-(}_>DUAEo*Od15A>yz@jV@PvlU}DLtQTl+HurC( zj`EVVZBD7@ImPY|KKg52wEVC4Wl zk&TUJDDVm#qpGh&sbnKosBw5}t;s3DZY48y_0DT2vns+hkFQT}$G*A_FOo!p zy>e@P<#ie|hY*lgOOI&%Oxhj0&(tCRpB{YA&G3_Fb!jUuwJ6!wCne${{vbq#yr$0% zY&oSWTq{$dYI3;PdxArOXx{W?R+yGAR6Ks%1dU6~*FMW+s3cOu`|}1)6{1&aW<9Ak zpc3B2P?mlxmgfrAg1;ZFkR~NfBH|C=N*QC<9*0xow*6_5Ei(4^M{Jj*qlOi?u?~7 zA_6Pn7{u8Cm2mj=Q6#s%B`;q=Z7CjFc=4?W>>EJwB{Z91(TXH@A%waY)*YqHGlanP z)iAACS54qos5_Y-bTW<>W2VjO$nO^;c2r-V4CKJKYMP0P>++L<5PS^H zJ|2+37f}2qYDd=v)?FI6YEkP9MO}ej&TyoU9S3N&!8gMVPy0HOCaKLmDWP4o3)A*_ zb*>rGKLB8AJAdNSXkwzdMd)tuj_O>QdSsvOoB> zd|Kc3;oADK>~p}Hv`ICV9%RAAs2u2HbkbKc7{EysMP~(BCf>`U@F$j%pDa@*{^YUP z%GLfgWsFrU(Oyxm;=Pg64mty3-nTp1a^2ZmjCqVe^Uc7MU*A#cjRK;4DZWoKk!|KH{R1KZ_bWo7&Sh3&SPYG!VBu)&K(q5&)%0IB=` z;da3we$n@DXM+uI|3}_c&f340k4)N!Px2R}qpy|VRp^Omh3gu}qeL-or}PfkV+kC5Jife7-ux+3-a{ae5f z+6YFGIk>B&N4&1#o=6F_NXU(_RHGEDZwNdOBmiWY4_D9zMEjqC;Q9{MfC-q3uWR5X zZJ!%q$Lb$PFK8r+x?r+H1q4L$5`pAzlSn3T6aSKxXS{kjsA!R*PJqfLZ=%ZO|5E~GUxI~s$ zh0ULR@vjN^TaM;cRc8vX&0cH}3p%3T(7x#C92^{Ga2V#l8oLuA8v~~eK9}hFXFxc- zD6IP~DpALv9#a|V-OOs8glUC-sBg_xK<*7y;<8yz6%vxZdb3(;m3zp$H;8`7pQ#}Z z734C3!Qfd!c|R7$FfQLT8v0sV_=a#0n?izaf;@|>g1>(6@53{GPd>lHF&DmJ2>lk^ z8XiAWKnnhG<@)NJ{!zwg1nQ;tM5iLnUG)OsEl&0?-;iv-o!3jA-DV8U!ybC613-=q zapnk~XMoS}HZQ4iLaKL#NktjliJuq$)|sf*dMk`a;T=Oi(Y{J^%7SvD;R%RrDhlwD)=MeRPd&4&YXIoqI8?%!q;MK7q56gqVL}oi@oyD3z zo}M59**C@ea?oSzG#CVE9hhJYNL*(**<`L8P;QcdWs~5c5}scl@fi`sIWL-J4B7_K z(?{su392Ii z#8d59RrxPc%@05s!P80VDK|v)p#z?Oa-E+Ix{GveZ2tJS5N`aWJoX;=wHV^W{)Bzj z{-T>BsA-CLmTwWv{JHnfF7CS~WHDtNTDmtF_@4Ym2J_DLQR0EanY$?YG+lUg&a%-z zd49SE{b}z2k+s3K`8o2!lTxwfiECu>3w&X~I8_VzA^xoRBIp1?x806Ss91piF*o~$ zO>AOm<^bQ+0$FQs0~Ms8$b&|?xFD=^b_DHO(>LFMKm1<(uRAR5>XN9I3IrM>45@Ex z2j*B1iic$8QSmYU^fh>kNC%a=p%ylC;C%(f)5d^cb@l(WH9jx`Hm3(<%j(%o+v-2PZ{AU?uE3w#yxHTt5F{4D z%^efq=`T+Im_2Uv;aG*K}3-7~MEASuio(jt+q}Prz;F7tQ-rR1xZteL- zcg&o?XKm8uk3P{!<-qe#?6N}-toaXtM{O70w_C59BS?>a_fI`Smd%gx*R0$>Z?a1e zC$P;QI@VEZ9SMw&)y$$)c>|Y^?sO~YxjQE)Sg#ey}rAXRy7sk7JDPUPLNf|Mck?P)+aViWnP{leajpH20vo^`_xhI~{vWI8#3kcj?uy?_|_hgj;FdGv#bq(iB~?cf+=BmtWUr$biSi#= ze~?1H&?p8spcCQ{n1xt`9G4R^**f;8UR83OQgPlhF=F|K`Ih>IoFs;6!!bY-G zAksGc1>TS;h|*0;NKbO3+VU;r4hjDF2pRRX2w}^MJmqv0TSwVvhe4_Hh_+ z!zZmq9k$DCJ<$2PNxtd5m^H1S;Cb*F8Eo{4s+;}usS$VYTxd7JhZ;N9sK`_DGx;O} zYlMMjsgffzoAIWlP`qN=4hjmy(cBAo2ri zQV|BSZOgc&mw04qWv!yz^}F zez}cCPZ3z8_Oi7Ow;9-tvi?#1J)(Ppd8SVy@6oE0V}o0c$!y{Xgm{rL2mZPP0oO=8 zdbn_uNKa{4ytbMaamj0EO#L}dJJc}u_W|^|>d;*Lh8c4=MDXRU_nxr6$j87kFK4a< zWm_n55<;t1=s;CcP=V7JOH;26Qfqgy3uOej?O@f zPFh=7H6GYIendLzg4xQFT?nKV02>cS@wxbQP&Xi4JZ4$zom2eu4Zc=+{rIH(fZ%U! zXljBp3{Tr7900;Oqt5S-8Xzr;@%N{0)MaO8Y4zK1r{@9FbUIVID{0ra2t=TE@7&$Z zlc|U@Qj(Vy_|R7KK~!GpOAI~elc#iaN~p4y4qe}w9GuxnS$Zy#xP!b@O#$oCSLH|I zi_HxXvOL;H+pq*{YnqMneJ#u;khPPzG%)2V>h5D~M2>2PA^6x@{j0F-zKomW(lT%h zStxG!w(GLaNoj)&=^|(fHREJTp`L0P{8M_#O6`#qO8p-(m9f@|`+NnAlDmGE$0e=n zYN)z(X{uHZWJ%(hU6^w%cMeYDTPms!%134Gw=;jj0e`qw8$wxJ|@)e@w zBb3>gc?ik$d0({|Z1nF}COm9XaebzMrT}|bp?B?57*RGS%P;&~SG5%pj&P|5dr2r0 zZZ`zgFHv7R3MiTmb`{8V(r@_FW3a_chhdjW9}PhS4c!KR1S2!(yDlB+f8_S6 zMIz+I3^Cmy%1#9xRCoJ#=rxNrUIacFE*M8*iz!RILQ~QM3z@(TMLn_5%<(JnFj**hQ3WQozs2-^EH=IX#vsZUZ!e8Lsk+ zB8U*NpMP_W&#w_RSnnyiObS^Aal)!e$99CGdXit-OCM2(UjP z3>&xOS~w_U21YMImP!N~gB7Ghb2u3wp6-NPYJX*&lRKxwNrk~oGnP5RsCbxyzjzt~ zdAk5cj7Q!J*kH@3+P(4`5!sbC1yf3^)@^m{cEIc)UN zY{^CC_b+ZzQ9l}^oOwg{76?Rt@knFGn1;-@GVl0vM^TE=w#+wDg;5& z;MhwutS5c#L}{(WbzYfF%3c2wM)VW2rJa}q7CK0cSSB~qY4N^MXi0J2Bx@J=^;-S(Lrs=^EHn~2FwpJZ<_ZUR5hR?|8}c^N zIsl~F2S?b5yu?4_P?+Vlr;dCi-QXo-E|vKgK;xpi3lEb&*nV({yWJV#vQM2OIj*og z!v5*S_+55lohc5z+z>*ng zGee-lZ1@oCKbp6+_>AF{C^B<)KB;3EOnKZs>ATM0?yCNma|ULtQ~yvy9UilU63+2U zV&8j}ss>J6vSoc@Pc3Pp+*D=RbDz}PQNFpJOyTl;-15dvs+p-!!RHALxRl|;k0{^R zX2MRE$0DrZ?QmJx?BtnKW8B&oy`_w5HmAtR>P7X}cY}pV{bBe&lBl9%&4h6$oJ2pD z>IeGcU-iVM#!)m0!$$f_Nrkl}nW>EyCC2CLC^!-o?*aQsrw_1J?`bU|Y__skIZt*q z=ArMR-NqHNxVS!8==YJJKmi{$R?^J?^4Y{zURp~XjB9Qg=N}22tU3RG{OWv|->-Qr z1m4uhWK%2sg@T8MAh;%7lLd!ep1aU&12#~ly=aH(QrR|W?S)R)}!N1m0k(snej2Sv%xL#gG~d*vqT#owNc`q2|kBFm^7MnORiP?*UQ>%0zWAs zVJDn{+gvDf>}I9a{0GXK@okj#l>(!;-Gf-(FLIV83q{ImsHgMV>D=ePVYz z!9^J(guLq3W*4NLIBV<@Q-~n5H283_<;ci4$USk#VKUVpG{&@3lW4MXHl!>AksR=? z$)Ea*h&aor8LluniNA2t-8f#3O8?lfAg4$dW1}|f5@z$dTv)9h`s^dTN4jtD23_U4 z=vp$XG^>}k81g=o6wj8zYuD=?N%h%-17rR?Zf8&MOx4d~ofsixnz-01M&aI@@17^j zPSz*m!BH@zcc4_P=QbAWh$aFNvZC^BjU1)IX)QF2nAQ1~LIZTf>|}pQMXGC&d7#-C zl3kh$&dQz?6>6|L2ck823H2$iYLu1h{P>H@_5hMvL&LL3{ZzWq(|w1e<_8u}!q)nq zlV*}3UZq|X-N>dlCN6)g{cXWd7Rsu3s|_Rmr6Xax+hGS12cnAO)UW2Qb(9HU;$AE+ zM8{aT?uzkQ(k9NB+;df*^}Axuz!S{u^m5~f(%rr+6*R}?e(Q`rQ~o!et!ecG4;7|w zEwyTD<2yd*_H4jW+t7!<7385&8b?@5{yTwGWykmoLPexuxRA6obvj&tL}&bOzmN9* z+L?#ib6z#?f}Ku=#930U43FcoWk)(}DNrg%UH2^7%B9vVJD0f9YPg-L5~mhystkC+ zlJ-Le9mo479wgY~rH@p3w@q4;6SDgLjLNnoE9AqlCb(s*qEno-wGg$Nh-P)`p27Su zXS&VV^4yS7a)IIh_>2MjG{p4B4iowmp*tDO2Pxw^f1@1wE339_(Wjo84oe-@zi?NMq zmRZmOaYjTn#3E34Qj(0z!vGAD07VxL_d?{S*8%ZArZ}`bdJV+q>4FZ`mu+|z<0kDm z8m#PzDokAv@$!w`Lm>`aru&Esq@JFURLDFf?A281J??rY(@g)4@nw}DXZdnpA=wuC z+`S#}Vk0L!AU3Mw{rzheNjLH+X;iGi#Ujrp;KA{xVoqNop_9`lkT<`io-b1R^nHU? zQQKv6Iw%;B?MXkZNbc4j0aquZzd(oaI~??G7kJ|z)m{9u=wZ>akdHKI**VEX6VwGW0G}aF(b};!Lme(u|(VgpIN(`lnf;Rl76Dbo-v3O zzu2JCF>la_8ZsM72o}n>mO>uKUSxWzA79N_ZiOELs4F^2s@FJtn57cHJtS6<1bu0V z{9rpSVOt%W$o-o?c58B8U73mX5UEaP_!L44B+yn;9RT?G&Qjs_9CqE=Rs{Smd&w_N zbf(dtJ8tX5(wVI#c4yN|X5?{~;h<4&KkpuTC{!J*uJ+TI7L%wd7|Ho7s!A%4n#a## zl8lwljUC%zJIcfx#o!6tNc$?EM$0`@lceo&qT0DxsZfI(fE*DiCD+7UE2iNz&{mP$ z9-4BUM#~LPxX4*(v&=!&zCS)dM1&mY^9X;AUtrKmIJiEsaFma|PP{R`f(*}B2gSo1 zM$daZbi=s9Vm0D>s|UY^7?EwXDJu|uJs94f)k}gn6foD`NLbvE4GFGO9&oMwF2p?) zhtBO7e8OfpRpC29D=t82;-@pvSt;sRDwVos4--!H!YzpGOv(e zCUChH-xSHPL;p%3KK`V8U!6AkThp7)1sJxiwsilV>z*aW1%bp8oTjJ+TcnQ`_<>pN z#1e)T;INdWKc*&WlK}tk&Be^4s}n0!jmo#55!QP6$8{R`hJK&*XOgATw|IXsLH#nC zxQuBO3mCTIW7SQ2FO_X`nD)e;;4t=}jIyT?o;XIA`paENJRo(vYlopSbg*_I61-43 zifazp?}i&1wH{MfL}Vm;}22ErHL$p#5Ci%!97WFp z*WqK+G;zvnv>T4xX=;4e_9=O@{k|%t;K`kxJfCGDV=sGQSEp9bqT)59+rsd4?>9LI zzVgCbX&=M>l@-XbGMkEnu$%g|TCh2hB9QP|faH2($N2B>HxsSBh$T(s1s&nf#mh^V z`Fi=%7R?_NB3Ckj;_RtzQgV@_4%iv5%@(*8P#+|dGzTtR#36k!h3&|{lqA35>F+lN zTPdL7V`*MD-oQz?s>?=`C#t<9V?BTNWDIDWV{gFtZ!g0 zua1ka@OSkYkZtauMy>VZ#MXeO#S3w#Pqbl!!EgHb+2P7lNWcMKqQXs-rTOAd#ElQs~JzZpsiv zuaKt9bz0hJkiR)sD?ZHku6s0qOmRsdJ_v*F`wR&s^Rxxkk%_6M0VZ-Q@jT1_f`MWk$V>yv`CEHvVJiarn>Ep>ubNKVOU ziS>0Qj8GB@TUtN)<8Z|nEbB4WSb~j$I2J)}c;_GvNY>3Hi-C$&<2Bt}?xoAWck7 zp90G3kkf=d19Vu|27ypfp9ePNnhvfU!T#0oFyDvI=Q0`{TiFuiwMGQX^+;O$Gt6Wqn7-OT4q|9+#I9R1q2y zqPKYNN|+UT)!JZ}-^H_U!Pxl2`gc|6`#0h`Qrv3_AX-h$CX9`iKx@x^!Xn|5M9D|e zZ5aC0xr_*dxJr+y0G&w`@r4MJCQdfK+fd)e-JML8R{fAH?VoBT;2TVFsfl|B6>1aQ3vmZFHT57;9{&v3(rjtZ0;!kxnKGMFm zQJN473rT!Lm}4}j{#Ct^Ud0%OJDJ|FS5@dSjY>LyRBC;^Mtmkb2Gf?i*U?eLaqzXF zwi3;yI#kMCPCI&QBcgl%K+S0j-L`ou1>Wkugmq^O4NiWUO*oDYx^4a^OO2SAS1}^a z&m`AVI0J3b-kU?oN^Rl8;0bUWzNFv(ysMlX@1#kL6Jc&AR`FKg`x)+#!`CC>!ZSTr zDxkMAk4H7hE1e!)OsErbyPP-J%#e3e9^H{)Fu=UR`UyJ)_Ea)a;3_cGG@6P9#s9Py zorR3B+k5U_as0u_F9LOKb*myJu^|~3S1-rONv&+~y_%w_4GFd=e&)FM3Ve|5p>81x zwBti6-kT@BjPimAG^M1K(huRC8Mm45SPZK7^H{q!E@q$rh!{XXw~+Jz39>Gt2L)j! zo{jWvr5dtGW`4&#=4zwHG{`$O8(x0m z^of%rpJ>J?-};2S!#P!k*nqEwNk0^=(uml0) zm(3N;cOm7cwmcZDV|zonV~`#q-5*3$9dHy|xc&EuWW{UMHCu~k7J(Y3PuXq;n0 zKwD5mdagztoZv;jWh%(=buW-RptqQGDRsyZ$^@De(1%H={+UOPL+hM0Tp@jH6fmCv zNeRYPR6!)t3ifR&v$@F{Xv^}oBup*fY&c!c3P7jwnQmnt6MKsws~snLGJ4>eK}xg^ zv?@36(X&uL^FBs98fgA*0;5yf+yiZlCX4aZo^P3*cJvSv<~tWEi|2(vd1pLq4$YNF zeOU4>9NueUuu1UtgmE$>b(_~pj%+J-S1Pm4L{N{qF@vm2VIG2=1TYS4mTu0>L`o_> zBKj~iuO$7!qFfOf3WxQ&ueJJm$BZhEY-aYvxxGpFiR+8!$Uqy(ec=q)F~TLH@50{( zS}7_+g_wa8P*Tj4Lj{zKBy2DDJ{m35&Ab9|PLRR72}tyWii!yDhHh4pOLxDO4Odeg zMkfA#RSGlBQ~531X^V`VR*-YMuip)e>~2%Sl54V615koY#q!z6d$T$HeWb-U)P~}W znHYud4kj`7C2k&u3~vL+IYwnIymLzhR?Q5mDnSX331&%?&vLRJt~Q6&`H;)Q8Ij>2 z<9aX6aQP5+A%kR<8Bv{iDf2Ux1osVZsw0zW=N5V(8tp?Z95}4(D=T_%br`%dbm^9` z$FylK+-Y7Zeof`DWa#Yr+?O^uw_C5WpIp{DhPRd1_q;|*mxWyCF))RDZlj6_yjIY# zs0lN&JBSO%_A($6;@U53(WS7@U2u9B!^lWO>Rdtr7 zJ(@@#yp|@qQNP{waTr&Xh85=%O9xegG<NSkaIG zZ4A3L!5ZgJMn3fppHop`nc6tSBrcoyy_ZlWWIs!4!F)kNI}V!R%Reg`?1GcE$}RxM z3Okxq)aJFn&E|UG?SE@vE2wAEMJ{T}Dd{v;5n-ejkS-3D{}3X34z`Z-Z*jncf;GMh z61Lcdzq#$7kl##fQJYR#k?6`Pkc2|c4<~g!Snw2J2t%kJ=*zVx$)8{P{f*t&!)!l> zV2RDkZLP&oa2^wMx&lL05-Jw^khZq@yvjk-?hyA*ZI&(fj;A^O<$N)kvS#W|JKSi2kqCq7e4N1?$|ABwgoktSmM=gj=b5q2-| z)JS4#upjlvCWt*e1H6P07RUM#G`dTjJ$}xRNY5H#e0uMEeR|(#MVS5tC6XQPr&^?P zBjfTWJl!;(n~E#77mrA?LwL!EDKg|Da>!xw?LIe7%+KiCsoZ>_>DpIC=Ed2Q zMmrPn>W~m0m&_&@7Kv{pPVLYh5ipw%#y6FCz7DcY?byvuERtl0L#mzi;f!isN6|yt zA}wmHSy3;*O}w72ZkE;_xnh29eq~O@wjX_lU%q!ZV03mH=p%krH7lxzxWYN|XRyIC zH02evh$r1uc{&O8A-qS3iuL4HB1?^<6hqgUzCk>aCNzMqeDm$DZY=X|M#@oo)zpK$ zdNM5Czx}5Vb7A@He3^^D^Uoee(a+IJsIa;y#%}rTh&y7r2GF|c?EYEvB=_v=KfG33 zCyVLxeR36;My^irc^h_j9a22fYpA|96#}JLf{DT2I28EUCoCxoj@LgNL{5?uLaNB= zDTKb@r&W=o(;tKe-}Ak|u|*Hu!*fmUZ+-ZPuIblu&bWPsB`ztVyZdDRBM(5-ymD}2 zk5;Q{v|V`j=Ay|+qC`_3e@<~@@%)UyUzAVzOq{1`eAn2Tuq{fvs}!XO-v2U;0mUqu z;Qhy12}6Z=r)_M^Ilsyy&UlLRU6l{m#BA%1Z#zql*Ibz}Sn770#68S*#NT@X?F8jWhwF>TuB5;Sshn72D^i^Gz z2gYIYM_C+HBgN@`xkYC8Xe^N_mhJT?j%4`FlP;5M(}0nmt)%8&`zGj@poX!w^!MH; zx4@}F9%N1zT@HL~4f~%oT;{1KrwB$g44>44dP*&2se~n%w)}Q_3w0jof9#^)3F7N3 zzAOO+lowuJGJ+H3f-U!HeWQA@Zh#e z43ukSdO+IMVWxRMGPkPFN$v*84jJxNTO=S|2>kKPCY%sxeICHn zj9~y?Vf3GIN{lD`?%v?+MCrLX>!N;<{LrV6+E%8wi$*1^|H)(X7lf0q_b~mX? zuwa&6@oubGZba|Ckrr;m1SUMIb|eO%U9N~1af+ok`}PiQe6(T>wwPIkqakXQ9Vzd1 zda>1g8Y<;DAm01YU7}xs%C?*%2wBzur60e~T zEz42R@YSbpizcA4LYEJ7m_1ZdW0Z4!R^V!jH(@VHzRlX`D9_>HP8r zZSfodhiamY*FRsey6V!gsn?a2l=6ttR)Je&l%Kent)_^O!ovH)s!lNtaa7n0VL6YK zzJzIt5h%@m^;k_UA7p1Kqn-mv*1o*%-JKKb`oQ-#aI?)TqP%YFAoFuc8xNwg+930k z8*WLfUsoSNIPb$il(U{>aOs=tR9CX(HctfcJ(N8&*&n5L!aZzYK~twkrcctO?^>^A z_-J3o*6KdzNNewiQQ5#r6}{OC#LH&0A)oln88mG!@EO0{Vwdoj>(BYoP9~xae4ix^ zC_1)^!0L766*{#a9=8$BZR6vf@-Z*pr>OEhb04b*LKV$zhkd41z>%WgM` zGgTOV*%^L{Ib6nnGxjEL2Rhbw4XM($Sj2~#F2GiVAW$u*V@ZGKeO%Mf!fL|LUTr1j z1=YPNL0_KwRo@0!mrx-XFXebZm|UJX1kUbI^wJs&_cuI>azLRMxxl3$s+|*lc0VRS zF?k-iq8k6V7dF zeBTg3inRhG!RLn6yj3*Vu_W(~+|pbXkmRm#Z2kRS&%`L>=)HtjWlbOH2V^byVQddu zTqHU3pBk72Kk^!t#JhO*9TrY8JKB#!7eB*{itvk3=vxF(E|@oT{8k^!suaC!k$HNq zzSjV1GsX>9C_B=k{T9;ko!AOjdgpp$E&0jQK9n;jB-A=0j1w*{wG`Gs_Csk;Z7&YkalGRsNAR z=Kt}Pc@A|hD$M-q=ShN%mM`!Ul@pCW&SJVpou!NUS9zoqOnxF$Xvy*B@0IB&!fWd1 zq|hOq&T>YHgD+)<;YVl-u^-+~FkMijq^=sd{2)`7L0xdW9>1JCGgZ}w%YtBSo#v)Z zzN{z^4ys1pH0>f3%NLTiXMa#Y92>F4U9WWg5Z8`CaOR9J&rXGc*GnHPzx<1y?Zy$c zb<&le|C^eZQ1_+(XV)%enw?=Cp=(fNW?uR>i^~XDWQ|u^C>4jHMjsE{l&=iKCnk`i ztR(lQ%wX;bp1*M*`aQyA#lwIsVS|g~HS=i;{b@sIj-b;UX2T*Wp7?wSAC9MO7fV2O z=RQA!!MS5fl0q!-UEq%!`}SQ&KBnpYH2;UFoo+09bT}uGZe-|!4+nO#*t(!q7frVx zU1hj4=b(6O@b!kqG%bC3iRnF9;17bVy$n2X1Gdq&~)$z(>$ zsX-0vbRa3s%en&&2zwSyKFGbR<8mp$jEMJ;oi$atD{aip84zs<*bZAezo3SreRGIB z#%S7^qQm)E@zDiu%3h38kU|2>#ils&9i}dtHv!(y1+ibvnz%dpPuHlr@^d7}HKy4{TBw z+TuD|$u?rp#<2C2;0^K`No}G9UJ7j6g`9=Y_*mgr1dbo$CaJO&DKsP%!v zTn?lR?@aHg9d_@DerBTNP{6WlIVYqg%cZh>)ke&yUIz2Pvn3ImUZ0K|n0jt*da|PV zw3|9K28gvtH}ZU7jzXfojw*1W)g|nBna}-=Wc!>l22LoWmKlf(E*r+d)n=HaI=$`N zS`x>W%xm48G@ijPO|zR=1M*5o(OqiCPMB9CJ9OAIPGAHR>{olDhBl-*8WnR-QJs9gPK@&73jwfYS%oqu$btl z^M0I3$GX1K37~;L;Jvi{Op5My=N=jod8^PjKfK;ibTsJa%(Bz|-fERTY2K_Zot10H z&-_KbnJhFcvVD37nQ2hN_06+AT%@sNJj#^Ja^CNRBAARHM*0~k4i(oPzvFRB)_$-i z>187>b-^|l2=7HWs@-Yvwly!$*p^?^1u}z9nyT zy547L>zovCBSu0aZC6W6{P^{|ZfP<#_U{@k{!C32wO`-SFNi3+Sb+|H2bNfKAu1z# zI5S)E!NY-gAR*}Y`WqONY+h!peIGwY;e%k-a{aWLE^(DA$crg<=-eoBOpWx9=kOOU z&6@Nb*fey-tV6`+>T;EE1MP{Zku~=PGB$pC^?!RX+H@X=vCdnIanA@Px8to{<$uCY z{3Te7+%Rd&*USw0X7Ywc?fdVGd_q^}56Fu9`YHOi%5+0#1#gEF(;_~SgiWV8q~3Un z)-vsQdthH)l-WUMBYSjRuPc6GlBnhKoD9Pq(aM z2A&Md!Mq=RhWwnWU5h#I;SOv z-{5^*OLPfYelUR7>F~_%64eaD{0K6`pVnS%DW=RtX{>xh_=mK z8t_{fq(Ko4QooA~}Pe2W@+!AkpU>qBrM0DA; zR3%1@zv8~*A9nmiWV=N&NhZQ){{DQAfaM!pY`^w#Mk9vJXr0c61wGW@)yS5BrcULD zTLVPW;w&Wp2w~DbZFnpM0($<#Yz{oGtf1~_L=4nO@^jNs!FR`xJcS#ab707O!i_k1 zEr$$+DlV;<**#*RDxQk;47MxOH8D{u7kEPEVjkm)Wb>!^tf0-1b|pFNg%Sq| zR~NqF()UJRk(KhwgPo_fD3eYP6Df(xNtmQ96}87BlF+ z4hnbosQNr$Qs9SxP`V3)We8Qx$s1UOkUT%$Ui{PSb|$zT_vUi=iu*cchAg;9t)-wk z;5I|gN&!ZcxW>LCg%eZXP_h*N7a^1{uy4(!I$&KtzJ={B8#=y+qI&XMPHalE5XV=a z4+Yn&Y^0h_aLjN6MdPi~H)w%z`X&o%Z|mHpHqU7{G=`u}9!)m0x0Hh?Z;CNZSXEm8{R)jns`#9-;L8Z$7cJ01?$T$7cLQ$=#$Jq#%n2PP^==g$=#wL-|3zuU9%3NRsu<&EHzrFC}BgqBs#@S$b$TxS)dsgP7-sxzHlx3>` zVLSnrO2$;g*(&2;xWrP*hNUz5LUEJ4cX&x#?kJ-4#2&e`a4>LX-+O%E6>ZJ$`x z+D(wv-z}xWJgX^@ce2>Gi!Q<8QMsazW+V0%jYW^sk9b^9wegS$U(*aVrRzNFa~S7N zUf0&w)C!K+p>CYz98%x*G3ir?5){Bp4UtME8L^hwSW|L_RqL8%g&^Bep;Vt`jX148 zYbm!u<%EgCV}tq?YUVOMhMb2=&We$G@e0Nk+I8|O87eO|x#F~$wR;D)bJ17NCB_&B zwSVb_&&OE*u-{isA)VHp`k3U$u&F6|IzdF8sn|(zwV<0S~?%7yt z8w1?YbABSsR&U?<6yl$_>0-plZk3lxN-a^1fZwrZCC(lg3?D^btA9R3nDy;^LsNAZ z&q)-7qKEF7G6+Cs&UTubZO?dm?&i*+wRlgAI`US91HjP-WF5bVam zIButQsM%M_2YZ2HA3(P&{Y55c?zczeN}r6B3u&s- Slufq4!ZDGkmlq$XE%!n{c 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

rT(6uHiLjeqmD0U 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 literal 0 HcmV?d00001