diff --git a/src/hopen/syntax/silly_j.cljc b/src/hopen/syntax/silly_j.cljc
new file mode 100644
index 0000000..e788de5
--- /dev/null
+++ b/src/hopen/syntax/silly_j.cljc
@@ -0,0 +1,51 @@
+(ns hopen.syntax.silly-j
+  (:require [hopen.renderer.xf :as rxf]
+            [instaparse.core :as insta]))
+
+(declare parse)
+
+;; TODO test case
+(defn render
+  ([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      = '}'
+                SILLY    = [FCTX | FN]
+                FCTX     = '@' ':' ATTR
+                ATTR     = #'[^}]'+
+                FN       = FNNAME APPLIES*
+                APPLIES  = SPC | FCTX | APPLY
+                FNNAME   = #'[a-zA-Z0-9\\-]+'
+                SPC      = #'\\ '+
+                APPLY    = #'^[^@\\ ][^}\\ ]+'
+                "
+                ))
+
+(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
+        })))
diff --git a/test/hopen/runner.cljs b/test/hopen/runner.cljs
index 625ad81..5ce7cf9 100644
--- a/test/hopen/runner.cljs
+++ b/test/hopen/runner.cljs
@@ -5,6 +5,7 @@
              [hopen.renderer.xf-test]
              [hopen.syntax.handlebars-test]
              [hopen.syntax.partition-test]
+             [hopen.syntax.silly-j-test]
              [hopen.syntax.util-test]
              [hopen.util-test]))
 
@@ -12,5 +13,6 @@
            'hopen.renderer.xf-test
            'hopen.syntax.handlebars-test
            'hopen.syntax.partition-test
+           'hopen.syntax.silly-j-test
            'hopen.syntax.util-test
            'hopen.util-test)
diff --git a/test/hopen/syntax/silly_j_test.cljc b/test/hopen/syntax/silly_j_test.cljc
new file mode 100644
index 0000000..a1031e0
--- /dev/null
+++ b/test/hopen/syntax/silly_j_test.cljc
@@ -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 "
+                                                                       '(hopen/ctx :name)
+                                                                       ", "
+                                                                       '(hopen/ctx :n)
+                                                                       " * "
+                                                                       '(hopen/ctx :n)
+                                                                       " = "
+                                                                       '(square (hopen/ctx :n))]
+        )))