func (self *jsbeautifier) beautify(s *string) (string, error) {

	if !utils.InStrArray(self.options["brace_style"].(string), []string{"expand", "collapse", "end-expand", "none"}) {
		return "", errors.New("opts.brace-style must be \"expand\", \"collapse\", \"end-exapnd\", or \"none\".")
	}

	s = self.blank_state(s)

	input := self.unpack(s, self.options["eval_code"].(bool))
	t := tokenizer.New(input, self.options, "    ")
	self.tkch = t.Tokenize()
	self.token_pos = 0

	for token := range self.tkch {
		self.parse_token(token)

		for !self.token_queue.Empty() {
			qtoken := self.token_queue.Shift()
			self.parse_token(*qtoken)
		}
	}

	sweet_code := self.output.get_code()
	if self.options["end_with_newline"].(bool) {
		sweet_code += "\n"
	}

	return sweet_code, nil
}
func (self *jsbeautifier) handle_start_block(current_token *tokenizer.Token) {
	next_token, nmore := self.get_token()
	second_token, smore := self.get_token()
	if smore && ((second_token.Text() == ":" && utils.InStrArray(next_token.Type(), []string{"TK_STRING", "TK_WORD", "TK_RESERVED"})) || (utils.InStrArray(next_token.Text(), []string{"get", "set"}) && utils.InStrArray(second_token.Type(), []string{"TK_WORD", "TK_RESE$RVED"}))) {
		if !utils.InStrArray(self.last_last_text, []string{"class", "interface"}) {
			self.set_mode(ObjectLiteral)
		} else {
			self.set_mode(BlockStatement)
		}
	} else {
		self.set_mode(BlockStatement)
	}

	empty_braces := (nmore) && len(next_token.CommentsBefore()) == 0 && next_token.Text() == "}"
	empty_anonymous_function := empty_braces && self.flags.last_word == "function" && self.last_type == "TK_END_EXPR"

	if self.options["brace_style"].(string) == "expand" || (self.options["brace_style"].(string) == "none" && current_token.WantedNewLine()) {
		if self.last_type != "TK_OPERATOR" && (empty_anonymous_function || self.last_type == "TK_EQUALS" || (self.last_type == "TK_RESERVED" && self.is_special_word(self.flags.last_text) && self.flags.last_text != "else")) {
			self.output.space_before_token = true
		} else {
			self.print_newline(false, true)
		}
	} else {
		if !utils.InStrArray(self.last_type, []string{"TK_OPERATOR", "TK_START_EXPR"}) {
			if self.last_type == "TK_START_BLOCK" {
				self.print_newline(false, false)
			} else {
				self.output.space_before_token = true
			}
		} else {
			if self.is_array(self.previous_flags.mode) && self.flags.last_text == "," {
				if self.last_last_text == "}" {
					self.output.space_before_token = true
				} else {
					self.print_newline(false, false)
				}
			}
		}
	}

	self.print_token(*current_token, "")
	self.indent()
}
func (self *jsbeautifier) start_of_statement(current_token tokenizer.Token) bool {

	if (self.last_type == "TK_RESERVED" && utils.InStrArray(self.flags.last_text, []string{"var", "let", "const"}) && current_token.Type() == "TK_WORD") || (self.last_type == "TK_RESERVED" && self.flags.last_text == "do") || (self.last_type == "TK_RESERVED" && self.flags.last_text == "return" && !current_token.WantedNewLine()) || (self.last_type == "TK_RESERVED" && self.flags.last_text == "else" && !(current_token.Type() == "TK_RESERVED" && current_token.Text() == "if")) || (self.last_type == "TK_END_EXPR" && (self.previous_flags.mode == ForInitializer || self.previous_flags.mode == Conditional)) || (self.last_type == "TK_WORD" && self.flags.mode == BlockStatement && !self.flags.in_case && !(current_token.Text() == "--" || current_token.Text() == "++") && current_token.Type() != "TK_WORD" && current_token.Type() != "TK_RESERVED") || (self.flags.mode == ObjectLiteral && ((self.flags.last_text == ":" && self.flags.ternary_depth == 0) || (self.last_type == "TK_RESERVED" && utils.InStrArray(self.flags.last_text, []string{"get", "set"})))) {

		self.set_mode(Statement)
		self.indent()
		if self.last_type == "TK_RESERVED" && utils.InStrArray(self.flags.last_text, []string{"var", "let", "const"}) && current_token.Type() == "TK_WORD" {
			self.flags.declaration_statement = true
		}

		if !self.start_of_object_property() {
			self.allow_wrap_or_preserved_newline(current_token, (current_token.Type() == "TK_RESERVED" && utils.InStrArray(current_token.Text(), []string{"do", "for", "if", "while"})))
		}

		return true
	} else {
		return false
	}
}
func (self *jsbeautifier) handle_string(current_token *tokenizer.Token) {
	if self.start_of_statement(*current_token) {
		self.output.space_before_token = true
	} else if self.last_type == "TK_RESERVED" || self.last_type == "TK_WORD" {
		self.output.space_before_token = true
	} else if utils.InStrArray(self.last_type, []string{"TK_COMMA", "TK_START_EXPR", "TK_EQUALS", "TK_OPERATOR"}) {
		if !self.start_of_object_property() {
			self.allow_wrap_or_preserved_newline(*current_token, false)
		}
	} else {
		self.print_newline(false, false)
	}

	self.print_token(*current_token, "")
}
func (self *jsbeautifier) handle_operator(current_token *tokenizer.Token) {
	if self.start_of_statement(*current_token) {

	}

	if self.last_type == "TK_RESERVED" && self.is_special_word(self.flags.last_text) {
		self.output.space_before_token = true
		self.print_token(*current_token, "")
		return
	}

	if current_token.Text() == "*" && self.last_type == "TK_DOT" {
		self.print_token(*current_token, "")
		return
	}

	if current_token.Text() == ":" && self.flags.in_case {
		self.flags.case_body = true
		self.indent()
		self.print_token(*current_token, "")
		self.print_newline(false, false)
		self.flags.in_case = false
		return
	}

	if current_token.Text() == "::" {
		self.print_token(*current_token, "")
		return
	}

	if current_token.WantedNewLine() && (current_token.Text() == "--" || current_token.Text() == "++") {
		self.print_newline(false, true)
	}

	if self.last_type == "TK_OPERATOR" {
		self.allow_wrap_or_preserved_newline(*current_token, false)
	}

	space_before := true
	space_after := true

	if utils.InStrArray(current_token.Text(), []string{"--", "++", "!", "~"}) || ((current_token.Text() == "+" || current_token.Text() == "-") && (utils.InStrArray(self.last_type, []string{"TK_START_BLOCK", "TK_START_EXPR", "TK_EQUALS", "TK_OPERATOR"}) || utils.InStrArray(self.flags.last_text, tokenizer.GetLineStarters()) || self.flags.last_text == ",")) {
		space_after = false
		space_before = false

		if self.flags.last_text == ";" && self.is_expression(self.flags.mode) {
			space_before = true
		}

		if self.last_type == "TK_RESERVED" || self.last_type == "TK_END_EXPR" {
			space_before = true
		} else if self.last_type == "TK_OPERATOR" {
			space_before = (utils.InStrArray(current_token.Text(), []string{"--", "-"}) && utils.InStrArray(self.flags.last_text, []string{"--", "-"})) || (utils.InStrArray(current_token.Text(), []string{"++", "+"}) && utils.InStrArray(self.flags.last_text, []string{"++", "+"}))
		}

		if self.flags.mode == BlockStatement && (self.flags.last_text == "{" || self.flags.last_text == ";") {
			self.print_newline(false, false)
		}
	} else if current_token.Text() == ":" {
		if self.flags.ternary_depth == 0 {
			space_before = false
		} else {
			self.flags.ternary_depth -= 1
		}
	} else if current_token.Text() == "?" {
		self.flags.ternary_depth += 1
	} else if current_token.Text() == "*" && self.last_type == "TK_RESERVED" && self.flags.last_text == "function" {
		space_before = false
		space_after = false
	}

	if space_before {
		self.output.space_before_token = true
	}

	self.print_token(*current_token, "")

	if space_after {
		self.output.space_before_token = true
	}
}
func (self *jsbeautifier) handle_word(current_token *tokenizer.Token) {

	if current_token.Type() == "TK_RESERVED" && self.flags.mode != ObjectLiteral && (current_token.Text() == "set" || current_token.Text() == "get") {
		current_token.SetType("TK_WORD")
	}

	if current_token.Type() == "TK_RESERVED" && self.flags.mode == ObjectLiteral {
		next_token, _ := self.get_token()
		if next_token.Text() == ":" {
			current_token.SetType("TK_WORD")
		}
	}

	if self.start_of_statement(*current_token) {
	} else if current_token.WantedNewLine() && !self.is_expression(self.flags.mode) && (self.last_type != "TK_OPERATOR" || (self.flags.last_text == "--" || self.flags.last_text == "++")) && self.last_type != "TK_EQUALS" && (self.options["preserve_newlines"].(bool) || !(self.last_type == "TK_RESERVED" && utils.InStrArray(self.flags.last_text, []string{"var", "let", "const", "set", "get"}))) {
		self.print_newline(false, false)
	}

	if self.flags.do_block && !self.flags.do_while {
		if current_token.Type() == "TK_RESERVED" && current_token.Text() == "while" {
			self.output.space_before_token = true
			self.print_token(*current_token, "")
			self.output.space_before_token = true
			self.flags.do_while = true
			return
		} else {
			self.print_newline(false, false)
			self.flags.do_block = false
		}
	}

	if self.flags.if_block {
		if (!self.flags.else_block) && (current_token.Type() == "TK_RESERVED" && current_token.Text() == "else") {
			self.flags.else_block = true
		} else {
			for self.flags.mode == Statement {
				self.restore_mode()
			}
			self.flags.if_block = false
		}
	}

	if current_token.Type() == "TK_RESERVED" && (current_token.Text() == "case" || (current_token.Text() == "default" && self.flags.in_case_statement)) {
		self.print_newline(false, false)

		if self.flags.case_body || self.options["jslint_happy"].(bool) {
			self.flags.case_body = false
			self.deindent()
		}

		self.print_token(*current_token, "")
		self.flags.in_case = true
		self.flags.in_case_statement = true
		return
	}

	if current_token.Type() == "TK_RESERVED" && current_token.Text() == "function" {

		if (self.flags.last_text == "}" || self.flags.last_text == ";") || (self.output.just_added_newline() && !utils.InStrArray(self.flags.last_text, []string{"[", "{", ":", "=", ","})) {
			if !self.output.just_added_blankline() && len(current_token.CommentsBefore()) == 0 {
				self.print_newline(false, false)
				self.print_newline(true, false)
			}
		}

		if self.last_type == "TK_RESERVED" || self.last_type == "TK_WORD" {
			if self.last_type == "TK_RESERVED" && utils.InStrArray(self.flags.last_text, []string{"get", "set", "new", "return", "export"}) {
				self.output.space_before_token = true
			} else if self.last_type == "TK_RESERVED" && self.flags.last_text == "default" && self.last_last_text == "export" {
				self.output.space_before_token = true
			} else {
				self.print_newline(false, false)
			}
		} else if self.last_type == "TK_OPERATOR" || self.flags.last_text == "=" {
			self.output.space_before_token = true
		} else if !self.flags.multiline_frame && (self.is_expression(self.flags.mode) || self.is_array(self.flags.mode)) {

		} else {
			self.print_newline(false, false)
		}
	}

	if utils.InStrArray(self.last_type, []string{"TK_COMMA", "TK_START_EXPR", "TK_EQUALS", "TK_OPERATOR"}) {

		if !self.start_of_object_property() {
			self.allow_wrap_or_preserved_newline(*current_token, false)
		}
	}

	if current_token.Type() == "TK_RESERVED" && utils.InStrArray(current_token.Text(), []string{"function", "get", "set"}) {
		self.print_token(*current_token, "")
		self.flags.last_word = current_token.Text()
		return
	}

	prefix := "NONE"
	if self.last_type == "TK_END_BLOCK" {
		if !(current_token.Type() == "TK_RESERVED" && utils.InStrArray(current_token.Text(), []string{"else", "catch", "finally"})) {
			prefix = "NEWLINE"
		} else {
			if utils.InStrArray(self.options["brace_style"].(string), []string{"expand", "end-expand"}) || (self.options["brace_style"].(string) == "none" && current_token.WantedNewLine()) {
				prefix = "NEWLINE"
			} else {
				prefix = "SPACE"
				self.output.space_before_token = true
			}
		}
	} else if self.last_type == "TK_SEMICOLON" && self.flags.mode == BlockStatement {
		prefix = "NEWLINE"
	} else if self.last_type == "TK_SEMICOLON" && self.is_expression(self.flags.mode) {
		prefix = "SPACE"
	} else if self.last_type == "TK_STRING" {
		prefix = "NEWLINE"
	} else if self.last_type == "TK_RESERVED" || self.last_type == "TK_WORD" || (self.flags.last_text == "*" && self.last_last_text == "function") {
		prefix = "SPACE"
	} else if self.last_type == "TK_START_BLOCK" {
		prefix = "NEWLINE"
	} else if self.last_type == "TK_END_EXPR" {
		self.output.space_before_token = true
		prefix = "NEWLINE"
	}

	if current_token.Type() == "TK_RESERVED" && utils.InStrArray(current_token.Text(), tokenizer.GetLineStarters()) && self.flags.last_text != ")" {

		if self.flags.last_text == "else" || self.flags.last_text == "export" {
			prefix = "SPACE"
		} else {
			prefix = "NEWLINE"
		}
	}

	if current_token.Type() == "TK_RESERVED" && utils.InStrArray(current_token.Text(), []string{"else", "catch", "finally"}) {
		if self.last_type != "TK_END_BLOCK" || self.options["brace_style"].(string) == "expand" || self.options["brace_style"].(string) == "end-expand" || (self.options["brace_style"].(string) == "none" && current_token.WantedNewLine()) {
			self.print_newline(false, false)
		} else {
			self.output.trim(true)

			if self.output.current_line.last() != "}" {
				self.print_newline(false, false)
			}

			self.output.space_before_token = true
		}
	} else if prefix == "NEWLINE" {
		if self.last_type == "TK_RESERVED" && self.is_special_word(self.flags.last_text) {
			self.output.space_before_token = true
		} else if self.last_type != "TK_END_EXPR" {
			if (self.last_type != "TK_START_EXPR" || !(current_token.Type() == "TK_RESERVED" && utils.InStrArray(current_token.Text(), []string{"var", "let", "const"}))) && self.flags.last_text != ":" {
				if current_token.Type() == "TK_RESERVED" && current_token.Text() == "if" && self.flags.last_text == "else" {
					self.output.space_before_token = true
				} else {
					self.print_newline(false, false)
				}
			}
		} else if current_token.Type() == "TK_RESERVED" && utils.InStrArray(current_token.Text(), tokenizer.GetLineStarters()) && self.flags.last_text != ")" {
			self.print_newline(false, false)
		}
	} else if self.flags.multiline_frame && self.is_array(self.flags.mode) && self.flags.last_text == "," && self.last_last_text == "}" {
		self.print_newline(false, false)
	} else if prefix == "SPACE" {
		self.output.space_before_token = true
	}

	self.print_token(*current_token, "")
	self.flags.last_word = current_token.Text()

	if current_token.Type() == "TK_RESERVED" && current_token.Text() == "do" {
		self.flags.do_block = true
	}

	if current_token.Type() == "TK_RESERVED" && current_token.Text() == "if" {
		self.flags.if_block = true
	}

}
func (self *jsbeautifier) handle_start_expr(current_token *tokenizer.Token) {
	if self.start_of_statement(*current_token) {

	}
	next_mode := Expression
	if current_token.Text() == "[" {
		if self.last_type == "TK_WORD" || self.flags.last_text == ")" {
			if self.last_type == "TK_RESERVED" && utils.InStrArray(self.flags.last_text, tokenizer.GetLineStarters()) {
				self.output.space_before_token = true
			}
			self.set_mode(next_mode)
			self.print_token(*current_token, "")
			self.indent()
			if self.options["space_in_paren"].(bool) {
				self.output.space_before_token = true
			}
			return
		}

		next_mode = ArrayLiteral
		if self.is_array(self.flags.mode) {
			if self.flags.last_text == "[" || (self.flags.last_text == "," && (self.last_last_text == "]" || self.last_last_text == "}")) {
				if !self.options["keep_array_indentation"].(bool) {
					self.print_newline(false, false)
				}
			}
		}
	} else {
		if self.last_type == "TK_RESERVED" && self.flags.last_text == "for" {
			next_mode = ForInitializer
		} else if self.last_type == "TK_RESERVED" && (self.flags.last_text == "if" || self.flags.last_text == "while") {
			next_mode = Conditional
		} else {
			next_mode = Expression
		}
	}

	if self.flags.last_text == ";" || self.last_type == "TK_START_BLOCK" {
		self.print_newline(false, false)
	} else if utils.InStrArray(self.last_type, []string{"TK_END_EXPR", "TK_START_EXPR", "TK_END_BLOCK"}) || self.flags.last_text == "." {
		self.allow_wrap_or_preserved_newline(*current_token, current_token.WantedNewLine())
	} else if !(self.last_type == "TK_RESERVED" && current_token.Text() == "(") && !utils.InStrArray(self.last_type, []string{"TK_WORD", "TK_OPERATOR"}) {
		self.output.space_before_token = true
	} else if (self.last_type == "TK_RESERVED" && (self.flags.last_word == "function" || self.flags.last_word == "typeof")) || (self.flags.last_text == "*" && self.last_last_text == "function") {
		if self.options["space_after_anon_function"].(bool) {
			self.output.space_before_token = true
		}
	} else if self.last_type == "TK_RESERVED" && (utils.InStrArray(self.flags.last_text, tokenizer.GetLineStarters()) || self.flags.last_text == "catch") {
		self.output.space_before_token = true
	}

	if self.last_type == "TK_EQUALS" || self.last_type == "TK_OPERATOR" {
		if !self.start_of_object_property() {
			self.allow_wrap_or_preserved_newline(*current_token, false)
		}
	}

	self.set_mode(next_mode)
	self.print_token(*current_token, "")

	if self.options["space_in_paren"].(bool) {
		self.output.space_before_token = true
	}
	self.indent()
}
func (self *jsbeautifier) is_special_word(s string) bool {
	return utils.InStrArray(s, []string{"case", "return", "do", "if", "throw", "else"})
}
func (self *tokenizer) getNextToken() (string, string) {
	defer func() { self.tokens_parsed++ }()

	whitespace_on_this_line := make([]string, 0)
	self.n_newlines = 0
	self.whitespace_before_token = ""

	if self.parser_pos >= len(*self.input) {
		return "", "TK_EOF"
	}

	if self.tokens_parsed == 0 {
		self.last_token = NewSimpleToken("{", "TK_START_BLOCK", self.n_newlines, self.whitespace_before_token)
	}

	c := self.AdvanceNextChar()

	for utils.InStrArray(c, whitespace[:]) {
		if c == "\n" {
			self.n_newlines += 1
			// whitespace_on_this_line = []
		} else if c == self.indent_string {
			whitespace_on_this_line = append(whitespace_on_this_line, self.indent_string)
		} else if c != "\r" {
			whitespace_on_this_line = append(whitespace_on_this_line, " ")
		}

		if self.parser_pos >= len(*self.input) {
			return "", "TK_EOF"
		}

		c = self.AdvanceNextChar()
	}

	if len(whitespace_on_this_line) != 0 {
		self.whitespace_before_token = strings.Join(whitespace_on_this_line, "")
	}

	if digit.Match([]byte(c)) {

		allow_decimal := true
		allow_e := true
		local_digit := digit

		tempregex, _ := regexp.Compile("[Xx]")

		if c == "0" && self.parser_pos < len(*self.input) && tempregex.Match([]byte(self.GetNextChar())) {
			allow_decimal = false
			allow_e = false
			c += self.AdvanceNextChar()
			local_digit, _ = regexp.Compile("[0123456789abcdefABCDEF]")
		} else {
			c = ""
			self.BackupChar()
		}

		for self.parser_pos < len(*self.input) && local_digit.Match([]byte(self.GetNextChar())) {
			c += self.AdvanceNextChar()

			if allow_decimal && self.parser_pos < len(*self.input) && self.GetNextChar() == "." {

				c += self.AdvanceNextChar()
				allow_decimal = false
			}

			tempregex, _ := regexp.Compile("[Ee]")
			if allow_e && self.parser_pos < len(*self.input) && tempregex.Match([]byte(self.GetNextChar())) {
				c += self.AdvanceNextChar()

				tempregex, _ := regexp.Compile("[+-]")
				if self.parser_pos < len(*self.input) && tempregex.Match([]byte(self.GetNextChar())) {
					c += self.AdvanceNextChar()
				}

				allow_e = false
				allow_decimal = false
			}
		}

		return c, "TK_WORD"
	}

	if self.acorn.IsIdentifierStart(self.GetLastRune()) {
		if self.parser_pos < len(*self.input) {
			for self.acorn.IsIdentifierChar(self.GetNextRune()) {
				c += self.AdvanceNextChar()
				if self.parser_pos == len(*self.input) {
					break
				}
			}
		}

		if !(self.last_token.tktype == "TK_DOT" || (self.last_token.tktype == "TK_RESERVED" && (self.last_token.text == "set" || self.last_token.text == "get"))) && utils.InStrArray(c, reserved_words) {
			if c == "in" {
				return c, "TK_OPERATOR"
			}

			return c, "TK_RESERVED"
		}

		return c, "TK_WORD"
	}

	if c == "(" || c == "[" {
		return c, "TK_START_EXPR"
	}

	if c == ")" || c == "]" {
		return c, "TK_END_EXPR"
	}

	if c == "{" {
		return c, "TK_START_BLOCK"
	}

	if c == "}" {
		return c, "TK_END_BLOCK"
	}

	if c == ";" {
		return c, "TK_SEMICOLON"
	}

	if c == "/" {
		comment := ""
		inline_comment := true
		nextCh, nextWidth := self.GetNextCharWithWidth()
		if nextCh == "*" {
			self.parser_pos += nextWidth

			nextCh, nextWidth = self.GetNextCharWithWidth()
			if self.parser_pos < len(*self.input) {
				for !(nextCh == "*" && self.parser_pos+nextWidth < len(*self.input) && string((*self.input)[self.parser_pos+nextWidth]) == "/") && self.parser_pos < len(*self.input) {
					c = self.AdvanceNextChar()
					comment += c
					if c == "\r" || c == "\n" {
						inline_comment = false
					}

					if self.parser_pos >= len(*self.input) {
						break
					}
					nextCh, nextWidth = self.GetNextCharWithWidth()
				}
			}
			self.parser_pos += 2

			if inline_comment && self.n_newlines == 0 {
				return "/*" + comment + "*/", "TK_INLINE_COMMENT"
			} else {
				return "/*" + comment + "*/", "TK_BLOCK_COMMENT"
			}
		}

		if self.GetNextChar() == "/" {
			comment = c
			for self.GetNextChar() != "\r" && self.GetNextChar() != "\n" {
				comment += self.AdvanceNextChar()
				if self.parser_pos >= len(*self.input) {
					break
				}
			}

			return comment, "TK_COMMENT"
		}
	}

	tempr := regexp.MustCompile(`^<(!\[CDATA\[[\s\S]*?\]\]|[-a-zA-Z:0-9_.]+|\{[^{}]*\})\s*([-a-zA-Z:0-9_.]+=(\{[^{}]*\}|"[^"]*"|'[^']*')\s*)*\/?\s*>`)

	if c == "`" || c == "'" || c == "\"" || ((c == "/") || (self.options["e4x"].(bool) && c == "<" && tempr.Match([]byte(string((*self.input)[self.parser_pos-1:]))))) && ((self.last_token.tktype == "TK_RESERVED" && utils.InStrArray(self.last_token.text, []string{"return", "case", "throw", "else", "do", "typeof", "yield"})) || (self.last_token.tktype == "TK_END_EXPR" && self.last_token.text == ")" && self.last_token.parent != nil && self.last_token.parent.tktype == "TK_RESERVED" && utils.InStrArray(self.last_token.parent.text, []string{"if", "while", "for"})) || (utils.InStrArray(self.last_token.tktype, []string{"TK_COMMENT", "TK_START_EXPR", "TK_START_BLOCK", "TK_END_BLOCK", "TK_OPERATOR", "TK_EQUALS", "TK_EOF", "TK_SEMICOLON", "TK_COMMA"}))) {

		sep := c
		esc := false
		esc1 := 0
		esc2 := 0
		resulting_string := c
		in_char_class := false

		if sep == "/" { //regexp
			in_char_class = false
			for self.parser_pos < len(*self.input) && (esc || in_char_class || self.GetNextChar() != sep) && !self.acorn.GetNewline().Match([]byte(self.GetNextChar())) {
				resulting_string += self.AdvanceNextChar()
				if !esc {
					esc = self.GetLastChar() == "\\"
					if self.GetLastChar() == "[" {
						in_char_class = true
					} else if self.GetLastChar() == "]" {
						in_char_class = false
					}
				} else {
					esc = false
				}

			}
		} else if self.options["e4x"].(bool) && sep == "<" { // xml
			xmlRegExp := regexp.MustCompile(`<(\/?)(!\[CDATA\[[\s\S]*?\]\]|[-a-zA-Z:0-9_.]+|\{[^{}]*\})\s*([-a-zA-Z:0-9_.]+=(\{[^{}]*\}|"[^"]*"|\'[^\']*\')\s*)*(\/?)\s*>`)
			xmlStr := (*self.input)[self.parser_pos-1:]
			match := xmlRegExp.FindStringSubmatch((xmlStr))

			if match != nil {
				rootTag := match[2]
				depth := 0
				lastPos := 0
				for match != nil {
					isEndTag := match[1]
					tagName := match[2]
					isSingeltonTag := (match[len(match)-1] != "") || (strings.HasPrefix(match[2], "![CDATA["))
					if tagName == rootTag && !isSingeltonTag {
						if isEndTag != "" {
							depth -= 1
						} else {
							depth += 1
						}
					}

					if depth <= 0 {
						break
					}

					indices := xmlRegExp.FindStringSubmatchIndex(xmlStr[lastPos:])
					lastPos += indices[1]

					match = xmlRegExp.FindStringSubmatch(xmlStr[lastPos:])
				}
				xmlLength := 0
				if match != nil {
					indices := xmlRegExp.FindStringSubmatchIndex(xmlStr[lastPos:])
					xmlLength = lastPos + indices[1]
				} else {
					xmlLength = len(xmlStr)
				}

				self.parser_pos += xmlLength - 1

				return xmlStr[:xmlLength], "TK_STRING"
			}

		} else { // string
			for self.parser_pos < len(*self.input) && (esc || (self.GetNextChar() != sep && (sep == "`" || !self.acorn.GetNewline().Match([]byte(self.GetNextChar()))))) {
				resulting_string += self.AdvanceNextChar()
				if esc1 > 0 && esc1 >= esc2 {
					esc1, ok := strconv.ParseUint(resulting_string[esc2:], 16, 0)

					if ok != nil {
						esc1 = 0
					}
					if esc1 >= 0x20 && esc1 <= 0x7e {
						esc1c := string(esc1)
						resulting_string = resulting_string[:len(resulting_string)-2-esc2]
						if esc1c == sep || esc1c == "\\" {
							resulting_string += "\\"
						}
						resulting_string += esc1c
					}
					esc1 = 0
				}
				if esc1 > 0 {
					esc1 += 1
				} else if !esc {
					esc = self.GetLastChar() == "\\"
				} else {
					esc = false
					if self.options["unescape_strings"].(bool) {
						if self.GetLastChar() == "x" {
							esc1 += 1
							esc2 = 2
						} else if self.GetLastChar() == "u" {
							esc1 += 1
							esc2 = 4
						}
					}
				}
			}
		}

		if self.parser_pos < len(*self.input) && self.GetNextChar() == sep {
			resulting_string += self.AdvanceNextChar()

			if sep == "/" {
				for self.parser_pos < len(*self.input) && self.acorn.IsIdentifierStart(self.GetNextRune()) {
					resulting_string += self.AdvanceNextChar()
				}
			}
		}
		return resulting_string, "TK_STRING"
	}

	if c == "#" {

		if self.tokens_parsed == 0 && len(*self.input) > self.parser_pos && self.GetNextChar() == "!" {
			resulting_string := c
			for self.parser_pos < len(*self.input) && c != "\n" {
				c = self.AdvanceNextChar()
				resulting_string += c
			}
			return strings.TrimSpace(resulting_string) + "\n", "TK_UNKNOWN"
		}

		sharp := "#"
		if match := digit.Match([]byte(self.GetNextChar())); self.parser_pos < len(*self.input) && match {
			for {
				c = self.AdvanceNextChar()
				sharp += c
				if self.parser_pos >= len(*self.input) || c == "#" || c == "=" {
					break
				}
			}
		}

		nextCh, nextWidth := self.GetNextCharWithWidth()
		if c == "#" || self.parser_pos >= len(*self.input) {

		} else if nextCh == "[" && string((*self.input)[self.parser_pos+nextWidth]) == "]" {
			sharp += "[]"
			self.parser_pos += 2
		} else if nextCh == "{" && string((*self.input)[self.parser_pos+nextWidth]) == "}" {
			sharp += "{}"
			self.parser_pos += 2
		}
		return sharp, "TK_WORD"
	}

	slice, out_of_bounds := self.GetCharSlice(1, 3)

	if c == "<" && !out_of_bounds && slice == "<!--" {
		for self.parser_pos < len(*self.input) && self.GetNextChar() != "\n" {
			c += self.AdvanceNextChar()
		}
		self.in_html_comment = true
		return c, "TK_COMMENT"
	}

	slice, out_of_bounds = self.GetCharSlice(1, 2)

	if c == "-" && self.in_html_comment && !out_of_bounds && slice == "-->" {
		self.in_html_comment = false
		self.parser_pos += 2
		return "-->", "TK_COMMENT"
	}

	if c == "." {
		return c, "TK_DOT"
	}

	if utils.InStrArray(c, punct) {
		for self.parser_pos < len(*self.input) && utils.InStrArray(c+self.GetNextChar(), punct) {
			c += self.AdvanceNextChar()
			if self.parser_pos >= len(*self.input) {
				break
			}
		}

		if c == "," {
			return c, "TK_COMMA"
		}

		if c == "=" {
			return c, "TK_EQUALS"
		}
		return c, "TK_OPERATOR"
	}

	return c, "TK_UNKNOWN"
}