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)]
|