mw-parser/src/mw_parser/flow.clj

68 lines
2.9 KiB
Clojure

(ns ^{:doc "A very simple parser which parses flow rules."
:author "Simon Brooke"}
mw-parser.flow
(:require [clojure.string :refer [join]]
[mw-parser.declarative :refer [build-parser]]
[mw-parser.simplify :refer [simplify-second-of-two]]))
(def flow-grammar
"Grammar for flow rules.
My initial conception of this would be that production rules
(if-then rules) and flow rules (flow-from-to rules) would be
entirely separate, presented to the parser as separate text
files, and parsed and compiled by different chains of functions.
This appears not to be necessary. Flow rules are easy to parse
with the same parser as production rules -- a lot of the grammar
is intentionally common -- and the rules are easily discriminated
at the compilation ('generate') stage.
The basic rule I want to be able to compile at this stage is the 'mutual
aid' rule:
`flow 1 food from house having food > 1 to house with least food within 2`
"
(join "\n" ["FLOW-RULE := FLOW SPACE QUANTITY SPACE PROPERTY SPACE FROM SPACE SOURCE SPACE TO-HOW SPACE DESTINATION;"
"PERCENTAGE := NUMBER #'%';"
"QUANTITY := PERCENTAGE | NUMBER | EXPRESSION | SOME;"
"SOURCE := STATE | STATE SPACE WITH SPACE CONDITIONS;"
"DESTINATION := STATE | STATE SPACE WITH SPACE FLOW-CONDITIONS | STATE SPACE WITHIN SPACE VALUE SPACE WITH SPACE FLOW-CONDITIONS;"
"DETERMINER := MOST | LEAST;"
"DETERMINER-CONDITION := DETERMINER SPACE PROPERTY | DETERMINER SPACE PROPERTY;"
"FLOW-CONDITIONS := DETERMINER-CONDITION | CONDITIONS"
"STATE := SYMBOL;"
"TO-HOW := TO | TO-EACH | TO-FIRST;"
"TO-EACH := TO SPACE EACH | TO SPACE ALL;"
"TO-FIRST := TO SPACE FIRST"]))
(def parse-flow
"Parse the argument, assumed to be a string in the correct syntax, and return a parse tree."
(build-parser flow-grammar))
(defn simplify-flow
[tree]
(if (coll? tree)
(case (first tree)
:CONDITION (simplify-second-of-two tree)
:CONDITIONS (simplify-second-of-two tree)
:DETERMINER (simplify-second-of-two tree)
;; :DETERMINER-CONDITION (simplify-determiner-condition tree)
:EXPRESSION (simplify-second-of-two tree)
:FLOW nil
;; :FLOW-CONDITIONS (simplify-second-of-two tree)
:PROPERTY (simplify-second-of-two tree)
:PROPERTY-CONDITION-OR-EXPRESSION (simplify-second-of-two tree)
:SPACE nil
:QUANTITY (simplify-second-of-two tree)
:STATE (list :PROPERTY-CONDITION
(list :SYMBOL "state")
'(:QUALIFIER
(:EQUIVALENCE
(:IS "is")))
(list :EXPRESSION
(list :VALUE (second tree))))
(remove nil? (map simplify-flow tree)))
tree))