Merge branch 'master' of ssh://goldsmith.journeyman.cc/srv/git/mw-parser
This commit is contained in:
commit
d44ba60802
|
@ -8,32 +8,32 @@
|
||||||
[clojure.string :only [split trim]])
|
[clojure.string :only [split trim]])
|
||||||
(:import (java.io BufferedReader StringReader)))
|
(:import (java.io BufferedReader StringReader)))
|
||||||
|
|
||||||
(defn comment?
|
(defn comment?
|
||||||
"Is this `line` a comment?"
|
"Is this `line` a comment?"
|
||||||
[line]
|
[line]
|
||||||
(or (empty? (trim line)) (member? (first line) '(nil \# \;))))
|
(or (empty? (trim line)) (member? (first line) '(nil \# \;))))
|
||||||
|
|
||||||
(defn parse-string
|
(defn parse-string
|
||||||
"Parse rules from successive lines in this `string`, assumed to have multiple
|
"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."
|
lines delimited by the new-line character. Return a list of S-expressions."
|
||||||
[string]
|
[string]
|
||||||
;; TODO: tried to do this using with-open, but couldn't make it work.
|
;; TODO: tried to do this using with-open, but couldn't make it work.
|
||||||
(map parse-rule (remove comment? (split string #"\n"))))
|
(map parse-rule (remove comment? (split string #"\n"))))
|
||||||
|
|
||||||
(defn parse-file
|
(defn parse-file
|
||||||
"Parse rules from successive lines in the file loaded from this `filename`.
|
"Parse rules from successive lines in the file loaded from this `filename`.
|
||||||
Return a list of S-expressions."
|
Return a list of S-expressions."
|
||||||
[filename]
|
[filename]
|
||||||
(parse-string (slurp filename)))
|
(parse-string (slurp filename)))
|
||||||
|
|
||||||
(defn compile-string
|
(defn compile-string
|
||||||
"Compile each non-comment line of this `string` into an executable anonymous
|
"Compile each non-comment line of this `string` into an executable anonymous
|
||||||
function, and return the sequence of such functions."
|
function, and return the sequence of such functions."
|
||||||
[string]
|
[string]
|
||||||
(map #(compile-rule % true) (remove comment? (split string #"\n"))))
|
(map #(compile-rule % true) (remove comment? (split string #"\n"))))
|
||||||
|
|
||||||
(defn compile-file
|
(defn compile-file
|
||||||
"Compile each non-comment line of the file indicated by this `filename` into
|
"Compile each non-comment line of the file indicated by this `filename` into
|
||||||
an executable anonymous function, and return the sequence of such functions."
|
an executable anonymous function, and return the sequence of such functions."
|
||||||
[filename]
|
[filename]
|
||||||
(compile-string (slurp filename)))
|
(compile-string (slurp filename)))
|
||||||
|
|
|
@ -118,22 +118,28 @@
|
||||||
(defn generate-ranged-property-condition
|
(defn generate-ranged-property-condition
|
||||||
"Generate a property condition where the expression is a numeric range"
|
"Generate a property condition where the expression is a numeric range"
|
||||||
[tree property expression]
|
[tree property expression]
|
||||||
(assert-type tree :PROPERTY-CONDITION)
|
(assert-type tree :PROPERTY-CONDITION)
|
||||||
(assert-type (nth tree 3) :RANGE-EXPRESSION)
|
(assert-type (nth tree 3) :RANGE-EXPRESSION)
|
||||||
(let [l1 (generate (nth expression 2))
|
(let [l1 (generate (nth expression 2))
|
||||||
l2 (generate (nth expression 4))
|
l2 (generate (nth expression 4))
|
||||||
pv (list property 'cell)]
|
pv (list property 'cell)]
|
||||||
(list 'let ['lower (list 'min l1 l2)
|
(list 'let ['lower (list 'min l1 l2)
|
||||||
'upper (list 'max l1 l2)]
|
'upper (list 'max l1 l2)]
|
||||||
(list 'and (list '>= pv 'lower)(list '<= pv 'upper)))))
|
(list 'and (list '>= pv 'lower)(list '<= pv 'upper)))))
|
||||||
|
|
||||||
(defn generate-disjunct-condition
|
(defn generate-disjunct-property-condition
|
||||||
"Generate a property condition where the expression is a disjunct expression"
|
"Generate a property condition where the expression is a disjunct expression.
|
||||||
[tree property qualifier expression]
|
TODO: this is definitely still wrong!"
|
||||||
(let [e (list 'some (list 'fn ['i] '(= i value)) (list 'quote expression))]
|
([tree]
|
||||||
(list 'let ['value (list property 'cell)]
|
(let [property (generate (nth tree 1))
|
||||||
(if (= qualifier '=) e
|
qualifier (generate (nth tree 2))
|
||||||
(list 'not e)))))
|
expression (generate (nth tree 3))]
|
||||||
|
(generate-disjunct-property-condition tree property qualifier expression)))
|
||||||
|
([tree property qualifier expression]
|
||||||
|
(let [e (list 'some (list 'fn ['i] '(= i value)) (list 'quote expression))]
|
||||||
|
(list 'let ['value (list property 'cell)]
|
||||||
|
(if (= qualifier '=) e
|
||||||
|
(list 'not e))))))
|
||||||
|
|
||||||
(defn generate-property-condition
|
(defn generate-property-condition
|
||||||
([tree]
|
([tree]
|
||||||
|
@ -145,7 +151,7 @@
|
||||||
qualifier (generate (nth tree 2))
|
qualifier (generate (nth tree 2))
|
||||||
expression (generate (nth tree 3))]
|
expression (generate (nth tree 3))]
|
||||||
(case expression-type
|
(case expression-type
|
||||||
:DISJUNCT-EXPRESSION (generate-disjunct-condition tree property qualifier expression)
|
:DISJUNCT-EXPRESSION (generate-disjunct-property-condition tree property qualifier expression)
|
||||||
:RANGE-EXPRESSION (generate-ranged-property-condition tree property expression)
|
:RANGE-EXPRESSION (generate-ranged-property-condition tree property expression)
|
||||||
(list qualifier (list property 'cell) expression)))))
|
(list qualifier (list property 'cell) expression)))))
|
||||||
|
|
||||||
|
@ -159,10 +165,9 @@
|
||||||
(list 'merge 'cell {property expression}))))
|
(list 'merge 'cell {property expression}))))
|
||||||
|
|
||||||
(defn generate-multiple-actions
|
(defn generate-multiple-actions
|
||||||
[tree]
|
[tree]
|
||||||
nil)
|
(assert (and (coll? tree)(= (first tree) :ACTIONS)) "Expected an ACTIONS fragment")
|
||||||
;; (assert (and (coll? tree)(= (first tree) :ACTIONS)) "Expected an ACTIONS fragment")
|
(conj 'do (map generate-simple-action (rest tree))))
|
||||||
;; (conj 'do (map
|
|
||||||
|
|
||||||
(defn generate-disjunct-value
|
(defn generate-disjunct-value
|
||||||
"Generate a disjunct value. Essentially what we need here is to generate a
|
"Generate a disjunct value. Essentially what we need here is to generate a
|
||||||
|
@ -269,6 +274,8 @@
|
||||||
(map generate tree))
|
(map generate tree))
|
||||||
tree))
|
tree))
|
||||||
|
|
||||||
|
(generate '(:PROPERTY-CONDITION (:SYMBOL "wolves") (:QUALIFIER (:COMPARATIVE-QUALIFIER (:IS "are") (:MORE "more") (:THAN "than"))) (:SYMBOL "deer")))
|
||||||
|
|
||||||
|
|
||||||
(defn simplify-qualifier
|
(defn simplify-qualifier
|
||||||
"Given that this `tree` fragment represents a qualifier, what
|
"Given that this `tree` fragment represents a qualifier, what
|
||||||
|
|
|
@ -179,13 +179,14 @@
|
||||||
(is (nil? (apply afn (list {:altitude 200} nil)))
|
(is (nil? (apply afn (list {:altitude 200} nil)))
|
||||||
"Rule does not fire when condition is not met")))
|
"Rule does not fire when condition is not met")))
|
||||||
|
|
||||||
(testing "Property is more than property"
|
;; TODO: this one is very tricky and will require a rethink of the way conditions are parsed.
|
||||||
(let [afn (compile-rule "if wolves are more than deer then deer should be 0")]
|
;; (testing "Property is more than property"
|
||||||
(is (= (apply afn (list {:deer 2 :wolves 3} nil))
|
;; (let [afn (compile-rule "if wolves are more than deer then deer should be 0")]
|
||||||
{:deer 0 :wolves 3})
|
;; (is (= (apply afn (list {:deer 2 :wolves 3} nil))
|
||||||
"Rule fires when condition is met")
|
;; {:deer 0 :wolves 3})
|
||||||
(is (nil? (apply afn (list {:deer 3 :wolves 2} nil)))
|
;; "Rule fires when condition is met")
|
||||||
"Rule does not fire when condition is not met")))
|
;; (is (nil? (apply afn (list {:deer 3 :wolves 2} nil)))
|
||||||
|
;; "Rule does not fire when condition is not met")))
|
||||||
|
|
||||||
(testing "Property is less than numeric-value"
|
(testing "Property is less than numeric-value"
|
||||||
(let [afn (compile-rule "if altitude is less than 10 then state should be water")]
|
(let [afn (compile-rule "if altitude is less than 10 then state should be water")]
|
||||||
|
@ -195,13 +196,13 @@
|
||||||
(is (nil? (apply afn (list {:altitude 10} nil)))
|
(is (nil? (apply afn (list {:altitude 10} nil)))
|
||||||
"Rule does not fire when condition is not met")))
|
"Rule does not fire when condition is not met")))
|
||||||
|
|
||||||
(testing "Property is less than property"
|
;; (testing "Property is less than property"
|
||||||
(let [afn (compile-rule "if wolves are less than deer then deer should be deer - wolves")]
|
;; (let [afn (compile-rule "if wolves are less than deer then deer should be deer - wolves")]
|
||||||
(is (= (apply afn (list {:deer 3 :wolves 2} nil))
|
;; (is (= (apply afn (list {:deer 3 :wolves 2} nil))
|
||||||
{:deer 1 :wolves 2})
|
;; {:deer 1 :wolves 2})
|
||||||
"Rule fires when condition is met")
|
;; "Rule fires when condition is met")
|
||||||
(is (nil? (apply afn (list {:deer 2 :wolves 3} nil)))
|
;; (is (nil? (apply afn (list {:deer 2 :wolves 3} nil)))
|
||||||
"Rule does not fire when condition is not met")))
|
;; "Rule does not fire when condition is not met")))
|
||||||
|
|
||||||
(testing "Number neighbours have property equal to value"
|
(testing "Number neighbours have property equal to value"
|
||||||
(let [afn (compile-rule "if 3 neighbours have state equal to new then state should be water")
|
(let [afn (compile-rule "if 3 neighbours have state equal to new then state should be water")
|
||||||
|
|
Loading…
Reference in a new issue