func (s *Scanner) scanNumber() (token.Pos, string) { start := s.off for unicode.IsDigit(s.ch) { s.next() } return token.Pos(start), s.str[start:s.off] }
func (s *Scanner) scanComment() (token.Pos, string) { start := s.off - 1 for s.ch != '\n' && s.off < len(s.str) { s.next() } return token.Pos(start), s.str[start:s.off] }
func (s *Scanner) scanIdentifier() (token.Pos, string) { start := s.off for unicode.IsDigit(s.ch) || isAlpha(s.ch) || s.ch == '_' || s.ch == '-' { s.next() } return token.Pos(start), s.str[start:s.off] }
func ParseFile(f *token.File, str string) *ast.File { if f.Size() != len(str) { fmt.Println("File size does not match string length.") return nil } root := ast.NewFile(token.Pos(1), token.Pos(len(str)+1)) p := new(parser) p.init(f, str) p.topScope = root.Scope p.curScope = root.Scope n := p.parse() for p.file.NumErrors() < 10 && p.tok != token.EOF { root.Nodes = append(root.Nodes, n) p.next() n = p.parse() } if p.topScope != p.curScope { panic("Imbalanced scope!") } return root }
func (s *Scanner) next() { s.off = s.roff if s.off < len(s.str) { r, n := utf8.DecodeRuneInString(s.str[s.off:]) if r == utf8.RuneError { s.file.AddError(s.file.Base()+token.Pos(s.off), "Invalid UTF8 string!") return } s.ch = r s.roff += n } else { s.ch = 0 } if s.ch == '\n' { s.file.AddLine(s.off) } //s.roff++ }
func (s *Scanner) Scan() (tok token.Token, pos token.Pos, lit string) { s.skipWhitespace() if isAlpha(s.ch) { pos, lit = s.scanIdentifier() tok = token.Lookup(lit) return } if unicode.IsDigit(s.ch) { pos, lit = s.scanNumber() return token.NUMBER, pos, lit } ch := s.ch pos = token.Pos(s.off) s.next() switch ch { case '+': tok = token.ADD case '-': if unicode.IsDigit(s.ch) { // is '-' a unary operator for a number? pos, lit = s.scanNumber() pos, lit, tok = pos-1, string('-')+lit, token.NUMBER return } tok = token.SUB case '*': tok = token.MUL case '/': tok = token.DIV case '%': tok = token.MOD case '(': tok = token.LPAREN case ')': tok = token.RPAREN case ';': pos, lit = s.scanComment() tok = token.COMMENT return case '=': tok = token.EQ case '<': switch s.ch { case '=': lit = string(ch) + string(s.ch) tok = token.LTE s.next() return case '>': lit = string(ch) + string(s.ch) tok = token.NEQ s.next() return } tok = token.LT case '>': if s.ch == '=' { lit = string(ch) + string(s.ch) tok = token.GTE s.next() return } tok = token.GT case '"': lit = s.scanString() tok = token.STRING return default: if s.off >= len(s.str) { tok = token.EOF pos = token.Pos(s.off) return } } lit = string(ch) return }
func (n *Number) End() token.Pos { return n.Num + token.Pos(len(n.Lit)) }
func (i *Identifier) End() token.Pos { return i.Id + token.Pos(len(i.Lit)) }
func (s *String) End() token.Pos { return s.Str + token.Pos(len(s.Lit)) }