All tests pass. I should now be able to ditch the old parser and use the
new, but first I want to do some major code restructuring.
This commit is contained in:
parent
1c6ceb899c
commit
9836cbff50
|
@ -18,12 +18,13 @@
|
||||||
;; in order to simplify translation into other natural languages, all
|
;; in order to simplify translation into other natural languages, all
|
||||||
;; TOKENS within the parser should be unambiguous
|
;; TOKENS within the parser should be unambiguous
|
||||||
"RULE := IF SPACE CONDITIONS SPACE THEN SPACE ACTIONS;
|
"RULE := IF SPACE CONDITIONS SPACE THEN SPACE ACTIONS;
|
||||||
CONDITIONS := DISJUNCT-CONDITION | CONJUNCT-CONDITION | PROPERTY-CONDITION | NEIGHBOURS-CONDITION ;
|
CONDITIONS := DISJUNCT-CONDITION | CONJUNCT-CONDITION | CONDITION ;
|
||||||
DISJUNCT-CONDITION := CONDITION SPACE OR SPACE CONDITIONS;
|
DISJUNCT-CONDITION := CONDITION SPACE OR SPACE CONDITIONS;
|
||||||
CONJUNCT-CONDITION := CONDITION SPACE AND SPACE CONDITIONS;
|
CONJUNCT-CONDITION := CONDITION SPACE AND SPACE CONDITIONS;
|
||||||
CONDITION := NEIGHBOURS-CONDITION | PROPERTY-CONDITION;
|
CONDITION := WITHIN-CONDITION | NEIGHBOURS-CONDITION | PROPERTY-CONDITION;
|
||||||
WITHIN-CONDITION := NEIGHBOURS-CONDITION SPACE WITHIN SPACE NUMERIC-EXPRESSION;
|
WITHIN-CONDITION := QUANTIFIER SPACE NEIGHBOURS SPACE WITHIN SPACE NUMBER SPACE IS SPACE PROPERTY-CONDITION-OR-EXPRESSION;
|
||||||
NEIGHBOURS-CONDITION := WITHIN-CONDITION | QUANTIFIER SPACE NEIGHBOURS SPACE IS SPACE PROPERTY-CONDITION | QUANTIFIER SPACE NEIGHBOURS IS EXPRESSION | QUALIFIER SPACE NEIGHBOURS-CONDITION;
|
NEIGHBOURS-CONDITION := QUANTIFIER SPACE NEIGHBOURS SPACE IS SPACE PROPERTY-CONDITION | QUALIFIER SPACE NEIGHBOURS-CONDITION;
|
||||||
|
PROPERTY-CONDITION-OR-EXPRESSION := PROPERTY-CONDITION | EXPRESSION;
|
||||||
PROPERTY-CONDITION := PROPERTY SPACE QUALIFIER SPACE EXPRESSION | VALUE;
|
PROPERTY-CONDITION := PROPERTY SPACE QUALIFIER SPACE EXPRESSION | VALUE;
|
||||||
EXPRESSION := SIMPLE-EXPRESSION | RANGE-EXPRESSION | NUMERIC-EXPRESSION | DISJUNCT-EXPRESSION | VALUE;
|
EXPRESSION := SIMPLE-EXPRESSION | RANGE-EXPRESSION | NUMERIC-EXPRESSION | DISJUNCT-EXPRESSION | VALUE;
|
||||||
SIMPLE-EXPRESSION := QUALIFIER SPACE EXPRESSION | VALUE;
|
SIMPLE-EXPRESSION := QUALIFIER SPACE EXPRESSION | VALUE;
|
||||||
|
@ -31,7 +32,7 @@
|
||||||
RANGE-EXPRESSION := BETWEEN SPACE NUMERIC-EXPRESSION SPACE AND SPACE NUMERIC-EXPRESSION;
|
RANGE-EXPRESSION := BETWEEN SPACE NUMERIC-EXPRESSION SPACE AND SPACE NUMERIC-EXPRESSION;
|
||||||
NUMERIC-EXPRESSION := VALUE | VALUE SPACE OPERATOR SPACE NUMERIC-EXPRESSION;
|
NUMERIC-EXPRESSION := VALUE | VALUE SPACE OPERATOR SPACE NUMERIC-EXPRESSION;
|
||||||
NEGATED-QUALIFIER := QUALIFIER SPACE NOT | NOT SPACE QUALIFIER;
|
NEGATED-QUALIFIER := QUALIFIER SPACE NOT | NOT SPACE QUALIFIER;
|
||||||
COMPARATIVE-QUALIFIER := IS SPACE COMPARATIVE SPACE THAN;
|
COMPARATIVE-QUALIFIER := IS SPACE COMPARATIVE SPACE THAN | COMPARATIVE SPACE THAN;
|
||||||
QUALIFIER := COMPARATIVE-QUALIFIER | NEGATED-QUALIFIER | EQUIVALENCE | IS SPACE QUALIFIER;
|
QUALIFIER := COMPARATIVE-QUALIFIER | NEGATED-QUALIFIER | EQUIVALENCE | IS SPACE QUALIFIER;
|
||||||
QUANTIFIER := NUMBER | SOME | NONE | ALL | COMPARATIVE SPACE THAN SPACE NUMBER;
|
QUANTIFIER := NUMBER | SOME | NONE | ALL | COMPARATIVE SPACE THAN SPACE NUMBER;
|
||||||
EQUIVALENCE := IS SPACE EQUAL | EQUAL | IS ;
|
EQUIVALENCE := IS SPACE EQUAL | EQUAL | IS ;
|
||||||
|
@ -59,12 +60,13 @@
|
||||||
IS := 'is' | 'are' | 'have' | 'has';
|
IS := 'is' | 'are' | 'have' | 'has';
|
||||||
NUMBER := #'[0-9]+' | #'[0-9]+.[0-9]+';
|
NUMBER := #'[0-9]+' | #'[0-9]+.[0-9]+';
|
||||||
SYMBOL := #'[a-z]+';
|
SYMBOL := #'[a-z]+';
|
||||||
ACTIONS := ACTION | ACTION SPACE 'and' SPACE ACTIONS
|
ACTIONS := ACTION | ACTION SPACE AND SPACE ACTIONS
|
||||||
ACTION := SIMPLE-ACTION | PROBABLE-ACTION;
|
ACTION := SIMPLE-ACTION | PROBABLE-ACTION;
|
||||||
PROBABLE-ACTION := VALUE SPACE 'chance in' SPACE VALUE SPACE SIMPLE-ACTION;
|
PROBABLE-ACTION := VALUE SPACE CHANCE-IN SPACE VALUE SPACE SIMPLE-ACTION;
|
||||||
SIMPLE-ACTION := SYMBOL SPACE BECOMES SPACE EXPRESSION
|
SIMPLE-ACTION := SYMBOL SPACE BECOMES SPACE EXPRESSION;
|
||||||
BECOMES := 'should be'
|
CHANCE-IN := 'chance in';
|
||||||
SPACE := #' *'"
|
BECOMES := 'should be' | 'becomes';
|
||||||
|
SPACE := #' *'";
|
||||||
)
|
)
|
||||||
|
|
||||||
(defn TODO
|
(defn TODO
|
||||||
|
@ -73,7 +75,7 @@
|
||||||
message)
|
message)
|
||||||
|
|
||||||
|
|
||||||
(declare generate simplify)
|
(declare generate generate-action simplify)
|
||||||
|
|
||||||
|
|
||||||
(defn suitable-fragment?
|
(defn suitable-fragment?
|
||||||
|
@ -90,6 +92,18 @@
|
||||||
(throw (Exception. (format "Expected a %s fragment" type)))))
|
(throw (Exception. (format "Expected a %s fragment" type)))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn search-tree
|
||||||
|
"Return the first element of this tree which has this tag in a depth-first, left-to-right search"
|
||||||
|
[tree tag]
|
||||||
|
(cond
|
||||||
|
(= (first tree) tag) tree
|
||||||
|
:else (first
|
||||||
|
(remove nil?
|
||||||
|
(map
|
||||||
|
#(search-tree % tag)
|
||||||
|
(rest tree))))))
|
||||||
|
|
||||||
|
|
||||||
(defn generate-rule
|
(defn generate-rule
|
||||||
"From this `tree`, assumed to be a syntactically correct rule specification,
|
"From this `tree`, assumed to be a syntactically correct rule specification,
|
||||||
generate and return the appropriate rule as a function of two arguments."
|
generate and return the appropriate rule as a function of two arguments."
|
||||||
|
@ -103,25 +117,25 @@
|
||||||
generate and return the appropriate clojure fragment."
|
generate and return the appropriate clojure fragment."
|
||||||
[tree]
|
[tree]
|
||||||
(assert-type tree :CONDITIONS)
|
(assert-type tree :CONDITIONS)
|
||||||
(generate (nth tree 1)))
|
(generate (second tree)))
|
||||||
|
|
||||||
|
|
||||||
(defn generate-condition
|
(defn generate-condition
|
||||||
[tree]
|
[tree]
|
||||||
(assert-type tree :CONDITION)
|
(assert-type tree :CONDITION)
|
||||||
(generate (nth tree 1)))
|
(generate (second tree)))
|
||||||
|
|
||||||
|
|
||||||
(defn generate-conjunct-condition
|
(defn generate-conjunct-condition
|
||||||
[tree]
|
[tree]
|
||||||
(assert-type tree :CONJUNCT-CONDITION)
|
(assert-type tree :CONJUNCT-CONDITION)
|
||||||
(list 'and (generate (nth tree 1))(generate (nth tree 3))))
|
(cons 'and (map generate (rest tree))))
|
||||||
|
|
||||||
|
|
||||||
(defn generate-disjunct-condition
|
(defn generate-disjunct-condition
|
||||||
[tree]
|
[tree]
|
||||||
(assert-type tree :DISJUNCT-CONDITION)
|
(assert-type tree :DISJUNCT-CONDITION)
|
||||||
(list 'or (generate (nth tree 1))(generate (nth tree 3))))
|
(cons 'or (map generate (rest tree))))
|
||||||
|
|
||||||
|
|
||||||
(defn generate-ranged-property-condition
|
(defn generate-ranged-property-condition
|
||||||
|
@ -141,7 +155,7 @@
|
||||||
"Generate a property condition where the expression is a disjunct expression.
|
"Generate a property condition where the expression is a disjunct expression.
|
||||||
TODO: this is definitely still wrong!"
|
TODO: this is definitely still wrong!"
|
||||||
([tree]
|
([tree]
|
||||||
(let [property (generate (nth tree 1))
|
(let [property (generate (second tree))
|
||||||
qualifier (generate (nth tree 2))
|
qualifier (generate (nth tree 2))
|
||||||
expression (generate (nth tree 3))]
|
expression (generate (nth tree 3))]
|
||||||
(generate-disjunct-property-condition tree property qualifier expression)))
|
(generate-disjunct-property-condition tree property qualifier expression)))
|
||||||
|
@ -169,7 +183,7 @@
|
||||||
(generate-property-condition tree (first (nth tree 3)))))
|
(generate-property-condition tree (first (nth tree 3)))))
|
||||||
([tree expression-type]
|
([tree expression-type]
|
||||||
(assert-type tree :PROPERTY-CONDITION)
|
(assert-type tree :PROPERTY-CONDITION)
|
||||||
(let [property (generate (nth tree 1))
|
(let [property (generate (second tree))
|
||||||
qualifier (generate (nth tree 2))
|
qualifier (generate (nth tree 2))
|
||||||
e (generate (nth tree 3))
|
e (generate (nth tree 3))
|
||||||
expression (cond
|
expression (cond
|
||||||
|
@ -182,21 +196,61 @@
|
||||||
(list qualifier (list property 'cell) expression)))))
|
(list qualifier (list property 'cell) expression)))))
|
||||||
|
|
||||||
|
|
||||||
(defn generate-simple-action
|
(defn generate-qualifier
|
||||||
[tree]
|
[tree]
|
||||||
(assert-type tree :SIMPLE-ACTION)
|
(if
|
||||||
(let [property (generate (nth tree 1))
|
(= (count tree) 2)
|
||||||
expression (generate (nth tree 3))]
|
(generate (second tree))
|
||||||
(if (or (= property :x) (= property :y))
|
;; else
|
||||||
(throw (Exception. reserved-properties-error))
|
(generate (nth tree 2))))
|
||||||
(list 'merge 'cell {property expression}))))
|
|
||||||
|
|
||||||
|
(defn generate-simple-action
|
||||||
|
([tree]
|
||||||
|
(assert-type tree :SIMPLE-ACTION)
|
||||||
|
(generate-simple-action tree []))
|
||||||
|
([tree others]
|
||||||
|
(assert-type tree :SIMPLE-ACTION)
|
||||||
|
(let [property (generate (second tree))
|
||||||
|
expression (generate (nth tree 3))]
|
||||||
|
(if (or (= property :x) (= property :y))
|
||||||
|
(throw (Exception. reserved-properties-error))
|
||||||
|
(list 'merge
|
||||||
|
(if (empty? others) 'cell
|
||||||
|
;; else
|
||||||
|
(generate others))
|
||||||
|
{property expression})))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn generate-probable-action
|
||||||
|
([tree]
|
||||||
|
(assert-type tree :PROBABLE-ACTION)
|
||||||
|
(generate-probable-action tree []))
|
||||||
|
([tree others]
|
||||||
|
(assert-type tree :PROBABLE-ACTION)
|
||||||
|
(let
|
||||||
|
[chances (generate (nth tree 1))
|
||||||
|
total (generate (nth tree 2))
|
||||||
|
action (generate-action (nth tree 3) others)]
|
||||||
|
;; TODO: could almost certainly be done better with macro syntax
|
||||||
|
(list 'if
|
||||||
|
(list '< (list 'rand total) chances)
|
||||||
|
action))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn generate-action
|
||||||
|
[tree others]
|
||||||
|
(case (first tree)
|
||||||
|
:ACTIONS (generate-action (first tree) others)
|
||||||
|
:SIMPLE-ACTION (generate-simple-action tree others)
|
||||||
|
:PROBABLE-ACTION (generate-probable-action tree others)
|
||||||
|
(throw (Exception. (str "Not a known action type: " (first tree))))))
|
||||||
|
|
||||||
|
|
||||||
(defn generate-multiple-actions
|
(defn generate-multiple-actions
|
||||||
[tree]
|
[tree]
|
||||||
(assert (and (coll? tree)(= (first tree) :ACTIONS)) "Expected an ACTIONS fragment")
|
(assert-type tree :ACTIONS)
|
||||||
(conj 'do (map generate-simple-action (rest tree))))
|
(generate-action (first (rest tree)) (second (rest tree))))
|
||||||
|
|
||||||
|
|
||||||
(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
|
||||||
|
@ -224,7 +278,9 @@
|
||||||
"Generate code for a condition which refers to neighbours."
|
"Generate code for a condition which refers to neighbours."
|
||||||
([tree]
|
([tree]
|
||||||
(assert-type tree :NEIGHBOURS-CONDITION)
|
(assert-type tree :NEIGHBOURS-CONDITION)
|
||||||
(generate-neighbours-condition tree (first (second (second tree)))))
|
(case (first (second tree))
|
||||||
|
:QUANTIFIER (generate-neighbours-condition tree (first (second (second tree))))
|
||||||
|
:QUALIFIER (cons (generate (second tree)) (rest (generate (nth tree 2))))))
|
||||||
([tree quantifier-type]
|
([tree quantifier-type]
|
||||||
(let [quantifier (second tree)
|
(let [quantifier (second tree)
|
||||||
pc (generate (nth tree 4))]
|
pc (generate (nth tree 4))]
|
||||||
|
@ -234,7 +290,8 @@
|
||||||
:MORE (let [value (generate (nth quantifier 3))]
|
:MORE (let [value (generate (nth quantifier 3))]
|
||||||
(generate-neighbours-condition '> value pc 1))
|
(generate-neighbours-condition '> value pc 1))
|
||||||
:LESS (let [value (generate (nth quantifier 3))]
|
:LESS (let [value (generate (nth quantifier 3))]
|
||||||
(generate-neighbours-condition '< value pc 1)))))
|
(generate-neighbours-condition '< value pc 1))
|
||||||
|
)))
|
||||||
([comp1 quantity property-condition distance]
|
([comp1 quantity property-condition distance]
|
||||||
(list comp1
|
(list comp1
|
||||||
(list 'count
|
(list 'count
|
||||||
|
@ -245,6 +302,31 @@
|
||||||
(generate-neighbours-condition comp1 quantity property-condition 1)))
|
(generate-neighbours-condition comp1 quantity property-condition 1)))
|
||||||
|
|
||||||
|
|
||||||
|
(defn generate-within-condition
|
||||||
|
"Generate code for a condition which refers to neighbours within a specified distance.
|
||||||
|
NOTE THAT there's clearly masses of commonality between this and
|
||||||
|
`generate-neighbours-condition`, and that some refactoring is almost certainly
|
||||||
|
desirable. It may be that it's better to simplify a `NEIGHBOURS-CONDITION`
|
||||||
|
into a `WITHIN-CONDITION` in the simplification stage."
|
||||||
|
([tree]
|
||||||
|
(assert-type tree :WITHIN-CONDITION)
|
||||||
|
(case (first (second tree))
|
||||||
|
:QUANTIFIER (generate-within-condition tree (first (second (second tree))))
|
||||||
|
:QUALIFIER (TODO "qualified within... help!")))
|
||||||
|
([tree quantifier-type]
|
||||||
|
(let [quantifier (second tree)
|
||||||
|
distance (generate (nth tree 4))
|
||||||
|
pc (generate (nth tree 6))]
|
||||||
|
(case quantifier-type
|
||||||
|
:NUMBER (generate-neighbours-condition '= (read-string (second (second quantifier))) pc distance)
|
||||||
|
:SOME (generate-neighbours-condition '> 0 pc distance)
|
||||||
|
:MORE (let [value (generate (nth quantifier 3))]
|
||||||
|
(generate-neighbours-condition '> value pc distance))
|
||||||
|
:LESS (let [value (generate (nth quantifier 3))]
|
||||||
|
(generate-neighbours-condition '< value pc distance))
|
||||||
|
))))
|
||||||
|
|
||||||
|
|
||||||
(defn generate
|
(defn generate
|
||||||
"Generate code for this (fragment of a) parse tree"
|
"Generate code for this (fragment of a) parse tree"
|
||||||
[tree]
|
[tree]
|
||||||
|
@ -253,7 +335,7 @@
|
||||||
(case (first tree)
|
(case (first tree)
|
||||||
:ACTIONS (generate-multiple-actions tree)
|
:ACTIONS (generate-multiple-actions tree)
|
||||||
:COMPARATIVE (generate (second tree))
|
:COMPARATIVE (generate (second tree))
|
||||||
:COMPARATIVE-QUALIFIER (generate (nth tree 2))
|
:COMPARATIVE-QUALIFIER (generate (second tree))
|
||||||
:CONDITION (generate-condition tree)
|
:CONDITION (generate-condition tree)
|
||||||
:CONDITIONS (generate-conditions tree)
|
:CONDITIONS (generate-conditions tree)
|
||||||
:CONJUNCT-CONDITION (generate-conjunct-condition tree)
|
:CONJUNCT-CONDITION (generate-conjunct-condition tree)
|
||||||
|
@ -271,14 +353,16 @@
|
||||||
:NEIGHBOURS-CONDITION (generate-neighbours-condition tree)
|
:NEIGHBOURS-CONDITION (generate-neighbours-condition tree)
|
||||||
:NUMERIC-EXPRESSION (generate-numeric-expression tree)
|
:NUMERIC-EXPRESSION (generate-numeric-expression tree)
|
||||||
:NUMBER (read-string (second tree))
|
:NUMBER (read-string (second tree))
|
||||||
|
:OPERATOR (symbol (second tree))
|
||||||
|
:PROBABLE-ACTION (generate-probable-action tree)
|
||||||
:PROPERTY (list (generate (second tree)) 'cell) ;; dubious - may not be right
|
:PROPERTY (list (generate (second tree)) 'cell) ;; dubious - may not be right
|
||||||
:PROPERTY-CONDITION (generate-property-condition tree)
|
:PROPERTY-CONDITION (generate-property-condition tree)
|
||||||
:QUALIFIER (generate (second tree))
|
:QUALIFIER (generate-qualifier tree)
|
||||||
:RULE (generate-rule tree)
|
:RULE (generate-rule tree)
|
||||||
:SIMPLE-ACTION (generate-simple-action tree)
|
:SIMPLE-ACTION (generate-simple-action tree)
|
||||||
:SYMBOL (keyword (second tree))
|
:SYMBOL (keyword (second tree))
|
||||||
:VALUE (generate (second tree))
|
:VALUE (generate (second tree))
|
||||||
:OPERATOR (symbol (second tree))
|
:WITHIN-CONDITION (generate-within-condition tree)
|
||||||
(map generate tree))
|
(map generate tree))
|
||||||
tree))
|
tree))
|
||||||
|
|
||||||
|
@ -300,7 +384,7 @@
|
||||||
"There are a number of possible simplifications such that if the `tree` has
|
"There are a number of possible simplifications such that if the `tree` has
|
||||||
only two elements, the second is semantically sufficient."
|
only two elements, the second is semantically sufficient."
|
||||||
[tree]
|
[tree]
|
||||||
(if (= (count tree) 2) (simplify (nth tree 1)) tree))
|
(if (= (count tree) 2) (simplify (second tree)) tree))
|
||||||
|
|
||||||
|
|
||||||
(defn rule?
|
(defn rule?
|
||||||
|
@ -316,15 +400,17 @@
|
||||||
(coll? tree)
|
(coll? tree)
|
||||||
(case (first tree)
|
(case (first tree)
|
||||||
:ACTION (simplify-second-of-two tree)
|
:ACTION (simplify-second-of-two tree)
|
||||||
:ACTIONS (simplify-second-of-two tree)
|
:ACTIONS (cons (first tree) (simplify (rest tree)))
|
||||||
|
:CHANCE-IN nil
|
||||||
:COMPARATIVE (simplify-second-of-two tree)
|
:COMPARATIVE (simplify-second-of-two tree)
|
||||||
:CONDITION (simplify-second-of-two tree)
|
:CONDITION (simplify-second-of-two tree)
|
||||||
:CONDITIONS (simplify-second-of-two tree)
|
:CONDITIONS (simplify-second-of-two tree)
|
||||||
:EXPRESSION (simplify-second-of-two tree)
|
:EXPRESSION (simplify-second-of-two tree)
|
||||||
:NOT nil ;; TODO is this right?!? It looks wrong
|
|
||||||
:PROPERTY (simplify-second-of-two tree)
|
:PROPERTY (simplify-second-of-two tree)
|
||||||
|
:PROPERTY-CONDITION-OR-EXPRESSION (simplify-second-of-two tree)
|
||||||
:SPACE nil
|
:SPACE nil
|
||||||
:THEN nil
|
:THEN nil
|
||||||
|
:AND nil
|
||||||
:VALUE (simplify-second-of-two tree)
|
:VALUE (simplify-second-of-two tree)
|
||||||
(remove nil? (map simplify tree)))
|
(remove nil? (map simplify tree)))
|
||||||
tree))
|
tree))
|
||||||
|
|
|
@ -436,12 +436,12 @@
|
||||||
"Addition is executed")))
|
"Addition is executed")))
|
||||||
|
|
||||||
(testing "Arithmetic action: addition of property value"
|
(testing "Arithmetic action: addition of property value"
|
||||||
(let [afn (compile-rule "if state is climax then fertility should be fertility + leaf-fall")]
|
(let [afn (compile-rule "if state is climax then fertility should be fertility + leaffall")]
|
||||||
(is (= (:fertility
|
(is (= (:fertility
|
||||||
(apply afn
|
(apply afn
|
||||||
(list {:state :climax
|
(list {:state :climax
|
||||||
:fertility 0
|
:fertility 0
|
||||||
:leaf-fall 1} nil)))
|
:leaffall 1} nil)))
|
||||||
1)
|
1)
|
||||||
"Addition is executed")))
|
"Addition is executed")))
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue