<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <link rel="stylesheet" href="../coverage.css"/> <title> mw_parser/core.clj </title> </head> <body> <span class="covered" title="1 out of 1 forms covered"> 001 (ns ^{:doc "A very simple parser which parses production rules." </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 002 :author "Simon Brooke"} </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 003 mw-parser.core </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 004 (:use mw-engine.utils </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 005 [clojure.string :only [split trim triml]]) </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 006 (:gen-class) </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 007 ) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 008 </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 009 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 010 ;;;; </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 011 ;;;; mw-parser: a rule parser for MicroWorld. </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 012 ;;;; </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 013 ;;;; This program is free software; you can redistribute it and/or </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 014 ;;;; modify it under the terms of the GNU General Public License </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 015 ;;;; as published by the Free Software Foundation; either version 2 </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 016 ;;;; of the License, or (at your option) any later version. </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 017 ;;;; </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 018 ;;;; This program is distributed in the hope that it will be useful, </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 019 ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 020 ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 021 ;;;; GNU General Public License for more details. </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 022 ;;;; </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 023 ;;;; You should have received a copy of the GNU General Public License </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 024 ;;;; along with this program; if not, write to the Free Software </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 025 ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 026 ;;;; USA. </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 027 ;;;; </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 028 ;;;; Copyright (C) 2014 Simon Brooke </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 029 ;;;; </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 030 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 031 ;;;; </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 032 ;;;; A very simple parser which parses production rules of the following forms: </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 033 ;;;; </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 034 ;;;; * "if altitude is less than 100 and state is forest then state should be climax and deer should be 3" </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 035 ;;;; * "if altitude is 100 or fertility is 25 then state should be heath and fertility should be 24.3" </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 036 ;;;; * "if altitude is 100 or fertility is 25 then state should be heath" </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 037 ;;;; * "if deer is more than 2 and wolves is 0 and fertility is more than 20 then deer should be deer + 2" </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 038 ;;;; * "if deer is more than 1 and wolves is more than 1 then deer should be deer - wolves" </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 039 ;;;; * "if state is grassland and 4 neighbours have state equal to water then state should be village" </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 040 ;;;; * "if state is forest and fertility is between 55 and 75 then state should be climax" </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 041 ;;;; * "if 6 neighbours have state equal to water then state should be village" </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 042 ;;;; * "if state is in grassland or pasture or heath and 4 neighbours are water then state should be village" </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 043 ;;;; * "if state is forest or state is climax and some neighbours have state equal to fire then 3 in 5 chance that state should be fire" </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 044 ;;;; * "if state is pasture and more than 3 neighbours have state equal to scrub then state should be scrub" </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 045 ;;;; * </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 046 ;;;; </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 047 ;;;; it generates rules in the form expected by `mw-engine.core`, q.v. </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 048 ;;;; </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 049 ;;;; It is, as I say, very simple; it generates a complete rule, or it fails completely, returning nil. </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 050 ;;;; Very occasionally it generates a wrong rule - one which is not a correct translation of the rule </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 051 ;;;; semantics - but that is buggy behaviour, which I'll try to fix over the next few weeks, not a </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 052 ;;;; design fault. </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 053 ;;;; </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 054 ;;;; More significantly it does not generate useful error messages on failure. </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 055 ;;;; </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 056 ;;;; This parser is now obsolete, but is retained in the codebase for now in </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 057 ;;;; case it is of use to anyone. Prefer the declarative.clj parser. </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 058 ;;;; </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 059 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; </span><br/> <span class="blank" title="0 out of 0 forms covered"> 060 </span><br/> <span class="covered" title="2 out of 2 forms covered"> 061 (declare parse-conditions) </span><br/> <span class="covered" title="2 out of 2 forms covered"> 062 (declare parse-not-condition) </span><br/> <span class="covered" title="2 out of 2 forms covered"> 063 (declare parse-simple-condition) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 064 </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 065 ;; a regular expression which matches string representation of positive numbers </span><br/> <span class="covered" title="2 out of 2 forms covered"> 066 (def re-number #"^[0-9.]*$") </span><br/> <span class="blank" title="0 out of 0 forms covered"> 067 </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 068 ;; error thrown when an attempt is made to set a reserved property </span><br/> <span class="covered" title="2 out of 2 forms covered"> 069 (def reserved-properties-error </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 070 "The properties 'x' and 'y' of a cell are reserved and should not be set in rule actions") </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 071 ;; error thrown when a rule cannot be parsed </span><br/> <span class="covered" title="2 out of 2 forms covered"> 072 (def bad-parse-error "I did not understand '%s'") </span><br/> <span class="blank" title="0 out of 0 forms covered"> 073 </span><br/> <span class="covered" title="1 out of 1 forms covered"> 074 (defn- keyword-or-numeric </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 075 "If this token appears to represent an explicit number, return that number; </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 076 otherwise, make a keyword of it and return that." </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 077 [token] </span><br/> <span class="partial" title="4 out of 5 forms covered"> 078 (cond </span><br/> <span class="covered" title="7 out of 7 forms covered"> 079 (re-matches re-number token) (read-string token) </span><br/> <span class="partial" title="3 out of 4 forms covered"> 080 (keyword? token) token </span><br/> <span class="covered" title="3 out of 3 forms covered"> 081 true (keyword token))) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 082 </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 083 ;; Generally all functions in this file with names beginning 'parse-' take a </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 084 ;; sequence of tokens (and in some cases other optional arguments) and return a </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 085 ;; vector comprising </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 086 ;; </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 087 ;; 1. A code fragment parsed from the front of the sequence of tokens, and </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 088 ;; 2. the remaining tokens which were not consumed in constructing that fragment. </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 089 ;; </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 090 ;; In every case if the function cannot parse the desired construct from the </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 091 ;; front of the sequence of tokens it returns nil. </span><br/> <span class="blank" title="0 out of 0 forms covered"> 092 </span><br/> <span class="blank" title="0 out of 0 forms covered"> 093 </span><br/> <span class="covered" title="1 out of 1 forms covered"> 094 (defn parse-numeric-value </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 095 "Parse a number." </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 096 [[value & remainder]] </span><br/> <span class="covered" title="15 out of 15 forms covered"> 097 (if (and value (re-matches re-number value)) [(read-string value) remainder])) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 098 </span><br/> <span class="covered" title="1 out of 1 forms covered"> 099 (defn parse-property-int </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 100 "Parse a token assumed to be the name of a property of the current cell, </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 101 whose value is assumed to be an integer." </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 102 [[value & remainder]] </span><br/> <span class="covered" title="11 out of 11 forms covered"> 103 (if value [(list 'get-int 'cell (keyword value)) remainder])) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 104 </span><br/> <span class="covered" title="1 out of 1 forms covered"> 105 (defn parse-property-value </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 106 "Parse a token assumed to be the name of a property of the current cell." </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 107 [[value & remainder]] </span><br/> <span class="covered" title="10 out of 10 forms covered"> 108 (if value [(list (keyword value) 'cell) remainder])) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 109 </span><br/> <span class="covered" title="1 out of 1 forms covered"> 110 (defn parse-token-value </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 111 "Parse a token assumed to be a simple token value." </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 112 [[value & remainder]] </span><br/> <span class="covered" title="7 out of 7 forms covered"> 113 (if value [(keyword value) remainder])) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 114 </span><br/> <span class="covered" title="1 out of 1 forms covered"> 115 (defn parse-simple-value </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 116 "Parse a value from the first of these `tokens`. If `expect-int` is true, return </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 117 an integer or something which will evaluate to an integer." </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 118 ([tokens expect-int] </span><br/> <span class="partial" title="7 out of 8 forms covered"> 119 (or </span><br/> <span class="covered" title="3 out of 3 forms covered"> 120 (parse-numeric-value tokens) </span><br/> <span class="covered" title="1 out of 1 forms covered"> 121 (cond expect-int </span><br/> <span class="covered" title="3 out of 3 forms covered"> 122 (parse-property-int tokens) </span><br/> <span class="covered" title="3 out of 3 forms covered"> 123 true (parse-token-value tokens)))) </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 124 ([tokens] </span><br/> <span class="covered" title="4 out of 4 forms covered"> 125 (parse-simple-value tokens false))) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 126 </span><br/> <span class="covered" title="1 out of 1 forms covered"> 127 (defn gen-token-value </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 128 "Parse a single value from this single token and return just the generated </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 129 code, not a pair." </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 130 [token expect-int] </span><br/> <span class="covered" title="8 out of 8 forms covered"> 131 (first (parse-simple-value (list token) expect-int))) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 132 </span><br/> <span class="covered" title="1 out of 1 forms covered"> 133 (defn parse-disjunct-value </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 134 "Parse a list of values from among these `tokens`. If `expect-int` is true, return </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 135 integers or things which will evaluate to integers." </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 136 [[OR token & tokens] expect-int] </span><br/> <span class="covered" title="6 out of 6 forms covered"> 137 (cond (member? OR '("or" "in")) </span><br/> <span class="covered" title="9 out of 9 forms covered"> 138 (let [value (first (parse-simple-value (list token) expect-int)) </span><br/> <span class="covered" title="5 out of 5 forms covered"> 139 seek-others (= (first tokens) "or")] </span><br/> <span class="partial" title="4 out of 5 forms covered"> 140 (cond seek-others </span><br/> <span class="covered" title="5 out of 5 forms covered"> 141 (let [[others remainder] (parse-disjunct-value tokens expect-int)] </span><br/> <span class="covered" title="6 out of 6 forms covered"> 142 [(cons value others) remainder]) </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 143 true </span><br/> <span class="covered" title="5 out of 5 forms covered"> 144 [(list value) tokens])))) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 145 </span><br/> <span class="covered" title="1 out of 1 forms covered"> 146 (defn parse-value </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 147 "Parse a value from among these `tokens`. If `expect-int` is true, return </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 148 an integer or something which will evaluate to an integer." </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 149 ([tokens expect-int] </span><br/> <span class="partial" title="4 out of 5 forms covered"> 150 (or </span><br/> <span class="covered" title="4 out of 4 forms covered"> 151 (parse-disjunct-value tokens expect-int) </span><br/> <span class="covered" title="3 out of 3 forms covered"> 152 (parse-simple-value tokens expect-int))) </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 153 ([tokens] </span><br/> <span class="covered" title="4 out of 4 forms covered"> 154 (parse-value tokens false))) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 155 </span><br/> <span class="covered" title="1 out of 1 forms covered"> 156 (defn parse-member-condition </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 157 "Parses a condition of the form '[property] in [value] or [value]...'" </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 158 [[property IS IN & rest]] </span><br/> <span class="partial" title="11 out of 12 forms covered"> 159 (if (and (member? IS '("is" "are")) (= IN "in")) </span><br/> <span class="covered" title="8 out of 8 forms covered"> 160 (let [[l remainder] (parse-disjunct-value (cons "in" rest) false)] </span><br/> <span class="covered" title="15 out of 15 forms covered"> 161 [(list 'member? (list (keyword property) 'cell) (list 'quote l)) remainder]))) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 162 </span><br/> <span class="covered" title="1 out of 1 forms covered"> 163 (defn- parse-less-condition </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 164 "Parse '[property] less than [value]'." </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 165 [[property IS LESS THAN & rest]] </span><br/> <span class="partial" title="20 out of 21 forms covered"> 166 (cond (and (member? IS '("is" "are")) (member? LESS '("less" "fewer")) (= THAN "than")) </span><br/> <span class="covered" title="5 out of 5 forms covered"> 167 (let [[value remainder] (parse-value rest true)] </span><br/> <span class="covered" title="13 out of 13 forms covered"> 168 [(list '< (list 'get-int 'cell (keyword property)) value) remainder]))) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 169 </span><br/> <span class="covered" title="1 out of 1 forms covered"> 170 (defn- parse-more-condition </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 171 "Parse '[property] more than [value]'." </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 172 [[property IS MORE THAN & rest]] </span><br/> <span class="partial" title="20 out of 21 forms covered"> 173 (cond (and (member? IS '("is" "are")) (member? MORE '("more" "greater")) (= THAN "than")) </span><br/> <span class="covered" title="5 out of 5 forms covered"> 174 (let [[value remainder] (parse-value rest true)] </span><br/> <span class="covered" title="13 out of 13 forms covered"> 175 [(list '> (list 'get-int 'cell (keyword property)) value) remainder]))) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 176 </span><br/> <span class="covered" title="1 out of 1 forms covered"> 177 (defn- parse-between-condition </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 178 [[p IS BETWEEN v1 AND v2 & rest]] </span><br/> <span class="partial" title="27 out of 29 forms covered"> 179 (cond (and (member? IS '("is" "are")) (= BETWEEN "between") (= AND "and") (not (nil? v2))) </span><br/> <span class="covered" title="9 out of 9 forms covered"> 180 (let [property (first (parse-simple-value (list p) true)) </span><br/> <span class="covered" title="8 out of 8 forms covered"> 181 value1 (first (parse-simple-value (list v1) true)) </span><br/> <span class="covered" title="8 out of 8 forms covered"> 182 value2 (first (parse-simple-value (list v2) true))] </span><br/> <span class="covered" title="4 out of 4 forms covered"> 183 [(list 'or </span><br/> <span class="covered" title="6 out of 6 forms covered"> 184 (list '< value1 property value2) </span><br/> <span class="covered" title="7 out of 7 forms covered"> 185 (list '> value1 property value2)) rest]))) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 186 </span><br/> <span class="covered" title="1 out of 1 forms covered"> 187 (defn- parse-is-condition </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 188 "Parse clauses of the form 'x is y', 'x is in y or z...', </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 189 'x is between y and z', 'x is more than y' or 'x is less than y'. </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 190 It is necessary to disambiguate whether value is a numeric or keyword." </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 191 [[property IS value & rest]] </span><br/> <span class="partial" title="1 out of 2 forms covered"> 192 (cond </span><br/> <span class="covered" title="4 out of 4 forms covered"> 193 (member? IS '("is" "are")) </span><br/> <span class="covered" title="8 out of 8 forms covered"> 194 (let [tokens (cons property (cons value rest))] </span><br/> <span class="partial" title="2 out of 3 forms covered"> 195 (cond </span><br/> <span class="covered" title="19 out of 19 forms covered"> 196 (re-matches re-number value) [(list '= (list 'get-int 'cell (keyword property)) (read-string value)) rest] </span><br/> <span class="covered" title="15 out of 15 forms covered"> 197 value [(list '= (list (keyword property) 'cell) (keyword value)) rest])))) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 198 </span><br/> <span class="covered" title="1 out of 1 forms covered"> 199 (defn- parse-not-condition </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 200 "Parse the negation of a simple condition." </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 201 [[property IS NOT & rest]] </span><br/> <span class="partial" title="12 out of 13 forms covered"> 202 (cond (and (member? IS '("is" "are")) (= NOT "not")) </span><br/> <span class="covered" title="10 out of 10 forms covered"> 203 (let [partial (parse-simple-condition (cons property (cons "is" rest)))] </span><br/> <span class="partial" title="2 out of 3 forms covered"> 204 (cond partial </span><br/> <span class="covered" title="2 out of 2 forms covered"> 205 (let [[condition remainder] partial] </span><br/> <span class="covered" title="6 out of 6 forms covered"> 206 [(list 'not condition) remainder]))))) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 207 </span><br/> <span class="covered" title="1 out of 1 forms covered"> 208 (defn- gen-neighbours-condition </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 209 ([comp1 quantity property value remainder comp2 distance] </span><br/> <span class="covered" title="4 out of 4 forms covered"> 210 [(list comp1 </span><br/> <span class="covered" title="3 out of 3 forms covered"> 211 (list 'count </span><br/> <span class="covered" title="6 out of 6 forms covered"> 212 (list 'get-neighbours-with-property-value 'world </span><br/> <span class="covered" title="1 out of 1 forms covered"> 213 '(cell :x) '(cell :y) distance </span><br/> <span class="covered" title="7 out of 7 forms covered"> 214 (keyword property) (keyword-or-numeric value) comp2)) </span><br/> <span class="covered" title="1 out of 1 forms covered"> 215 quantity) </span><br/> <span class="covered" title="1 out of 1 forms covered"> 216 remainder]) </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 217 ([comp1 quantity property value remainder comp2] </span><br/> <span class="not-covered" title="0 out of 9 forms covered"> 218 (gen-neighbours-condition comp1 quantity property value remainder comp2 1))) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 219 </span><br/> <span class="covered" title="1 out of 1 forms covered"> 220 (defn parse-comparator-neighbours-condition </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 221 "Parse conditions of the form '...more than 6 neighbours are [condition]'" </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 222 [[MORE THAN n NEIGHBOURS WITHIN distance have-or-are & rest]] </span><br/> <span class="covered" title="8 out of 8 forms covered"> 223 (let [quantity (first (parse-numeric-value (list n))) </span><br/> <span class="covered" title="8 out of 8 forms covered"> 224 comparator (cond (= MORE "more") '> </span><br/> <span class="covered" title="4 out of 4 forms covered"> 225 (member? MORE '("fewer" "less")) '<)] </span><br/> <span class="covered" title="3 out of 3 forms covered"> 226 (cond </span><br/> <span class="covered" title="4 out of 4 forms covered"> 227 (not= WITHIN "within") </span><br/> <span class="covered" title="2 out of 2 forms covered"> 228 (parse-comparator-neighbours-condition </span><br/> <span class="covered" title="2 out of 2 forms covered"> 229 (flatten </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 230 ;; two tokens were mis-parsed as 'within distance' that weren't </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 231 ;; actually 'within' and a distance. Splice in 'within 1' and try </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 232 ;; again. </span><br/> <span class="covered" title="12 out of 12 forms covered"> 233 (list MORE THAN n NEIGHBOURS "within" "1" WITHIN distance have-or-are rest))) </span><br/> <span class="partial" title="14 out of 15 forms covered"> 234 (and quantity </span><br/> <span class="covered" title="1 out of 1 forms covered"> 235 comparator </span><br/> <span class="covered" title="3 out of 3 forms covered"> 236 (= THAN "than") </span><br/> <span class="covered" title="1 out of 1 forms covered"> 237 (= NEIGHBOURS "neighbours")) </span><br/> <span class="partial" title="2 out of 3 forms covered"> 238 (cond </span><br/> <span class="covered" title="3 out of 3 forms covered"> 239 (= have-or-are "are") </span><br/> <span class="covered" title="2 out of 2 forms covered"> 240 (let [[value & remainder] rest </span><br/> <span class="covered" title="4 out of 4 forms covered"> 241 dist (gen-token-value distance true)] </span><br/> <span class="covered" title="9 out of 9 forms covered"> 242 (gen-neighbours-condition comparator quantity :state value remainder = dist)) </span><br/> <span class="covered" title="3 out of 3 forms covered"> 243 (= have-or-are "have") </span><br/> <span class="covered" title="2 out of 2 forms covered"> 244 (let [[property comp1 comp2 value & remainder] rest </span><br/> <span class="covered" title="4 out of 4 forms covered"> 245 dist (gen-token-value distance true)] </span><br/> <span class="partial" title="13 out of 14 forms covered"> 246 (cond (and (= comp1 "equal") (= comp2 "to")) </span><br/> <span class="covered" title="5 out of 5 forms covered"> 247 (gen-neighbours-condition comparator quantity property </span><br/> <span class="covered" title="4 out of 4 forms covered"> 248 value remainder = dist) </span><br/> <span class="covered" title="10 out of 10 forms covered"> 249 (and (= comp1 "more") (= comp2 "than")) </span><br/> <span class="covered" title="5 out of 5 forms covered"> 250 (gen-neighbours-condition comparator quantity property </span><br/> <span class="covered" title="4 out of 4 forms covered"> 251 value remainder > dist) </span><br/> <span class="partial" title="9 out of 10 forms covered"> 252 (and (= comp1 "less") (= comp2 "than")) </span><br/> <span class="covered" title="5 out of 5 forms covered"> 253 (gen-neighbours-condition comparator quantity property </span><br/> <span class="covered" title="4 out of 4 forms covered"> 254 value remainder < dist) </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 255 )))))) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 256 </span><br/> <span class="covered" title="1 out of 1 forms covered"> 257 (defn parse-some-neighbours-condition </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 258 [[SOME NEIGHBOURS & rest]] </span><br/> <span class="covered" title="2 out of 2 forms covered"> 259 (cond </span><br/> <span class="covered" title="10 out of 10 forms covered"> 260 (and (= SOME "some") (= NEIGHBOURS "neighbours")) </span><br/> <span class="covered" title="6 out of 6 forms covered"> 261 (parse-comparator-neighbours-condition (concat '("more" "than" "0" "neighbours") rest)))) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 262 </span><br/> <span class="covered" title="1 out of 1 forms covered"> 263 (defn parse-simple-neighbours-condition </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 264 "Parse conditions of the form '...6 neighbours are [condition]'" </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 265 [[n NEIGHBOURS WITHIN distance have-or-are & rest]] </span><br/> <span class="covered" title="8 out of 8 forms covered"> 266 (let [quantity (first (parse-numeric-value (list n)))] </span><br/> <span class="covered" title="2 out of 2 forms covered"> 267 (cond </span><br/> <span class="covered" title="8 out of 8 forms covered"> 268 (and quantity (= NEIGHBOURS "neighbours")) </span><br/> <span class="partial" title="3 out of 4 forms covered"> 269 (cond </span><br/> <span class="covered" title="4 out of 4 forms covered"> 270 (not= WITHIN "within") </span><br/> <span class="covered" title="2 out of 2 forms covered"> 271 (parse-simple-neighbours-condition </span><br/> <span class="covered" title="2 out of 2 forms covered"> 272 (flatten </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 273 ;; two tokens were mis-parsed as 'within distance' that weren't </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 274 ;; actually 'within' and a distance. Splice in 'within 1' and try </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 275 ;; again. </span><br/> <span class="covered" title="10 out of 10 forms covered"> 276 (list n NEIGHBOURS "within" "1" WITHIN distance have-or-are rest))) </span><br/> <span class="covered" title="3 out of 3 forms covered"> 277 (= have-or-are "are") </span><br/> <span class="covered" title="2 out of 2 forms covered"> 278 (let [[value & remainder] rest </span><br/> <span class="covered" title="4 out of 4 forms covered"> 279 dist (gen-token-value distance true)] </span><br/> <span class="covered" title="9 out of 9 forms covered"> 280 (gen-neighbours-condition '= quantity :state value remainder = dist)) </span><br/> <span class="covered" title="3 out of 3 forms covered"> 281 (= have-or-are "have") </span><br/> <span class="covered" title="2 out of 2 forms covered"> 282 (let [[property comp1 comp2 value & remainder] rest </span><br/> <span class="covered" title="4 out of 4 forms covered"> 283 dist (gen-token-value distance true)] </span><br/> <span class="partial" title="13 out of 14 forms covered"> 284 (cond (and (= comp1 "equal") (= comp2 "to")) </span><br/> <span class="covered" title="8 out of 8 forms covered"> 285 (gen-neighbours-condition '= quantity property value remainder = </span><br/> <span class="covered" title="1 out of 1 forms covered"> 286 dist) </span><br/> <span class="covered" title="10 out of 10 forms covered"> 287 (and (= comp1 "more") (= comp2 "than")) </span><br/> <span class="covered" title="8 out of 8 forms covered"> 288 (gen-neighbours-condition '= quantity property value remainder > </span><br/> <span class="covered" title="1 out of 1 forms covered"> 289 dist) </span><br/> <span class="partial" title="9 out of 10 forms covered"> 290 (and (= comp1 "less") (= comp2 "than")) </span><br/> <span class="covered" title="8 out of 8 forms covered"> 291 (gen-neighbours-condition '= quantity property value remainder < </span><br/> <span class="covered" title="1 out of 1 forms covered"> 292 dist) </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 293 )))))) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 294 </span><br/> <span class="covered" title="1 out of 1 forms covered"> 295 (defn parse-neighbours-condition </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 296 "Parse conditions referring to neighbours" </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 297 [tokens] </span><br/> <span class="covered" title="9 out of 9 forms covered"> 298 (or </span><br/> <span class="covered" title="3 out of 3 forms covered"> 299 (parse-simple-neighbours-condition tokens) </span><br/> <span class="covered" title="3 out of 3 forms covered"> 300 (parse-comparator-neighbours-condition tokens) </span><br/> <span class="covered" title="2 out of 2 forms covered"> 301 (parse-some-neighbours-condition tokens) </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 302 )) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 303 </span><br/> <span class="covered" title="1 out of 1 forms covered"> 304 (defn parse-simple-condition </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 305 "Parse conditions of the form '[property] [comparison] [value]'." </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 306 [tokens] </span><br/> <span class="covered" title="25 out of 25 forms covered"> 307 (or </span><br/> <span class="covered" title="3 out of 3 forms covered"> 308 (parse-neighbours-condition tokens) </span><br/> <span class="covered" title="3 out of 3 forms covered"> 309 (parse-member-condition tokens) </span><br/> <span class="covered" title="3 out of 3 forms covered"> 310 (parse-not-condition tokens) </span><br/> <span class="covered" title="3 out of 3 forms covered"> 311 (parse-less-condition tokens) </span><br/> <span class="covered" title="3 out of 3 forms covered"> 312 (parse-more-condition tokens) </span><br/> <span class="covered" title="3 out of 3 forms covered"> 313 (parse-between-condition tokens) </span><br/> <span class="covered" title="2 out of 2 forms covered"> 314 (parse-is-condition tokens))) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 315 </span><br/> <span class="covered" title="1 out of 1 forms covered"> 316 (defn- parse-disjunction-condition </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 317 "Parse '... or [condition]' from `tokens`, where `left` is the already parsed first disjunct." </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 318 [left tokens] </span><br/> <span class="covered" title="4 out of 4 forms covered"> 319 (let [partial (parse-conditions tokens)] </span><br/> <span class="covered" title="2 out of 2 forms covered"> 320 (if partial </span><br/> <span class="covered" title="2 out of 2 forms covered"> 321 (let [[right remainder] partial] </span><br/> <span class="covered" title="7 out of 7 forms covered"> 322 [(list 'or left right) remainder])))) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 323 </span><br/> <span class="covered" title="1 out of 1 forms covered"> 324 (defn- parse-conjunction-condition </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 325 "Parse '... and [condition]' from `tokens`, where `left` is the already parsed first conjunct." </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 326 [left tokens] </span><br/> <span class="covered" title="4 out of 4 forms covered"> 327 (let [partial (parse-conditions tokens)] </span><br/> <span class="covered" title="2 out of 2 forms covered"> 328 (if partial </span><br/> <span class="covered" title="2 out of 2 forms covered"> 329 (let [[right remainder] partial] </span><br/> <span class="covered" title="7 out of 7 forms covered"> 330 [(list 'and left right) remainder])))) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 331 </span><br/> <span class="covered" title="1 out of 1 forms covered"> 332 (defn- parse-conditions </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 333 "Parse conditions from `tokens`, where conditions may be linked by either 'and' or 'or'." </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 334 [tokens] </span><br/> <span class="covered" title="4 out of 4 forms covered"> 335 (let [partial (parse-simple-condition tokens)] </span><br/> <span class="covered" title="2 out of 2 forms covered"> 336 (if partial </span><br/> <span class="covered" title="2 out of 2 forms covered"> 337 (let [[left [next & remainder]] partial] </span><br/> <span class="partial" title="4 out of 5 forms covered"> 338 (cond </span><br/> <span class="covered" title="7 out of 7 forms covered"> 339 (= next "and") (parse-conjunction-condition left remainder) </span><br/> <span class="covered" title="7 out of 7 forms covered"> 340 (= next "or") (parse-disjunction-condition left remainder) </span><br/> <span class="covered" title="1 out of 1 forms covered"> 341 true partial))))) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 342 </span><br/> <span class="covered" title="1 out of 1 forms covered"> 343 (defn- parse-left-hand-side </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 344 "Parse the left hand side ('if...') of a production rule." </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 345 [[IF & tokens]] </span><br/> <span class="covered" title="1 out of 1 forms covered"> 346 (if </span><br/> <span class="covered" title="3 out of 3 forms covered"> 347 (= IF "if") </span><br/> <span class="covered" title="3 out of 3 forms covered"> 348 (parse-conditions tokens))) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 349 </span><br/> <span class="covered" title="1 out of 1 forms covered"> 350 (defn- parse-arithmetic-action </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 351 "Parse actions of the form '[property] should be [property] [arithmetic-operator] [value]', </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 352 e.g. 'fertility should be fertility + 1', or 'deer should be deer - wolves'." </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 353 [previous [prop1 SHOULD BE prop2 operator value & rest]] </span><br/> <span class="covered" title="3 out of 3 forms covered"> 354 (cond </span><br/> <span class="covered" title="4 out of 4 forms covered"> 355 (member? prop1 '("x" "y")) </span><br/> <span class="covered" title="1 out of 1 forms covered"> 356 (throw </span><br/> <span class="covered" title="2 out of 2 forms covered"> 357 (Exception. reserved-properties-error)) </span><br/> <span class="partial" title="10 out of 12 forms covered"> 358 (and (= SHOULD "should") </span><br/> <span class="covered" title="3 out of 3 forms covered"> 359 (= BE "be") </span><br/> <span class="covered" title="3 out of 3 forms covered"> 360 (member? operator '("+" "-" "*" "/"))) </span><br/> <span class="partial" title="9 out of 10 forms covered"> 361 [(list 'merge (or previous 'cell) </span><br/> <span class="covered" title="7 out of 7 forms covered"> 362 {(keyword prop1) (list 'int </span><br/> <span class="covered" title="12 out of 12 forms covered"> 363 (list (symbol operator) (list 'get-int 'cell (keyword prop2)) </span><br/> <span class="partial" title="3 out of 4 forms covered"> 364 (cond </span><br/> <span class="covered" title="7 out of 7 forms covered"> 365 (re-matches re-number value) (read-string value) </span><br/> <span class="covered" title="8 out of 8 forms covered"> 366 true (list 'get-int 'cell (keyword value)))))}) rest])) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 367 </span><br/> <span class="covered" title="1 out of 1 forms covered"> 368 (defn- parse-set-action </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 369 "Parse actions of the form '[property] should be [value].'" </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 370 [previous [property SHOULD BE value & rest]] </span><br/> <span class="partial" title="2 out of 3 forms covered"> 371 (cond </span><br/> <span class="covered" title="4 out of 4 forms covered"> 372 (member? property '("x" "y")) </span><br/> <span class="not-covered" title="0 out of 1 forms covered"> 373 (throw </span><br/> <span class="not-covered" title="0 out of 2 forms covered"> 374 (Exception. reserved-properties-error)) </span><br/> <span class="partial" title="9 out of 10 forms covered"> 375 (and (= SHOULD "should") (= BE "be")) </span><br/> <span class="covered" title="10 out of 10 forms covered"> 376 [(list 'merge (or previous 'cell) </span><br/> <span class="partial" title="18 out of 19 forms covered"> 377 {(keyword property) (cond (re-matches re-number value) (read-string value) true (keyword value))}) rest])) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 378 </span><br/> <span class="covered" title="1 out of 1 forms covered"> 379 (defn- parse-simple-action [previous tokens] </span><br/> <span class="covered" title="9 out of 9 forms covered"> 380 (or (parse-arithmetic-action previous tokens) </span><br/> <span class="covered" title="3 out of 3 forms covered"> 381 (parse-set-action previous tokens))) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 382 </span><br/> <span class="covered" title="1 out of 1 forms covered"> 383 (defn- parse-actions </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 384 "Parse actions from tokens." </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 385 [previous tokens] </span><br/> <span class="covered" title="5 out of 5 forms covered"> 386 (let [[left remainder] (parse-simple-action previous tokens)] </span><br/> <span class="partial" title="2 out of 3 forms covered"> 387 (cond left </span><br/> <span class="partial" title="8 out of 9 forms covered"> 388 (cond (= (first remainder) "and") </span><br/> <span class="covered" title="6 out of 6 forms covered"> 389 (parse-actions left (rest remainder)) </span><br/> <span class="covered" title="3 out of 3 forms covered"> 390 true (list left))))) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 391 </span><br/> <span class="covered" title="1 out of 1 forms covered"> 392 (defn- parse-probability </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 393 "Parse a probability of an action from this collection of tokens" </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 394 [previous [n CHANCE IN m & tokens]] </span><br/> <span class="covered" title="2 out of 2 forms covered"> 395 (cond </span><br/> <span class="covered" title="10 out of 10 forms covered"> 396 (and (= CHANCE "chance")(= IN "in")) </span><br/> <span class="covered" title="5 out of 5 forms covered"> 397 (let [[action remainder] (parse-actions previous tokens)] </span><br/> <span class="partial" title="2 out of 3 forms covered"> 398 (cond action </span><br/> <span class="covered" title="4 out of 4 forms covered"> 399 [(list 'cond </span><br/> <span class="covered" title="3 out of 3 forms covered"> 400 (list '< </span><br/> <span class="covered" title="3 out of 3 forms covered"> 401 (list 'rand </span><br/> <span class="covered" title="8 out of 8 forms covered"> 402 (first (parse-simple-value (list m) true))) </span><br/> <span class="covered" title="8 out of 8 forms covered"> 403 (first (parse-simple-value (list n) true))) </span><br/> <span class="covered" title="2 out of 2 forms covered"> 404 action) remainder])))) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 405 </span><br/> <span class="covered" title="1 out of 1 forms covered"> 406 (defn- parse-right-hand-side </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 407 "Parse the right hand side ('then...') of a production rule." </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 408 [[THEN & tokens]] </span><br/> <span class="covered" title="4 out of 4 forms covered"> 409 (if (= THEN "then") </span><br/> <span class="covered" title="6 out of 6 forms covered"> 410 (or </span><br/> <span class="covered" title="4 out of 4 forms covered"> 411 (parse-probability nil tokens) </span><br/> <span class="covered" title="2 out of 2 forms covered"> 412 (parse-actions nil tokens)))) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 413 </span><br/> <span class="covered" title="1 out of 1 forms covered"> 414 (defn parse-rule </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 415 "Parse a complete rule from this `line`, expected to be either a string or a </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 416 sequence of string tokens. Return the rule in the form of an S-expression. </span><br/> <span class="blank" title="0 out of 0 forms covered"> 417 </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 418 Throws an exception if parsing fails." </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 419 [line] </span><br/> <span class="partial" title="3 out of 4 forms covered"> 420 (cond </span><br/> <span class="covered" title="3 out of 3 forms covered"> 421 (string? line) </span><br/> <span class="covered" title="9 out of 9 forms covered"> 422 (let [rule (parse-rule (split (triml line) #"\s+"))] </span><br/> <span class="partial" title="5 out of 6 forms covered"> 423 (cond rule rule </span><br/> <span class="covered" title="6 out of 6 forms covered"> 424 true (throw (Exception. (format bad-parse-error line))))) </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 425 true </span><br/> <span class="covered" title="4 out of 4 forms covered"> 426 (let [[left remainder] (parse-left-hand-side line) </span><br/> <span class="covered" title="3 out of 3 forms covered"> 427 [right junk] (parse-right-hand-side remainder)] </span><br/> <span class="covered" title="2 out of 2 forms covered"> 428 (cond </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 429 ;; there should be a valide left hand side and a valid right hand side </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 430 ;; there shouldn't be anything left over (junk should be empty) </span><br/> <span class="partial" title="12 out of 13 forms covered"> 431 (and left right (empty? junk)) </span><br/> <span class="covered" title="11 out of 11 forms covered"> 432 (list 'fn ['cell 'world] (list 'if left right)))))) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 433 </span><br/> <span class="covered" title="1 out of 1 forms covered"> 434 (defn compile-rule </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 435 "Parse this `rule-text`, a string conforming to the grammar of MicroWorld rules, </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 436 into Clojure source, and then compile it into an anonymous </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 437 function object, getting round the problem of binding mw-engine.utils in </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 438 the compiling environment. If `return-tuple?` is present and true, return </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 439 a list comprising the anonymous function compiled, and the function from </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 440 which it was compiled. </span><br/> <span class="blank" title="0 out of 0 forms covered"> 441 </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 442 Throws an exception if parsing fails." </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 443 ([rule-text return-tuple?] </span><br/> <span class="covered" title="1 out of 1 forms covered"> 444 (do </span><br/> <span class="covered" title="3 out of 3 forms covered"> 445 (use 'mw-engine.utils) </span><br/> <span class="covered" title="6 out of 6 forms covered"> 446 (let [afn (eval (parse-rule rule-text))] </span><br/> <span class="partial" title="3 out of 4 forms covered"> 447 (cond </span><br/> <span class="partial" title="11 out of 12 forms covered"> 448 (and afn return-tuple?)(list afn (trim rule-text)) </span><br/> <span class="covered" title="1 out of 1 forms covered"> 449 true afn)))) </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 450 ([rule-text] </span><br/> <span class="covered" title="4 out of 4 forms covered"> 451 (compile-rule rule-text false))) </span><br/> </body> </html>