uint16 NTYPE_MODULE = 0
uint16 NTYPE_EXPORT = 1
uint16 NTYPE_STRUCT = 2
uint16 NTYPE_TYPE = 3
uint16 NTYPE_ID = 4
uint16 NTYPE_BIN_OP = 5
uint16 NTYPE_PRE_OP = 6
uint16 NTYPE_POST_OP = 7
uint16 NTYPE_FUNCTION = 8
uint16 NTYPE_METHOD = 9
uint16 NTYPE_TLIST = 10
uint16 NTYPE_DLIST = 11
uint16 NTYPE_ELIST = 12
uint16 NTYPE_SLIST = 13
uint16 NTYPE_LITERAL = 14
# uint16 NTYPE_KEY_TYPE = 14 # Unused
uint16 NTYPE_ENUM = 15
uint16 NTYPE_DECL = 16
uint16 NTYPE_VLIST = 17
uint16 NTYPE_VALUE = 18
uint16 NTYPE_CAST = 19
uint16 NTYPE_FLOW_CONTROL = 20
uint16 NTYPE_IF_BLOCK = 21
uint16 NTYPE_ELIF_BLOCK = 22
uint16 NTYPE_ELSE_BLOCK = 23
uint16 NTYPE_LOOP_BLOCK = 24
uint16 NTYPE_ASM = 998
uint16 NTYPE_EMPTY = 999

struct Node {
	uint16 _type,
	~uint8 data,
	utils.Vector sub,
	~Node parent
}

/; method Node
	/; init (uint16 _type, ~uint8 data)
		self.data = data
		self._type = _type
		self.parent = NULL

		Node n
		self.sub.init(len n)
		self.parent = NULL
	;/

	/; eq (~uint8 cstr) [bool]
		/; if (utils.strcmp(self.data, cstr) == true)
			return true
		;/
		return false
	;/

	/; end
		_delete(self.data)
		
		/; loop (uint i = 0; i < self.sub.count) [i++]
			~Node cur = self.sub.get(i)
			cur`.end()
		;/
		self.sub.end()
	;/

	/; update_children
		/; loop (int i = 0; i < self.sub.count) [i++]
			~Node cur = self.sub.get(i)
			cur`.parent = ~self
		;/
	;/

	/; add_child(~Node n) [~Node]
		n`.parent = ~self
		~int chk = self.sub.data
		self.sub.push(n)
		~int cmp = self.sub.data
		/; loop (int i = 0; i < self.sub.count) [i++]
			n = self.sub.get(i)
			n`.update_children()
		;/
		return n
	;/
;/

/; _get_closing_delim(uint8 ch) [uint8]
	/; if (ch == '/' || ch == ';')
		return ';'
	;; else if (ch == '(')
		return ')'
	;; else if (ch == '[')
		return ']'
	;; else if (ch == '{')
		return '}'
	;/
	return 0
;/

/; _is_closing(~Token tok) [bool]
	/; if (tok`._type !== TTYPE_DELIM)
		return false
	;/
	
	uint8 ch = tok`.data`
	/; if (ch == ';' || ch == '}' || ch == ']' || ch == ')')
		return true
	;/
	return false
;/

/; _advance_check(~utils.File fin, ~Token tok, ~uint8 eq) [bool]
	/; if (tok`._type !== TTYPE_ERR && tok`.eq(eq) == true)
		Token tmp = produce_next_token(fin, tok`)
		tok`.end()
		tok` = tmp
		return true
	;/
	return false
;/

int MAX_ERR_SHOW = 15
int errors_shown = 0

/; _ast_print_err (~utils.File fin, ~Token tok, ~uint8 msg)
	
	#/; if (errors_shown !< MAX_ERR_SHOW)
	#	return
	#;/

	#errors_shown = errors_shown + 1
	
	_printf(msg)
	_printf(":\n\0")
	_printf("  File: \0")
	~uint8 p = fin`.path.to_cstr('/')
	_printf(p)
	_delete(p)
	_printf("\n  At: \0")
	print_token(tok`)
	_printf("\n\0")

	/; if (errors_shown == MAX_ERR_SHOW)
		_printf("\nToo many errors to print, other errors will be suppressed\n\0")
	;/
;/

/; _ast_block_pass(~utils.File fin, ~Token first)
	/; loop (int deep = 1; deep > 0 && first`._type !== TTYPE_ERR)
		/; if (first`.eq(";/\0") == true)
			deep = deep - 1
		;; else if (first`.eq("/;\0") == true)
			deep = deep + 1
		;; else if (first`.eq(";;\0") == true && deep == 1)
			deep = deep - 1
		;/

		/; if (deep > 0)
			Token tmp = produce_next_token(fin, first`)
			first`.end()
			first` = tmp
		;/
	;/
;/



# AST values

/; _op_prefix(~Token op) [bool]
	int l = utils.strlen(op`.data)
	/; if (op`._type !== TTYPE_AUG)
		return false
	;/
	
	/; if (op`.eq("len\0") == true || op`.eq("--\0") == true || op`.eq("++\0") == true)
		return true
	;/

	/; if (l !== 1)
		return false
	;/

	/; if (op`.data` == '-' || op`.data` == '!' || op`.data` == '~')
		return true
	;/

	return false
;/

/; _op_postfix(~Token op) [bool]
	/; if (op`.eq("`\0") == true || op`.eq("++\0") == true || op`.eq("--\0") == true)
		return true
	;/
	return false
;/

/; _op_bin(~Token op) [bool]
	/; if (op`.eq("-\0") == true)
		return true
	;/
	/; if (_op_prefix(op) == true || _op_postfix(op) == true)
		return false
	;/
	return true
;/

/; _op_order(~uint8 op) [int]
	int l = utils.strlen(op)

	/; if (l == 1)
		uint8 ch = op`
		/; if (ch == '`')
			return 0
		;; else if (ch == '.')
			return 1
		;; else if (ch == '~')
			return 2
		;; else if (ch == '*' || ch == '/' || ch == '%')
			return 6
		;; else if (ch == '+' || ch == '-')
			return 7
		;; else if (ch == '!' || ch == '&' || ch == '|' || ch == '^')
			return 8
		;; else if (ch == '<' || ch == '>')
			return 9
		;; else if (ch == '=')
			return 11
		;/
	;; else if (l == 2)
		/; if (utils.strcmp(op, "is\0"))
			return 2
		;/

		/; if (op{0} == op{1})
			uint8 ch = op`
			/; if (ch == '+' || ch == '-')
				return 3
			;; else if (ch == '<' || ch == '>')
				return 4
			;; else if (ch == '=')
				return 9
			;/
			return 10
		;/

		/; if (op{1} == '<' || op{1} == '>')
			return 9
		;; else if (op{1} == '=')
			return 11
		;; else if (op{0} == '!')
			return 8
		;/
	;; else if (l == 3)
		/; if (utils.strcmp(op, "len\0") == true)
			return 5
		;; else if (op{1} == '=')
			return 9
		;/
		return 10
	;/

	_printf("[FATAL] [CMPERR] _op_order: Augment not implemented in ordering \0")
	_print_num("'%s'\n\0", op)
	return 999
;/

/; _astv_pre_id (~utils.File fin, ~Node cur, ~Token first) [~Node]
	/; loop (first`._type == TTYPE_AUG)
		/; if (_op_prefix(first) == false)
			_ast_print_err(fin, first, "Only certain augments (-, !, ~, --, ++, len) can be used as prefixes for bare values\0")
			return cur
		;/
		Node pre
		pre.init(NTYPE_PRE_OP, first`.data)

		cur = cur`.add_child(~pre)
		first` = produce_next_token(fin, first`)
	;/

	return cur
;/

/; _astv_cast (~utils.File fin, ~Node mod, ~Token first) [int]
	int out = first`.line
	/; if (first`.eq("[\0"))
		Node cast
		cast.init(NTYPE_CAST, utils.strcpy("\0"))
		out = _ast_list_type(fin, ~cast, first)
		~Node tmp = mod`.sub.get(mod`.sub.count - 1)
		cast.add_child(tmp)
		mod`.sub.pop()
		mod`.add_child(~cast)
	;/
	return out
;/

/; _astv_post_id (~utils.File fin, ~Node mod, ~Token first, bool lnok) [int]
	int ln = first`.line
	/; loop (bool run = true; run == true && first`._type !== TTYPE_ERR)
		/; if (ln !== first`.line && lnok == false)
			run = false
		;; else if (_op_postfix(first) == true)
			Node post
			post.init(NTYPE_POST_OP, first`.data)
			mod`.add_child(~post)
			first` = produce_next_token(fin, first`)
		;; else if (first`.eq("(\0") == true)
			ln = _ast_list_value(fin, mod, first)
			/; if (first`.eq("[\0") == true && (ln == first`.line || lnok == true))
				ln = _ast_list_value(fin, mod, first)
				run = false
			;/
		;; else if (first`.eq("{\0") == true)
			Node ind
			ind.init(NTYPE_POST_OP, first`.data)
			first` = produce_next_token(fin, first`)
			/; if (_ast_value(fin, ~ind, first, true) == false)
				_ast_print_err(fin, first, "Expected value for index operation after '{'\0")
			;/
			mod`.add_child(~ind)
			ln = first`.line
			/; if (_advance_check(fin, first, "}\0") == false)
				_ast_print_err(fin, first, "Expected '}' to show the end of an index operation after the value\0")
				run = false
			;/
		;; else
			run = false
		;/
	;/
	return ln
