func (s *Scanner) Init(file *token.File, src []byte, err ErrorHandler, mode Mode) {
	if file.Size() != len(src) {
		panic(fmt.Sprintf("file size (%d) does not match src len (%d)", file.Size(), len(src)))
	}
	s.file = file
	s.dir, _ = filepath.Split(file.Name())
	s.src = src
	s.err = err
	s.mode = mode
	s.ch = ' '
	s.offset = 0
	s.rdOffset = 0
	s.lineOffset = 0
	s.insertSemi = false
	s.ErrorCount = 0
	s.lastToken = token.ILLEGAL
	s.goxState.push(GO)
	s.next()
	if s.ch == bom {
		s.next()  
	}
}
Init prepares the scanner s to tokenize the text src by setting the
scanner at the beginning of src. The scanner uses the file set file
for position information and it adds line information for each line.
It is ok to re-use the same file when re-scanning the same file as
line information which is already present is ignored. Init causes a
panic if the file size does not match the src size.

Calls to Scan will invoke the error handler err if they encounter a
syntax error and err is not nil. Also, for each error encountered,
the Scanner field ErrorCount is incremented by one. The mode parameter
determines how comments are handled.

Note that Init may call err if there is an error in the first character
of the file.
package scanner
import (
	"bytes"
	"fmt"
	"path/filepath"
	"strconv"
	"unicode"
	"unicode/utf8"
	"github.com/8byt/gox/token"
)
type ErrorHandler func(pos token.Position, msg string)
type goxMode int
const (
	GO goxMode = iota
	GOX_TAG
	BARE_WORDS
)
type StackState struct {
	mode       goxMode
	braceDepth int
}
type goxStack struct {
	*StackState
	stack []StackState
}
func (s *goxStack) push(mode goxMode) {
	s.stack = append(s.stack, StackState{mode: mode, braceDepth: 0})
	s.StackState = &s.stack[len(s.stack)-1]
}
func (s *goxStack) pop() error {
	if len(s.stack) <= 1 {
		return fmt.Errorf("Unable to pop empty gox stack")
	}
	s.stack = s.stack[:len(s.stack)-1]
	s.StackState = &s.stack[len(s.stack)-1]
	return nil
}
type Scanner struct {
	file *token.File   
	dir  string        
	src  []byte        
	err  ErrorHandler  
	mode Mode          
	ch         rune  
	offset     int   
	rdOffset   int   
	lineOffset int   
	insertSemi bool  
	lastToken token.Token
	goxState  goxStack
	ErrorCount int  
}
const bom = 0xFEFF  
func (s *Scanner) next() {
	if s.rdOffset < len(s.src) {
		s.offset = s.rdOffset
		if s.ch == '\n' {
			s.lineOffset = s.offset
			s.file.AddLine(s.offset)
		}
		r, w := rune(s.src[s.rdOffset]), 1
		switch {
		case r == 0:
			s.error(s.offset, "illegal character NUL")
		case r >= utf8.RuneSelf:
			r, w = utf8.DecodeRune(s.src[s.rdOffset:])
			if r == utf8.RuneError && w == 1 {
				s.error(s.offset, "illegal UTF-8 encoding")
			} else if r == bom && s.offset > 0 {
				s.error(s.offset, "illegal byte order mark")
			}
		}
		s.rdOffset += w
		s.ch = r
	} else {
		s.offset = len(s.src)
		if s.ch == '\n' {
			s.lineOffset = s.offset
			s.file.AddLine(s.offset)
		}
		s.ch = -1  
	}
}
type Mode uint
const (
	ScanComments    Mode = 1 << iota  
	dontInsertSemis                   
)