+class Node
+ constructor: (type, args = {}) ->
+ @type = type # one of the TYPE_* constants above
+ @name = args.name ? '' # tag name
+ @text = args.text ? '' # contents for text/comment nodes
+ @attrs = args.attrs ? {}
+ @attrs_a = args.attr_k ? [] # attrs in progress, TYPE_OPEN_TAG only
+ @children = args.children ? []
+ serialize: -> # for unit tests
+ ret = ''
+ switch @type
+ when TYPE_TAG
+ ret += 'tag:'
+ ret += JSON.stringify @name
+ ret += ','
+ ret += JSON.stringify @attrs
+ ret += ','
+ sep = '['
+ for c in @children
+ ret += sep
+ sep = ','
+ ret += c.serialize()
+ ret += ']'
+ when TYPE_TEXT
+ ret += 'text:'
+ ret += JSON.stringify @text
+ when TYPE_COMMENT
+ ret += 'comment:'
+ ret += JSON.stringify @text
+ when TYPE_DOCTYPE
+ ret += 'doctype'
+ # FIXME
+ else
+ ret += 'unknown:'
+ return ret
+
+
+# helpers: (only take args that are normally known when parser creates nodes)
+new_open_tag = (name) ->
+ return new Node TYPE_OPEN_TAG, name: name
+new_end_tag = (name) ->
+ return new Node TYPE_END_TAG, name: name
+new_text_node = (txt) ->
+ return new Node TYPE_TEXT, text: txt
+new_comment_node = (txt) ->
+ return new Node TYPE_COMMENT, text: txt
+new_eof_token = ->
+ return new Node TYPE_EOF
+