Commits

Steve Losh  committed 9abbc19

Initial commit.

  • Participants

Comments (0)

Files changed (7)

+/target
+/lib
+/classes
+/checkouts
+pom.xml
+*.jar
+*.class
+.lein-deps-sum
+.lein-failures
+.lein-plugins
+syntax: glob
+target/
+lib/
+classes/
+checkouts/
+pom.xml
+*.jar
+*.class
+.lein-deps-sum
+.lein-failures
+.lein-plugins

File README.markdown

+# Dram
+
+Clojure templating that won't make you drink.
+
+Not ready yet.
+
+Usage
+-----
+
+Don't yet.
+
+License
+-------
+
+Copyright 2012 Steve Losh and contributors.
+
+Distributed under the MIT/X11 license.
+(defproject dram "0.1.0-SNAPSHOT"
+  :description "Clojure templating that won't make you want to drink."
+  :url "http://sjl.bitbucket.org/dram/"
+  :license {:name "MIT/X11"}
+  :dependencies [[org.clojure/clojure "1.4.0"]
+                 [the/parsatron "0.0.3"]])

File src/dram/core.clj

+(ns dram.core)
+
+(defn foo
+  "I don't do a whole lot."
+  [x]
+  (println x "Hello, World!"))

File src/dram/parser.clj

+(ns dram.parser
+  (:refer-clojure :exclude [char])
+  (:use [the.parsatron]))
+
+
+; Whitespace ------------------------------------------------------------------
+(defparser whitespace-char []
+  (token #{\space \newline \tab}))
+
+(defparser optional-whitespace []
+  (many (whitespace-char))
+  (always nil))
+
+(defparser required-whitespace []
+  (many1 (whitespace-char))
+  (always nil))
+
+
+; Numbers ---------------------------------------------------------------------
+(defparser literal-integer-pos []
+  (let->> [digits (many1 (digit))]
+    (always (Integer/parseInt (apply str digits)))))
+
+(defparser literal-integer-neg []
+  (char \-)
+  (let->> [n (literal-integer-pos)]
+    (always (- n))))
+
+(defparser literal-integer []
+  (either (attempt (literal-integer-neg))
+          (literal-integer-pos)))
+
+
+; Strings ---------------------------------------------------------------------
+(defparser literal-string-escape []
+  (char \\)
+  (let->> [ch (any-char)]
+    (always (case ch
+              \\ \\
+              \n \newline
+              \" \"
+              ch))))
+
+(defparser literal-string-char []
+  (either (attempt (literal-string-escape))
+          (token (complement #{\"}))))
+
+(defparser literal-string []
+  (between (char \") (char \")
+           (let->> [contents (many (literal-string-char))]
+             (always (apply str contents)))))
+
+
+; Main ------------------------------------------------------------------------
+(defn parse
+  "Parse the given string into a Dram AST."
+  [string]
+  (run (>> (literal-string)) string))
+
+
+(comment
+  (parse "")
+  ) 

File test/dram/test/parser.clj

+(ns dram.test.parser
+  (:require [dram.parser :as p]
+            [clojure.test :refer :all]
+            [the.parsatron :refer [run]]))
+
+(defmacro is-error [input parser]
+  `(~'is (~'thrown? RuntimeException (run ~parser ~input))))
+
+(defmacro parses-as [input parser output]
+  `(~'is (~'= ~output (run ~parser ~input))))
+
+(deftest whitespace-test
+  (testing "Optional whitespace parses to nil."
+    (parses-as "" (p/optional-whitespace) nil)
+    (parses-as "     " (p/optional-whitespace) nil)
+    (parses-as "\t" (p/optional-whitespace) nil)
+    (parses-as "\n" (p/optional-whitespace) nil)
+    (parses-as "\n \t " (p/optional-whitespace) nil))
+  (testing "Required whitespace parses to nil."
+    (parses-as "     " (p/required-whitespace) nil)
+    (parses-as "\t" (p/required-whitespace) nil)
+    (parses-as "\n" (p/required-whitespace) nil)
+    (parses-as "\n \t " (p/required-whitespace) nil))
+  (testing "Required whitespace is actually required."
+    (is-error "" (p/required-whitespace))
+    (is-error "foo " (p/required-whitespace))))
+
+(deftest integer-test
+  (testing "Parsing integers results in Clojure integers."
+    (parses-as "1" (p/literal-integer) 1)
+    (parses-as "10" (p/literal-integer) 10)
+    (parses-as "9234" (p/literal-integer) 9234))
+  (testing "Parsing negative integers."
+    (parses-as "-1" (p/literal-integer) -1)
+    (parses-as "-2945" (p/literal-integer) -2945))
+  (testing "Parsing garbage with the integer parser fails."
+    (is-error "" (p/literal-integer))
+    (is-error " 1" (p/literal-integer))
+    (is-error "foo" (p/literal-integer))
+    (is-error "-" (p/literal-integer))
+    (is-error " -1" (p/literal-integer))
+    (is-error "- 1" (p/literal-integer))
+    (is-error "-a12" (p/literal-integer))))
+
+(deftest string-test
+  (testing "Literal strings of simple characters parse to Clojure strings."
+    (parses-as "\"\"" (p/literal-string) "")
+    (parses-as "\"foo\"" (p/literal-string) "foo")
+    (parses-as "\" bar \"" (p/literal-string) " bar "))
+  (testing "Escape sequences are supported in strings."
+    (parses-as "\"a\\nb\"" (p/literal-string) "a\nb")
+    (parses-as "\"a\\\\b\"" (p/literal-string) "a\\b")
+    (parses-as "\"a\\\\nb\"" (p/literal-string) "a\\nb"))
+    (parses-as "\"a\\\"b\"" (p/literal-string) "a\"b")
+  (testing "Garbage doesn't parse as strings."
+    (is-error "foo" (p/literal-string)) 
+    (is-error "\"foo" (p/literal-string))
+    (is-error "foo\"" (p/literal-string)))
+  (testing "Parses the first bit as a string, so it should succeed (for now)."
+    (parses-as "\"fo\"o\"" (p/literal-string) "fo")))