Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Silly-j parser #12

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion project.clj
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
:target-path "target/%s"

:dependencies [[org.clojure/clojure "1.10.0"]
[org.clojure/clojurescript "1.10.520"]]
[org.clojure/clojurescript "1.10.520"]
[instaparse "1.4.10"]]
:plugins [[lein-doo "0.1.10"]]
:cljsbuild
{:builds [{:id "node-test"
Expand Down
51 changes: 51 additions & 0 deletions src/hopen/syntax/silly_j.cljc
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
(ns hopen.syntax.silly-j
(:require [hopen.renderer.xf :as rxf]
[instaparse.core :as insta]))

(declare parse)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be avoided if the render function can be defined after the parser.

Usually, the declare is only used when there is a cross recursion between 2 functions defined at the root level.


;; TODO test case
(defn render
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest to let the user do his own composition between the renderers and the parsers.

If this function is here just for testing, it makes sense to move it to the test namespace.

([template data]
(render template data '()))
([template data other-env]
(let [new-env (update rxf/default-env :bindings assoc other-env)
renderer (rxf/renderer (parse template) new-env)]
(transduce renderer str data))))

(def ebnf
(insta/parser "
S = [STR | SILLYSTR]+
STR = #'[^{}]+'
SILLYSTR = OBK SILLY CBK
OBK = '{'
CBK = '}'
Copy link
Member

@green-coder green-coder Apr 2, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest using non-abbreviated names or less abbreviated names, to ensure that anybody can easily read the source code.

OPEN_BLOCK, CLOSE_BLOCK for example.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a side note: the casing (upper-case / lower-case) does not matter for instaparse.

SILLY = [FCTX | FN]
FCTX = '@' ':' ATTR
ATTR = #'[^}]'+
FN = FNNAME APPLIES*
APPLIES = SPC | FCTX | APPLY
FNNAME = #'[a-zA-Z0-9\\-]+'
SPC = #'\\ '+
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SPACE

APPLY = #'^[^@\\ ][^}\\ ]+'
"
))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Odie I think that you might want to give instaparse a try.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, I think mustache is sufficiently simple to deal with by hand. (Famous last words?)

Instaparse is really fantastic, but my last impression of it was “really magical, but maybe somewhat slow”. It might have been due to an ambiguous grammar that caused it to try going down two separate paths of the grammar tree though.

Anyway, since there are no complicated grammatical structures, and mustache is already fully spec’ed out, I’ll try seeing it through the rest of the way.


(defn parse [msg]
(->> (ebnf msg)
(insta/transform
{:STR str
:APPLY str
:FNNAME str
:ATTR str
:FCTX (fn [at comma attr]
(list 'hopen/ctx (keyword attr)))
:SPC identity
:FN (fn [first-elm & applies]
(cons (symbol first-elm)
(remove #{" "} applies)))
:APPLIES identity
:SILLY identity
:SILLYSTR (fn [obrk silly cbrk] silly)
:S list
})))
2 changes: 2 additions & 0 deletions test/hopen/runner.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
(:require [cljs.test :as t :include-macros true]
[doo.runner :refer-macros [doo-all-tests doo-tests]]
[hopen.renderer.xf-test]
[hopen.syntax.silly-j-test]
[hopen.util-test]))

(doo-tests 'hopen.renderer.xf-test
'hopen.syntax.silly-j-test
'hopen.util-test)
21 changes: 21 additions & 0 deletions test/hopen/syntax/silly_j_test.cljc
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
(ns hopen.syntax.silly-j-test
(:require #?(:clj [clojure.test :refer [deftest testing is are]]
:cljs [cljs.test :refer [deftest testing is are]
:include-macros true])
[hopen.syntax.silly-j :refer [parse]]))

(deftest parse-test
(testing "basic syntax test"
(are [template parsed]
(= (parse template)
parsed)
;; Split string and context
"Hello {@:name}, {@:n} * {@:n} = {square @:n}" ["Hello "
green-coder marked this conversation as resolved.
Show resolved Hide resolved
'(hopen/ctx :name)
", "
'(hopen/ctx :n)
" * "
'(hopen/ctx :n)
" = "
'(square (hopen/ctx :n))]
)))