Skip to content
Irakli Gozalishvili edited this page Nov 17, 2013 · 2 revisions

Analyzer takes read wisp code form and performs both syntax & macro expansions over it, producing AST nodes that are hash maps that implement following interface:

{:type :keyword
:form '(read data)}

The :type key is mapped to a keyword representing the AST variant type. All the AST nodes produced by analyzer comply to some AST type interface described by this document.

The :form key is mapped to an actual form that was analyzed producing AST node containing it. Note that raw forms mapped to the key will also typically have a metadata containing source location information of the node.

Location information contains start (the position of the first character of the parsed source region) & and an end position (the position of the first character after the parsed source region):

Both :start and :end positions contain (0-indexed) :line number and a (0-indexed) :column number that can be obtained as illustrated in the examples below:

;; Start line position
(:line (:start (meta (:form node))))
;; Start column position
(:column (:start (meta (:form node))))

;; End line position
(:line (:end (meta (:form node))))
;; End columnt position
(:column (:end (meta (:form node))))

LiteralNode

Literals are represented by an AST nodes of with :op :constant:

{:op :constant
 :form nil}

{:op :constant
 :form "foo"}

{:op :constant
 :form true}

{:op :constant
 :form 5}

{:op :constant
 :form #"foo"}

{:op :constant
 :form ':bar}

{:op :constant
 :form 'baz}

Reader spits out actual primitive on literals (except for quoted symbols), for literal nodes don't carry any metadata with them, but that should change in a future.

IdentifierNode

Identifier nodes typically represent either referces to a specific bindings or an identifiers of the declared bindings. Declaration identifier nodes are the ones which have :info field to nil.

{:op :var
 :form 'foo
 :info null}

Reference identifiers on the other hand have :info field mapped to a hash that representing binding it's reference of:

{:op :var
 :form 'bar
 :info {:name 'bar
        :shadow nil}}

Sometimes bindings may shadow bindings in an outer scope. Such nodes will have :shadow field mapped to true and :depth field mapped to the integer representing level of shadowing depth (this information is used by writer to rename binding definitions based on shadowing depth).

{:op :var
 :form 'foo
 :info {:name 'foo
        :shadow true
        :depth 1}

ParameterNode

Parameter nodes represent parameters of the function expressions or catch expressions. Parameter nodes also carry shadowing similar to identifiers:

{:op :parameter
 :id IdentifierNode
 :form 'foo
 :depth 1
 :shadow true}

BindingNode

Binding nodes represent bindings defined via let and loop forms

{:op :binding
 :id {:op :var
      :form 'foo
      :info null
      :depth 1
      :shadow true}
 :init {:op :constant
        :form 1}
 :form '(foo 1)}

DefinitionNode

{:op :def
 :doc nil
 :id IdentifierNode
 :init Node
 :export false
 :form '(def foo 1)}

IfNode

If nodes are nodes representing if expressions:

{:op :if
 :test Node
 :consequent Node
 :alternate Node
 :form '(if (empty? chars)
            :eof
            (recur (rest chars)
                   (conj result (first chars))))}

ThrowNode

Throw nodes represent throw expressions. :throw field is mapped to arbitrary node that is a second form in the throw.

{:op :throw
 :throw {:op :var
         :form 'error
         :info nil}
 :form '(throw error)}

AssignmentNode

Assignment nodes are produced by set! expressions. :target field is mapped to an identifier node and :value field is mapped to expression being assigned to that identifier:

{:op :set!
 :target {:op :var
          :form 'foo
          :info nil}
  :value {:op :constant
          :form "bar"}
 :form '(set! foo "bar")}

NewNode

New node are produced by new special forms. It's :constructor field is mapped to a node (typically identifier but could be any expression) representing a constructor. It's :params field is mapped to a vector of (any) nodes passed to a constructor:

{:type :new
 :constructor {:op :var
               :form 'Error
               :info nil}
 :params [{:op :constant
           :form "Boom!"}]
 :form '(new Error "Boom!)}