;/

/; _ast_value_bare(~utils.File fin, ~Node mod, ~Token first, bool lnok) [bool]

	~Node cur = mod
	
	cur = _astv_pre_id(fin, cur, first)

	int ln = first`.line

	# Pre-flight check
	/; if (first`.eq("{\0") == true)
		ln = _ast_list_value(fin, cur, first)
	;; else if (_advance_check(fin, first, "(\0") == true)
		_ast_value(fin, cur, first, true)
		ln = first`.line
		/; if (_advance_check(fin, first, ")\0") == false)
			_ast_print_err(fin, first, "Expected closing ')' for singlet\0")
			return false
		;/
		/; if (ln == first`.line || lnok == true)
			ln = _astv_cast(fin, cur, first)
			~Node tmp = cur`.sub.get(cur`.sub.count - 1)
		;/
	;; else if (first`._type == TTYPE_USRWD)
		Node val
		val.init(NTYPE_ID, first`.data)
		first` = produce_next_token(fin, first`)
		cur`.add_child(~val)
	;; else if (first`._type == TTYPE_LITRL)
		Node val
		val.init(NTYPE_LITERAL, first`.data)
		first` = produce_next_token(fin, first`)
		cur`.add_child(~val)
	;; else
		_ast_print_err(fin, first, "Expected compound, parenthetical, literal, or identifier for bare value\0")
		return false
	;/
	
	/; if (ln == first`.line || lnok == true)
		ln = _astv_post_id(fin, cur`.sub.get(cur`.sub.count - 1), first, lnok)
	;; else
		return true
	;/

	bool run = ln == first`.line

	# Methods and members
	/; loop (; run == true && _advance_check(fin, first, ".\0") == true)
		/; if (first`._type !== TTYPE_USRWD)
			_ast_print_err(fin, first, "Expected method/member name after '.'\0")
			return false
		;/
		
		~Node repl = cur`.sub.get(cur`.sub.count - 1)
		Node dot
		dot.init(NTYPE_BIN_OP, utils.strcpy(".\0"))
		dot.add_child(repl)

		Node val
		val.init(NTYPE_ID, first`.data)
		int ln = first`.line
		first` = produce_next_token(fin, first`)

		/; if (first`.line !== ln && lnok == false)
			run = false
		;; else
			ln = _astv_post_id(fin, ~val, first, lnok)
		;/

		dot.add_child(~val)

		cur`.sub.pop()
		cur = cur`.add_child(~dot)
	;/

	return true
;/

/; _assoc_right(~uint8 op) [bool]
	int order = _op_order(op)
	/; if (order == 11)
		return true
	;/
	return false
;/

# op - operator to compare against
# i - op order of inserting op
/; _assoc (~uint8 op, int i) [bool]
	int j = _op_order(op)

	/; if (_assoc_right(op) && i == j)
		return false
	;/

	return i !< j
;/

# Needs to be re-done to respect left and right associativity rules
/; _ast_value (~utils.File fin, ~Node mod, ~Token first, bool lnok) [bool]
	
	Node val
	val.init(NTYPE_VALUE, utils.strcpy("\0"))

	~Node cur = ~val

	bool run = _ast_value_bare(fin, cur, first, lnok)
	bool valid = run
	
	/; loop (run == true && first`._type !== TTYPE_ERR)
		/; if (first`._type == TTYPE_SEP || _is_closing(first) == true)
			run = false
		;; else if (first`.eq(".\0") == true)
			run = false
			valid = false
		;; else if (first`._type == TTYPE_AUG && _op_bin(first) == true)
			Node bin
			bin.init(NTYPE_BIN_OP, first`.data)
			
			int i = _op_order(first`.data)
			bool gt = false
			/; if (cur`._type == NTYPE_BIN_OP)
				gt = _assoc(cur`.data, i)
			;/

			# Start from the top and work our way down
			/; loop (gt == true)
				cur = cur`.parent

				/; if (cur`._type == NTYPE_BIN_OP)
					gt = _assoc(cur`.data, i)
				;; else
					gt = false
				;/
			;/
			
			~Node rhs = cur`.sub.get(cur`.sub.count - 1)
			bin.add_child(rhs)
			cur`.sub.pop()
			cur = cur`.add_child(~bin)

			first` = produce_next_token(fin, first`)
			/; if (utils.strcmp(bin.data, "is\0"))
				_ast_type(fin, cur, first)
			;; else
				run = _ast_value_bare(fin, cur, first, lnok)
				valid = run
			;/

		;; else
			run = false
		;/
	;/

	mod`.add_child(~val)
	return valid
;/

/; _ast_keyword_expr (~utils.File fin, ~Node mod, ~Token first)
	int ln = first`.line

	/; if (first`.eq("return\0") == true || first`.eq("continue\0") == true || first`.eq("break\0") == true)
		Node ret
		ret.init(NTYPE_FLOW_CONTROL, first`.data)
		first` = produce_next_token(fin, first`)
		
		/; if (first`.line == ln && _is_closing(first) == false && first`._type !== TTYPE_ERR)
			_ast_value(fin, ~ret, first, false)
		;/
		mod`.add_child(~ret)

		return
	;; else
		_ast_print_err(fin, first, "Unsupported keyword statement\0")
		Token tmp = produce_next_token(fin, first`)
		first`.end()
		first` = tmp
	;/
;/



# AST types

/; _type_helper_pre (~utils.File fin, ~Node mod, ~Token first)

	/; loop (bool run = true; first`._type !== TTYPE_ERR && run == true)
		/; if (first`._type == TTYPE_AUG && first`.eq("~\0") == true)
			# Pointer
			Node ptr
			ptr.init(NTYPE_PRE_OP, first`.data)
			mod`.add_child(~ptr)
			first` = produce_next_token(fin, first`)
		;; else if (first`._type == TTYPE_DELIM && first`.eq("{\0") == true)
			# Array
			Node arr
			arr.init(NTYPE_PRE_OP, first`.data)
			first` = produce_next_token(fin, first`)
			
			/; if (first`._type == TTYPE_LITRL && is_numeric(first`.data`) == true)
				Node num
				num.init(NTYPE_LITERAL, first`.data)
				arr.add_child(~num)

				first` = produce_next_token(fin, first`)

				/; if (first`.eq("}\0") == true)
					Token tmp = produce_next_token(fin, first`)
					first`.end()
					first` = tmp
				;; else
					_ast_print_err(fin, first, "Expected closing '}' after integer in type declaration\0")
					run = false
				;/
			;; else if (first`.eq("}\0") == true)
				Token tmp = produce_next_token(fin, first`)
				first`.end()
				first` = tmp
			;; else
				_ast_print_err(fin, first, "Expected integer or '}' to define either a fixed sized array or pointer to unknown sized array\0")
				run = false
			;/

			mod`.add_child(~arr)

		;; else
			run = false
		;/
	;/

;/

/; _type_helper_func (~utils.File fin, ~Node mod, ~Token first)
	/; if (first`.eq("(\0") == true)
		_ast_list_type(fin, mod, first)
	;/

	/; if (first`.eq("[\0") == true)
		_ast_list_type(fin, mod, first)
	;/
;/

/; _type_helper_usertype (~utils.File fin, ~Node mod, ~Token first)
	
	/; loop (bool run = true; run == true && first`._type !== TTYPE_ERR)
		/; if (first`._type == TTYPE_USRWD)
			Node utp
			utp.init(NTYPE_ID, first`.data)
			first` = produce_next_token(fin, first`)
			mod`.add_child(~utp)

			/; if (first`._type !== TTYPE_AUG || first`.eq(".\0") == false)
				run = false
			;; else
				Token tmp = produce_next_token(fin, first`)
				first`.end()
				first` = tmp
			;/
		;; else
			_ast_print_err(fin, first, "Expected identifier in fully qualified type chain\0")
			run = false
		;/
	;/

	/; if (first`._type == TTYPE_DELIM && first`.eq("(\0") == true)
		_ast_list_type(fin, mod, first)
	;/
;/

/; _ast_type (~utils.File fin, ~Node mod, ~Token first)

	Node typ
	typ.init(NTYPE_TYPE, utils.strcpy("\0"))

	# Prefix values (~, {}, {#})
	_type_helper_pre(fin, ~typ, first)

	# Check to see if this is a function pointer type
	/; if (first`.eq("void\0") == true)
		Node ktp
		ktp.init(NTYPE_ID, first`.data)
		typ.add_child(~ktp)
		first` = produce_next_token(fin, first`)
		
		_type_helper_func(fin, ~typ, first)
		mod`.add_child(~typ)
		return
	;/

	# user type or keytype
	/; if (first`._type == TTYPE_USRWD)
		_type_helper_usertype(fin, ~typ, first)
	;; else if (first`._type == TTYPE_KEYTP)
		Node ktp
		ktp.init(NTYPE_ID, first`.data)
		typ.add_child(~ktp)
		first` = produce_next_token(fin, first`)
	;; else
		_ast_print_err(fin, first, "Expected keytype or usertype when parsing type\0")
		mod`.add_child(~typ)
		return
	;/

	# The ol' reference
	/; if (first`.eq("`\0"))
		Node post
		post.init(NTYPE_POST_OP, first`.data)
		typ.add_child(~post)
		first` = produce_next_token(fin, first`)
	;/

	mod`.add_child(~typ)
;/



# AST lists

/; _ast_list_value (~utils.File fin, ~Node mod, ~Token first) [int]
	Node list
	list.init(NTYPE_VLIST, first`.data)

	uint8 end = _get_closing_delim(first`.data`)

	first` = produce_next_token(fin, first`)

	/; loop (first`._type !== TTYPE_ERR && first`.data` !== end)
		_ast_value(fin, ~list, first, true)

		/; if (_advance_check(fin, first, ",\0") == false && (first`._type !== TTYPE_DELIM || first`.data` !== end))
			_ast_print_err(fin, first, "Expected ',' to continue the value list or a closing delimiter\0")
			mod`.add_child(~list)
			return first`.line
		;/
	;/

	mod`.add_child(~list)

	int ln = first`.line
	
	Token next = produce_next_token(fin, first`)
	first`.end()
	first` = next
	
	return ln
;/

/; _maybe_helper_decl (~utils.File fin, ~Node mod, ~Token first)
	# either a continuation of prev type or a new type then an id
	Token next = produce_next_token(fin, first`)
	/; if (next._type !== TTYPE_ERR && next.eq(",\0") || _is_closing(~next) == true)
		# Another id
		Node id
		id.init(NTYPE_ID, first`.data)
		mod`.add_child(~id)

		first` = next
		return
	;/

	# have to parse as a type
	Node tp
	tp.init(NTYPE_TYPE, utils.strcpy("\0"))

	Node utmp
	utmp.init(NTYPE_ID, first`.data)

	tp.add_child(~utmp)
	first` = next

	bool run = true
	/; if (first`._type !== TTYPE_AUG || first`.eq(".\0") == false)
		run = false
	;; else
		next = produce_next_token(fin, first`)
		first`.end()
		first` = next
	;/

	# Adapted from _type_helper_usertype
	/; loop (run == true && first`._type !== TTYPE_ERR)
		/; if (first`._type == TTYPE_USRWD)
			Node utp
			utp.init(NTYPE_ID, first`.data)
			first` = produce_next_token(fin, first`)
			tp.add_child(~utp)

			/; if (first`._type !== TTYPE_AUG || first`.eq(".\0") == false)
				run = false
			;; else
				next = produce_next_token(fin, first`)
				first`.end()
				first` = next
			;/
		;; else
			_ast_print_err(fin, first, "Expected identifier in fully qualified type chain\0")
			run = false
		;/
	;/

	/; if (first`._type == TTYPE_DELIM && first`.eq("(\0") == true)
		_ast_list_type(fin, ~tp, first)
	;/

	mod`.add_child(~tp)

	/; if (first`._type !== TTYPE_USRWD)
		_ast_print_err(fin, first, "Expected identifier after user type in type list\0")
		return
	;/

	Node id
	id.init(NTYPE_ID, first`.data)
	mod`.add_child(~id)

	first` = produce_next_token(fin, first`)
;/

/; _ast_list_decl (~utils.File fin, ~Node mod, ~Token first) [int]
	Node list
	list.init(NTYPE_DLIST, first`.data)

	uint8 end = _get_closing_delim(first`.data`)

	first` = produce_next_token(fin, first`)
	bool seen = false

	/; loop (first`._type !== TTYPE_ERR && first`.data` !== end)
		/; if (seen == false || first`._type ==TTYPE_KEYTP || first`.eq("~\0") == true || first`.eq("{\0") == true)
			_ast_type(fin, ~list, first)

			/; if (first`._type !== TTYPE_USRWD)
				/; if (seen == false)
					_ast_print_err(fin, first, "Expected type then identifier as first items in declaration list\0")
				;; else
					_ast_print_err(fin, first, "Expected identifier after type in params/struct def\0")
				;/
				mod`.add_child(~list)
				return first`.line
			;/

			seen = true

			Node id
			id.init(NTYPE_ID, first`.data)

			list.add_child(~id)
			first` = produce_next_token(fin, first`)

		;; else if (first`._type == TTYPE_USRWD)
			_maybe_helper_decl(fin, ~list, first)
		;; else
			_ast_print_err(fin, first, "Expected type or parameter name in declaration list\0")
			mod`.add_child(~list)
			return first`.line
		;/

		/; if (_advance_check(fin, first, ",\0") == false && _is_closing(first) == false)
			_ast_print_err(fin, first, "Expected ',' to continue the declaration list or a closing delimiter\0")
			mod`.add_child(~list)
			return first`.line
		;/
	;/

	mod`.add_child(~list)
	
	int ln = first`.line

	Token next = produce_next_token(fin, first`)
	first`.end()
	first` = next

	return ln
;/

/; _ast_list_enum (~utils.File fin, ~Node mod, ~Token first) [int]
	Node list
	list.init(NTYPE_ELIST, first`.data)

	uint8 end = _get_closing_delim(first`.data`)

	first` = produce_next_token(fin, first`)

	int ln = first`.line

	/; loop (first`._type !== TTYPE_ERR && first`.data` !== end)
		/; if (first`._type == TTYPE_USRWD)
			ln = first`.line

			Node enum_id
			enum_id.init(NTYPE_ID, first`.data)
			
			first` = produce_next_token(fin, first`)

			/; if (_advance_check(fin, first, "=\0"))
				_ast_value(fin, ~enum_id, first, true)
			;/

			list.add_child(~enum_id)
			
		;; else
			_ast_print_err(fin, first, "Expected identifier in body of enum declaration\0")
			mod`.add_child(~list)
			return ln
		;/
		
		/; if (first`.eq(",\0") == true)
			ln = first`.line
		;/

		/; if (_advance_check(fin, first, ",\0") == false && _is_closing(first) == false)
			_ast_print_err(fin, first, "Expected ',' to continue the type list or a closing delimiter\0")
			mod`.add_child(~list)
			return ln
		;/
	;/

	mod`.add_child(~list)

	ln = first`.line
	
	Token next = produce_next_token(fin, first`)
	first`.end()
	first` = next

	return ln
;/

/; _ast_list_type (~utils.File fin, ~Node mod, ~Token first) [int]
	Node list
	list.init(NTYPE_TLIST, first`.data)

	uint8 end = _get_closing_delim(first`.data`)

	first` = produce_next_token(fin, first`)

	int ln = first`.line

	/; loop (first`._type !== TTYPE_ERR && first`.data` !== end)

		/; if (first`._type == TTYPE_USRWD || first`._type == TTYPE_KEYTP || first`.eq("~\0") == true || first`.eq("{\0") == true)
			ln = first`.line
			_ast_type(fin, ~list, first)
		;; else
			_ast_print_err(fin, first, "Expected type in type list\0")
			mod`.add_child(~list)
			return ln
		;/

		/; if (_advance_check(fin, first, ",\0") == false && _is_closing(first) == false)
			_ast_print_err(fin, first, "Expected ',' to continue the type list or a closing delimiter\0")
			mod`.add_child(~list)
			return ln
		;/
	;/

	mod`.add_child(~list)

	ln = first`.line

	Token next = produce_next_token(fin, first`)
	first`.end()
	first` = next

	return ln
;/

/; _ast_list_stmt (~utils.File fin, ~Node mod, ~Token first)
	Node list
	list.init(NTYPE_SLIST, first`.data)

	uint8 end = _get_closing_delim(first`.data`)
	first` = produce_next_token(fin, first`)

	int ln = first`.line

	/; loop (bool run = true; run == true && first`._type !== TTYPE_ERR && first`.data` !== end)
		/; if (_advance_check(fin, first, "asm\0") == true)
			_ast_asm(fin, ~list, first)
		;; else if (first`._type == TTYPE_KEYTP || first`.eq("{\0") == true)
			_ast_decl(fin, ~list, first)
		;; else if (first`._type == TTYPE_USRWD || first`.eq("~\0") == true)
			_maybe_helper_fun(fin, ~list, first, true)
		;; else if (first`._type == TTYPE_LITRL || first`.eq("(\0") == true || _op_prefix(first))
			_ast_value(fin, ~list, first, true)
		;; else if (first`._type == TTYPE_KEYWD)
			_ast_keyword_expr(fin, ~list, first)
		;; else if (first`.eq(";\0") == true)
			Node empty
			empty.init(NTYPE_EMPTY, utils.strcpy("\0"))
			list.add_child(~empty)
		;; else
			_ast_print_err(fin, first, "Expected definition, expression, or ';' in statement list\0")
			run = false
			Token tmp = produce_next_token(fin, first`)
			first`.end()
			first` = tmp
		;/

		/; if (_advance_check(fin, first, ";\0") == false)
			run = false
		;/
	;/

	mod`.add_child(~list)

	ln = first`.line
	
	/; if (first`._type !== TTYPE_DELIM || first`.data` !== end)
		_ast_print_err(fin, first, "Expected closing at end of statement list\0")
	;; else
		Token tmp = produce_next_token(fin, first`)
		first`.end()
		first` = tmp
	;/

	return ln
;/


# Method blocks

/; _block_helper_method(~utils.File fin, ~Node mod, ~Token first)
	Token blf = first`

	first` = produce_next_token(fin, first`)

	/; loop (bool run = true; run == true)
		/; if (first`._type == TTYPE_USRWD)
			_ast_function(fin, mod, first)
		;; else
			_ast_print_err(fin, first, "Expected function or operator overload in method block\0")
		;/

		_ast_block_pass(fin, first)

		/; if (_advance_check(fin, first, ";/\0") == true)
			/; if (first`.data` == ';')
				run = false
			;; else if (_advance_check(fin, first, "/;\0") == false)
				_ast_print_err(fin, first, "Expected opening block in method block\0")
			;/
		;; else if (_advance_check(fin, first, ";;\0") == false)
			_ast_print_err(fin, ~blf, "Could not find closing ;/ for function in method block\0")
			run = false
		;/
	;/

	blf.end()
;/

/; _ast_method (~utils.File fin, ~Node mod, ~Token first)
	Token blf = first`

	/; if (first`._type !== TTYPE_USRWD)
		_ast_print_err(fin, first, "Expected identifier of struct after 'method'\0")
		return
	;/

	Node mth
	mth.init(NTYPE_METHOD, first`.data)
	first` = produce_next_token(fin, first`)

	/; loop (bool run = true; run == true && first`._type == TTYPE_DELIM)
		/; if (first`.eq("/;\0") == true)
			_block_helper_method(fin, ~mth, first)
		;; else
			/; if (first`.data` !== ';')
				_ast_print_err(fin, first, "Method block being skipped. Parsing will resume after the end\0")
			;/
			run = false
		;/
	;/

	_ast_block_pass(fin, first)

	/; if (first`.eq(";/\0") == false)
		_ast_print_err(fin, ~blf, "Could not find closing ;/ for method block\0")
	;/

	mod`.add_child(~mth)
;/



# function blocks

/; _ast_flow (~utils.File fin, ~Node mod, ~Token first)
	int block_type = NTYPE_IF_BLOCK
	/; if (_advance_check(fin, first, "else\0") == true)
		/; if (_advance_check(fin, first, "if\0") == true)
			block_type = NTYPE_ELIF_BLOCK
		;; else
			block_type = NTYPE_ELSE_BLOCK
		;/
	;; else if (_advance_check(fin, first, "loop\0") == true)
		block_type = NTYPE_LOOP_BLOCK
	;; else
		Token tok = produce_next_token(fin, first`)
		first`.end()
		first` = tok
	;/

	Node out
	out.init(block_type, utils.strcpy("\0"))

	/; if (block_type !== NTYPE_ELSE_BLOCK && first`.eq("(\0") == true)
		_ast_list_stmt(fin, ~out, first)
	;/

	/; if (block_type == NTYPE_LOOP_BLOCK && first`.eq("[\0") == true)
		_ast_list_stmt(fin, ~out, first)
	;/

	/; loop (bool run = true; run == true && first`._type !== TTYPE_ERR)
		/; if (first`._type == TTYPE_DELIM && first`.data` == ';')
			run = false
		;; else if (_advance_check(fin, first, "asm\0") == true)
			_ast_asm(fin, ~out, first)
		;; else if (first`.eq("/;\0") == true)
			_ast_fun_block(fin, ~out, first)
		;; else if (first`._type == TTYPE_KEYTP || first`.eq("{\0") == true)
			_ast_decl(fin, ~out, first)
		;; else if (first`._type == TTYPE_USRWD || first`.eq("~\0") == true)
			_maybe_helper_fun(fin, ~out, first, false)
		;; else if (first`._type == TTYPE_LITRL || first`.eq("(\0") == true || _op_prefix(first))
			_ast_value(fin, ~out, first, false)
		;; else if (first`._type == TTYPE_KEYWD)
			_ast_keyword_expr(fin, ~out, first)
		;; else
			_ast_print_err(fin, first, "Expected definition, expression, or sub block in flow block\0")

			Token tmp = produce_next_token(fin, first`)
			first`.end()
			first` = tmp
		;/
	;/

	mod`.add_child(~out)
;/


/; _ast_fun_block (~utils.File fin, ~Node mod, ~Token first)
	Token blf = first`
	first` = produce_next_token(fin, first`)

	/; loop (bool run = true; run == true && first`._type !== TTYPE_ERR)
		/; if (first`.eq("if\0") == true || first`.eq("else\0") == true || first`.eq("loop\0") == true)
			_ast_flow(fin, mod, first)
		# ;; else if (first`._type == TTYPE_USRWD)
		# TODO: Functions in functions
		#	_ast_function(fin, mod, first)
		;; else
			_ast_print_err(fin, first, "Expected 'if', 'else', or 'loop' for function level block\0")
		;/

		run = _advance_check(fin, first, ";;\0")
		/; if (run == false && first`.eq(";/\0") == false)
			_ast_print_err(fin, first, "Block being skipped. Parsing will pick up after the end\0")
		;/
	;/

	_ast_block_pass(fin, first)

	/; if (_advance_check(fin, first`, ";/\0") == false)
		_ast_print_err(fin, ~blf, "Could not find closing ;/ for top block\0")
	;/
	blf.end()
;/

# The following code (mhf_post_list and mhf_post)
# are a convoluted hellscape of terrible
# design choices.  Both functions may recursively call
# the other, and both produce a multitude of different
# output values based on what they think the AST should
# be (sometimes based on the next token, sometimes not).

# For instance, mhf_post tries to return NULL when it
# thinks the next token means we are in a state where we
# can parse a declaration (we have seen a valid type and
# the next token is an identifier) but if we are calling
# this function from mhf_post_list, we are inside a list,
# making this an invalid next token in either the case
# where we are parsing a declaraion OR the case where we
# are parsing a value.  It should blow up, so mhf_post_list
# checks to see if it's null and returns whatever output
# list it has created instead so something higher up the
# chain (mhf_finish_value) can catch it and explode instead.
# It's almost like an exception. Fuck me.

# Otherwise, mhf_post will return whatever node the mhf_finish_value
# should use as the node to start stitching together with binary operators
# and values. Even worse, the node it should return may be a sub-node
# FROM MHF_POST_LIST!!!

# _mhf_post_list, however, should NEVER return NULL.  In the case
# where it suceeded in parsing a list of types, it will return
# the passed in ~Node (which SHOULD be a type node), but otherwise,
# it will return the node it was trying to generate when the failure
# occurred.  That's at least slightly fewer possible options,
# but it is very important to remember that the token it ends on is
# the end of the list, which allows checking whether the line
# number of the next token is the same.  If it's not, this WHOLE THING
# was a FUNCTION CALL, and the ENTIRE FUCKING TREE NEEDS TO BE
# RE-WORKED THROUGH THE TRANSFORM FUNCTION TO REPRESENT THAT.

# Both functions try to compensate by checking the output
# state of the other, and it creates a clusterfuck of strange
# if statements and pointer logic that I wrote in an exremely
# sleep deprived state.  I'm just really hoping this
# works.  It will all probably get refactored later when
# the standard library is fully flushed out and the compiler
# is more mature.  For now, may this warning be a sufficient
# deterrant for the common programmar looking to refactor.

# The only saving grace of this is I guess that it's O(n)
# (Each loop iterates over tokens until it reaches an end state
# and the tokens never back track.  Plus I'm pretty sure the
# transformer is O(n) in terms of the number of nodes in the
# subtree.)

# If you want to skip the most hellish spaghetti code I have ever
# had the displesure of writing, just search for "maybe_helper_fun"
# and have your editor of choice skip to that point.

/; _mhf_post_list (~utils.File fin, ~Node mod, ~Token first) [~Node]
	Node out
	out.init(NTYPE_TLIST, first`.data)
	first` = produce_next_token(fin, first`)
	
	/; loop (bool run = true; run == true && first`._type !== TTYPE_ERR)
		Node _typ
		_typ.init(NTYPE_TYPE, utils.strcpy("\0"))
		_type_helper_pre(fin, ~_typ, first)

		/; if (first`._type == TTYPE_USRWD || first`._type == TTYPE_KEYTP)
			# Try to keep parsing as a type, if we error out we
			# will return whatever post returns
			~Node cur = _mhf_post(fin, ~_typ, first, true)
			/; if (cur == ~_typ && first`.eq(",\0") == true)
				# Keep going
				Token tmp = produce_next_token(fin, first`)
				first`.end()
				first` = tmp
			;; else if (cur == ~_typ && first`.eq(")\0") == true)
				# Stop here, reached end of list
				run = false
			;; else
				# Some error occurred, mhf_transform will
				# preserve lists so we return the list we were
				# creating.
				# mhf_finish_value can find the last valid parse
				# before the error occured by getting the last
				# subnode from the list
				/; if (cur == NULL || cur == ~_typ)
					cur = out.add_child(~_typ)
				;; else
					out.add_child(~_typ)
				;/
				mod`.add_child(~out)
				return cur
			;/
		;; else
			# Oh no! We hit a value!
			out.add_child(~_typ)
			return mod`.add_child(~out)
		;/

		out.add_child(~_typ)
	;/

	mod`.add_child(~out)
	# Properly parsed type list
	return mod
;/

/; _mhf_post (~utils.File fin, ~Node mod, ~Token first, bool lnok) [~Node]
	
	/; if (first`._type == TTYPE_KEYTP)
		Node id
		id.init(NTYPE_ID, first`.data)
		mod`.add_child(~id)
		first` = produce_next_token(fin, first`)

		/; if (id.eq("void\0") == true)
			_type_helper_func(fin, mod, first)
		;; else if (first`.eq("`\0") == true)
			Node post
			post.init(NTYPE_POST_OP, first`.data)
			mod`.add_child(~post)
			first` = produce_next_token(fin, first`)
		;/

		/; if (first`._type == TTYPE_USRWD)
			return NULL
		;/
		return mod
	;/
	
	int ln = first`.line
	/; loop (bool run = true; run == true && first`._type !== TTYPE_ERR)
		/; if (first`._type == TTYPE_USRWD)
			Node id
			id.init(NTYPE_ID, first`.data)
			mod`.add_child(~id)
			first` = produce_next_token(fin, first`)
		;; else
			return mod
		;/

		/; if (first`.line !== ln && lnok == false)
			return mod
		;; else if (first`.eq(".\0") == true)
			Token tmp = produce_next_token(fin, first`)
			first`.end()
			first` = tmp
			ln = first`.line
		;; else if (first`.eq("(\0") == true || first`._type == TTYPE_USRWD)
			run = false
		;; else
			return mod
		;/
	;/

	/; if (first`.eq("(\0") == true)
		~Node weird = _mhf_post_list(fin, mod, first)
		# We get back right at the end paren of the list.
		# If the next token is a USRWD on the same line,
		# we want to return NULL, otherwise return the weird
		# pointer
		int ln = first`.line
		/; if (weird == mod && _advance_check(fin, first, ")\0") == true)
			/; if (first`._type == TTYPE_USRWD && (first`.line == ln || lnok == true))
				return NULL
			;/
		;/
		return weird
	;/

	/; if (first`._type == TTYPE_USRWD)
		return NULL
	;/
	return mod
;/

# Transform type nodes into value nodes
/; _mhf_transform (~Node _type, at) [~Node]
	Node out
	out.init(NTYPE_VALUE, utils.strcpy("\0"))
	
	~Node sub, cur
	cur = ~out
	int idx = 0
	
	/; loop (bool run = true; run == true && idx < _type`.sub.count)
		sub = _type`.sub.get(idx)
		/; if (sub`._type !== NTYPE_PRE_OP)
			run = false
		;; else
			Node new
			new.init(NTYPE_PRE_OP, utils.strcpy(sub`.data))
			cur = cur`.add_child(~new)
			idx++
		;/
	;/

	/; loop (idx < _type`.sub.count && sub`._type == NTYPE_ID)
		/; if (idx < _type`.sub.count - 1)
			sub = _type`.sub.get(idx + 1)
			/; if (sub`._type == NTYPE_ID)
				sub = _type`.sub.get(idx)
				Node op, n
				op.init(NTYPE_BIN_OP, utils.strcpy(".\0"))
				n.init(NTYPE_ID, utils.strcpy(sub`.data))
				/; if (cur`.sub.count == 0)
					op.add_child(~n)
				;; else
					sub = cur`.sub.get(cur`.sub.count - 1)
					sub`.add_child(~n)
					op.add_child(sub)
					cur`.sub.pop()
				;/
				cur`.add_child(~op)
			;; else
				sub = _type`.sub.get(idx)
				Node n
				n.init(NTYPE_ID, utils.strcpy(sub`.data))
				/; if (cur`.sub.count !== 0)
					cur = cur`.sub.get(cur`.sub.count - 1)
				;/
				cur = cur`.add_child(~n)
			;/
		;; else
			Node n
			n.init(NTYPE_ID, utils.strcpy(sub`.data))
			/; if (cur`.sub.count !== 0)
				cur = cur`.sub.get(cur`.sub.count - 1)
			;/
			cur = cur`.add_child(~n)
		;/

		idx++

		/; if (idx < _type`.sub.count)
			sub = _type`.sub.get(idx)
		;/
	;/
	
	~int pt1 = at
	/; if (idx < _type`.sub.count && sub`._type == NTYPE_TLIST && sub`.eq("(\0") == true)
		Node lst
		lst.init(NTYPE_VLIST, utils.strcpy("(\0"))
		
		/; loop (int i = 0; i < sub`.sub.count) [i++]
			~Node lsub = sub`.sub.get(i)
			at = _mhf_transform(lsub, at)
			~int pt2 = lsub
			/; if (at == lsub)
				at = lst.add_child(lsub)
			;; else
				lst.add_child(lsub)
			;/
		;/
		
		/; loop (sub`.sub.count > 0)
			sub`.sub.pop()
		;/

		~int pt2 = sub
		/; if (pt1 == pt2)
			at = cur`.add_child(~lst)
		;; else
			cur`.add_child(~lst)
		;/
	;/

	_type`.end()
	_type` = out
	_type`.update_children()
	return at
;/

/; _mhf_escape (~utils.File fin, ~Node mod, ~Token first, ~Node cur)
	int deep = 0
	~int p1 = cur
	~int p2 = mod
	/; loop (bool run = true; run == true && p1 !== p2 && first`._type !== TTYPE_ERR)
		/; if (first`.eq(")\0") == true)
			/; if (deep > 0)
				deep = deep - 1
			;; else if (cur`.eq("(\0") == true)
				cur = cur`.parent
				p1 = cur
			;; else
				/; loop (cur`.parent !== NULL && cur`.eq("(\0") == false)
					cur = cur`.parent
				;/
				/; if (cur`.parent == NULL)
					return
				;/
				cur = cur`.parent
				p1 = cur
			;/

			/; if (cur`.eq("(\0") == false)
				run = false
			;/
		;; else if (first`.eq("(\0") == true)
			deep = deep + 1
		;/

		Token tmp = produce_next_token(fin, first`)
		first`.end()
		first` = tmp
	;/
;/

/; _mhf_up_to_value (~Node cur) [~Node]
	~int p1 = cur
	/; loop (p1 !== NULL)
		/; if (cur`._type == NTYPE_VALUE)
			return cur
		;/
		cur = cur`.parent
		p1 = cur
	;/
	return NULL
;/

/; _mhf_lower (~Node cur) [~Node]
	/; loop (bool run = true; run == true)
		/; if (cur`.sub.count > 0)
			cur = cur`.sub.get(cur`.sub.count - 1)
		;; else
			return cur
		;/

		/; if (cur`.eq(".\0") || cur`._type == NTYPE_ID)
			return cur
		;/
	;/
	# should never happen
	return NULL
;/

/; _mhf_post_value(~utils.File fin, ~Node cur, ~Token first, bool lnok) [~Node]
	int ln = first`.line
	/; loop (bool run = true; run == true && first`._type !== TTYPE_ERR)
		/; if (ln !== first`.line && lnok == false)
			run = false
		;; else if (_advance_check(fin, first, ".\0") == true)
			/; if (first`._type == TTYPE_USRWD)
				Node op, id

				op.init(NTYPE_BIN_OP, utils.strcpy(".\0"))
				id.init(NTYPE_ID, first`.data)
				ln = first`.line
				
				cur = cur`.parent
				~Node sub = cur`.sub.get(cur`.sub.count - 1)
				
				op.add_child(sub)
				op.add_child(~id)
				
				cur`.sub.pop()
				cur = cur`.add_child(~op)
				
				first` = produce_next_token(fin, first`)
			;; else
				_ast_print_err(fin, first, "Expected identifier after '.'\0")
				return NULL
			;/
		;; else if (_op_postfix(first) == true)
			Node op
			op.init(NTYPE_POST_OP, first`.data)
			/; if (cur`.eq(".\0") == true)
				cur = cur`.sub.get(cur`.sub.count - 1)
				cur`.add_child(~op)
				cur = cur`.parent
			;; else if (cur`._type == NTYPE_ID)
				cur`.add_child(~op)
			;; else
				_ast_print_err(fin, first, "Unsure where we are at in the tree ('`'). [CMPERR]")
				op.end()
				return NULL
			;/
			first` = produce_next_token(fin, first`)
		;; else if (first`.eq("(\0") == true)
			/; if (cur`.eq(".\0") == true)
				cur = cur`.sub.get(cur`.sub.count - 1)
				ln = _ast_list_value(fin, cur, first)
				cur = cur`.parent
			;; else if (cur`._type == NTYPE_ID)
				ln = _ast_list_value(fin, cur, first)
			;; else
				_ast_print_err(fin, first, "Unsure where we are at in the tree ('('). [CMPERR]")
				return NULL
			;/
		;; else if (first`.eq("{\0") == true)
			Node ind
			ind.init(NTYPE_POST_OP, first`.data)
			first` = produce_next_token(fin, first`)
			/; if (_ast_value(fin, ~ind, first, true) == false)
				_ast_print_err(fin, first, "Expected value for index operation after '{'\0")
			;/

			/; if (cur`.eq(".\0") == true)
				cur = cur`.sub.get(cur`.sub.count - 1)
				cur`.add_child(~ind)
				cur = cur`.parent
			;; else if (cur`._type == NTYPE_ID)
				cur`.add_child(~ind)
			;; else
				_ast_print_err(fin, first, "Unsure where we are at in the tree ('{'). [CMPERR]")
				ind.end()
				return NULL
			;/

			ln = first`.line
			/; if (_advance_check(fin, first, "}\0") == false)
				_ast_print_err(fin, first, "Expected '}' to show the end of an index operation after the value\0")
				return NULL
			;/
		;; else
			run = false
		;/
	;/

	return cur
;/

/; _mhf_inner_value(~utils.File fin, ~Node cur, ~Token first, ~int ln) [~Node]
	cur = _mhf_lower(cur)

	#/; if (cur`._type !== NTYPE_ID && cur`.eq(".\0") == false && cur`.sub.count == 0 && first`._type == TTYPE_LITRL)
	#	Node lt
	#	lt.init(NTYPE_LITERAL, first`.data)
	#	first` = produce_next_token(fin, first`)
	#	cur = cur`.add_child(~lt)
	#;/

	cur = _mhf_post_value(fin, cur, first, true)
	/; if (cur == NULL)
		return cur
	;/

	cur = _mhf_up_to_value(cur)

	bool did_binop = false

	/; loop (bool run = true; run == true && first`._type !== TTYPE_ERR)
		/; if (first`.eq(")\0") == true || first`.eq(",\0") == true)
			run = false
		;; else if (first`.eq(".\0") == true)
			_ast_print_err(fin, first, "Unexpected token within function call (1).  Expected binary operator then value, ',', or ')'.\0")
			return NULL
		;; else if (first`._type == TTYPE_AUG && _op_bin(first) == true)
			did_binop = true
			Node bin
			bin.init(NTYPE_BIN_OP, first`.data)
			
			int i = _op_order(first`.data)
			bool gt = false
			/; if (cur`._type == NTYPE_BIN_OP)
				gt = _assoc(cur`.data, i)
			;/

			# Start from the top and work our way down
			/; loop (gt == true)
				cur = cur`.parent

				/; if (cur`._type == NTYPE_BIN_OP)
					gt = _assoc(cur`.data, i)
				;; else
					gt = false
				;/
			;/
			
			~Node lhs = cur`.sub.get(cur`.sub.count - 1)
			bin.add_child(lhs)
			cur`.sub.pop()
			cur = cur`.add_child(~bin)

			first` = produce_next_token(fin, first`)
			/; if (utils.strcmp(bin.data, "is\0"))
				_ast_type(fin, cur, first)
			;; else
				run = _ast_value_bare(fin, cur, first, true)
			;/

		;; else
			_ast_print_err(fin, first, "Unexpected token within function call (2).  Expected binary operator then value, ',', or ')'.\0")
			return NULL
		;/
	;/

	cur = cur`.parent
	/; if (did_binop == true)
		cur = cur`.parent
	;/
	
	ln` = first`.line
	/; if (_advance_check(fin, first, ")\0"))
		/; if (cur`.eq("(\0") == true)
			cur = _mhf_up_to_value(cur)
		;/
	;; else if (_advance_check(fin, first, ",\0") == false)
		_ast_print_err(fin, first, "Expected ')' or ',' to complete function call.\0")
		return NULL
	;/
	return cur
;/

/; _mhf_outer_list(~utils.File fin, ~Node cur, ~Token first, ~int ln) [~Node]
	/; loop (first`._type !== TTYPE_ERR && first`.eq(")\0") == false)
		_ast_value(fin, cur, first, true)

		/; if (_advance_check(fin, first, ",\0") == false && first`.eq(")\0") == false)
			_ast_print_err(fin, first, "Expected ',' to continue the value list or a closing delimiter\0")
			return NULL
		;/
	;/

	ln` = first`.line

	Token next = produce_next_token(fin, first`)
	first`.end()
	first` = next
	
	cur = _mhf_up_to_value(cur)
	return cur
;/

/; _mhf_finish_value (~utils.File fin, ~Node mod, ~Token first, ~Node cur, bool lnok)
	# First, if we are in a sub-list, we need to keep parsing as normal as if we were in _list_value
	~int p1 = cur
	~int p2 = mod
	int ln = first`.line
	bool firstRun = true
	
	# While we are in subtree
	/; loop (bool run = true; run == true && p1 !== p2 && first`._type !== TTYPE_ERR)
		~Node tmp = cur
		# First loop for while we are in value
		/; if (tmp`._type == NTYPE_VALUE)
			tmp = _mhf_inner_value(fin, tmp, first, ~ln)
		;/

		# Second loop for while we are in val-list
		/; if (tmp !== NULL && tmp`._type == NTYPE_VLIST)
			tmp = _mhf_outer_list(fin, tmp, first, ~ln)
		;/

		/; if (tmp !== NULL && tmp`._type !== NTYPE_VALUE && tmp`._type !== NTYPE_VLIST)
			_ast_print_err(fin, first, "[CMPERR] Unsure where we are in the tree\n\0")
			print_ast(tmp)
			return
		;/

		/; if (tmp == NULL)
			# TODO: SOME ERR
			_mhf_escape(fin, mod, first, cur)
			return
		;/
		cur = tmp
		p1 = cur
	;/

	cur = _mhf_lower(cur)
	/; if (ln == first`.line || lnok == true)
		~Node tmp = _mhf_post_value(fin, cur, first, lnok)
		/; if (tmp == NULL)
			_ast_print_err(fin, first, "Escaping\0")
			_mhf_escape(fin, mod, first, cur)
			return
		;/
		cur = tmp
	;/
	cur = _mhf_up_to_value(cur)
	
	# After, we need to work similarly for the top value, however,
	# we need to keep track of line numbers so that we properly stop.
	/; loop (bool run = true; run == true && first`._type !== TTYPE_ERR)
		/; if (first`.line !== ln && lnok == false)
			run = false
		;; else if (first`._type == TTYPE_SEP || _is_closing(first) == true)
			run = false
		;; else if (first`.eq(".\0") == true)
			run = false
		;; else if (first`._type == TTYPE_AUG && _op_bin(first) == true)
			Node bin
			bin.init(NTYPE_BIN_OP, first`.data)
			
			int i = _op_order(first`.data)
			bool gt = false
			/; if (cur`._type == NTYPE_BIN_OP)
				gt = _assoc(cur`.data, i)
			;/

			# Start from the top and work our way down
			/; loop (gt == true)
				cur = cur`.parent

				/; if (cur`._type == NTYPE_BIN_OP)
					gt = _assoc(cur`.data, i)
				;; else
					gt = false
				;/
			;/
			
			~Node lhs = cur`.sub.get(cur`.sub.count - 1)
			bin.add_child(lhs)
			cur`.sub.pop()
			cur = cur`.add_child(~bin)

			first` = produce_next_token(fin, first`)
			/; if (utils.strcmp(bin.data, "is\0"))
				_ast_type(fin, cur, first)
			;; else
				run = _ast_value_bare(fin, cur, first, lnok)
			;/

		;; else
			run = false
		;/
	;/
;/

/; _mhf_finish_decl (~utils.File fin, ~Node mod, ~Token first, bool lnok)
	Node out
	out.init(NTYPE_DECL, utils.strcpy("\0"))
	out.add_child(mod)

	/; loop (bool run = true; run == true)
		/; if (first`._type == TTYPE_USRWD)
			Node var
			var.init(NTYPE_ID, first`.data)
			int ln = first`.line

			first` = produce_next_token(fin, first`)
			/; if (first`.eq("=\0") && (first`.line == ln || lnok == true))
				Token tmp = produce_next_token(fin, first`)
				first`.end()
				first` = tmp
				_ast_value(fin, ~var, first, false)
			;; else if (first`.line !== ln && lnok == false)
				run = false
			;/

			out.add_child(~var)

			/; if (first`.eq(",\0") == false)
				run = false
			;; else if (run == true)
				Token tmp = produce_next_token(fin, first`)
				first`.end()
				first` = tmp
			;/
		;; else
			_ast_print_err(fin, first, "Expected variable name in declaration\0")
			run = false
		;/
	;/
	
	mod` = out
;/

/; _maybe_helper_fun (~utils.File fin, ~Node mod, ~Token first, bool lnok)
	# Try parsing as a type first, and if we encounter something weird we will transform
	# the output into a value before proceeding
	Node out
	out.init(NTYPE_TYPE, utils.strcpy("\0"))

	_type_helper_pre(fin, ~out, first)

	/; if (first`.eq("(\0"))
		~Node cur = _mhf_transform(~out, ~out)
		_mhf_finish_value(fin, ~out, first, cur, lnok)

	;; else if (first`._type !== TTYPE_USRWD && first`._type !== TTYPE_KEYTP)
		_ast_print_err(fin, first, "Unexpected token. Expected the completion of a declaration or value (identifier or '(')\0")

	;; else
		# Post is a bit of a weird function.  It returns a pointer the node where
		# _mhf_finish_value should begin merging in values, or zero in the case
		# that this looks like a proper declaration
		~Node cur = _mhf_post(fin, ~out, first, lnok)
		/; if (cur == NULL)
			_mhf_finish_decl(fin, ~out, first, lnok)

		;; else
			cur = _mhf_transform(~out, cur)
			_mhf_finish_value(fin, ~out, first, cur, lnok)
		;/
	;/
	
	mod`.add_child(~out)
;/

/; _ast_function (~utils.File fin, ~Node mod, ~Token first)
	/; if (first`._type !== TTYPE_USRWD)
		_ast_print_err(fin, first, "[FATAL] [CMPERR] Expected function name\0")
		return
	;/

	Node fn
	fn.init(NTYPE_FUNCTION, first`.data)
	first` = produce_next_token(fin, first`)

	/; if (first`.eq("(\0") == true)
		_ast_list_decl(fin, ~fn, first)
	;/

	/; if (first`.eq("[\0") == true)
		_ast_list_type(fin, ~fn, first)
	;/
	
	/; loop (bool run = true; run == true && first`._type !== TTYPE_ERR)
		/; if (_advance_check(fin, first, "asm\0") == true)
			_ast_asm(fin, ~fn, first)
		;; else if (first`.eq("/;\0") == true)
			_ast_fun_block(fin, ~fn, first)
		;; else if (first`._type == TTYPE_KEYTP || first`.eq("{\0") == true)
			_ast_decl(fin, ~fn, first)
		;; else if (first`._type == TTYPE_USRWD || first`.eq("~\0") == true)
			_maybe_helper_fun(fin, ~fn, first, false)
		;; else if (first`._type == TTYPE_LITRL || first`.eq("(\0") == true || _op_prefix(first))
			_ast_value(fin, ~fn, first, false)
		;; else if (first`._type == TTYPE_KEYWD)
			_ast_keyword_expr(fin, ~fn, first)
		;; else if (first`._type == TTYPE_DELIM && first`.data` == ';')
			run = false
		;; else
			_ast_print_err(fin, first, "Expected definition, expression, or sub block in function\0")

			Token tmp = produce_next_token(fin, first`)
			first`.end()
			first` = tmp
		;/
	;/

	mod`.add_child(~fn)
;/



# Top level directives

/; _ast_import (~utils.File fin, ~Node mod, ~Token first)

	/; if (first`._type !== TTYPE_LITRL || first`.data` !== '"')
		_ast_print_err(fin, first, "Expected string or import literal after 'import'\0")

		Token tmp = produce_next_token(fin, first`)
		first`.end()
		first` = tmp
		
		return
	;/

	~uint8 rel = utils.unquote_str(first`.data)
	utils.File imp = fin`.relative(rel)
	_delete(rel)

	rel = imp.path.to_cstr('/')
	_printf("Importing \0")
	_printf(rel)
	_printf("\n\0")
	_delete(rel)

	_ast_file(~imp, mod)
	imp.end()

	Token tmp = produce_next_token(fin, first`)
	first`.end()
	first` = tmp
;/

/; _ast_asm (~utils.File fin, ~Node mod, ~Token first)

	/; if (first`._type !== TTYPE_LITRL || first`.data` !== '"')
		_ast_print_err(fin, first, "Expected string literal after 'ast'\0")

		Token tmp = produce_next_token(fin, first`)
		first`.end()
		first` = tmp
		
		return
	;/
	
	Node an
	an.init(NTYPE_ASM, utils.unquote_str(first`.data))
	mod`.add_child(~an)

	Token tmp = produce_next_token(fin, first`)
	first`.end()
	first` = tmp
;/

/; _ast_struct (~utils.File fin, ~Node mod, ~Token first)
	
	# Identifier check
	/; if (first`._type !== TTYPE_USRWD)
		_ast_print_err(fin, first, "Expected new identifier for typedef after 'struct'\0")

		Token tmp = produce_next_token(fin, first`)
		first`.end()
		first` = tmp
		
		return
	;/

	# Root struct node
	Node sct
	sct.init(NTYPE_STRUCT, first`.data)
	first` = produce_next_token(fin, first`)

	# Check for def list
	/; if (first`._type !== TTYPE_DELIM || first`.data` !== '{')
		_ast_print_err(fin, first, "Expected new identifier for typedef after 'struct'\0")
		mod`.add_child(~sct)

		Token tmp = produce_next_token(fin, first`)
		first`.end()
		first` = tmp
		
		return
	;/

	# Parse deflist and push root node into module
	_ast_list_decl(fin, ~sct, first)
	mod`.add_child(~sct)
;/

/; _ast_enum (~utils.File fin, ~Node mod, ~Token first)
	# Identifier check
	/; if (first`._type !== TTYPE_USRWD)
		_ast_print_err(fin, first, "Expected new identifier for def after 'enum'\0")

		Token tmp = produce_next_token(fin, first`)
		first`.end()
		first` = tmp
		
		return
	;/

	# Root struct node
	Node sct
	sct.init(NTYPE_ENUM, first`.data)
	first` = produce_next_token(fin, first`)

	# Check for enum type
	/; if (first`.data` == '[')
		_ast_list_type(fin, ~sct, first)
	;/

	# Check for def list
	/; if (first`._type !== TTYPE_DELIM || first`.data` !== '{')
		_ast_print_err(fin, first, "Expected '{' after enum definition\0")
		mod`.add_child(~sct)
		return
	;/

	# Parse deflist and push root node into module
	_ast_list_enum(fin, ~sct, first)
	mod`.add_child(~sct)
;/

/; _ast_decl (~utils.File fin, ~Node mod, ~Token first)
	Node decl
	decl.init(NTYPE_DECL, utils.strcpy("\0"))
	
	_ast_type(fin, ~decl, first)

	/; loop (bool run = true; run == true)
		/; if (first`._type == TTYPE_USRWD)
			Node var
			var.init(NTYPE_ID, first`.data)

			first` = produce_next_token(fin, first`)
			/; if (first`.eq("=\0"))
				Token tmp = produce_next_token(fin, first`)
				first`.end()
				first` = tmp
				_ast_value(fin, ~var, first, false)
			;/

			decl.add_child(~var)

			/; if (first`.eq(",\0") == false)
				run = false
			;; else
				Token tmp = produce_next_token(fin, first`)
				first`.end()
				first` = tmp
			;/
		;; else
			_ast_print_err(fin, first, "Expected variable name in declaration\0")
			run = false
		;/
	;/

	mod`.add_child(~decl)
;/

/; _ast_top_block(~utils.File fin, ~Node mod, ~Token first)

	Token blf = first`
	first` = produce_next_token(fin, first`)

	/; loop (bool run = true; run == true && first`._type !== TTYPE_ERR)
		/; if (first`.eq("module\0") == true || first`.eq("export\0") == true)
			_ast_module(fin, mod, first)
		;; else if (_advance_check(fin, first, "method\0") == true)
			_ast_method(fin, mod, first)
		;; else if (first`._type == TTYPE_USRWD)
			_ast_function(fin, mod, first)
		;; else
			_ast_print_err(fin, first, "Expected module, method, or function for top level block\0")
		;/

		run = _advance_check(fin, first, ";;\0")
		/; if (run == false && first`.eq(";/\0") == false && first`.eq(";;\0") == false)
			_ast_print_err(fin, first, "Block being skipped. Parsing will pick up after the end\0")
		;/
	;/

	_ast_block_pass(fin, first)

	/; if (first`.eq(";/\0") == false && first`.eq(";;\0") == false)
		_ast_print_err(fin, ~blf, "Could not find closing ;/ for top block\0")
	;; else
		Token tmp = produce_next_token(fin, first`)
		first`.end()
		first` = tmp
	;/
	blf.end()
;/

/; _ast_module(~utils.File fin, ~Node mod, ~Token first)
	uint16 nt = NTYPE_MODULE

	/; if (_advance_check(fin, first, "export\0") == true)
		/; if (_advance_check(fin, first, "module\0") == false)
			_ast_print_err(fin, first, "Expected 'module' keyword after 'export'\0")
			return
		;/
		nt = NTYPE_EXPORT
	;; else if (_advance_check(fin, first, "module\0") == false)
		_printf("[FATAL] The following issue is with the compiler, not your program.\n\0")
		_printf("[FATAL] Please report the following issue to tnslc upstream.\n\0")
		_ast_print_err(fin, first, "[FATAL] [CMPERR] Should only call _ast_module when 'module' or 'export' are seen\0")
	;/

	/; if (first`._type !== TTYPE_USRWD)
		_ast_print_err(fin, first, "Expected module name (identifier) after 'module'\0")
	;/

	Node nmod
	nmod.init(nt, first`.data)
	first` = produce_next_token(fin, first`)

	/; loop (bool run = true; run == true && first`._type !== TTYPE_ERR)
		/; if (_advance_check(fin, first, "import\0") == true)
			_ast_import(fin, ~nmod, first)
		;; else if (_advance_check(fin, first, "struct\0") == true)
			_ast_struct(fin, ~nmod, first)
		;; else if (_advance_check(fin, first, "enum\0") == true)
			_ast_enum(fin, ~nmod, first)
		;; else if (_advance_check(fin, first, "asm\0") == true)
			_ast_asm(fin, ~nmod, first)
		;; else if (first`.eq("/;\0") == true)
			_ast_top_block(fin, ~nmod, first)
		;; else if (first`._type == TTYPE_KEYTP || first`._type == TTYPE_USRWD || first`.eq("~\0") == true || first`.eq("{\0") == true)
			_ast_decl(fin, ~nmod, first)
		;; else if (first`._type == TTYPE_DELIM && first`.data` == ';')
			run = false
		;; else
			_ast_print_err(fin, first, "Expected 'import', 'struct', 'asm', block, or declaration in top level\0")

			Token tmp = produce_next_token(fin, first`)
			first`.end()
			first` = tmp
		;/
	;/

	mod`.add_child(~nmod)
;/

/; _ast_file (~utils.File fin, ~Node mod)
	fin`.open()
	
	Token first = produce_first_token(fin)
	/; loop (first._type !== TTYPE_ERR)
		/; if (_advance_check(fin, ~first, "import\0") == true)
			_ast_import(fin, mod, ~first)
		;; else if (_advance_check(fin, ~first, "struct\0") == true)
			_ast_struct(fin, mod, ~first)
		;; else if (_advance_check(fin, ~first, "enum\0") == true)
			_ast_enum(fin, mod, ~first)
		;; else if (_advance_check(fin, ~first, "asm\0") == true)
			_ast_asm(fin, mod, ~first)
		;; else if (first.eq("/;\0") == true)
			_ast_top_block(fin, mod, ~first)
		;; else if (first._type == TTYPE_KEYTP || first._type == TTYPE_USRWD || first.eq("~\0") == true || first.eq("{\0") == true)
			_ast_decl(fin, mod, ~first)
		;; else
			_ast_print_err(fin, ~first, "Expected 'import', 'struct', 'asm', block, or declaration in top level\0")

			Token tmp = produce_next_token(fin, first)
			first.end()
			first = tmp
		;/
	;/

	first.end()

	fin`.close()
;/

/; generate_ast (~utils.File fin) [Node]
	Node out

	utils.Vector v
	v.init(1)

	out.init(NTYPE_MODULE, v.as_cstr())

	_ast_file(fin, ~out)

	return out
;/

#
# Print out the AST from a specific node
#

/; print_node_type (~Node n)
	/; if (n`._type == NTYPE_MODULE)
		_printf("MODULE\0")
	;; else if (n`._type == NTYPE_EXPORT)
		_printf("EXPORT\0")
	;; else if (n`._type == NTYPE_STRUCT)
		_printf("STRUCT\0")
	;; else if (n`._type == NTYPE_TYPE)
		_printf("TYPE\0")
	;; else if (n`._type == NTYPE_ID)
		_printf("ID\0")
	;; else if (n`._type == NTYPE_BIN_OP)
		_printf("BIN_OP\0")
	;; else if (n`._type == NTYPE_PRE_OP)
		_printf("PRE_OP\0")
	;; else if (n`._type == NTYPE_POST_OP)
		_printf("POST_OP\0")
	;; else if (n`._type == NTYPE_FUNCTION)
		_printf("FUNCTION\0")
	;; else if (n`._type == NTYPE_METHOD)
		_printf("METHOD\0")
	;; else if (n`._type == NTYPE_TLIST)
		_printf("TLIST\0")
	;; else if (n`._type == NTYPE_DLIST)
		_printf("DLIST\0")
	;; else if (n`._type == NTYPE_ELIST)
		_printf("ELIST\0")
	;; else if (n`._type == NTYPE_SLIST)
		_printf("SLIST\0")
	;; else if (n`._type == NTYPE_LITERAL)
		_printf("LITERAL\0")
#	;; else if (n`._type == NTYPE_KEY_TYPE)
#		_printf("KEY_TYPE\0")
	;; else if (n`._type == NTYPE_ENUM)
		_printf("ENUM\0")
	;; else if (n`._type == NTYPE_DECL)
		_printf("DECL\0")
	;; else if (n`._type == NTYPE_VLIST)
		_printf("VLIST\0")
	;; else if (n`._type == NTYPE_VALUE)
		_printf("VALUE\0")
	;; else if (n`._type == NTYPE_CAST)
		_printf("CAST\0")
	;; else if (n`._type == NTYPE_FLOW_CONTROL)
		_printf("FLOW_CONTROL\0")
	;; else if (n`._type == NTYPE_IF_BLOCK)
		_printf("IF_BLOCK\0")
	;; else if (n`._type == NTYPE_ELIF_BLOCK)
		_printf("ELIF_BLOCK\0")
	;; else if (n`._type == NTYPE_ELSE_BLOCK)
		_printf("ELSE_BLOCK\0")
	;; else if (n`._type == NTYPE_LOOP_BLOCK)
		_printf("LOOP_BLOCK\0")
	;; else if (n`._type == NTYPE_ASM)
		_printf("ASM\0")
	;; else if (n`._type == NTYPE_EMPTY)
		_printf("EMPTY\0")
	;/
;/

/; print_node_head (~Node n)
	_printf("{ NODE_TYPE: \0")
	print_node_type(n)
	_printf(", DATA: \0")
	_printf(n`.data)
	_printf("\n\0")
;/

/; print_ast_rec(~Node n, uint depth)
	/; loop (int i = 0; i < depth) [i++]
		_printf("  \0")
	;/
	print_node_head(n)

	/; loop (uint i = 0; i < n`.sub.count) [i++]
		~Node s = n`.sub.get(i)
		print_ast_rec(s, depth + 1)
	;/
	
	/; loop (int i = 0; i < depth) [i++]
		_printf("  \0")
	;/
	_printf("}\n\0")
;/

/; print_ast (~Node n)
	print_ast_rec(n, 0)
	/; if (verify_ast_integrity(n) == false)
		_printf("Integrity test failed\n\0")
	;; else
		_printf("Integrity test passed\n\0")
	;/
;/

/; verify_ast_integrity (~Node n) [bool]
	/; loop (int i = 0; i < n`.sub.count) [i++]
		~Node s = n`.sub.get(i)
		
		/; if (s`.parent !== n)
			_printf("Test failed at: \n\0")
			print_node_head(s)
			_printf("}\n\0")
			_printf("Parent: \n\0")
			print_node_head(n)
			_printf("}\n\0")
			~int p = n
			int ptr = p
			_print_num("Expected: %p\n\0", ptr)
			~int p = s`.parent
			ptr = p
			_print_num("Got: %p\n\0", ptr)
			return false
		;/

		/; if (verify_ast_integrity(s) == false)
			return false
		;/
	;/

	return true
;/