diff --git a/src/FiniteAutomata.kt b/src/FiniteAutomata.kt
index 8382e59..9bb8693 100644
--- a/src/FiniteAutomata.kt
+++ b/src/FiniteAutomata.kt
@@ -1,9 +1,13 @@
 import dev.w1zzrd.automata.*
 
 fun main(args: Array<String>){
+    // Create a language with the set of elements {0, 1}
     val language = Language.makeLanguage(0, 1)
+
+    // Create a nondeterministic automaton
     val nfa = Automaton(language, false)
 
+    // Declare states of the NFA
     val stateS = nfa.makeState("s")
     val stateQ1 = nfa.makeState("q1")
     val stateQ2 = nfa.makeState("q2", true)
@@ -11,8 +15,10 @@ fun main(args: Array<String>){
     val stateQ = nfa.makeState("q")
     val stateR = nfa.makeState("r", true)
 
+    // Add epsilon transition from S to Q1 and P
     stateS.addEpsilon(stateQ1, stateP)
 
+    // Add regular state-transition connectives
     stateQ1.addConnective(0, stateQ1)
     stateQ1.addConnective(1, stateQ2)
 
@@ -23,14 +29,18 @@ fun main(args: Array<String>){
 
     stateQ.addConnective(arrayOf(0, 1), stateR)
 
+    // Declare S as the initial state
     nfa.entryPoint = stateS
 
+    // Convert the NFA into an equivalent DFA
     val dfa = nfa.toDeterministicAutomaton(true)
 
+    // Get a traverser for the DFA and manually traverse the string "1100", then print the resulting state
     val dtraverser = dfa.makeTraverser()
     dtraverser.traverse(1, 1, 0, 0)
     println(dtraverser.currentState.toString())
 
+    // Do the same as above but for the NFA
     val ntraverser = nfa.makeTraverser()
     ntraverser.traverse(1, 1, 0, 0)
     println(ntraverser.currentState.toString())
diff --git a/src/dev/w1zzrd/automata/Automaton.kt b/src/dev/w1zzrd/automata/Automaton.kt
index 7bc7b6a..b6b7bf7 100644
--- a/src/dev/w1zzrd/automata/Automaton.kt
+++ b/src/dev/w1zzrd/automata/Automaton.kt
@@ -1,10 +1,39 @@
 package dev.w1zzrd.automata
 
+/**
+ * A finite automaton that accepts elements from the given language and
+ * which is either deterministic or nondeterministic
+ */
 class Automaton<T>(val language: Language<T>, val deterministic: Boolean){
+    /**
+     * All states of the automaton
+     */
     private val states = ArrayList<State<T>>()
-    private val factory = StateFactory(language, deterministic)
-    var entryPoint: State<T>? = null
 
+    /**
+     * Which state the automaton should start at.
+     *
+     * @exception IllegalArgumentException If there is an attempt to set the initial state to one that does not exist in
+     * the set of possible states for this automaton.
+     */
+    var entryPoint: State<T>? = null
+        set(value){
+            if(!states.contains(value))
+                throw IllegalArgumentException("State not valid for this automaton!")
+            field = value
+        }
+
+    /**
+     * Add states to the automaton (if, for example, they weren't automatically created with [makeState])
+     * Note that nondeterministic states can only be added to nondeterministic automata. Deterministic states have
+     * no similar or corresponding restrictions.
+     *
+     * @param states States to add to the automaton
+     *
+     * @exception IllegalArgumentException If a nondeterministic state was passed to a deterministic automaton.
+     *
+     * @see Automaton.makeState
+     */
     fun addStates(vararg states: State<T>){
         states.forEach { state ->
             if(addState(state))
@@ -14,6 +43,18 @@ class Automaton<T>(val language: Language<T>, val deterministic: Boolean){
         }
     }
 
+    /**
+     * Add a single state to the automaton (if, for example, it wasn't automatically created with [makeState]).
+     * Note that a nondeterministic state can only be added to a nondeterministic automaton. Deterministic states have
+     * no similar or corresponding restrictions.
+     *
+     * @param state State to add to the automaton
+     *
+     * @return True if the state was successfully added, else false.
+     * @exception IllegalArgumentException If a nondeterministic state was passed to a deterministic automaton.
+     *
+     * @see Automaton.makeState
+     */
     fun addState(state: State<T>): Boolean{
         if(deterministic && !state.isDeterministic)
             throw IllegalArgumentException("Deterministic automaton can only contain deterministic states!")
@@ -25,13 +66,40 @@ class Automaton<T>(val language: Language<T>, val deterministic: Boolean){
         return false
     }
 
+    /**
+     * Create a new state in this automaton. The generated state will be deterministic if the automaton represented by
+     * this object is deterministic, otherwise it will be nondeterministic.
+     *
+     * @param name The [State.name] of the State. Note that this must be unique for this automaton
+     * @param acceptState Whether or not the generated State should be an final/accept state of the automaton
+     * @return The generated state.
+     *
+     * @see State.acceptState
+     * @see State.name
+     */
     fun makeState(name: String, acceptState: Boolean = false): State<T> {
-        val state = factory.make(name, acceptState)
+        val state = State.make(name, acceptState, language, deterministic) // Create the state
+
+        // Ensure that the state is successfully added to the automaton
         if(!addState(state))
             throw IllegalArgumentException("Duplicate state detected!")
+
         return state
     }
 
+    /**
+     * Checks whether the given input string will leave the automaton in an accept-state after processing the string.
+     * This happens when, after the final element in the string is processed, the automaton is currently in an accept-
+     * state - in the case of deterministic automata - or the set of current states contains an accept-state.
+     *
+     * @param string The string of values governing the state transitions in the automaton starting at the specified
+     * initial state.
+     *
+     * @return True if the current state representation is (or contains) an accept state.
+     *
+     * @see Automaton.entryPoint
+     * @see State.acceptState
+     */
     fun accepts(vararg string: T): Boolean {
         if(!(language hasVerbs string))
             throw IllegalArgumentException("All verbs in string must be part of the language!")
@@ -44,6 +112,47 @@ class Automaton<T>(val language: Language<T>, val deterministic: Boolean){
         return traverser.accepted
     }
 
+    /**
+     * Converts the automaton represented by this object into its equivalent DFA representation. If this object already
+     * is a DFA (i.e. if [deterministic] is true), then no action is performed.
+     *
+     *
+     *
+     * An example of how this is done:
+     *
+     *   Assume we have the language {0, 1} and states 'a' and 'b'
+     *
+     *   Assume we start at 'a' and that 'b' is an accept state.
+     *
+     *   Assume 'a' transitions to 'a' or 'b' on input 0, and transitions to 'b' on input 1
+     *
+     *   Assume 'b' transitions to 'a' on input 0 and does nothing on input '1'
+     *
+     *   In this case, we can construct the following transition table:
+     *
+     * ..............|.0........|.1...
+     *
+     * ->.{a}....|.{a, b}.|.{b}
+     *
+     * F..{a, b}.|.{a, b}.|.{b}
+     *
+     * F..{b}.....|.{a}.....|.∅
+     *
+     * The keys (leftmost table elements) can then be used as the names of the new states in the DFA representation, and
+     * the states in the corresponding table entries represent the connectives for the DFA. In the case of the empty set
+     * (∅), this must become its own state that has no outgoing connectives.
+     *
+     *
+     * @param printTable Whether or not to print the generated NFA state-input mappings to STDOUT
+     *
+     * @return A deterministic automaton which processes the same language as the automaton represented by this object.
+     * When the object called already is deterministic, it simply returns itself.
+     *
+     * @exception IllegalStateException If [entryPoint] is null, as no DFA can be generated if there is no entry point.
+     *
+     * @see Automaton.deterministic
+     * @see Automaton.entryPoint
+     */
     fun toDeterministicAutomaton(printTable: Boolean = false): Automaton<T> {
         if(deterministic) return this
         if(entryPoint == null)
@@ -62,40 +171,56 @@ class Automaton<T>(val language: Language<T>, val deterministic: Boolean){
             }
             return if(result == null) null else result to find!!
         }
+
+        // Simple function for converting states to a corresponding string
+        // The corresponding string will describe a set of the included states
         fun Iterable<State<T>>.toReadableString(): String {
-            val builder = StringBuilder("{")
             val stringComparator = Comparator.naturalOrder<String>()
             val sorted = sortedWith(Comparator{ state1, state2 -> stringComparator.compare(state1.name, state2.name) })
+
+            // If the set is empty, return the empty set ;)
             if(sorted.isEmpty()) return "∅"
-            for(state in sorted)
-                builder.append(state.name).append(',')
-            if(sorted.isNotEmpty()) builder.setCharAt(builder.length - 1, '}')
-            else builder.append('}')
+
+            // A non-empty set starts with a '{'
+            val builder = StringBuilder("{")
+
+            // Append the name of each state, followed by a comma
+            for(state in sorted) builder.append(state.name).append(',')
+
+            // The last character should be a '}', not a comma, so replace the above appended comma accordingly
+            builder.setCharAt(builder.length - 1, '}')
+
             return builder.toString()
         }
 
+        // Create a traverser object for this automaton and get the initial state of it
         val traverser = StateTraverser(entryPoint!!)
         val startingState = traverser.currentState
 
-        // Initialize table
+        // Initialize the table with an empty map
         tableEntries[startingState] = HashMap()
 
         var currentMapping: Pair<MutableList<State<T>>, T>? = null
+
+        // Continue to populate table until all columns of all rows are populated
         while(tableEntries.run {
                     currentMapping = findUnpopulatedMapping()
                     currentMapping != null
                 }){
+
+            // Set the state of the traverser to the state for which we are populating the table entry
             traverser.currentState = currentMapping!!.first
             traverser.traverse(currentMapping!!.second)
 
-            if(tableEntries[currentMapping!!.first] == null)
-                tableEntries[currentMapping!!.first] = HashMap()
-
+            // Save the result of the traversal
             tableEntries[currentMapping!!.first]!![currentMapping!!.second] = traverser.currentState
+
+            // If the resulting state is one for which we don't have a row in the table, create it!
             if(tableEntries.keys.firstOrNull { traverser.currentState.contentsEquals(it) } == null)
                 tableEntries[traverser.currentState] = HashMap()
         }
 
+        // Print the table, if requested
         if(printTable)
             for(key in tableEntries.keys.sortedBy { if(it.contentsEquals(startingState)) 0 else if (it.isAcceptState()) 2 else 1  }){
                 print(
@@ -110,61 +235,122 @@ class Automaton<T>(val language: Language<T>, val deterministic: Boolean){
                 println()
             }
 
+        // Create a one-to-one mapping between the set of reachable state-sets of the NFA to states in the DFA
         val oldToNew = HashMap<MutableList<State<T>>, State<T>>()
 
+        // Create the DFA
         val dfa = Automaton(language, true)
+
+        // Generate the NFA-DFA state-set-to-state mappings, as well as populating the DFA with the necessary states
         for(tableState in tableEntries.keys)
             oldToNew[tableState] = dfa.makeState(tableState.toReadableString(), tableState.contentsEquals(startingState))
 
+        // Apply the mapping schema determined by the generated state-table to the DFA
         for(oldState in oldToNew.keys)
             for(mapping in tableEntries[oldState]!!)
                 oldToNew[oldState]!!.addConnective(mapping.key, oldToNew[mapping.value]!!)
 
+        // Set the start of the DFA to be the state corresponding to the starting state of the NFA
         dfa.entryPoint = oldToNew[startingState]
 
         return dfa
     }
 
+    /**
+     * check if the contents of two collections is equal.
+     *
+     * @param other The other collection to compare against
+     *
+     * @return True if the length of the two collections is equal, and each element in one collection has an equivalent
+     * element in the other
+     */
     private infix fun <V> Collection<V>.contentsEquals(other: Collection<V>) =
             size == other.size &&
             firstOrNull { other.firstOrNull { check -> check == it } == null } == null
 
+    /**
+     * Whether or not the given set of states is an accept-state-set.
+     *
+     * @return True if one or more of the states in the list is an accept state, otherwise false.
+     */
     private fun MutableList<State<T>>.isAcceptState() = firstOrNull { it.acceptState } != null
 
-    fun makeTraverser(): StateTraverser{
+    /**
+     * Create a [StateTraverser] for this automaton.
+     *
+     * @return A [StateTraverser] starting at the set [entryPoint].
+     *
+     * @exception IllegalStateException If the [entryPoint] for this automaton is null.
+     */
+    fun makeTraverser(): StateTraverser {
         if(entryPoint == null)
             throw IllegalStateException("Entry point state must be defined!")
         return StateTraverser(entryPoint!!)
     }
 
+    /**
+     * A class that allows simulation of an automaton.
+     *
+     * @param entryPoint Which state to start at when simulating the automaton.
+     */
     inner class StateTraverser(entryPoint: State<T>) {
+        /**
+         * A list describing the set of currently active states. In the case of a deterministic automaton, this will at
+         * most have a size of 1.
+         */
         var currentState: MutableList<State<T>> = ArrayList()
 
+        /**
+         * Whether or not the current state(s) is an accept state
+         */
         val accepted: Boolean
             get() = currentState.isAcceptState()
 
         init {
+            // The initial state is determined by epsilon-traversal
             currentState.traverseEpsilon(entryPoint)
         }
 
+        /**
+         * Traverse states according to the given string
+         *
+         * @param verbs The string to traverse according to. All elements of the string must be part of the language of
+         * the automaton!
+         *
+         * @see Automaton.language
+         */
         fun traverse(vararg verbs: T){
             for(verb in verbs)
                 transformState(verb)
         }
 
+        /**
+         * Transform the state according to a single element from the language
+         *
+         * @param verb Element to traverse according to
+         */
         private fun transformState(verb: T){
             val nextState = ArrayList<State<T>>()
 
+            // Loop through all active states
             for(state in currentState)
-                for(traverseState in state.getConnective(verb)) {
+                // Get all states that each state transitions to for the given element
+                for(traverseState in state.getConnective(verb))
+                    // Perform epsilon transitions for each newly discovered state
                     nextState.traverseEpsilon(traverseState)
-                }
 
+            // Update the state of the traverser
             currentState = nextState
         }
 
+        /**
+         * Perform an epsilon transition from the given state and apply it to the list represented by this object.
+         */
         private fun MutableList<State<T>>.traverseEpsilon(state: State<T>){
+            // Bad way of avoiding duplicates, but hey, I wrote this in a couple of hours
             if(!contains(state)) add(state)
+
+            // Recursively traverse epsilon connectives for new connectives (i.e. for states not already traversed)
             for(epsilonState in state.getEpsilon())
                 if(!contains(epsilonState))
                     traverseEpsilon(epsilonState)
diff --git a/src/dev/w1zzrd/automata/Language.kt b/src/dev/w1zzrd/automata/Language.kt
index 5d57c31..cd47864 100644
--- a/src/dev/w1zzrd/automata/Language.kt
+++ b/src/dev/w1zzrd/automata/Language.kt
@@ -2,16 +2,61 @@ package dev.w1zzrd.automata
 
 import kotlin.collections.ArrayList
 
+/**
+ * A language for an automaton. This defines what input an automaton can accept.
+ *
+ * @param language A raw list of what elements are contained in this language.
+ */
 class Language<T> private constructor(private val language: List<T>) {
 
+    /**
+     * The elements of the language. This cannot contain duplicates.
+     */
     val elements: List<T>
         get() = ArrayList(language)
 
+    /**
+     * Whether or not this language contains a given element.
+     *
+     * @param verb Element to check for
+     *
+     * @return True if the given element is in the language set, else false.
+     */
     infix fun hasVerb(verb: T) = language.contains(verb)
+
+    /**
+     * Whether or not this language contains a set of given elements.
+     *
+     * @param string Elements to check for
+     *
+     * @return True if all of the given elements are in the language set, else false.
+     */
     infix fun hasVerbs(string: Iterable<T>) = string.firstOrNull { !(this hasVerb it) } == null
+
+    /**
+     * Whether or not this language contains a set of given elements.
+     *
+     * @param string Elements to check for
+     *
+     * @return True if all of the given elements are in the language set, else false.
+     */
     infix fun hasVerbs(string: Array<out T>) = string.firstOrNull { !(this hasVerb it) } == null
 
+    /**
+     * Companion object acting as a factory (of sorts) for Languages.
+     */
     companion object {
+
+        /**
+         * Create a language from a given set of elements.
+         *
+         * @param language The set of elements defining the language
+         *
+         * @return A [Language] object if the set of language elements comprise a valid language.
+         *
+         * @exception IllegalArgumentException If the given set of language elements do not comprise a valid language (
+         * i.e. if there are duplicate elements).
+         */
         fun <T> makeLanguage(vararg language: T): Language<T> {
             language.forEachIndexed { outerIndex, outerValue ->
                 language.forEachIndexed { innerIndex, innerValue ->
diff --git a/src/dev/w1zzrd/automata/State.kt b/src/dev/w1zzrd/automata/State.kt
index 55c0187..8eaef9e 100644
--- a/src/dev/w1zzrd/automata/State.kt
+++ b/src/dev/w1zzrd/automata/State.kt
@@ -1,5 +1,14 @@
 package dev.w1zzrd.automata
 
+/**
+ * A state in a finite automaton
+ *
+ * @param name The unique name of the state used to identify it
+ * @param language The acceptable language for this state (used for mapping transitions)
+ * @param isDeterministic Whether or not this state allows epsilon-transitions and/or multiple transition targets for an
+ * input
+ * @param acceptState Whether or not this state is a final (accept) state for an automaton
+ */
 class State<T>(
         val name: String,
         val language: Language<T>,
@@ -16,18 +25,45 @@ class State<T>(
      */
     private val epsilon = ArrayList<State<T>>()
 
+    /**
+     * Declare that a given set of elements from the language result in a transition to the given states.
+     *
+     * @param verbs Elements that result in the transitions to the given states
+     * @param state The states to transition to
+     */
     fun addConnective(verbs: Array<T>, vararg state: State<T>) = verbs.forEach { addConnective(it, *state) }
+
+    /**
+     * Declare that a given element from the language results in a transition to the given states.
+     *
+     * @param verb Element that results in the transition to the given states
+     * @param state The states to transition to
+     *
+     * @exception IllegalArgumentException If a transition was declared that is characteristic of a nondeterministic
+     * transition (i.e. more than one target was specified, or more than one target would be specified upon successful
+     * declaration of this connective), but the state represented by this object is deterministic.
+     *
+     * @exception IllegalArgumentException If the given element is not a part of the declared language.
+     */
     fun addConnective(verb: T, vararg state: State<T>){
+        // Ensure nondeterministic behaviour is only possible for nondeterministic states
         if(isDeterministic && (state.size > 1 || connective[verb]?.contains(state[0]) == false))
             throw IllegalArgumentException("Deterministic states can only contain one-to-one connectives!")
 
+        // Ensure element is indeed a part of the language
         if(language hasVerb verb){
+            // Create the mapping if necessary, otherwise just add it the the mapped connective list
             if(connective[verb] == null) connective[verb] = mutableListOf(*state)
             else connective[verb]!!.addAll(state)
         }
         else throw IllegalArgumentException("Verb must be in language!")
     }
 
+    /**
+     * Declared an epsilon transition from this state to a given set of states.
+     *
+     * @exception IllegalStateException If the state represented by this object is deterministic
+     */
     fun addEpsilon(vararg state: State<T>){
         if(isDeterministic)
             throw IllegalStateException("Epsilon-transitions are not possible in DFA models!")
@@ -35,9 +71,20 @@ class State<T>(
         epsilon.addAll(state)
     }
 
+    /**
+     * "Simulate" a transition from this state for a given element from the language.
+     *
+     * @return The set of states that result from applying the element to this state (if any).
+     */
     fun getConnective(verb: T) =
             ArrayList(connective[verb] ?: listOf<State<T>>())
 
+    /**
+     * Gets all immediate epsilon transitions from this state. This will NOT get all indirect epsilon transitions from
+     * this state. I.e., state A has an epsilon transition to state B, and B has an epsilon transition to state C,
+     * A.getEpsilon() will only return a set containing B, since C is only indirectly connected to a through epsilon
+     * transitions.
+     */
     fun getEpsilon() = ArrayList(epsilon)
 
     override fun equals(other: Any?) = other is State<*> && other.name == name
@@ -48,8 +95,12 @@ class State<T>(
     override fun toString(): String {
         return name
     }
-}
 
-class StateFactory<T>(val language: Language<T>, val deterministic: Boolean){
-    fun make(name: String, acceptState: Boolean) = State(name, language, deterministic, acceptState)
+    /**
+     * Factory class for creating [State] object. Really just here for convenience.
+     */
+    companion object {
+        fun <T> make(name: String, acceptState: Boolean, language: Language<T>, deterministic: Boolean) =
+                State(name, language, deterministic, acceptState)
+    }
 }
\ No newline at end of file