diff --git a/README.md b/README.md index bc6cdc7..bb23915 100644 --- a/README.md +++ b/README.md @@ -318,7 +318,7 @@ Only vectors beginning with keywords are interpreted as elements. A vector can s ```clojure ;; Not elements -(c/html [0 1 2]) ; => "123" +(c/html [0 1 2]) ; => "012" (c/html ["foo" "bar"]) ; => "foobar" (c/html ^::c/content [:foo :bar]) ; => "foobar" @@ -424,7 +424,7 @@ Use `token-serializer` and `html-serializer` to access individual tokens and fra ### DOCTYPE -Use `doctype-html5`. It's just a RawString wrapping ``. Because it's a RawString, it is safe to wrap in a vector to concatenate with the rest of the HTML document. +Use `c/doctype-html5`. It's just a RawString wrapping ``. Because it's a RawString, it is safe to wrap in a vector to concatenate with the rest of the HTML document. ```clojure (c/html [c/doctype-html5 [:html "..."]]) @@ -434,7 +434,7 @@ Use `doctype-html5`. It's just a RawString wrapping ``. Because i ###   -Use the `nbsp` constant. +Use the `c/nbsp` constant. ```clojure (c/html [:div "foo" c/nbsp "bar"]) @@ -687,25 +687,26 @@ Functions calls, and generally any list values, block compilation traversal. Cal ### Alias Elements -Alias elements are implemented as `c/resolve-alias` function calls. As a result, they also block compilation. However, the arguments pass to `c/resolve-alias` will be compiled. +Alias elements are implemented as `c/resolve-alias` (via `c/resolve-alias-with-meta`) function calls. As a result, they also block compilation. However, the arguments pass to `c/resolve-alias` will be compiled. ```clojure -(defmethod c/resolve-alias ::FooComp +(defmethod c/resolve-alias ::CompileMyAlias [_ attrs content] [:div attrs content]) -(pprint (clojure.walk/macroexpand-all +(pprint + (clojure.walk/macroexpand-all '(cc/compile - [::FooComp {:foo "bar"} + [::CompileMyAlias {:foo "bar"} [:p "content 1"] [:p "content 2"]]))) ;; Results in: -(dev.onionpancakes.chassis.core/resolve-alias +(dev.onionpancakes.chassis.core/resolve-alias-with-meta nil - :user/FooComp + :user/CompileMyAlias {:foo "bar"} - [#object[dev.onionpancakes.chassis.core.RawString 0x2da06c23 "

content 1

content 2

"]]) + [#object[dev.onionpancakes.chassis.core.RawString 0x34e3a7d6 "

content 1

content 2

"]]) ``` ### Macro Calls @@ -714,22 +715,22 @@ Macros are expanded during compilation. Like function calls, those which expand ```clojure (pprint - (cc/compile - [:ol - (for [i (range 4)] - [:li i])])) + (cc/compile + [:ol + (for [i (range 4)] + [:li i])])) ;; Results in: -[[#object[dev.onionpancakes.chassis.core.OpeningTag 0xe119f5b "
    "] +[[#object[dev.onionpancakes.chassis.core.OpeningTag 0x6e462cc4 "
      "] ([:li 0] [:li 1] [:li 2] [:li 3])] - #object[dev.onionpancakes.chassis.core.RawString 0x7a434ee8 "
    "]] + #object[dev.onionpancakes.chassis.core.RawString 0x27b55932 "
"]] ;; Manually call compile in the inner form to reach inside. (pprint - (cc/compile - [:ol - (for [i (range 4)] - (cc/compile [:li i]))])) + (cc/compile + [:ol + (for [i (range 4)] + (cc/compile [:li i]))])) ``` Macros which expand into non-lists can participate in compilation. Therefore, it is possible to use macros to abstract element components in a compile friendly way. diff --git a/src/dev/onionpancakes/chassis/core.clj b/src/dev/onionpancakes/chassis/core.clj index 6d1f51f..54cfcaf 100644 --- a/src/dev/onionpancakes/chassis/core.clj +++ b/src/dev/onionpancakes/chassis/core.clj @@ -1,13 +1,13 @@ (ns dev.onionpancakes.chassis.core) (defprotocol AttributeValue - (append-attribute-fragment-to [this sb attr-name] "Appends attribute key and value html fragment.")) + (append-attribute-fragment-to [this sb attr-name] "Appends attribute key and value HTML fragment.")) (defprotocol AttributeValueFragment - (^String attribute-value-fragment [this] "Returns attribute value fragment string or nil if none.")) + (^String attribute-value-fragment [this] "Returns attribute value HTML fragment or nil if none.")) (defprotocol Token - (append-fragment-to [this sb] "Appends html fragment.") + (append-fragment-to [this sb] "Appends HTML fragment.") (^String fragment [this] "Returns HTML fragment.")) (defprotocol Node @@ -27,15 +27,16 @@ ;; - DFS is implemented using a stack of Iterators. (java.util.Deque) ;; Note that head of stack is held by loop binding rather than the actual head of stack. ;; - Node children returns a value that is as flat as possible -;; to minimized the depth of search (size of Deque). -;; See the count varying node-children-n implementations +;; to minimize the depth of search (size of Deque). +;; See the varying element-children-n implementations. ;; - Iterables returned by Node children should prefer implementations ;; that are internally indexes to arrays. ;; Iterators over Vectors are fast, Iterators over Seqs are not as fast. -;; - DFS emits a minimum number of Tokens. Therefore Node children emits +;; - DFS emits minimum number of Tokens. Therefore Node children return ;; OpeningTag and ClosingTag types as "fat" tokens capturing the bracket, ;; tag name, and tag attributes data into one Token instance. -;; - Coalesce appends in large chunks showed 20% performance boost compared to +;; - Coalescing appends in large chunks showed 25% performance boost +;; (the dev example dropped from 500us to 400us) when compared to ;; to fragmented appends. Interleaving appends with branches and computation ;; is detrimental. Therefore, the code is structured like a decision ;; tree so the branches and computation happens early and the appends are