 (defun zencoding-tag (input)
   "Parse a tag."
   (zencoding-run zencoding-tagname
-                 (let ((result it)
-                       (tagname (cdr expr)))
+                 (let ((tagname (cadr expr))
+                       (has-body? (cddr expr)))
                    (zencoding-pif (zencoding-run zencoding-identifier
                                                  (zencoding-tag-classes
-                                                  `(tag ,tagname ((id ,(cddr expr)))) input)
-                                                 (zencoding-tag-classes `(tag ,tagname ()) input))
-                                  (let ((expr-and-input it) (expr (car it)) (input (cdr it)))
-                                    (zencoding-pif (zencoding-tag-props expr input)
-                                                   it
-                                                   expr-and-input))))
-                 '(error "expected tagname")))
+                                                  `(tag (,tagname ,has-body? ,(cddr expr))) input)
+                                                 (zencoding-tag-classes
+                                                  `(tag (,tagname ,has-body? nil)) input))
+                                  (let ((expr (car it))
+                                        (input (cdr it)))
+                                    (zencoding-tag-props expr input))))
+                 (zencoding-default-tag input)))
+
+(defun zencoding-default-tag (input)
+  "Parse a #id or .class"
+  (zencoding-parse "\\([#|\\.]\\)" 1 "tagname"
+                   (zencoding-tag (concat "div" (elt it 0)))))
 
 (defun zencoding-tag-props (tag input)
-  (zencoding-run zencoding-props
-                 (let ((tagname (cadr tag))
-                       (existing-props (caddr tag))
-                       (props (cdr expr)))
-                   `((tag ,tagname
-                          ,(append existing-props props))
-                     . ,input))))
+  (let ((tag-data (cadr tag)))
+    (zencoding-run zencoding-props
+                   (let ((props (cdr expr)))
+                     `((tag ,(append tag-data (list props))) . ,input))
+                   `((tag ,(append tag-data '(nil))) . ,input))))
 
 (defun zencoding-props (input)
   "Parse many props."

                 ("a#q.x>b"                "<a id=\"q\" class=\"x\"><b></b></a>")
                 ("a#q.x.y.z>b"            "<a id=\"q\" class=\"x y z\"><b></b></a>")
                 ("a#q.x.y.z>b#p.l.m.n"    "<a id=\"q\" class=\"x y z\"><b id=\"p\" class=\"l m n\"></b></a>")
                 ("a>b+c"                  "<a><b></b><c></c></a>")
                 ("a>b+c>d"                "<a><b></b><c><d></d></c></a>")
                 ;; Multiplication
                 ("a*1"                    "<a></a>")
                 ("a*2"                    "<a></a><a></a>")
                 ("a*2+b*2"                "<a></a><a></a><b></b><b></b>")
                 ("a*2>b*2"                "<a><b></b><b></b></a><a><b></b><b></b></a>")
                 ("a>b*2"                  "<a><b></b><b></b></a>")
                 ("a#q.x>b#q.x*2"          "<a id=\"q\" class=\"x\"><b id=\"q\" class=\"x\"></b><b id=\"q\" class=\"x\"></b></a>")
                 ;; Properties
                 ("a x=y"                  "<a x=\"y\"></a>")
                 ("a x=y m=l"              "<a x=\"y\" m=\"l\"></a>")
                 ("a#foo x=y m=l"          "<a id=\"foo\" x=\"y\" m=\"l\"></a>")
                 ("a.foo x=y m=l"          "<a class=\"foo\" x=\"y\" m=\"l\"></a>")
                 ("a#foo.bar.mu x=y m=l"   "<a id=\"foo\" class=\"bar mu\" x=\"y\" m=\"l\"></a>")
                 ("a x=y+b"                "<a x=\"y\"></a><b></b>")
                 ("a x=y+b x=y"            "<a x=\"y\"></a><b x=\"y\"></b>")
                 ("a x=y>b"                "<a x=\"y\"><b></b></a>")
                 ("a x=y>b x=y"            "<a x=\"y\"><b x=\"y\"></b></a>")
                 ("a x=y>b x=y+c x=y"      "<a x=\"y\"><b x=\"y\"></b><c x=\"y\"></c></a>")
                 ;; Parentheses
                 ("(a)"                    "<a></a>")
                 ("(a)+(b)"                "<a></a><b></b>")
                 ("a>(b)"                  "<a><b></b></a>")
                 ("(a>b)>c"                "<a><b></b></a>")
                 ("(a>b)+c"                "<a><b></b></a><c></c>")
                 ("z+(a>b)+c+k"            "<z></z><a><b></b></a><c></c><k></k>")
                 ("(a)*2"                  "<a></a><a></a>")
                 ("((a)*2)"                "<a></a><a></a>")
                 ("((a)*2)"                "<a></a><a></a>")
                 ("(a>b)*2"                "<a><b></b></a><a><b></b></a>")
                 ("(a+b)*2"                "<a></a><b></b><a></a><b></b>")
                 )))
    (mapc (lambda (input)
            (let ((expected (cadr input))
                  (actual (zencoding-transform (car (zencoding-expr (car input))))))
              (if (not (equal expected actual))
                  (error (concat "Assertion " (car input) " failed:"

;; Zen coding parsers

(defun zencoding-expr (input)
  "Parse a zen coding expression with optional filters."
  (zencoding-pif (zencoding-parse "\\(.*?\\)|" 2 "expr|filter" it)
                 (let ((input (elt it 1))
                       (filters (elt it 2)))
                   (zencoding-pif (zencoding-extract-filters filters)
                                  (zencoding-filter input it)
                                  it))
                 (zencoding-filter input (zencoding-default-filter))))

(defun zencoding-subexpr (input)
  "Parse a zen coding expression with no filter. This pretty much defines precedence."
  (zencoding-run zencoding-siblings
                 it
                 (zencoding-run zencoding-parent-child
