func (t *tokenizer) scanEscape(quote rune) rune {
	var n int
	var base, max uint32
	var r rune
	switch t.r {
	case 'a':
		r = '\a'
	case 'b':
		r = '\b'
	case 'f':
		r = '\f'
	case 'n':
		r = '\n'
	case 'r':
		r = '\r'
	case 't':
		r = '\t'
	case 'v':
		r = '\v'
	case '\\':
		r = '\\'
	case quote:
		r = quote
	case '0', '1', '2', '3', '4', '5', '6', '7':
		n, base, max = 3, 8, 255
	case 'x':
		t.nextChar()
		n, base, max = 2, 16, 255
	case 'u':
		t.nextChar()
		n, base, max = 4, 16, unicode.MaxRune
	case 'U':
		t.nextChar()
		n, base, max = 8, 16, unicode.MaxRune
	default:
		msg := "unknown escape sequence"
		if t.r < 0 {
			msg = "escape sequence not terminated"
		}
		t.error(msg)
	}
	if r > 0 {
		return r
	}
	var x uint32
	for n > 0 {
		d := uint32(digitVal(t.r))
		if d >= base {
			msg := fmt.Sprintf("illegal character %#U in escape sequence", t.r)
			if t.r < 0 {
				msg = "escape sequence not terminated"
			}
			t.error(msg)
		}
		x = x*base + d
		t.nextChar()
		n--
		if n == 0 && base == 16 && max == 255 && t.r == '\\' {
			rd := t.readOffset
			t.nextChar()
			if t.r == 'x' {
				n = 2
				max = unicode.MaxRune
				t.nextChar()
			} else {
				t.readOffset = rd
			}
		}
	}
	if x > max || 0xD800 <= x && x < 0xE000 {
		t.error("escape sequence is invalid Unicode code point")
	}
	return rune(x)
}
scans a valid escape sequence and returns the evaluated value
package parse
import (
	"fmt"
	"github.com/glhrmfrts/yo/ast"
	"os"
	"unicode"
	"unicode/utf8"
)
type tokenizer struct {
	offset     int
	readOffset int
	r          rune
	src        []byte
	filename   string
	lineno     int
	insertSemi bool
	last       ast.Token
}
const bom = 0xFEFF
const eof = -1
func isLetter(ch rune) bool {
	return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= 0x80 && unicode.IsLetter(ch)
}
func isDigit(ch rune) bool {
	return '0' <= ch && ch <= '9' || ch >= 0x80 && unicode.IsDigit(ch)
}
func (t *tokenizer) error(msg string) {
	fmt.Printf("%s:%d -> syntax error: %s\n", t.filename, t.lineno, msg)
	os.Exit(1)
}
func (t *tokenizer) nextChar() bool {
	if t.readOffset < len(t.src) {
		t.offset = t.readOffset
		ch := t.src[t.readOffset]
		r, w := rune(ch), 1
		switch {
		case r == 0:
			t.error("illegal character NUL")
		case r >= 0x80:
			r, w = utf8.DecodeRune(t.src[t.offset:])
			if r == utf8.RuneError && w == 1 {
				t.error("illegal UTF-8 encoding")
			} else if r == bom && t.offset > 0 {
				t.error("illegal byte order mark")
			}
		}
		if ch == '\n' {
			t.lineno++
		}
		t.r = r
		t.readOffset += w
		return true
	}
	t.r = eof
	t.offset = len(t.src)
	return false
}
func (t *tokenizer) scanComment() bool {
	if t.r == '/' {
		for t.r != eof && t.r != '\n' {
			t.nextChar()
		}
		return true
	}
	return false
}
func (t *tokenizer) scanIdentifier() string {
	offs := t.offset
	for isLetter(t.r) || isDigit(t.r) {
		t.nextChar()
	}
	return string(t.src[offs:t.offset])
}
func digitVal(ch rune) int {
	switch {
	case '0' <= ch && ch <= '9':
		return int(ch - '0')
	case 'a' <= ch && ch <= 'f':
		return int(ch - 'a' + 10)
	case 'A' <= ch && ch <= 'F':
		return int(ch - 'A' + 10)
	}
	return 16
}
func (t *tokenizer) scanMantissa(base int) {
	for digitVal(t.r) < base {
		t.nextChar()
	}
}
func (t *tokenizer) scanNumber(seenDecimalPoint bool) (ast.Token, string) {
	offs := t.offset
	typ := ast.TokenInt
	if seenDecimalPoint {
		typ = ast.TokenFloat
		offs--
		t.scanMantissa(10)
		goto exponent
	}
	if t.r == '0' {
		offs := t.offset
		t.nextChar()
		if t.r == 'x' || t.r == 'X' {
			t.nextChar()
			t.scanMantissa(16)
			if t.offset-offs <= 2 {
				t.error("illegal hexadecimal number")
			}
		} else {
			seenDecimalDigit := false
			t.scanMantissa(8)
			if t.r == '8' || t.r == '9' {
				seenDecimalDigit = true
				t.scanMantissa(10)
			}
			if t.r == '.' || t.r == 'e' || t.r == 'E' {
				goto fraction
			}
			if seenDecimalDigit {
				t.error("illegal octal number")
			}
		}
		goto exit
	}
	t.scanMantissa(10)
fraction:
	if t.r == '.' {
		typ = ast.TokenFloat
		t.nextChar()
		t.scanMantissa(10)
	}
exponent:
	if t.r == 'e' || t.r == 'E' {
		typ = ast.TokenFloat
		t.nextChar()
		if t.r == '-' || t.r == '+' {
			t.nextChar()
		}
		t.scanMantissa(10)
	}
exit:
	return typ, string(t.src[offs:t.offset])
}