diff --git a/README.md b/README.md index 59eb55b..84cf94b 100644 --- a/README.md +++ b/README.md @@ -137,4 +137,5 @@ Have fun! Copyright © 2014 [Simon Brooke](mailto:simon@journeyman.cc) -Distributed under the terms of the [GNU General Public License v2](http://www.gnu.org/licenses/gpl-2.0.html) \ No newline at end of file +Distributed under the terms of the [GNU General Public License v2] +(http://www.gnu.org/licenses/gpl-2.0.html) \ No newline at end of file diff --git a/resources/public/docs/mw-parser/uberdoc.html b/resources/public/docs/mw-parser/uberdoc.html index d40132a..4b6e319 100644 --- a/resources/public/docs/mw-parser/uberdoc.html +++ b/resources/public/docs/mw-parser/uberdoc.html @@ -3029,7 +3029,7 @@ net.brehaut.ClojureTools = (function (SH) { }; })(SyntaxHighlighter);
mw-parser0.1.0-SNAPSHOTParser for production rules for MicroWorld engine -dependencies
| (this space intentionally left almost blank) | |||||||||
parse multiple rules from a stream, possibly a file - although the real + dependencies
| (this space intentionally left almost blank) | |||||||||
parse multiple rules from a stream, possibly a file - although the real objective is to parse rules out of a block of text from a textarea | ||||||||||
(ns mw-parser.bulk @@ -3097,7 +3097,10 @@ more complex issue which I don't yet know how to address. | (declare parse-conditions) (declare parse-not-condition) (declare parse-simple-condition) | |||||||||
a regular expression which matches string representation of numbers - | (def re-number #"^[0-9.]*$") | |||||||||
If this token appears to represent an explicit number, return that number; + | (def re-number #"^[0-9.]*$") | |||||||||
error thrown when an attempt is made to set a reserved property + | (def reserved-properties-error + "The properties 'x' and 'y' of a cell are reserved and should not be set in rule actions") | |||||||||
error thrown when a rule cannot be parsed + | (def bad-parse-error "I did not understand '%s'") | |||||||||
If this token appears to represent an explicit number, return that number; otherwise, make a keyword of it and return that. | (defn- keyword-or-numeric [token] @@ -3138,7 +3141,11 @@ front of the sequence of tokens it returns nil. (parse-property-int tokens) true (parse-token-value tokens)))) ([tokens] - (parse-simple-value tokens false))) | |||||||||
Parse a list of values from among these | ||||||||||
Parse a single value from this single token and return just the generated + code, not a pair. + | (defn gen-token-value + [token expect-int] + (first (parse-simple-value (list token) expect-int))) | |||||||||
Parse a list of values from among these | (defn parse-disjunct-value [[OR token & tokens] expect-int] @@ -3203,56 +3210,81 @@ front of the sequence of tokens it returns nil. ([comp1 quantity property value remainder comp2 distance] [(list comp1 (list 'count - (list 'get-neighbours-with-property-value 'world '(cell :x) '(cell :y) 1 + (list 'get-neighbours-with-property-value 'world + '(cell :x) '(cell :y) distance (keyword property) (keyword-or-numeric value) comp2)) quantity) remainder]) ([comp1 quantity property value remainder comp2] (gen-neighbours-condition comp1 quantity property value remainder comp2 1))) | |||||||||
Parse conditions of the form '...more than 6 neighbours are [condition]' | (defn parse-comparator-neighbours-condition - [[MORE THAN n NEIGHBOURS have-or-are & rest]] + [[MORE THAN n NEIGHBOURS WITHIN distance have-or-are & rest]] (let [quantity (first (parse-numeric-value (list n))) comparator (cond (= MORE "more") '> (member? MORE '("fewer" "less")) '<)] (cond + (not (= WITHIN "within")) + (parse-comparator-neighbours-condition + (flatten + ;; two tokens were mis-parsed as 'within distance' that weren't + ;; actually 'within' and a distance. Splice in 'within 1' and try + ;; again. + (list MORE THAN n NEIGHBOURS "within" "1" WITHIN distance have-or-are rest))) (and quantity comparator (= THAN "than") (= NEIGHBOURS "neighbours")) (cond (= have-or-are "are") - (let [[value & remainder] rest] - (gen-neighbours-condition comparator quantity :state value remainder =)) + (let [[value & remainder] rest + dist (gen-token-value distance true)] + (gen-neighbours-condition comparator quantity :state value remainder = dist)) (= have-or-are "have") - (let [[property comp1 comp2 value & remainder] rest] + (let [[property comp1 comp2 value & remainder] rest + dist (gen-token-value distance true)] (cond (and (= comp1 "equal") (= comp2 "to")) - (gen-neighbours-condition comparator quantity property value remainder =) + (gen-neighbours-condition comparator quantity property + value remainder = dist) (and (= comp1 "more") (= comp2 "than")) - (gen-neighbours-condition comparator quantity property value remainder >) + (gen-neighbours-condition comparator quantity property + value remainder > dist) (and (= comp1 "less") (= comp2 "than")) - (gen-neighbours-condition comparator quantity property value remainder <))))))) | |||||||||
+ (gen-neighbours-condition comparator quantity property + value remainder < dist))))))) | ||||||||||
(defn parse-some-neighbours-condition [[SOME NEIGHBOURS & rest]] (cond (and (= SOME "some") (= NEIGHBOURS "neighbours")) (parse-comparator-neighbours-condition (concat '("more" "than" "0" "neighbours") rest)))) | ||||||||||
Parse conditions of the form '...6 neighbours are [condition]' | (defn parse-simple-neighbours-condition - [[n NEIGHBOURS have-or-are & rest]] + [[n NEIGHBOURS WITHIN distance have-or-are & rest]] (let [quantity (first (parse-numeric-value (list n)))] (cond (and quantity (= NEIGHBOURS "neighbours")) (cond + (not (= WITHIN "within")) + (parse-simple-neighbours-condition + (flatten + ;; two tokens were mis-parsed as 'within distance' that weren't + ;; actually 'within' and a distance. Splice in 'within 1' and try + ;; again. + (list n NEIGHBOURS "within" "1" WITHIN distance have-or-are rest))) (= have-or-are "are") - (let [[value & remainder] rest] - (gen-neighbours-condition '= quantity :state value remainder =)) + (let [[value & remainder] rest + dist (gen-token-value distance true)] + (gen-neighbours-condition '= quantity :state value remainder = dist)) (= have-or-are "have") - (let [[property comp1 comp2 value & remainder] rest] + (let [[property comp1 comp2 value & remainder] rest + dist (gen-token-value distance true)] (cond (and (= comp1 "equal") (= comp2 "to")) - (gen-neighbours-condition '= quantity property value remainder =) + (gen-neighbours-condition '= quantity property value remainder = + dist) (and (= comp1 "more") (= comp2 "than")) - (gen-neighbours-condition '= quantity property value remainder >) + (gen-neighbours-condition '= quantity property value remainder > + dist) (and (= comp1 "less") (= comp2 "than")) - (gen-neighbours-condition '= quantity property value remainder <))))))) | |||||||||
Parse conditions referring to neighbours + (gen-neighbours-condition '= quantity property value remainder < + dist))))))) | ||||||||||
Parse conditions referring to neighbours | (defn parse-neighbours-condition [tokens] (or @@ -3297,9 +3329,13 @@ front of the sequence of tokens it returns nil. (parse-conditions tokens))) | |||||||||
Parse actions of the form '[property] should be [property] [arithmetic-operator] [value]', e.g. 'fertility should be fertility + 1', or 'deer should be deer - wolves'. | (defn- parse-arithmetic-action - [previous [prop1 should be prop2 operator value & rest]] - (if (and (= should "should") - (= be "be") + [previous [prop1 SHOULD BE prop2 operator value & rest]] + (cond + (member? prop2 '("x" "y")) + (throw + (Exception. reserved-properties-error)) + (and (= SHOULD "should") + (= BE "be") (member? operator '("+" "-" "*" "/"))) [(list 'merge (or previous 'cell) {(keyword prop1) (list 'int @@ -3308,8 +3344,12 @@ front of the sequence of tokens it returns nil. (re-matches re-number value) (read-string value) true (list 'get-int 'cell (keyword value)))))}) rest])) | |||||||||
Parse actions of the form '[property] should be [value].' | (defn- parse-set-action - [previous [property should be value & rest]] - (if (and (= should "should") (= be "be")) + [previous [property SHOULD BE value & rest]] + (cond + (member? property '("x" "y")) + (throw + (Exception. reserved-properties-error)) + (and (= SHOULD "should") (= BE "be")) [(list 'merge (or previous 'cell) {(keyword property) (cond (re-matches re-number value) (read-string value) true (keyword value))}) rest])) | |||||||||
(defn- parse-simple-action [previous tokens] @@ -3349,7 +3389,7 @@ front of the sequence of tokens it returns nil. (string? line) (let [rule (parse-rule (split (triml line) #"\s+"))] (cond rule rule - true (throw (Exception. (str "I did not understand '" line "'"))))) + true (throw (Exception. (format bad-parse-error line))))) true (let [[left remainder] (parse-left-hand-side line) [right junk] (parse-right-hand-side remainder)] |