From 28da9555badd81cdb8e0dbc58e6df1ef3cdc9078 Mon Sep 17 00:00:00 2001
From: Simon Brooke
(defn get-neighbours-with-property-value + ([world x y depth property value comparator] + (filter #(apply comparator (list (get % property) value)) (get-neighbours world x y depth))) ([world x y depth property value] - (filter #(= (get % property) value) (get-neighbours world x y depth))) + (get-neighbours-with-property-value world x y depth property value =)) ([world cell depth property value] (get-neighbours-with-property-value world (:x cell) (:y cell) depth property value)) diff --git a/resources/public/docs/mw-parser/uberdoc.html b/resources/public/docs/mw-parser/uberdoc.html index 199cb45..b3b9e2d 100644 --- a/resources/public/docs/mw-parser/uberdoc.html +++ b/resources/public/docs/mw-parser/uberdoc.html @@ -3035,29 +3035,36 @@ objective is to parse rules out of a block of text from a textarea
(ns mw-parser.bulk (:use mw-parser.core mw-engine.utils - clojure.java.io) - (:import (java.io BufferedReader StringReader)))
(defn parse-line [line] - (let [initial (first line)] - (cond - (member? initial '(nil \# \;)) nil - true (parse-rule line))))
Parse rules from lines returned by this reader
. Ignore
- lines starting with ;;
, but otherwise throw an exception if any
- line cannot be parsed.
(defn- parse-from-reader - [reader] - (remove nil? - (map parse-line - (line-seq reader))))
Parse rules from successive lines in the file loaded from this filename
Is this line
a comment?
(defn comment? + [line] + (or (empty? (trim line)) (member? (first line) '(nil \# \;))))
Parse rules from successive lines in this string
, assumed to have multiple
+ lines delimited by the new-line character. Return a list of S-expressions.
(defn parse-string + [string] + ;; TODO: tried to do this using with-open, but couldn't make it work. + (map parse-rule (remove comment? (split string #"\n"))))
Parse rules from successive lines in the file loaded from this filename
.
+ Return a list of S-expressions.
(defn parse-file [filename] - (with-open [rdr (reader filename)] - (remove nil? - (map parse-line - (line-seq rdr)))))
Parse rules from successive lines in this string
(defn parse-string - [string] - (parse-from-reader (BufferedReader. (StringReader. string))))
A very simple parser which parses production rules of the following forms:
+ (parse-string (slurp filename)))Compile each non-comment line of this string
into an executable anonymous
+ function, and return the sequence of such functions.
(defn compile-string + [string] + (map compile-rule (split string #"\n")))
Compile each non-comment line of the file indicated by this filename
into
+ an executable anonymous function, and return the sequence of such functions.
(defn compile-file + [filename] + (compile-string (slurp filename)))
(let [lines + (doall (with-open [rdr (reader filename)] (line-seq rdr)))] + (map parse-line lines)))
+(defn parse-string
+ "Parse rules from successive lines in this string
"
+ [string]
+ (parse-from-reader (BufferedReader. (StringReader. string))))
A very simple parser which parses production rules of the following forms:
In every case if the function cannot parse the desired construct from the front of the sequence of tokens it returns nil.
Parse a number.
-(defn- parse-numeric-value +
(defn parse-numeric-value [[value & remainder]] (if (re-matches re-number value) [(read-string value) remainder]))
Parse a token assumed to be the name of a property of the current cell, whose value is assumed to be an integer.
-(defn- parse-property-int +
(defn parse-property-int [[value & remainder]] (if value [(list 'get-int 'cell (keyword value)) remainder]))
Parse a token assumed to be the name of a property of the current cell.
-(defn- parse-property-value +
(defn parse-property-value [[value & remainder]] - (if value [(list (keyword value) 'cell) remainder]))
Parse a value from the first of these tokens
. If expect-int
is true, return
+ (if value [(list (keyword value) 'cell) remainder]))
Parse a token assumed to be a simple token value.
+(defn parse-token-value + [[value & remainder]] + (if value [(keyword value) remainder]))
Parse a value from the first of these tokens
. If expect-int
is true, return
an integer or something which will evaluate to an integer.
(defn- parse-simple-value +
(defn parse-simple-value ([tokens expect-int] (or (parse-numeric-value tokens) (cond expect-int (parse-property-int tokens) - true (parse-property-value tokens)))) + true (parse-token-value tokens)))) ([tokens] (parse-simple-value tokens false)))
Parse a list of values from among these tokens
. If expect-int
is true, return
- an integer or something which will evaluate to an integer.
(defn- parse-disjunct-value + integers or things which will evaluate to integers. +
(defn parse-disjunct-value [[OR token & tokens] expect-int] (cond (member? OR '("or" "in")) - (let [[others remainder] (parse-disjunct-value tokens expect-int)] - [(cons - (cond - expect-int (first (parse-simple-value (list token) true)) - true (keyword token)) - others) - remainder]) - true [nil (cons OR (cons token tokens))]))
Parse a value from among these tokens
. If expect-int
is true, return
+ (let [value (first (parse-simple-value (list token) expect-int))
+ seek-others (= (first tokens) "or")]
+ (cond seek-others
+ (let [[others remainder] (parse-disjunct-value tokens expect-int)]
+ [(cons value others) remainder])
+ true
+ [(list value) tokens]))))
Parse a value from among these tokens
. If expect-int
is true, return
an integer or something which will evaluate to an integer.
(defn- parse-value +
(defn parse-value ([tokens expect-int] (or (parse-disjunct-value tokens expect-int) @@ -3149,21 +3159,23 @@ front of the sequence of tokens it returns nil. ([tokens] (parse-value tokens false)))
Parses a condition of the form '[property] in [value] or [value]...'
(defn- parse-member-condition - [[property IN & rest]] - (if (= IN "in") + [[property IS IN & rest]] + (if (and (member? IS '("is" "are")) (= IN "in")) (let [[l remainder] (parse-disjunct-value (cons "in" rest) false)] [(list 'member? (keyword property) l) remainder])))
Parse '[property] less than [value]'.
(defn- parse-less-condition - [[property LESS THAN value & rest]] - (cond (and (= LESS "less") (= THAN "than")) - [(list '< (list 'get-int 'cell (keyword property)) (read-string value)) rest]))
Parse '[property] more than [value]'.
+ [[property IS LESS THAN & rest]] + (cond (and (member? IS '("is" "are")) (member? LESS '("less" "fewer")) (= THAN "than")) + (let [[value remainder] (parse-value rest true)] + [(list '< (list 'get-int 'cell (keyword property)) value) remainder])))Parse '[property] more than [value]'.
(defn- parse-more-condition - [[property MORE THAN value & rest]] - (cond (and (= MORE "more") (= THAN "than")) - [(list '> (list 'get-int 'cell (keyword property)) (read-string value)) rest]))
(defn- parse-between-condition - [[p BETWEEN v1 AND v2 & rest]] - (cond (and (= BETWEEN "between") (= AND "and") (not (nil? v2))) + [[p IS BETWEEN v1 AND v2 & rest]] + (cond (and (member? IS '("is" "are")) (= BETWEEN "between") (= AND "and") (not (nil? v2))) (let [property (first (parse-simple-value (list p) true)) value1 (first (parse-simple-value (list v1) true)) value2 (first (parse-simple-value (list v2) true))] @@ -3178,10 +3190,6 @@ front of the sequence of tokens it returns nil. (member? IS '("is" "are")) (let [tokens (cons property (cons value rest))] (cond - (= value "in") (parse-member-condition tokens) - (= value "between") (parse-between-condition tokens) - (= value "more") (parse-more-condition tokens) - (= value "less") (parse-less-condition tokens) (re-matches re-number value) [(list '= (list 'get-int 'cell (keyword property)) (read-string value)) rest] value [(list '= (list (keyword property) 'cell) (keyword value)) rest]))))
Parse the negation of a simple condition.
(defn- parse-not-condition @@ -3192,14 +3200,14 @@ front of the sequence of tokens it returns nil. (let [[condition remainder] partial] [(list 'not condition) remainder])))))
(defn- gen-neighbours-condition - [comparator quantity property value remainder] + [comparator quantity property value remainder comp2] [(list comparator (list 'count - (list 'get-neighbours-with-property-value 'world 'cell - (keyword property) (keyword-or-numeric value))) + (list 'get-neighbours-with-property-value 'world '(cell :x) '(cell :y) + (keyword property) (keyword-or-numeric value) comp2)) quantity) remainder])
Parse conditions of the form '...more than 6 neighbours are [condition]'
-(defn- parse-comparator-neighbours-condition +
(defn parse-comparator-neighbours-condition [[MORE THAN n NEIGHBOURS have-or-are & rest]] (let [quantity (first (parse-numeric-value (list n))) comparator (cond (= MORE "more") '> @@ -3212,21 +3220,21 @@ front of the sequence of tokens it returns nil. (cond (= have-or-are "are") (let [[value & remainder] rest] - (gen-neighbours-condition comparator quantity :state value remainder)) + (gen-neighbours-condition comparator quantity :state value remainder =)) (= have-or-are "have") (let [[property comp1 comp2 value & remainder] rest] (cond (and (= comp1 "equal") (= comp2 "to")) - (gen-neighbours-condition comparator quantity property value remainder) -;; (and (= comp1 "more") (= comp2 "than")) -;; (gen-neighbours-condition '> quantity property value remainder) -;; (and (= comp1 "less") (= comp2 "than")) -;; (gen-neighbours-condition '< quantity property value remainder)))))))
(defn- parse-some-neighbours-condition + (gen-neighbours-condition comparator quantity property value remainder =) + (and (= comp1 "more") (= comp2 "than")) + (gen-neighbours-condition '> quantity property value remainder >) + (and (= comp1 "less") (= comp2 "than")) + (gen-neighbours-condition '< quantity property value remainder <)))))))
(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 +
(defn parse-simple-neighbours-condition [[n NEIGHBOURS have-or-are & rest]] (let [quantity (first (parse-numeric-value (list n)))] (cond @@ -3243,21 +3251,22 @@ front of the sequence of tokens it returns nil. ;; (gen-neighbours-condition '> quantity property value remainder) ;; (and (= comp1 "less") (= comp2 "than")) ;; (gen-neighbours-condition '< quantity property value remainder)))))))
Parse conditions referring to neighbours
-(defn- parse-neighbours-condition +
(defn parse-neighbours-condition [tokens] (or (parse-simple-neighbours-condition tokens) (parse-comparator-neighbours-condition tokens) (parse-some-neighbours-condition tokens)))
Parse conditions of the form '[property] [comparison] [value]'.
-(defn- parse-simple-condition +
(defn parse-simple-condition [tokens] (or (parse-neighbours-condition tokens) (parse-member-condition tokens) (parse-not-condition tokens) - (parse-is-condition tokens) (parse-less-condition tokens) - (parse-more-condition tokens)))
Parse '... or [condition]' from tokens
, where left
is the already parsed first disjunct.
Parse '... or [condition]' from tokens
, where left
is the already parsed first disjunct.
(defn- parse-disjunction-condition [left tokens] (let [partial (parse-conditions tokens)] @@ -3291,10 +3300,11 @@ front of the sequence of tokens it returns nil. (= be "be") (member? operator '("+" "-" "*" "/"))) [(list 'merge (or previous 'cell) - {(keyword prop1) (list (symbol operator) (list 'get-int 'cell (keyword prop2)) - (cond - (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].'
+ {(keyword prop1) (list 'int + (list (symbol operator) (list 'get-int 'cell (keyword prop2)) + (cond + (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")) @@ -3327,18 +3337,29 @@ front of the sequence of tokens it returns nil. (if (= THEN "then") (or (parse-probability nil tokens) - (parse-actions nil tokens))))
Parse a complete rule from this string or sequence of string tokens.
+ (parse-actions nil tokens))))Parse a complete rule from this line
, expected to be either a string or a
+ sequence of string tokens. Return the rule in the form of an S-expression.
Throws an exception if parsing fails.
(defn parse-rule [line] (cond - (string? line) (parse-rule (split (triml line) #"\s+")) - true (let [[left remainder] (parse-left-hand-side line) + (string? line) + (let [rule (parse-rule (split (triml line) #"\s+"))] + (cond rule rule + true (throw (Exception. (str "I did not understand '" line "'"))))) + true + (let [[left remainder] (parse-left-hand-side line) [right junk] (parse-right-hand-side remainder)] - ;; there shouldn't be any junk (should be null) - (list 'fn ['cell 'world] (list 'if left right)))))
Parse this rule-text
, a string conforming to the grammar of MicroWorld rules,
+ ;; TODO: there shouldn't be any junk (should be null)
+ (cond
+ (and left right (nil? junk))
+ (list 'fn ['cell 'world] (list 'if left right))))))
Parse this rule-text
, a string conforming to the grammar of MicroWorld rules,
into Clojure source, and then compile it into an anonymous
function object, getting round the problem of binding mw-engine.utils in
the compiling environment.
Throws an exception if parsing fails.
(defn compile-rule [rule-text] (do diff --git a/resources/public/docs/mw-ui/uberdoc.html b/resources/public/docs/mw-ui/uberdoc.html index ade7351..e4ef147 100644 --- a/resources/public/docs/mw-ui/uberdoc.html +++ b/resources/public/docs/mw-ui/uberdoc.html @@ -3228,7 +3228,7 @@ net.brehaut.ClojureTools = (function (SH) { (file-seq (clojure.java.io/file "resources/public/img/tiles"))))))
(defn docs-page [] (layout/render "docs.html" {:title "Documentation" - :parser (util/md->html "/md/parser.md") + :parser (util/md->html "/md/mw-parser.md") :states (list-states) :components ["mw-engine" "mw-parser" "mw-ui"]}))
(defroutes home-routes diff --git a/src/mw_ui/routes/home.clj b/src/mw_ui/routes/home.clj index c20abd3..ddd3f02 100644 --- a/src/mw_ui/routes/home.clj +++ b/src/mw_ui/routes/home.clj @@ -23,7 +23,7 @@ (defn docs-page [] (layout/render "docs.html" {:title "Documentation" - :parser (util/md->html "/md/parser.md") + :parser (util/md->html "/md/mw-parser.md") :states (list-states) :components ["mw-engine" "mw-parser" "mw-ui"]}))