[
  {
    "path": ".codecov.yml",
    "content": "coverage:\n  ignore:\n  - Applications/Xcode.app/.*\n  - build/.*\n  - .build/.*\n  - Documentation/.*\n  - Example/Pods/.*\n  - Scripts/.*\n  - vendor/.*\n  precision: 2\n  round: down\n  range: \"80...100\"\n  status:\n    patch: yes\n    project: yes\n    changes: no"
  },
  {
    "path": ".github/.config.yml",
    "content": "updateDocsComment: >\n  Thanks for opening this pull request! The maintainers of this repository would appreciate it if you would update some of our documentation based on your changes.\n\nrequestInfoReplyComment: >\n  We would appreciate it if you could provide us with more info about this issue/pr!\n\nrequestInfoLabelToAdd: request-more-info\n\nnewPRWelcomeComment: >\n  Thanks so much for opening your first PR here!\n\nfirstPRMergeComment: >\n  Congrats on merging your first pull request here! :tada: How awesome!\n\nnewIssueWelcomeComment: >\n  Thanks for opening this issue, a maintainer will get back to you shortly!\n\nsentimentBotToxicityThreshold: .7\n\nsentimentBotReplyComment: >\n  Please be sure to review the code of conduct and be respectful of other users\n\nlockThreads:\n  toxicityThreshold: .7\n  numComments: 2\n  setTimeInHours: 72\n  replyComment: >\n    This thread is being locked due to exceeding the toxicity minimums"
  },
  {
    "path": ".gitignore",
    "content": ".DS_Store\n/.build\nbuild\n/Packages\n\nxcuserdata\n.xcuserstate\n\nPods\nPackage.resolved\n\ndocs\ngh-pages\nDocumentation/Output"
  },
  {
    "path": ".jazzy.yml",
    "content": "author: Laszlo Teveli\nauthor_url: https://tevelee.github.io\nreadme: README.md\n\ndocumentation: Documentation/*.md\nabstract: Documentation/Sections/*.md\n\nmodule: Eval\nxcodebuild_arguments: [-scheme,Eval-Package]\n\noutput: Documentation/Output\ntheme: apple\n\ngithub_url: https://github.com/tevelee/Eval\ngithub_file_prefix: https://github.com/tevelee/Eval/tree/master\n\nroot_url: https://tevelee.github.io/Eval\n\nclean: true\nmin_acl: internal\n\nframework_root: Sources\nsource_directory: ."
  },
  {
    "path": ".swift-version",
    "content": "5.0"
  },
  {
    "path": ".swiftlint.yml",
    "content": "reporter: \"xcode\"\nopt_in_rules:\n  - array_init\n  - attributes\n  - block_based_kvo\n  - class_delegate_protocol\n  - closing_brace\n  - closure_end_indentation\n  - closure_parameter_position\n  - closure_spacing\n  - colon\n  - comma\n  - compiler_protocol_init\n  # - conditional_returns_on_newline\n  - contains_over_first_not_nil\n  - control_statement\n  - custom_rules\n  - cyclomatic_complexity\n  - discarded_notification_center_observer\n  - discouraged_direct_init\n  - discouraged_object_literal\n  - dynamic_inline\n  - empty_count\n  - empty_enum_arguments\n  - empty_parameters\n  - empty_parentheses_with_trailing_closure\n  # - explicit_acl\n  - explicit_enum_raw_value\n  - explicit_init\n  - explicit_top_level_acl\n  # - explicit_type_interface\n  - extension_access_modifier\n  - fallthrough\n  - fatal_error_message\n  - file_header\n  - file_length\n  - first_where\n  - for_where\n  - force_cast\n  - force_try\n  - force_unwrapping\n  - function_body_length\n  - function_parameter_count\n  - generic_type_name\n  - identifier_name\n  - implicit_getter\n  - implicit_return\n  - implicitly_unwrapped_optional\n  - is_disjoint\n  - joined_default_parameter\n  - large_tuple\n  - leading_whitespace\n  - legacy_cggeometry_functions\n  - legacy_constant\n  - legacy_constructor\n  - legacy_nsgeometry_functions\n  - let_var_whitespace\n  - line_length\n  - literal_expression_end_indentation\n  - mark\n  - multiline_arguments\n  - multiline_parameters\n  - multiple_closures_with_trailing_closure\n  - nesting\n  - nimble_operator\n  # - no_extension_access_modifier\n  # - no_grouping_extension\n  - notification_center_detachment\n  - number_separator\n  - object_literal\n  - opening_brace\n  - operator_usage_whitespace\n  - operator_whitespace\n  - overridden_super_call\n  - override_in_extension\n  - pattern_matching_keywords\n  - prefixed_toplevel_constant\n  - private_action\n  - private_outlet\n  - private_over_fileprivate\n  - private_unit_test\n  - prohibited_super_call\n  - protocol_property_accessors_order\n  - quick_discouraged_call\n  - quick_discouraged_focused_test\n  - quick_discouraged_pending_test\n  - redundant_discardable_let\n  - redundant_nil_coalescing\n  - redundant_optional_initialization\n  - redundant_string_enum_value\n  - redundant_void_return\n  - required_enum_case\n  - return_arrow_whitespace\n  - shorthand_operator\n  - single_test_class\n  - sorted_first_last\n  - sorted_imports\n  - statement_position\n  - strict_fileprivate\n  - superfluous_disable_command\n  - switch_case_alignment\n  - switch_case_on_newline\n  - syntactic_sugar\n  - todo\n  - trailing_closure\n  - trailing_comma\n  - trailing_newline\n  - trailing_semicolon\n  - trailing_whitespace\n  - type_body_length\n  - type_name\n  - unneeded_break_in_switch\n  - unneeded_parentheses_in_closure_argument\n  - unused_closure_parameter\n  - unused_enumerated\n  - unused_optional_binding\n  - valid_ibinspectable\n  - vertical_parameter_alignment\n  - vertical_parameter_alignment_on_call\n  - vertical_whitespace\n  - void_return\n  - weak_delegate\n  - xctfail_message\n  - yoda_condition\nincluded:\n  - Sources\n  - Tests\n  - Examples/AttributedStringExample/Sources\n  - Examples/AttributedStringExample/Tests\n  - Examples/ColorParserExample/Sources\n  - Examples/ColorParserExample/Tests\n  - Examples/TemplateExample/Sources\n  - Examples/TemplateExample/Tests\n  - Scripts/Sources\nforce_cast: error\nforce_try: error\nline_length: 320\ntype_body_length:\n  - 300\n  - 400\nfile_length:\n  warning: 500\n  error: 1000\ntype_name:\n  min_length: 4\n  max_length: 25 \nidentifier_name:\n  min_length: 3\n  max_length: 35\nfile_header:\n  severity: error\n  required_string: |\n    /*\n     *  Copyright (c) 2018 Laszlo Teveli.\n     *\n     *  Licensed to the Apache Software Foundation (ASF) under one\n     *  or more contributor license agreements.  See the NOTICE file\n     *  distributed with this work for additional information\n     *  regarding copyright ownership.  The ASF licenses this file\n     *  to you under the Apache License, Version 2.0 (the\n     *  \"License\"); you may not use this file except in compliance\n     *  with the License.  You may obtain a copy of the License at\n     *\n     *  http://www.apache.org/licenses/LICENSE-2.0\n     *\n     *  Unless required by applicable law or agreed to in writing,\n     *  software distributed under the License is distributed on an\n     *  \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n     *  KIND, either express or implied.  See the License for the\n     *  specific language governing permissions and limitations\n     *  under the License.\n     */"
  },
  {
    "path": ".travis.yml",
    "content": "osx_image: xcode11.3\nlanguage: swift\nsudo: true\nenv:\n  global:\n    - EXPANDED_CODE_SIGN_IDENTITY=\"-\"\n    - EXPANDED_CODE_SIGN_IDENTITY_NAME=\"-\"\n    - EXPANDED_PROVISIONING_PROFILE=\"-\"\nbefore_script:\n- sh Scripts/git_auth.sh\nscript:\n- travis_retry Scripts/ci.sh\n- sleep 3\n"
  },
  {
    "path": ".version",
    "content": "1.5.0\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing to Eval\n\n## 👍🎉 First off, thanks for taking the time to contribute! 🎉👍\n\n**You are more than welcomed to do so!**\n\nThe following is a set of guidelines and best practices for contributing to Eval. These are mostly guidelines, not rules. Use your best judgment, and feel free to propose changes to this document in a Pull Request.\n\n## Code of Conduct\n\nNothing serious, all I ask is to be respectful and as helpful as you would expect others commnicating with you.\n\n## I don't want to read this whole thing, I just have a question!\n\nThe easiest channel is Twitter. You can reach out to me `@tevelee`, or feel free to write a mail at `tevelee [at] gmail [dot] com`.\n\nIf you have bigger concerns, feel free to write a GitHub issue. \n\n## What should I know before I get started?\n\nFirst of all, please read the [documentation pages](Documentation), and feel free to check out the examples. \n\nThere are a few things you need to be aware of when contributing:\n\n* The repository is only opened to a very selected set of contributors. If you need any code modifications, you need to fork and create a Pull Request.\n* There is a CI up and running\n* I use SwiftLint with build-in rules to keep the code as nice as possible\n* There is Danger configured with some rules, auto-checking contributions before I do\n* I intend to keep the code test coverage as high as possible. Please be mindful about this when contributing\n\n# How Can I Contribute?\n\n## Reporting Bugs or Suggesting Enhancements\n\nFeel free to use the same channels as I described in the README: \n\nThe easiest channel is Twitter. You can reach out to me `@tevelee`, or feel free to write a mail at `tevelee [at] gmail [dot] com`.\n\nIf you have bigger concerns, feel free to write a GitHub issue. \n\n## Pull Requests\n\n### Git Commit Messages\n\nPlease use git rebase keep your number commits as low as possible.\n\n### Documentation Styleguide\n\nI use a standard style of markdown pages in the [README.md](README.md) and in the [Documentation folder](Documentation).\n\nI also document the code, most importantly the public interfaces. I intend to keep the line documentation coverage of the publicly available methods and classes a 100%.\n\n### Issue and Pull Request Labels\n\nNo rules you need to be aware of\n"
  },
  {
    "path": "Dangerfile",
    "content": "# Sometimes it's a README fix, or something like that - which isn't relevant for\n# including in a project's CHANGELOG for example\nnot_declared_trivial = !(github.pr_title.include? \"#trivial\")\nhas_app_changes = !git.modified_files.grep(/Sources/).empty?\n\n# ENSURE THAT LABELS HAVE BEEN USED ON THE PR\nfail \"Please add labels to this PR\" if github.pr_labels.empty?\n\n# Mainly to encourage writing up some reasoning about the PR, rather than just leaving a title\nif github.pr_body.length < 5\n  fail \"Please provide a summary in the Pull Request description\"\nend\n\n# Pay extra attention if external contributors modify certain files\nif git.modified_files.include?(\"LICENSE.txt\")\n  fail \"External contributor has edited the LICENSE.txt\"\nend\nif git.modified_files.include?(\"Gemfile\") or git.modified_files.include?(\"Gemfile.lock\")\n  warn \"External contributor has edited the Gemfile and/or Gemfile.lock\"\nend\nif git.modified_files.include?(\"Eval.podspec\") or git.modified_files.include?(\"Package.swift\")\n  warn \"External contributor has edited the Eval.podspec and/or Package.swift\"\nend\n\n# Make it more obvious that a PR is a work in progress and shouldn't be merged yet\nwarn(\"PR is classed as Work in Progress\") if github.pr_title.include? \"WIP\"\n\n# Warn when there is a big PR\nwarn(\"Big PR, try to keep changes smaller if you can\") if git.lines_of_code > 500\n\n# Changelog entries are required for changes to library files.\nno_changelog_entry = !git.modified_files.include?(\"Changelog.md\")\nif has_app_changes && no_changelog_entry && not_declared_trivial\n  #warn(\"Any changes to library code should be reflected in the Changelog. Please consider adding a note there\")\nend\n\n# Added (or removed) library files need to be added (or removed) from the Carthage Xcode project to avoid breaking things for our Carthage users.\nadded_swift_library_files = !(git.added_files.grep(/Sources.*\\.swift/).empty?)\ndeleted_swift_library_files = !(git.deleted_files.grep(/Sources.*\\.swift/).empty?)\nmodified_carthage_xcode_project = !(git.modified_files.grep(/Eval\\.xcodeproj/).empty?)\nif (added_swift_library_files || deleted_swift_library_files) && !modified_carthage_xcode_project\n  warn(\"Added or removed library files require the Carthage Xcode project to be updated\")\nend\n\nmissing_doc_changes = git.modified_files.grep(/Documentation/).empty?\ndoc_changes_recommended = git.insertions > 15\nif has_app_changes && missing_doc_changes && doc_changes_recommended && not_declared_trivial\n  warn(\"Consider adding supporting documentation to this change. Documentation can be found in the `Documentation` directory.\")\nend\n\n# Warn when library files has been updated but not tests.\ntests_updated = !git.modified_files.grep(/Tests/).empty?\nif has_app_changes && !tests_updated\n  warn(\"The library files were changed, but the tests remained unmodified. Consider updating or adding to the tests to match the library changes.\")\nend\n\n# Give inline build results (compile and link time warnings and errors)\nxcode_summary.report 'build/tests/summary.json' if File.file?('build/tests/summary.json')\nxcode_summary.report 'build/example/summary.json' if File.file?('build/example/summary.json')\n\n# Run SwiftLint\nswiftlint.lint_files\n#swiftlint.lint_files inline_mode: true\n"
  },
  {
    "path": "Documentation/Example projects.md",
    "content": "# Example projects\n\nI included a few use-cases, which bring significant improvements on how things are processed before - at least in my previous projects.\n​\n### [Template language](https://github.com/tevelee/Eval/blob/master/Examples/TemplateExample/Tests/TemplateExampleTests/TemplateExampleTests.swift)\n\nI was able to create a full-blown template language, completely, using this framework and nothing else. It's almost like a competitor of the one I mentioned ([Twig](https://github.com/twigphp/Twig)). This is the most advanced example of them all!\n\nI created a standard library with all the possible operators you can imagine. With helpers, each operator is a small, one-liner addition. Added the important data types, such as arrays, strings, numbers, booleans, dates, etc., and a few functions, to be more awesome. [Take a look for inspiration!](https://github.com/tevelee/Eval/blob/master/Examples/TemplateExample/Sources/TemplateExample/TemplateExample.swift)\n\nTogether, it makes an excellent addition to my model-object generation project, and **REALLY useful for server-side Swift development as well**!\n\n### [Attributed string parser](https://github.com/tevelee/Eval/blob/master/Examples/AttributedStringExample/Tests/AttributedStringExampleTests/AttributedStringExampleTests.swift)\n\nI created another small example, parsing attribtuted strings from simple expressions using XML style tags, such as bold, italic, underlined, colored, etc.\n\nWith just a few operators, this solution can deliver attributed strings from basic APIs, which otherwise would be hard to manage.\n\nMy connected project is an iOS application, using the Spotify [HUB framework](https://github.com/spotify/HubFramework), in which I can now provide rich strings with my view-models and parse them from the JSON string results.\n\n### [Color parser](https://github.com/tevelee/Eval/blob/master/Examples/ColorParserExample/Tests/ColorParserExampleTests/ColorParserExampleTests.swift)\n\nA color parser is also used by the BFF (Backend For Frontend, not 👭) project I mentioned before. It can parse Swift Color objects from many different styles of strings, such as `#ffddee`, or `red`, or `rgba(1,0.5,0.4,1)`. I included this basic example in the repository as well.\n\n"
  },
  {
    "path": "Documentation/Interpreter engine details.md",
    "content": "# Technical details\n\n## Interpreter engine\n\nTBD\n\n## Template engine \n\nTBD"
  },
  {
    "path": "Documentation/Strongly-typed evaluator.md",
    "content": "# Strongly typed evaluator\n\nThis kind of evaluator interprets its input as one function. It searches for the one with the highest precedence and works its way down from that. \nOcassionally, more functions are present in the same expression. In this case, it goes recursively, all the way down to the most basic elements: variables or literals, which are trivial to evaluate.\n\n## Creation\n\nThe way to create typed interpreters is the following:\n\n```swift\nlet interpreter = TypedInterpreter(dataTypes: [number, string, boolean, array, date],\n                                   functions: [concat, add, multiply, substract, divide],\n                                   context: Context(variables: [\"example\": 1]))\n```\n\nFirst, you'll need the data types you are going to work with. These are a smaller subsets of the build in Swift data types, you can map them to existing types (Swift types of the ones of your own)\n\nThe second parameter are the functions you can apply on the above listed data types. All the functions - regardless of the grouping of the data types - should be listed here.\nTypically, in case of numbers, these are numeric operators. In case of string, these can be concatenation, getters, slicing, etc.\nOr, these can be complex things, such as parentheses, data factories, or high level functional operations, such as filter, map or reduce.\n\nAnd lastly, an optional context object, if you have any global variables.\n\nVariables in the context can be expression specific, or global that apply to every evaluation session. \n\n## Data types\n\nData types map the outside world to the inside of the expression. They map existing types to inner data types. \n\nThey don't restrict any behaviour, so these types can either be built-in Swift types, such as String, Array, Date; or they can be your custom classes, srtucts, or enums.\n\nLet's see it in action:\n\n```swift\nlet number = DataType(type: Double.self, literals: [numberLiteral, piConstant]) { String(describing: $0) }\n```\n\nIf has a type, that is the existing type of the sorrounding program. The literals, which can tell the framework whether a given string can be converted to a given type. \n\nTypical example is the `String` literal, which encloses something between quotes: `'like this'`. The can also be constants, for example `pi` for numbers of `true` for booleans.\n\nThe last parameter is a `print` closure. It tells the framework how to render the given type when needed. Typically used while debugging, or when templates use the `print` statement.\n\nIn summary: literals provide the input, print provides the output of a mapped type.\n\n### Literals\n\nLet's check out some literals a bit more deeply. \n\nThe block used for literals have two parameters: the input string, and an interpreter.\nMost of the times, only the input is enough to recognise things, like numbers:\n\n```swift\nLiteral { value, _ in Double(value) }\n```\nArrays, on the other hand, should process their content (Comma `,` separated values between brackets `[` `]`). For this, the second parameter, the interpreter can be used.\n\n#### Constants\n\nLiterals are the perfect place to recognise constants, such as:\n\n```swift\nLiteral(\"pi\", convertsTo: Double.pi)\n```\nor\n                                                          \n```swift\n[Literal(\"false\", convertsTo: false)\n```\nOf course, there are multiple ways to represent them (for example, as a single keyword function pattern), but this seems like a place where they can be most closely connected to their type.\n\nThe `convertsTo` parameter of `Literal`s are `autoclosure` parameters, which means, that they are going to be processed lazily.\n\n```swift\nLiteral(\"now\", convertsTo: Date())\n```\n\nThe `now` string is going to be expressed as the current timestamp at the time of the evaluation, not the time of the initialisation.\n\n## Functions\n\nSimilarly to templates, typed interpreters use the same building blocks to build up their patterns: `Keyword`s and `Variable`s.\n\n### Keywords\n\n`Keyword`s are the most basic elements of a pattern; they represent simple, static `String`s. You can chain them, for example `Keyword(\"<\") + Keyword(\"br/\") + Keyword(>}\")`, or simply merge them `Keyword(\"<br/>\")`. Logically, these two are the same, but the former accepts any number of whitespaces between the tags, while the latter allows none, as it is a strict match. \n\nMost of the time though, you are going to need to handle placeholders, varying number of elements. That's where `Variable`s come into place.\n\n### Variables\n\nLet's check out the following, really straightforward pattern:\n\n```swift\nFunction(Keyword(\"(\") + Variable<Any>(\"body\") + Keyword(\")\")) { variables, _, _ in\n\treturn variables[\"body\"]\n}\n```\n\nSomething between two enclosing parentheses `(`, `)`. The middle tag is a `Variable`, which means that its value is going to be passed through in the block, using its name. Let's imagine the following input: `(5)`. Here, the `variables` dictionary is going to have `5` under the key `body`.\n\n#### Generics\n\nSince its value is going to be processed, there is a generic sign as well, signalling that this current `Variable` accepts `Any` kind of data, no transfer is needed. Let's imagine if we wrote `Variable<String>` instead. In this case, `5` would not match to the pattern, it would be intact. But, for example, `('Hello')` would do.\n\nLet check out a `+` operator. This could equally mean addition for numeric types\n\n```swift\nFunction(Variable<Double>(\"lhs\") + Keyword(\"+\") + Variable<Double>(\"rhs\")) { arguments,_,_ in\n    guard let lhs = arguments[\"lhs\"] as? Double, let rhs = arguments[\"rhs\"] as? Double else { return nil }\n    return lhs + rhs\n}\n```\nor concatenation for strings\n\n```swift\nFunction(Variable<String>(\"lhs\") + Keyword(\"+\") + Variable<String>(\"rhs\")) { arguments,_,_ in\n    guard let lhs = arguments[\"lhs\"] as? String, let rhs = arguments[\"rhs\"] as? String else { return nil }\n    return lhs + rhs\n}\n```\nSince the interpreter is strongly typed, always the appropriate one is going to be selected by the framework.\n\n#### Evaluation\n\nVariables also have optional properties, such as `interpreted`, `shortest`, or `acceptsNilValue`. They might also have a `map` block, which by default is `nil`.\n\n* `interpreted` tells the framework, that its value should be evaluated. This is true, by default. But, the option exists to modify this to false. In that case, `(2 + 3)` would not generate the number `5` under the `body` key, but `2 + 3` as a `String`.\n* `shortest` signals the \"strength\" of the matching operation. By default it's false, we need the most possible characters. The only scenario where this could get tricky is if the last element of a pattern is a `Variable`. In that case, the preferred setting is `false`, so we need the largest possible match!\nLet's find out why! A general addition operator (which looks like this `Variable<Double>(\"lhs\") + Keyword(\"+\") + Variable<Double>(\"rhs\")`) would recognise the pattern `12 + 34`, but it also matches to `12 + 3`. What's what shortest means, the shortest match, in this case, is `12 + 3`, which - semantically - is an incorrect match. \nBut don't worry, the framework already knows about this, so it sets the right value for your variables, even in the last place!\n* `acceptsNilValue` informs the framework if `nil` should be accepted by the pattern. For example, `1 + '5'` with the previous example (`Double + Double`) would not match. But, if the `acceptsNilValue` is defined, then the block would trigger, with `{'lhs': 1, 'rhs': nil}`, so you can decide by your own logic what to do in this case.\n* Finally, the `map` block can be used to further transform the value of your `Variable` before calling the block on the `Pattern`. Since map is a trailing closure, it's quite easy to add. For example, `Variable<Int>(\"example\") { Double($0) }` would recognise only `Int` values, but would transform them to `Double` instances when providing them in the `variables` dictionary. This map can also return `nil` values but depends on your logic if you want to accept them or not. Side note: the previous map generates a `Variable<Double>` kind of variable instance.\n\n### Specialised elements\n\n#### Open & Close Keyword\n\nParentheses are quite common in expressions. They are often embedded in each other. Embedding is a nasty problem of interpreters, as `(a * (b + c))` would logically be evaluated with `(b + c)` first, and the rest afterwards. \n\nBut, an algorithm, by default, would interpret things linearly, disregarding the semantics: `(a * (b + c))` would be the match for the first if statement, with a totally invalid `a * (b + c` data, until the first match.\n\nThis, of course, needs to be solved, but it's not that easy as it first looks! Some edge cases would not work unless we somehow try to connect them together. For this reason, I added two special elements: `OpenKeyword` and `CloseKeyword`. These work exactly the same way as normal `Keyword`s do, but add a bit more semantics to the framework: these two should be connected together, and therefore embedding them should not be a problem as they come in pairs. \n\nThe previous parentheses statement should - correctly - look like this:\n\n```swift\nFunction(OpenVariable<String>(\"lhs\") + Keyword(\"+\") + CloseVariable<String>(\"rhs\")) { arguments,_,_ in\n    guard let lhs = arguments[\"lhs\"] as? String, let rhs = arguments[\"rhs\"] as? String else { return nil }\n    return lhs + rhs\n}\n```\n\nBy using the `OpenKeyword` and `CloseKeyword` types, these become connected, so embedding parentheses in an expression shouldn't be a problem. \nAfter this match is defined, they can be embedded in each other as deeply as needed.\n\n#### Multiple Patterns in one Function\n\nThis is a rarely used pattern, but `Function`s consists of an array of `Pattern` elements. \nUsually, one `Function` does only one operation. Unless this is true, grouping multiple `Pattern`s into one `Function` allows semantical grouping of opeartors. \n\nFor example a Boolean negation can be expressed in multiple ways: `not(true)` or `!true`. In this case, semantically both expressions do the same thing, therefore it might be a good practice to use one `Function` with two `Pattern`s for this. \n\n## Context\n\nYou can also pass contextual values, which - for now - equal to variables.\n\n```swift\nexpression.evaluate(\"1 + var\", context: Context(variables: [\"var\": 2]))\n```\n\nThe reason that the variables are encapsulated in a context is that context is a class, while variables are mutable `var` struct properties on that object. With this construction the context reference can be passed around to multiple interpreter instances, but keeps the copy-on-write (🐮) behaviour of the modification.\n\nContext defined during the initialisation apply to every evaluation performed with the given interpreter, while the ones passed to the `evaluate` method only apply to that specific  expression instance.\n\nIf some patterns modify the context, they have the option to modify the general context (for long term settings, such as `value++`), or the local one (for example, the interation variable of a `for` loop).\n\n### Order of statements define precedence\n\nThe earlier a pattern is represent in the array of `functions`, the higher precedence it gets. \nPractically, if there is an addition function and a multiplication one, the multiplication should be defined earlier (as it has higher precedence), because both are going to match the following expression:\n`1 * 2 + 3`, but if addition goes first, then the evaluation would process `1 * 2` on `lhs` and `3` on `rhs`, which - of course - is incorrect.  \n\nTypically, parentheses and higher precedence operators should go earlier in the array."
  },
  {
    "path": "Documentation/Template evaluator.md",
    "content": "# Template evaluator\n\nThe logic of the interpreter is fairly easy: it goes over the input character by character and replaces any patterns it can find. \n\n## Creation\n\nThe way to create template interpreters is the following:\n\n```swift\nlet template = StringTemplateInterpreter(statements: [ifStatement, printStatement], \n\t\t\t\t\t\t\t\t   interpreter: interpreter, \n\t\t\t\t\t\t\t\t   context: Context(variables: [\"example\": 1]))\n```\n\nFirst, you'll need the statements that you aim to recognise.\nThen, you'll need a typed interpreter, so that you can evaluate strongly typed expressions. \nAnd lastly, an optional context object, if you have any global variables.\n\nVariables in the context can be expression specific, or global that apply to every evaluation session. \n\nThe template interpreter and the given typed interpreter don't share the same context. Apart from the containment dependency, they don't have any logical connection. The reason for this is that templates need a special context feeding the template content, but typed interpreters might work with totally different data types. It is totally up to the developer how they want their context to be managed. Since the context is a class, its reference can be passed around, so it's quite straightforward to have them share the same context object - if needed.\n\n## Statement examples\n\n### Keywords\n\n`Keyword`s are the most basic elements of a pattern; they represent simple, static `String`s. You can chain them, for example `Keyword(\"{%\") + Keyword(\"if\") + Keyword(\"%}\")`, or simply merge them `Keyword(\"{% if %}\")`. Logically, these two are the same, but the former accepts any number of whitespaces between the tags, while the latter allows only one, as it is a strict match. \n\nMost of the time though, you are going to need to handle placeholders, varying number of elements. That's where `Variable`s come into place.\n\n### Variables\n\nLet's check out the following, really straightforward pattern:\n\n```swift\nPattern(Keyword(\"{{\") + Variable<Any>(\"body\") + Keyword(\"}}\")) { variables, interpreter, _ in\n    guard let body = variables[\"body\"] else { return nil }\n    return interpreter.typedInterpreter.print(body)\n}\n```\n\nSomething between two enclosing parentheses `{{`, `}}`. The middle tag is a `Variable`, which means that its value is going to be passed through in the block, using its name. Let's imagine the following input: `The winner is: {{ 5 }}`. Here, the `variables` dictionary is going to have `5` under the key `body`.\n\n#### Generics\n\nSince its value is going to be processed, there is a generic sign as well, signalling that this current `Variable` accepts `Any` kind of data, no transfer is needed. Let's imagine if we wrote `Variable<String>` instead. In this case, `5` would not match to the template, it would be intact. But, for example, `{{ 'Hello' }}` would do.\n\n#### Evaluation\n\nVariables also have optional properties, such as `interpreted`, `shortest`, or `acceptsNilValue`. They might also have a `map` block, which by default is `nil`.\n\n* `interpreted` tells the framework, that its value should be evaluated. This is true, by default. But, the option exists to modify this to false. In that case, `{{ 2 + 3 }}` would not generate the number `5` under the `body` key, but `2 + 3` as a `String`.\n* `shortest` signals the \"strength\" of the matching operation. By default it's false, we need the most possible characters. The only scenario where this could get tricky is if the last element of a pattern is a `Variable`. In that case, the preferred setting is `false`, so we need the largest possible match!\nLet's find out why! A general addition operator (which looks like this `Variable<Double>(\"lhs\") + Keyword(\"+\") + Variable<Double>(\"rhs\")`) would recognise the pattern `12 + 34`, but it also matches to `12 + 3`. What's what shortest means, the shortest match, in this case, is `12 + 3`, which - semantically - is an incorrect match. \nBut don't worry, the framework already knows about this, so it sets the right value for your variables, even in the last place!\n* `acceptsNilValue` informs the framework if `nil` should be accepted by the pattern. For example, `1 + '5'` with the previous example (`Double + Double`) would not match. But, if the `acceptsNilValue` is defined, then the block would trigger, with `{'lhs': 1, 'rhs': nil}`, so you can decide by your own logic what to do in this case.\n* Finally, the `map` block can be used to further transform the value of your `Variable` before calling the block on the `Pattern`. Since map is a trailing closure, it's quite easy to add. For example, `Variable<Int>(\"example\") { Double($0) }` would recognise only `Int` values, but would transform them to `Double` instances when providing them in the `variables` dictionary. This map can also return `nil` values but depends on your logic if you want to accept them or not. Side note: the previous map generates a `Variable<Double>` kind of variable instance.\n\n### Specialised elements\n\n#### Template Variable\n\nBy default, `Variable` instances use typed interpreters to evaluate their value. Sometimes though, they should be processed with the template interpreter. A good example is the `if` statement:\n\n\n```swift\nPattern(Keyword(\"{%\") + Keyword(\"if\") + Variable<Bool>(\"condition\") + Keyword(\"%}\") + TemplateVariable(\"body\") + Keyword(\"{% endif %}\")) { variables, interpreter, _ in\n    guard let condition = variables[\"condition\"] as? Bool, let body = variables[\"body\"] as? String else { return nil }\n    if condition {\n        return body\n    }\n    return nil\n}\n```\n\nThis statement has two semantically different kinds of variable, but they both are just placeholders. The first (`condition`) is an interpreted variable, which at the end returns a `Boolean` value. \n\nThe second one is a bit different; it should not be evaluated the same way as `condition`. We need to further evaluate the enclosed template, that's why this variable\n\n1. Should not be interpreted\n2. Should be evaluated using the template interpreter, not the typed interpreter\n\nThat's why there's a subclass called `TemplateVariable`, which forces these two options when initialised. It DOES evaluate its content but uses the template interpreter to do so.\n\nA quick example: `Header ... {% if x > 0 %}Number of results: {{ x }} {% endif %} ... Footer`\n\nHere, `x > 0` is a `Boolean` expression, but the body between the `if`, and `endif` tags is a template, such as the whole expression.\n\n#### Open & Close Keyword\n\n`if` statements are quite common in templates. They are often chained and embedded in each other. Embedding is a nasty problem of interpreters, as `{% if %}a{% if %}b{% endif %}c{% endif %}` would logically be evaluated with `{% if %}b{% endif %}` first, and the rest afterwards. \n\nBut, an algorithm, by default, would interpret things linearly, disregarding the semantics: `{% if %}a{% if %}b{% endif %}` would be the match for the first if statement, with a totally invalid `a{% if %}b` data. \n\nThis, of course, needs to be solved, but it's not that easy as it first looks! Some edge cases would not work unless we somehow try to connect them together. For this reason, I added two special elements: `OpenKeyword` and `CloseKeyword`. These work exactly the same way as normal `Keyword`s do, but add a bit more semantics to the framework: these two should be connected together, and therefore embedding them should not be a problem as they come in pairs. \n\nThe previous `if` statement, now with an `else` block should - correctly - look like this:\n\n```swift\nPattern(OpenKeyword(\"{% \"if\") + Variable<Bool>(\"condition\") + Keyword(\"%}\") + TemplateVariable(\"body\") + Keyword(\"{% else %}\") + TemplateVariable(\"else\") + CloseKeyword(\"{% endif %}\")) { variables, interpreter, _ in\n    guard let condition = variables[\"condition\"] as? Bool, let body = variables[\"body\"] as? String else { return nil }\n    if condition {\n        return body\n    } else {\n        return variables[\"else\"] as? String\n    }\n}\n```\n\nBy using the `OpenKeyword` and `CloseKeyword` types, these become connected, so embedding `if` statements in a template shouldn't be a problem. \n\nSimilarly, this works for the `print` statement from an earlier example:\n\n```swift\nPattern(OpenKeyword(\"{{\") + Variable<Any>(\"body\") + CloseKeyword(\"}}\")) { variables, interpreter, _ in\n    guard let body = variables[\"body\"] else { return nil }\n    return interpreter.typedInterpreter.print(body)\n}\n```\n\n## Evaluation\n\nThe evaluation of the templates happens with the `evaluate` function on the interpreter:\n\n```swift\ntemplate.evaluate(\"{{ 1 + 2 }}\")\n```\n\nThe result of the evaluation - in case of templates - is always a `String`. In the result you shouldn't see any template elements, because they were recognised, processed, and replaced during the evaluation by the interpreter.\n\n### Context\n\nYou can also pass contextual values, which - for now - equal to variables.\n\n```swift\ntemplate.evaluate(\"{{ 1 + var }}\", context: Context(variables: [\"var\": 2]))\n```\n\nThe reason that the variables are encapsulated in a context is that context is a class, while variables are mutable `var` struct properties on that object. With this construction the context reference can be passed around to multiple interpreter instances, but keeps the copy-on-write (🐮) behaviour of the modification.\n\nContext defined during the initialisation apply to every evaluation performed with the given interpreter, while the ones passed to the `evaluate` method only apply to that specific  expression instance.\n\nIf some patterns modify the context, they have the option to modify the general context (for long term settings), or the local one (for example, the interation variable of a `for` loop).\n\n### Order of statements define precedence\n\nThe earlier a pattern is represent in the array of `statements`, the higher precedence it gets. \nPractically, if there is an `if` statement and an `if-else` one, the `if-else` should be defined earlier, because both are going to match the following expression:\n`{% if x < 0 %}A{% else %}B{% endif %}`, but if `if` goes first, then the output - and the `body` of the `if` statement - is going to be processed as `A{% else %}B`. \n\nTypically, parentheses and richer type of expressions should go earlier in the array.\n"
  },
  {
    "path": "Documentation/Tips & Tricks.md",
    "content": "# Tips & Tricks\n\nThe following sections provide handy Tips and Tricks to help you effectively build up your own interpreter using custom operators and data types.\n\n## Get inspired by checking out the examples\n\nThere are quite a few operators and data types available in the [TemplateLanguage Example](https://github.com/tevelee/Eval/blob/master/Examples/TemplateExample/Sources/TemplateExample/TemplateExample.swift#L114-L150) project, under the StandardLibrary class\n\nAlso, there are quite a few expressions available [in some of the unit tests](https://github.com/tevelee/Eval/blob/master/Tests/EvalTests/IntegrationTests/InterpreterTests.swift#L47-L86) as well.\n\n## Use helper functions to define operators\n\nIt's a lot readable to define operators in a one-liner expression, rather than using long patterns:\n\n```swift\ninfixOperator(\"+\") { (lhs: String, rhs: String) in lhs + rhs }\n```\n```swift\nsuffixOperator(\"is odd\") { (value: Double) in Int(value) % 2 == 1 }\n```\n```swift\nprefixOperator(\"!\") { (value: Bool) in !value }\n```\n\nYou can find a few helpers [in the examples](https://github.com/tevelee/Eval/tree/master/Examples/TemplateExample/Sources/TemplateExample/TemplateExample.swift#L331-L412). Feel free to use them!\n\n## Be mindful about precedence\n\n#### Template expressions\n\nThe earlier a pattern is represent in the array of `statements`, the higher precedence it gets. \nPractically, if there is an `if` statement and an `if-else` one, the `if-else` should be defined earlier, because both are going to match the following expression:\n`{% if x < 0 %}A{% else %}B{% endif %}`, but if `if` goes first, then the output - and the `body` of the `if` statement - is going to be processed as `A{% else %}B`. \n\nTypically, parentheses and richer type of expressions should go earlier in the array.\n\n#### Typed expressions\n\nThe earlier a pattern is represent in the array of `functions`, the higher precedence it gets. \nPractically, if there is an addition function and a multiplication one, the multiplication should be defined earlier (as it has higher precedence), because both are going to match the following expression:\n`1 * 2 + 3`, but if addition goes first, then the evaluation would process `1 * 2` on `lhs` and `3` on `rhs`, which - of course - is incorrect.  \n\nTypically, parentheses and higher precedence operators should go earlier in the array.\n\n## Use Any for generics: `Variable<Any>`\n\nIf you are not sure about the allowed input type of your expressions, or you just want to defer that decision until your match is ran and your hit the block in the pattern, feel free to use `Variable<Any>(\"name\")` in your patterns.\n\nIt makes life a lot easier, than definig functions for each type.\n\n## Use map on `Variable`s for pre-filtering\n\nBefore processing Variable values, there is an option to pre-filter or modify them before it hits the match block. \n\nExamples include data type conversion and other types of validation.\n\n## Use `OpenKeyword` and `CloseKeyword` for embedding parentheses\n\nEmbedding is a common issue with interpreters and compilers. In order to provide some extra semantics to the engine, please use the `OpenKeyword(\"[\")` and `OpenKeyword(\"]\")` options, when defining `Keyword`s that come in pairs.\n\n## Share context between `StringTemplateInterpreter` and `TypedInterpreter`\n\nIf you use template interpreters, they need a typed interpreter to hold. Both interpreters have `context` variables, so if you are not being careful enough, it can cause headaches. \n\nSince `Context` is a class, its reference can be passed around and used in multiple places. \n\nThe reason that the variables are encapsulated in a context is that context is a class, while variables are mutable `var` struct properties on that object. With this construction the context reference can be passed around to multiple interpreter instances, but keeps the copy-on-write (🐮) behaviour of the modification.\n\nContext defined during the initialisation apply to every evaluation performed with the given interpreter, while the ones passed to the `evaluate` method only apply to that specific  expression instance.\n\n## Define constants in `Literal`s\n\nThe frameworks allows multiple ways to express static strings and convert them. \nI believe the best place to put constants are in the `Literal`s of `DataType`s.\n\nUse the `Literal(\"YES\", convertsTo: true)` `Literal` initialiser for easy definition.\n\nThe `convertsTo` parameter of `Literal`s are `autoclosure` parameters, which means, that they are going to be processed lazily.\n\n```swift\nLiteral(\"now\", convertsTo: Date())\n```\n\nThe `now` string is going to be expressed as the current timestamp at the time of the evaluation, not the time of the initialisation.\n\n## Map any function signatures from Swift, dynamically\n\nThe framework is really lightweight and not really restrictive in regards of how to parse your expressions. Free your mind, and do stuff dynamically.\n\n```swift\nFunction(Variable<Any>(\"lhs\") + Keyword(\".\") + Variable<String>(\"rhs\", interpreted: false)) { (arguments,_,_) -> Double? in\n        if let lhs = arguments[\"lhs\"] as? NSObjectProtocol,\n            let rhs = arguments[\"rhs\"] as? String,\n            let result = lhs.perform(Selector(rhs)) {\n            return Double(Int(bitPattern: result.toOpaque()))\n        }\n        return nil\n    }\n])\n```\n\nPerform any method call of any type and maybe process their output as well. It's not the safest way to go with it, but this is just an example.\n\nThis opens up the way of running almost any arbitrary code on Apple platforms, from any backend. But, this does it in a very controlled way, as you must define a set of data types and functions that apply, unless you call them dynamically at runtime.\n\n## Experiment with your expressions!\n\nIt's quite easy to add new operators, functions, and data types. I suggest not to think about them too long, just dare to experpiment with them, what's possible and what is not. \n\nYou can always add new types or functions if you need extra functionality. The options are practically endless!\n\n## Debugging tips\n\n#### If an expression haven't been matched\n* It's common, that some validation caught the value\n* Print your expressions or put breakpoints into the affected match blocks or variable map blocks\n\n#### If you see weird output\n* Play with the order of the newly added opeartions.\n* Incorrect precedence can turn expressions upside down\n\nThe framework is still in an early stage, so debugging helpers will follow in upcoming releases. Please stay tuned!\n\n## Validate your expressions before putting them out in production code\n\nNot every expression work out of the box as you might expect. Operators and functions depend on each other, especially in terms of precedence. If one pattern was recognised before the other one, your code might not run as you expected.\n\nPro Tip: Write unit tests to validate expressions. Feel free to use `as!` operator to force-cast the result expressions in tests, but only in tests. It's not a problem is tests crash, you can fix it right away, but it's not okay in production.\n"
  },
  {
    "path": "Eval.playground/Contents.swift",
    "content": "//: Playground - noun: a place where people can play\nimport Foundation\nimport Eval\n\nlet context = InterpreterContext()\n\nlet interpreter = TypedInterpreter(dataTypes: [numberDataType, stringDataType, arrayDataType, booleanDataType, dateDataType],\n                                   functions: [parentheses, multipication, addition, lessThan],\n                                   context: context)\n\nlet template = TemplateInterpreter(statements: [ifStatement, printStatement],\n                                   interpreter: interpreter,\n                                   context: context)\n\ninterpreter.evaluate(\"2 + 3 * 4\")\n\ntemplate.evaluate(\"{% if 10 < 21 %}Hello{% endif %} {{ name }}!\", context: InterpreterContext(variables: [\"name\": \"Eval\"]))\n"
  },
  {
    "path": "Eval.playground/Sources/Helpers.swift",
    "content": "import Foundation\nimport Eval\n\npublic func infixOperator<A,B,T>(_ symbol: String, body: @escaping (A, B) -> T) -> Function<T?> {\n    return Function([Variable<A>(\"lhs\", shortest: true), Keyword(symbol), Variable<B>(\"rhs\", shortest: false)]) { arguments,_,_ in\n        guard let lhs = arguments[\"lhs\"] as? A, let rhs = arguments[\"rhs\"] as? B else { return nil }\n        return body(lhs, rhs)\n    }\n}\n\npublic func prefixOperator<A,T>(_ symbol: String, body: @escaping (A) -> T) -> Function<T?> {\n    return Function([Keyword(symbol), Variable<A>(\"value\", shortest: false)]) { arguments,_,_ in\n        guard let value = arguments[\"value\"] as? A else { return nil }\n        return body(value)\n    }\n}\n\npublic func suffixOperator<A,T>(_ symbol: String, body: @escaping (A) -> T) -> Function<T?> {\n    return Function([Variable<A>(\"value\", shortest: true), Keyword(symbol)]) { arguments,_,_ in\n        guard let value = arguments[\"value\"] as? A else { return nil }\n        return body(value)\n    }\n}\n\npublic func function<T>(_ name: String, body: @escaping ([Any]) -> T?) -> Function<T> {\n    return Function([Keyword(name), Keyword(\"(\"), Variable<String>(\"arguments\", shortest: true, interpreted: false), Keyword(\")\")]) { variables, interpreter, _ in\n        guard let arguments = variables[\"arguments\"] as? String else { return nil }\n        let interpretedArguments = arguments.split(separator: \",\").flatMap { interpreter.evaluate(String($0).trimmingCharacters(in: .whitespacesAndNewlines)) }\n        return body(interpretedArguments)\n    }\n}\n\npublic func functionWithNamedParameters<T>(_ name: String, body: @escaping ([String: Any]) -> T?) -> Function<T> {\n    return Function([Keyword(name), Keyword(\"(\"), Variable<String>(\"arguments\", shortest: true, interpreted: false), Keyword(\")\")]) { variables, interpreter, _ in\n        guard let arguments = variables[\"arguments\"] as? String else { return nil }\n        var interpretedArguments: [String: Any] = [:]\n        for argument in arguments.split(separator: \",\") {\n            let parts = String(argument).trimmingCharacters(in: .whitespacesAndNewlines).split(separator: \"=\")\n            if let key = parts.first, let value = parts.last {\n                interpretedArguments[String(key)] = interpreter.evaluate(String(value))\n            }\n        }\n        return body(interpretedArguments)\n    }\n}\n\npublic func objectFunction<O,T>(_ name: String, body: @escaping (O) -> T?) -> Function<T> {\n    return Function([Variable<O>(\"lhs\", shortest: true), Keyword(\".\"), Variable<String>(\"rhs\", shortest: false, interpreted: false) { value,_ in\n        guard let value = value as? String, value == name else { return nil }\n        return value\n        }]) { variables, interpreter, _ in\n            guard let object = variables[\"lhs\"] as? O, variables[\"rhs\"] != nil else { return nil }\n            return body(object)\n    }\n}\n\npublic func objectFunctionWithParameters<O,T>(_ name: String, body: @escaping (O, [Any]) -> T?) -> Function<T> {\n    return Function([Variable<O>(\"lhs\", shortest: true), Keyword(\".\"), Variable<String>(\"rhs\", interpreted: false) { value,_ in\n        guard let value = value as? String, value == name else { return nil }\n        return value\n    }, Keyword(\"(\"), Variable<String>(\"arguments\", interpreted: false), Keyword(\")\")]) { variables, interpreter, _ in\n        guard let object = variables[\"lhs\"] as? O, variables[\"rhs\"] != nil, let arguments = variables[\"arguments\"] as? String else { return nil }\n        let interpretedArguments = arguments.split(separator: \",\").flatMap { interpreter.evaluate(String($0).trimmingCharacters(in: .whitespacesAndNewlines)) }\n        return body(object, interpretedArguments)\n    }\n}\n\npublic func objectFunctionWithNamedParameters<O,T>(_ name: String, body: @escaping (O, [String: Any]) -> T?) -> Function<T> {\n    return Function([Variable<O>(\"lhs\", shortest: true), Keyword(\".\"), Variable<String>(\"rhs\", interpreted: false) { value,_ in\n        guard let value = value as? String, value == name else { return nil }\n        return value\n    }, Keyword(\"(\"), Variable<String>(\"arguments\", interpreted: false), Keyword(\")\")]) { variables, interpreter, _ in\n        guard let object = variables[\"lhs\"] as? O, variables[\"rhs\"] != nil, let arguments = variables[\"arguments\"] as? String else { return nil }\n        var interpretedArguments: [String: Any] = [:]\n        for argument in arguments.split(separator: \",\") {\n            let parts = String(argument).trimmingCharacters(in: .whitespacesAndNewlines).split(separator: \"=\")\n            if let key = parts.first, let value = parts.last {\n                interpretedArguments[String(key)] = interpreter.evaluate(String(value))\n            }\n        }\n        return body(object, interpretedArguments)\n    }\n}\n"
  },
  {
    "path": "Eval.playground/Sources/TypesAndFunctions.swift",
    "content": "import Foundation\nimport Eval\n\n//MARK: Double\n\npublic let numberDataType = DataType(type: Double.self, literals:[\n        Literal { Double($0.value) },\n        Literal(\"pi\", convertsTo: Double.pi)\n]) { value, _ in String(describing: value) }\n\n//MARK: Bool\n\npublic let booleanDataType = DataType(type: Bool.self, literals: [\n    Literal(\"false\", convertsTo: false),\n    Literal(\"true\", convertsTo: true)\n]) { $0.value ? \"true\" : \"false\" }\n\n//MARK: String\n\nlet singleQuotesLiteral = Literal { (input, _) -> String? in\n    guard let first = input.first, let last = input.last, first == last, first == \"'\" else { return nil }\n    let trimmed = input.trimmingCharacters(in: CharacterSet(charactersIn: \"'\"))\n    return trimmed.contains(\"'\") ? nil : trimmed\n}\npublic let stringDataType = DataType(type: String.self, literals: [singleQuotesLiteral]) { $0.value }\n\n//MARK: Date\n\npublic let dateDataType = DataType(type: Date.self, literals: [Literal<Date>(\"now\", convertsTo: Date())]) {\n    let dateFormatter = DateFormatter()\n    dateFormatter.calendar = Calendar(identifier: .gregorian)\n    dateFormatter.dateFormat = \"yyyy-MM-dd HH:mm:ss\"\n    return dateFormatter.string(from: $0)\n}\n\n//MARK: Array\n\nlet arrayLiteral = Literal { (input, interpreter) -> [CustomStringConvertible]? in\n    guard let first = input.first, let last = input.last, first == \"[\", last == \"]\" else { return nil }\n    return input\n        .trimmingCharacters(in: CharacterSet(charactersIn: \"[]\"))\n        .split(separator: \",\")\n        .map{ $0.trimmingCharacters(in: .whitespacesAndNewlines) }\n        .map{ interpreter.evaluate(String($0)) as? CustomStringConvertible ?? String($0) }\n}\npublic let arrayDataType = DataType(type: [CustomStringConvertible].self, literals: [arrayLiteral]) { $0.value.map{ $0.description }.joined(separator: \",\") }\n\n//MARK: Operators\n\npublic let max = objectFunction(\"max\") { (object: [Double]) -> Double? in object.max() }\npublic let min = objectFunction(\"min\") { (object: [Double]) -> Double? in object.min() }\n\npublic let formatDate = objectFunctionWithParameters(\"format\") { (object: Date, arguments: [Any]) -> String? in\n    guard let format = arguments.first as? String else { return nil }\n    let dateFormatter = DateFormatter()\n    dateFormatter.calendar = Calendar(identifier: .gregorian)\n    dateFormatter.dateFormat = format\n    return dateFormatter.string(from: object)\n}\n\npublic let not = prefixOperator(\"!\") { (value: Bool) in !value }\n\npublic let dateFactory = function(\"Date\") { (arguments: [Any]) -> Date? in\n    guard let arguments = arguments as? [Double], arguments.count >= 3 else { return nil }\n    var components = DateComponents()\n    components.calendar = Calendar(identifier: .gregorian)\n    components.year = Int(arguments[0])\n    components.month = Int(arguments[1])\n    components.day = Int(arguments[2])\n    components.hour = arguments.count > 3 ? Int(arguments[3]) : 0\n    components.minute = arguments.count > 4 ? Int(arguments[4]) : 0\n    components.second = arguments.count > 5 ? Int(arguments[5]) : 0\n    return components.date\n}\n\npublic let parentheses = Function([Keyword(\"(\"), Variable<Any>(\"body\"), Keyword(\")\")]) { $0.variables[\"body\"] }\npublic let addition = infixOperator(\"+\") { (lhs: Double, rhs: Double) in lhs + rhs }\npublic let multipication = infixOperator(\"*\") { (lhs: Double, rhs: Double) in lhs * rhs }\npublic let concat = infixOperator(\"+\") { (lhs: String, rhs: String) in lhs + rhs }\npublic let inNumberArray = infixOperator(\"in\") { (lhs: Double, rhs: [Double]) in rhs.contains(lhs) }\npublic let inStringArray = infixOperator(\"in\") { (lhs: String, rhs: [String]) in rhs.contains(lhs) }\npublic let range = infixOperator(\"...\") { (lhs: Double, rhs: Double) in CountableClosedRange(uncheckedBounds: (lower: Int(lhs), upper: Int(rhs))).map { Double($0) } }\npublic let prefix = infixOperator(\"starts with\") { (lhs: String, rhs: String) in lhs.hasPrefix(lhs) }\npublic let isOdd = suffixOperator(\"is odd\") { (value: Double) in Int(value) % 2 == 1 }\npublic let isEven = suffixOperator(\"is even\") { (value: Double) in Int(value) % 2 == 0 }\npublic let lessThan = infixOperator(\"<\") { (lhs: Double, rhs: Double) in lhs < rhs }\npublic let greaterThan = infixOperator(\">\") { (lhs: Double, rhs: Double) in lhs > rhs }\npublic let equals = infixOperator(\"==\") { (lhs: Double, rhs: Double) in lhs == rhs }\n\n//MARK: Template elements\n\npublic let ifStatement = Matcher([Keyword(\"{%\"), Keyword(\"if\"), Variable<Bool>(\"condition\"), Keyword(\"%}\"), TemplateVariable(\"body\"), Keyword(\"{%\"), Keyword(\"endif\"), Keyword(\"%}\")]) { (variables, interpreter: StringTemplateInterpreter, _) -> String? in\n    guard let condition = variables[\"condition\"] as? Bool, let body = variables[\"body\"] as? String else { return nil }\n    if condition {\n        return body\n    }\n    return nil\n}\n\npublic let printStatement = Matcher([Keyword(\"{{\"), Variable<Any>(\"body\"), Keyword(\"}}\")]) { (variables, interpreter: StringTemplateInterpreter, _) -> String? in\n    guard let body = variables[\"body\"] else { return nil }\n    return interpreter.typedInterpreter.print(body)\n}\n"
  },
  {
    "path": "Eval.playground/contents.xcplayground",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<playground version='5.0' target-platform='macos' display-mode='raw'>\n    <timeline fileName='timeline.xctimeline'/>\n</playground>"
  },
  {
    "path": "Eval.playground/playground.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "Eval.playground/xcshareddata/xcschemes/Playground.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1020\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"Eval::Eval\"\n               BuildableName = \"Eval.framework\"\n               BlueprintName = \"Eval\"\n               ReferencedContainer = \"container:Eval.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n      </Testables>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"Eval::Eval\"\n            BuildableName = \"Eval.framework\"\n            BlueprintName = \"Eval\"\n            ReferencedContainer = \"container:Eval.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"Eval::Eval\"\n            BuildableName = \"Eval.framework\"\n            BlueprintName = \"Eval\"\n            ReferencedContainer = \"container:Eval.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "Eval.podspec",
    "content": "Pod::Spec.new do |s|\n  s.name = \"Eval\"\n  s.version = \"1.5.0\"\n  s.summary = \"Eval is a lightweight interpreter framework written in  Swift, evaluating expressions at runtime\"\n  s.description = <<-DESC\nEval is a lightweight interpreter framework written in Swift, for 📱iOS, 🖥 macOS, and 🐧Linux platforms.\n\nIt evaluates expressions at runtime, with operators and data types you define.\n                   DESC\n  s.homepage = \"https://tevelee.github.io/Eval/\"\n  s.license = { :type => \"Apache 2.0\", :file => \"LICENSE.txt\" }\n  s.author = { \"Laszlo Teveli\" => \"tevelee@gmail.com\" }\n  s.social_media_url = \"http://twitter.com/tevelee\"\n  s.source = { :git => \"https://github.com/tevelee/Eval.git\", :tag => \"#{s.version}\" }\n  s.source_files = \"Sources/**/*.{h,swift}\"\n\n  s.ios.deployment_target = \"8.0\"\n  s.osx.deployment_target = \"10.10\"\n  s.watchos.deployment_target = \"2.0\"\n  s.tvos.deployment_target = \"9.0\"\nend\n"
  },
  {
    "path": "Eval.xcodeproj/EvalTests_Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<plist version=\"1.0\">\n<dict>\n  <key>CFBundleDevelopmentRegion</key>\n  <string>en</string>\n  <key>CFBundleExecutable</key>\n  <string>$(EXECUTABLE_NAME)</string>\n  <key>CFBundleIdentifier</key>\n  <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n  <key>CFBundleInfoDictionaryVersion</key>\n  <string>6.0</string>\n  <key>CFBundleName</key>\n  <string>$(PRODUCT_NAME)</string>\n  <key>CFBundlePackageType</key>\n  <string>BNDL</string>\n  <key>CFBundleShortVersionString</key>\n  <string>1.0</string>\n  <key>CFBundleSignature</key>\n  <string>????</string>\n  <key>CFBundleVersion</key>\n  <string>$(CURRENT_PROJECT_VERSION)</string>\n  <key>NSPrincipalClass</key>\n  <string></string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Eval.xcodeproj/Eval_Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<plist version=\"1.0\">\n<dict>\n  <key>CFBundleDevelopmentRegion</key>\n  <string>en</string>\n  <key>CFBundleExecutable</key>\n  <string>$(EXECUTABLE_NAME)</string>\n  <key>CFBundleIdentifier</key>\n  <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n  <key>CFBundleInfoDictionaryVersion</key>\n  <string>6.0</string>\n  <key>CFBundleName</key>\n  <string>$(PRODUCT_NAME)</string>\n  <key>CFBundlePackageType</key>\n  <string>FMWK</string>\n  <key>CFBundleShortVersionString</key>\n  <string>1.0</string>\n  <key>CFBundleSignature</key>\n  <string>????</string>\n  <key>CFBundleVersion</key>\n  <string>$(CURRENT_PROJECT_VERSION)</string>\n  <key>NSPrincipalClass</key>\n  <string></string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Eval.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXAggregateTarget section */\n\t\t\"Eval::EvalPackageTests::ProductTarget\" /* EvalPackageTests */ = {\n\t\t\tisa = PBXAggregateTarget;\n\t\t\tbuildConfigurationList = OBJ_67 /* Build configuration list for PBXAggregateTarget \"EvalPackageTests\" */;\n\t\t\tbuildPhases = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\tOBJ_70 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = EvalPackageTests;\n\t\t\tproductName = EvalPackageTests;\n\t\t};\n/* End PBXAggregateTarget section */\n\n/* Begin PBXBuildFile section */\n\t\t3AED32EA232D382D00FA2596 /* PerformanceTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AED32E9232D382D00FA2596 /* PerformanceTest.swift */; };\n\t\t3AED32ED232D3D4D00FA2596 /* Suffix.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AED32EB232D3D3500FA2596 /* Suffix.swift */; };\n\t\tOBJ_51 /* Common.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_9 /* Common.swift */; };\n\t\tOBJ_52 /* Elements.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_10 /* Elements.swift */; };\n\t\tOBJ_53 /* TemplateInterpreter.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_11 /* TemplateInterpreter.swift */; };\n\t\tOBJ_54 /* TypedInterpreter.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_12 /* TypedInterpreter.swift */; };\n\t\tOBJ_55 /* MatchResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_14 /* MatchResult.swift */; };\n\t\tOBJ_56 /* Matcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_15 /* Matcher.swift */; };\n\t\tOBJ_57 /* Pattern.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_16 /* Pattern.swift */; };\n\t\tOBJ_58 /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_17 /* Utils.swift */; };\n\t\tOBJ_65 /* Package.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_6 /* Package.swift */; };\n\t\tOBJ_76 /* InterpreterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_21 /* InterpreterTests.swift */; };\n\t\tOBJ_77 /* TemplateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_22 /* TemplateTests.swift */; };\n\t\tOBJ_78 /* DataTypeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_24 /* DataTypeTests.swift */; };\n\t\tOBJ_79 /* FunctionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_25 /* FunctionTests.swift */; };\n\t\tOBJ_80 /* InterpreterContextTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_26 /* InterpreterContextTests.swift */; };\n\t\tOBJ_81 /* KeywordTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_27 /* KeywordTests.swift */; };\n\t\tOBJ_82 /* LiteralTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_28 /* LiteralTests.swift */; };\n\t\tOBJ_83 /* MatchResultTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_29 /* MatchResultTests.swift */; };\n\t\tOBJ_84 /* MatchStatementTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_30 /* MatchStatementTests.swift */; };\n\t\tOBJ_85 /* MatcherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_31 /* MatcherTests.swift */; };\n\t\tOBJ_86 /* PatternTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_32 /* PatternTests.swift */; };\n\t\tOBJ_87 /* TemplateInterpreterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_33 /* TemplateInterpreterTests.swift */; };\n\t\tOBJ_88 /* TypedInterpreterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_34 /* TypedInterpreterTests.swift */; };\n\t\tOBJ_89 /* UtilTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_35 /* UtilTests.swift */; };\n\t\tOBJ_90 /* VariableProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_36 /* VariableProcessor.swift */; };\n\t\tOBJ_91 /* VariableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_37 /* VariableTests.swift */; };\n\t\tOBJ_92 /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_38 /* Utils.swift */; };\n\t\tOBJ_94 /* Eval.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = \"Eval::Eval::Product\" /* Eval.framework */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXContainerItemProxy section */\n\t\t3A0B80062294367A008925A6 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = OBJ_1 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = \"Eval::Eval\";\n\t\t\tremoteInfo = Eval;\n\t\t};\n\t\t3A0B80072294367B008925A6 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = OBJ_1 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = \"Eval::EvalTests\";\n\t\t\tremoteInfo = EvalTests;\n\t\t};\n/* End PBXContainerItemProxy section */\n\n/* Begin PBXFileReference section */\n\t\t3AED32E9232D382D00FA2596 /* PerformanceTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PerformanceTest.swift; sourceTree = \"<group>\"; };\n\t\t3AED32EB232D3D3500FA2596 /* Suffix.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Suffix.swift; sourceTree = \"<group>\"; };\n\t\t\"Eval::Eval::Product\" /* Eval.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Eval.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t\"Eval::EvalTests::Product\" /* EvalTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; path = EvalTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tOBJ_10 /* Elements.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Elements.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_11 /* TemplateInterpreter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateInterpreter.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_12 /* TypedInterpreter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TypedInterpreter.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_14 /* MatchResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MatchResult.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_15 /* Matcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Matcher.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_16 /* Pattern.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pattern.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_17 /* Utils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utils.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_21 /* InterpreterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InterpreterTests.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_22 /* TemplateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateTests.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_24 /* DataTypeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataTypeTests.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_25 /* FunctionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FunctionTests.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_26 /* InterpreterContextTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InterpreterContextTests.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_27 /* KeywordTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeywordTests.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_28 /* LiteralTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiteralTests.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_29 /* MatchResultTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MatchResultTests.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_30 /* MatchStatementTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MatchStatementTests.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_31 /* MatcherTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MatcherTests.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_32 /* PatternTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PatternTests.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_33 /* TemplateInterpreterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateInterpreterTests.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_34 /* TypedInterpreterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TypedInterpreterTests.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_35 /* UtilTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UtilTests.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_36 /* VariableProcessor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VariableProcessor.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_37 /* VariableTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VariableTests.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_38 /* Utils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utils.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_39 /* Documentation */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Documentation; sourceTree = SOURCE_ROOT; };\n\t\tOBJ_40 /* Eval.xcworkspace */ = {isa = PBXFileReference; lastKnownFileType = wrapper.workspace; path = Eval.xcworkspace; sourceTree = SOURCE_ROOT; };\n\t\tOBJ_41 /* Examples */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Examples; sourceTree = SOURCE_ROOT; };\n\t\tOBJ_42 /* Scripts */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Scripts; sourceTree = SOURCE_ROOT; };\n\t\tOBJ_6 /* Package.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; path = Package.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_9 /* Common.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Common.swift; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\tOBJ_59 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 0;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tOBJ_93 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 0;\n\t\t\tfiles = (\n\t\t\t\tOBJ_94 /* Eval.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\tOBJ_13 /* Utilities */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_14 /* MatchResult.swift */,\n\t\t\t\tOBJ_15 /* Matcher.swift */,\n\t\t\t\tOBJ_16 /* Pattern.swift */,\n\t\t\t\tOBJ_17 /* Utils.swift */,\n\t\t\t);\n\t\t\tpath = Utilities;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_18 /* Tests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_19 /* EvalTests */,\n\t\t\t);\n\t\t\tname = Tests;\n\t\t\tsourceTree = SOURCE_ROOT;\n\t\t};\n\t\tOBJ_19 /* EvalTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_20 /* IntegrationTests */,\n\t\t\t\tOBJ_23 /* UnitTests */,\n\t\t\t\tOBJ_38 /* Utils.swift */,\n\t\t\t);\n\t\t\tname = EvalTests;\n\t\t\tpath = Tests/EvalTests;\n\t\t\tsourceTree = SOURCE_ROOT;\n\t\t};\n\t\tOBJ_20 /* IntegrationTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_21 /* InterpreterTests.swift */,\n\t\t\t\tOBJ_22 /* TemplateTests.swift */,\n\t\t\t\t3AED32E9232D382D00FA2596 /* PerformanceTest.swift */,\n\t\t\t\t3AED32EB232D3D3500FA2596 /* Suffix.swift */,\n\t\t\t);\n\t\t\tpath = IntegrationTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_23 /* UnitTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_24 /* DataTypeTests.swift */,\n\t\t\t\tOBJ_25 /* FunctionTests.swift */,\n\t\t\t\tOBJ_26 /* InterpreterContextTests.swift */,\n\t\t\t\tOBJ_27 /* KeywordTests.swift */,\n\t\t\t\tOBJ_28 /* LiteralTests.swift */,\n\t\t\t\tOBJ_29 /* MatchResultTests.swift */,\n\t\t\t\tOBJ_30 /* MatchStatementTests.swift */,\n\t\t\t\tOBJ_31 /* MatcherTests.swift */,\n\t\t\t\tOBJ_32 /* PatternTests.swift */,\n\t\t\t\tOBJ_33 /* TemplateInterpreterTests.swift */,\n\t\t\t\tOBJ_34 /* TypedInterpreterTests.swift */,\n\t\t\t\tOBJ_35 /* UtilTests.swift */,\n\t\t\t\tOBJ_36 /* VariableProcessor.swift */,\n\t\t\t\tOBJ_37 /* VariableTests.swift */,\n\t\t\t);\n\t\t\tpath = UnitTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_43 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t\"Eval::EvalTests::Product\" /* EvalTests.xctest */,\n\t\t\t\t\"Eval::Eval::Product\" /* Eval.framework */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = BUILT_PRODUCTS_DIR;\n\t\t};\n\t\tOBJ_5 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_6 /* Package.swift */,\n\t\t\t\tOBJ_7 /* Sources */,\n\t\t\t\tOBJ_18 /* Tests */,\n\t\t\t\tOBJ_39 /* Documentation */,\n\t\t\t\tOBJ_40 /* Eval.xcworkspace */,\n\t\t\t\tOBJ_41 /* Examples */,\n\t\t\t\tOBJ_42 /* Scripts */,\n\t\t\t\tOBJ_43 /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_7 /* Sources */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_8 /* Eval */,\n\t\t\t);\n\t\t\tname = Sources;\n\t\t\tsourceTree = SOURCE_ROOT;\n\t\t};\n\t\tOBJ_8 /* Eval */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_9 /* Common.swift */,\n\t\t\t\tOBJ_10 /* Elements.swift */,\n\t\t\t\tOBJ_11 /* TemplateInterpreter.swift */,\n\t\t\t\tOBJ_12 /* TypedInterpreter.swift */,\n\t\t\t\tOBJ_13 /* Utilities */,\n\t\t\t);\n\t\t\tname = Eval;\n\t\t\tpath = Sources/Eval;\n\t\t\tsourceTree = SOURCE_ROOT;\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t\"Eval::Eval\" /* Eval */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = OBJ_47 /* Build configuration list for PBXNativeTarget \"Eval\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tOBJ_50 /* Sources */,\n\t\t\t\tOBJ_59 /* Frameworks */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = Eval;\n\t\t\tproductName = Eval;\n\t\t\tproductReference = \"Eval::Eval::Product\" /* Eval.framework */;\n\t\t\tproductType = \"com.apple.product-type.framework\";\n\t\t};\n\t\t\"Eval::EvalTests\" /* EvalTests */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = OBJ_72 /* Build configuration list for PBXNativeTarget \"EvalTests\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tOBJ_75 /* Sources */,\n\t\t\t\tOBJ_93 /* Frameworks */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\tOBJ_95 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = EvalTests;\n\t\t\tproductName = EvalTests;\n\t\t\tproductReference = \"Eval::EvalTests::Product\" /* EvalTests.xctest */;\n\t\t\tproductType = \"com.apple.product-type.bundle.unit-test\";\n\t\t};\n\t\t\"Eval::SwiftPMPackageDescription\" /* EvalPackageDescription */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = OBJ_61 /* Build configuration list for PBXNativeTarget \"EvalPackageDescription\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tOBJ_64 /* Sources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = EvalPackageDescription;\n\t\t\tproductName = EvalPackageDescription;\n\t\t\tproductType = \"com.apple.product-type.framework\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\tOBJ_1 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastUpgradeCheck = 1020;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t\"Eval::EvalTests\" = {\n\t\t\t\t\t\tLastSwiftMigration = 1020;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = OBJ_2 /* Build configuration list for PBXProject \"Eval\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = OBJ_5;\n\t\t\tproductRefGroup = OBJ_43 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t\"Eval::Eval\" /* Eval */,\n\t\t\t\t\"Eval::SwiftPMPackageDescription\" /* EvalPackageDescription */,\n\t\t\t\t\"Eval::EvalPackageTests::ProductTarget\" /* EvalPackageTests */,\n\t\t\t\t\"Eval::EvalTests\" /* EvalTests */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\tOBJ_50 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 0;\n\t\t\tfiles = (\n\t\t\t\tOBJ_51 /* Common.swift in Sources */,\n\t\t\t\tOBJ_52 /* Elements.swift in Sources */,\n\t\t\t\tOBJ_53 /* TemplateInterpreter.swift in Sources */,\n\t\t\t\tOBJ_54 /* TypedInterpreter.swift in Sources */,\n\t\t\t\tOBJ_55 /* MatchResult.swift in Sources */,\n\t\t\t\tOBJ_56 /* Matcher.swift in Sources */,\n\t\t\t\tOBJ_57 /* Pattern.swift in Sources */,\n\t\t\t\tOBJ_58 /* Utils.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tOBJ_64 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 0;\n\t\t\tfiles = (\n\t\t\t\tOBJ_65 /* Package.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tOBJ_75 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 0;\n\t\t\tfiles = (\n\t\t\t\tOBJ_76 /* InterpreterTests.swift in Sources */,\n\t\t\t\tOBJ_77 /* TemplateTests.swift in Sources */,\n\t\t\t\tOBJ_78 /* DataTypeTests.swift in Sources */,\n\t\t\t\t3AED32ED232D3D4D00FA2596 /* Suffix.swift in Sources */,\n\t\t\t\tOBJ_79 /* FunctionTests.swift in Sources */,\n\t\t\t\tOBJ_80 /* InterpreterContextTests.swift in Sources */,\n\t\t\t\tOBJ_81 /* KeywordTests.swift in Sources */,\n\t\t\t\t3AED32EA232D382D00FA2596 /* PerformanceTest.swift in Sources */,\n\t\t\t\tOBJ_82 /* LiteralTests.swift in Sources */,\n\t\t\t\tOBJ_83 /* MatchResultTests.swift in Sources */,\n\t\t\t\tOBJ_84 /* MatchStatementTests.swift in Sources */,\n\t\t\t\tOBJ_85 /* MatcherTests.swift in Sources */,\n\t\t\t\tOBJ_86 /* PatternTests.swift in Sources */,\n\t\t\t\tOBJ_87 /* TemplateInterpreterTests.swift in Sources */,\n\t\t\t\tOBJ_88 /* TypedInterpreterTests.swift in Sources */,\n\t\t\t\tOBJ_89 /* UtilTests.swift in Sources */,\n\t\t\t\tOBJ_90 /* VariableProcessor.swift in Sources */,\n\t\t\t\tOBJ_91 /* VariableTests.swift in Sources */,\n\t\t\t\tOBJ_92 /* Utils.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXTargetDependency section */\n\t\tOBJ_70 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = \"Eval::EvalTests\" /* EvalTests */;\n\t\t\ttargetProxy = 3A0B80072294367B008925A6 /* PBXContainerItemProxy */;\n\t\t};\n\t\tOBJ_95 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = \"Eval::Eval\" /* Eval */;\n\t\t\ttargetProxy = 3A0B80062294367A008925A6 /* PBXContainerItemProxy */;\n\t\t};\n/* End PBXTargetDependency section */\n\n/* Begin XCBuildConfiguration section */\n\t\tOBJ_3 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tDYLIB_INSTALL_NAME_BASE = \"@rpath\";\n\t\t\t\tENABLE_NS_ASSERTIONS = YES;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.10;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tOTHER_SWIFT_FLAGS = \"-DXcode\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSDKROOT = macosx;\n\t\t\t\tSUPPORTED_PLATFORMS = \"macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator\";\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = \"SWIFT_PACKAGE DEBUG\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tUSE_HEADERMAP = NO;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tOBJ_4 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tCOPY_PHASE_STRIP = YES;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tDYLIB_INSTALL_NAME_BASE = \"@rpath\";\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = s;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.10;\n\t\t\t\tOTHER_SWIFT_FLAGS = \"-DXcode\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSDKROOT = macosx;\n\t\t\t\tSUPPORTED_PLATFORMS = \"macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator\";\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = SWIFT_PACKAGE;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Owholemodule\";\n\t\t\t\tUSE_HEADERMAP = NO;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tOBJ_48 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"$(PLATFORM_DIR)/Developer/Library/Frameworks\",\n\t\t\t\t);\n\t\t\t\tHEADER_SEARCH_PATHS = \"$(inherited)\";\n\t\t\t\tINFOPLIST_FILE = Eval.xcodeproj/Eval_Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) $(TOOLCHAIN_DIR)/usr/lib/swift/macosx\";\n\t\t\t\tOTHER_CFLAGS = \"$(inherited)\";\n\t\t\t\tOTHER_LDFLAGS = \"$(inherited)\";\n\t\t\t\tOTHER_SWIFT_FLAGS = \"$(inherited)\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = Eval;\n\t\t\t\tPRODUCT_MODULE_NAME = \"$(TARGET_NAME:c99extidentifier)\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME:c99extidentifier)\";\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = \"$(inherited)\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGET_NAME = Eval;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tOBJ_49 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"$(PLATFORM_DIR)/Developer/Library/Frameworks\",\n\t\t\t\t);\n\t\t\t\tHEADER_SEARCH_PATHS = \"$(inherited)\";\n\t\t\t\tINFOPLIST_FILE = Eval.xcodeproj/Eval_Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) $(TOOLCHAIN_DIR)/usr/lib/swift/macosx\";\n\t\t\t\tOTHER_CFLAGS = \"$(inherited)\";\n\t\t\t\tOTHER_LDFLAGS = \"$(inherited)\";\n\t\t\t\tOTHER_SWIFT_FLAGS = \"$(inherited)\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = Eval;\n\t\t\t\tPRODUCT_MODULE_NAME = \"$(TARGET_NAME:c99extidentifier)\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME:c99extidentifier)\";\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = \"$(inherited)\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGET_NAME = Eval;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tOBJ_62 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tLD = /usr/bin/true;\n\t\t\t\tOTHER_SWIFT_FLAGS = \"-swift-version 4.2 -I $(TOOLCHAIN_DIR)/usr/lib/swift/pm/4_2 -target x86_64-apple-macosx10.10 -sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tOBJ_63 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tLD = /usr/bin/true;\n\t\t\t\tOTHER_SWIFT_FLAGS = \"-swift-version 4.2 -I $(TOOLCHAIN_DIR)/usr/lib/swift/pm/4_2 -target x86_64-apple-macosx10.10 -sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tOBJ_68 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tOBJ_69 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tOBJ_73 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"$(PLATFORM_DIR)/Developer/Library/Frameworks\",\n\t\t\t\t);\n\t\t\t\tHEADER_SEARCH_PATHS = \"$(inherited)\";\n\t\t\t\tINFOPLIST_FILE = Eval.xcodeproj/EvalTests_Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @loader_path/../Frameworks @loader_path/Frameworks\";\n\t\t\t\tOTHER_CFLAGS = \"$(inherited)\";\n\t\t\t\tOTHER_LDFLAGS = \"$(inherited)\";\n\t\t\t\tOTHER_SWIFT_FLAGS = \"$(inherited)\";\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = \"$(inherited)\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGET_NAME = EvalTests;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tOBJ_74 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"$(PLATFORM_DIR)/Developer/Library/Frameworks\",\n\t\t\t\t);\n\t\t\t\tHEADER_SEARCH_PATHS = \"$(inherited)\";\n\t\t\t\tINFOPLIST_FILE = Eval.xcodeproj/EvalTests_Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @loader_path/../Frameworks @loader_path/Frameworks\";\n\t\t\t\tOTHER_CFLAGS = \"$(inherited)\";\n\t\t\t\tOTHER_LDFLAGS = \"$(inherited)\";\n\t\t\t\tOTHER_SWIFT_FLAGS = \"$(inherited)\";\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = \"$(inherited)\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGET_NAME = EvalTests;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\tOBJ_2 /* Build configuration list for PBXProject \"Eval\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tOBJ_3 /* Debug */,\n\t\t\t\tOBJ_4 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tOBJ_47 /* Build configuration list for PBXNativeTarget \"Eval\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tOBJ_48 /* Debug */,\n\t\t\t\tOBJ_49 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tOBJ_61 /* Build configuration list for PBXNativeTarget \"EvalPackageDescription\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tOBJ_62 /* Debug */,\n\t\t\t\tOBJ_63 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tOBJ_67 /* Build configuration list for PBXAggregateTarget \"EvalPackageTests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tOBJ_68 /* Debug */,\n\t\t\t\tOBJ_69 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tOBJ_72 /* Build configuration list for PBXNativeTarget \"EvalTests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tOBJ_73 /* Debug */,\n\t\t\t\tOBJ_74 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = OBJ_1 /* Project object */;\n}\n"
  },
  {
    "path": "Eval.xcodeproj/xcshareddata/xcschemes/Eval-Package.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1020\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"Eval::Eval\"\n               BuildableName = \"Eval.framework\"\n               BlueprintName = \"Eval\"\n               ReferencedContainer = \"container:Eval.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      codeCoverageEnabled = \"YES\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n         <TestableReference\n            skipped = \"NO\"\n            parallelizable = \"YES\"\n            testExecutionOrdering = \"random\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"Eval::EvalTests\"\n               BuildableName = \"EvalTests.xctest\"\n               BlueprintName = \"EvalTests\"\n               ReferencedContainer = \"container:Eval.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n      </Testables>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"Eval::Eval\"\n            BuildableName = \"Eval.framework\"\n            BlueprintName = \"Eval\"\n            ReferencedContainer = \"container:Eval.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "Eval.xcodeproj/xcshareddata/xcschemes/xcschememanagement.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<plist version=\"1.0\">\n<dict>\n  <key>SchemeUserState</key>\n  <dict>\n    <key>Eval-Package.xcscheme</key>\n    <dict></dict>\n  </dict>\n  <key>SuppressBuildableAutocreation</key>\n  <dict></dict>\n</dict>\n</plist>\n"
  },
  {
    "path": "Eval.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"group:Eval.playground\">\n   </FileRef>\n   <FileRef\n      location = \"container:Eval.xcodeproj\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "Eval.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>IDEDidComputeMac32BitWarning</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "Examples/.swiftlint.yml",
    "content": "disabled_rules:\n  - file_header"
  },
  {
    "path": "Examples/AttributedStringExample/.gitignore",
    "content": ".DS_Store\n/.build\n/Packages\n/*.xcodeproj"
  },
  {
    "path": "Examples/AttributedStringExample/Package.swift",
    "content": "// swift-tools-version:4.2\n\nimport PackageDescription\n\nlet package = Package(\n    name: \"AttributedStringExample\",\n    products: [\n        .library(\n            name: \"AttributedStringExample\",\n            targets: [\"AttributedStringExample\"])\n    ],\n    dependencies: [\n        .package(url: \"../../\", from: \"1.4.0\")\n    ],\n    targets: [\n        .target(\n            name: \"AttributedStringExample\",\n            dependencies: [\"Eval\"]),\n        .testTarget(\n            name: \"AttributedStringExampleTests\",\n            dependencies: [\"AttributedStringExample\"])\n    ]\n)\n"
  },
  {
    "path": "Examples/AttributedStringExample/README.md",
    "content": "# TemplateExample\n\nA description of this package.\n"
  },
  {
    "path": "Examples/AttributedStringExample/Sources/AttributedStringExample/TemplateExample.swift",
    "content": "import AppKit\n@_exported import Eval\nimport Foundation\n@_exported import class Eval.Pattern\n\n// swiftlint:disable:next type_name\npublic class AttributedStringTemplateInterpreter: TemplateInterpreter<NSAttributedString> {\n    typealias EvaluatedType = NSAttributedString\n\n    override public func evaluate(_ expression: String, context: Context = Context()) -> NSAttributedString {\n        return evaluate(expression, context: context, reducer: (initialValue: NSAttributedString(), reduceValue: { existing, next in\n            existing.appending(next)\n        }, reduceCharacter: { existing, next in\n            existing.appending(NSAttributedString(string: String(next)))\n        }))\n    }\n}\n\n// swiftlint:disable:next type_name\npublic class AttributedStringInterpreter: EvaluatorWithLocalContext {\n    public typealias EvaluatedType = NSAttributedString\n\n    let interpreter: AttributedStringTemplateInterpreter\n\n    init() {\n        let context = Context()\n\n        let center = NSMutableParagraphStyle()\n        center.alignment = .center\n\n        interpreter = AttributedStringTemplateInterpreter(statements: [AttributedStringInterpreter.attributeMatcher(name: \"bold\", attributes: [.font: NSFont.boldSystemFont(ofSize: 12)]),\n                                                                       AttributedStringInterpreter.attributeMatcher(name: \"red\", attributes: [.foregroundColor: NSColor.red]),\n                                                                       AttributedStringInterpreter.attributeMatcher(name: \"center\", attributes: [.paragraphStyle: center])],\n                                                          interpreter: TypedInterpreter(context: context),\n                                                          context: context)\n    }\n\n    public func evaluate(_ expression: String) -> AttributedStringInterpreter.EvaluatedType {\n        return interpreter.evaluate(expression)\n    }\n\n    public func evaluate(_ expression: String, context: Context) -> AttributedStringInterpreter.EvaluatedType {\n        return interpreter.evaluate(expression, context: context)\n    }\n\n    static func attributeMatcher(name: String, attributes: [NSAttributedString.Key: Any]) -> Pattern<NSAttributedString, TemplateInterpreter<NSAttributedString>> {\n        return Pattern([OpenKeyword(\"<\\(name)>\"), GenericVariable<String, AttributedStringTemplateInterpreter>(\"body\", options: .notInterpreted), CloseKeyword(\"</\\(name)>\")]) {\n            guard let body = $0.variables[\"body\"] as? String else { return nil }\n            return NSAttributedString(string: body, attributes: attributes)\n        }\n    }\n}\n\npublic extension NSAttributedString {\n    func appending(_ other: NSAttributedString) -> NSAttributedString {\n        let mutable = NSMutableAttributedString(attributedString: self)\n        mutable.append(other)\n        return mutable\n    }\n}\n"
  },
  {
    "path": "Examples/AttributedStringExample/Tests/.swiftlint.yml",
    "content": "disabled_rules:\n  - force_cast\n  - force_try\n  - type_name\n  - file_header\n  - explicit_top_level_acl"
  },
  {
    "path": "Examples/AttributedStringExample/Tests/AttributedStringExampleTests/AttributedStringExampleTests.swift",
    "content": "@testable import AttributedStringExample\nimport Eval\nimport XCTest\n\nclass AttributedStringExampleTests: XCTestCase {\n    let interpreter: AttributedStringInterpreter = AttributedStringInterpreter()\n\n    func testExample() {\n        let interpreter = AttributedStringInterpreter()\n\n        XCTAssertEqual(interpreter.evaluate(\"<bold>Hello</bold>\"), NSAttributedString(string: \"Hello\", attributes: [.font: NSFont.boldSystemFont(ofSize: 12)]))\n\n        XCTAssertEqual(interpreter.evaluate(\"It's <red>red</red>\"), NSAttributedString(string: \"It's \").appending(NSAttributedString(string: \"red\", attributes: [.foregroundColor: NSColor.red])))\n\n        let style = interpreter.evaluate(\"<center>Centered text</center>\").attribute(.paragraphStyle, at: 0, effectiveRange: nil) as! NSParagraphStyle\n        XCTAssertEqual(style.alignment, .center)\n    }\n}\n"
  },
  {
    "path": "Examples/AttributedStringExample/Tests/LinuxMain.swift",
    "content": "@testable import TemplateExampleTests\nimport XCTest\n\nXCTMain([\n    testCase(TemplateExampleTests.allTests)\n])\n"
  },
  {
    "path": "Examples/ColorParserExample/.gitignore",
    "content": ".DS_Store\n/.build\n/Packages\n/*.xcodeproj"
  },
  {
    "path": "Examples/ColorParserExample/Package.swift",
    "content": "// swift-tools-version:4.2\n\nimport PackageDescription\n\nlet package = Package(\n    name: \"ColorParserExample\",\n    products: [\n        .library(\n            name: \"ColorParserExample\",\n            targets: [\"ColorParserExample\"])\n    ],\n    dependencies: [\n        .package(url: \"../../\", from: \"1.4.0\")\n    ],\n    targets: [\n        .target(\n            name: \"ColorParserExample\",\n            dependencies: [\"Eval\"]),\n        .testTarget(\n            name: \"ColorParserExampleTests\",\n            dependencies: [\"ColorParserExample\"])\n    ]\n)\n"
  },
  {
    "path": "Examples/ColorParserExample/README.md",
    "content": "# TemplateExample\n\nA description of this package.\n"
  },
  {
    "path": "Examples/ColorParserExample/Sources/ColorParserExample/ColorParserExample.swift",
    "content": "import AppKit\n@_exported import Eval\n@_exported import class Eval.Pattern\nimport Foundation\n\npublic class ColorParser: EvaluatorWithLocalContext {\n    let interpreter: TypedInterpreter\n\n    init() {\n        interpreter = TypedInterpreter(dataTypes: [ColorParser.colorDataType()], functions: [ColorParser.mixFunction()])\n    }\n\n    static func colorDataType() -> DataType<NSColor> {\n        let hex = Literal<NSColor> {\n            guard $0.value.first == \"#\", $0.value.count == 7,\n            let red = Int($0.value[1...2], radix: 16),\n            let green = Int($0.value[3...4], radix: 16),\n            let blue = Int($0.value[5...6], radix: 16) else { return nil }\n            return NSColor(calibratedRed: CGFloat(red), green: CGFloat(green), blue: CGFloat(blue), alpha: 1)\n        }\n\n        let red = Literal(\"red\", convertsTo: NSColor.red)\n\n        return DataType(type: NSColor.self, literals: [hex, red]) { $0.value.description }\n    }\n\n    static func mixFunction() -> Function<NSColor> {\n        return Function([Variable<NSColor>(\"lhs\"), Keyword(\"mixed with\"), Variable<NSColor>(\"rhs\")]) {\n            guard let lhs = $0.variables[\"lhs\"] as? NSColor, let rhs = $0.variables[\"rhs\"] as? NSColor else { return nil }\n            return lhs.blend(with: rhs)\n        }\n    }\n\n    public func evaluate(_ expression: String) -> Any? {\n        return interpreter.evaluate(expression)\n    }\n\n    public func evaluate(_ expression: String, context: Context) -> Any? {\n        return interpreter.evaluate(expression, context: context)\n    }\n}\n\nextension String {\n    subscript (range: CountableClosedRange<Int>) -> Substring {\n        return self[index(startIndex, offsetBy: range.lowerBound) ..< index(startIndex, offsetBy: range.upperBound)]\n    }\n}\n\nextension NSColor {\n    func blend(with other: NSColor, using factor: CGFloat = 0.5) -> NSColor {\n        let inverseFactor = 1.0 - factor\n\n        var leftRed: CGFloat = 0\n        var leftGreen: CGFloat = 0\n        var leftBlue: CGFloat = 0\n        var leftAlpha: CGFloat = 0\n        getRed(&leftRed, green: &leftGreen, blue: &leftBlue, alpha: &leftAlpha)\n\n        var rightRed: CGFloat = 0\n        var rightGreen: CGFloat = 0\n        var rightBlue: CGFloat = 0\n        var rightAlpha: CGFloat = 0\n        other.getRed(&rightRed, green: &rightGreen, blue: &rightBlue, alpha: &rightAlpha)\n\n        return NSColor(calibratedRed: leftRed * factor + rightRed * inverseFactor,\n                       green: leftGreen * factor + rightGreen * inverseFactor,\n                       blue: leftBlue * factor + rightBlue * inverseFactor,\n                       alpha: leftAlpha * factor + rightAlpha * inverseFactor)\n    }\n}\n"
  },
  {
    "path": "Examples/ColorParserExample/Tests/.swiftlint.yml",
    "content": "disabled_rules:\n  - force_cast\n  - force_try\n  - type_name\n  - file_header\n  - explicit_top_level_acl"
  },
  {
    "path": "Examples/ColorParserExample/Tests/ColorParserExampleTests/ColorParserExampleTests.swift",
    "content": "@testable import ColorParserExample\nimport Eval\nimport XCTest\n\nclass ColorParserExampleTests: XCTestCase {\n    let colorParser: ColorParser = ColorParser()\n\n    func testExample() {\n        XCTAssertEqual(colorParser.evaluate(\"#00ff00\") as! NSColor, NSColor(calibratedRed: 0, green: 1, blue: 0, alpha: 1))\n        XCTAssertEqual(colorParser.evaluate(\"red\") as! NSColor, .red)\n        XCTAssertEqual(colorParser.evaluate(\"#ff0000 mixed with #0000ff\") as! NSColor, NSColor(calibratedRed: 0.5, green: 0, blue: 0.5, alpha: 1))\n    }\n}\n"
  },
  {
    "path": "Examples/ColorParserExample/Tests/LinuxMain.swift",
    "content": "@testable import TemplateExampleTests\nimport XCTest\n\nXCTMain([\n    testCase(TemplateExampleTests.allTests)\n])\n"
  },
  {
    "path": "Examples/TemplateExample/.gitignore",
    "content": ".DS_Store\n/.build\n/Packages\n/*.xcodeproj\n"
  },
  {
    "path": "Examples/TemplateExample/Package.swift",
    "content": "// swift-tools-version:4.2\n\nimport PackageDescription\n\nlet package = Package(\n    name: \"TemplateExample\",\n    products: [\n        .library(\n            name: \"TemplateExample\",\n            targets: [\"TemplateExample\"])\n    ],\n    dependencies: [\n        .package(url: \"../../\", from: \"1.4.0\")\n    ],\n    targets: [\n        .target(\n            name: \"TemplateExample\",\n            dependencies: [\"Eval\"]),\n        .testTarget(\n            name: \"TemplateExampleTests\",\n            dependencies: [\"TemplateExample\"])\n    ]\n)\n"
  },
  {
    "path": "Examples/TemplateExample/README.md",
    "content": "# TemplateExample\n\nA description of this package.\n"
  },
  {
    "path": "Examples/TemplateExample/Sources/TemplateExample/TemplateExample.swift",
    "content": "@_exported import Eval\n@_exported import class Eval.Pattern\nimport Foundation\n\npublic class TemplateLanguage: EvaluatorWithLocalContext {\n    public typealias EvaluatedType = String\n\n    let language: StringTemplateInterpreter\n    let macroReplacer: StringTemplateInterpreter\n\n    init(dataTypes: [DataTypeProtocol] = StandardLibrary.dataTypes,\n         functions: [FunctionProtocol] = StandardLibrary.functions,\n         templates: [Pattern<String, TemplateInterpreter<String>>] = TemplateLibrary.templates,\n         context: Context = Context()) {\n        TemplateLanguage.preprocess(context)\n\n        let interpreter = TypedInterpreter(dataTypes: dataTypes, functions: functions, context: context)\n        let language = StringTemplateInterpreter(statements: templates, interpreter: interpreter, context: context)\n        self.language = language\n\n        let block = Pattern<String, TemplateInterpreter<String>>([OpenKeyword(\"{{{\"), TemplateVariable(\"name\", options: .notInterpreted), CloseKeyword(\"}}}\")]) {\n            guard let name = $0.variables[\"name\"] as? String else { return nil }\n            return language.context.blocks[name]?.last?(language.context)\n        }\n        macroReplacer = StringTemplateInterpreter(statements: [block])\n    }\n\n    public func evaluate(_ expression: String) -> String {\n        return evaluate(expression, context: Context())\n    }\n\n    public func evaluate(_ expression: String, context: Context) -> String {\n        TemplateLanguage.preprocess(context)\n        let input = replaceWhitespaces(expression)\n        let result = language.evaluate(input, context: context)\n        let finalResult = macroReplacer.evaluate(result)\n        return finalResult.contains(TemplateLibrary.tagPrefix) ? language.evaluate(finalResult, context: context) : finalResult\n    }\n\n    public func evaluate(template from: URL) throws -> String {\n        let expression = try String(contentsOf: from)\n        return evaluate(expression)\n    }\n\n    public func evaluate(template from: URL, context: Context) throws -> String {\n        let expression = try String(contentsOf: from)\n        return evaluate(expression, context: context)\n    }\n\n    static func preprocess(_ context: Context) {\n        context.variables = context.variables.mapValues { value in\n            convert(value) {\n                if let integerValue = $0 as? Int {\n                    return Double(integerValue)\n                }\n                return $0\n            }\n        }\n    }\n\n    static func convert(_ value: Any, recursively: Bool = true, convert: @escaping (Any) -> Any) -> Any {\n        if recursively, let array = value as? [Any] {\n            return array.map { convert($0) }\n        }\n        if recursively, let dictionary = value as? [String: Any] {\n            return dictionary.mapValues { convert($0) }\n        }\n        return convert(value)\n    }\n\n    func replaceWhitespaces(_ input: String) -> String {\n        let tag = \"{-}\"\n        var input = input\n        repeat {\n            if var range = input.range(of: tag) {\n                searchForward: while true {\n                    if range.upperBound < input.index(before: input.endIndex) {\n                        let nextIndex = range.upperBound\n                        if let unicodeScalar = input[nextIndex].unicodeScalars.first,\n                            CharacterSet.whitespacesAndNewlines.contains(unicodeScalar) {\n                            range = Range(uncheckedBounds: (lower: range.lowerBound, upper: input.index(after: range.upperBound)))\n                        } else {\n                            break searchForward\n                        }\n                    } else {\n                        break searchForward\n                    }\n                }\n                searchBackward: while true {\n                    if range.lowerBound > input.startIndex {\n                        let nextIndex = input.index(before: range.lowerBound)\n                        if let unicodeScalar = input[nextIndex].unicodeScalars.first,\n                            CharacterSet.whitespacesAndNewlines.contains(unicodeScalar) {\n                            range = Range(uncheckedBounds: (lower: input.index(before: range.lowerBound), upper: range.upperBound))\n                        } else {\n                            break searchBackward\n                        }\n                    } else {\n                        break searchBackward\n                    }\n                }\n                input.replaceSubrange(range, with: \"\")\n            }\n        } while input.contains(tag)\n        return input\n    }\n}\n\ninternal typealias Macro = (arguments: [String], body: String)\ninternal typealias BlockRenderer = (_ context: Context) -> String\n\nextension Context {\n    static let macrosKey: String = \"__macros\"\n    var macros: [String: Macro] {\n        get {\n            return variables[Context.macrosKey] as? [String: Macro] ?? [:]\n        }\n        set {\n            variables[Context.macrosKey] = macros.merging(newValue) { _, new in new }\n        }\n    }\n\n    static let blocksKey: String = \"__blocks\"\n    var blocks: [String: [BlockRenderer]] {\n        get {\n            return variables[Context.blocksKey] as? [String: [BlockRenderer]] ?? [:]\n        }\n        set {\n            variables[Context.blocksKey] = blocks.merging(newValue) { _, new in new }\n        }\n    }\n}\n\npublic class TemplateLibrary {\n    public static var standardLibrary: StandardLibrary = StandardLibrary()\n    public static var templates: [Pattern<String, TemplateInterpreter<String>>] {\n        return [\n            ifElseStatement,\n            ifStatement,\n            printStatement,\n            forInStatement,\n            setUsingBodyStatement,\n            setStatement,\n            blockStatement,\n            macroStatement,\n            commentStatement,\n            importStatement,\n            spacelessStatement\n        ]\n    }\n\n    public static var tagPrefix: String = \"{%\"\n    public static var tagSuffix: String = \"%}\"\n\n    public static var ifStatement: Pattern<String, TemplateInterpreter<String>> {\n        return Pattern([Keyword(tagPrefix + \" if\"), Variable<Bool>(\"condition\"), Keyword(tagSuffix), TemplateVariable(\"body\", options: .notTrimmed) {\n            guard let content = $0.value as? String, !content.contains(tagPrefix + \" else \" + tagSuffix) else { return nil }\n            return content\n        }, Keyword(\"{%\"), Keyword(\"endif\"), Keyword(\"%}\")]) {\n            guard let condition = $0.variables[\"condition\"] as? Bool, let body = $0.variables[\"body\"] as? String else { return nil }\n            return condition ? body : \"\"\n        }\n    }\n\n    public static var ifElseStatement: Pattern<String, TemplateInterpreter<String>> {\n        return Pattern([OpenKeyword(tagPrefix + \" if\"), Variable<Bool>(\"condition\"), Keyword(tagSuffix), TemplateVariable(\"body\", options: .notTrimmed) {\n            guard let content = $0.value as? String, !content.contains(tagPrefix + \" else \" + tagSuffix) else { return nil }\n            return content\n        }, Keyword(tagPrefix + \" else \" + tagSuffix), TemplateVariable(\"else\", options: .notTrimmed) {\n            guard let content = $0.value as? String, !content.contains(tagPrefix + \" else \" + tagSuffix) else { return nil }\n            return content\n        }, CloseKeyword(tagPrefix + \" endif \" + tagSuffix)]) {\n            guard let condition = $0.variables[\"condition\"] as? Bool, let body = $0.variables[\"body\"] as? String else { return nil }\n            return condition ? body : $0.variables[\"else\"] as? String\n        }\n    }\n\n    public static var printStatement: Pattern<String, TemplateInterpreter<String>> {\n        return Pattern([OpenKeyword(\"{{\"), Variable<Any>(\"body\"), CloseKeyword(\"}}\")]) {\n            guard let body = $0.variables[\"body\"] else { return nil }\n            return $0.interpreter.typedInterpreter.print(body)\n        }\n    }\n\n    public static var forInStatement: Pattern<String, TemplateInterpreter<String>> {\n        return Pattern([OpenKeyword(tagPrefix + \" for\"),\n                        GenericVariable<String, StringTemplateInterpreter>(\"variable\", options: .notInterpreted), Keyword(\"in\"),\n                        Variable<[Any]>(\"items\"),\n                        Keyword(tagSuffix),\n                        GenericVariable<String, StringTemplateInterpreter>(\"body\", options: [.notInterpreted, .notTrimmed]),\n                        CloseKeyword(tagPrefix + \" endfor \" + tagSuffix)]) {\n            guard let variableName = $0.variables[\"variable\"] as? String,\n                let items = $0.variables[\"items\"] as? [Any],\n                let body = $0.variables[\"body\"] as? String else { return nil }\n            var result = \"\"\n            $0.context.push()\n            $0.context.variables[\"__loop\"] = items\n            for (index, item) in items.enumerated() {\n                $0.context.variables[\"__first\"] = index == items.startIndex\n                $0.context.variables[\"__last\"] = index == items.index(before: items.endIndex)\n                $0.context.variables[variableName] = item\n                result += $0.interpreter.evaluate(body, context: $0.context)\n            }\n            $0.context.pop()\n            return result\n        }\n    }\n\n    public static var setStatement: Pattern<String, TemplateInterpreter<String>> {\n        return Pattern([OpenKeyword(tagPrefix + \" set\"), TemplateVariable(\"variable\"), Keyword(tagSuffix), TemplateVariable(\"body\"), CloseKeyword(tagPrefix + \" endset \" + tagSuffix)]) {\n            guard let variableName = $0.variables[\"variable\"] as? String, let body = $0.variables[\"body\"] as? String else { return nil }\n            $0.interpreter.context.variables[variableName] = body\n            return \"\"\n        }\n    }\n\n    public static var setUsingBodyStatement: Pattern<String, TemplateInterpreter<String>> {\n        return Pattern([OpenKeyword(tagPrefix + \" set\"), TemplateVariable(\"variable\"), Keyword(\"=\"), Variable<Any>(\"value\"), CloseKeyword(tagSuffix)]) {\n            guard let variableName = $0.variables[\"variable\"] as? String else { return nil }\n            $0.interpreter.context.variables[variableName] = $0.variables[\"value\"]\n            return \"\"\n        }\n    }\n\n    public static var blockStatement: Pattern<String, TemplateInterpreter<String>> {\n        return Pattern([OpenKeyword(tagPrefix + \" block\"),\n                        GenericVariable<String, StringTemplateInterpreter>(\"name\", options: .notInterpreted),\n                        Keyword(tagSuffix),\n                        GenericVariable<String, StringTemplateInterpreter>(\"body\", options: .notInterpreted),\n                        CloseKeyword(tagPrefix + \" endblock \" + tagSuffix)]) { match in\n            guard let name = match.variables[\"name\"] as? String, let body = match.variables[\"body\"] as? String else { return nil }\n            let block: BlockRenderer = { context in\n                context.push()\n                context.merge(with: match.context) { existing, _ in existing }\n                context.variables[\"__block\"] = name\n                if let last = context.blocks[name] {\n                    context.blocks[name] = Array(last.dropLast())\n                }\n                let result = match.interpreter.evaluate(body, context: context)\n                context.pop()\n                return result\n            }\n            if let last = match.interpreter.context.blocks[name] {\n                match.interpreter.context.blocks[name] = last + [block]\n                return \"\"\n            } else {\n                match.interpreter.context.blocks[name] = [block]\n                return \"{{{\\(name)}}}\"\n            }\n        }\n    }\n\n    public static var macroStatement: Pattern<String, TemplateInterpreter<String>> {\n        return Pattern([OpenKeyword(tagPrefix + \" macro\"), GenericVariable<String, StringTemplateInterpreter>(\"name\", options: .notInterpreted), Keyword(\"(\"), GenericVariable<[String], StringTemplateInterpreter>(\"arguments\", options: .notInterpreted) {\n                guard let arguments = $0.value as? String else { return nil }\n                return arguments.split(separator: \",\").map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }\n        }, Keyword(\")\"), Keyword(tagSuffix), GenericVariable<String, StringTemplateInterpreter>(\"body\", options: .notInterpreted), CloseKeyword(tagPrefix + \" endmacro \" + tagSuffix)]) {\n            guard let name = $0.variables[\"name\"] as? String,\n                let arguments = $0.variables[\"arguments\"] as? [String],\n                let body = $0.variables[\"body\"] as? String else { return nil }\n            $0.interpreter.context.macros[name] = (arguments: arguments, body: body)\n            return \"\"\n        }\n    }\n\n    public static var commentStatement: Pattern<String, TemplateInterpreter<String>> {\n        return Pattern([OpenKeyword(\"{#\"), GenericVariable<String, StringTemplateInterpreter>(\"body\", options: .notInterpreted), CloseKeyword(\"#}\")]) { _ in \"\" }\n    }\n\n    public static var importStatement: Pattern<String, TemplateInterpreter<String>> {\n        return Pattern([OpenKeyword(tagPrefix + \" import\"), Variable<String>(\"file\"), CloseKeyword(tagSuffix)]) {\n            guard let file = $0.variables[\"file\"] as? String,\n                let url = Bundle.allBundles.compactMap({ $0.url(forResource: file, withExtension: nil) }).first,\n                let expression = try? String(contentsOf: url) else { return nil }\n            return $0.interpreter.evaluate(expression, context: $0.context)\n        }\n    }\n\n    public static var spacelessStatement: Pattern<String, TemplateInterpreter<String>> {\n        return Pattern([OpenKeyword(tagPrefix + \" spaceless \" + tagSuffix), TemplateVariable(\"body\"), CloseKeyword(tagPrefix + \" endspaceless \" + tagSuffix)]) {\n            guard let body = $0.variables[\"body\"] as? String else { return nil }\n            return body.self.components(separatedBy: .whitespacesAndNewlines).filter { !$0.isEmpty }.joined()\n        }\n    }\n}\n\n// swiftlint:disable:next type_body_length\npublic class StandardLibrary {\n    public static var dataTypes: [DataTypeProtocol] {\n        return [\n            stringType,\n            booleanType,\n            arrayType,\n            dictionaryType,\n            dateType,\n            numericType,\n            emptyType\n        ]\n    }\n    public static var functions: [FunctionProtocol] {\n        return [\n            parentheses,\n            macro,\n            blockParent,\n            ternaryOperator,\n\n            rangeFunction,\n            rangeOfStringFunction,\n            rangeBySteps,\n\n            loopIsFirst,\n            loopIsLast,\n            loopIsNotFirst,\n            loopIsNotLast,\n\n            startsWithOperator,\n            endsWithOperator,\n            containsOperator,\n            matchesOperator,\n            capitalise,\n            lowercase,\n            uppercase,\n            lowercaseFirst,\n            uppercaseFirst,\n            trim,\n            urlEncode,\n            urlDecode,\n            escape,\n            nl2br,\n\n            stringConcatenationOperator,\n\n            multiplicationOperator,\n            divisionOperator,\n            additionOperator,\n            subtractionOperator,\n            moduloOperator,\n            powOperator,\n\n            lessThanOperator,\n            lessThanOrEqualsOperator,\n            moreThanOperator,\n            moreThanOrEqualsOperator,\n            equalsOperator,\n            notEqualsOperator,\n\n            stringEqualsOperator,\n            stringNotEqualsOperator,\n\n            inNumericArrayOperator,\n            inStringArrayOperator,\n\n            incrementOperator,\n            decrementOperator,\n\n            negationOperator,\n            notOperator,\n            orOperator,\n            andOperator,\n\n            absoluteValue,\n            defaultValue,\n\n            isEvenOperator,\n            isOddOperator,\n\n            minFunction,\n            maxFunction,\n            sumFunction,\n            sqrtFunction,\n            roundFunction,\n            averageFunction,\n\n            arraySubscript,\n            arrayCountFunction,\n            arrayMapFunction,\n            arrayFilterFunction,\n            arraySortFunction,\n            arrayReverseFunction,\n            arrayMinFunction,\n            arrayMaxFunction,\n            arrayFirstFunction,\n            arrayLastFunction,\n            arrayJoinFunction,\n            arraySplitFunction,\n            arrayMergeFunction,\n            arraySumFunction,\n            arrayAverageFunction,\n\n            dictionarySubscript,\n            dictionaryCountFunction,\n            dictionaryFilterFunction,\n            dictionaryKeys,\n            dictionaryValues,\n\n            dateFactory,\n            dateFormat,\n\n            stringFactory\n        ]\n    }\n\n    // MARK: Types\n\n    public static var numericType: DataType<Double> {\n        let numberLiteral = Literal { Double($0.value) }\n        let piLiteral = Literal(\"pi\", convertsTo: Double.pi)\n        return DataType(type: Double.self, literals: [numberLiteral, piLiteral]) { String(format: \"%g\", $0.value) }\n    }\n\n    public static var stringType: DataType<String> {\n        let singleQuotesLiteral = literal(opening: \"'\", closing: \"'\") { $0.value }\n        return DataType(type: String.self, literals: [singleQuotesLiteral]) { $0.value }\n    }\n\n    public static var dateType: DataType<Date> {\n        let dateFormatter = DateFormatter(with: \"yyyy-MM-dd HH:mm:ss\")\n        let now = Literal<Date>(\"now\", convertsTo: Date())\n        return DataType(type: Date.self, literals: [now]) { dateFormatter.string(from: $0.value) }\n    }\n\n    public static var arrayType: DataType<[CustomStringConvertible]> {\n        let arrayLiteral = literal(opening: \"[\", closing: \"]\") { literal -> [CustomStringConvertible]? in\n            literal.value\n                .split(separator: \",\")\n                .map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }\n                .map { literal.interpreter.evaluate(String($0)) as? CustomStringConvertible ?? String($0) }\n        }\n        return DataType(type: [CustomStringConvertible].self, literals: [arrayLiteral]) { dataType in dataType.value.map { dataType.printer.print($0) }.joined(separator: \",\") }\n    }\n\n    public static var dictionaryType: DataType<[String: CustomStringConvertible?]> {\n        let dictionaryLiteral = literal(opening: \"{\", closing: \"}\") { body -> [String: CustomStringConvertible?]? in\n            let values = body.value\n                .split(separator: \",\")\n                .map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }\n            let parsedValues : [(key: String, value: CustomStringConvertible?)] = values\n                .map { $0.split(separator: \":\").map { body.interpreter.evaluate(String($0)) } }\n                .compactMap {\n                    guard let first = $0.first, let key = first as? String, let value = $0.last else { return nil }\n                    return (key: key, value: value as? CustomStringConvertible)\n                }\n            return Dictionary(grouping: parsedValues) { $0.key }.mapValues { $0.first?.value }\n        }\n        return DataType(type: [String: CustomStringConvertible?].self, literals: [dictionaryLiteral]) { dataType in\n            let items = dataType.value.map { key, value in\n                if let value = value {\n                    return \"\\(dataType.printer.print(key)): \\(dataType.printer.print(value))\"\n                } else {\n                    return \"\\(dataType.printer.print(key)): nil\"\n                }\n            }.sorted().joined(separator: \", \")\n            return \"[\\(items)]\"\n        }\n    }\n\n    public static var booleanType: DataType<Bool> {\n        let trueLiteral = Literal(\"true\", convertsTo: true)\n        let falseLiteral = Literal(\"false\", convertsTo: false)\n        return DataType(type: Bool.self, literals: [trueLiteral, falseLiteral]) { $0.value ? \"true\" : \"false\" }\n    }\n\n    public static var emptyType: DataType<Any?> {\n        let nullLiteral = Literal<Any?>(\"null\", convertsTo: nil)\n        let nilLiteral = Literal<Any?>(\"nil\", convertsTo: nil)\n        return DataType<Any?>(type: Any?.self, literals: [nullLiteral, nilLiteral]) { _ in \"null\" }\n    }\n\n    // MARK: Functions\n\n    public static var parentheses: Function<Double> {\n        return Function([OpenKeyword(\"(\"), Variable<Double>(\"body\"), CloseKeyword(\")\")]) { $0.variables[\"body\"] as? Double }\n    }\n\n    public static var macro: Function<Any> {\n        return Function([Variable<String>(\"name\", options: .notInterpreted) {\n            guard let value = $0.value as? String else { return nil }\n            return $0.interpreter.context.macros.keys.contains(value) ? value : nil\n        }, Keyword(\"(\"), Variable<String>(\"arguments\", options: .notInterpreted), Keyword(\")\")]) { match in\n            guard let arguments = match.variables[\"arguments\"] as? String,\n                let name = match.variables[\"name\"] as? String,\n                let macro = match.interpreter.context.macros[name.trimmingCharacters(in: .whitespacesAndNewlines)] else { return nil }\n            let interpretedArguments = arguments.split(separator: \",\").compactMap { match.interpreter.evaluate(String($0).trimmingCharacters(in: .whitespacesAndNewlines)) }\n            match.context.push()\n            for (key, value) in zip(macro.arguments, interpretedArguments) {\n                match.context.variables[key] = value\n            }\n            let result = match.interpreter.evaluate(macro.body, context: match.context)\n            match.context.pop()\n            return result\n        }\n    }\n\n    public static var blockParent: Function<Any> {\n        return Function([Keyword(\"parent\"), Keyword(\"(\"), Variable<String>(\"arguments\", options: .notInterpreted), Keyword(\")\")]) {\n            guard let arguments = $0.variables[\"arguments\"] as? String else { return nil }\n            var interpretedArguments: [String: Any] = [:]\n            for argument in arguments.split(separator: \",\") {\n                let parts = String(argument).trimmingCharacters(in: .whitespacesAndNewlines).split(separator: \"=\")\n                if let key = parts.first, let value = parts.last {\n                    interpretedArguments[String(key)] = $0.interpreter.evaluate(String(value))\n                }\n            }\n            guard let name = $0.context.variables[\"__block\"] as? String, let block = $0.context.blocks[name]?.last else { return nil }\n            $0.context.push()\n            $0.context.variables.merge(interpretedArguments) { _, new in new }\n            let result = block($0.context)\n            $0.context.pop()\n            return result\n        }\n    }\n\n    public static var ternaryOperator: Function<Any> {\n        return Function([Variable<Bool>(\"condition\"), Keyword(\"?\"), Variable<Any>(\"body\"), Keyword(\": \"), Variable<Any>(\"else\")]) {\n            guard let condition = $0.variables[\"condition\"] as? Bool else { return nil }\n            return condition ? $0.variables[\"body\"] : $0.variables[\"else\"]\n        }\n    }\n\n    public static var rangeFunction: Function<[Double]> {\n        return infixOperator(\"...\") { (lhs: Double, rhs: Double) in\n            CountableClosedRange(uncheckedBounds: (lower: Int(lhs), upper: Int(rhs))).map { Double($0) }\n        }\n    }\n\n    public static var rangeOfStringFunction: Function<[String]> {\n        return infixOperator(\"...\") { (lhs: String, rhs: String) in\n            CountableClosedRange(uncheckedBounds: (lower: Character(lhs), upper: Character(rhs))).map { String($0) }\n        }\n    }\n\n    public static var startsWithOperator: Function<Bool> {\n        return infixOperator(\"starts with\") { (lhs: String, rhs: String) in lhs.hasPrefix(rhs) }\n    }\n\n    public static var endsWithOperator: Function<Bool> {\n        return infixOperator(\"ends with\") { (lhs: String, rhs: String) in lhs.hasSuffix(rhs) }\n    }\n\n    public static var containsOperator: Function<Bool> {\n        return infixOperator(\"contains\") { (lhs: String, rhs: String) in lhs.contains(rhs) }\n    }\n\n    public static var matchesOperator: Function<Bool> {\n        return infixOperator(\"matches\") { (lhs: String, rhs: String) in\n            if let regex = try? NSRegularExpression(pattern: rhs) {\n                let matches = regex.numberOfMatches(in: lhs, range: NSRange(lhs.startIndex..., in: lhs))\n                return matches > 0\n            }\n            return false\n        }\n    }\n\n    public static var capitalise: Function<String> {\n        return objectFunction(\"capitalise\") { (value: String) -> String? in value.capitalized }\n    }\n\n    public static var lowercase: Function<String> {\n        return objectFunction(\"lower\") { (value: String) -> String? in value.lowercased() }\n    }\n\n    public static var uppercase: Function<String> {\n        return objectFunction(\"upper\") { (value: String) -> String? in value.uppercased() }\n    }\n\n    public static var lowercaseFirst: Function<String> {\n        return objectFunction(\"lowerFirst\") { (value: String) -> String? in\n            guard let first = value.first else { return nil }\n            return String(first).lowercased() + value[value.index(value.startIndex, offsetBy: 1)...]\n        }\n    }\n\n    public static var uppercaseFirst: Function<String> {\n        return objectFunction(\"upperFirst\") { (value: String) -> String? in\n            guard let first = value.first else { return nil }\n            return String(first).uppercased() + value[value.index(value.startIndex, offsetBy: 1)...]\n        }\n    }\n\n    public static var trim: Function<String> {\n        return objectFunction(\"trim\") { (value: String) -> String? in value.trimmingCharacters(in: .whitespacesAndNewlines) }\n    }\n\n    public static var urlEncode: Function<String> {\n        return objectFunction(\"urlEncode\") { (value: String) -> String? in value.addingPercentEncoding(withAllowedCharacters: .alphanumerics) }\n    }\n\n    public static var urlDecode: Function<String> {\n        return objectFunction(\"urlDecode\") { (value: String) -> String? in value.removingPercentEncoding }\n    }\n\n    public static var escape: Function<String> {\n        return objectFunction(\"escape\") { (value: String) -> String? in value.html }\n    }\n\n    public static var nl2br: Function<String> {\n        return objectFunction(\"nl2br\") { (value: String) -> String? in value\n            .replacingOccurrences(of: \"\\r\\n\", with: \"<br/>\")\n            .replacingOccurrences(of: \"\\n\", with: \"<br/>\")\n        }\n    }\n\n    public static var stringConcatenationOperator: Function<String> {\n        return infixOperator(\"+\") { (lhs: String, rhs: String) in lhs + rhs }\n    }\n\n    public static var additionOperator: Function<Double> {\n        return infixOperator(\"+\") { (lhs: Double, rhs: Double) in lhs + rhs }\n    }\n\n    public static var subtractionOperator: Function<Double> {\n        return infixOperator(\"-\") { (lhs: Double, rhs: Double) in lhs - rhs }\n    }\n\n    public static var multiplicationOperator: Function<Double> {\n        return infixOperator(\"*\") { (lhs: Double, rhs: Double) in lhs * rhs }\n    }\n\n    public static var divisionOperator: Function<Double> {\n        return infixOperator(\"/\") { (lhs: Double, rhs: Double) in lhs / rhs }\n    }\n\n    public static var moduloOperator: Function<Double> {\n        return infixOperator(\"%\") { (lhs: Double, rhs: Double) in Double(Int(lhs) % Int(rhs)) }\n    }\n\n    public static var powOperator: Function<Double> {\n        return infixOperator(\"**\") { (lhs: Double, rhs: Double) in pow(lhs, rhs) }\n    }\n\n    public static var lessThanOperator: Function<Bool> {\n        return infixOperator(\"<\") { (lhs: Double, rhs: Double) in lhs < rhs }\n    }\n\n    public static var moreThanOperator: Function<Bool> {\n        return infixOperator(\"<=\") { (lhs: Double, rhs: Double) in lhs <= rhs }\n    }\n\n    public static var lessThanOrEqualsOperator: Function<Bool> {\n        return infixOperator(\">\") { (lhs: Double, rhs: Double) in lhs > rhs }\n    }\n\n    public static var moreThanOrEqualsOperator: Function<Bool> {\n        return infixOperator(\">=\") { (lhs: Double, rhs: Double) in lhs >= rhs }\n    }\n\n    public static var equalsOperator: Function<Bool> {\n        return infixOperator(\"==\") { (lhs: Double, rhs: Double) in lhs == rhs }\n    }\n\n    public static var notEqualsOperator: Function<Bool> {\n        return infixOperator(\"!=\") { (lhs: Double, rhs: Double) in lhs != rhs }\n    }\n\n    public static var stringEqualsOperator: Function<Bool> {\n        return infixOperator(\"==\") { (lhs: String, rhs: String) in lhs == rhs }\n    }\n\n    public static var stringNotEqualsOperator: Function<Bool> {\n        return infixOperator(\"!=\") { (lhs: String, rhs: String) in lhs != rhs }\n    }\n\n    public static var inStringArrayOperator: Function<Bool> {\n        return infixOperator(\"in\") { (lhs: String, rhs: [String]) in rhs.contains(lhs) }\n    }\n\n    public static var inNumericArrayOperator: Function<Bool> {\n        return infixOperator(\"in\") { (lhs: Double, rhs: [Double]) in rhs.contains(lhs) }\n    }\n\n    public static var negationOperator: Function<Bool> {\n        return prefixOperator(\"!\") { (expression: Bool) in !expression }\n    }\n\n    public static var notOperator: Function<Bool> {\n        return prefixOperator(\"not\") { (expression: Bool) in !expression }\n    }\n\n    public static var andOperator: Function<Bool> {\n        return infixOperator(\"and\") { (lhs: Bool, rhs: Bool) in lhs && rhs }\n    }\n\n    public static var orOperator: Function<Bool> {\n        return infixOperator(\"or\") { (lhs: Bool, rhs: Bool) in lhs || rhs }\n    }\n\n    public static var absoluteValue: Function<Double> {\n        return objectFunction(\"abs\") { (value: Double) -> Double? in abs(value) }\n    }\n\n    public static var defaultValue: Function<Any> {\n        return Function([Variable<Any>(\"lhs\"), Keyword(\".\"), Variable<String>(\"rhs\", options: .notInterpreted) {\n            guard let value = $0.value as? String, value == \"default\" else { return nil }\n            return value\n        }, Keyword(\"(\"), Variable<Any>(\"fallback\"), Keyword(\")\")], options: .backwardMatch) {\n            guard let value = $0.variables[\"lhs\"], $0.variables[\"rhs\"] != nil else { return nil }\n            return isNilOrWrappedNil(value: value) ? $0.variables[\"fallback\"] : value\n        }\n    }\n\n    public static var incrementOperator: Function<Double> {\n        return suffixOperator(\"++\") { (expression: Double) in expression + 1 }\n    }\n\n    public static var decrementOperator: Function<Double> {\n        return suffixOperator(\"--\") { (expression: Double) in expression - 1 }\n    }\n\n    public static var isEvenOperator: Function<Bool> {\n        return suffixOperator(\"is even\") { (expression: Double) in Int(expression) % 2 == 0 }\n    }\n\n    public static var isOddOperator: Function<Bool> {\n        return suffixOperator(\"is odd\") { (expression: Double) in abs(Int(expression) % 2) == 1 }\n    }\n\n    public static var minFunction: Function<Double> {\n        return function(\"min\") { (arguments: [Any]) -> Double? in\n            guard let arguments = arguments as? [Double] else { return nil }\n            return arguments.min()\n        }\n    }\n\n    public static var maxFunction: Function<Double> {\n        return function(\"max\") { (arguments: [Any]) -> Double? in\n            guard let arguments = arguments as? [Double] else { return nil }\n            return arguments.max()\n        }\n    }\n\n    public static var arraySortFunction: Function<[Double]> {\n        return objectFunction(\"sort\") { (object: [Double]) -> [Double]? in object.sorted() }\n    }\n\n    public static var arrayReverseFunction: Function<[Double]> {\n        return objectFunction(\"reverse\") { (object: [Double]) -> [Double]? in object.reversed() }\n    }\n\n    public static var arrayMinFunction: Function<Double> {\n        return objectFunction(\"min\") { (object: [Double]) -> Double? in object.min() }\n    }\n\n    public static var arrayMaxFunction: Function<Double> {\n        return objectFunction(\"max\") { (object: [Double]) -> Double? in object.max() }\n    }\n\n    public static var arrayFirstFunction: Function<Double> {\n        return objectFunction(\"first\") { (object: [Double]) -> Double? in object.first }\n    }\n\n    public static var arrayLastFunction: Function<Double> {\n        return objectFunction(\"last\") { (object: [Double]) -> Double? in object.last }\n    }\n\n    public static var arrayJoinFunction: Function<String> {\n        return objectFunctionWithParameters(\"join\") { (object: [String], arguments: [Any]) -> String? in\n            guard let separator = arguments.first as? String else { return nil }\n            return object.joined(separator: separator)\n        }\n    }\n\n    public static var arraySplitFunction: Function<[String]> {\n        return Function([Variable<String>(\"lhs\"), Keyword(\".\"), Variable<String>(\"rhs\", options: .notInterpreted) {\n            guard let value = $0.value as? String, value == \"split\" else { return nil }\n            return value\n        }, Keyword(\"(\"), Variable<String>(\"separator\"), Keyword(\")\")]) {\n            guard let object = $0.variables[\"lhs\"] as? String, $0.variables[\"rhs\"] != nil, let separator = $0.variables[\"separator\"] as? String else { return nil }\n            return object.split(separator: Character(separator)).map { String($0) }\n        }\n    }\n\n    public static var arrayMergeFunction: Function<[Any]> {\n        return Function([Variable<[Any]>(\"lhs\"), Keyword(\".\"), Variable<String>(\"rhs\", options: .notInterpreted) {\n            guard let value = $0.value as? String, value == \"merge\" else { return nil }\n            return value\n        }, Keyword(\"(\"), Variable<[Any]>(\"other\"), Keyword(\")\")]) {\n            guard let object = $0.variables[\"lhs\"] as? [Any], $0.variables[\"rhs\"] != nil, let other = $0.variables[\"other\"] as? [Any] else { return nil }\n            return object + other\n        }\n    }\n\n    public static var arraySumFunction: Function<Double> {\n        return objectFunction(\"sum\") { (object: [Double]) -> Double? in object.reduce(0, +) }\n    }\n\n    public static var arrayAverageFunction: Function<Double> {\n        return objectFunction(\"avg\") { (object: [Double]) -> Double? in object.reduce(0, +) / Double(object.count) }\n    }\n\n    public static var arrayCountFunction: Function<Double> {\n        return objectFunction(\"count\") { (object: [Double]) -> Double? in Double(object.count) }\n    }\n\n    public static var dictionaryCountFunction: Function<Double> {\n        return objectFunction(\"count\") { (object: [String: Any]) -> Double? in Double(object.count) }\n    }\n\n    public static var arrayMapFunction: Function<[Any]> {\n        return Function([Variable<[Any]>(\"lhs\"), Keyword(\".\"), Variable<String>(\"rhs\", options: .notInterpreted) {\n            guard let value = $0.value as? String, value == \"map\" else { return nil }\n            return value\n        }, Keyword(\"(\"), Variable<String>(\"variable\", options: .notInterpreted), Keyword(\"=>\"), Variable<Any>(\"body\", options: .notInterpreted), Keyword(\")\")]) { match in\n            guard let object = match.variables[\"lhs\"] as? [Any], match.variables[\"rhs\"] != nil,\n                let variable = match.variables[\"variable\"] as? String,\n                let body = match.variables[\"body\"] as? String else { return nil }\n            match.context.push()\n            let result: [Any] = object.compactMap { item in\n                match.context.variables[variable] = item\n                return match.interpreter.evaluate(body, context: match.context)\n            }\n            match.context.pop()\n            return result\n        }\n    }\n\n    public static var arrayFilterFunction: Function<[Any]> {\n        return Function([Variable<[Any]>(\"lhs\"), Keyword(\".\"), Variable<String>(\"rhs\", options: .notInterpreted) {\n            guard let value = $0.value as? String, value == \"filter\" else { return nil }\n            return value\n        }, Keyword(\"(\"), Variable<String>(\"variable\", options: .notInterpreted), Keyword(\"=>\"), Variable<Any>(\"body\", options: .notInterpreted), Keyword(\")\")]) { match in\n            guard let object = match.variables[\"lhs\"] as? [Any], match.variables[\"rhs\"] != nil,\n                let variable = match.variables[\"variable\"] as? String,\n                let body = match.variables[\"body\"] as? String else { return nil }\n            match.context.push()\n            let result: [Any] = object.filter { item in\n                match.context.variables[variable] = item\n                if let result = match.interpreter.evaluate(body, context: match.context) as? Bool {\n                    return result\n                }\n                return false\n            }\n            match.context.pop()\n            return result\n        }\n    }\n\n    public static var dictionaryFilterFunction: Function<[String: Any]> {\n        return Function([Variable<[String: Any]>(\"lhs\"), Keyword(\".\"), Variable<String>(\"rhs\", options: .notInterpreted) {\n            guard let value = $0.value as? String, value == \"filter\" else { return nil }\n            return value\n        }, Keyword(\"(\"), Variable<String>(\"key\", options: .notInterpreted), Keyword(\",\"), Variable<String>(\"value\", options: .notInterpreted), Keyword(\"=>\"), Variable<Any>(\"body\", options: .notInterpreted), Keyword(\")\")]) { match in\n                guard let object = match.variables[\"lhs\"] as? [String: Any], match.variables[\"rhs\"] != nil,\n                    let keyVariable = match.variables[\"key\"] as? String,\n                    let valueVariable = match.variables[\"value\"] as? String,\n                    let body = match.variables[\"body\"] as? String else { return nil }\n                match.context.push()\n                let result: [String: Any] = object.filter { key, value in\n                    match.context.variables[keyVariable] = key\n                    match.context.variables[valueVariable] = value\n                    if let result = match.interpreter.evaluate(body, context: match.context) as? Bool {\n                        return result\n                    }\n                    return false\n                }\n                match.context.pop()\n                return result\n        }\n    }\n\n    public static var sumFunction: Function<Double> {\n        return function(\"sum\") { (arguments: [Any]) -> Double? in\n            guard let arguments = arguments as? [Double] else { return nil }\n            return arguments.reduce(0, +)\n        }\n    }\n\n    public static var averageFunction: Function<Double> {\n        return function(\"avg\") { (arguments: [Any]) -> Double? in\n            guard let arguments = arguments as? [Double] else { return nil }\n            return arguments.reduce(0, +) / Double(arguments.count)\n        }\n    }\n\n    public static var sqrtFunction: Function<Double> {\n        return function(\"sqrt\") { (arguments: [Any]) -> Double? in\n            guard let value = arguments.first as? Double else { return nil }\n            return sqrt(value)\n        }\n    }\n\n    public static var roundFunction: Function<Double> {\n        return function(\"round\") { (arguments: [Any]) -> Double? in\n            guard let value = arguments.first as? Double else { return nil }\n            return round(value)\n        }\n    }\n\n    public static var dateFactory: Function<Date?> {\n        return function(\"Date\") { (arguments: [Any]) -> Date? in\n            guard let arguments = arguments as? [Double], arguments.count >= 3 else { return nil }\n            var components = DateComponents()\n            components.calendar = Calendar(identifier: .gregorian)\n            components.year = Int(arguments[0])\n            components.month = Int(arguments[1])\n            components.day = Int(arguments[2])\n            components.hour = arguments.count > 3 ? Int(arguments[3]) : 0\n            components.minute = arguments.count > 4 ? Int(arguments[4]) : 0\n            components.second = arguments.count > 5 ? Int(arguments[5]) : 0\n            return components.date\n        }\n    }\n\n    public static var stringFactory: Function<String?> {\n        return function(\"String\") { (arguments: [Any]) -> String? in\n            guard let argument = arguments.first as? Double else { return nil }\n            return String(format: \"%g\", argument)\n        }\n    }\n\n    public static var rangeBySteps: Function<[Double]> {\n        return functionWithNamedParameters(\"range\") { (arguments: [String: Any]) -> [Double]? in\n            guard let start = arguments[\"start\"] as? Double, let end = arguments[\"end\"] as? Double, let step = arguments[\"step\"] as? Double else { return nil }\n            var result = [start]\n            var value = start\n            while value <= end - step {\n                value += step\n                result.append(value)\n            }\n            return result\n        }\n    }\n\n    public static var loopIsFirst: Function<Bool?> {\n        return Function([Variable<Any>(\"value\"), Keyword(\"is first\")]) {\n            $0.context.variables[\"__first\"] as? Bool\n        }\n    }\n\n    public static var loopIsLast: Function<Bool?> {\n        return Function([Variable<Any>(\"value\"), Keyword(\"is last\")]) {\n            $0.context.variables[\"__last\"] as? Bool\n        }\n    }\n\n    public static var loopIsNotFirst: Function<Bool?> {\n        return Function([Variable<Any>(\"value\"), Keyword(\"is not first\")]) {\n            guard let isFirst = $0.context.variables[\"__first\"] as? Bool else { return nil }\n            return !isFirst\n        }\n    }\n\n    public static var loopIsNotLast: Function<Bool?> {\n        return Function([Variable<Any>(\"value\"), Keyword(\"is not last\")]) {\n            guard let isLast = $0.context.variables[\"__last\"] as? Bool else { return nil }\n            return !isLast\n        }\n    }\n\n    public static var dateFormat: Function<String> {\n        return objectFunctionWithParameters(\"format\") { (object: Date, arguments: [Any]) -> String? in\n            guard let format = arguments.first as? String else { return nil }\n            let dateFormatter = DateFormatter(with: format)\n            return dateFormatter.string(from: object)\n        }\n    }\n\n    public static var arraySubscript: Function<Any?> {\n        return Function([Variable<[Any]>(\"array\"), Keyword(\".\"), Variable<Double>(\"index\")]) {\n            guard let array = $0.variables[\"array\"] as? [Any], let index = $0.variables[\"index\"] as? Double, index > 0, Int(index) < array.count else { return nil }\n            return array[Int(index)]\n        }\n    }\n\n    public static var dictionarySubscript: Function<Any?> {\n        return Function([Variable<[String: Any]>(\"dictionary\"), Keyword(\".\"), Variable<String>(\"key\", options: .notInterpreted)]) {\n            guard let dictionary = $0.variables[\"dictionary\"] as? [String: Any], let key = $0.variables[\"key\"] as? String else { return nil }\n            return dictionary[key]\n        }\n    }\n\n    public static var dictionaryKeys: Function<[String]> {\n        return objectFunction(\"keys\") { (object: [String: Any?]) -> [String] in\n            object.keys.sorted()\n        }\n    }\n\n    public static var dictionaryValues: Function<[Any?]> {\n        return objectFunction(\"values\") { (object: [String: Any?]) -> [Any?] in\n            if let values = object as? [String: Double] {\n                return values.values.sorted()\n            }\n            if let values = object as? [String: String] {\n                return values.values.sorted()\n            }\n            return Array(object.values)\n        }\n    }\n\n    public static var methodCallWithIntResult: Function<Double> {\n        return Function([Variable<Any>(\"lhs\"), Keyword(\".\"), Variable<String>(\"rhs\", options: .notInterpreted)]) {\n            if let lhs = $0.variables[\"lhs\"] as? NSObjectProtocol,\n                let rhs = $0.variables[\"rhs\"] as? String,\n                let result = lhs.perform(Selector(rhs)) {\n                return Double(Int(bitPattern: result.toOpaque()))\n            }\n            return nil\n        }\n    }\n\n    // MARK: Literal helpers\n\n    public static func literal<T>(opening: String, closing: String, convert: @escaping (_ literal: LiteralBody) -> T?) -> Literal<T> {\n        return Literal { literal -> T? in\n            guard literal.value.hasPrefix(opening), literal.value.hasSuffix(closing), literal.value.count > 1 else { return nil }\n            let inputWithoutOpening = String(literal.value.suffix(from: literal.value.index(literal.value.startIndex, offsetBy: opening.count)))\n            let inputWithoutSides = String(inputWithoutOpening.prefix(upTo: inputWithoutOpening.index(inputWithoutOpening.endIndex, offsetBy: -closing.count)))\n            guard !inputWithoutSides.contains(opening) && !inputWithoutSides.contains(closing) else { return nil }\n            return convert(LiteralBody(value: inputWithoutSides, interpreter: literal.interpreter))\n        }\n    }\n\n    // MARK: Operator helpers\n\n    public static func infixOperator<A, B, T>(_ symbol: String, body: @escaping (A, B) -> T) -> Function<T> {\n        return Function([Variable<A>(\"lhs\"), Keyword(symbol), Variable<B>(\"rhs\")], options: .backwardMatch) {\n            guard let lhs = $0.variables[\"lhs\"] as? A, let rhs = $0.variables[\"rhs\"] as? B else { return nil }\n            return body(lhs, rhs)\n        }\n    }\n\n    public static func prefixOperator<A, T>(_ symbol: String, body: @escaping (A) -> T) -> Function<T> {\n        return Function([Keyword(symbol), Variable<A>(\"value\")]) {\n            guard let value = $0.variables[\"value\"] as? A else { return nil }\n            return body(value)\n        }\n    }\n\n    public static func suffixOperator<A, T>(_ symbol: String, body: @escaping (A) -> T) -> Function<T> {\n        return Function([Variable<A>(\"value\"), Keyword(symbol)]) {\n            guard let value = $0.variables[\"value\"] as? A else { return nil }\n            return body(value)\n        }\n    }\n\n    // MARK: Function helpers\n\n    public static func function<T>(_ name: String, body: @escaping ([Any]) -> T?) -> Function<T> {\n        return Function([Keyword(name), OpenKeyword(\"(\"), Variable<String>(\"arguments\", options: .notInterpreted), CloseKeyword(\")\")]) { match in\n            guard let arguments = match.variables[\"arguments\"] as? String else { return nil }\n            let interpretedArguments = arguments.split(separator: \",\").compactMap { match.interpreter.evaluate(String($0).trimmingCharacters(in: .whitespacesAndNewlines)) }\n            return body(interpretedArguments)\n        }\n    }\n\n    public static func functionWithNamedParameters<T>(_ name: String, body: @escaping ([String: Any]) -> T?) -> Function<T> {\n        return Function([Keyword(name), OpenKeyword(\"(\"), Variable<String>(\"arguments\", options: .notInterpreted), CloseKeyword(\")\")]) {\n            guard let arguments = $0.variables[\"arguments\"] as? String else { return nil }\n            var interpretedArguments: [String: Any] = [:]\n            for argument in arguments.split(separator: \",\") {\n                let parts = String(argument).trimmingCharacters(in: .whitespacesAndNewlines).split(separator: \"=\")\n                if let key = parts.first, let value = parts.last {\n                    interpretedArguments[String(key)] = $0.interpreter.evaluate(String(value))\n                }\n            }\n            return body(interpretedArguments)\n        }\n    }\n\n    public static func objectFunction<O, T>(_ name: String, body: @escaping (O) -> T?) -> Function<T> {\n        return Function([Variable<O>(\"lhs\"), Keyword(\".\"), Variable<String>(\"rhs\", options: .notInterpreted) {\n            guard let value = $0.value as? String, value == name else { return nil }\n            return value\n        }], options: .backwardMatch) {\n            guard let object = $0.variables[\"lhs\"] as? O, $0.variables[\"rhs\"] != nil else { return nil }\n            return body(object)\n        }\n    }\n\n    public static func objectFunctionWithParameters<O, T>(_ name: String, body: @escaping (O, [Any]) -> T?) -> Function<T> {\n        return Function([Variable<O>(\"lhs\"), Keyword(\".\"), Variable<String>(\"rhs\", options: .notInterpreted) {\n            guard let value = $0.value as? String, value == name else { return nil }\n            return value\n        }, Keyword(\"(\"), Variable<String>(\"arguments\", options: .notInterpreted), Keyword(\")\")]) { match in\n            guard let object = match.variables[\"lhs\"] as? O, match.variables[\"rhs\"] != nil, let arguments = match.variables[\"arguments\"] as? String else { return nil }\n            let interpretedArguments = arguments.split(separator: \",\").compactMap { match.interpreter.evaluate(String($0).trimmingCharacters(in: .whitespacesAndNewlines)) }\n            return body(object, interpretedArguments)\n        }\n    }\n\n    public static func objectFunctionWithNamedParameters<O, T>(_ name: String, body: @escaping (O, [String: Any]) -> T?) -> Function<T> {\n        return Function([Variable<O>(\"lhs\"), Keyword(\".\"), Variable<String>(\"rhs\", options: .notInterpreted) {\n            guard let value = $0.value as? String, value == name else { return nil }\n            return value\n        }, OpenKeyword(\"(\"), Variable<String>(\"arguments\", options: .notInterpreted), CloseKeyword(\")\")]) { match in\n            guard let object = match.variables[\"lhs\"] as? O, match.variables[\"rhs\"] != nil, let arguments = match.variables[\"arguments\"] as? String else { return nil }\n            var interpretedArguments: [String: Any] = [:]\n            for argument in arguments.split(separator: \",\") {\n                let parts = String(argument).trimmingCharacters(in: .whitespacesAndNewlines).split(separator: \"=\")\n                if let key = parts.first, let value = parts.last {\n                    interpretedArguments[String(key)] = match.interpreter.evaluate(String(value))\n                }\n            }\n            return body(object, interpretedArguments)\n        }\n    }\n}\n\npublic extension DateFormatter {\n    convenience init(with format: String) {\n        self.init()\n        self.calendar = Calendar(identifier: .gregorian)\n        self.dateFormat = format\n    }\n}\n\nextension Character: Strideable {\n    public typealias Stride = Int\n\n    var value: UInt32 {\n        return unicodeScalars.first?.value ?? 0\n    }\n\n    public func distance(to other: Character) -> Int {\n        return Int(other.value) - Int(self.value)\n    }\n\n    public func advanced(by offset: Int) -> Character {\n        let advancedValue = offset + Int(self.value)\n        guard let advancedScalar = UnicodeScalar(advancedValue) else {\n            fatalError(\"\\(String(advancedValue, radix: 16)) does not represent a valid unicode scalar value.\")\n        }\n        return Character(advancedScalar)\n    }\n}\n\nextension String {\n    static let enc: [Character: String] =\n        [\" \": \"&emsp;\", \" \": \"&ensp;\", \" \": \"&nbsp;\", \" \": \"&thinsp;\", \"‾\": \"&oline;\", \"–\": \"&ndash;\", \"—\": \"&mdash;\",\n         \"¡\": \"&iexcl;\", \"¿\": \"&iquest;\", \"…\": \"&hellip;\", \"·\": \"&middot;\", \"'\": \"&apos;\", \"‘\": \"&lsquo;\", \"’\": \"&rsquo;\",\n         \"‚\": \"&sbquo;\", \"‹\": \"&lsaquo;\", \"›\": \"&rsaquo;\", \"‎\": \"&lrm;\", \"‏\": \"&rlm;\", \"­\": \"&shy;\", \"‍\": \"&zwj;\", \"‌\": \"&zwnj;\",\n         \"\\\"\": \"&quot;\", \"“\": \"&ldquo;\", \"”\": \"&rdquo;\", \"„\": \"&bdquo;\", \"«\": \"&laquo;\", \"»\": \"&raquo;\", \"⌈\": \"&lceil;\",\n         \"⌉\": \"&rceil;\", \"⌊\": \"&lfloor;\", \"⌋\": \"&rfloor;\", \"〈\": \"&lang;\", \"〉\": \"&rang;\", \"§\": \"&sect;\", \"¶\": \"&para;\",\n         \"&\": \"&amp;\", \"‰\": \"&permil;\", \"†\": \"&dagger;\", \"‡\": \"&Dagger;\", \"•\": \"&bull;\", \"′\": \"&prime;\", \"″\": \"&Prime;\",\n         \"´\": \"&acute;\", \"˜\": \"&tilde;\", \"¯\": \"&macr;\", \"¨\": \"&uml;\", \"¸\": \"&cedil;\", \"ˆ\": \"&circ;\", \"°\": \"&deg;\",\n         \"©\": \"&copy;\", \"®\": \"&reg;\", \"℘\": \"&weierp;\", \"←\": \"&larr;\", \"→\": \"&rarr;\", \"↑\": \"&uarr;\", \"↓\": \"&darr;\",\n         \"↔\": \"&harr;\", \"↵\": \"&crarr;\", \"⇐\": \"&lArr;\", \"⇑\": \"&uArr;\", \"⇒\": \"&rArr;\", \"⇓\": \"&dArr;\", \"⇔\": \"&hArr;\",\n         \"∀\": \"&forall;\", \"∂\": \"&part;\", \"∃\": \"&exist;\", \"∅\": \"&empty;\", \"∇\": \"&nabla;\", \"∈\": \"&isin;\", \"∉\": \"&notin;\",\n         \"∋\": \"&ni;\", \"∏\": \"&prod;\", \"∑\": \"&sum;\", \"±\": \"&plusmn;\", \"÷\": \"&divide;\", \"×\": \"&times;\", \"<\": \"&lt;\", \"≠\": \"&ne;\",\n         \">\": \"&gt;\", \"¬\": \"&not;\", \"¦\": \"&brvbar;\", \"−\": \"&minus;\", \"⁄\": \"&frasl;\", \"∗\": \"&lowast;\", \"√\": \"&radic;\",\n         \"∝\": \"&prop;\", \"∞\": \"&infin;\", \"∠\": \"&ang;\", \"∧\": \"&and;\", \"∨\": \"&or;\", \"∩\": \"&cap;\", \"∪\": \"&cup;\", \"∫\": \"&int;\",\n         \"∴\": \"&there4;\", \"∼\": \"&sim;\", \"≅\": \"&cong;\", \"≈\": \"&asymp;\", \"≡\": \"&equiv;\", \"≤\": \"&le;\", \"≥\": \"&ge;\", \"⊄\": \"&nsub;\",\n         \"⊂\": \"&sub;\", \"⊃\": \"&sup;\", \"⊆\": \"&sube;\", \"⊇\": \"&supe;\", \"⊕\": \"&oplus;\", \"⊗\": \"&otimes;\", \"⊥\": \"&perp;\",\n         \"⋅\": \"&sdot;\", \"◊\": \"&loz;\", \"♠\": \"&spades;\", \"♣\": \"&clubs;\", \"♥\": \"&hearts;\", \"♦\": \"&diams;\", \"¤\": \"&curren;\",\n         \"¢\": \"&cent;\", \"£\": \"&pound;\", \"¥\": \"&yen;\", \"€\": \"&euro;\", \"¹\": \"&sup1;\", \"½\": \"&frac12;\", \"¼\": \"&frac14;\",\n         \"²\": \"&sup2;\", \"³\": \"&sup3;\", \"¾\": \"&frac34;\", \"á\": \"&aacute;\", \"Á\": \"&Aacute;\", \"â\": \"&acirc;\", \"Â\": \"&Acirc;\",\n         \"à\": \"&agrave;\", \"À\": \"&Agrave;\", \"å\": \"&aring;\", \"Å\": \"&Aring;\", \"ã\": \"&atilde;\", \"Ã\": \"&Atilde;\", \"ä\": \"&auml;\",\n         \"Ä\": \"&Auml;\", \"ª\": \"&ordf;\", \"æ\": \"&aelig;\", \"Æ\": \"&AElig;\", \"ç\": \"&ccedil;\", \"Ç\": \"&Ccedil;\", \"ð\": \"&eth;\",\n         \"Ð\": \"&ETH;\", \"é\": \"&eacute;\", \"É\": \"&Eacute;\", \"ê\": \"&ecirc;\", \"Ê\": \"&Ecirc;\", \"è\": \"&egrave;\", \"È\": \"&Egrave;\",\n         \"ë\": \"&euml;\", \"Ë\": \"&Euml;\", \"ƒ\": \"&fnof;\", \"í\": \"&iacute;\", \"Í\": \"&Iacute;\", \"î\": \"&icirc;\", \"Î\": \"&Icirc;\",\n         \"ì\": \"&igrave;\", \"Ì\": \"&Igrave;\", \"ℑ\": \"&image;\", \"ï\": \"&iuml;\", \"Ï\": \"&Iuml;\", \"ñ\": \"&ntilde;\", \"Ñ\": \"&Ntilde;\",\n         \"ó\": \"&oacute;\", \"Ó\": \"&Oacute;\", \"ô\": \"&ocirc;\", \"Ô\": \"&Ocirc;\", \"ò\": \"&ograve;\", \"Ò\": \"&Ograve;\", \"º\": \"&ordm;\",\n         \"ø\": \"&oslash;\", \"Ø\": \"&Oslash;\", \"õ\": \"&otilde;\", \"Õ\": \"&Otilde;\", \"ö\": \"&ouml;\", \"Ö\": \"&Ouml;\", \"œ\": \"&oelig;\", \"Œ\": \"&OElig;\", \"ℜ\": \"&real;\", \"š\": \"&scaron;\", \"Š\": \"&Scaron;\", \"ß\": \"&szlig;\", \"™\": \"&trade;\", \"ú\": \"&uacute;\",\n         \"Ú\": \"&Uacute;\", \"û\": \"&ucirc;\", \"Û\": \"&Ucirc;\", \"ù\": \"&ugrave;\", \"Ù\": \"&Ugrave;\", \"ü\": \"&uuml;\", \"Ü\": \"&Uuml;\",\n         \"ý\": \"&yacute;\", \"Ý\": \"&Yacute;\", \"ÿ\": \"&yuml;\", \"Ÿ\": \"&Yuml;\", \"þ\": \"&thorn;\", \"Þ\": \"&THORN;\", \"α\": \"&alpha;\",\n         \"Α\": \"&Alpha;\", \"β\": \"&beta;\", \"Β\": \"&Beta;\", \"γ\": \"&gamma;\", \"Γ\": \"&Gamma;\", \"δ\": \"&delta;\", \"Δ\": \"&Delta;\",\n         \"ε\": \"&epsilon;\", \"Ε\": \"&Epsilon;\", \"ζ\": \"&zeta;\", \"Ζ\": \"&Zeta;\", \"η\": \"&eta;\", \"Η\": \"&Eta;\", \"θ\": \"&theta;\",\n         \"Θ\": \"&Theta;\", \"ϑ\": \"&thetasym;\", \"ι\": \"&iota;\", \"Ι\": \"&Iota;\", \"κ\": \"&kappa;\", \"Κ\": \"&Kappa;\", \"λ\": \"&lambda;\",\n         \"Λ\": \"&Lambda;\", \"µ\": \"&micro;\", \"μ\": \"&mu;\", \"Μ\": \"&Mu;\", \"ν\": \"&nu;\", \"Ν\": \"&Nu;\", \"ξ\": \"&xi;\", \"Ξ\": \"&Xi;\",\n         \"ο\": \"&omicron;\", \"Ο\": \"&Omicron;\", \"π\": \"&pi;\", \"Π\": \"&Pi;\", \"ϖ\": \"&piv;\", \"ρ\": \"&rho;\", \"Ρ\": \"&Rho;\",\n         \"σ\": \"&sigma;\", \"Σ\": \"&Sigma;\", \"ς\": \"&sigmaf;\", \"τ\": \"&tau;\", \"Τ\": \"&Tau;\", \"ϒ\": \"&upsih;\", \"υ\": \"&upsilon;\",\n         \"Υ\": \"&Upsilon;\", \"φ\": \"&phi;\", \"Φ\": \"&Phi;\", \"χ\": \"&chi;\", \"Χ\": \"&Chi;\", \"ψ\": \"&psi;\", \"Ψ\": \"&Psi;\",\n         \"ω\": \"&omega;\", \"Ω\": \"&Omega;\", \"ℵ\": \"&alefsym;\"]\n\n    var html: String {\n        var html = \"\"\n        for character in self {\n            if let entity = String.enc[character] {\n                html.append(entity)\n            } else {\n                html.append(character)\n            }\n        }\n        return html\n    }\n}\n\ninternal func isNilOrWrappedNil(value: Any) -> Bool {\n    let mirror = Mirror(reflecting: value)\n    if mirror.displayStyle == .optional {\n        if let first = mirror.children.first {\n            return isNilOrWrappedNil(value: first.value)\n        } else {\n            return true\n        }\n    }\n    return false\n}\n// swiftlint:disable:this file_length\n"
  },
  {
    "path": "Examples/TemplateExample/Tests/.swiftlint.yml",
    "content": "disabled_rules:\n  - force_cast\n  - force_try\n  - force_unwrapping\n  - type_name\n  - file_header\n  - explicit_top_level_acl"
  },
  {
    "path": "Examples/TemplateExample/Tests/LinuxMain.swift",
    "content": "@testable import TemplateExampleTests\nimport XCTest\n\nXCTMain([\n    testCase(TemplateExampleTests.allTests)\n])\n"
  },
  {
    "path": "Examples/TemplateExample/Tests/TemplateExampleTests/TemplateExampleComponentTests.swift",
    "content": "import Eval\n@testable import TemplateExample\nimport XCTest\n\nclass TemplateExampleComponentTests: XCTestCase {\n    let interpreter: TemplateLanguage = TemplateLanguage()\n\n    func testComplexExample() {\n        XCTAssertEqual(eval(\n\"\"\"\n{% if greet %}Hello{% else %}Bye{% endif %} {{ name }}!\n{% set works = true %}\n{% for i in [3,2,1] %}{{ i }}, {% endfor %}go!\n\nThis template engine {% if !works %}does not {% endif %}work{% if works %}s{% endif %}!\n\"\"\", [\"greet\": true, \"name\": \"Laszlo\"]),\n\"\"\"\nHello Laszlo!\n\n3, 2, 1, go!\n\nThis template engine works!\n\"\"\")\n    }\n\n    // MARK: Helpers\n\n    func eval(_ template: String, _ variables: [String: Any] = [:]) -> String {\n        let context = Context(variables: variables)\n        let result = interpreter.evaluate(template, context: context)\n        if !context.debugInfo.isEmpty {\n            print(context.debugInfo)\n        }\n        return result\n    }\n}\n"
  },
  {
    "path": "Examples/TemplateExample/Tests/TemplateExampleTests/TemplateExampleTests.swift",
    "content": "import Eval\n@testable import TemplateExample\nimport XCTest\n\nclass TemplateExampleTests: XCTestCase {\n    let interpreter: TemplateLanguage = TemplateLanguage()\n\n    // MARK: Statements\n\n    func testIfElseStatement() {\n        XCTAssertEqual(eval(\"{% if x in [1,2,3] %}Hello{% else %}Bye{% endif %} {{ name }}!\", [\"x\": 2, \"name\": \"Teve\"]), \"Hello Teve!\")\n    }\n\n    func testIfStatement() {\n        XCTAssertEqual(eval(\"{% if true %}Hello{% endif %} {{ name }}!\", [\"name\": \"Teve\"]), \"Hello Teve!\")\n    }\n\n    func testEmbeddedIfStatement() {\n        XCTAssertEqual(eval(\"Result: {% if x > 1 %}{% if x < 5 %}1<x<5{% endif %}{% endif %}\", [\"x\": 2]), \"Result: 1<x<5\")\n\n        XCTAssertEqual(eval(\"Result: {% if x > 1 %}{% if x < 5 %}1<x<5{% endif %}{% else %}x<=1{% endif %}\", [\"x\": 2]), \"Result: 1<x<5\")\n        XCTAssertEqual(eval(\"Result: {% if x >= 5 %}x>=5{% else %}{% if x > 1 %}1<x<5{% endif %}{% endif %}\", [\"x\": 2]), \"Result: 1<x<5\")\n\n        XCTAssertEqual(eval(\"Result: {% if x > 1 %}{% if x < 5 %}1<x<5{% else %}x>=5{% endif %}{% else %}x<=1{% endif %}\", [\"x\": 2]), \"Result: 1<x<5\")\n        XCTAssertEqual(eval(\"Result: {% if x >= 5 %}x>=5{% else %}{% if x > 1 %}1<x<5{% else %}x<=1{% endif %}{% endif %}\", [\"x\": 2]), \"Result: 1<x<5\")\n    }\n\n    func testPrintStatement() {\n        XCTAssertEqual(eval(\"{{ x }}\", [\"x\": \"Yo\"]), \"Yo\")\n        XCTAssertEqual(eval(\"{{ x + 1 }}\", [\"x\": 5]), \"6\")\n    }\n\n    func testSetStatement() {\n        _ = eval(\"{% set x = 4.0 %}\")\n        XCTAssertEqual(eval(\"{{ x }}\"), \"4\")\n    }\n\n    func testSetWithBodyStatement() {\n        _ = eval(\"{% set x %}this{% endset %}\")\n        XCTAssertEqual(eval(\"Check {{ x }} out\"), \"Check this out\")\n    }\n\n    func testForInStatement() {\n        XCTAssertEqual(eval(\"{% for i in [1,2,3] %}a{% endfor %}\"), \"aaa\")\n        XCTAssertEqual(eval(\"{% for i in x %}{{i*2}} {% endfor %}\", [\"x\": [1, 2, 3]]), \"2 4 6 \")\n        XCTAssertEqual(eval(\"{% for i in [1,2,3] %}{{i * 2}} {% endfor %}\"), \"2 4 6 \")\n        XCTAssertEqual(eval(\"{% for i in [1,2,3] %}{% if i is not first %}, {% endif %}{{i * 2}}{% endfor %}\"), \"2, 4, 6\")\n        XCTAssertEqual(eval(\"{% for i in [1,2,3] %}{{i * 2}}{% if i is not last %}, {% endif %}{% endfor %}\"), \"2, 4, 6\")\n        XCTAssertEqual(eval(\"{% for i in [1,2,3] %}{% if i is first %}^{% endif %}{{i}}{% if i is last %}${% endif %}{% endfor %}\"), \"^123$\")\n    }\n\n    func testCommentStatement() {\n        XCTAssertEqual(eval(\"Personal {# random comment #}Computer\"), \"Personal Computer\")\n    }\n\n    func testMacroStatement() {\n        XCTAssertEqual(eval(\"{% macro double(value) %}value * 2{% endmacro %}{{ double(4) }}\"), \"8\")\n        XCTAssertEqual(eval(\"{% macro concat(a, b) %}a + b{% endmacro %}{{ concat('Hello ', 'World!') }}\"), \"Hello World!\")\n    }\n\n    func testBlockStatement() {\n        XCTAssertEqual(eval(\"Title: {% block title1 %}Original{% endblock %}.\"), \"Title: Original.\")\n        XCTAssertEqual(eval(\"Title: {% block title2 %}Original{% endblock %}.{% block title2 %}Other{% endblock %}\"), \"Title: Other.\")\n        XCTAssertEqual(eval(\"Title: {% block title3 %}Original{% endblock %}.{% block title3 %}{{ parent() }} 2{% endblock %}\"), \"Title: Original 2.\")\n        XCTAssertEqual(eval(\"Title: {% block title4 %}Original{% endblock %}.{% block title4 %}{{ parent() }} 2{% endblock %}{% block title4 %}{{ parent() }}.1{% endblock %}\"), \"Title: Original 2.1.\")\n        XCTAssertEqual(eval(\"{% block title5 %}Hello {{name}}{% endblock %}{% block title5 %}{{ parent() }}!{% endblock %}\", [\"name\": \"George\"]), \"Hello George!\")\n        XCTAssertEqual(eval(\"{% block title6 %}Hello {{name}}{% endblock %}{% block title6 %}{{ parent(name='Laszlo') }}!{% endblock %}\", [\"name\": \"Geroge\"]), \"Hello Laszlo!\")\n    }\n\n    func testSpaceElimination() {\n        XCTAssertEqual(eval(\"asd   {-}   jkl\"), \"asdjkl\")\n        XCTAssertEqual(eval(\"{-}   jkl\"), \"jkl\")\n        XCTAssertEqual(eval(\"asd   {-}\"), \"asd\")\n\n        XCTAssertEqual(eval(\"asd   {-}{% if true %}   Hello   {% endif %}   \"), \"asd   Hello      \")\n        XCTAssertEqual(eval(\"asd   {-}{% if true %}{-}   Hello   {% endif %}   \"), \"asdHello      \")\n        XCTAssertEqual(eval(\"asd   {% if true %}   Hello {-}  {% endif %}   \"), \"asd      Hello   \")\n    }\n\n    // MARK: Data types\n\n    func testString() {\n        XCTAssertEqual(eval(\"{{ 'hello' }}\"), \"hello\")\n        XCTAssertEqual(eval(\"{{ String(1) }}\"), \"1\")\n    }\n\n    func testBoolean() {\n        XCTAssertEqual(eval(\"{{ true }}\"), \"true\")\n        XCTAssertEqual(eval(\"{{ false }}\"), \"false\")\n        XCTAssertEqual(eval(\"{{ 1 < 2 }}\"), \"true\")\n    }\n\n    func testDate() {\n        XCTAssertEqual(eval(\"{{ Date(2018,12,13).format('dd/MM/yy') }}\"), \"13/12/18\")\n    }\n\n    func testInteger() {\n        XCTAssertEqual(eval(\"{{ 1 }}\"), \"1\")\n    }\n\n    func testDouble() {\n        XCTAssertEqual(eval(\"{{ 2.5 }}\"), \"2.5\")\n    }\n\n    func testDictionary() {\n        XCTAssertEqual(eval(\"{{ {'a': 1, 'b': 2} }}\"), \"[a: 1, b: 2]\")\n        XCTAssertEqual(eval(\"{{ {} }}\"), \"[]\")\n    }\n\n    func testArray() {\n        XCTAssertEqual(eval(\"{{ [1,2,3] }}\"), \"1,2,3\")\n        XCTAssertEqual(eval(\"{{ [] }}\"), \"\")\n    }\n\n    func testEmpty() {\n        XCTAssertEqual(eval(\"{{ null }}\"), \"null\")\n        XCTAssertEqual(eval(\"{{ nil }}\"), \"null\")\n        XCTAssertEqual(eval(\"{{ [].0 }}\"), \"null\")\n    }\n\n    // MARK: Functions and operators\n\n    func testParentheses() {\n        XCTAssertEqual(eval(\"{{ ( 1 + 2 ) * 3 }}\"), \"9\")\n        XCTAssertEqual(eval(\"{{ ( (9/3) + 2 ) * 3 }}\"), \"15\")\n        XCTAssertEqual(eval(\"{{ (((2))) }}\"), \"2\")\n    }\n\n    func testTernary() {\n        XCTAssertEqual(eval(\"{{ true ? 1 : 2 }}\"), \"1\")\n        XCTAssertEqual(eval(\"{{ false ? 1 : 2 }}\"), \"2\")\n    }\n\n    func testRange() {\n        XCTAssertEqual(eval(\"{{ 1...3 }}\"), \"1,2,3\")\n        XCTAssertEqual(eval(\"{{ 'a'...'c' }}\"), \"a,b,c\")\n    }\n\n    func testRangeBySteps() {\n        XCTAssertEqual(eval(\"{{ range(start=1, end=7, step=2) }}\"), \"1,3,5,7\")\n    }\n\n    func testStartsWith() {\n        XCTAssertEqual(eval(\"{{ 'Hello' starts with 'H' }}\"), \"true\")\n        XCTAssertEqual(eval(\"{{ 'Hello' starts with 'Hell' }}\"), \"true\")\n        XCTAssertEqual(eval(\"{{ 'Hello' starts with 'Yo' }}\"), \"false\")\n    }\n\n    func testEndsWith() {\n        XCTAssertEqual(eval(\"{{ 'Hello' ends with 'o' }}\"), \"true\")\n        XCTAssertEqual(eval(\"{{ 'Hello' ends with 'ello' }}\"), \"true\")\n        XCTAssertEqual(eval(\"{{ 'Hello' ends with 'Yo' }}\"), \"false\")\n    }\n\n    func testContains() {\n        XCTAssertEqual(eval(\"{{ 'Partly' contains 'art' }}\"), \"true\")\n        XCTAssertEqual(eval(\"{{ 'Hello' contains 'art' }}\"), \"false\")\n    }\n\n    func testMatches() {\n        XCTAssertEqual(eval(\"{{ 'Partly' matches '[A-Z]art[a-z]{2}' }}\"), \"true\")\n        XCTAssertEqual(eval(\"{{ 'Partly' matches '\\\\d+' }}\"), \"false\")\n    }\n\n    func testConcat() {\n        XCTAssertEqual(eval(\"{{ 'This' + ' is ' + 'Sparta' }}\"), \"This is Sparta\")\n    }\n\n    func testAddition() {\n        XCTAssertEqual(eval(\"{{ 1 + 2 }}\"), \"3\")\n        XCTAssertEqual(eval(\"{{ 1 + 2 + 3 }}\"), \"6\")\n    }\n\n    func testSubstraction() {\n        XCTAssertEqual(eval(\"{{ 5 - 2 }}\"), \"3\")\n        XCTAssertEqual(eval(\"{{ 5 - 2 - 3 }}\"), \"0\")\n    }\n\n    func testMultiplication() {\n        XCTAssertEqual(eval(\"{{ 5 * 2 }}\"), \"10\")\n        XCTAssertEqual(eval(\"{{ 5 * 2 * 3 }}\"), \"30\")\n    }\n\n    func testDivision() {\n        XCTAssertEqual(eval(\"{{ 5 / 5 }}\"), \"1\")\n        XCTAssertEqual(eval(\"{{ 144 / 12 / 4 }}\"), \"3\")\n    }\n\n    func testPow() {\n        XCTAssertEqual(eval(\"{{ 2 ** 5 }}\"), \"32\")\n    }\n\n    func testNumericPrecedence() {\n        XCTAssertEqual(eval(\"{{ 4 + 2 * 3 }}\"), \"10\")\n        XCTAssertEqual(eval(\"{{ 4 - 2 * 3 }}\"), \"-2\")\n        XCTAssertEqual(eval(\"{{ 4 * 3 / 2 + 2 - 8 }}\"), \"0\")\n    }\n\n    func testLessThan() {\n        XCTAssertEqual(eval(\"{{ 2 < 3 }}\"), \"true\")\n        XCTAssertEqual(eval(\"{{ 3 < 2 }}\"), \"false\")\n        XCTAssertEqual(eval(\"{{ 2 < 2 }}\"), \"false\")\n    }\n\n    func testLessThanOrEqual() {\n        XCTAssertEqual(eval(\"{{ 2 <= 3 }}\"), \"true\")\n        XCTAssertEqual(eval(\"{{ 3 <= 2 }}\"), \"false\")\n        XCTAssertEqual(eval(\"{{ 2 <= 2 }}\"), \"true\")\n    }\n\n    func testGreaterThan() {\n        XCTAssertEqual(eval(\"{{ 2 > 3 }}\"), \"false\")\n        XCTAssertEqual(eval(\"{{ 3 > 2 }}\"), \"true\")\n        XCTAssertEqual(eval(\"{{ 2 > 2 }}\"), \"false\")\n    }\n\n    func testGreaterThanOrEqual() {\n        XCTAssertEqual(eval(\"{{ 2 >= 3 }}\"), \"false\")\n        XCTAssertEqual(eval(\"{{ 3 >= 2 }}\"), \"true\")\n        XCTAssertEqual(eval(\"{{ 2 >= 2 }}\"), \"true\")\n    }\n\n    func testEquals() {\n        XCTAssertEqual(eval(\"{{ 2 == 3 }}\"), \"false\")\n        XCTAssertEqual(eval(\"{{ 2 == 2 }}\"), \"true\")\n    }\n\n    func testNotEquals() {\n        XCTAssertEqual(eval(\"{{ 2 != 2 }}\"), \"false\")\n        XCTAssertEqual(eval(\"{{ 2 != 3 }}\"), \"true\")\n    }\n\n    func testInNumericArray() {\n        XCTAssertEqual(eval(\"{{ 2 in [1,2,3] }}\"), \"true\")\n        XCTAssertEqual(eval(\"{{ 5 in [1,2,3] }}\"), \"false\")\n    }\n\n    func testInStringArray() {\n        XCTAssertEqual(eval(\"{{ 'a' in ['a', 'b', 'c'] }}\"), \"true\")\n        XCTAssertEqual(eval(\"{{ 'z' in ['a', 'b', 'c'] }}\"), \"false\")\n    }\n\n    func testIncrement() {\n        XCTAssertEqual(eval(\"{{ 2++ }}\"), \"3\")\n        XCTAssertEqual(eval(\"{{ -1++ }}\"), \"0\")\n    }\n\n    func testDecrement() {\n        XCTAssertEqual(eval(\"{{ 7-- }}\"), \"6\")\n        XCTAssertEqual(eval(\"{{ -7-- }}\"), \"-8\")\n    }\n\n    func testNegation() {\n        XCTAssertEqual(eval(\"{{ not true }}\"), \"false\")\n        XCTAssertEqual(eval(\"{{ not false }}\"), \"true\")\n        XCTAssertEqual(eval(\"{{ !true }}\"), \"false\")\n        XCTAssertEqual(eval(\"{{ !false }}\"), \"true\")\n    }\n\n    func testAnd() {\n        XCTAssertEqual(eval(\"{{ true and true }}\"), \"true\")\n        XCTAssertEqual(eval(\"{{ false and false }}\"), \"false\")\n        XCTAssertEqual(eval(\"{{ true and false }}\"), \"false\")\n        XCTAssertEqual(eval(\"{{ false and true }}\"), \"false\")\n    }\n\n    func testOr() {\n        XCTAssertEqual(eval(\"{{ true or true }}\"), \"true\")\n        XCTAssertEqual(eval(\"{{ false or false }}\"), \"false\")\n        XCTAssertEqual(eval(\"{{ true or false }}\"), \"true\")\n        XCTAssertEqual(eval(\"{{ false or true }}\"), \"true\")\n    }\n\n    func testIsEven() {\n        XCTAssertEqual(eval(\"{{ 8 is even }}\"), \"true\")\n        XCTAssertEqual(eval(\"{{ 1 is even }}\"), \"false\")\n        XCTAssertEqual(eval(\"{{ -1 is even }}\"), \"false\")\n    }\n\n    func testIsOdd() {\n        XCTAssertEqual(eval(\"{{ 8 is odd }}\"), \"false\")\n        XCTAssertEqual(eval(\"{{ 1 is odd }}\"), \"true\")\n        XCTAssertEqual(eval(\"{{ -1 is odd }}\"), \"true\")\n    }\n\n    func testMax() {\n        XCTAssertEqual(eval(\"{{ [5,3,7,1].max }}\"), \"7\")\n        XCTAssertEqual(eval(\"{{ max(5,3,7,1) }}\"), \"7\")\n        XCTAssertEqual(eval(\"{{ [-5,-3,-7,-1].max }}\"), \"-1\")\n        XCTAssertEqual(eval(\"{{ max(-5,-3,-7,-1) }}\"), \"-1\")\n    }\n\n    func testMin() {\n        XCTAssertEqual(eval(\"{{ [5,3,7,1].min }}\"), \"1\")\n        XCTAssertEqual(eval(\"{{ min(5,3,7,1) }}\"), \"1\")\n        XCTAssertEqual(eval(\"{{ [-5,-3,-7,-1].min }}\"), \"-7\")\n        XCTAssertEqual(eval(\"{{ min(-5,-3,-7,-1) }}\"), \"-7\")\n    }\n\n    func testCount() {\n        XCTAssertEqual(eval(\"{{ [5,3,7,1].count }}\"), \"4\")\n        XCTAssertEqual(eval(\"{{ [].count }}\"), \"0\")\n        XCTAssertEqual(eval(\"{{ {'a': 5, 'b': 2}.count }}\"), \"2\")\n        XCTAssertEqual(eval(\"{{ {}.count }}\"), \"0\")\n    }\n\n    func testAverage() {\n        XCTAssertEqual(eval(\"{{ [1,2,3,4].avg }}\"), \"2.5\")\n        XCTAssertEqual(eval(\"{{ [2,2].avg }}\"), \"2\")\n        XCTAssertEqual(eval(\"{{ avg(1,2,3,4) }}\"), \"2.5\")\n        XCTAssertEqual(eval(\"{{ avg(2,2) }}\"), \"2\")\n    }\n\n    func testSum() {\n        XCTAssertEqual(eval(\"{{ [1,2,3,4].sum }}\"), \"10\")\n        XCTAssertEqual(eval(\"{{ sum(1,2,3,4) }}\"), \"10\")\n    }\n\n    func testSqrt() {\n        XCTAssertEqual(eval(\"{{ sqrt(225) }}\"), \"15\")\n        XCTAssertEqual(eval(\"{{ sqrt(4) }}\"), \"2\")\n    }\n\n    func testFirst() {\n        XCTAssertEqual(eval(\"{{ [1,2,3].first }}\"), \"1\")\n        XCTAssertEqual(eval(\"{{ [].first }}\"), \"null\")\n    }\n\n    func testLast() {\n        XCTAssertEqual(eval(\"{{ [1,2,3].last }}\"), \"3\")\n        XCTAssertEqual(eval(\"{{ [].last }}\"), \"null\")\n    }\n\n    func testDefault() {\n        XCTAssertEqual(eval(\"{{ null.default('fallback') }}\"), \"fallback\")\n        XCTAssertEqual(eval(\"{{ array.last.default('none') }}\", [\"array\": [1]]), \"1\")\n        XCTAssertEqual(eval(\"{{ array.last.default('none') }}\", [\"array\": []]), \"none\")\n        XCTAssertEqual(eval(\"{{ array.last.default(2) }}\", [\"array\": []]), \"2\")\n    }\n\n    func testJoin() {\n        XCTAssertEqual(eval(\"{{ ['1','2','3'].join('-') }}\"), \"1-2-3\")\n        XCTAssertEqual(eval(\"{{ [].join('-') }}\"), \"\")\n    }\n\n    func testSplit() {\n        XCTAssertEqual(eval(\"{{ 'a,b,c'.split(',') }}\"), \"a,b,c\")\n        XCTAssertEqual(eval(\"{{ 'a'.split('-') }}\"), \"a\")\n    }\n\n    func testMerge() {\n        XCTAssertEqual(eval(\"{{ [1,2,3].merge([4,5]) }}\"), \"1,2,3,4,5\")\n        XCTAssertEqual(eval(\"{{ [].merge([1]) }}\"), \"1\")\n    }\n\n    func testArraySubscript() {\n        XCTAssertEqual(eval(\"{{ array.1 }}\", [\"array\": [1, 2, 3]]), \"2\")\n        XCTAssertEqual(eval(\"{{ [1,2,3].1 }}\"), \"2\")\n        XCTAssertEqual(eval(\"{{ ['a', 'b', 'c'].1 }}\"), \"b\")\n    }\n\n    func testArrayMap() {\n        XCTAssertEqual(eval(\"{{ [1,2,3].map(i => i * 2) }}\"), \"2,4,6\")\n    }\n\n    func testArrayFilter() {\n        XCTAssertEqual(eval(\"{{ [1,2,3].filter(i => i % 2 == 1) }}\"), \"1,3\")\n    }\n\n    func testDictionaryFilter() {\n        XCTAssertEqual(eval(\"{{ {'a': 1, 'b': 2}.filter(k,v => k == 'a') }}\"), \"[a: 1]\")\n    }\n\n    func testDictionarySubscript() {\n        XCTAssertEqual(eval(\"{{ dict.b }}\", [\"dict\": [\"a\": 1, \"b\": 2]]), \"2\")\n        XCTAssertEqual(eval(\"{{ {'a': 1, 'b': 2}.b }}\"), \"2\")\n    }\n\n    func testDictionaryKeys() {\n        XCTAssertEqual(eval(\"{{ {'a': 1, 'b': 2}.keys }}\"), \"a,b\")\n    }\n\n    func testDictionaryValues() {\n        XCTAssertEqual(eval(\"{{ {'a': 1, 'b': 2}.values }}\"), \"1,2\")\n    }\n\n    func testAbsolute() {\n        XCTAssertEqual(eval(\"{{ 1.abs }}\"), \"1\")\n        XCTAssertEqual(eval(\"{{ -1.abs }}\"), \"1\")\n    }\n\n    func testRound() {\n        XCTAssertEqual(eval(\"{{ round(2.5) }}\"), \"3\")\n        XCTAssertEqual(eval(\"{{ round(1.2) }}\"), \"1\")\n    }\n\n    func testTrim() {\n        XCTAssertEqual(eval(\"{{ '  a  '.trim }}\"), \"a\")\n    }\n\n    func testEscape() {\n        XCTAssertEqual(eval(\"{{ ' ?&:/'.escape }}\"), \"&nbsp;?&amp;:/\")\n    }\n\n    func testUrlEncode() {\n        XCTAssertEqual(eval(\"{{ ' ?&:/'.urlEncode }}\"), \"%20%3F%26%3A%2F\")\n    }\n\n    func testUrlDecode() {\n        XCTAssertEqual(eval(\"{{ '%20%3F%26%3A%2F'.urlDecode }}\"), \" ?&:/\")\n    }\n\n    func testNl2br() {\n        XCTAssertEqual(eval(\"{{ 'a\\nb'.nl2br }}\"), \"a<br/>b\")\n    }\n\n    func testCapitalise() {\n        XCTAssertEqual(eval(\"{{ 'hello there'.capitalise }}\"), \"Hello There\")\n    }\n\n    func testUpper() {\n        XCTAssertEqual(eval(\"{{ 'hello there'.upper }}\"), \"HELLO THERE\")\n    }\n\n    func testLower() {\n        XCTAssertEqual(eval(\"{{ 'HELLO THERE'.lower }}\"), \"hello there\")\n    }\n\n    func testUpperFirst() {\n        XCTAssertEqual(eval(\"{{ 'hello there'.upperFirst }}\"), \"Hello there\")\n    }\n\n    func testLowerFirst() {\n        XCTAssertEqual(eval(\"{{ 'HELLO THERE'.lowerFirst }}\"), \"hELLO THERE\")\n    }\n\n    func testUpperCapitalise() {\n        XCTAssertEqual(eval(\"{{ 'hello there'.capitalise.upperFirst }}\"), \"Hello There\")\n    }\n\n    func testLowerCapitalise() {\n        XCTAssertEqual(eval(\"{{ 'HELLO THERE'.capitalise.lowerFirst }}\"), \"hello There\")\n    }\n\n    // MARK: Whitespace truncation\n\n    func testSpacelessTag() {\n        XCTAssertEqual(eval(\"{% spaceless %}   {% if true %}    Hello    {% endif %}    {% endspaceless %}\"), \"Hello\")\n    }\n\n    // MARK: Template file\n\n    func testTemplateFile() {\n        let result = try! interpreter.evaluate(template: Bundle(for: type(of: self)).url(forResource: \"template\", withExtension: \"txt\")!, context: Context(variables: [\"name\": \"Laszlo\"]))\n        XCTAssertEqual(result, \"Hello Laszlo!\")\n    }\n\n    func testTemplateWithImportFile() {\n        let result = try! interpreter.evaluate(template: Bundle(for: type(of: self)).url(forResource: \"import\", withExtension: \"txt\")!, context: Context(variables: [\"name\": \"Laszlo\"]))\n        XCTAssertEqual(result, \"Hello Laszlo!\\nBye!\")\n    }\n\n    // MARK: Helpers\n\n    func eval(_ template: String, _ variables: [String: Any] = [:]) -> String {\n        let context = Context(variables: variables)\n        let result = interpreter.evaluate(template, context: context)\n        if !context.debugInfo.isEmpty {\n//            print(context.debugInfo)\n        }\n        return result\n    }\n}\n"
  },
  {
    "path": "Examples/TemplateExample/Tests/TemplateExampleTests/import.txt",
    "content": "{% import 'template.txt' %}\nBye!"
  },
  {
    "path": "Examples/TemplateExample/Tests/TemplateExampleTests/template.txt",
    "content": "Hello {{name}}!"
  },
  {
    "path": "Gemfile",
    "content": "source 'https://rubygems.org'\n\ngem 'jazzy', '>=0.9'\n\ngem 'xcpretty'\ngem 'xcpretty-json-formatter'\n\ngem 'cocoapods'\n\ngem 'danger'\ngem 'danger-auto_label'\ngem 'danger-commit_lint'\ngem 'danger-mention'\ngem 'danger-pronto'\ngem 'danger-prose'\ngem 'danger-shellcheck'\n# gem 'danger-slather'\ngem 'danger-swiftlint'\ngem 'danger-tailor'\ngem 'danger-welcome_message'\ngem 'danger-xcode_summary'\ngem 'danger-xcodebuild'\ngem 'danger-xcov'"
  },
  {
    "path": "LICENSE.txt",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "Package.swift",
    "content": "// swift-tools-version:5.0\n\nimport PackageDescription\n\nlet package = Package(\n    name: \"Eval\",\n    products: [\n        .library(\n            name: \"Eval\",\n            targets: [\"Eval\"]),\n    ],\n    dependencies: [\n    ],\n    targets: [\n        .target(\n            name: \"Eval\",\n            dependencies: []),\n        .testTarget(\n            name: \"EvalTests\",\n            dependencies: [\"Eval\"]),\n    ]\n)\n"
  },
  {
    "path": "README.md",
    "content": "# { Eval }\n\n[![Travis CI status](https://travis-ci.org/tevelee/Eval.svg?branch=master)](https://travis-ci.org/tevelee/Eval)\n[![Framework version](https://img.shields.io/badge/Version-1.5.0-yellow.svg)]()\n[![Swift version](https://img.shields.io/badge/Swift-5.0-orange.svg)]()\n[![Code Documentation Coverage](https://tevelee.github.io/Eval/badge.svg)](https://tevelee.github.io/Eval)\n[![Code Test Coverage](https://codecov.io/gh/tevelee/Eval/branch/master/graph/badge.svg)](https://codecov.io/gh/tevelee/Eval)\n[![Platforms](https://img.shields.io/badge/Platforms-iOS%20|%20macOS%20|%20Linux-blue.svg)]()\n[![Lincese](https://img.shields.io/badge/License-Apache%202.0-green.svg)](https://github.com/tevelee/Eval/tree/master/LICENSE.txt)\n\n##### Dependency Managers\n\n[![CocoaPods compatible](https://img.shields.io/badge/CococaPods-Compatible-blue.svg)](http://cocoapods.org/pods/Eval)\n[![Swift Package Manager compatible](https://img.shields.io/badge/Swift%20Package%20Manager-Compatible-red.svg)](https://github.com/apple/swift-package-manager)\n[![Carthage compatible](https://img.shields.io/badge/Carthage-Compatible-brightgreen.svg?style=flat)](https://github.com/Carthage/Carthage)\n\n---\n\n- [👨🏻‍💻 About](#-about)\n- [📈 Getting Started](#-getting-started)\n\t- [🤓 Short Example](#-short-example)\n\t- [⚡️ Installation](#%EF%B8%8F-installation)\n\t- [⁉️ How does it work?](#%EF%B8%8F-how-does-it-work)\n- [🏃🏻 Status](#-status)\n- [💡 Motivation](#-motivation)\n- [📚 Examples](#-examples)\n- [🙋 Contribution](#-contribution)\n- [👀 Details](#-details)\n- [👤 Author](#-author)\n- [⚖️ License](#%EF%B8%8F-license)\n\n## 👨🏻‍💻 About\n\n**Eval** is a lightweight interpreter framework written in <img src=\"http://www.swiftapplications.com/wp-content/uploads/2016/04/swift-logo.png\" width=\"16\"> Swift, for 📱iOS, 🖥 macOS, and 🐧Linux platforms.\n\nIt evaluates expressions at runtime, with operators and data types you define.\n\n🍏 Pros | 🍎 Cons\n------- | --------\n🐥 Lightweight - the whole engine is really just a few hundred lines of code | 🤓 Creating custom operators and data types, on the other hand, can take a few extra lines - depending on your needs\n✅ Easy to use API - create new language elements in just a matter of seconds | ♻️ The evaluated result of the expressions must be strongly typed, so you can only accept what type you expect the result is going to be\n🎢 Fun - Since it is really easy to play with, it's joyful to add - even complex - language features | -\n🚀 Fast execution - I'm trying to optimise as much as possible. Has its limitations though | 🌧 Since it is a really generic concept, some optimisations cannot be made, compared to native interpreters\n\nThe framework currently supports two different types of execution modes:\n\n- **Strongly typed expressions**: like a programming language\n- **Template languages**: evaluating expressions in arbitrary string environments\n\n*Let's see just a few examples:*\n\nIt's extremely easy to formulate expressions (and evaluate them at runtime), like \n\n- `5 in 1...3` evaluates to `false` Bool type\n- `'Eval' starts with 'E'` evaluates to `true` Bool type\n- `'b' in ['a','c','d']` evaluates to `false` Bool type\n- `x < 2 ? 'a' : 'b'` evaluates to `\"a\"` or `\"b\"` String type, based on the `x` Int input variable\n- `Date(2018, 12, 13).format('yyyy-MM-dd')` evaluates to `\"2018-12-13\"` string\n- `'hello'.length` evaluates to `5` Integer\n- `now` evaluates to `Date()`\n\nAnd templates, such as\n\n- `{% if name != nil %}Hello{% else %}Bye{% endif %} {{ name|default('user') }}!`, whose output is `Hello Adam!` or `Bye User!`\n- `Sequence: {% for i in 1...5 %}{{ 2 * i }} {% endfor %}` which is `2 4 6 8 10 `\n\nAnd so on... The result of these expressions depends on the content, determined by the evaluation. It can be any type which is returned by the functions (String, [Double], Date, or even custom types of your own.)\n\nYou can find various ways of usage in the examples section below.\n\n## 🏃🏻 Status\n\n- [x] Library implementation\n- [x] API finalisation\n- [x] Swift Package Manager support\n- [x] Initial documentation\n- [x] Example project (template engine)\n- [x] CocoaPods support\n- [x] CI\n- [x] Code test-coverage\n- [x] v1.0\n- [x] Fully detailed documentation\n- [x] Contribution guides\n- [x] Further example projects\n- [x] Debugging helpers\n- [x] v1.1\n\nThis is a really early stage of the project, I'm still deep in the process of all the open-sourcing related tasks, such as firing up a CI, creating a beautiful documentation page, managing administrative tasks around stability. \n\nPlease stay tuned for the updates!\n\n## 📈 Getting started\n\nFor the expressions to work, you'll need to create an interpreter instance, providing your data types and expressions you aim to support, and maybe some input variables - if you need any.\n\n```swift\nlet interpreter = TypedInterpreter(dataTypes: [number, string, boolean, array, date],\n                                   functions: [multipication, addition, ternary],\n                                   context: Context(variables: [\"x\": 2.0]))\n```\n\nAnd call it with a string expression, as follows.\n\n```swift                                   \nlet result = interpreter.evaluate(\"2 * x + 1\") as? Double\n```\n\n### 🤓 Short example\n\nLet's check out a fairly complex example, and build it from scratch! Let's implement a language which can parse the following expression:\n\n```swift\nx != 0 ? 5 * x : pi + 1\n```\n\nThere's a ternary operator `?:` in there, which we will need. Also, supporting number literals (`0`, `5`, and `1`) and boolean types (`true/false`). There's also a not equal operator `!=` and a `pi` constant. Let's not forget about the addition `+` and multiplication `*` as well!\n\nFirst, here are the data types.\n\n```swift\nlet numberLiteral = Literal { value,_ in Double(value) } //Converts every number literal, if it can be represented with a Double instance\nlet piConstant = Literal(\"pi\", convertsTo: Double.pi)\n\nlet number = DataType(type: Double.self, literals: [numberLiteral, piConstant]) { String(describing: $0) }\n```\n\n```swift\nlet trueLiteral = Literal(\"true\", convertsTo: true)\nlet falseLiteral = Literal(\"false\", convertsTo: false)\n\nlet boolean = DataType(type: Bool.self, literals: [trueLiteral, falseLiteral]) { $0 ? \"true\" : \"false\" }\n```\n\n(The last parameter, expressed as a block, tells the framework how to formulise this type of data as a String for debug messages or other purposes)\n\nNow, let's build the operators:\n\n```swift\nlet multiplication = Function<Double>(Variable<Double>(\"lhs\") + Keyword(\"*\") + Variable<Double>(\"rhs\")) { arguments in\n    guard let lhs = arguments[\"lhs\"] as? Double, let rhs = arguments[\"rhs\"] as? Double else { return nil }\n    return lhs * rhs\n}\n```\n```swift\nlet addition = Function<Double>(Variable<Double>(\"lhs\") + Keyword(\"+\") + Variable<Double>(\"rhs\")) { arguments in\n    guard let lhs = arguments[\"lhs\"] as? Double, let rhs = arguments[\"rhs\"] as? Double else { return nil }\n    return lhs + rhs\n}\n```\n```swift\nlet notEquals = Function<Bool>(Variable<Double>(\"lhs\") + Keyword(\"!=\") + Variable<Double>(\"rhs\")) { arguments in\n    guard let lhs = arguments[\"lhs\"] as? Double, let rhs = arguments[\"rhs\"] as? Double else { return nil }\n    return lhs != rhs\n}\n```\n```swift\nlet ternary = Function<Any>(Variable<Bool>(\"condition\") + Keyword(\"?\") + Variable<Any>(\"true\") + Keyword(\":\") + Variable<Any>(\"false\")) { arguments in\n    guard let condition = arguments[\"condition\"] as? Bool else { return nil }\n    if condition {\n        return  arguments[\"true\"]\n    } else {\n        return  arguments[\"false\"]\n    }\n}\n```\n\nLooks like, we're all set. Let's evaluate our expression!\n\n```swift\nlet interpreter = TypedInterpreter(dataTypes: [number, boolean],\n                                   functions: [multipication, addition, notEquals, ternary])\n                                   \nlet result : Double = interpreter.evaluate(\"x != 0 ? 5 * x : pi + 1\", context: Context(variables: [\"x\": 3.0]))\nXCTAssertEqual(result, 15.0) //Pass!\n```\n\nNow, that we have operators and data types, we can also evaluate anything using these data types:\n\n* `interpreter.evaluate(\"3 != 4\") as Bool`\n* `interpreter.evaluate(\"2 + 1.5 * 6\") as Double` (since multiplication is defined earlier in the array, it has a higher precedence, as expected)\n* `interpreter.evaluate(\"true ? 1 : 2.5\") as Double`\n\nAs you have seen, it's really easy and intuitive to build custom languages, using simple building blocks. With just a few custom data types and functions, the possibilities are endless. Operators, functions, string, arrays, dates...\n\nThe motto of the framework: Build your own (mini) language!\n\n### ⚡️ Installation\n\nYou have a few options to include the library in your app. \n\n- Swift Package Manager\n- CocoaPods\n- Carthage\n- Manually\n\n#### Swift Package Manager\n\nJust add the following line to your dependencies:\n\n```swift\n.package(url: \"https://github.com/tevelee/Eval.git\", from: \"1.5.0\"),\n```\n\nAnd reference it by name in your targets:\n\n```swift\ntargets: [\n    .target(name: \"MyAwesomeApp\", dependencies: [\"Eval\"]),\n]\n```\n\nAnd finally, run the integration command:\n\n```bash\nswift package resolve\n```\n\n#### CocoaPods\n\nJust add the following line to your `Podfile`:\n\n```ruby\npod 'Eval', '~> 1.5.0'\n```\nAnd install the new dependency:\n\n```bash\npod install\n```\n\n#### Carthage\n\nJust add the following line to your `Cartfile`:\n\n```ruby\ngithub \"tevelee/Eval\" >= 1.5.0\n```\nAnd install the new dependency:\n\n```bash\ncarthage update\n```\n\n#### Manually\n\n(Not recommended! Please use a package manager instead to keep your dependencies up to date.)\n\nClone the repository content and copy the files into a new target in your app.\n\n### ⁉️ How does it work?\n\nThe interpreter itself does not define anything or any way to deal with the input string on its own. \nAll it does is recognising patterns. \n\nBy creating data types, you provide literals to the framework, which it can interpret as an element or a result of the expression. \nThese types are transformed to real Swift types.\n\nBy defining functions, you provide patterns to the framework to recognise. \nFunctions are also typed, they return Swift types as a result of their evaluation.\nFunctions consist of keywords and variables, nothing more. \n\n- Keywords are static strings which should not be interpreted as data (such as `if`, or `{`, `}`). \n- Variables, on the other hand, are typed values, recursively evaluated. For example, if a variable recognises something, that proves to be a further pattern, it recursively evaluates their body, until they find context-variables or literals of any given data type.\n\nFunctions also have blocks, which provide the recognised variables in a key-value dictionary parameter, and you can do whatever you want with them: print them, convert them, modify or assign them to context-variables. \n\nThe addition function above, for example, consists of two variables on each side, and the `+` keyword in the middle. It also requires a block, where both sides are given in a `[String:Any]`, so the closure can get the values of the placeholders and add them together.\n\nThere's one interesting aspect of this solution: Unlike traditional - native - interpreters or compilers, this one recognises patterns from top to bottom. \nMeaning, that it looks at the input string, your expression, and recognises patterns in priority order, and recursively go deeper and deeper until the most basic expressions are met.\n\nA traditional interpreter, however, parses expressions character by character, feeding the results to a lexer, the tokeniser, then builds up an abstract syntax tree (which is highly optimisable), and finally converts it to a binary (compiler) or evaluates it at runtime (interpreter), in one word: bottom-up.\n\nThe two solutions can be compared in various ways. The two main differences are in ease of use, and performance. \nThis version of an interpreter provides an effortless way to define patterns, types, etc., but has its cost! It cannot parse as optimally as a traditional compiler could, as it doesn't have an internal graph of expressions (AST), but still performs in a much more than acceptable way.\nDefinition-wise, this framework provides an easily understandable way of language-elements, but the traditional one really lacks behind, because the lexer is usually an ugly, hardly understandable state machine, or regular expression, BAKED INTO the interpreter code itself.\n\n## 💡 Motivation\n\nI have another project, in which I'm generating Objective-C and Swift model objects with loads of utils, based on really short templates. This project was not possible currently in Swift, as there is no template language - capable enough - to create my templates. (I ended up using a third party PHP framework, called [Twig](https://github.com/twigphp/Twig)). So finally, I created one for Swift!\n\nIt turned out, that making it a little more generic - here and there - makes the whole thing really capable and flexible of using in different use-cases.\n\nThe pattern matching was there, but soon I realised, that I'm going to need expressions as well, for printing, evaluating in if/while statements and so on. First, I was looking at an excellent library, [Expression](https://github.com/nicklockwood/Expression), created by Nick Lockwood, which is capable of evaluating numeric expressions. Unfortunately, I wanted a bit more, defining strings, dates, array, and further types and expressions, so I used my existing pattern matching solution to bring this capability to life.\n\nIt ended up quite positively after I discovered the capabilities of a generic solution like this. The whole thing just blew my mind, language features could have been defined in a matter of seconds, and I wanted to share this discovery with the world, so here you are :)\n\n## 📚 Examples\n​\n​I included a few use-cases, which bring significant improvements on how things are processed before - at least in my previous projects.\n​\n### [Template language](https://github.com/tevelee/Eval/blob/master/Examples/TemplateExample/Tests/TemplateExampleTests/TemplateExampleTests.swift)\n\nI was able to create a full-blown template language, completely, using this framework and nothing else. It's almost like a competitor of the one I mentioned ([Twig](https://github.com/twigphp/Twig)). This is the most advanced example of them all!\n\nI created a standard library with all the possible operators you can imagine. With helpers, each operator is a small, one-liner addition. Added the important data types, such as arrays, strings, numbers, booleans, dates, etc., and a few functions, to be more awesome. [Take a look for inspiration!](https://github.com/tevelee/Eval/tree/master/Examples/TemplateExample/Sources/TemplateExample/TemplateExample.swift)\n\nTogether, it makes an excellent addition to my model-object generation project, and **REALLY useful for server-side Swift development as well**!\n\n### [Attributed string parser](https://github.com/tevelee/Eval/blob/master/Examples/AttributedStringExample/Tests/AttributedStringExampleTests/AttributedStringExampleTests.swift)\n\nI created another small example, parsing attribtuted strings from simple expressions using XML style tags, such as bold, italic, underlined, colored, etc.\n\nWith just a few operators, this solution can deliver attributed strings from basic APIs, which otherwise would be hard to manage.\n\nMy connected project is an iOS application, using the Spotify [HUB framework](https://github.com/spotify/HubFramework), in which I can now provide rich strings with my view-models and parse them from the JSON string results.\n\n### [Color parser](https://github.com/tevelee/Eval/blob/master/Examples/ColorParserExample/Tests/ColorParserExampleTests/ColorParserExampleTests.swift)\n\nA color parser is also used by the BFF (Backend For Frontend, not 👭) project I mentioned before. It can parse Swift Color objects from many different styles of strings, such as `#ffddee`, or `red`, or `rgba(1,0.5,0.4,1)`. I included this basic example in the repository as well.\n\n## 🙋 Contribution\n\nAnyone is more than welcome to contribute to **Eval**! It can even be an addition to the docs or to the code directly, by [raising an issue](https://github.com/tevelee/Interpreter/issues/new) or in the form of a pull request. Both are equally valuable to me! Happy to assist anyone!\n\nIn case you need help or want to report a bug - please file an issue. Make sure to provide as much information as you can; sample code also makes it a lot easier for me to help you. Check out the [contribution guidelines](https://github.com/tevelee/Eval/tree/master/CONTRIBUTING.md) for further information. \n\nI collected some use cases, and great opportunities for beginner tasks if anybody is motivated to bring this project to a more impressive state!\n\n## 👀 Details\n\nPlease check out [https://tevelee.github.io/Eval](https://tevelee.github.io/Eval) for the more detailed documentation pages!\n\n## 👤 Author\n\nI am Laszlo Teveli, software engineer, iOS evangelist. In my free time I like to work on my hobby projects and open sourcing them 😉\n\nFeel free to reach out to me anytime via `tevelee [at] gmail [dot] com`, or `@tevelee` on Twitter.\n\n## ⚖️ License\n\n**Eval** is available under the Apache 2.0 licensing rules. See the [LICENSE](https://github.com/tevelee/Eval/tree/master/LICENSE.txt) file for more information.\n"
  },
  {
    "path": "Scripts/.gitignore",
    "content": ".DS_Store\n/.build\n/Packages\n/*.xcodeproj\n"
  },
  {
    "path": "Scripts/.swiftlint.yml",
    "content": "disabled_rules:\n  - force_try\n  - file_header\n  - file_length\n  - explicit_top_level_acl\n  - function_body_length\n"
  },
  {
    "path": "Scripts/Package.swift",
    "content": "// swift-tools-version:4.2\n\nimport PackageDescription\n\nlet package = Package(\n    name: \"Automation\",\n    dependencies: [\n        .package(url: \"https://github.com/xcodeswift/xcproj.git\", from: \"4.0.0\"),\n        ],\n    targets: [\n        .target(\n            name: \"Automation\",\n            dependencies: [\"xcproj\"]),\n        ]\n)\n"
  },
  {
    "path": "Scripts/Sources/Automation/Error.swift",
    "content": "import Foundation\n\nenum CIError: Error {\n    case invalidExitCode(statusCode: Int32, errorOutput: String?)\n    case timeout\n    case logicalError(message: String)\n}\n"
  },
  {
    "path": "Scripts/Sources/Automation/Eval.swift",
    "content": "import Foundation\nimport PathKit\nimport xcproj\n\nclass Eval {\n    static func main() {\n        print(\"💁🏻‍♂️ Job type: \\(TravisCI.jobType().description)\")\n\n        if isSpecificJob() {\n            return\n        }\n\n        if TravisCI.isPullRquestJob() || Shell.nextArg(\"--env\") == \"pr\" {\n            runPullRequestLane()\n        } else {\n            runContinousIntegrationLane()\n        }\n    }\n\n    static func runPullRequestLane() {\n        runCommands(\"Building Pull Request\") {\n            try prepareForBuild()\n            try build()\n            try runTests()\n\n            try prepareExamplesForBuild()\n            try buildExamples()\n            try runTestsOnExamples()\n\n            try runLinter()\n            try runDanger()\n        }\n    }\n\n    static func runContinousIntegrationLane() {\n        runCommands(\"Building CI\") {\n            try prepareForBuild()\n            try build()\n            try runTests()\n\n            try prepareExamplesForBuild()\n            try buildExamples()\n            try runTestsOnExamples()\n\n            try generateDocs()\n            try publishDocs()\n\n            try runLinter()\n            try runCocoaPodsLinter()\n\n            try testCoverage()\n\n            try runDanger()\n\n            try releaseNewVersion()\n        }\n    }\n\n    static func isSpecificJob() -> Bool {\n        guard let jobsString = Shell.nextArg(\"--jobs\") else { return false }\n        let jobsToRun = jobsString.split(separator: \",\").map { String($0) }\n        let jobsFound = jobsToRun.compactMap { job in jobs.first { $0.key == job } }\n        runCommands(\"Executing jobs: \\(jobsString)\") {\n            if let job = jobsToRun.first(where: { !self.jobs.keys.contains($0) }) {\n                throw CIError.logicalError(message: \"Job not found: \\(job)\")\n            }\n            try jobsFound.forEach {\n                print(\"🏃🏻 Running job \\($0.key)\")\n                try $0.value()\n            }\n        }\n        return !jobsFound.isEmpty\n    }\n\n    static func runCommands(_ title: String, commands: () throws -> Void) {\n        do {\n            if !TravisCI.isRunningLocally() {\n                print(\"travis_fold:start: \\(title)\")\n            }\n\n            print(\"ℹ️ \\(title)\")\n            try commands()\n\n            if !TravisCI.isRunningLocally() {\n                print(\"travis_fold:end: \\(title)\")\n            }\n\n            print(\"🎉 Finished successfully\")\n        } catch let CIError.invalidExitCode(statusCode, errorOutput) {\n            print(\"😢 Error happened: [InsufficientExitCode] \", errorOutput ?? \"unknown error\")\n            exit(statusCode)\n        } catch let CIError.logicalError(message) {\n            print(\"😢 Error happened: [LogicalError] \", message)\n            exit(-1)\n        } catch CIError.timeout {\n            print(\"🕙 Timeout\")\n            exit(-1)\n        } catch {\n            print(\"😢 Error happened [General]\")\n            exit(-1)\n        }\n    }\n\n    // MARK: Tasks\n\n    static let jobs: [String: () throws -> Void] = [\n        \"prepareForBuild\": prepareForBuild,\n        \"prepareExamplesForBuild\": prepareExamplesForBuild,\n        \"build\": build,\n        \"buildExamples\": buildExamples,\n        \"runTests\": runTests,\n        \"runTestsOnExamples\": runTestsOnExamples,\n        \"runLinter\": runLinter,\n        \"generateDocs\": generateDocs,\n        \"publishDocs\": publishDocs,\n        \"runCocoaPodsLinter\": runCocoaPodsLinter,\n        \"testCoverage\": testCoverage,\n        \"runDanger\": runDanger\n    ]\n\n    static func prepareForBuild() throws {\n        if TravisCI.isRunningLocally() {\n            print(\"🔦 Install dependencies\")\n            try Shell.executeAndPrint(\"rm -f Package.resolved\")\n            try Shell.executeAndPrint(\"rm -rf .build\")\n            try Shell.executeAndPrint(\"rm -rf build\")\n            try Shell.executeAndPrint(\"rm -rf Eval.xcodeproj\")\n            try Shell.executeAndPrint(\"bundle install\")\n        }\n\n        print(\"🤖 Generating project file\")\n        try Shell.executeAndPrint(\"swift package generate-xcodeproj --enable-code-coverage\")\n    }\n\n    static func build() throws {\n        print(\"♻️ Building\")\n        try Shell.executeAndPrint(\"swift build\", timeout: 120)\n        try Shell.executeAndPrint(\"xcodebuild clean build -configuration Release -scheme Eval-Package | bundle exec xcpretty --color\", timeout: 120)\n    }\n\n    static func runTests() throws {\n        print(\"👀 Running automated tests\")\n        try Shell.executeAndPrint(\"swift test\", timeout: 120)\n        try Shell.executeAndPrint(\"xcodebuild test -configuration Release -scheme Eval-Package -enableCodeCoverage YES | bundle exec xcpretty --color\", timeout: 120)\n    }\n\n    static func runLinter() throws {\n        print(\"👀 Running linter\")\n        try Shell.executeAndPrint(\"swiftlint lint\", timeout: 60)\n    }\n\n    static func generateDocs() throws {\n        print(\"📚 Generating documentation\")\n        try Shell.executeAndPrint(\"bundle exec jazzy --config .jazzy.yml\", timeout: 120)\n    }\n\n    static func publishDocs() throws {\n        print(\"📦 Publishing documentation\")\n\n        let dir = \"gh-pages\"\n        let file = \"github_rsa\"\n        defer {\n            print(\"📦 ✨ Cleaning up\")\n            try! Shell.executeAndPrint(\"rm -f \\(file)\")\n            try! Shell.executeAndPrint(\"rm -rf \\(dir)\")\n            try! Shell.executeAndPrint(\"rm -rf Documentation/Output\")\n        }\n\n        if TravisCI.isRunningLocally() {\n            print(\"📦 ✨ Preparing\")\n            try Shell.executeAndPrint(\"rm -rf \\(dir)\")\n        }\n\n        if let repo = currentRepositoryUrl()?.replacingOccurrences(of: \"https://github.com/\", with: \"git@github.com:\") {\n            let branch = \"gh-pages\"\n\n            print(\"📦 📥 Fetching previous docs\")\n            try Shell.executeAndPrint(\"git clone --depth 1 -b \\(branch) \\(repo) \\(dir)\", timeout: 30)\n\n            print(\"📦 📄 Updating to the new one\")\n            try Shell.executeAndPrint(\"cp -Rf Documentation/Output/ \\(dir)\")\n\n            print(\"📦 👉 Committing\")\n            try Shell.executeAndPrint(\"git -C \\(dir) add .\")\n            try Shell.executeAndPrint(\"git -C \\(dir) commit -m 'Automatic documentation update'\")\n            try Shell.executeAndPrint(\"git -C \\(dir) add .\")\n\n            print(\"📦 📤 Pushing\")\n            let remote = \"origin\"\n            try Shell.executeAndPrint(\"git -C \\(dir) push --force \\(remote) \\(branch)\", timeout: 30)\n        } else {\n            throw CIError.logicalError(message: \"Repository URL not found\")\n        }\n    }\n\n    static func runCocoaPodsLinter() throws {\n        print(\"🔮 Validating CocoaPods support\")\n        let flags = TravisCI.isRunningLocally() ? \"--verbose\" : \"\"\n        try Shell.executeAndPrint(\"export EXPANDED_CODE_SIGN_IDENTITY=-\", timeout: 10)\n        try Shell.executeAndPrint(\"export EXPANDED_CODE_SIGN_IDENTITY_NAME=-\", timeout: 10)\n        try Shell.executeAndPrint(\"bundle exec pod lib lint \\(flags)\", timeout: 300)\n    }\n\n    static func testCoverage() throws {\n        defer {\n            print(\"📦 ✨ Cleaning up\")\n            try! Shell.executeAndPrint(\"rm -f Eval.framework.coverage.txt\")\n            try! Shell.executeAndPrint(\"rm -f EvalTests.xctest.coverage.txt\")\n        }\n\n        print(\"☝🏻 Uploading code test coverage data\")\n        try Shell.executeAndPrint(\"bash <(curl -s https://codecov.io/bash) -J Eval\", timeout: 120)\n    }\n\n    static func runDanger() throws {\n        if TravisCI.isRunningLocally() {\n            print(\"⚠️ Running Danger in local mode\")\n            try Shell.executeAndPrint(\"bundle exec danger pr --verbose || true\", timeout: 120)\n        } else if TravisCI.isPullRquestJob() {\n            print(\"⚠️ Running Danger\")\n            try Shell.executeAndPrint(\"bundle exec danger --verbose || true\", timeout: 120)\n        }\n    }\n\n    static func releaseNewVersion() throws {\n        guard case .travisPushOnBranch(_) = TravisCI.jobType() else { return }\n\n        if let message = try commitMessage() {\n            let message = message.trimmingCharacters(in: .whitespacesAndNewlines)\n            let regex = try NSRegularExpression(pattern: \"^Version (\\\\d{1,2}\\\\.\\\\d{1,2}\\\\.\\\\d{1,2})$\")\n            let matches = regex.numberOfMatches(in: message, range: NSRange(message.startIndex..., in: message))\n            if matches > 0, let currentTag = try Shell.execute(\"git show HEAD~1:.version\")?.output {\n                let currentTag = currentTag.trimmingCharacters(in: .whitespacesAndNewlines)\n                let tag = message.replacingOccurrences(of: \"Version \", with: \"\")\n\n                guard let tags = try Shell.execute(\"git tag -l\")?.output?.components(separatedBy: .whitespacesAndNewlines),\n                    !tags.contains(tag) else { return }\n\n                print(\"🤖 Applying new version \\(tag) in project\")\n                let files = [\"README.md\", \".version\", \"Eval.podspec\"]\n                for file in files {\n                    try Shell.executeAndPrint(\"sed -i '' 's/\\(currentTag)/\\(tag)/g' \\(file)\")\n                    try Shell.executeAndPrint(\"git add \\(file)\")\n                }\n                try Shell.executeAndPrint(\"git commit --amend --no-edit\")\n\n                print(\"🔖 Tagging \\(tag)\")\n                try Shell.executeAndPrint(\"git tag \\(tag) HEAD\")\n\n                print(\"💁🏻 Pushing changes\")\n                try Shell.executeAndPrint(\"git remote add ssh_origin git@github.com:tevelee/Eval.git\")\n                try Shell.executeAndPrint(\"git push ssh_origin HEAD:master --force\")\n                try Shell.executeAndPrint(\"git push ssh_origin HEAD:master --force --tags\")\n\n                print(\"📦 Releasing package managers\")\n                try Shell.executeAndPrint(\"pod trunk push . || true\", timeout: 600)\n            }\n        }\n    }\n\n    static func prepareExamplesForBuild() throws {\n        print(\"🤖 Generating project files for Examples\")\n        try onAllExamples { _ in\n            let cleanup = [\n                \"rm -f Package.resolved\",\n                \"rm -rf .build\",\n                \"rm -rf build\"\n            ]\n            let build = [\n                \"swift package generate-xcodeproj\"\n            ]\n            return (cleanup + build).joined(separator: \" && \")\n        }\n\n        try performManualSteps()\n    }\n\n    static func buildExamples() throws {\n        print(\"♻️ Building Examples\")\n        try onAllExamples { example in\n            \"xcodebuild clean build -scheme \\(example)-Package | bundle exec xcpretty --color\"\n        }\n    }\n\n    static func runTestsOnExamples() throws {\n        print(\"👀 Running automated tests on Examples\")\n        try onAllExamples { example in\n            \"xcodebuild test -scheme \\(example)-Package | bundle exec xcpretty --color\"\n        }\n    }\n\n    // MARK: Helpers\n\n    static func onAllExamples(_ command: (String) throws -> String) throws {\n        for (name, directory) in try examples() {\n            let commands = [\n                \"pushd \\(directory)\",\n                try command(name),\n                \"popd\"\n            ]\n            try Shell.executeAndPrint(commands.joined(separator: \" && \"), timeout: 120)\n        }\n    }\n\n    static func examples() throws -> [(name: String, directory: String)] {\n        let directory = \"Examples\"\n        return try FileManager.default.contentsOfDirectory(atPath: directory).map { ($0, \"\\(directory)/\\($0)\") }.filter { !$0.name.hasPrefix(\".\") }\n    }\n\n    static func currentRepositoryUrl(dir: String = \".\") -> String? {\n        if let command = try? Shell.execute(\"git -C \\(dir) config --get remote.origin.url\"),\n            let output = command?.output?.trimmingCharacters(in: .whitespacesAndNewlines), !output.isEmpty {\n            return output\n        }\n        return nil\n    }\n\n    static func currentBranch(dir: String = \".\") -> String? {\n        if let command = try? Shell.execute(\"git -C \\(dir) rev-parse --abbrev-ref HEAD\"),\n            let output = command?.output?.trimmingCharacters(in: .whitespacesAndNewlines), !output.isEmpty {\n            return output\n        }\n        return nil\n    }\n\n    static func commitMessage(dir: String = \".\") throws -> String? {\n        if TravisCI.isRunningLocally() {\n            return try Shell.execute(\"git -C \\(dir) log -1 --pretty=%B\")?.output\n        } else {\n            return Shell.env(name: \"TRAVIS_COMMIT_MESSAGE\")\n        }\n    }\n\n    // MARK: Manual steps\n\n    static func performManualSteps() throws {\n        try performManualStepsForTemplateExample()\n    }\n\n    static func performManualStepsForTemplateExample() throws {\n        let example = \"TemplateExample\"\n        print(\"⏳ Configuring \\(example)\")\n\n        let base = Path(\"Examples/\\(example)/\")\n        let path = Path(\"\\(base)/\\(example).xcodeproj\")\n        let project = try XcodeProj(path: path)\n\n        let testsGroup = project.pbxproj.objects.groups.first { $0.value.name == \"\\(example)Tests\" }\n\n        let phase = PBXResourcesBuildPhase()\n        let ref = project.pbxproj.objects.generateReference(phase, \"CopyResourcesBuildPhase\")\n        project.pbxproj.objects.addObject(phase, reference: ref)\n\n        if let target = project.pbxproj.objects.targets(named: \"\\(example)Tests\").first {\n            target.object.buildPhases.append(ref)\n        }\n\n        let tests = Path(\"\\(base)/Tests/\\(example)Tests\")\n        let files = try tests.children().compactMap { $0.components.last }.filter { $0.hasSuffix(\"txt\") }\n        for file in files {\n            let fileRef = PBXFileReference(sourceTree: .group, name: nil, path: file)\n            fileRef.fileEncoding = 4 //utf8\n            let ref = project.pbxproj.objects.generateReference(fileRef, file)\n            project.pbxproj.objects.fileReferences.append(fileRef, reference: ref)\n\n            let buildFile = PBXBuildFile(fileRef: ref)\n            let buildFileRef = project.pbxproj.objects.generateReference(buildFile, file)\n            project.pbxproj.objects.buildFiles.append(buildFile, reference: buildFileRef)\n\n            testsGroup?.value.children.append(ref)\n            phase.files.append(buildFileRef)\n        }\n\n        try project.writePBXProj(path: path)\n        print(\"🤖 Generated project file\")\n    }\n}\n"
  },
  {
    "path": "Scripts/Sources/Automation/Shell.swift",
    "content": "import Foundation\n\nclass Shell {\n    static func executeAndPrint(_ command: String, timeout: Double = 10, allowFailure: Bool = false) throws {\n        print(\"$ \\(command)\")\n        let output = try executeShell(commandPath: \"/bin/bash\", arguments: [\"-c\", command], timeout: timeout, allowFailure: allowFailure) {\n            print($0, separator: \"\", terminator: \"\")\n        }\n        if let error = output?.error {\n            print(error)\n        }\n    }\n\n    static func execute(_ command: String, timeout: Double = 10, allowFailure: Bool = false) throws -> (output: String?, error: String?)? {\n        return try executeShell(commandPath: \"/bin/bash\", arguments: [\"-c\", command], timeout: timeout, allowFailure: allowFailure)\n    }\n\n    static func bash(commandName: String,\n                     arguments: [String] = [],\n                     timeout: Double = 10,\n                     allowFailure: Bool = false) throws -> (output: String?, error: String?)? {\n        guard let execution = try? executeShell(commandPath: \"/bin/bash\" ,\n                                                arguments: [ \"-l\", \"-c\", \"/usr/bin/which \\(commandName)\" ],\n                                                timeout: 1),\n            var whichPathForCommand = execution?.output else { return nil }\n\n        whichPathForCommand = whichPathForCommand.trimmingCharacters(in: NSCharacterSet.whitespacesAndNewlines)\n        return try executeShell(commandPath: whichPathForCommand, arguments: arguments, timeout: timeout, allowFailure: allowFailure)\n    }\n\n    static func executeShell(commandPath: String,\n                             arguments: [String] = [],\n                             timeout: Double = 10,\n                             allowFailure: Bool = false,\n                             stream: @escaping (String) -> Void = { _ in }) throws -> (output: String?, error: String?)? {\n        let task = Process()\n        task.launchPath = commandPath\n        task.arguments = arguments\n\n        let pipeForOutput = Pipe()\n        task.standardOutput = pipeForOutput\n\n        let pipeForError = Pipe()\n        task.standardError = pipeForError\n        task.launch()\n\n        let fileHandle = pipeForOutput.fileHandleForReading\n        fileHandle.waitForDataInBackgroundAndNotify()\n\n        var outputData = Data()\n\n        func process(data: Data) {\n            outputData.append(data)\n            if let output = String(data: data, encoding: .utf8) {\n                stream(output)\n            }\n        }\n\n        let observer = NotificationCenter.default.addObserver(forName: Notification.Name.NSFileHandleDataAvailable, object: fileHandle, queue: nil) { notification in\n            if let noitificationFileHandle = notification.object as? FileHandle {\n                process(data: noitificationFileHandle.availableData)\n                noitificationFileHandle.waitForDataInBackgroundAndNotify()\n            }\n        }\n\n        defer {\n            NotificationCenter.default.removeObserver(observer)\n        }\n\n        var shouldTimeout = false\n        DispatchQueue.main.asyncAfter(deadline: .now() + timeout) {\n            if task.isRunning {\n                shouldTimeout = true\n                task.terminate()\n            }\n        }\n\n        task.waitUntilExit()\n\n        process(data: fileHandle.readDataToEndOfFile())\n\n        if shouldTimeout {\n            throw CIError.timeout\n        }\n\n        let output = String(data: outputData, encoding: .utf8)\n\n        let errorData = pipeForError.fileHandleForReading.readDataToEndOfFile()\n        let error = String(data: errorData, encoding: .utf8)\n\n        let exitCode = task.terminationStatus\n        if exitCode > 0 && !allowFailure {\n            throw CIError.invalidExitCode(statusCode: exitCode, errorOutput: error)\n        }\n\n        return (output, error)\n    }\n\n    static func env(name: String) -> String? {\n        return ProcessInfo.processInfo.environment[name]\n    }\n\n    static func args() -> [String] {\n        return ProcessInfo.processInfo.arguments\n    }\n\n    static func nextArg(_ arg: String) -> String? {\n        if let index = Shell.args().index(of: arg), Shell.args().count > index + 1 {\n            return Shell.args()[index.advanced(by: 1)]\n        }\n        return nil\n    }\n}\n"
  },
  {
    "path": "Scripts/Sources/Automation/Travis.swift",
    "content": "import Foundation\n\nclass TravisCI {\n    enum JobType: CustomStringConvertible {\n        case local\n        case travisAPI\n        case travisCron\n        case travisPushOnBranch(branch: String)\n        case travisPushOnTag(name: String)\n        case travisPullRequest(branch: String, sha: String, slug: String)\n\n        var description: String {\n            switch self {\n            case .local:\n                return \"Local\"\n            case .travisAPI:\n                return \"Travis (API)\"\n            case .travisCron:\n                return \"Travis (Cron job)\"\n            case .travisPushOnBranch(let branch):\n                return \"Travis (Push on branch '\\(branch)')\"\n            case .travisPushOnTag(let name):\n                return \"Travis (Push of tag '\\(name)')\"\n            case .travisPullRequest(let branch):\n                return \"Travis (Pull Request on branch '\\(branch)')\"\n            }\n        }\n    }\n\n    static func isPullRquestJob() -> Bool {\n        return Shell.env(name: \"TRAVIS_EVENT_TYPE\") == \"pull_request\"\n    }\n\n    static func isRunningLocally() -> Bool {\n        return Shell.env(name: \"TRAVIS\") != \"true\"\n    }\n\n    static func isCIJob() -> Bool {\n        return !isRunningLocally() && !isPullRquestJob()\n    }\n\n    static func jobType() -> JobType {\n        if isRunningLocally() {\n            return .local\n        } else if isPullRquestJob() {\n            return .travisPullRequest(branch: Shell.env(name: \"TRAVIS_PULL_REQUEST_BRANCH\") ?? \"\",\n                                      sha: Shell.env(name: \"TRAVIS_PULL_REQUEST_SHA\") ?? \"\",\n                                      slug: Shell.env(name: \"TRAVIS_PULL_REQUEST_SLUG\") ?? \"\")\n        } else if Shell.env(name: \"TRAVIS_EVENT_TYPE\") == \"cron\" {\n            return .travisCron\n        } else if Shell.env(name: \"TRAVIS_EVENT_TYPE\") == \"api\" {\n            return .travisAPI\n        } else if let tag = Shell.env(name: \"TRAVIS_TAG\"), !tag.isEmpty {\n            return .travisPushOnTag(name: tag)\n        } else if let branch = Shell.env(name: \"TRAVIS_BRANCH\"), !branch.isEmpty {\n            return .travisPushOnBranch(branch: branch)\n        } else {\n            fatalError(\"Cannot identify job type\")\n        }\n    }\n}\n"
  },
  {
    "path": "Scripts/Sources/Automation/main.swift",
    "content": "import Foundation\n\nEval.main()\n"
  },
  {
    "path": "Scripts/ci.sh",
    "content": "#!/bin/bash\n\necho \"🤖 Assembling automation process\"\n\nroot=`git rev-parse --show-toplevel`\ncd \"$root/Scripts\"\nswift build\n\necho \"🏃 Running automation process\"\n\noutput=`swift build --show-bin-path`\ncd \"$root\"\n\"$output/automation\"\n"
  },
  {
    "path": "Scripts/git_auth.sh",
    "content": "#!/bin/bash\n\nopenssl aes-256-cbc -K $encrypted_f50468713ad3_key -iv $encrypted_f50468713ad3_iv -in github_rsa.enc -out github_rsa -d\nchmod 600 github_rsa\nssh-add github_rsa\nssh -o StrictHostKeyChecking=no git@github.com || true\ngit config --global user.email tevelee@gmail.com\ngit config --global user.name 'Travis CI'\n"
  },
  {
    "path": "Sources/Eval/Common.swift",
    "content": "/*\n *  Copyright (c) 2018 Laszlo Teveli.\n *\n *  Licensed to the Apache Software Foundation (ASF) under one\n *  or more contributor license agreements.  See the NOTICE file\n *  distributed with this work for additional information\n *  regarding copyright ownership.  The ASF licenses this file\n *  to you under the Apache License, Version 2.0 (the\n *  \"License\"); you may not use this file except in compliance\n *  with the License.  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing,\n *  software distributed under the License is distributed on an\n *  \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n *  KIND, either express or implied.  See the License for the\n *  specific language governing permissions and limitations\n *  under the License.\n */\n\nimport Foundation\n\n/// A protocol which is capable of evaluating string expressions to a strongly typed object\npublic protocol Evaluator {\n    /// The type of the evaluation result\n    associatedtype EvaluatedType\n\n    /// The only method in `Evaluator` protocol which does the evaluation of a string expression, and returns a strongly typed object\n    /// - parameter expression: The input\n    /// - returns: The evaluated value\n    func evaluate(_ expression: String) -> EvaluatedType\n}\n\n/// A special kind of evaluator which uses an `InterpreterContext` instance to evaluate expressions\n/// The context contains variables which can be used during the evaluation\npublic protocol EvaluatorWithLocalContext: Evaluator {\n    /// Evaluates the provided string expression with the help of the context parameter, and returns a strongly typed object\n    /// - parameter expression: The input\n    /// - parameter context: The local context if there is something expression specific needs to be provided\n    /// - returns: The evaluated value\n    func evaluate(_ expression: String, context: Context) -> EvaluatedType\n}\n\n/// The base protocol of interpreters, that are context-aware, and capable of recursively evaluating variables. They use the evaluate method as their main input\npublic protocol Interpreter: EvaluatorWithLocalContext {\n    /// The evaluator type to use when interpreting variables\n    associatedtype VariableEvaluator: EvaluatorWithLocalContext\n\n    /// The stored context object for helping evaluation and providing persistency\n    var context: Context { get }\n\n    /// Sometimes interpreters don't use themselves to evaluate variables by default, maybe a third party, or another contained interpreter. For example, the `StringTemplateInterpreter` class uses `TypedInterpreter` instance to evaluate its variables.\n    var interpreterForEvaluatingVariables: VariableEvaluator { get }\n}\n\n/// A protocol which is able to express custom values as Strings\npublic protocol Printer {\n    /// Converts its input parameter to a String value\n    /// - parameter input: The value to print\n    /// - returns: The converted String instance\n    func print(_ input: Any) -> String\n}\n\n/// Detailed information about recognised expressions\npublic struct ExpressionInfo {\n    /// The raw String input of the expression\n    var input: String\n    /// The generated output of the expression\n    var output: Any\n    /// A stringified version of the elements of the `Matcher` object\n    var pattern: String\n    /// The name of the pattern\n    var patternName: String\n    /// All the variables computed during the evaluation\n    var variables: [String: Any]\n}\n\n/// The only responsibility of the `InterpreterContext` class is to store variables, and keep them during the execution, where multiple expressions might use the same set of variables.\npublic class Context {\n    /// The stored variables\n    public var variables: [String: Any]\n\n    /// Debug information for recognised patterns\n    public var debugInfo: [String: ExpressionInfo] = [:]\n\n    /// Context can behave as a stack. If `push` is called, it saves a snapshot of the current state of variables to a stack and lets you modify the content, while the previous values are stored, safely.\n    /// When `pop` is called, it restores the last snapshot, destorying all the changes that happened after the last snapshot.\n    /// Useful for temporal variables!\n    var stack : [(variables: [String: Any], debugInfo: [String: ExpressionInfo])] = []\n\n    /// Users of the context may optionally provide an initial set of variables\n    /// - parameter variables: Variable names and values\n    public init(variables: [String: Any] = [:]) {\n        self.variables = variables\n    }\n\n    /// Context can behave as a stack. If `push` is called, it saves a snapshot of the current state of variables to a stack and lets you modify the content, while the previous values are stored, safely.\n    /// When `pop` is called, it restores the last snapshot, destorying all the changes that happened after the last snapshot.\n    /// Useful for temporal variables! It should be called before setting the temporal variables\n    public func push() {\n        stack.append((variables: variables, debugInfo: debugInfo))\n    }\n\n    /// Context can behave as a stack. If `push` is called, it saves a snapshot of the current state of variables to a stack and lets you modify the content, while the previous values are stored, safely.\n    /// When `pop` is called, it restores the last snapshot, destorying all the changes that happened after the last snapshot.\n    /// Useful for temporal variables! It should be called when the temporal variables are not needed anymore\n    public func pop() {\n        if let last = stack.popLast() {\n            variables = last.variables\n            debugInfo = last.debugInfo\n        }\n    }\n\n    /// Creates a new context instance by merging their variable dictionaries. The one in the parameter overrides the duplicated items of the existing one\n    /// - parameter with: The other context to merge with\n    /// - returns: A new `InterpreterContext` instance with the current and the parameter variables merged inside\n    public func merging(with other: Context?) -> Context {\n        if let other = other {\n            return Context(variables: other.variables.merging(self.variables) { eixstingValue, _ in eixstingValue })\n        } else {\n            return self\n        }\n    }\n\n    /// Modifies the current context instance by merging its variable dictionary with the parameter. The one in the parameter overrides the duplicated items of the existing one\n    /// - parameter with: The other context to merge with\n    /// - parameter existing: During the merge the parameter on the existing dictionary (same terminolody with Dictionary.merge)\n    /// - parameter new: During the merge the parameter on the merged dictionary (same terminolody with Dictionary.merge)\n    /// - returns: The same `InterpreterContext` instance after merging the variables dictionary with the variables in the context given as parameter\n    public func merge(with other: Context?, merge: (_ existing: Any, _ new: Any) throws -> Any) {\n        if let other = other {\n            try? variables.merge(other.variables, uniquingKeysWith: merge)\n        }\n    }\n}\n\n/// This is where the `Matcher` is able to determine the `MatchResult` for a given input inside the provided substring range\n/// - parameter amongst: All the `Matcher` instances to evaluate, in priority order\n/// - parameter in: The input\n/// - parameter from: The start of the checked range\n/// - parameter interpreter: An interpreter instance - if variables need any further evaluation\n/// - parameter context: The context - if variables need any contextual information\n/// - parameter connectedRanges: Ranges of string indices that are connected with opening-closing tag pairs, respectively\n/// - returns: The result of the match operation\ninternal func matchStatement<T, E>(amongst statements: [Pattern<T, E>], in input: String, from start: String.Index? = nil, interpreter: E, context: Context, connectedRanges: [ClosedRange<String.Index>] = []) -> MatchResult<T> {\n    let results = statements.lazy.map { statement -> (element: Pattern<T, E>, result: MatchResult<T>) in\n        let result = statement.matches(string: input, from: start, interpreter: interpreter, context: context, connectedRanges: connectedRanges)\n        return (element: statement, result: result)\n    }\n    if let matchingElement = results.first(where: { $0.result.isMatch() }) {\n        return matchingElement.result\n    } else if results.contains(where: { $0.result.isPossibleMatch() }) {\n        return .possibleMatch\n    }\n    return .noMatch\n}\n\n/// Independent helper function that determines the pairs of opening and closing keywords\n/// - parameter input: The input string to search ranges in\n/// - parameter statements: Patterns that contain the opening and closing keyword types that should be matched\n/// - returns: The ranges of opening-closing pairs, keeping logical hierarchy\ninternal func collectConnectedRanges(input: String, statements: [Pattern<Any, TypedInterpreter>]) -> [ClosedRange<String.Index>] {\n    return statements.compactMap { pattern -> [ClosedRange<String.Index>] in\n        let keywords = pattern.elements.compactMap { $0 as? Keyword }\n        let openingKeywords = keywords.filter { $0.type == .openingStatement }\n        let closingKeywords = keywords.filter { $0.type == .closingStatement }\n\n        guard !openingKeywords.isEmpty && !closingKeywords.isEmpty else { return [] }\n\n        var ranges: [ClosedRange<String.Index>] = []\n        var rangeStart: [String.Index] = []\n        var position = input.startIndex\n        repeat {\n            let relevantInput = input[position...]\n            let start = openingKeywords\n                .first { relevantInput.contains($0.name) }\n                .flatMap { relevantInput.range(of: $0.name)?.lowerBound }\n            let end = closingKeywords\n                .first { relevantInput.contains($0.name) }\n                .flatMap { relevantInput.range(of: $0.name)?.lowerBound }\n            if let start = start, let end = end {\n                if start < end {\n                    rangeStart.append(start)\n                } else {\n                    let lastOpening = rangeStart.removeLast()\n                    ranges.append(lastOpening...end)\n                }\n                position = input.index(after: min(start, end))\n            } else if let start = start {\n                rangeStart.append(start)\n                position = input.index(after: start)\n            } else if let end = end {\n                if rangeStart.isEmpty {\n                    return []\n                }\n                let lastOpening = rangeStart.removeLast()\n                ranges.append(lastOpening...end)\n                position = input.index(after: end)\n            } else {\n                break\n            }\n        } while position < input.endIndex\n\n        return ranges\n    }.reduce([], +)\n}\n"
  },
  {
    "path": "Sources/Eval/Elements.swift",
    "content": "/*\n *  Copyright (c) 2018 Laszlo Teveli.\n *\n *  Licensed to the Apache Software Foundation (ASF) under one\n *  or more contributor license agreements.  See the NOTICE file\n *  distributed with this work for additional information\n *  regarding copyright ownership.  The ASF licenses this file\n *  to you under the Apache License, Version 2.0 (the\n *  \"License\"); you may not use this file except in compliance\n *  with the License.  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing,\n *  software distributed under the License is distributed on an\n *  \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n *  KIND, either express or implied.  See the License for the\n *  specific language governing permissions and limitations\n *  under the License.\n */\n\nimport Foundation\n\n/// `MatchElement`s are used by `Matcher` instances to be able to recognise patterns.\n/// Currently, the two main kind of `MatchElement` classes are `Keyword`s and `Variable`s\npublic protocol PatternElement {\n    /// Using this method, an element returns how much the String provided in the `prefix` parameter matches the current element\n    /// - parameter prefix: The input\n    /// - parameter options: Options that modify the matching algorithm\n    /// - returns: The result of the match operation\n    func matches(prefix: String, options: PatternOptions) -> MatchResult<Any>\n}\n\n/// `Keyword` instances are used to provide static points in match sequences so that they can be used as pillars of the expressions the developer tries to match\npublic class Keyword: PatternElement, Equatable {\n    /// The type of the Keyword determines whether the item holds some special purpose, or it's just an ordinary static String\n    public enum KeywordType: Equatable {\n        /// By default, `Keyword` is created as a generic type, meaning, that there is no special requirement, that they need to fulfil\n        case generic\n        /// If a pattern contains two, semantically paired `Keyword`s, they often represent opening and closing parentheses or any special enclosing characters.\n        /// This case represents the first one of the pair, needs to be matched. Often these are expressed as opening parentheses, e.g. `(`\n        case openingStatement\n        /// If a pattern contains two, semantically paired `Keyword`s, they often represent opening and closing parentheses or any special enclosing characters.\n        /// This case represents the second (and last) one of the pair, needs to be matched. Often these are expressed as closing parentheses, e.g. `)`\n        case closingStatement\n    }\n\n    /// Name (and value) of the `Keyword`\n    let name: String\n\n    /// Type of the keyword, which gives the framework some extra semantics about its nature\n    let type: KeywordType\n\n    /// `Keyword` initialiser\n    /// - parameter name: The name (and value) of the `Keyword`\n    /// - parameter type: Type of the keyword, which gives the framework some extra semantics about its nature. Defaults to `KeywordType.generic`\n    public init(_ name: String, type: KeywordType = .generic) {\n        self.name = name.trim()\n        self.type = type\n    }\n\n    /// `Keyword` instances are returning exactMatch, when they are equal to the `prefix` input.\n    /// If the input is really just a prefix of the keyword, possible metch is returned. noMatch otherwise.\n    /// - parameter prefix: The input\n    /// - parameter options: Options that modify the matching algorithm\n    /// - returns: The result of the match operation\n    public func matches(prefix: String, options: PatternOptions = []) -> MatchResult<Any> {\n        let checker = options.contains(.backwardMatch) ? String.hasSuffix : String.hasPrefix\n        if name == prefix || checker(prefix)(name) {\n            return .exactMatch(length: name.count, output: name, variables: [:])\n        } else if checker(name)(prefix) {\n            return .possibleMatch\n        }\n        return .noMatch\n    }\n\n    /// `Keyword` instances are `Equatable`s\n    /// - parameter lhs: Left hand side\n    /// - parameter rhs: Right hand side\n    /// - returns: Whether the names and types are equal in `lhs` and `rhs`\n    public static func == (lhs: Keyword, rhs: Keyword) -> Bool {\n        return lhs.name == rhs.name && lhs.type == rhs.type\n    }\n}\n\n/// A special subclass of the `Keyword` class, which initialises a `Keyword` with an opening type.\n/// Usually used for opening parentheses: `OpenKeyword(\"[\")`\npublic class OpenKeyword: Keyword {\n    /// The initialiser uses the opening type, but the `name` still must be provided\n    /// - parameter name: The name (and value) of the `Keyword`\n    public init(_ name: String) {\n        super.init(name, type: .openingStatement)\n    }\n}\n\n/// A special subclass of the `Keyword` class, which initialises a `Keyword` with an closing type.\n/// Usually used for closing parentheses: `CloseKeyword(\"]\")`\npublic class CloseKeyword: Keyword {\n    /// The initialiser uses the closing type, but the `name` still must be provided\n    /// - parameter name: The name (and value) of the `Keyword`\n    public init(_ name: String) {\n        super.init(name, type: .closingStatement)\n    }\n}\n\n/// Options that modify the behaviour of the variable matching, and the output that the framework provides\npublic struct VariableOptions: OptionSet {\n    /// Integer representation of the option\n    public let rawValue: Int\n    /// Basic initialiser with the integer representation\n    public init(rawValue: Int) {\n        self.rawValue = rawValue\n    }\n\n    /// If set, the value of the recognised placeholder will not be processed. Otherwise, it will be evaluated, using the `interpreterForEvaluatingVariables` property of the interpreter instance\n    public static let notInterpreted: VariableOptions = VariableOptions(rawValue: 1 << 0)\n    /// Whether the processed variable should be or not to be trimmed (removing whitespaces from both sides)\n    public static let notTrimmed: VariableOptions = VariableOptions(rawValue: 1 << 1)\n    /// Provides information whether the match should be exhaustive or just use the shortest possible matching string (even zero characters in some edge cases). This depends on the surrounding `Keyword` instances in the containing collection.\n    public static let exhaustiveMatch: VariableOptions = VariableOptions(rawValue: 1 << 2)\n    /// If interpreted and the result of the evaluation is `nil`, then `acceptsNilValue` determines if the current match result should be instant noMatch, or `nil` is an accepted value, so the matching should be continued\n    public static let acceptsNilValue: VariableOptions = VariableOptions(rawValue: 1 << 3)\n\n    /// In order to avoid double negatives in the source code (e.g. !notInterpreted), this helper checks the lack of .notInterpreted value in the optionset\n    var interpreted: Bool { return !contains(.notInterpreted) }\n    /// In order to avoid double negatives in the source code (e.g. !notTrimmed), this helper checks the lack of .notTrimmed value in the optionset\n    var trimmed: Bool { return !contains(.notTrimmed) }\n}\n\n/// Protocol for all Variables\ninternal protocol VariableProtocol {\n    /// Unique identifier of the variable that is used when matching and returning them in the matcher.\n    var name: String { get }\n    /// Options that modify the behaviour of the variable matching, and the output that the framework provides\n    var options: VariableOptions { get }\n    /// The result of the evaluated variable will be ran through this map function, transforming its value. By default the map tries to convert the matched value to the expected type, using the `as?` operator.\n    /// - parameter input: The first parameter is the value is going to be transformed\n    /// - parameter interpreter: Helps the mapper function to parse and interpret the contents\n    /// - returns: The transformed value or nil - if the value was validated with a negative result\n    func performMap(input: Any, interpreter: Any) -> Any?\n}\n\n/// It's a data transfer object passed in the `Variable` matcher block\npublic struct VariableBody<I: Interpreter> {\n    /// The raw value to match\n    public var value: Any\n    /// An interpreter instance if the raw value needs any further evaluation\n    public var interpreter: I\n}\n\n/// Generic superclass of `Variable`s which are aware of their `Interpreter` classes,\n/// as they use it when mapping their values\npublic class GenericVariable<T, I: Interpreter>: VariableProtocol, PatternElement, Equatable {\n    /// Maps and validates the variable value to another\n    /// - parameter body: Struct containing the raw matched value and an interpreter object\n    /// - returns: The transformed value or nil, if the value was validated with a negative result\n    public typealias VariableMapper<T, I: Interpreter> = (_ body: VariableBody<I>) -> T?\n\n    /// Unique identifier of the variable that is used when matching and returning them in the matcher.\n    let name: String\n    /// Options that modify the behaviour of the variable matching, and the output that the framework provides\n    let options: VariableOptions\n    /// The result of the evaluated variable will be running through this map function, transforming its value. By default the map tries to convert the matched value to the expected type, using the `as?` operator.\n    let map: VariableMapper<T, I>\n\n    /// Initialiser for all the properties\n    /// - parameter name: `GenericVariable`s have a name (unique identifier), that is used when matching and returning them in the matcher.\n    /// - parameter options: Options that modify the behaviour of the variable matching, and the output that the framework provides\n    /// - parameter map: If provided, then the result of the evaluated variable will be running through this map function. By default the map tries to convert the matched value to the expected type, using the `as?` operator. Defaults to identical map, using the `as?` operator for value transformation\n    public init(_ name: String,\n                options: VariableOptions = [],\n                map: @escaping VariableMapper<T, I> = { $0.value as? T }) {\n        self.name = name\n        self.options = options\n        self.map = map\n    }\n\n    /// `GenericVariables` always return anyMatch MatchResult, forwarding the shortest argument, provided during initialisation\n    /// - parameter prefix: The input\n    /// - returns: The result of the match operation. Always `anyMatch` with the shortest argument, provided during initialisation\n    public func matches(prefix: String, options: PatternOptions = []) -> MatchResult<Any> {\n        return .anyMatch(exhaustive: self.options.contains(.exhaustiveMatch))\n    }\n\n    /// A helper method to map the value of the current variable to another type\n    /// - parameter map: The transformation function\n    /// - parameter value: The value to be mapped\n    /// - returns: A new variable instance using the value mapper block\n    public func mapped<K>(_ map: @escaping (_ value: T) -> K?) -> GenericVariable<K, I> {\n        return GenericVariable<K, I>(name, options: options) {\n            guard let value = self.map($0) else { return nil }\n            return map(value)\n        }\n    }\n\n    /// The result of the evaluated variable will be ran through this map function, transforming its value. By default the map tries to convert the matched value to the expected type, using the `as?` operator.\n    /// - parameter input: The first parameter is the value is going to be transformed\n    /// - parameter interpreter: Helps the mapper function to parse and interpret the contents\n    /// - returns: The transformed value or nil - if the value was validated with a negative result\n    func performMap(input: Any, interpreter: Any) -> Any? {\n        guard let interpreter = interpreter as? I else { return nil }\n        return map(VariableBody(value: input, interpreter: interpreter))\n    }\n\n    public static func == (lhs: GenericVariable<T, I>, rhs: GenericVariable<T, I>) -> Bool {\n        return lhs.name == rhs.name && lhs.options == rhs.options\n    }\n}\n"
  },
  {
    "path": "Sources/Eval/TemplateInterpreter.swift",
    "content": "/*\n *  Copyright (c) 2018 Laszlo Teveli.\n *\n *  Licensed to the Apache Software Foundation (ASF) under one\n *  or more contributor license agreements.  See the NOTICE file\n *  distributed with this work for additional information\n *  regarding copyright ownership.  The ASF licenses this file\n *  to you under the Apache License, Version 2.0 (the\n *  \"License\"); you may not use this file except in compliance\n *  with the License.  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing,\n *  software distributed under the License is distributed on an\n *  \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n *  KIND, either express or implied.  See the License for the\n *  specific language governing permissions and limitations\n *  under the License.\n */\n\nimport Foundation\n\n/// This interpreter is used to evaluate string expressions and return a transformed string, replacing the content where it matches certain patterns.\n/// Typically used in web applications, where the rendering of an HTML page is provided as a template, and the application replaces certain statements, based on input parameters.\nopen class TemplateInterpreter<T>: Interpreter {\n    /// The statements (patterns) registered to the interpreter. If found, these are going to be processed and replaced with the evaluated value\n    public let statements: [Pattern<T, TemplateInterpreter<T>>]\n\n    /// The context used when evaluating the expressions. These context variables are global, used in every evaluation processed with this instance.\n    public let context: Context\n\n    /// The `StringTemplateInterpreter` contains a `TypedInterpreter`, as it is quite common practice to evaluate strongly typed expression as s support for the template language.\n    /// Common examples are: condition part of an if statement, or body of a print statement\n    public let typedInterpreter: TypedInterpreter\n\n    /// The evaluator type that is being used to process variables. By default, the TypedInterpreter is being used\n    public typealias VariableEvaluator = TypedInterpreter\n\n    /// The result type of a template evaluation\n    public typealias EvaluatedType = T\n\n    /// The evaluator, that is being used to process variables\n    public lazy var interpreterForEvaluatingVariables: TypedInterpreter = { typedInterpreter }()\n\n    /// The statements, and context parameters are optional, but highly recommended to use with actual values.\n    /// In order to properly initialise a `StringTemplateInterpreter`, you'll need a `TypedInterpreter` instance as well.\n    /// - parameter statements: The patterns that the interpreter should recognise\n    /// - parameter interpreter: A `TypedInterpreter` instance to evaluate typed expressions appearing in the template\n    /// - parameter context: Global context that is going to be used with every expression evaluated with the current instance. Defaults to empty context\n    public init(statements: [Pattern<T, TemplateInterpreter<T>>] = [],\n                interpreter: TypedInterpreter = TypedInterpreter(),\n                context: Context = Context()) {\n        self.statements = statements\n        self.typedInterpreter = interpreter\n        self.context = context\n    }\n\n    /// The main part of the evaluation happens here. In this case, only the global context variables are going to be used\n    /// - parameter expression: The input\n    /// - returns: The output of the evaluation\n    public func evaluate(_ expression: String) -> T {\n        return evaluate(expression, context: Context())\n    }\n\n    /// The main part of the evaluation happens here. In this case, the global context variables merged with the provided context are going to be used.\n    /// - parameter expression: The input\n    /// - parameter context: Local context that is going to be used with this expression only\n    /// - returns: The output of the evaluation\n    open func evaluate(_ expression: String, context: Context) -> T {\n        fatalError(\"Shouldn't instantiate `TemplateInterpreter` directly. Please subclass with a dedicated type instead\")\n    }\n\n    /// Reduce block can convet a stream of values into one, by calling this block for every element, returning a single value at the end. The concept is usually used in functional environments\n    /// - parameter existing: The previously computed value. In case the current iteration is the first, it's the inital value.\n    /// - parameter next: The value of the current element in the iteration\n    /// - returns: The a combined value based on the previous and the new value\n    public typealias Reducer<T, K> = (_ existing: T, _ next: K) -> T\n\n    /// In order to support generic types, not just plain String objects, a reducer helps to convert the output to the dedicated output type\n    /// - parameter initialValue: based on the type, an initial value must to be provided which can serve as a base of the output\n    /// - parameter reduceValue: during template execution, if there is some template to replace, the output value can be used to append to the previously existing output\n    /// - parameter reduceCharacter: during template execution, if there is nothing to replace, the value is computed by the character-by-character iteration, appending to the previously existing output\n    public typealias TemplateReducer = (initialValue: T, reduceValue: Reducer<T, T>, reduceCharacter: Reducer<T, Character>)\n\n    /// The main part of the evaluation happens here. In this case, the global context variables merged with the provided context are going to be used.\n    /// - parameter expression: The input\n    /// - parameter context: Local context that is going to be used with this expression only\n    /// - parameter reducer: In order to support generic types, not just plain String objects, a reducer helps to convert the output to the dedicated output type\n    /// - returns: The output of the evaluation\n    public func evaluate(_ expression: String, context: Context = Context(), reducer: TemplateReducer) -> T {\n        context.merge(with: self.context) { existing, _ in existing }\n        var output = reducer.initialValue\n\n        var position = expression.startIndex\n        repeat {\n            let result = matchStatement(amongst: statements, in: expression, from: position, interpreter: self, context: context)\n            switch result {\n            case .noMatch, .possibleMatch:\n                output = reducer.reduceCharacter(output, expression[position])\n                position = expression.index(after: position)\n            case let .exactMatch(length, matchOutput, _):\n                output = reducer.reduceValue(output, matchOutput)\n                position = expression.index(position, offsetBy: length)\n            default:\n                assertionFailure(\"Invalid result\")\n            }\n        } while position < expression.endIndex\n\n        return output\n    }\n}\n\n/// This interpreter is used to evaluate string expressions and return a transformed string, replacing the content where it matches certain patterns.\n/// Typically used in web applications, where the rendering of an HTML page is provided as a template, and the application replaces certain statements, based on input parameters.\npublic class StringTemplateInterpreter: TemplateInterpreter<String> {\n    /// The result of a template evaluation is a String\n    public typealias EvaluatedType = String\n\n    /// The main part of the evaluation happens here. In this case, the global context variables merged with the provided context are going to be used.\n    /// - parameter expression: The input\n    /// - parameter context: Local context that is going to be used with this expression only\n    /// - returns: The output of the evaluation\n    public override func evaluate(_ expression: String, context: Context) -> String {\n        guard !expression.isEmpty else { return \"\" }\n        return evaluate(expression, context: context, reducer: (initialValue: \"\",\n                                                                reduceValue: { existing, next in existing + next },\n                                                                reduceCharacter: { existing, next in existing + String(next) }))\n    }\n}\n\n/// A special kind of variable that is used in case of `StringTemplateInterpreter`s. It does not convert its content using the `interpreterForEvaluatingVariables` but always uses the `StringTemplateInterpreter` instance.\n/// It's perfect for expressions, that have a body, that needs to be further interpreted, such as an if or while statement.\npublic class TemplateVariable: GenericVariable<String, StringTemplateInterpreter> {\n    /// No changes compared to the initialiser of the superclass `Variable`, uses the same parameters\n    /// - parameter name: `GenericVariable`s have a name (unique identifier), that is used when matching and returning them in the matcher.\n    /// - parameter options: Options that modify the behaviour of the variable matching, and the output that the framework provides\n    /// - parameter map: If provided, then the result of the evaluated variable will be running through this map function\n    /// Whether the processed variable sould be trimmed (removing whitespaces from both sides). Defaults to `true`\n    public override init(_ name: String, options: VariableOptions = [], map: @escaping VariableMapper<String, StringTemplateInterpreter> = { $0.value as? String }) {\n        super.init(name, options: options.union(.notInterpreted)) {\n            guard let stringValue = $0.value as? String else { return \"\" }\n            let result = options.interpreted ? $0.interpreter.evaluate(stringValue) : stringValue\n            return map(VariableBody(value: result, interpreter: $0.interpreter))\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/Eval/TypedInterpreter.swift",
    "content": "/*\n *  Copyright (c) 2018 Laszlo Teveli.\n *\n *  Licensed to the Apache Software Foundation (ASF) under one\n *  or more contributor license agreements.  See the NOTICE file\n *  distributed with this work for additional information\n *  regarding copyright ownership.  The ASF licenses this file\n *  to you under the Apache License, Version 2.0 (the\n *  \"License\"); you may not use this file except in compliance\n *  with the License.  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing,\n *  software distributed under the License is distributed on an\n *  \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n *  KIND, either express or implied.  See the License for the\n *  specific language governing permissions and limitations\n *  under the License.\n */\n\nimport Foundation\n\n/// A type of interpreter implementation that is capable of evaluating arbitrary string expressions to strongly typed variables\npublic class TypedInterpreter: Interpreter, Printer {\n    /// The result is a strongly typed value or `nil` (if it cannot be properly processed)\n    public typealias EvaluatedType = Any?\n\n    /// The global context used for every evaluation with this instance\n    public let context: Context\n\n    /// The interpreter used for evaluating variable values. In case of the `TypedInterpreter`, it's itself\n    public lazy var interpreterForEvaluatingVariables: TypedInterpreter = { [unowned self] in self }()\n\n    /// The data types that the expression is capable of recognise\n    public let dataTypes: [DataTypeProtocol]\n\n    /// The list of functions that are available during the evaluation to process the recognised data types\n    public let functions: [FunctionProtocol]\n\n    /// A cache of functions where expressions have matched before. This improves the performance a lot, when computing already established functions\n    var functionCache: [String: FunctionProtocol] = [:]\n\n    /// A cache of data types where expressions have matched before. This improves the performance a lot, when computing already established data types\n    var dataTypeCache: [String: DataTypeProtocol] = [:]\n\n    /// Each item of the input list (data types, functions and the context) is optional, but strongly recommended to provide them. It's usual that for every data type, there are a few functions provided, so the list can occasionally be pretty long.\n    /// - parameter dataTypes: The types the interpreter should recognise the work with\n    /// - parameter functions: The functions that can operate on the dataTypes\n    /// - context: Global context that is going to be used with every expression evaluated with the current instance. Defaults to empty context\n    public init(dataTypes: [DataTypeProtocol] = [],\n                functions: [FunctionProtocol] = [],\n                context: Context = Context()) {\n        self.dataTypes = dataTypes\n        self.functions = functions\n        self.context = context\n    }\n\n    /// The evaluation method, that produces the strongly typed results. In this case, only the globally available context can be used\n    /// - parameter expression: The input\n    /// - returns: The output of the evaluation\n    public func evaluate(_ expression: String) -> Any? {\n        return evaluate(expression, context: Context())\n    }\n\n    /// The evaluation method, that produces the strongly typed results. In this case, only the context is a result of merging the global context and the one provided in the parameter\n    /// - parameter expression: The input\n    /// - parameter context: Local context that is going to be used with this expression only\n    /// - returns: The output of the evaluation\n    public func evaluate(_ expression: String, context: Context) -> Any? {\n        context.merge(with: self.context) { existing, _ in existing }\n        let expression = expression.trim()\n        let patterns = functions.compactMap { ($0 as? Function<Any>)?.patterns }.reduce([Pattern]()) { list, item in list + item }\n        let connectedRanges = collectConnectedRanges(input: expression, statements: patterns)\n\n        return functionFromCache(for: expression, using: context, connectedRanges: connectedRanges)\n            ?? dataTypeFromCache(for: expression)\n            ?? dataType(for: expression)\n            ?? variable(for: expression, using: context)\n            ?? function(for: expression, using: context, connectedRanges: connectedRanges)\n    }\n\n    /// If the expression belongs to a cached function, it uses the function converter to evaluate it\n    /// - parameter expression: The expression to evaluate\n    /// - parameter context: The context to be using when the evaluation happens\n    /// - parameter connectedRanges: Ranges of string indices that are connected with opening-closing tag pairs, respectively\n    /// - returns: The value - if the expression is interpreted. `nil` otherwise\n    func functionFromCache(for expression: String, using context: Context, connectedRanges: [ClosedRange<String.Index>]) -> Any? {\n        guard let cachedFunction = functionCache[expression],\n            let value = cachedFunction.convert(input: expression, interpreter: self, context: context, connectedRanges: connectedRanges) else { return nil }\n        return value\n    }\n\n    /// If the expression belongs to a cached data type, it uses the data type converter to evaluate it\n    /// - parameter expression: The expression to evaluate\n    /// - returns: The value - if the expression is interpreted. `nil` otherwise\n    func dataTypeFromCache(for expression: String) -> Any? {\n        guard let cachedDataType = dataTypeCache[expression],\n            let value = cachedDataType.convert(input: expression, interpreter: self) else { return nil }\n        return value\n    }\n\n    /// If the expression is recognised as a function, it uses that function to evaluate the value\n    /// - parameter expression: The expression to evaluate\n    /// - parameter context: The context to be using when the evaluation happens\n    /// - parameter connectedRanges: Ranges of string indices that are connected with opening-closing tag pairs, respectively\n    /// - returns: The value - if the expression is interpreted. `nil` otherwise\n    func function(for expression: String, using context: Context, connectedRanges: [ClosedRange<String.Index>]) -> Any? {\n        for function in functions.reversed() {\n            if let value = function.convert(input: expression, interpreter: self, context: context, connectedRanges: connectedRanges) {\n                functionCache[expression] = function\n                return value\n            }\n        }\n        return nil\n    }\n\n    /// If the expression is recognised as a data type, it uses that data type to convert its value\n    /// - parameter expression: The expression to evaluate\n    /// - parameter context: The context to be using when the evaluation happens\n    /// - returns: The value - if the expression is interpreted. `nil` otherwise\n    func dataType(for expression: String) -> Any? {\n        for dataType in dataTypes {\n            if let value = dataType.convert(input: expression, interpreter: self) {\n                dataTypeCache[expression] = dataType\n                return value\n            }\n        }\n        return nil\n    }\n\n    /// If the expression is recognised as a variable, it uses that variable to replace its value\n    /// - parameter expression: The expression to evaluate\n    /// - parameter context: The context where the variables are stored\n    /// - returns: The value - if the expression is interpreted. `nil` otherwise\n    func variable(for expression: String, using context: Context) -> Any? {\n        for variable in context.variables where expression == variable.key {\n            return variable.value\n        }\n        return nil\n    }\n\n    /// A helper to be able to effectively print any result, coming out of the evaluation. The `print` method recognises the used data type and uses its string conversion block\n    /// - parameter input: Any value that is a valid `DataType` or a `CustomStringConvertible` instance\n    /// - returns: The string representation of the value or empty string if it cannot be processed\n    public func print(_ input: Any) -> String {\n        for dataType in dataTypes {\n            if let value = dataType.print(value: input, printer: self) {\n                return value\n            }\n        }\n        if let input = input as? CustomStringConvertible {\n            return input.description\n        }\n        return \"\"\n    }\n}\n\n/// Data types tell the framework which kind of data can be parsed in the expressions\npublic protocol DataTypeProtocol {\n    /// If the framework meets with some static value that hasn't been processed before, it tries to convert it with every registered data type.\n    /// This method returns nil if the conversion could not have been processed with any of the type's literals.\n    /// - parameter input: The input to convert as a `DataType` value\n    /// - parameter interpreter: An interpreter instance if the content needs any further evaluation\n    /// - returns: The value of the `DataType` or `nil` if it cannot be processed\n    func convert(input: String, interpreter: TypedInterpreter) -> Any?\n\n    /// This is a convenience method, for debugging and value printing purposes, which can return a string from the current data type.\n    /// It does not need to be unique or always the same for the same input values.\n    /// - parameter input: Any value that is a valid `DataType`\n    /// - parameter printer: An interpreter instance if the content recursively contains further data types to print\n    /// - returns: The string representation of the value or `nil` if it cannot be processed\n    func print(value input: Any, printer: Printer) -> String?\n}\n\n/// It's a data transfer object passed in the `DataType` converter block\npublic struct DataTypeBody<T> {\n    /// Value of the data type to match\n    public var value: T\n    /// A printer instance to use to Stringify the value\n    public var printer: Printer\n}\n\n/// The implementation of a `DataType` uses the `DataTypeProtocol` to convert input to a strongly typed data and print it if needed\npublic class DataType<T>: DataTypeProtocol {\n    /// The existing type to map to an internal one\n    let type: T.Type\n    /// Array of literals that tell the framework how to transform certain types to an internal `DataType` representation\n    let literals: [Literal<T>]\n    /// A method to convert an internal representation to strings - for debugging and output representation purposes\n    /// - parameter body: Struct containing the value and a printer instance\n    /// - parameter printer: An interpreter instance if the content recursively contains further data types to print\n    private let print: (_ body: DataTypeBody<T>) -> String\n\n    /// To be able to bridge the outside world effectively, it needs to provide an already existing Swift or user-defined type. This can be class, struct, enum, or anything else, for example, block or function (which is not recommended).\n    /// The literals tell the framework which strings can be represented in the given data type\n    /// The last print block is used to convert the value of any DataType to a string value. It does not need to be unique or always the same for the same input values.\n    /// - parameter type: The existing type to map to an internal one\n    /// - parameter literals: Array of literals that tell the framework how to transform certain types to an internal `DataType` representation\n    /// - parameter print: A method to convert an internal representation to strings - for debugging and output representation purposes\n    /// - parameter body: Struct containing the value and a printer instance\n    public init (type: T.Type,\n                 literals: [Literal<T>],\n                 print: @escaping (_ body: DataTypeBody<T>) -> String) {\n        self.type = type\n        self.literals = literals\n        self.print = print\n    }\n\n    /// For the conversion it uses the registered literals, to be able to process the input and return an existing type\n    /// - parameter input: The input to convert as a `DataType` value\n    /// - parameter interpreter: An interpreter instance if the content needs any further evaluation\n    /// - returns: The value of the `DataType` or `nil` if it cannot be processed\n    public func convert(input: String, interpreter: TypedInterpreter) -> Any? {\n        return literals.compactMap { $0.convert(input: input, interpreter: interpreter) }.first\n    }\n\n    /// This is a convenience method, for debugging and value printing purposes, which can return a string from the current data type.\n    /// It does not need to be unique or always the same for the same input values.\n    /// - parameter value: Any value that is a valid `DataType`\n    /// - parameter printer: An interpreter instance if the content recursively contains further data types to print\n    /// - returns: The string representation of the value or `nil` if it cannot be processed\n    public func print(value input: Any, printer: Printer) -> String? {\n        guard let input = input as? T else { return nil }\n        return self.print(DataTypeBody(value: input, printer: printer))\n    }\n}\n\n/// It's a data transfer object passed in the `Literal` converter block\npublic struct LiteralBody {\n    /// Value of the literal to match\n    public var value: String\n    /// An interpreter instance if the raw value needs any further evaluation\n    public var interpreter: TypedInterpreter\n\n    /// - parameter value: Value of the literal to match\n    /// - parameter interpreter: An interpreter instance if the raw value needs any further evaluation\n    public init(value: String, interpreter: TypedInterpreter) {\n        self.value = value\n        self.interpreter = interpreter\n    }\n}\n\n/// `Literal`s are used by `DataType`s to be able to recognise static values, that can be expressed as a given type\npublic class Literal<T> {\n    /// For the conversion it uses the registered literals, to be able to process the input and return an existing type\n    /// - parameter body: Struct ontaining the raw matched value and an interpreter\n    /// - returns: The value of the `DataType` or `nil` if it cannot be processed\n    let convert: (_ body: LiteralBody) -> T?\n\n    /// In case of more complicated expression, this initialiser accepts a `convert` block, which can be used to process any value. Return nil, if the input cannot be accepted and converted.\n    /// - parameter convert: The conversion block to process values\n    /// - parameter body: Struct ontaining the raw matched value and an interpreter\n    public init(convert: @escaping (_ body: LiteralBody) -> T?) {\n        self.convert = convert\n    }\n\n    /// In case the literals are easily expressed, static keywords, then this initialiser is the best to use.\n    /// - parameter check: The string to check for in the input string (with exact match)\n    /// - parameter convertsTo: Statically typed associated value. As it is expressed as an autoclosure, the provided expression will be evaluated at recognition time, not initialisation time. For example, Date() is perfectly acceptable to use here.\n    public init(_ check: String, convertsTo value: @autoclosure @escaping () -> T) {\n        self.convert = { check == $0.value ? value() : nil }\n    }\n\n    /// For the conversion it uses the registered literals, to be able to process the input and return an existing type\n    /// - parameter input: The input to convert as a `DataType` value\n    /// - parameter interpreter: An interpreter instance if the content needs any further evaluation\n    /// - returns: The value of the `DataType` or `nil` if it cannot be processed\n    func convert(input: String, interpreter: TypedInterpreter) -> T? {\n        return convert(LiteralBody(value: input, interpreter: interpreter))\n    }\n}\n\n/// `Function`s can process values in given `DataType`s, allowing the expressions to be feature-rich\npublic protocol FunctionProtocol {\n    /// Functions use similar conversion methods as `DataType`s. If they return `nil`, the function does not apply to the given input. Otherwise, the result is expressed as an instance of a given `DataType`\n    /// It uses the interpreter the and parsing context to be able to effectively process the content\n    /// - parameter input: The input to convert as a `DataType` value\n    /// - parameter interpreter: An interpreter instance if the content needs any further evaluation\n    /// - parameter context: The context - if vaiables need any contextual information\n    /// - parameter connectedRanges: Ranges of string indices that are connected with opening-closing tag pairs, respectively\n    /// - returns: A valid value of any `DataType` or `nil` if it cannot be processed\n    func convert(input: String, interpreter: TypedInterpreter, context: Context, connectedRanges: [ClosedRange<String.Index>]) -> Any?\n}\n\n/// `Function`s can process values in given `DataType`s, allowing the expressions to be feature-rich\npublic class Function<T>: FunctionProtocol {\n    /// Although `Function`s typically contain only one pattern, multiple ones can be added, for semantic grouping purposes\n    public let patterns: [Pattern<T, TypedInterpreter>]\n\n    /// If multiple patterns are provided use this initialiser. Otherwise, for only one, there is `init(_,matcher:)`\n    /// - parameter patterns: The array of patterns to be able to recognise\n    public init(patterns: [Pattern<T, TypedInterpreter>]) {\n        self.patterns = patterns\n    }\n\n    /// In case there is only one pattern, this initialiser is the preferred one to use\n    /// - parameter elements: Contains the pattern that needs to be recognised\n    /// - parameter options: Options that modify the pattern matching algorithm\n    /// - parameter matcher: Ending closure that transforms and processes the recognised value\n    public init(_ elements: [PatternElement], options: PatternOptions = [], matcher: @escaping MatcherBlock<T, TypedInterpreter>) {\n        self.patterns = [Pattern(elements, options: options, matcher: matcher)]\n    }\n\n    /// The matching of the input expression of a given `Function` happens in this method. It only accepts matches from the matcher, that are exact matches.\n    /// - parameter input: The input to convert as a `DataType` value\n    /// - parameter interpreter: An interpreter instance if the content needs any further evaluation\n    /// - parameter context: The context - if vaiables need any contextual information\n    /// - parameter connectedRanges: Ranges of string indices that are connected with opening-closing tag pairs, respectively\n    /// - returns: A valid value of any `DataType` or `nil` if it cannot be processed\n    public func convert(input: String, interpreter: TypedInterpreter, context: Context, connectedRanges: [ClosedRange<String.Index>] = []) -> Any? {\n        guard case let .exactMatch(_, output, _) = matchStatement(amongst: patterns, in: input, interpreter: interpreter, context: context, connectedRanges: connectedRanges) else { return nil }\n        return output\n    }\n}\n\n/// `Variable` represents a named placeholder, so when the matcher recognises a pattern, the values of the variables are passed to them in a block.\npublic class Variable<T>: GenericVariable<T, TypedInterpreter> {\n}\n"
  },
  {
    "path": "Sources/Eval/Utilities/MatchResult.swift",
    "content": "/*\n *  Copyright (c) 2018 Laszlo Teveli.\n *\n *  Licensed to the Apache Software Foundation (ASF) under one\n *  or more contributor license agreements.  See the NOTICE file\n *  distributed with this work for additional information\n *  regarding copyright ownership.  The ASF licenses this file\n *  to you under the Apache License, Version 2.0 (the\n *  \"License\"); you may not use this file except in compliance\n *  with the License.  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing,\n *  software distributed under the License is distributed on an\n *  \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n *  KIND, either express or implied.  See the License for the\n *  specific language governing permissions and limitations\n *  under the License.\n */\n\nimport Foundation\n\n/// Whenever a match operation is performed, the result is going to be a `MatchResult` instance.\npublic enum MatchResult<T> {\n    /// The input could not be matched\n    case noMatch\n    /// The input can match, if it were continued. (It's the prefix of the matching expression)\n    case possibleMatch\n    /// The input matches the expression. It provides information about the `length` of the matched input, the `output` after the evaluation, and the `variables` that were processed during the process.\n    /// - parameter length: The length of the match in the input string\n    /// - parameter output: The interpreted content\n    /// - parameter variables: The key-value pairs of the found `Variable` instances along the way\n    case exactMatch(length: Int, output: T, variables: [String: Any])\n    /// In case the matching sequence only consists of one variable, the result is going to be anyMatch\n    /// - parameter exhaustive: Whether the matching should be exaustive or just return the shortest matching result\n    case anyMatch(exhaustive: Bool)\n\n    /// Shorter syntax for pattern matching `MatchResult.exactMatch`\n    /// - returns: Whether the case of the current instance is `exactMatch`\n    func isMatch() -> Bool {\n        if case .exactMatch(_, _, _) = self {\n            return true\n        }\n        return false\n    }\n\n    /// Shorter syntax for pattern matching `MatchResult.anyMatch`\n    /// - parameter exhaustive: If the result is `anyMatch`, this one filter the content by its exhaustive parameter - if provided. Uses `false` otherwise\n    /// - returns: Whether the case of the current instance is `anyMatch`\n    func isAnyMatch(exhaustive: Bool = false) -> Bool {\n        if case .anyMatch(let parameter) = self {\n            return exhaustive == parameter\n        }\n        return false\n    }\n\n    /// Shorter syntax for pattern matching `MatchResult.noMatch`\n    /// - returns: Whether the case of the current instance is `noMatch`\n    func isNoMatch() -> Bool {\n        if case .noMatch = self {\n            return true\n        }\n        return false\n    }\n\n    /// Shorter syntax for pattern matching `MatchResult.anypossibleMatch`\n    /// - returns: Whether the case of the current instance is `possibleMatch`\n    func isPossibleMatch() -> Bool {\n        if case .possibleMatch = self {\n            return true\n        }\n        return false\n    }\n}\n\n/// `MatchResult` with Equatable objects are also Equatable\npublic extension MatchResult where T: Equatable {\n    /// `MatchResult` with Equatable objects are also Equatable\n    /// - parameter lhs: Left hand side\n    /// - parameter rhs: Right hand side\n    /// - returns: Whether the `MatchResult` have the same values, including the contents of their associated objects\n    static func == (lhs: MatchResult<T>, rhs: MatchResult<T>) -> Bool {\n        switch (lhs, rhs) {\n        case (.noMatch, .noMatch), (.possibleMatch, .possibleMatch):\n            return true\n        case let (.anyMatch(lhsShortest), .anyMatch(rhsShortest)):\n            return lhsShortest == rhsShortest\n        case let (.exactMatch(lhsLength, lhsOutput, lhsVariables), .exactMatch(rhsLength, rhsOutput, rhsVariables)):\n            return lhsLength == rhsLength && lhsOutput == rhsOutput && (lhsVariables as NSDictionary).isEqual(to: rhsVariables)\n        default:\n            return false\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/Eval/Utilities/Matcher.swift",
    "content": "/*\n *  Copyright (c) 2018 Laszlo Teveli.\n *\n *  Licensed to the Apache Software Foundation (ASF) under one\n *  or more contributor license agreements.  See the NOTICE file\n *  distributed with this work for additional information\n *  regarding copyright ownership.  The ASF licenses this file\n *  to you under the Apache License, Version 2.0 (the\n *  \"License\"); you may not use this file except in compliance\n *  with the License.  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing,\n *  software distributed under the License is distributed on an\n *  \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n *  KIND, either express or implied.  See the License for the\n *  specific language governing permissions and limitations\n *  under the License.\n */\n\nimport Foundation\n\n/// A tuple with the variable metadata and its value\n/// - parameter metadata: Name, options, mapping information\n/// - parameter value: The value of the variable\ninternal typealias VariableValue = (metadata: VariableProtocol, value: String)\n\n/// A processor that can process a raw value with extra information, such as interpreter and context\ninternal protocol VariableProcessorProtocol {\n    /// The method that can process the variable\n    /// - parameter variable: The raw value to process\n    /// - returns: The computed value of the variable\n    func process(_ variable: VariableValue) -> Any?\n}\n\n/// A processor that can process a raw value with extra information, such as interpreter and context\ninternal class VariableProcessor<E: Interpreter>: VariableProcessorProtocol {\n    /// An interpreter instance to use during the processing\n    let interpreter: E\n    /// The context to use during the processing\n    let context: Context\n\n    /// Initialiser of the processor\n    /// - parameter interpreter: An interpreter instance to use during the processing\n    /// - parameter context: The context to use during the processing\n    init(interpreter: E, context: Context) {\n        self.interpreter = interpreter\n        self.context = context\n    }\n\n    /// Maps and evaluates variable content, based on its interpretation settings\n    /// - parameter variable: The variable to process\n    /// - returns: The result of the matching operation\n    func process(_ variable: VariableValue) -> Any? {\n        let value = variable.metadata.options.trimmed ? variable.value.trim() : variable.value\n        if variable.metadata.options.interpreted {\n            let variableInterpreter = interpreter.interpreterForEvaluatingVariables\n            let output = variableInterpreter.evaluate(value, context: context)\n            return variable.metadata.performMap(input: output, interpreter: variableInterpreter)\n        }\n        return variable.metadata.performMap(input: value, interpreter: interpreter)\n    }\n}\n\n/// This class provides the main logic of the `Eval` framework, performing the pattern matching details\ninternal class Matcher {\n    /// The pattern to match against\n    let pattern: PatternProtocol\n    /// A processor that is able to evaluate the variables with extra information, such as context and interpreter\n    let processor: VariableProcessorProtocol\n\n    /// Initialiser of the matcher\n    /// - parameter pattern: The pattern to match against\n    /// - parameter processor: A processor that is able to evaluate the variables with extra information, such as context and interpreter\n    init(pattern: PatternProtocol, processor: VariableProcessorProtocol) {\n        self.pattern = pattern\n        self.processor = processor\n    }\n\n    /// The active variable that can be appended during the execution, used by the helper methods\n    private var currentlyActiveVariable: VariableValue?\n\n    /// Tries to append the next input character to the currently active variables - if we have any\n    /// - returns: Whether the append was successful\n    private func tryToAppendCurrentVariable(remainder: inout String) -> Bool {\n        if let variable = currentlyActiveVariable {\n            appendNextCharacterToVariable(variable, remainder: &remainder)\n        }\n        return currentlyActiveVariable != nil\n    }\n\n    /// Appends the next character to the provided variables\n    /// - parameter variable: The variable to append to\n    /// - parameter remainder: The remainder of the evaluated input\n    private func appendNextCharacterToVariable(_ variable: VariableValue, remainder: inout String) {\n        if remainder.isEmpty {\n            currentlyActiveVariable = (variable.metadata, variable.value)\n        } else {\n            if pattern.options.contains(.backwardMatch) {\n                currentlyActiveVariable = (variable.metadata, String(describing: remainder.removeLast()) + variable.value)\n            } else {\n                currentlyActiveVariable = (variable.metadata, variable.value + String(describing: remainder.removeFirst()))\n            }\n        }\n    }\n\n    /// An element to initialise the variable with\n    /// - parameter element: The variable element\n    private func initialiseVariable(_ element: PatternElement) {\n        if currentlyActiveVariable == nil, let variable = element as? VariableProtocol {\n            currentlyActiveVariable = (variable, \"\")\n        }\n    }\n\n    /// When the recognition of a variable arrives to the final stage, function finalises its value and appends the variables array\n    /// - returns: Whether the registration was successful (the finalisation resulted in a valid value)\n    private func registerAndValidateVariable(variables: inout [String: Any]) -> Bool {\n        if let variable = currentlyActiveVariable {\n            let result = processor.process(variable)\n            variables[variable.metadata.name] = result\n            return !variable.metadata.options.contains(.acceptsNilValue) && result != nil\n        }\n        return false\n    }\n\n    /// Increments the elementIndex value\n    /// - parameter elementIndex: The index to be incremented\n    private func nextElement(_ elementIndex: inout Int) {\n        elementIndex += pattern.options.contains(.backwardMatch) ? -1 : 1\n    }\n\n    /// Checks whether the current index is the last one\n    /// - parameter elementIndex: The index to be checked\n    /// - returns: Whether the index is the last one of the elements array\n    private func notFinished(_ elementIndex: Int) -> Bool {\n        if pattern.options.contains(.backwardMatch) {\n            return elementIndex >= pattern.elements.startIndex\n        } else {\n            return elementIndex < pattern.elements.endIndex\n        }\n    }\n\n    /// Helper method to determine the first index of the collection, based on its options\n    /// - returns: The first index of the collection\n    private func initialIndex() -> Int {\n        if pattern.options.contains(.backwardMatch) {\n            return pattern.elements.index(before: pattern.elements.endIndex)\n        } else {\n            return pattern.elements.startIndex\n        }\n    }\n\n    /// Removes and returns the next character from the input\n    /// - parameter remainder: The remainder of the input\n    /// - parameter length: The number of characters to be removed\n    /// - returns: The last few characers from the input, defined by the `length` parameter\n    private func drop(_ remainder: String, length: Int) -> String {\n        if pattern.options.contains(.backwardMatch) {\n            return String(remainder.dropLast(length))\n        } else {\n            return String(remainder.dropFirst(length))\n        }\n    }\n\n    /// Removes whitespaces characters from the upcoming consecutive input characters\n    /// - parameter remainder: The input to remove whitespaces from\n    private func skipWhitespaces(_ remainder: inout String) {\n        let whitespaces = CharacterSet.whitespacesAndNewlines\n        repeat {\n            if pattern.options.contains(.backwardMatch), let last = remainder.last?.unicodeScalars.first, whitespaces.contains(last) {\n                _ = remainder.removeLast()\n            } else if let first = remainder.first?.unicodeScalars.first, whitespaces.contains(first) {\n                _ = remainder.removeFirst()\n            } else {\n                break\n            }\n        } while true\n    }\n\n    /// Removes whitespaces characters from the upcoming consecutive input characters, when the context allows to do so\n    /// - parameter remainder: The input to remove whitespaces from\n    /// - parameter index: The index of the current element\n    private func skipWhitespacesIfNeeded(_ remainder: inout String, index: Int) {\n        var shouldTrim = false\n        if let variable = currentlyActiveVariable {\n            shouldTrim = variable.metadata.options.trimmed\n        } else if index < pattern.elements.endIndex && pattern.elements[index] is Keyword {\n            shouldTrim = true\n        }\n        if shouldTrim && notFinished(index) {\n            skipWhitespaces(&remainder)\n        }\n    }\n\n    /// This match method provides the main logic of the `Eval` framework, performing the pattern matching, trying to identify, whether the input string is somehow related, or completely matches the pattern.\n    /// - parameter string: The input\n    /// - parameter from: The start of the range to analyse the result in\n    /// - parameter connectedRanges: Ranges of string indices that are connected with opening-closing tag pairs, respectively\n    /// - parameter renderer: If the result is an exactMatch, it uses this renderer block to compute the output based on the matched variables\n    /// - parameter variables: The set of variables collected during the execution\n    /// - returns: The result of the matching operation\n    // swiftlint:disable:next cyclomatic_complexity function_body_length\n    func match<T>(string: String,\n                  from start: String.Index?,\n                  connectedRanges: [ClosedRange<String.Index>] = [],\n                  renderer: @escaping (_ variables: [String: Any]) -> T?) -> MatchResult<T> {\n        let start = start ?? string.startIndex\n        let trimmed = String(string[start...])\n        var elementIndex = initialIndex()\n        var remainder = trimmed\n        var variables: [String: Any] = [:]\n\n        repeat {\n            let element = pattern.elements[elementIndex]\n            let result = element.matches(prefix: remainder, options: pattern.options)\n\n            switch result {\n            case .noMatch:\n                guard tryToAppendCurrentVariable(remainder: &remainder) else { return .noMatch }\n            case .possibleMatch:\n                return .possibleMatch\n            case .anyMatch(let exhaustive):\n                initialiseVariable(element)\n                if exhaustive {\n                    _ = tryToAppendCurrentVariable(remainder: &remainder)\n                    if remainder.isEmpty {\n                        guard registerAndValidateVariable(variables: &variables) else { return .possibleMatch }\n                        nextElement(&elementIndex)\n                    }\n                } else {\n                    nextElement(&elementIndex)\n                }\n            case let .exactMatch(length, _, embeddedVariables):\n                let position = pattern.options.contains(.backwardMatch) ? remainder.endIndex : trimmed.index(trimmed.endIndex, offsetBy: -remainder.count)\n                let isOpeningOrClosingKeyword = (element as? Keyword)?.type != .generic\n                if isEmbedded(element: element, in: String(string[start...]), at: position) {\n                    if currentlyActiveVariable != nil {\n                        _ = tryToAppendCurrentVariable(remainder: &remainder)\n                    } else {\n                        nextElement(&elementIndex)\n                    }\n                } else if connectedRanges.contains(where: { $0.contains(position) }) && !isOpeningOrClosingKeyword {\n                    if currentlyActiveVariable != nil {\n                        _ = tryToAppendCurrentVariable(remainder: &remainder)\n                    }\n                } else {\n                    variables.merge(embeddedVariables) { key, _ in key }\n                    if currentlyActiveVariable != nil {\n                        guard registerAndValidateVariable(variables: &variables) else { return .noMatch }\n                        currentlyActiveVariable = nil\n                    }\n                    nextElement(&elementIndex)\n                    remainder = drop(remainder, length: length)\n                    if elementIndex < pattern.elements.count && element is Keyword {\n                        skipWhitespacesIfNeeded(&remainder, index: elementIndex)\n                    }\n                }\n            }\n        } while notFinished(elementIndex)\n\n        if let renderedOutput = renderer(variables) {\n            return .exactMatch(length: string.count - string.distance(from: string.startIndex, to: start) - remainder.count, output: renderedOutput, variables: variables)\n        } else {\n            return .noMatch\n        }\n    }\n\n    /// Determines whether the current character is an `OpenKeyword`, so there might be another embedded match later\n    /// - parameter element: The element to check whether it's an `OpenKeyword`\n    /// - parameter in: The input\n    /// - parameter at: The starting position to check from\n    /// - returns: Whether the element conditions apply and the position is before the last one\n    func isEmbedded(element: PatternElement, in string: String, at currentPosition: String.Index) -> Bool {\n        if let closingTag = element as? Keyword, closingTag.type == .closingStatement, let closingPosition = positionOfClosingTag(in: string, from: string.startIndex),\n            currentPosition < closingPosition {\n            return true\n        }\n        return false\n    }\n\n    /// Determines whether the current character is an `OpenKeyword` and fins the position of its appropriate `ClosingKeyword` pair\n    /// - parameter in: The input\n    /// - parameter from: The starting position of the checking range\n    /// - returns: `nil` if the `CloseKeyword` pair cannot be found. The position otherwise\n    func positionOfClosingTag(in string: String, from start: String.Index) -> String.Index? {\n        if let opening = pattern.elements.first(where: { ($0 as? Keyword)?.type == .openingStatement }) as? Keyword,\n            let closing = pattern.elements.first(where: { ($0 as? Keyword)?.type == .closingStatement }) as? Keyword {\n            var counter = 0\n            var position = start\n            repeat {\n                var isCloseTagEarlier = false\n                let relevantString = string[position...]\n                let open = relevantString.range(of: opening.name)?.lowerBound\n                let close = relevantString.range(of: closing.name)?.lowerBound\n                if let open = open, let close = close, close < open {\n                    isCloseTagEarlier = true\n                }\n                if let open = open, !isCloseTagEarlier {\n                    counter += 1\n                    position = string.index(open, offsetBy: opening.name.count)\n                } else if let close = close {\n                    counter -= 1\n                    if counter == 0 {\n                        return close\n                    }\n                    position = string.index(close, offsetBy: closing.name.count)\n                } else {\n                    break\n                }\n            } while true\n        }\n        return nil\n    }\n}\n"
  },
  {
    "path": "Sources/Eval/Utilities/Pattern.swift",
    "content": "/*\n *  Copyright (c) 2018 Laszlo Teveli.\n *\n *  Licensed to the Apache Software Foundation (ASF) under one\n *  or more contributor license agreements.  See the NOTICE file\n *  distributed with this work for additional information\n *  regarding copyright ownership.  The ASF licenses this file\n *  to you under the Apache License, Version 2.0 (the\n *  \"License\"); you may not use this file except in compliance\n *  with the License.  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing,\n *  software distributed under the License is distributed on an\n *  \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n *  KIND, either express or implied.  See the License for the\n *  specific language governing permissions and limitations\n *  under the License.\n */\n\nimport Foundation\n\n/// It's a data transfer object passed in the `Pattern` matcher block\npublic struct PatternBody<E: Evaluator> {\n    /// The key-value pairs of the `Variable` instances found along the way\n    public var variables: [String: Any]\n    /// The evaluator instance to help parsing the content\n    public var interpreter: E\n    /// The context if the matcher block needs any contextual information\n    public var context: Context\n}\n\n/// `MatcherBlock` is used by `Matcher` and `Function` classes when the matched expression should be processed in a custom way. It should return a strongly typed object after the evaluations.\n/// The first parameter contains the values of every matched `Variable` instance.\n/// The second parameter is the evaluator. If there is a need to process the value of the variable further, creators of this block can use this evaluator, whose value is always the interpreter currently in use\n/// In its last parameter if provides information about the context, and therefore allows access to read or modify the context variables.\n/// - parameter body: Struct containing the matched variables, an interpreter, and a context\n/// - returns: The converted value\npublic typealias MatcherBlock<T, E: Evaluator> = (_ body: PatternBody<E>) -> T?\n\n/// Options that modify the pattern matching algorithm\npublic struct PatternOptions: OptionSet {\n    /// Integer representation of the option\n    public let rawValue: Int\n    /// Basic initialiser with the integer representation\n    public init(rawValue: Int) {\n        self.rawValue = rawValue\n    }\n\n    /// Searches of the elements of the pattern backward from the end of the output. Othwerise, if not present, it matches from the beginning.\n    public static let backwardMatch: PatternOptions = PatternOptions(rawValue: 1 << 0)\n}\n\n/// Pattern consists of array of elements\npublic protocol PatternProtocol {\n    /// `Matcher` instances are capable of recognising patterns described in the `elements` collection. It only remains effective, if the `Variable` instances are surrounded by `Keyword` instances, so no two `Variable`s should be next to each other. Otherwise, their matching result and value would be undefined.\n    /// This collection should be provided during the initialisation, and cannot be modified once the `Matcher` instance has been created.\n    var elements: [PatternElement] { get }\n\n    /// Options that modify the pattern matching algorithm\n    var options: PatternOptions { get }\n\n    /// Optional name to identify the pattern. If not provided during initialisation, it will fall back to the textual representation of the elements array\n    var name: String { get }\n}\n\n/// Pattern consists of array of elements\npublic class Pattern<T, I: Interpreter>: PatternProtocol {\n    /// `Matcher` instances are capable of recognising patterns described in the `elements` collection. It only remains effective, if the `Variable` instances are surrounded by `Keyword` instances, so no two `Variable`s should be next to each other. Otherwise, their matching result and value would be undefined.\n    /// This collection should be provided during the initialisation, and cannot be modified once the `Matcher` instance has been created.\n    public let elements: [PatternElement]\n\n    /// The block to process the elements with\n    let matcher: MatcherBlock<T, I>\n\n    /// Options that modify the pattern matching algorithm\n    public let options: PatternOptions\n\n    /// Optional name to identify the pattern. If not provided during initialisation, it will fall back to the textual representation of the elements array\n    public let name: String\n\n    /// The first parameter is the pattern, that needs to be recognised. The `matcher` ending closure is called whenever the pattern has successfully been recognised and allows the users of this framework to provide custom computations using the matched `Variable` values.\n    /// - parameter elemenets: The pattern to recognise\n    /// - parameter name: Optional identifier for the pattern. Defaults to the string representation of the elements\n    /// - parameter options: Options that modify the pattern matching algorithm\n    /// - parameter matcher: The block to process the input with\n    public init(_ elements: [PatternElement],\n                name: String? = nil,\n                options: PatternOptions = [],\n                matcher: @escaping MatcherBlock<T, I>) {\n        self.name = name ?? Pattern.stringify(elements: elements)\n        self.matcher = matcher\n        self.options = options\n        self.elements = Pattern.elementsByReplacingTheLastVariableNotToBeShortestMatch(in: elements, options: options)\n    }\n\n    /// If the last element in the elements pattern is a variable, shortest match will not match until the end of the input string, but just until the first empty character.\n    /// - parameter in: The elements array where the last element should be replaced\n    /// - parameter options: Options that modify the pattern matching algorithm\n    /// - returns: A new collection of elements, where the last element is replaced, whether it's a variable with shortest flag on\n    static func elementsByReplacingTheLastVariableNotToBeShortestMatch(in elements: [PatternElement], options: PatternOptions) -> [PatternElement] {\n        var elements = elements\n        let index = options.contains(.backwardMatch) ? elements.startIndex : elements.index(before: elements.endIndex)\n\n        /// Replaces the last element in the elements collection with the new one in the parmeter\n        /// - parameter element: The element to be replaced\n        /// - parameter new: The replacement\n        /// - parameter previousOptions: The element to be replaced\n        func replaceLast(_ element: VariableProtocol, with new: (_ previousOptions: VariableOptions) -> PatternElement) {\n            elements.remove(at: index)\n            elements.insert(new(element.options.union(.exhaustiveMatch)), at: index)\n        }\n\n        if let last = elements[index] as? GenericVariable<I.EvaluatedType, I>, !last.options.contains(.exhaustiveMatch) {\n            replaceLast(last) { GenericVariable(last.name, options: $0, map: last.map) }\n        } else if let last = elements[index] as? VariableProtocol, !last.options.contains(.exhaustiveMatch) { //in case it cannot be converted, let's use Any. Losing type information\n            replaceLast(last) { GenericVariable<Any, I>(last.name, options: $0) { last.performMap(input: $0.value, interpreter: $0.interpreter) } }\n        }\n        return elements\n    }\n\n    /// This matcher provides the main logic of the `Eval` framework, performing the pattern matching, trying to identify, whether the input string is somehow related, or completely matches the pattern of the `Pattern` instance.\n    /// Uses the `Matcher` class for the evaluation\n    /// - parameter string: The input\n    /// - parameter from: The start of the range to analyse the result in\n    /// - parameter interpreter: An interpreter instance - if the variables need any further evaluation\n    /// - parameter context: The context - if the block uses any contextual data\n    /// - parameter connectedRanges: Ranges of string indices that are connected with opening-closing tag pairs, respectively\n    /// - returns: The result of the matching operation\n    func matches(string: String, from start: String.Index? = nil, interpreter: I, context: Context, connectedRanges: [ClosedRange<String.Index>] = []) -> MatchResult<T> {\n        let start = start ?? string.startIndex\n        let processor = VariableProcessor(interpreter: interpreter, context: context)\n        let matcher = Matcher(pattern: self, processor: processor)\n        let result = matcher.match(string: string, from: start, connectedRanges: connectedRanges) { variables in\n            self.matcher(PatternBody(variables: variables, interpreter: interpreter, context: context))\n        }\n\n        if case let .exactMatch(_, output, variables) = result {\n            let input = String(string[start...])\n            context.debugInfo[input] = ExpressionInfo(input: input, output: output, pattern: elementsAsString(), patternName: name, variables: variables)\n        }\n\n        return result\n    }\n\n    /// A textual representation of the Pattern's elements array\n    /// - returns: A stringified version of the input elements\n    func elementsAsString() -> String {\n        return Pattern.stringify(elements: elements)\n    }\n\n    /// A textual representation of the elements array\n    /// - returns: A stringified version of the input elements\n    static func stringify(elements: [PatternElement]) -> String {\n        return elements.map {\n            if let keyword = $0 as? Keyword {\n                return keyword.name\n            } else if let variable = $0 as? VariableProtocol {\n                return \"{\\(variable.name)}\"\n            }\n            return \"\"\n        }.joined(separator: \" \")\n    }\n}\n"
  },
  {
    "path": "Sources/Eval/Utilities/Utils.swift",
    "content": "/*\n *  Copyright (c) 2018 Laszlo Teveli.\n *\n *  Licensed to the Apache Software Foundation (ASF) under one\n *  or more contributor license agreements.  See the NOTICE file\n *  distributed with this work for additional information\n *  regarding copyright ownership.  The ASF licenses this file\n *  to you under the Apache License, Version 2.0 (the\n *  \"License\"); you may not use this file except in compliance\n *  with the License.  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing,\n *  software distributed under the License is distributed on an\n *  \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n *  KIND, either express or implied.  See the License for the\n *  specific language governing permissions and limitations\n *  under the License.\n */\n\nimport Foundation\n\n/// Syntactic sugar for `MatchElement` instances to feel like concatenation, whenever the input requires an array of elements.\n/// - parameter left: Left hand side\n/// - parameter right: Right hand side\n/// - returns: An array with two elements (left and right in this order)\npublic func + (left: PatternElement, right: PatternElement) -> [PatternElement] {\n    return [left, right]\n}\n\n/// Syntactic sugar for appended arrays\n/// - parameter array: The array to append\n/// - parameter element: The appended element\n/// - returns: A new array by appending `array` with `element`\ninternal func + <A>(array: [A], element: A) -> [A] {\n    return array + [element]\n}\n\n/// Syntactic sugar for appending mutable arrays\n/// - parameter array: The array to append\n/// - parameter element: The appended element\ninternal func += <A> (array: inout [A], element: A) {\n    array = array + element //swiftlint:disable:this shorthand_operator\n}\n\n/// Helpers on `String` to provide `Int` based subscription features and easier usage\nextension String {\n    /// Shorter syntax for trimming\n    /// - returns: The `String` without the prefix and postfix whitespace characters\n    func trim() -> String {\n        return trimmingCharacters(in: .whitespacesAndNewlines)\n    }\n}\n"
  },
  {
    "path": "Tests/.swiftlint.yml",
    "content": "disabled_rules:\n  - force_cast\n  - force_unwrapping\n  - file_header\n  - type_name\n  - explicit_top_level_acl"
  },
  {
    "path": "Tests/EvalTests/IntegrationTests/InterpreterTests.swift",
    "content": "@testable import Eval\nimport class Eval.Pattern\nimport XCTest\n\nclass InterpreterTests: XCTestCase {\n    // swiftlint:disable:next function_body_length\n    func test_whenAddingALotOfFunctions_thenInterpretationWorksCorrectly() {\n        let number = numberDataType()\n        let string = stringDataType()\n        let date = dateDataType()\n        let array = arrayDataType()\n        let boolean = booleanDataType()\n\n        let methodCall = methodCallFunction()\n        let max = objectFunction(\"max\") { (object: [Double]) -> Double? in object.max() }\n        let min = objectFunction(\"min\") { (object: [Double]) -> Double? in object.min() }\n        let sum = objectFunction(\"sum\") { (object: [Double]) -> Double? in object.reduce(0, +) }\n        let format = dateFomatFunction()\n        let dateFactory = dateFactoryFunction()\n        let not = prefixOperator(\"!\") { (value: Bool) in !value }\n        let not2 = function(\"not\") { (arguments: [Any]) -> Bool? in\n            guard let boolArgument = arguments.first as? Bool else { return nil }\n            return !boolArgument\n        }\n        let sqrtFunction = function(\"sqrt\") { (arguments: [Any]) -> Double? in\n            guard let argument = arguments.first as? Double else { return nil }\n            return sqrt(argument)\n        }\n        let add = function(\"add\") { (arguments: [Any]) -> Double? in\n            guard let arguments = arguments as? [Double] else { return nil }\n            return arguments.reduce(0, +)\n        }\n        let test = functionWithNamedParameters(\"test\") { (arguments: [String: Any]) -> Double? in\n            guard let foo = arguments[\"foo\"] as? Double, let bar = arguments[\"bar\"] as? Double else { return nil }\n            return foo + bar\n        }\n        let parenthesis = Function([Keyword(\"(\"), Variable<Any>(\"body\"), Keyword(\")\")]) { $0.variables[\"body\"] }\n        let plusOperator = infixOperator(\"+\") { (lhs: Double, rhs: Double) in lhs + rhs }\n        let concat = infixOperator(\"+\") { (lhs: String, rhs: String) in lhs + rhs }\n        let multipicationOperator = infixOperator(\"*\") { (lhs: Double, rhs: Double) in lhs * rhs }\n        let inArrayNumber = infixOperator(\"in\") { (lhs: Double, rhs: [Double]) in rhs.contains(lhs) }\n        let inArrayString = infixOperator(\"in\") { (lhs: String, rhs: [String]) in rhs.contains(lhs) }\n        let range = infixOperator(\"...\") { (lhs: Double, rhs: Double) in CountableClosedRange(uncheckedBounds: (lower: Int(lhs), upper: Int(rhs))).map { Double($0) } }\n        let prefix = infixOperator(\"starts with\") { (lhs: String, rhs: String) in lhs.hasPrefix(rhs) }\n        let isOdd = suffixOperator(\"is odd\") { (value: Double) in Int(value) % 2 == 1 }\n        let isEven = suffixOperator(\"is even\") { (value: Double) in Int(value) % 2 == 0 }\n        let lessThan = infixOperator(\"<\") { (lhs: Double, rhs: Double) in lhs < rhs }\n\n        let increment = incrementFunction()\n\n        let interpreter = TypedInterpreter(dataTypes: [number, string, boolean, array, date],\n                                           functions: [concat, parenthesis, methodCall, sum, range, sqrtFunction, dateFactory, format, multipicationOperator, plusOperator, inArrayNumber, inArrayString, isOdd, isEven, add, max, min, not, not2, prefix, increment, lessThan, test],\n                                           context: Context(variables: [\"test\": 2.0, \"name\": \"Teve\"]))\n        XCTAssertEqual(interpreter.evaluate(\"123\") as! Double, 123)\n        XCTAssertEqual(interpreter.evaluate(\"1 + 2 + 3\") as! Double, 6)\n        XCTAssertEqual(interpreter.evaluate(\"2 + 3 * 4\") as! Double, 14)\n        XCTAssertEqual(interpreter.evaluate(\"2 * 3 + 4\") as! Double, 10)\n        XCTAssertEqual(interpreter.evaluate(\"2 * (3 + 4)\") as! Double, 14)\n        XCTAssertEqual(interpreter.evaluate(\"(3 + 4) * 2\") as! Double, 14)\n        XCTAssertEqual(interpreter.evaluate(\"'hello'\") as! String, \"hello\")\n        XCTAssertEqual(interpreter.evaluate(\"false\") as! Bool, false)\n        XCTAssertEqual(interpreter.evaluate(\"!false\") as! Bool, true)\n        XCTAssertEqual(interpreter.evaluate(\"not(false)\") as! Bool, true)\n        XCTAssertEqual(interpreter.evaluate(\"true\") as! Bool, true)\n        XCTAssertEqual(interpreter.evaluate(\"add(1,2)\") as! Double, 3)\n        XCTAssertEqual(interpreter.evaluate(\"[1,2]\") as! [Double], [1, 2])\n        XCTAssertEqual(interpreter.evaluate(\"['1','2']\") as! [String], [\"1\", \"2\"])\n        XCTAssertEqual(interpreter.evaluate(\"[true, false]\") as! [Bool], [true, false])\n        XCTAssertEqual(interpreter.evaluate(\"[1,2].count\") as! Double, 2)\n        XCTAssertEqual(interpreter.evaluate(\"'hello'.length\") as! Double, 5)\n        XCTAssertEqual(interpreter.evaluate(\"[0,3,1,2].max\") as! Double, 3)\n        XCTAssertEqual(interpreter.evaluate(\"pi * 2\") as! Double, Double.pi * 2)\n        XCTAssertEqual(interpreter.evaluate(\"1 in [3,2,1,2,3]\") as! Bool, true)\n        XCTAssertEqual(interpreter.evaluate(\"not(1 in [1])\") as! Bool, false)\n        XCTAssertEqual(interpreter.evaluate(\"'b' in ['a','c','d']\") as! Bool, false)\n        XCTAssertEqual(interpreter.evaluate(\"1...5\") as! [Double], [1, 2, 3, 4, 5])\n        XCTAssertEqual(interpreter.evaluate(\"[1, test]\") as! [Double], [1, 2])\n        XCTAssertEqual(interpreter.evaluate(\"2 in 1...5\") as! Bool, true)\n        XCTAssertEqual(interpreter.evaluate(\"5 is odd\") as! Bool, true)\n        XCTAssertEqual(interpreter.evaluate(\"2 is odd\") as! Bool, false)\n        XCTAssertEqual(interpreter.evaluate(\"4 is even\") as! Bool, true)\n        XCTAssertEqual(interpreter.evaluate(\"2 < 3\") as! Bool, true)\n        XCTAssertEqual(interpreter.evaluate(\"'Teve' starts with 'T'\") as! Bool, true)\n        XCTAssertEqual(interpreter.evaluate(\"'Hello ' + name\") as! String, \"Hello Teve\")\n        XCTAssertEqual(interpreter.evaluate(\"12++\") as! Double, 13)\n        XCTAssertEqual(interpreter.evaluate(\"(test + 2)++\") as! Double, 5)\n        XCTAssertEqual(interpreter.evaluate(\"test++\") as! Double, 3)\n        XCTAssertEqual(interpreter.evaluate(\"test\") as! Double, 3)\n        XCTAssertEqual(interpreter.evaluate(\"sqrt(4)\") as! Double, 2)\n        XCTAssertNotNil(interpreter.evaluate(\"now.format('yyyy-MM-dd')\"))\n        XCTAssertEqual(interpreter.evaluate(\"Date(2018, 12, 13).format('yyyy-MM-dd')\") as! String, \"2018-12-13\")\n        XCTAssertEqual(interpreter.evaluate(\"test(foo=1, bar=2)\") as! Double, 3)\n        XCTAssertNil(interpreter.evaluate(\"add(1,'a')\"))\n        XCTAssertNil(interpreter.evaluate(\"hello\"))\n\n        let context = Context()\n        _ = interpreter.evaluate(\"Date(1009 * 2, sqrt(144), 10 + 3).format('yyyy-MM-dd')\", context: context)\n\n        context.debugInfo.forEach {\n            print(\"DEBUG STEP: '\\($0.value.pattern)', where \\($0.value.variables), rendered to \\($0.value.output) from input \\($0.key)\")\n        }\n\n        let ifStatement = Pattern<String, TemplateInterpreter<String>>([Keyword(\"{%\"), Keyword(\"if\"), Variable<Bool>(\"condition\"), Keyword(\"%}\"), TemplateVariable(\"body\"), Keyword(\"{% endif %}\")]) {\n            guard let condition = $0.variables[\"condition\"] as? Bool, let body = $0.variables[\"body\"] as? String else { return nil }\n            if condition {\n                return body\n            }\n            return nil\n        }\n\n        let printStatement = Pattern<String, TemplateInterpreter<String>>([Keyword(\"{{\"), Variable<Any>(\"body\"), Keyword(\"}}\")]) {\n            guard let body = $0.variables[\"body\"] else { return nil }\n            return $0.interpreter.typedInterpreter.print(body)\n        }\n\n        let template = StringTemplateInterpreter(statements: [ifStatement, printStatement], interpreter: interpreter, context: Context())\n        XCTAssertEqual(template.evaluate(\"{{ 1 + 2 }}\"), \"3.0\")\n        XCTAssertEqual(template.evaluate(\"{{ 'Hello' + ' ' + 'World' + '!' }}\"), \"Hello World!\")\n        XCTAssertEqual(template.evaluate(\"asd {% if 10 < 21 %}Hello{% endif %} asd\"), \"asd Hello asd\")\n        XCTAssertEqual(template.evaluate(\"asd {% if 10 < 21 %}{{ 'Hello ' + name }}{% endif %} asd\"), \"asd Hello Teve asd\")\n    }\n\n    func test_whenEmbeddingTags_thenInterpretationWorksCorrectly() {\n        let parenthesis = Function<Any>([OpenKeyword(\"(\"), Variable<Any>(\"body\"), CloseKeyword(\")\")]) { $0.variables[\"body\"] }\n        let addition = infixOperator(\"+\") { (lhs: Double, rhs: Double) in lhs + rhs }\n        let interpreter = TypedInterpreter(dataTypes: [numberDataType(), stringDataType()],\n                                           functions: [parenthesis, addition])\n\n        XCTAssertEqual(interpreter.evaluate(\"(1)\") as! Double, 1)\n        XCTAssertEqual(interpreter.evaluate(\"(1) + (2)\") as! Double, 3)\n        XCTAssertEqual(interpreter.evaluate(\"(1 + (2))\") as! Double, 3)\n        XCTAssertEqual(interpreter.evaluate(\"(1 + 2)\") as! Double, 3)\n        XCTAssertEqual(interpreter.evaluate(\"((1) + 2)\") as! Double, 3)\n        XCTAssertEqual(interpreter.evaluate(\"((1) + (2))\") as! Double, 3)\n    }\n\n    func test_whenEmbeddingTagsWithNonCummitativeOperation_thenInterpretationWorksCorrectly() {\n        let parenthesis = Function<Any>([OpenKeyword(\"(\"), Variable<Any>(\"body\"), CloseKeyword(\")\")]) { $0.variables[\"body\"] }\n        let addition = infixOperator(\"+\") { (lhs: Double, rhs: Double) in lhs + rhs }\n        let subtraction = infixOperator(\"-\") { (lhs: Double, rhs: Double) in lhs - rhs }\n        let interpreter = TypedInterpreter(dataTypes: [numberDataType(), stringDataType()],\n                                           functions: [parenthesis, subtraction, addition])\n\n        XCTAssertEqual(interpreter.evaluate(\"6 - 4 - 2\") as! Double, 0)\n        XCTAssertEqual(interpreter.evaluate(\"6 - (4 + 2)\") as! Double, 0)\n        XCTAssertEqual(interpreter.evaluate(\"6 - (4 - 2)\") as! Double, 4)\n        XCTAssertEqual(interpreter.evaluate(\"12 - (6 - (4 - 2))\") as! Double, 8)\n    }\n\n    func test_whenStartsWithParentheses_thenInterpretationWorksCorrectly() {\n        let parenthesis = Function<Any>([OpenKeyword(\"(\"), Variable<Any>(\"body\"), CloseKeyword(\")\")]) { $0.variables[\"body\"] }\n        let addition = infixOperator(\"+\") { (lhs: Double, rhs: Double) in lhs + rhs }\n        let multiplication = infixOperator(\"*\") { (lhs: Double, rhs: Double) in lhs * rhs }\n        let interpreter = TypedInterpreter(dataTypes: [numberDataType(), stringDataType()],\n                                           functions: [parenthesis, multiplication, addition])\n\n        XCTAssertEqual(interpreter.evaluate(\"(2 + 3)\") as! Double, 5)\n        XCTAssertEqual(interpreter.evaluate(\"(2 + 3) * 4\") as! Double, 20)\n    }\n\n    // MARK: Helpers - operators\n\n    func infixOperator<A, B, T>(_ symbol: String, body: @escaping (A, B) -> T) -> Function<T?> {\n        return Function([Variable<A>(\"lhs\"), Keyword(symbol), Variable<B>(\"rhs\")], options: .backwardMatch) {\n            guard let lhs = $0.variables[\"lhs\"] as? A, let rhs = $0.variables[\"rhs\"] as? B else { return nil }\n            return body(lhs, rhs)\n        }\n    }\n\n    func prefixOperator<A, T>(_ symbol: String, body: @escaping (A) -> T) -> Function<T?> {\n        return Function([Keyword(symbol), Variable<A>(\"value\")]) {\n            guard let value = $0.variables[\"value\"] as? A else { return nil }\n            return body(value)\n        }\n    }\n\n    func suffixOperator<A, T>(_ symbol: String, body: @escaping (A) -> T) -> Function<T?> {\n        return Function([Variable<A>(\"value\"), Keyword(symbol)]) {\n            guard let value = $0.variables[\"value\"] as? A else { return nil }\n            return body(value)\n        }\n    }\n\n    func function<T>(_ name: String, body: @escaping ([Any]) -> T?) -> Function<T> {\n        return Function([Keyword(name), OpenKeyword(\"(\"), Variable<String>(\"arguments\", options: .notInterpreted), CloseKeyword(\")\")]) { match in\n            guard let arguments = match.variables[\"arguments\"] as? String else { return nil }\n            let interpretedArguments: [Any] = arguments.split(separator: \",\").compactMap { match.interpreter.evaluate(String($0).trim(), context: match.context) }\n            return body(interpretedArguments)\n        }\n    }\n\n    func functionWithNamedParameters<T>(_ name: String, body: @escaping ([String: Any]) -> T?) -> Function<T> {\n        return Function([Keyword(name), Keyword(\"(\"), Variable<String>(\"arguments\", options: .notInterpreted), Keyword(\")\")]) {\n            guard let arguments = $0.variables[\"arguments\"] as? String else { return nil }\n            var interpretedArguments: [String: Any] = [:]\n            for argument in arguments.split(separator: \",\") {\n                let parts = String(argument).trim().split(separator: \"=\")\n                if let key = parts.first, let value = parts.last {\n                    interpretedArguments[String(key)] = $0.interpreter.evaluate(String(value))\n                }\n            }\n            return body(interpretedArguments)\n        }\n    }\n\n    func objectFunction<O, T>(_ name: String, body: @escaping (O) -> T?) -> Function<T> {\n        return Function([Variable<O>(\"lhs\"), Keyword(\".\"), Variable<String>(\"rhs\", options: .notInterpreted) {\n            guard let value = $0.value as? String, value == name else { return nil }\n            return value\n        }]) {\n            guard let object = $0.variables[\"lhs\"] as? O, $0.variables[\"rhs\"] != nil else { return nil }\n            return body(object)\n        }\n    }\n\n    func objectFunctionWithParameters<O, T>(_ name: String, body: @escaping (O, [Any]) -> T?) -> Function<T> {\n        return Function([Variable<O>(\"lhs\"), Keyword(\".\"), Variable<String>(\"rhs\", options: .notInterpreted) {\n            guard let value = $0.value as? String, value == name else { return nil }\n            return value\n        }, Keyword(\"(\"), Variable<String>(\"arguments\", options: .notInterpreted), Keyword(\")\")]) { match in\n            guard let object = match.variables[\"lhs\"] as? O, match.variables[\"rhs\"] != nil, let arguments = match.variables[\"arguments\"] as? String else { return nil }\n            let interpretedArguments = arguments.split(separator: \",\").compactMap { match.interpreter.evaluate(String($0).trim()) }\n            return body(object, interpretedArguments)\n        }\n    }\n\n    // MARK: Helpers - data types\n\n    func numberDataType() -> DataType<Double> {\n        return DataType(type: Double.self,\n                        literals: [Literal { Double($0.value) },\n                                   Literal(\"pi\", convertsTo: Double.pi)]) { String(describing: $0.value) }\n    }\n\n    func stringDataType() -> DataType<String> {\n        let singleQuotesLiteral = Literal { literal -> String? in\n            guard let first = literal.value.first, let last = literal.value.last, first == last, first == \"'\" else { return nil }\n            let trimmed = literal.value.trimmingCharacters(in: CharacterSet(charactersIn: \"'\"))\n            return trimmed.contains(\"'\") ? nil : trimmed\n        }\n        return DataType(type: String.self, literals: [singleQuotesLiteral]) { $0.value }\n    }\n\n    func dateDataType() -> DataType<Date> {\n        let dateFormatter = DateFormatter()\n        dateFormatter.calendar = Calendar(identifier: .gregorian)\n        dateFormatter.dateFormat = \"yyyy-MM-dd HH:mm:ss\"\n\n        return DataType(type: Date.self, literals: [Literal<Date>(\"now\", convertsTo: Date())]) { dateFormatter.string(from: $0.value) }\n    }\n\n    func arrayDataType() -> DataType<[CustomStringConvertible]> {\n        let arrayLiteral = Literal { literal -> [CustomStringConvertible]? in\n            guard let first = literal.value.first, let last = literal.value.last, first == \"[\", last == \"]\" else { return nil }\n            return literal.value\n                .trimmingCharacters(in: CharacterSet(charactersIn: \"[]\"))\n                .split(separator: \",\")\n                .map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }\n                .map { literal.interpreter.evaluate(String($0)) as? CustomStringConvertible ?? String($0) }\n        }\n        return DataType(type: [CustomStringConvertible].self, literals: [arrayLiteral]) { $0.value.map { $0.description }.joined(separator: \",\") }\n    }\n\n    func booleanDataType() -> DataType<Bool> {\n        return DataType(type: Bool.self, literals: [Literal(\"false\", convertsTo: false), Literal(\"true\", convertsTo: true)]) { $0.value ? \"true\" : \"false\" }\n    }\n\n    // MARK: Helpers - functions\n\n    func methodCallFunction() -> Function<Double> {\n        return Function(patterns: [\n            Pattern(Variable<Any>(\"lhs\") + Keyword(\".\") + Variable<String>(\"rhs\", options: .notInterpreted)) {\n                if let lhs = $0.variables[\"lhs\"] as? NSObjectProtocol,\n                    !(lhs is NSNull),\n                    let rhs = $0.variables[\"rhs\"] as? String,\n                    let result = lhs.perform(Selector(rhs)) {\n                    return Double(Int(bitPattern: result.toOpaque()))\n                }\n                return nil\n            }\n        ])\n    }\n\n    func dateFomatFunction() -> Function<String> {\n        return objectFunctionWithParameters(\"format\") { (object: Date, arguments: [Any]) -> String? in\n            guard let format = arguments.first as? String else { return nil }\n            let dateFormatter = DateFormatter()\n            dateFormatter.calendar = Calendar(identifier: .gregorian)\n            dateFormatter.dateFormat = format\n            return dateFormatter.string(from: object)\n        }\n    }\n\n    func dateFactoryFunction() -> Function<Date> {\n        return function(\"Date\") { (arguments: [Any]) -> Date? in\n            guard let arguments = arguments as? [Double], arguments.count >= 3 else { return nil }\n            var components = DateComponents()\n            components.calendar = Calendar(identifier: .gregorian)\n            components.year = Int(arguments[0])\n            components.month = Int(arguments[1])\n            components.day = Int(arguments[2])\n            components.hour = arguments.count > 3 ? Int(arguments[3]) : 0\n            components.minute = arguments.count > 4 ? Int(arguments[4]) : 0\n            components.second = arguments.count > 5 ? Int(arguments[5]) : 0\n            return components.date\n        }\n    }\n\n    func incrementFunction() -> Function<Double> {\n        return Function([Variable<Any>(\"value\", options: .notInterpreted), Keyword(\"++\")]) {\n            if let argument = $0.variables[\"value\"] as? String {\n                if let variable = $0.interpreter.context.variables.first(where: { argument == $0.key }), let value = variable.value as? Double {\n                    let incremented = value + 1\n                    $0.interpreter.context.variables[variable.key] = incremented\n                    return incremented\n                } else if let argument = $0.interpreter.evaluate(argument) as? Double {\n                    return argument + 1\n                }\n            }\n            return nil\n        }\n    }\n}\n"
  },
  {
    "path": "Tests/EvalTests/IntegrationTests/PerformanceTest.swift",
    "content": "//\n//  PerformanceTest.swift\n//  EvalTests\n//\n//  Created by László Teveli on 2019. 09. 14..\n//\n\nimport XCTest\n@testable import Eval\n\nclass PerformanceTest: XCTestCase {\n    var interpreter: TypedInterpreter?\n    \n    override func setUp() {\n        super.setUp()\n        let not = prefixOperator(\"!\") { (value: Bool) in !value }\n        let not2 = prefixOperator(\"x\") { (value: Bool) in !value }\n        let equality = infixOperator(\"==\") { (lhs: Bool, rhs: Bool) in lhs == rhs }\n        \n        interpreter = TypedInterpreter(dataTypes: [stringDataType(), booleanDataType(), numberDataType()],\n                                       functions: [not, not2, equality],\n                                       context: Context(variables: [\"nothing\": true]))\n    }\n    \n    func test_suffix1() {\n        self.measure {\n            for _ in 1...1000 {\n                _ = self.interpreter?.evaluate(\"!nothing\")\n            }\n        }\n    }\n    \n    func test_suffix2() {\n        self.measure {\n            for _ in 1...1000 {\n                _ = self.interpreter?.evaluate(\"x nothing\")\n            }\n        }\n    }\n    \n    func test_suffix3() {\n        self.measure {\n            for _ in 1...1000 {\n                _ = self.interpreter?.evaluate(\"nothing == true\")\n            }\n        }\n    }\n\n    func numberDataType() -> DataType<Double> {\n        return DataType(type: Double.self,\n                        literals: [Literal { Double($0.value) },\n                                   Literal(\"pi\", convertsTo: Double.pi)]) { String(describing: $0.value) }\n    }\n    \n    func stringDataType() -> DataType<String> {\n        let singleQuotesLiteral = Literal { literal -> String? in\n            guard let first = literal.value.first, let last = literal.value.last, first == last, first == \"'\" else { return nil }\n            let trimmed = literal.value.trimmingCharacters(in: CharacterSet(charactersIn: \"'\"))\n            return trimmed.contains(\"'\") ? nil : trimmed\n        }\n        return DataType(type: String.self, literals: [singleQuotesLiteral]) { $0.value }\n    }\n\n    func booleanDataType() -> DataType<Bool> {\n        return DataType(type: Bool.self, literals: [Literal(\"false\", convertsTo: false), Literal(\"true\", convertsTo: true)]) { $0.value ? \"true\" : \"false\" }\n    }\n    \n    func prefixOperator<A, T>(_ symbol: String, body: @escaping (A) -> T) -> Function<T?> {\n        return Function([Keyword(symbol), Variable<A>(\"value\")]) {\n            guard let value = $0.variables[\"value\"] as? A else { return nil }\n            return body(value)\n        }\n    }\n    \n    func infixOperator<A, B, T>(_ symbol: String, body: @escaping (A, B) -> T) -> Function<T?> {\n        return Function([Variable<A>(\"lhs\"), Keyword(symbol), Variable<B>(\"rhs\")], options: .backwardMatch) {\n            guard let lhs = $0.variables[\"lhs\"] as? A, let rhs = $0.variables[\"rhs\"] as? B else { return nil }\n            return body(lhs, rhs)\n        }\n    }\n}\n"
  },
  {
    "path": "Tests/EvalTests/IntegrationTests/Suffix.swift",
    "content": "//\n//  Suffix.swift\n//  Eval\n//\n//  Created by László Teveli on 2019. 09. 14..\n//\n\nimport Foundation\nimport XCTest\n@testable import Eval\n\nclass MiniExpressionStandardLibraryTest: XCTestCase {\n    private func evaluate<R>(_ expression: String, inputs: [String: Any] = [:]) -> R? {\n        let context = Context(variables: inputs)\n        let interpreter = TypedInterpreter(dataTypes: MiniExpressionStandardLibrary.dataTypes, functions: MiniExpressionStandardLibrary.functions, context: context)\n        let result = interpreter.evaluate(expression, context: context)\n        print(context.debugInfo)\n        return result as? R\n    }\n    func testComposition() {\n        // based on feedback I realized this doesn't work...\n        // TODO: figure out the suffix error in this case\n        XCTAssertEqual(evaluate(\"(toggle == true) and (url exists)\", inputs: [\"toggle\": true, \"url\": 1]), true)\n//        XCTAssertEqual(evaluate(\"(toggle == true) and (url exists)\", inputs: [\"toggle\": true]), false)\n        XCTAssertEqual(evaluate(\"(toggle == true) and (not(url exists))\", inputs: [\"toggle\": true]), true)\n    }\n    func testComposition2() {\n        // this (prefix function) does work...\n        XCTAssertEqual(evaluate(\"(toggle == true) and (didset url)\", inputs: [\"toggle\": true, \"url\": 1]), true)\n//        XCTAssertEqual(evaluate(\"(toggle == true) and (didset url)\", inputs: [\"toggle\": true]), false)\n        XCTAssertEqual(evaluate(\"(toggle == true) and (not(didset url))\", inputs: [\"toggle\": true]), true)\n    }\n}\n\nclass MiniExpressionStandardLibrary {\n    static var dataTypes: [DataTypeProtocol] {\n        return [\n            booleanType,\n        ]\n    }\n    static var functions: [FunctionProtocol] {\n        return [\n            andOperator,\n            boolParentheses,\n            existsOperator,\n            boolEqualsOperator,\n            didsetOperator,\n        ]\n    }\n    // MARK: - Types\n    \n    static var booleanType: DataType<Bool> {\n        let trueLiteral = Literal(\"true\", convertsTo: true)\n        let falseLiteral = Literal(\"false\", convertsTo: false)\n        return DataType(type: Bool.self, literals: [trueLiteral, falseLiteral]) { $0.value ? \"true\" : \"false\" }\n    }\n    // MARK: - Functions\n    \n    static var boolEqualsOperator: Function<Bool> {\n        return infixOperator(\"==\") { (lhs: Bool, rhs: Bool) in lhs == rhs }\n    }\n    static var boolParentheses: Function<Bool> {\n        return Function([OpenKeyword(\"(\"), Variable<Bool>(\"body\"), CloseKeyword(\")\")]) { $0.variables[\"body\"] as? Bool }\n    }\n    static var andOperator: Function<Bool> {\n        return infixOperator(\"and\") { (lhs: Bool, rhs: Bool) in lhs && rhs }\n    }\n    static var existsOperator: Function<Bool> {\n        return suffixOperator(\"exists\") { (expression: Any?) in expression != nil }\n    }\n    static var didsetOperator: Function<Bool> {\n        return prefixOperator(\"didset\") { (expression: Any?) in expression != nil }\n    }\n    // MARK: - Operator helpers\n    \n    static func infixOperator<A, B, T>(_ symbol: String, body: @escaping (A, B) -> T) -> Function<T> {\n        return Function([Variable<A>(\"lhs\"), Keyword(symbol), Variable<B>(\"rhs\")], options: .backwardMatch) {\n            guard let lhs = $0.variables[\"lhs\"] as? A, let rhs = $0.variables[\"rhs\"] as? B else { return nil }\n            return body(lhs, rhs)\n        }\n    }\n    static func prefixOperator<A, T>(_ symbol: String, body: @escaping (A) -> T) -> Function<T> {\n        return Function([Keyword(symbol), Variable<A>(\"value\")]) {\n            guard let value = $0.variables[\"value\"] as? A else { return nil }\n            return body(value)\n        }\n    }\n    static func suffixOperator<A, T>(_ symbol: String, body: @escaping (A) -> T) -> Function<T> {\n        return Function([Variable<A>(\"value\"), Keyword(symbol)]) {\n            guard let value = $0.variables[\"value\"] as? A else { return nil }\n            return body(value)\n        }\n    }\n}\n"
  },
  {
    "path": "Tests/EvalTests/IntegrationTests/TemplateTests.swift",
    "content": "@testable import Eval\nimport class Eval.Pattern\nimport XCTest\n\nclass TemplateTests: XCTestCase {\n    func test_flow() {\n        let parenthesis = Function([Keyword(\"(\"), Variable<Any>(\"body\"), Keyword(\")\")]) { $0.variables[\"body\"] }\n        let subtractOperator = infixOperator(\"-\") { (lhs: Double, rhs: Double) in lhs - rhs }\n\n        let interpreter = TypedInterpreter(dataTypes: [numberDataType()], functions: [parenthesis, subtractOperator])\n\n        XCTAssertEqual(interpreter.evaluate(\"6 - (4 - 2)\") as! Double, 4)\n    }\n\n    func test_whenAddingALotOfFunctions_thenInterpretationWorksCorrectly() {\n        let parenthesis = Function([Keyword(\"(\"), Variable<Any>(\"body\"), Keyword(\")\")]) { $0.variables[\"body\"] }\n        let plusOperator = infixOperator(\"+\") { (lhs: Double, rhs: Double) in lhs + rhs }\n        let concat = infixOperator(\"+\") { (lhs: String, rhs: String) in lhs + rhs }\n        let lessThan = infixOperator(\"<\") { (lhs: Double, rhs: Double) in lhs < rhs }\n\n        let interpreter = TypedInterpreter(dataTypes: [numberDataType(), stringDataType()],\n                                           functions: [concat, parenthesis, plusOperator, lessThan],\n                                           context: Context(variables: [\"name\": \"Laszlo Teveli\"]))\n\n        let ifStatement = Pattern<String, TemplateInterpreter<String>>([Keyword(\"{%\"), Keyword(\"if\"), Variable<Bool>(\"condition\"), Keyword(\"%}\"), TemplateVariable(\"body\"), Keyword(\"{% endif %}\")]) {\n            guard let condition = $0.variables[\"condition\"] as? Bool, let body = $0.variables[\"body\"] as? String else { return nil }\n            return condition ? body : nil\n        }\n\n        let printStatement = Pattern<String, TemplateInterpreter<String>>([Keyword(\"{{\"), Variable<Any>(\"body\"), Keyword(\"}}\")]) {\n            guard let body = $0.variables[\"body\"] else { return nil }\n            return $0.interpreter.typedInterpreter.print(body)\n        }\n\n        let template = StringTemplateInterpreter(statements: [ifStatement, printStatement], interpreter: interpreter, context: Context())\n        XCTAssertEqual(template.evaluate(\"{{ 1 + 2 }}\"), \"3.0\")\n        XCTAssertEqual(template.evaluate(\"{{ 'Hello' + ' ' + 'World' + '!' }}\"), \"Hello World!\")\n        XCTAssertEqual(template.evaluate(\"asd {% if 10 < 21 %}Hello{% endif %} asd\"), \"asd Hello asd\")\n        XCTAssertEqual(template.evaluate(\"ehm, {% if 10 < 21 %}{{ 'Hello ' + name }}{% endif %}!\"), \"ehm, Hello Laszlo Teveli!\")\n    }\n\n    func test_whenEmbeddingTags_thenInterpretationWorksCorrectly() {\n        let parenthesis = Function<Any>([OpenKeyword(\"(\"), Variable<Any>(\"body\"), CloseKeyword(\")\")]) { $0.variables[\"body\"] }\n        let lessThan = infixOperator(\"<\") { (lhs: Double, rhs: Double) in lhs < rhs }\n        let interpreter = TypedInterpreter(dataTypes: [numberDataType(), stringDataType(), booleanDataType()], functions: [parenthesis, lessThan], context: Context())\n\n        let braces = Pattern<String, TemplateInterpreter<String>>([OpenKeyword(\"(\"), TemplateVariable(\"body\"), CloseKeyword(\")\")]) { $0.variables[\"body\"] as? String }\n        let ifStatement = Pattern<String, TemplateInterpreter<String>>([OpenKeyword(\"{% if\"), Variable<Bool>(\"condition\"), Keyword(\"%}\"), TemplateVariable(\"body\"), CloseKeyword(\"{% endif %}\")]) {\n            guard let condition = $0.variables[\"condition\"] as? Bool, let body = $0.variables[\"body\"] as? String else { return nil }\n            return condition ? body : nil\n        }\n\n        let template = StringTemplateInterpreter(statements: [braces, ifStatement], interpreter: interpreter, context: Context())\n        XCTAssertEqual(template.evaluate(\"(a)\"), \"a\")\n        XCTAssertEqual(template.evaluate(\"(a(b))\"), \"ab\")\n        XCTAssertEqual(template.evaluate(\"((a)b)\"), \"ab\")\n        XCTAssertEqual(template.evaluate(\"(a(b)c)\"), \"abc\")\n        XCTAssertEqual(template.evaluate(\"{% if 10 < 21 %}Hello {% if true %}you{% endif %}!{% endif %}\"), \"Hello you!\")\n    }\n\n    // MARK: Helpers - data types\n\n    func numberDataType() -> DataType<Double> {\n        return DataType(type: Double.self,\n                        literals: [Literal { Double($0.value) },\n                                   Literal(\"pi\", convertsTo: Double.pi) ]) { String(describing: $0.value) }\n    }\n\n    func stringDataType() -> DataType<String> {\n        let singleQuotesLiteral = Literal { literal -> String? in\n            guard let first = literal.value.first, let last = literal.value.last, first == last, first == \"'\" else { return nil }\n            let trimmed = literal.value.trimmingCharacters(in: CharacterSet(charactersIn: \"'\"))\n            return trimmed.contains(\"'\") ? nil : trimmed\n        }\n        return DataType(type: String.self, literals: [singleQuotesLiteral]) { $0.value }\n    }\n\n    func booleanDataType() -> DataType<Bool> {\n        return DataType(type: Bool.self, literals: [Literal(\"false\", convertsTo: false), Literal(\"true\", convertsTo: true)]) { $0.value ? \"true\" : \"false\" }\n    }\n\n    // MARK: Helpers - operators\n\n        func infixOperator<A, B, T>(_ symbol: String, body: @escaping (A, B) -> T) -> Function<T?> {\n        return Function([Variable<A>(\"lhs\"), Keyword(symbol), Variable<B>(\"rhs\")]) {\n            guard let lhs = $0.variables[\"lhs\"] as? A, let rhs = $0.variables[\"rhs\"] as? B else { return nil }\n            return body(lhs, rhs)\n        }\n    }\n}\n"
  },
  {
    "path": "Tests/EvalTests/UnitTests/DataTypeTests.swift",
    "content": "@testable import Eval\nimport XCTest\n\nclass DataTypeTests: XCTestCase {\n\n    // MARK: init\n\n    func test_whenInitialised_then() {\n        let type = Double.self\n        let literal = Literal { Double($0.value) }\n        let print: (DataTypeBody<Double>) -> String = { String($0.value) }\n\n        let dataType = DataType(type: type, literals: [literal], print: print)\n\n        XCTAssertTrue(type == dataType.type.self)\n        XCTAssertTrue(literal === dataType.literals[0])\n        XCTAssertNotNil(dataType.print)\n    }\n\n    // MARK: convert\n\n    func test_whenConverting_thenGeneratesStringValue() {\n        let dataType = DataType(type: Double.self, literals: [Literal { Double($0.value) }]) { String($0.value) }\n\n        let result = dataType.convert(input: \"1\", interpreter: TypedInterpreter())\n\n        XCTAssertEqual(result as! Double, 1)\n    }\n\n    func test_whenConvertingInvalidValue_thenGeneratesNilValue() {\n        let dataType = DataType(type: Double.self, literals: [Literal { Double($0.value) }]) { String($0.value) }\n\n        let result = dataType.convert(input: \"a\", interpreter: TypedInterpreter())\n\n        XCTAssertNil(result)\n    }\n\n    // MARK: print\n\n    func test_whenPrinting_thenGeneratesStringValue() {\n        let dataType = DataType(type: Double.self, literals: [Literal { Double($0.value) }]) { _ in \"printed value\" }\n\n        let result = dataType.print(value: 1.0, printer: TypedInterpreter())\n\n        XCTAssertEqual(result, \"printed value\")\n    }\n}\n"
  },
  {
    "path": "Tests/EvalTests/UnitTests/FunctionTests.swift",
    "content": "@testable import Eval\nimport XCTest\nimport class Eval.Pattern\n\nclass FunctionTests: XCTestCase {\n\n    // MARK: init\n\n    func test_whenInitialised_thenPatternsAreSaved() {\n        let pattern = Pattern<Int, TypedInterpreter>([Keyword(\"in\")]) { _ in 1 }\n\n        let function = Function(patterns: [pattern])\n\n        XCTAssertEqual(function.patterns.count, 1)\n        XCTAssertTrue(pattern === function.patterns[0])\n    }\n\n    func test_whenInitialisedWithOnePatters_thenPatternIsSaved() {\n        let pattern = [Keyword(\"in\")]\n\n        let function = Function(pattern) { _ in 1 }\n\n        XCTAssertEqual(function.patterns.count, 1)\n        XCTAssertEqual(function.patterns[0].elements.count, 1)\n        XCTAssertTrue(pattern[0] === function.patterns[0].elements[0] as! Keyword)\n    }\n\n    // MARK: convert\n\n    func test_whenConverting_thenResultIsValid() {\n        let function = Function([Keyword(\"in\")]) { _ in 1 }\n\n        let result = function.convert(input: \"input\", interpreter: TypedInterpreter(), context: Context())\n\n        XCTAssertEqual(result as! Int, 1)\n    }\n\n    func test_whenConvertingInvalidValue_thenConversionReturnsNil() {\n        let function = Function([Keyword(\"in\")]) { _ in 1 }\n\n        let result = function.convert(input: \"example\", interpreter: TypedInterpreter(), context: Context())\n\n        XCTAssertNil(result)\n    }\n}\n"
  },
  {
    "path": "Tests/EvalTests/UnitTests/InterpreterContextTests.swift",
    "content": "@testable import Eval\nimport XCTest\n\nclass InterpreterContextTests: XCTestCase {\n\n    // MARK: init\n\n    func test_whenCreated_thenVariablesAreSet() {\n        let variables = [\"test\": 2]\n\n        let context = Context(variables: variables)\n\n        XCTAssertEqual(variables, context.variables as! [String: Int])\n    }\n\n    // MARK: push/pop\n\n    func test_whenPushing_thenRemainsTheSame() {\n        let variables = [\"test\": 2]\n        let context = Context(variables: variables)\n\n        context.push()\n\n        XCTAssertEqual(variables, context.variables as! [String: Int])\n    }\n\n    func test_whenPushingAndModifying_thenContextChanges() {\n        let variables = [\"test\": 2]\n        let context = Context(variables: variables)\n\n        context.push()\n        context.variables[\"a\"] = 3\n\n        XCTAssertNotEqual(variables, context.variables as! [String: Int])\n    }\n\n    func test_whenPushingModifyingAndPopping_thenRestores() {\n        let variables = [\"test\": 2]\n        let context = Context(variables: variables)\n\n        context.push()\n        context.variables[\"a\"] = 3\n        context.pop()\n\n        XCTAssertEqual(variables, context.variables as! [String: Int])\n    }\n\n    func test_whenJustPopping_thenNothingHappens() {\n        let variables = [\"test\": 2]\n        let context = Context(variables: variables)\n\n        context.pop()\n\n        XCTAssertEqual(variables, context.variables as! [String: Int])\n    }\n\n    // MARK: merging\n\n    func test_whenMergingTwo_thenCreatesANewContext() {\n        let one = Context(variables: [\"a\": 1])\n        let two = Context(variables: [\"b\": 2])\n\n        let result = one.merging(with: two)\n\n        XCTAssertEqual(result.variables as! [String: Int], [\"a\": 1, \"b\": 2])\n        XCTAssertFalse(one === result)\n        XCTAssertFalse(two === result)\n    }\n\n    func test_whenMergingTwo_thenParameterOverridesVariablesInSelf() {\n        let one = Context(variables: [\"a\": 1])\n        let two = Context(variables: [\"a\": 2, \"x\": 3])\n\n        let result = one.merging(with: two)\n\n        XCTAssertEqual(result.variables as! [String: Int], [\"a\": 2, \"x\": 3])\n    }\n\n    func test_whenMergingWithNil_thenReturnsSelf() {\n        let context = Context(variables: [\"a\": 1])\n\n        let result = context.merging(with: nil)\n\n        XCTAssertTrue(result === context)\n    }\n\n    // MARK: merge\n\n    func test_whenMergingTwoInAMutableWay_thenMergesVariables() {\n        let one = Context(variables: [\"a\": 1])\n        let two = Context(variables: [\"b\": 2])\n\n        one.merge(with: two) { existing, _ in existing }\n\n        XCTAssertEqual(one.variables as! [String: Int], [\"a\": 1, \"b\": 2])\n    }\n\n    func test_whenMergingTwoInAMutableWay_thenParameterOverridesVariablesInSelf() {\n        let one = Context(variables: [\"a\": 1])\n        let two = Context(variables: [\"a\": 2, \"x\": 3])\n\n        one.merge(with: two) { existing, _ in existing }\n\n        XCTAssertEqual(one.variables as! [String: Int], [\"a\": 1, \"x\": 3])\n    }\n\n    func test_whenMergingTwoInAMutableWayReversed_thenParameterOverridesVariablesInSelf() {\n        let one = Context(variables: [\"a\": 1])\n        let two = Context(variables: [\"a\": 2, \"x\": 3])\n\n        two.merge(with: one) { _, new in new }\n\n        XCTAssertEqual(two.variables as! [String: Int], [\"a\": 1, \"x\": 3])\n    }\n\n    func test_whenMergingWithNilInAMutableWay_thenReturnsSelf() {\n        let context = Context(variables: [\"a\": 1])\n\n        context.merge(with: nil) { existing, _ in existing }\n\n        XCTAssertTrue(context.variables as! [String: Int] == [\"a\": 1])\n    }\n}\n"
  },
  {
    "path": "Tests/EvalTests/UnitTests/KeywordTests.swift",
    "content": "@testable import Eval\nimport XCTest\n\nclass KeywordTests: XCTestCase {\n\n    // MARK: Initialisation\n\n    func test_whenKeywordIsCreated_thenNameAndTypeIsSet() {\n        let dummyName = \"test name\"\n        let dummyType = Keyword.KeywordType.generic\n\n        let keyword = Keyword(dummyName, type: dummyType)\n\n        XCTAssertEqual(keyword.name, dummyName)\n        XCTAssertEqual(keyword.type, dummyType)\n    }\n\n    func test_whenKeywordIsCreated_thenTypeIsGenericByDefault() {\n        let keyword = Keyword(\"test name\")\n\n        XCTAssertEqual(keyword.type, .generic)\n    }\n\n    // MARK: Equality\n\n    func test_whenIdenticalKeywordsAreCreated_thenTheyAreEqual() {\n        let keyword1 = Keyword(\"test name\", type: .openingStatement)\n        let keyword2 = Keyword(\"test name\", type: .openingStatement)\n\n        XCTAssertEqual(keyword1, keyword2)\n    }\n\n    func test_whenKeywordsWithDifferentNamesAreCreated_thenTheyAreNotEqual() {\n        let keyword1 = Keyword(\"test name\", type: .openingStatement)\n        let keyword2 = Keyword(\"different\", type: .openingStatement)\n\n        XCTAssertNotEqual(keyword1, keyword2)\n    }\n\n    func test_whenKeywordsWithDifferentTypesAreCreated_thenTheyAreNotEqual() {\n        let keyword1 = Keyword(\"test name\", type: .openingStatement)\n        let keyword2 = Keyword(\"test name\", type: .closingStatement)\n\n        XCTAssertNotEqual(keyword1, keyword2)\n    }\n\n    // MARK: Match\n\n    func test_whenPartlyMatches_thenReturnsPossibleMatch() {\n        let keyword = Keyword(\"checking prefix\")\n\n        let result = keyword.matches(prefix: \"check\")\n\n        XCTAssertTrue(result.isPossibleMatch())\n    }\n\n    func test_whenNotMatches_thenReturnsNoMatch() {\n        let keyword = Keyword(\"checking prefix\")\n\n        let result = keyword.matches(prefix: \"example\")\n\n        XCTAssertTrue(result.isNoMatch())\n    }\n\n    func test_whenMatches_thenReturnsExactMatch() {\n        let keyword = Keyword(\"checking prefix\")\n\n        let result = keyword.matches(prefix: \"checking prefix\")\n\n        verifyMatch(expectation: \"checking prefix\", result: result)\n    }\n\n    func test_whenMatchesAndContinues_thenReturnsExactMatch() {\n        let keyword = Keyword(\"checking prefix\")\n\n        let result = keyword.matches(prefix: \"checking prefix with extra content\")\n\n        verifyMatch(expectation: \"checking prefix\", result: result)\n    }\n\n    // MARK: OpenKeyword\n\n    func test_whenCreatingOpenKeyword_thenTheTypeIsSetCorrectly() {\n        let keyword = OpenKeyword(\"checking prefix\")\n\n        XCTAssertEqual(keyword.type, .openingStatement)\n        XCTAssertEqual(keyword.name, \"checking prefix\")\n    }\n\n    // MARK: CloseKeyword\n\n    func test_whenCreatingCloseKeyword_thenTheTypeIsSetCorrectly() {\n        let keyword = CloseKeyword(\"checking prefix\")\n\n        XCTAssertEqual(keyword.type, .closingStatement)\n        XCTAssertEqual(keyword.name, \"checking prefix\")\n    }\n\n    // MARK: Match performance\n\n    func test_whenShortKeywordMatchesShortInput_thenPerformsWell() {\n        let keyword = Keyword(\"=\")\n        self.measure {\n            _ = keyword.matches(prefix: \"= asd\")\n        }\n    }\n\n    func test_whenShortKeywordNotMatchesInput_thenPerformsWell() {\n        let keyword = Keyword(\"=\")\n        self.measure {\n            _ = keyword.matches(prefix: \"checking prefix\")\n        }\n    }\n\n    func test_whenShortKeywordHureInput_thenPerformsWell() {\n        let keyword = Keyword(\"=\")\n        self.measure {\n            _ = keyword.matches(prefix: \"\"\"\nLorem Ipsum is simply dummy text of the printing and typesetting industry.\nLorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.\nIt has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged.\nIt was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.\n\"\"\")\n        }\n    }\n\n    func test_whenLargeKeywordMatchesShortInput_thenPerformsWell() {\n        let keyword = Keyword(\"this is an example to match\")\n        self.measure {\n            _ = keyword.matches(prefix: \"this is an example to match and some other things\")\n        }\n    }\n\n    func test_whenLargeKeywordNotMatchesInput_thenPerformsWell() {\n        let keyword = Keyword(\"this is an example to match\")\n        self.measure {\n            _ = keyword.matches(prefix: \"x and y\")\n        }\n    }\n\n    func test_whenLargeKeywordHureInput_thenPerformsWell() {\n        let keyword = Keyword(\"=\")\n        self.measure {\n            _ = keyword.matches(prefix: \"\"\"\nLorem Ipsum is simply dummy text of the printing and typesetting industry.\nLorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.\nIt has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged.\nIt was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.\n\"\"\")\n        }\n    }\n\n    // MARK: Helpers\n\n    func verifyMatch(expectation: String, result: MatchResult<Any>) {\n        if case .exactMatch(let length, let output, let variables) = result {\n            XCTAssertEqual(length, expectation.count)\n            XCTAssertEqual(output as! String, expectation)\n            XCTAssertTrue(variables.isEmpty)\n        } else {\n            fatalError(\"No match\")\n        }\n    }\n}\n"
  },
  {
    "path": "Tests/EvalTests/UnitTests/LiteralTests.swift",
    "content": "@testable import Eval\nimport XCTest\n\nclass LiteralTests: XCTestCase {\n\n    // MARK: init\n\n    func test_whenInitialisedWithBlock_thenParameterIsSaved() {\n        let block: (LiteralBody) -> Double? = { Double($0.value) }\n\n        let literal = Literal(convert: block)\n\n        XCTAssertNotNil(literal.convert)\n    }\n\n    func test_whenInitialisedWithValue_thenConvertBlockIsSaved() {\n        let literal = Literal(\"true\", convertsTo: false)\n\n        XCTAssertNotNil(literal.convert)\n    }\n\n    // MARK: convert\n\n    func test_whenConverting_thenCallsBlock() {\n        let block: (LiteralBody) -> Int? = { _ in 123 }\n        let literal = Literal(convert: block)\n\n        let result = literal.convert(input: \"asd\", interpreter: TypedInterpreter())\n\n        XCTAssertEqual(result!, 123)\n    }\n}\n"
  },
  {
    "path": "Tests/EvalTests/UnitTests/MatchResultTests.swift",
    "content": "@testable import Eval\nimport XCTest\n\nclass MatchResultTests: XCTestCase {\n\n    // MARK: isMatch\n\n    func test_whenMatchIsExactMatch_thenIsMatchReturnsTrue() {\n        let matchResult = MatchResult.exactMatch(length: 1, output: \"a\", variables: [:])\n\n        XCTAssertTrue(matchResult.isMatch())\n    }\n\n    func test_whenMatchIsNotExactMatch_thenIsMatchReturnsFalse() {\n        let matchResult = MatchResult<String>.anyMatch(exhaustive: true)\n\n        XCTAssertFalse(matchResult.isMatch())\n    }\n\n    // MARK: isPossibleMatch\n\n    func test_whenMatchIsPossibleyMatch_thenIsPossibleMatchReturnsTrue() {\n        let matchResult = MatchResult<Int>.possibleMatch\n\n        XCTAssertTrue(matchResult.isPossibleMatch())\n    }\n\n    func test_whenMatchIsNotPossibleyMatch_thenIsPossibleMatchReturnsFalse() {\n        let matchResult = MatchResult<Int>.noMatch\n\n        XCTAssertFalse(matchResult.isPossibleMatch())\n    }\n\n    // MARK: isNoMatch\n\n    func test_whenMatchIsNoMatch_thenIsNoMatchReturnsTrue() {\n        let matchResult = MatchResult<Int>.noMatch\n\n        XCTAssertTrue(matchResult.isNoMatch())\n    }\n\n    func test_whenMatchIsNotNoMatch_thenIsNoMatchReturnsFalse() {\n        let matchResult = MatchResult<Int>.anyMatch(exhaustive: false)\n\n        XCTAssertFalse(matchResult.isNoMatch())\n    }\n\n    // MARK: isAnyMatch\n\n    func test_whenMatchIsAnyMatch_thenIsAnyMatchReturnsTrue() {\n        let matchResult = MatchResult<Int>.anyMatch(exhaustive: true)\n\n        XCTAssertTrue(matchResult.isAnyMatch(exhaustive: true))\n    }\n\n    func test_whenMatchIsAnyMatch_thenIsAnyMatchWithParameterReturnsTrue() {\n        let matchResult = MatchResult<Int>.anyMatch(exhaustive: false)\n\n        XCTAssertTrue(matchResult.isAnyMatch(exhaustive: false))\n    }\n\n    func test_whenMatchIsNotAnyMatch_thenIsAnyMatchReturnsFalse() {\n        let matchResult = MatchResult<Int>.possibleMatch\n\n        XCTAssertFalse(matchResult.isAnyMatch())\n    }\n\n    // MARK: Equality\n\n    func test_whenTwoAnyMatchesAreCompared_thenResultIsEqual() {\n        let one = MatchResult<Int>.anyMatch(exhaustive: false)\n        let two = MatchResult<Int>.anyMatch(exhaustive: false)\n\n        XCTAssertTrue(one == two)\n    }\n\n    func test_whenTwoAnyMatchesWithDifferentPropertiesAreCompared_thenResultIsNotEqual() {\n        let one = MatchResult<Int>.anyMatch(exhaustive: false)\n        let two = MatchResult<Int>.anyMatch(exhaustive: true)\n\n        XCTAssertFalse(one == two)\n    }\n\n    func test_whenTwoNoMatchesAreCompared_thenResultIsEqual() {\n        let one = MatchResult<Int>.noMatch\n        let two = MatchResult<Int>.noMatch\n\n        XCTAssertTrue(one == two)\n    }\n\n    func test_whenTwoPossibleMatchesAreCompared_thenResultIsEqual() {\n        let one = MatchResult<Int>.possibleMatch\n        let two = MatchResult<Int>.possibleMatch\n\n        XCTAssertTrue(one == two)\n    }\n\n    func test_whenTwoExactMatchesAreCompared_thenResultIsEqual() {\n        let one = MatchResult<String>.exactMatch(length: 1, output: \"a\", variables: [:])\n        let two = MatchResult<String>.exactMatch(length: 1, output: \"a\", variables: [:])\n\n        XCTAssertTrue(one == two)\n    }\n\n    func test_whenTwoExactMatchesWithDifferentPropertiesAreCompared_thenResultIsNotEqual() {\n        let one = MatchResult<String>.exactMatch(length: 1, output: \"a\", variables: [:])\n        let two = MatchResult<String>.exactMatch(length: 2, output: \"b\", variables: [\"1\": 2])\n\n        XCTAssertFalse(one == two)\n    }\n\n    func test_whenTwoDifferentMatchesAreCompared_thenResultIsNotEqual() {\n        let one = MatchResult<String>.exactMatch(length: 1, output: \"a\", variables: [:])\n        let two = MatchResult<String>.anyMatch(exhaustive: true)\n\n        XCTAssertFalse(one == two)\n    }\n}\n"
  },
  {
    "path": "Tests/EvalTests/UnitTests/MatchStatementTests.swift",
    "content": "@testable import Eval\nimport XCTest\nimport class Eval.Pattern\n\nclass MatchStatementTests: XCTestCase {\n\n    func test_whenMatchingOne_returnsMatch() {\n        let input = \"input\"\n        let matcher = Pattern<Int, DummyInterpreter>([Keyword(\"in\")]) { _ in 1 }\n\n        let result1 = matcher.matches(string: input, interpreter: DummyInterpreter(), context: Context())\n        let result2 = matchStatement(amongst: [matcher], in: input, interpreter: DummyInterpreter(), context: Context())\n\n        XCTAssertTrue(result1 == result2)\n    }\n\n    func test_whenMatchingTwo_returnsMatch() {\n        let input = \"input\"\n        let matcher1 = Pattern<Int, DummyInterpreter>([Keyword(\"in\")]) { _ in 1 }\n        let matcher2 = Pattern<Int, DummyInterpreter>([Keyword(\"on\")]) { _ in 2 }\n\n        let result = matchStatement(amongst: [matcher1, matcher2], in: input, interpreter: DummyInterpreter(), context: Context())\n\n        XCTAssertTrue(result == MatchResult.exactMatch(length: 2, output: 1, variables: [:]))\n    }\n\n    func test_whenMatchingTwoMatches_returnsTheFirstMatch() {\n        let input = \"input\"\n        let matcher1 = Pattern<Int, DummyInterpreter>([Keyword(\"in\")]) { _ in 1 }\n        let matcher2 = Pattern<Int, DummyInterpreter>([Keyword(\"inp\")]) { _ in 2 }\n\n        let result = matchStatement(amongst: [matcher1, matcher2], in: input, interpreter: DummyInterpreter(), context: Context())\n\n        XCTAssertTrue(result == MatchResult.exactMatch(length: 2, output: 1, variables: [:]))\n    }\n\n    func test_whenMatchingInvalid_returnsNoMatch() {\n        let input = \"xxx\"\n        let matcher1 = Pattern<Int, DummyInterpreter>([Keyword(\"in\")]) { _ in 1 }\n        let matcher2 = Pattern<Int, DummyInterpreter>([Keyword(\"on\")]) { _ in 2 }\n\n        let result = matchStatement(amongst: [matcher1, matcher2], in: input, interpreter: DummyInterpreter(), context: Context())\n\n        XCTAssertTrue(result == MatchResult.noMatch)\n    }\n\n    func test_whenMatchingPrefix_returnsPossibleMatch() {\n        let input = \"i\"\n        let matcher1 = Pattern<Int, DummyInterpreter>([Keyword(\"in\")]) { _ in 1 }\n        let matcher2 = Pattern<Int, DummyInterpreter>([Keyword(\"on\")]) { _ in 2 }\n\n        let result = matchStatement(amongst: [matcher1, matcher2], in: input, interpreter: DummyInterpreter(), context: Context())\n\n        XCTAssertTrue(result == MatchResult.possibleMatch)\n    }\n}\n"
  },
  {
    "path": "Tests/EvalTests/UnitTests/MatcherTests.swift",
    "content": "@testable import Eval\nimport XCTest\n\nclass MatcherTests: XCTestCase {\n\n    // MARK: isEmbedded\n\n    func test_whenEmbedding_thenIsEmbeddedReturnsTrue() {\n        let opening = Keyword(\"(\", type: .openingStatement)\n        let closing = Keyword(\")\", type: .closingStatement)\n        let processor = VariableProcessor(interpreter: DummyInterpreter(), context: Context())\n        let matcher = Matcher(pattern: pattern([opening, closing]), processor: processor)\n\n        let input = \"(input(random))\"\n        let result = matcher.isEmbedded(element: closing, in: input, at: input.startIndex)\n\n        XCTAssertTrue(result)\n    }\n\n    func test_whenNotEmbedding_thenIsEmbeddedReturnsFalse() {\n        let opening = Keyword(\"(\", type: .openingStatement)\n        let closing = Keyword(\")\", type: .closingStatement)\n        let processor = VariableProcessor(interpreter: DummyInterpreter(), context: Context())\n        let matcher = Matcher(pattern: pattern([opening, closing]), processor: processor)\n\n        let input = \"input\"\n        let result = matcher.isEmbedded(element: opening, in: input, at: input.startIndex)\n\n        XCTAssertFalse(result)\n    }\n\n    func test_whenEmbeddingButLate_thenIsEmbeddedReturnsFalse() {\n        let opening = Keyword(\"(\", type: .openingStatement)\n        let closing = Keyword(\")\", type: .closingStatement)\n        let processor = VariableProcessor(interpreter: DummyInterpreter(), context: Context())\n        let matcher = Matcher(pattern: pattern([opening, closing]), processor: processor)\n\n        let input = \"input(random)\"\n        let result = matcher.isEmbedded(element: closing, in: input, at: input.index(input.startIndex, offsetBy: 12))\n\n        XCTAssertFalse(result)\n    }\n\n    // MARK: positionOfClosingTag\n\n    func test_whenEmbedding_thenClosingPositionIsValid() {\n        let opening = Keyword(\"(\", type: .openingStatement)\n        let closing = Keyword(\")\", type: .closingStatement)\n        let processor = VariableProcessor(interpreter: DummyInterpreter(), context: Context())\n        let matcher = Matcher(pattern: pattern([opening, closing]), processor: processor)\n\n        let input = \"(input(random))\"\n        XCTAssertEqual(matcher.positionOfClosingTag(in: input, from: input.startIndex), input.index(input.startIndex, offsetBy: 14))\n        XCTAssertEqual(matcher.positionOfClosingTag(in: input, from: input.index(after: input.startIndex)), input.index(input.startIndex, offsetBy: 13))\n    }\n\n    func test_whenNotEmbedding_thenClosingPositionIsNil() {\n        let opening = Keyword(\"(\", type: .openingStatement)\n        let closing = Keyword(\")\", type: .closingStatement)\n        let processor = VariableProcessor(interpreter: DummyInterpreter(), context: Context())\n        let matcher = Matcher(pattern: pattern([opening, closing]), processor: processor)\n\n        let input = \"input\"\n        XCTAssertNil(matcher.positionOfClosingTag(in: input, from: input.startIndex))\n    }\n\n    func test_whenEmbeddingButLate_thenClosingPositionIsNil() {\n        let opening = Keyword(\"(\", type: .openingStatement)\n        let closing = Keyword(\")\", type: .closingStatement)\n        let processor = VariableProcessor(interpreter: DummyInterpreter(), context: Context())\n        let matcher = Matcher(pattern: pattern([opening, closing]), processor: processor)\n\n        let input = \"(input(random))\"\n        XCTAssertNil(matcher.positionOfClosingTag(in: input, from: input.index(input.startIndex, offsetBy: 8)))\n    }\n\n    private func pattern(_ elements: [PatternElement]) -> Eval.Pattern<Any, DummyInterpreter> {\n        return Pattern(elements) { _ in \"\" }\n    }\n}\n"
  },
  {
    "path": "Tests/EvalTests/UnitTests/PatternTests.swift",
    "content": "@testable import Eval\nimport XCTest\nimport class Eval.Pattern\n\nclass PatternTests: XCTestCase {\n\n    // MARK: init\n\n    class DummyElement: PatternElement {\n        func matches(prefix: String, options: PatternOptions) -> MatchResult<Any> {\n            return .noMatch\n        }\n    }\n\n    func test_whenInitialised_thenElementsAndMatcherAreSet() {\n        let element = DummyElement()\n        let matcherBlock: MatcherBlock<Int, DummyInterpreter> = { _ in 1 }\n\n        let matcher = Pattern<Int, DummyInterpreter>([element], matcher: matcherBlock)\n\n        XCTAssertTrue(element === matcher.elements[0] as! DummyElement)\n        //XCTAssertTrue(matcherBlock === matcher.matcher)\n    }\n\n    func test_whenInitialisedWithVariableOnTheLastPlace_thenLastVariableBecomesNotShortest() {\n        let element = DummyElement()\n        let variable = GenericVariable<String, DummyInterpreter>(\"name\")\n\n        let matcher = Pattern<String, DummyInterpreter>([element, variable]) { _ in \"x\" }\n\n        let result = matcher.elements[1] as! GenericVariable<String, DummyInterpreter>\n        XCTAssertTrue(element === matcher.elements[0] as! DummyElement)\n        XCTAssertFalse(variable === result)\n        XCTAssertTrue(result.options.contains(.exhaustiveMatch))\n    }\n\n    // MARK: matches\n\n    // swiftlint:disable:next function_body_length\n    func test_whenMatching_thenExpectingAppropriateResults() {\n        // swiftlint:disable:next nesting\n        typealias TestCase = (elements: [PatternElement], input: String, expectedResult: MatchResult<Int>)\n\n        let keyword = Keyword(\"ok\")\n        let variable = GenericVariable<String, DummyInterpreter>(\"name\", options: .notInterpreted)\n        let variableLongest = GenericVariable<String, DummyInterpreter>(\"name\", options: [.notInterpreted, .exhaustiveMatch])\n        let variable2 = GenericVariable<String, DummyInterpreter>(\"last\", options: .notInterpreted)\n\n        let testCases: [TestCase] = [\n            ([keyword], \"invalid\", .noMatch),\n            ([keyword], \"o\", .possibleMatch),\n            ([keyword], \"ok\", .exactMatch(length: 2, output: 1, variables: [:])),\n            ([keyword], \"okokok\", .exactMatch(length: 2, output: 1, variables: [:])),\n\n            ([variable], \"anything\", .exactMatch(length: 8, output: 1, variables: [\"name\": \"anything\"])),\n            ([variableLongest], \"anything\", .exactMatch(length: 8, output: 1, variables: [\"name\": \"anything\"])),\n\n            ([variable, keyword], \"invalid\", .possibleMatch),\n            ([variable, keyword], \"invalid o\", .possibleMatch),\n            ([variable, keyword], \"invalid ok\", .exactMatch(length: 10, output: 1, variables: [\"name\": \"invalid\"])),\n            ([variable, keyword], \"invalidxok\", .exactMatch(length: 10, output: 1, variables: [\"name\": \"invalidx\"])),\n            ([variable, keyword], \"invalidxok extra\", .exactMatch(length: 10, output: 1, variables: [\"name\": \"invalidx\"])),\n\n            ([keyword, variable], \"xokthen\", .noMatch),\n            ([keyword, variable], \"o\", .possibleMatch),\n            ([keyword, variable], \"oi\", .noMatch),\n            ([keyword, variable], \"ok\", .exactMatch(length: 2, output: 1, variables: [\"name\": \"\"])),\n            ([keyword, variable], \"ok then\", .exactMatch(length: 7, output: 1, variables: [\"name\": \"then\"])),\n            ([keyword, variable], \"ok,then\", .exactMatch(length: 7, output: 1, variables: [\"name\": \",then\"])),\n\n            ([keyword, variable, keyword], \"o\", .possibleMatch),\n            ([keyword, variable, keyword], \"ok\", .possibleMatch),\n            ([keyword, variable, keyword], \"oko\", .possibleMatch),\n            ([keyword, variable, keyword], \"okok\", .exactMatch(length: 4, output: 1, variables: [\"name\": \"\"])),\n            ([keyword, variable, keyword], \"okxok\", .exactMatch(length: 5, output: 1, variables: [\"name\": \"x\"])),\n            ([keyword, variable, keyword], \"okokok\", .exactMatch(length: 4, output: 1, variables: [\"name\": \"\"])),\n            ([keyword, variableLongest, keyword], \"ok\", .possibleMatch),\n            ([keyword, variableLongest, keyword], \"okx\", .possibleMatch),\n            ([keyword, variableLongest, keyword], \"oko\", .possibleMatch),\n\n            ([keyword, variableLongest, keyword], \"okok\", .possibleMatch),\n            ([keyword, variableLongest, keyword], \"okxok\", .possibleMatch),\n\n            ([variable, keyword, variable2], \"xo\", .possibleMatch),\n            ([variable, keyword, variable2], \"xok\", .exactMatch(length: 3, output: 1, variables: [\"name\": \"x\", \"last\": \"\"])),\n            ([variable, keyword, variable2], \"xoky\", .exactMatch(length: 4, output: 1, variables: [\"name\": \"x\", \"last\": \"y\"])),\n            ([variable, keyword, variable2], \"xoky and rest\", .exactMatch(length: 13, output: 1, variables: [\"name\": \"x\", \"last\": \"y and rest\"])),\n            ([variable, keyword, variable2], \"xokoky\", .exactMatch(length: 6, output: 1, variables: [\"name\": \"x\", \"last\": \"oky\"]))\n        ]\n\n        for testCase in testCases {\n            let matcher = Pattern<Int, DummyInterpreter>(testCase.elements) { _ in 1 }\n            let result = matcher.matches(string: testCase.input, interpreter: DummyInterpreter(), context: Context())\n            XCTAssertTrue(result == testCase.expectedResult, \"\\(testCase.input) should have resulted in \\(testCase.expectedResult) but got \\(result) instead\")\n        }\n    }\n\n    func test_whenMatchingForwards_thenExpectingAppropriateResults() {\n        let matcher = Pattern<Int, TypedInterpreter>([Variable<Int>(\"lhs\"), Keyword(\"-\"), Variable<Int>(\"rhs\")]) {\n            guard let lhs = $0.variables[\"lhs\"] as? Int, let rhs = $0.variables[\"rhs\"] as? Int else { return nil }\n            return lhs - rhs\n        }\n        let function = Function(patterns: [matcher])\n        let interpreter = TypedInterpreter(dataTypes: [DataType(type: Int.self, literals: [Literal { Int($0.value) }]) { String($0.value) }], functions: [function])\n        XCTAssertEqual(interpreter.evaluate(\"3 - 2 - 1\") as! Int, 2)\n    }\n\n    func test_whenMatchingBackwards_thenExpectingAppropriateResults() {\n        let matcher = Pattern<Int, TypedInterpreter>([Variable<Int>(\"lhs\"), Keyword(\"-\"), Variable<Int>(\"rhs\")], options: .backwardMatch) {\n            guard let lhs = $0.variables[\"lhs\"] as? Int, let rhs = $0.variables[\"rhs\"] as? Int else { return nil }\n            return lhs - rhs\n        }\n        let function = Function(patterns: [matcher])\n        let interpreter = TypedInterpreter(dataTypes: [DataType(type: Int.self, literals: [Literal { Int($0.value) }]) { String($0.value) }], functions: [function])\n        XCTAssertEqual(interpreter.evaluate(\"3 - 2 - 1\") as! Int, 0)\n    }\n}\n"
  },
  {
    "path": "Tests/EvalTests/UnitTests/TemplateInterpreterTests.swift",
    "content": "@testable import Eval\nimport XCTest\nimport class Eval.Pattern\n\nclass StringTemplateInterpreterTests: XCTestCase {\n\n    // MARK: init\n\n    func test_whenInitialised_thenPropertiesAreSaved() {\n        let matcher = Pattern<String, TemplateInterpreter<String>>([Keyword(\"in\")]) { _ in \"a\" }\n        let statements = [matcher]\n        let interpreter = TypedInterpreter()\n        let context = Context()\n\n        let stringTemplateInterpreter = StringTemplateInterpreter(statements: statements,\n                                                                  interpreter: interpreter,\n                                                                  context: context)\n\n        XCTAssertEqual(stringTemplateInterpreter.statements.count, 1)\n        XCTAssertTrue(statements[0] === stringTemplateInterpreter.statements[0])\n        XCTAssertTrue(interpreter === stringTemplateInterpreter.typedInterpreter)\n        XCTAssertTrue(context === stringTemplateInterpreter.context)\n        XCTAssertFalse(stringTemplateInterpreter.typedInterpreter.context === stringTemplateInterpreter.context)\n    }\n\n    func test_whenInitialised_thenTypedAndTemplateInterpreterDoNotShareTheSameContext() {\n        let stringTemplateInterpreter = StringTemplateInterpreter(statements: [], interpreter: TypedInterpreter(), context: Context())\n\n        XCTAssertFalse(stringTemplateInterpreter.typedInterpreter.context === stringTemplateInterpreter.context)\n    }\n\n    // MARK: evaluate\n\n    func test_whenEvaluates_thenTransformationHappens() {\n        let matcher = Pattern<String, TemplateInterpreter<String>>([Keyword(\"in\")]) { _ in \"contains\" }\n        let interpreter = StringTemplateInterpreter(statements: [matcher],\n                                                    interpreter: TypedInterpreter(),\n                                                    context: Context())\n\n        let result = interpreter.evaluate(\"a in b\")\n\n        XCTAssertEqual(result, \"a contains b\")\n    }\n\n    func test_whenEvaluates_thenUsesGlobalContext() {\n        let matcher = Pattern<String, TemplateInterpreter<String>>([Keyword(\"{somebody}\")]) { $0.context.variables[\"person\"] as? String }\n        let interpreter = StringTemplateInterpreter(statements: [matcher],\n                                                    interpreter: TypedInterpreter(),\n                                                    context: Context(variables: [\"person\": \"you\"]))\n\n        let result = interpreter.evaluate(\"{somebody} + me\")\n\n        XCTAssertEqual(result, \"you + me\")\n    }\n\n    // MARK: evaluate with context\n\n    func test_whenEvaluatesWithContext_thenUsesLocalContext() {\n        let matcher = Pattern<String, TemplateInterpreter<String>>([Keyword(\"{somebody}\")]) { $0.context.variables[\"person\"] as? String }\n        let interpreter = StringTemplateInterpreter(statements: [matcher],\n                                                    interpreter: TypedInterpreter(),\n                                                    context: Context())\n\n        let result = interpreter.evaluate(\"{somebody} + me\", context: Context(variables: [\"person\": \"you\"]))\n\n        XCTAssertEqual(result, \"you + me\")\n    }\n\n    func test_whenEvaluatesWithContext_thenLocalOverridesGlobalContext() {\n        let matcher = Pattern<String, TemplateInterpreter<String>>([Keyword(\"{somebody}\")]) { $0.context.variables[\"person\"] as? String }\n        let interpreter = StringTemplateInterpreter(statements: [matcher],\n                                                    interpreter: TypedInterpreter(),\n                                                    context: Context(variables: [\"person\": \"nobody\"]))\n\n        let result = interpreter.evaluate(\"{somebody} + me\", context: Context(variables: [\"person\": \"you\"]))\n\n        XCTAssertEqual(result, \"you + me\")\n    }\n\n    // MARK: TemplateVariable\n\n    func test_whenUsingTemplateVariable_thenTransformationHappens() {\n        let matcher = Pattern<String, TemplateInterpreter<String>>([Keyword(\"{\"), TemplateVariable(\"person\"), Keyword(\"}\")]) { _ in \"you\" }\n        let interpreter = StringTemplateInterpreter(statements: [matcher],\n                                                    interpreter: TypedInterpreter(),\n                                                    context: Context())\n\n        let result = interpreter.evaluate(\"{somebody} + me\")\n\n        XCTAssertEqual(result, \"you + me\")\n    }\n\n    func test_whenUsingTemplateVariableWithNilResult_thenTransformationNotHappens() {\n        let matcher = Pattern<String, TemplateInterpreter<String>>([Keyword(\"{\"), TemplateVariable(\"person\"), Keyword(\"}\")]) { _ in nil }\n        let interpreter = StringTemplateInterpreter(statements: [matcher],\n                                                    interpreter: TypedInterpreter(),\n                                                    context: Context())\n\n        let result = interpreter.evaluate(\"{somebody} + me\")\n\n        XCTAssertEqual(result, \"{somebody} + me\")\n    }\n}\n"
  },
  {
    "path": "Tests/EvalTests/UnitTests/TypedInterpreterTests.swift",
    "content": "@testable import Eval\nimport XCTest\n\nclass TypedInterpreterTests: XCTestCase {\n\n    // MARK: init\n\n    func test_whenInitialised_thenPropertiesAreSaved() {\n        let dataTypes = [DataType(type: String.self, literals: []) { $0.value }]\n        let functions = [Function([Keyword(\"a\")]) { _ in \"a\" } ]\n        let context = Context()\n\n        let interpreter = TypedInterpreter(dataTypes: dataTypes,\n                                           functions: functions,\n                                           context: context)\n\n        XCTAssertEqual(interpreter.dataTypes.count, 1)\n        XCTAssertTrue(dataTypes[0] === interpreter.dataTypes[0] as! DataType<String>)\n\n        XCTAssertEqual(interpreter.functions.count, 1)\n        XCTAssertTrue(functions[0] === interpreter.functions[0] as! Function<String>)\n\n        XCTAssertTrue(context === interpreter.context)\n    }\n\n    // MARK: evaluate\n\n    func test_whenEvaluates_thenTransformationHappens() {\n        let interpreter = TypedInterpreter(dataTypes: [DataType(type: Int.self, literals: [Literal { Int($0.value) }]) { String($0.value) }],\n                                           functions: [Function([Variable<Int>(\"lhs\"), Keyword(\"plus\"), Variable<Int>(\"rhs\")]) { ($0.variables[\"lhs\"] as! Int) + ($0.variables[\"rhs\"] as! Int) } ],\n                                           context: Context())\n\n        let result = interpreter.evaluate(\"1 plus 2\")\n\n        XCTAssertEqual(result as! Int, 3)\n    }\n\n    func test_whenEvaluates_thenUsesGlobalContext() {\n        let interpreter = TypedInterpreter(dataTypes: [DataType(type: Int.self, literals: [Literal { Int($0.value) }]) { String($0.value) }],\n                                           functions: [Function([Variable<Int>(\"lhs\"), Keyword(\"plus\"), Variable<Int>(\"rhs\")]) { ($0.variables[\"lhs\"] as! Int) + ($0.variables[\"rhs\"] as! Int) } ],\n                                           context: Context(variables: [\"a\": 2]))\n\n        let result = interpreter.evaluate(\"1 plus a\")\n\n        XCTAssertEqual(result as! Int, 3)\n    }\n\n    // MARK: evaluate with context\n\n    func test_whenEvaluatesWithContext_thenUsesLocalContext() {\n        let interpreter = TypedInterpreter(dataTypes: [DataType(type: Int.self, literals: [Literal { Int($0.value) }]) { String($0.value) }],\n                                           functions: [Function([Variable<Int>(\"lhs\"), Keyword(\"plus\"), Variable<Int>(\"rhs\")]) { ($0.variables[\"lhs\"] as! Int) + ($0.variables[\"rhs\"] as! Int) } ],\n                                           context: Context())\n\n        let result = interpreter.evaluate(\"1 plus a\", context: Context(variables: [\"a\": 2]))\n\n        XCTAssertEqual(result as! Int, 3)\n    }\n\n    func test_whenEvaluatesWithContext_thenLocalOverridesGlobalContext() {\n        let interpreter = TypedInterpreter(dataTypes: [DataType(type: Int.self, literals: [Literal { Int($0.value) }]) { String($0.value) }],\n                                           functions: [Function([Variable<Int>(\"lhs\"), Keyword(\"plus\"), Variable<Int>(\"rhs\")]) { ($0.variables[\"lhs\"] as! Int) + ($0.variables[\"rhs\"] as! Int) } ],\n                                           context: Context(variables: [\"a\": 1]))\n\n        let result = interpreter.evaluate(\"1 plus a\", context: Context(variables: [\"a\": 2]))\n\n        XCTAssertEqual(result as! Int, 3)\n    }\n\n    // MARK: print\n\n    func test_whenPrintingDataType_thenReturnsItsBlock() {\n        let interpreter = TypedInterpreter(dataTypes: [DataType(type: Int.self, literals: [Literal { Int($0.value) }]) { String($0.value) }],\n                                           functions: [],\n                                           context: Context())\n\n        let result = interpreter.print(1)\n\n        XCTAssertEqual(result, \"1\")\n    }\n\n    func test_whenPrintingUnknownDataType_thenReturnsDescription() {\n        let interpreter = TypedInterpreter(dataTypes: [DataType(type: Int.self, literals: [Literal { Int($0.value) }]) { String($0.value) }],\n                                           functions: [],\n                                           context: Context())\n\n        let result = interpreter.print(true)\n\n        XCTAssertEqual(result, true.description)\n    }\n}\n"
  },
  {
    "path": "Tests/EvalTests/UnitTests/UtilTests.swift",
    "content": "@testable import Eval\nimport XCTest\n\nclass UtilTests: XCTestCase {\n\n    // MARK: plus operator on Elements\n\n    class DummyX: PatternElement, Equatable {\n        func matches(prefix: String, options: PatternOptions) -> MatchResult<Any> { return .noMatch }\n        static func == (lhs: DummyX, rhs: DummyX) -> Bool { return true }\n    }\n\n    class DummyY: PatternElement, Equatable {\n        func matches(prefix: String, options: PatternOptions) -> MatchResult<Any> { return .possibleMatch }\n        static func == (lhs: DummyY, rhs: DummyY) -> Bool { return true }\n    }\n\n    func test_whenApplyingPlusOperatorOnElements_thenItCreatedAnArray() {\n        let element1 = DummyX()\n        let element2 = DummyY()\n\n        let result = element1 + element2\n\n        XCTAssertEqual(result.count, 2)\n        XCTAssertEqual(result[0] as! DummyX, element1)\n        XCTAssertEqual(result[1] as! DummyY, element2)\n    }\n\n    // MARK: plus operator on Array\n\n    func test_whenApplyingPlusOperatorOnArrayWithItem_thenItCreatesAMergedArray() {\n        let result = [1, 2, 3] + 4\n\n        XCTAssertEqual(result, [1, 2, 3, 4])\n    }\n\n    func test_whenApplyingPlusEqualsOperatorOnArrayWithItem_thenItCreatesAMergedArray() {\n        var array = [1, 2, 3]\n        array += 4\n\n        XCTAssertEqual(array, [1, 2, 3, 4])\n    }\n\n    // MARK: String trim\n\n    func test_whenTrimminString_thenRemovesWhitespaces() {\n        XCTAssertEqual(\"   asd   \".trim(), \"asd\")\n        XCTAssertEqual(\" \\t  asd \\n  \".trim(), \"asd\")\n    }\n}\n"
  },
  {
    "path": "Tests/EvalTests/UnitTests/VariableProcessor.swift",
    "content": "@testable import Eval\nimport XCTest\n\nclass VariableProcessorTests: XCTestCase {\n\n    // init\n\n    func test_whenInitialising_thenSetsParametersCorrectly() {\n        let interpreter = DummyInterpreter()\n        let context = Context()\n        let processor = VariableProcessor(interpreter: interpreter, context: context)\n\n        XCTAssertTrue(interpreter === processor.interpreter)\n        XCTAssertTrue(context === processor.context)\n    }\n\n    // process\n\n    func test_whenProcessing_thenUsesMap() {\n        let variable: VariableValue = (metadata: GenericVariable<String, DummyInterpreter>(\"name\") { _ in \"xyz\" }, value: \"asd\")\n        let processor = VariableProcessor(interpreter: DummyInterpreter(), context: Context())\n\n        let result = processor.process(variable)\n\n        XCTAssertEqual(result as! String, \"xyz\")\n    }\n\n    func test_whenProcessingAndInterpreted_thenUsesInterpreter() {\n        let variable: VariableValue = (metadata: GenericVariable<String, DummyInterpreter>(\"name\", options: .notTrimmed), value: \"asd\")\n        let processor = VariableProcessor(interpreter: DummyInterpreter(), context: Context())\n\n        let result = processor.process(variable)\n\n        XCTAssertEqual(result as! String, \"a\")\n    }\n\n    func test_whenProcessingAndNotTrimmed_thenDoesNotTrim() {\n        let variable: VariableValue = (metadata: GenericVariable<String, DummyInterpreter>(\"name\", options: [.notTrimmed, .notInterpreted]), value: \"  asd  \")\n        let processor = VariableProcessor(interpreter: DummyInterpreter(), context: Context())\n\n        let result = processor.process(variable)\n\n        XCTAssertEqual(result as! String, \"  asd  \")\n    }\n}\n"
  },
  {
    "path": "Tests/EvalTests/UnitTests/VariableTests.swift",
    "content": "@testable import Eval\nimport XCTest\n\nclass VariableTests: XCTestCase {\n\n    // MARK: init\n\n    func test_whenInitialised_thenPropertiesAreSet() {\n        let variable = GenericVariable<String, DummyInterpreter>(\"name\", options: .acceptsNilValue) { _ in nil }\n\n        XCTAssertEqual(variable.name, \"name\")\n        XCTAssertEqual(variable.options, .acceptsNilValue)\n        XCTAssertNotNil(variable.map)\n    }\n\n    func test_whenInitialised_thenDefaultAreSetCorrectly() {\n        let variable = GenericVariable<String, DummyInterpreter>(\"name\")\n\n        XCTAssertEqual(variable.name, \"name\")\n        XCTAssertEqual(variable.options, [])\n        XCTAssertNotNil(variable.map)\n    }\n\n    // MARK: matches\n\n    func test_whenCallingMatches_thenReturnAny() {\n        let variable = GenericVariable<String, DummyInterpreter>(\"name\")\n\n        XCTAssertTrue(variable.matches(prefix: \"asd\").isAnyMatch())\n    }\n\n    // MARK: mapped\n\n    func test_whenCallingMatched_thenCreatesANewVariable() {\n        let variable = GenericVariable<String, TypedInterpreter>(\"name\")\n        let result = variable.mapped { Double($0) }\n\n        XCTAssertNotNil(result)\n        XCTAssertEqual(variable.name, result.name)\n        XCTAssertEqual(variable.options, result.options)\n        XCTAssertEqual(result.performMap(input: \"1\", interpreter: TypedInterpreter()) as! Double, 1)\n    }\n\n    // MARK: performMap\n\n    func test_whenCallingPerformMap_thenUsesMapClosure() {\n        let variable = GenericVariable<Int, DummyInterpreter>(\"name\") { _ in 123 }\n        let result = variable.performMap(input: 1, interpreter: DummyInterpreter())\n\n        XCTAssertEqual(result as! Int, 123)\n    }\n\n    // MARK: matches performance\n\n    func test_whenCallingMatchesWithShortInput_thenPerformsEffectively() {\n        let variable = GenericVariable<String, DummyInterpreter>(\"name\")\n\n        XCTAssertTrue(variable.matches(prefix: \"asd\").isAnyMatch())\n    }\n\n    func test_whenCallingMatchesWithLargeInput_thenPerformsEffectively() {\n        let variable = GenericVariable<String, DummyInterpreter>(\"name\")\n\n        XCTAssertTrue(variable.matches(prefix: \"\"\"\nLorem Ipsum is simply dummy text of the printing and typesetting industry.\nLorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.\nIt has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged.\nIt was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.\n\"\"\").isAnyMatch())\n    }\n}\n"
  },
  {
    "path": "Tests/EvalTests/Utils.swift",
    "content": "import Eval\nimport Foundation\n\nclass DummyInterpreter: Interpreter {\n    typealias VariableEvaluator = DummyInterpreter\n    typealias EvaluatedType = String\n\n    var context: Context\n    var interpreterForEvaluatingVariables: DummyInterpreter { return self }\n\n    func evaluate(_ expression: String) -> String { return \"a\" }\n    func evaluate(_ expression: String, context: Context) -> String { return \"a\" }\n    init() { context = Context() }\n}\n"
  },
  {
    "path": "Tests/LinuxMain.swift",
    "content": "@testable import InterpreterTests\nimport XCTest\n\nXCTMain([\n    testCase(InterpreterTests.allTests)\n])\n"
  }
]