Skip to content

Commit

Permalink
Removed regular-expressions from gluer.clauses.
Browse files Browse the repository at this point in the history
The gluer.parser now includes the matched groups for regular
expression terminals. This means there is only one place where
the regular expressions are managed (in gluer.resources). It can
be improved further, by having named capture groups, but this
requires a lot more refactoring.
  • Loading branch information
aroemers committed Oct 30, 2012
1 parent dc9ab86 commit 3e377cb
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 27 deletions.
48 changes: 26 additions & 22 deletions src/gluer/clauses.clj
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,15 @@
(ffirst where-clause)))


;;; Helper functions.

(defn- full-class-name
"Returns the fully qualified class name, based on a package name and class
name. The package may be nil."
[package class-name]
(str package (when package ".") class-name))


;;; The 'new' what clause.

(defmethod check-what :what-clause-new
Expand Down Expand Up @@ -98,20 +107,18 @@

(defmethod check-what :what-clause-call
[association]
(let [what (get-in association [:what :what-clause-call :method :word])
matched (re-matches #"((\w+\.)+)(\w+)\(.*\)" what)
class-name (apply str (butlast (second matched)))]
(let [{:keys [word match]} (get-in association [:what :what-clause-call :method])
class-name (full-class-name (nth match 1) (nth match 2))]
(if-let [ctclass (r/class-by-name class-name)]
(check-expression what)
(check-expression word)
(format "Class %s in the `new' clause not found. Please check the name or classpath."
class-name))))

(defmethod type-of-what :what-clause-call
[what-clause]
(let [what (get-in what-clause [:what-clause-call :method :word])
matched (re-matches #"((\w+\.)+)(\w+)\(.*\)" what)
class-name (apply str (butlast (second matched)))
method-name (nth matched 3)
(let [match (get-in what-clause [:what-clause-call :method :match])
class-name (full-class-name (nth match 1) (nth match 2))
method-name (nth match 3)
ctclass (r/class-by-name class-name)
method (first (filter #(= (.getName %) method-name) (.getMethods ctclass)))]
(.getName (.getReturnType method))))
Expand Down Expand Up @@ -146,40 +153,37 @@

(defmethod check-where :where-clause-field
[association]
(let [where (get-in association [:where :where-clause-field :field :word])
matched (re-matches #"((?:\w+\.)+)(\w+)" where)
class-name (apply str (butlast (second matched)))
field-name (nth matched 2)]
(let [match (get-in association [:where :where-clause-field :field :match])
class-name (full-class-name (nth match 1) (nth match 2))
field-name (nth match 3)]
(if-let [ctclass (r/class-by-name class-name)]
(try
(let [field (.getDeclaredField ctclass field-name)]
nil) ;--- TODO: Check if field has init code or injection is overwritten in a constructor.
nil) ;--- Check if field has init code or injection is overwritten in a constructor?
(catch javassist.NotFoundException nfe
(format "Class %s does not have a field named %s." class-name field-name)))
(format "Class %s cannot be found. Please check the name or classpath."))))


(defmethod type-of-where :where-clause-field
[where-clause]
(let [where (get-in where-clause [:where-clause-field :field :word])
matched (re-matches #"((?:\w+\.)+)(\w+)" where)
class-name (apply str (butlast (second matched)))
field-name (nth matched 2)
(let [match (get-in where-clause [:where-clause-field :field :match])
class-name (full-class-name (nth match 1) (nth match 2))
field-name (nth match 3)
ctclass (r/class-by-name class-name)
field (.getDeclaredField ctclass field-name)]
(.getName (.getType field))))

(defmethod transforms-classes :where-clause-field
[association]
(let [where (get-in association [:where :where-clause-field :field :word])
matched (re-matches #"((?:\w+\.)+)(\w+)" where)]
#{(apply str (butlast (second matched)))}))
(let [match (get-in association [:where :where-clause-field :field :match])]
#{(full-class-name (nth match 1) (nth match 2))}))

(defmethod inject-where :where-clause-field
[where-clause ctclass retrieval-code]
(let [constructors (.getDeclaredConstructors ctclass)
where (get-in where-clause [:where-clause-field :field :word])
field-name (nth (re-matches #"((?:\w+\.)+)(\w+)" where) 2)
match (get-in where-clause [:where-clause-field :field :match])
field-name (nth match 3)
constructor-code (format "_inject_%1$s();" field-name)
field-code (format "private boolean _%1$s_injected;" field-name)
method-code (format
Expand Down
11 changes: 10 additions & 1 deletion src/gluer/parser.clj
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
;;;--- TODO: Make parser a stand-alone library.
;;;
;;;--- TODO: Add parse functions for regular expression terminals,
;;; so one could have for instance {:call {:word "alice.bob.Foo$Bar.get(true)"
;;; :line-nr 1
;;; :data {:class-name "Foo$Bar"
;;; :package "alice.bob"
;;; :method-name "get"}}}
;;;
;;;--- TODO: How to deal with [:foo*] rules, where errors in parsing :foo are lost?

(ns gluer.parser
(:use [clojure.string :only (split split-lines join)]))
Expand All @@ -21,7 +30,7 @@
word (:word token)]
(if token
(if-let [match (re-matches re word)]
{:succes token;(if (vector? match) (first match) match)
{:succes (assoc token :match match)
:remainder (rest remainder)}
{:error (str "Unexpected token '" word "' on line " (:line-nr token)
", expected a word matching the regex '" re "'.")})
Expand Down
14 changes: 10 additions & 4 deletions src/gluer/resources.clj
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,12 @@

;;; Parsing the .gluer files and building the association library

;; The following definitions are (partial) regular expression, each yielding one
;; capture group.
(def ^:private package-pattern "(?:((?:\\w+\\.)*\\w+)\\.)")
(def ^:private class-pattern "((?:\\w|\\$)+)")
(def ^:private member-pattern "(\\w+)")

(def rules
"The parse rules for .gluer files."
{; Basic rules
Expand All @@ -148,17 +154,17 @@
:where #{ :where-clause-field }
:what #{ :what-clause-new :what-clause-call :what-clause-single}
:using ["using" :class]
:class #"((\w+\.)*)((\w|\$)+)"

:class (re-pattern (str package-pattern "?" class-pattern))
; Where clauses
:where-clause-field ["field" :field]
:field #"(\w+\.)+\w+"
:field (re-pattern (str package-pattern "?" class-pattern "\\." member-pattern))

; What clauses
:what-clause-new ["new" :class]

:what-clause-call ["call" :method]
:method #"(\w+\.)+\w+\(.*\)"
:method (re-pattern (str package-pattern "?" class-pattern "\\." member-pattern "\\(.*\\)"))

:what-clause-single ["single" :class]})

Expand Down

0 comments on commit 3e377cb

Please sign in to comment.