func (d *Dict) expandDirective(in *scanner.Scanner, out *bufio.Writer) error { var err error c := in.Next() switch c { case lDelim: switch in.Peek() { case lDelim: return copyNext(in, out) case condDelim: in.Next() err = d.expandCond(in, out) default: if err = d.expandVar(in, out); err == nil { err = match(in, rDelim) } } case rDelim: if err = writeString(out, "}"); err == nil { err = match(in, rDelim) } case scanner.EOF: err = parseErr(in, "Expected '%c' or '%c', got EOF", lDelim, rDelim) default: err = parseErr(in, "Expected '%c' or '%c', got '%c'", lDelim, rDelim, c) } return err }
func copyUntilDelim(in *scanner.Scanner, out *bufio.Writer) error { var err error for err == nil && !isEOF(in) && in.Peek() != lDelim && in.Peek() != rDelim { err = copyNext(in, out) } return err }
func parseVariable(sc *scanner.Scanner) (result []byte, err error) { delims := []byte{byte(sc.Next())} if ch := sc.Peek(); ch == '{' { delims = append(delims, byte(sc.Next())) } name, err := parseName(sc) if err == nil && len(delims) > 1 && '}' != byte(sc.Peek()) { err = errInvalidSyntax } if err != nil { name = append(delims, name...) if len(delims) > 1 { name = append(name, byte(sc.Next())) } return name, err } if len(delims) > 1 { sc.Next() } return name, err }
// ProcessConfig replaces references of environment varialbes for the given data // Support variable syntax: $varname, ${varname} func ProcessConfig(data []byte, e *env.Env, escapeChar rune) ([]byte, error) { var result []byte var sc scanner.Scanner sc.Init(bytes.NewReader(data)) DONE: for { switch ch := sc.Peek(); ch { default: result = append(result, byte(sc.Next())) case scanner.EOF: break DONE case escapeChar: curr, next := sc.Next(), sc.Peek() if next != '$' { result = append(result, byte(curr)) } if next != scanner.EOF { result = append(result, byte(sc.Next())) } case '$': name, err := parseVariable(&sc) if err != nil { pos := sc.Pos() return result, fmt.Errorf(`parseError:%d:%d: %v %q`, pos.Line, pos.Offset, err, name) } result = append(result, e.Get(string(name))...) } } return result, nil }
func scanArray(s *scanner.Scanner, out chan Part, stop villa.Stop) (toStop bool) { if scanRune(s, out, stop, TP_ARRAY_START, '[') { return true } skipWhitespaces(s) if s.Peek() != ']' { for { if scanValue(s, out, stop) { return true } skipWhitespaces(s) if s.Peek() != ',' { break } if scanRune(s, out, stop, TP_COMMA, ',') { return true } skipWhitespaces(s) } } return scanRune(s, out, stop, TP_ARRAY_END, ']') }
func split(expr string) (keys []string, err error) { var msgs []string var s scanner.Scanner s.Init(strings.NewReader(expr)) s.Mode = scanner.ScanIdents | scanner.ScanInts | scanner.ScanStrings s.Error = func(s *scanner.Scanner, msg string) { msgs = append(msgs, fmt.Sprintf("%s %s", s.Pos(), msg)) } key := "" keys = []string{} for err == nil { t := s.Peek() // fmt.Printf(">>> %s: %s %s\n", s.Pos(), scanner.TokenString(t), s.TokenText()) switch t { case '[': key, err = scanBracketedKey(&s) case '.': s.Scan() continue case scanner.EOF: goto end default: key, err = scanKey(&s) } if len(msgs) > 0 { err = errors.New(strings.Join(msgs, "\n")) } if err == nil { keys = append(keys, key) } } end: return }
func scanTo3(s *scanner.Scanner, target0, target1, target2 rune) bool { for { // match 0, 1 if !scanTo2(s, target0, target1) { // EOF return false } switch s.Peek() { case scanner.EOF: s.Next() return false case target2: // matched 2, found s.Next() return true case target1: if target0 == target1 { loop: for { switch s.Next() { case scanner.EOF: return false case target2: return true case target0: // keep scanning default: // not found, go to out loop break loop } } } } } }
func (w *wordsStruct) addString(str string) { var scan scanner.Scanner scan.Init(strings.NewReader(str)) for scan.Peek() != scanner.EOF { w.addChar(scan.Next()) } }
// Parse the selector after ':' func ParsePseudo(selector *CSSSelector, s scanner.Scanner) error { if selector.Pseudo != nil { return fmt.Errorf("Combined multiple pseudo classes") } var b bytes.Buffer for s.Peek() != scanner.EOF { if _, err := b.WriteRune(s.Next()); err != nil { return err } } cmd := b.String() var err error switch { case cmd == "empty": selector.Pseudo = func(n *html.Node) bool { return n.FirstChild == nil } case cmd == "first-child": selector.Pseudo = firstChildPseudo case cmd == "last-child": selector.Pseudo = lastChildPseudo case cmd == "only-child": selector.Pseudo = func(n *html.Node) bool { return firstChildPseudo(n) && lastChildPseudo(n) } case cmd == "first-of-type": selector.Pseudo = firstOfTypePseudo case cmd == "last-of-type": selector.Pseudo = lastOfTypePseudo case cmd == "only-of-type": selector.Pseudo = func(n *html.Node) bool { return firstOfTypePseudo(n) && lastOfTypePseudo(n) } case strings.HasPrefix(cmd, "contains("): selector.Pseudo, err = parseContainsPseudo(cmd[len("contains("):]) if err != nil { return err } case strings.HasPrefix(cmd, "nth-child("), strings.HasPrefix(cmd, "nth-last-child("), strings.HasPrefix(cmd, "nth-last-of-type("), strings.HasPrefix(cmd, "nth-of-type("): if selector.Pseudo, err = parseNthPseudo(cmd); err != nil { return err } case strings.HasPrefix(cmd, "not("): if selector.Pseudo, err = parseNotPseudo(cmd[len("not("):]); err != nil { return err } case strings.HasPrefix(cmd, "parent-of("): if selector.Pseudo, err = parseParentOfPseudo(cmd[len("parent-of("):]); err != nil { return err } default: return fmt.Errorf("%s not a valid pseudo class", cmd) } return nil }
func parseText(s *scanner.Scanner, depth int) ([]ast, error) { var slice []ast for { switch s.Scan() { case '+', '-', '/', '%', '*', '=', '<', '>', '!': slice = append(slice, parseIdent(s.TokenText())) case scanner.Ident: ident := s.TokenText() // Periods are allowed in package names. for s.Peek() == '.' { s.Next() ident += "." if s.Scan() != scanner.Ident { return nil, stitchError{pos: s.Pos(), err: fmt.Errorf("bad ident name: %s", ident)} } ident += s.TokenText() } slice = append(slice, parseIdent(ident)) case scanner.Float: x, _ := strconv.ParseFloat(s.TokenText(), 64) slice = append(slice, astFloat(x)) case scanner.Int: x, _ := strconv.Atoi(s.TokenText()) slice = append(slice, astInt(x)) case scanner.String: str := strings.Trim(s.TokenText(), "\"") slice = append(slice, astString(str)) case '(': // We need to save our position before recursing because the // scanner will have moved on by the time the recursive call // returns. pos := s.Pos() sexp, err := parseText(s, depth+1) if err != nil { return nil, err } slice = append(slice, astSexp{sexp: sexp, pos: pos}) case ')': if depth == 0 { return nil, stitchError{s.Pos(), errUnbalancedParens} } return slice, nil case scanner.EOF: if depth != 0 { return nil, stitchError{s.Pos(), errUnbalancedParens} } return slice, nil default: return nil, stitchError{s.Pos(), fmt.Errorf("bad element: %s", s.TokenText())} } } }
func scanTo2(s *scanner.Scanner, target0, target1 rune) bool { for { switch s.Next() { case scanner.EOF: return false case target0: if s.Peek() == target1 { s.Next() // skip targe1 return true } } } }
// collect the next characters in s that are numbers // assumes at least TokenText is a number func Number(s *scanner.Scanner) string { var buffer bytes.Buffer for s.Scan() != scanner.EOF { buffer.WriteString(s.TokenText()) if _, ok := strconv.Atoi(string(s.Peek())); ok != nil { return buffer.String() } } // reached the end of file, but that's ok potentially? return buffer.String() }
func readVar(in *scanner.Scanner) (s string, err error) { var buf bytes.Buffer for isVarRune(in.Peek()) { buf.WriteRune(in.Next()) } s = buf.String() if in.Peek() != rDelim { err = parseErr(in, "Unexpected character '%c'", in.Next()) } else if len(s) == 0 { err = parseErr(in, "Empty variable") } return }
func parseXML(sc *scanner.Scanner) (*Token, bool) { var entity = new(bytes.Buffer) token := new(Token) // Skip the '<' sc.Scan() switch sc.Peek() { case '/': token.Type = XMLEndToken sc.Next() case '!': log.Tracef("parseXML skipping comment") next := sc.Next() for next != '>' { next = sc.Next() } return nil, false default: token.Type = XMLStartToken } log.Tracef("parseXML creating %s element", token.Type) for { tok := sc.Scan() log.Tracef("parseXML found %s. Token is %v. Entity is: '%s'", sc.TokenText(), tok, entity.String()) switch { case tok == '>': token.Text = entity.String() return token, true case unicode.IsSpace(tok): return nil, false default: log.Tracef("parseXML appending %s to string", sc.TokenText()) entity.WriteString(sc.TokenText()) } } }
func scanKeyword(s *scanner.Scanner, out chan Part, stop villa.Stop) (toStop bool) { start := s.Pos() switch s.Peek() { case scanner.EOF: s.Next() return output(out, stop, TP_EOF_UNEXPECTED, start, s.Pos()) case 't': return scanWord(s, out, stop, []rune("true")) case 'f': return scanWord(s, out, stop, []rune("false")) case 'n': return scanWord(s, out, stop, []rune("null")) } s.Next() return output(out, stop, TP_ERROR, start, s.Pos()) }
func parseName(sc *scanner.Scanner) (result []byte, err error) { if ch := sc.Peek(); scanner.EOF == ch { return result, errInvalidSyntax } for { if ch := sc.Peek(); unicode.IsLetter(ch) || unicode.IsDigit(ch) || '_' == ch { result = append(result, byte(sc.Next())) } else { if len(result) == 0 { err = errInvalidSyntax } return result, err } } }
func scanValue(s *scanner.Scanner, out chan Part, stop villa.Stop) (toStop bool) { start := s.Pos() switch s.Peek() { case scanner.EOF: return output(out, stop, TP_EOF_UNEXPECTED, start, s.Pos()) case '"': return scanString(s, out, stop) case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': return scanNumber(s, out, stop) case 't', 'f', 'n': return scanKeyword(s, out, stop) case '{': return scanObject(s, out, stop) case '[': return scanArray(s, out, stop) } return output(out, stop, TP_ERROR, start, s.Pos()) }
func fields(s *scanner.Scanner, tok rune) step { switch tok { case '.': return fields case '{': return fields case '}': return endStruct(s, tok) case ';': return fields case scanner.Ident: if s.Peek() == '.' { return fields } return emitField(s, tok) } return fail }
func (d *Dict) expandCond(in *scanner.Scanner, writer *bufio.Writer) error { expand, err := d.evalBool(in) if err != nil { return err } var out *bufio.Writer expanded := false for err == nil && !isEOF(in) { if !expanded && expand { out = writer expanded = true } if err = copyUntilDelim(in, out); err != nil { break } if in.Peek() == lDelim { in.Next() switch in.Peek() { case lDelim: err = copyNext(in, out) case condDelim: in.Next() if in.Peek() == rDelim { in.Next() return nil } else { err = d.expandCond(in, out) } case condElsif: in.Next() out = nil if in.Peek() == rDelim { in.Next() expand = true } else { expand, err = d.evalBool(in) } default: err = d.expandVar(in, out) if out == nil || err == nil { err = match(in, rDelim) } } } else { err = d.expandDirective(in, out) } } return err }
func get_map(data []byte) (map[string]string, error) { src := bytes.NewReader(data) var s scanner.Scanner var tok rune s.Init(src) var key, value string m := map[string]string{} for { if tok = s.Scan(); tok == scanner.Ident { key = s.TokenText() if tok = s.Scan(); tok == rune('=') { tok = s.Scan() if tok == scanner.String { v := []rune(s.TokenText()) value = string(v[1 : len(v)-1]) } else { if tok == scanner.Ident { value = s.TokenText() for { if tok = s.Peek(); tok == rune(',') || tok == scanner.EOF { break } tok = s.Scan() value += s.TokenText() } } } m[key] = value tok = s.Scan() if tok == scanner.EOF { break } if tok == rune(',') { continue } } } return nil, errors.New("Failed to parse SASL challenge string") } return m, nil }
func ParseTags(s *scanner.Scanner, g *Game) error { //fmt.Println("starting tags parse") run := s.Peek() for run != scanner.EOF { switch run { case '[', ']', '\n', '\r': run = s.Next() case '1': return nil default: s.Scan() tag := s.TokenText() s.Scan() val := s.TokenText() //fmt.Println("tag:", tag, "; val:", val) g.Tags[tag] = strings.Trim(val, "\"") } run = s.Peek() } return nil }
func scanString(s *scanner.Scanner, out chan Part, stop villa.Stop) (toStop bool) { start := s.Pos() // start quote if r := s.Next(); r == scanner.EOF { return output(out, stop, TP_EOF_UNEXPECTED, start, s.Pos()) } else if r != '"' { return output(out, stop, TP_ERROR, start, s.Pos()) } // body for s.Peek() != '"' { if r := s.Next(); r == scanner.EOF { return output(out, stop, TP_EOF_UNEXPECTED, start, s.Pos()) } else if r == '\\' { switch s.Next() { case scanner.EOF: return output(out, stop, TP_EOF_UNEXPECTED, start, s.Pos()) case '"', '\\', '/', 'b', 'f', 'n', 'r', 't': // just ok case 'u': for i := 0; i < 4; i++ { r := s.Next() if r == scanner.EOF { return output(out, stop, TP_EOF_UNEXPECTED, start, s.Pos()) } if !isHexadecimal(r) { return output(out, stop, TP_ERROR, start, s.Pos()) } } default: return output(out, stop, TP_ERROR, start, s.Pos()) } } } // end quote s.Next() return output(out, stop, TP_STRING, start, s.Pos()) }
func scanObject(s *scanner.Scanner, out chan Part, stop villa.Stop) (toStop bool) { if scanRune(s, out, stop, TP_OBJECT_START, '{') { return true } skipWhitespaces(s) if s.Peek() != '}' { for { if scanString(s, out, stop) { return true } skipWhitespaces(s) if scanRune(s, out, stop, TP_COLON, ':') { return true } skipWhitespaces(s) if scanValue(s, out, stop) { return true } skipWhitespaces(s) if s.Peek() != ',' { break } if scanRune(s, out, stop, TP_COMMA, ',') { return true } skipWhitespaces(s) } } return scanRune(s, out, stop, TP_OBJECT_END, '}') }
func skipWhiteSpace(s *scanner.Scanner) { for isWhiteSpace(s.Peek()) { s.Next() } }
func scanBlock(s *scanner.Scanner) (blockType int, name string) { if s.Peek() != '<' { for s.Peek() != scanner.EOF && s.Peek() != '<' { s.Next() } return TP_FINAL, "" } // '<' s.Next() switch tp := s.Next(); tp { case '?': // PI // to find ?> scanTo2(s, '?', '>') return TP_FINAL, "" case '!': switch s.Next() { case scanner.EOF: // malformed case '[': // <![CDATA // find ]]> scanTo3(s, ']', ']', '>') case '-': // comments // find --> scanTo3(s, '-', '-', '>') return TP_COMMENT, "" default: // Attribute-List // find > scanTo1(s, '>') } return TP_FINAL, "" case '/': // end tag name := make([]rune, 0, 8) for { r := s.Next() if r == scanner.EOF || r == '>' { break } if isWhiteSpace(r) { scanTo1(s, '>') break } name = append(name, r) } if len(name) == 0 { // malformed return TP_FINAL, "" } return TP_END, string(name) case '>': // malformed return TP_FINAL, "" default: // start tag name := []rune{tp} for { r := s.Next() if r == scanner.EOF || r == '>' { break } if r == '/' { if s.Peek() == '>' { s.Next() return TP_FINAL, string(name) } } if isWhiteSpace(r) { loop: for { switch s.Next() { case scanner.EOF: return TP_FINAL, string(name) case '/': if s.Peek() == '>' { s.Next() return TP_FINAL, string(name) } case '>': break loop } } break } name = append(name, r) } return TP_START, string(name) } }
func skipWhitespaces(s *scanner.Scanner) { for s.Peek() != scanner.EOF && isWhitespace(s.Peek()) { s.Next() } }
func regexpMatch(pattern, path string) (bool, error) { regStr := "^" if _, err := filepath.Match(pattern, path); err != nil { return false, err } var scan scanner.Scanner scan.Init(strings.NewReader(pattern)) sl := string(os.PathSeparator) escSL := sl if sl == `\` { escSL += `\` } for scan.Peek() != scanner.EOF { ch := scan.Next() if ch == '*' { if scan.Peek() == '*' { scan.Next() if scan.Peek() == scanner.EOF { regStr += ".*" } else { regStr += "((.*" + escSL + ")|([^" + escSL + "]*))" } if string(scan.Peek()) == sl { scan.Next() } } else { regStr += "[^" + escSL + "]*" } } else if ch == '?' { regStr += "[^" + escSL + "]" } else if strings.Index(".$", string(ch)) != -1 { regStr += `\` + string(ch) } else if ch == '\\' { if sl == `\` { regStr += escSL continue } if scan.Peek() != scanner.EOF { regStr += `\` + string(scan.Next()) } else { regStr += `\` } } else { regStr += string(ch) } } regStr += "$" res, err := regexp.MatchString(regStr, path) if err != nil { err = filepath.ErrBadPattern } return res, err }
func ParseMoves(s *scanner.Scanner, g *Game) error { //fmt.Println("starting moves parse") s.Mode = scanner.ScanIdents | scanner.ScanChars | scanner.ScanInts | scanner.ScanStrings run := s.Peek() board := NewBoard() var err error if len(g.Tags["FEN"]) > 0 { board, err = NewBoardFEN(g.Tags["FEN"]) if err != nil { return err } } num := "" white := "" black := "" for run != scanner.EOF { switch run { case '(': for run != ')' && run != scanner.EOF { run = s.Next() } case '{': for run != '}' && run != scanner.EOF { run = s.Next() } case '#', '.', '+', '!', '?', '\n', '\r': run = s.Next() run = s.Peek() default: s.Scan() if s.TokenText() == "{" { run = '{' continue } if num == "" { num = s.TokenText() for s.Peek() == '-' { s.Scan() num += s.TokenText() s.Scan() num += s.TokenText() } for s.Peek() == '/' { s.Scan() num += s.TokenText() s.Scan() num += s.TokenText() s.Scan() num += s.TokenText() s.Scan() num += s.TokenText() s.Scan() num += s.TokenText() s.Scan() num += s.TokenText() } if isEnd(num) { return nil } } else if white == "" { white = s.TokenText() for s.Peek() == '-' { s.Scan() white += s.TokenText() s.Scan() white += s.TokenText() } for s.Peek() == '/' { s.Scan() white += s.TokenText() s.Scan() white += s.TokenText() s.Scan() white += s.TokenText() s.Scan() white += s.TokenText() s.Scan() white += s.TokenText() s.Scan() white += s.TokenText() } if isEnd(white) { return nil } if s.Peek() == '=' { s.Scan() white += s.TokenText() s.Scan() white += s.TokenText() } move, err := board.MoveFromAlgebraic(white, White) if err != nil { fmt.Println(board) return err } g.Moves = append(g.Moves, move) board.MakeMove(move) } else if black == "" { black = s.TokenText() for s.Peek() == '-' { s.Scan() black += s.TokenText() s.Scan() black += s.TokenText() } for s.Peek() == '/' { s.Scan() black += s.TokenText() s.Scan() black += s.TokenText() s.Scan() black += s.TokenText() s.Scan() black += s.TokenText() s.Scan() black += s.TokenText() s.Scan() black += s.TokenText() } if isEnd(black) { return nil } if s.Peek() == '=' { s.Scan() black += s.TokenText() s.Scan() black += s.TokenText() } move, err := board.MoveFromAlgebraic(black, Black) if err != nil { fmt.Println(board) return err } g.Moves = append(g.Moves, move) board.MakeMove(move) num = "" white = "" black = "" } run = s.Peek() } } return nil }
// regexpMatch tries to match the logic of filepath.Match but // does so using regexp logic. We do this so that we can expand the // wildcard set to include other things, like "**" to mean any number // of directories. This means that we should be backwards compatible // with filepath.Match(). We'll end up supporting more stuff, due to // the fact that we're using regexp, but that's ok - it does no harm. func regexpMatch(pattern, path string) (bool, error) { regStr := "^" // Do some syntax checking on the pattern. // filepath's Match() has some really weird rules that are inconsistent // so instead of trying to dup their logic, just call Match() for its // error state and if there is an error in the pattern return it. // If this becomes an issue we can remove this since its really only // needed in the error (syntax) case - which isn't really critical. if _, err := filepath.Match(pattern, path); err != nil { return false, err } // Go through the pattern and convert it to a regexp. // We use a scanner so we can support utf-8 chars. var scan scanner.Scanner scan.Init(strings.NewReader(pattern)) sl := string(os.PathSeparator) escSL := sl if sl == `\` { escSL += `\` } for scan.Peek() != scanner.EOF { ch := scan.Next() if ch == '*' { if scan.Peek() == '*' { // is some flavor of "**" scan.Next() if scan.Peek() == scanner.EOF { // is "**EOF" - to align with .gitignore just accept all regStr += ".*" } else { // is "**" regStr += "((.*" + escSL + ")|([^" + escSL + "]*))" } // Treat **/ as ** so eat the "/" if string(scan.Peek()) == sl { scan.Next() } } else { // is "*" so map it to anything but "/" regStr += "[^" + escSL + "]*" } } else if ch == '?' { // "?" is any char except "/" regStr += "[^" + escSL + "]" } else if strings.Index(".$", string(ch)) != -1 { // Escape some regexp special chars that have no meaning // in golang's filepath.Match regStr += `\` + string(ch) } else if ch == '\\' { // escape next char. Note that a trailing \ in the pattern // will be left alone (but need to escape it) if sl == `\` { // On windows map "\" to "\\", meaning an escaped backslash, // and then just continue because filepath.Match on // Windows doesn't allow escaping at all regStr += escSL continue } if scan.Peek() != scanner.EOF { regStr += `\` + string(scan.Next()) } else { regStr += `\` } } else { regStr += string(ch) } } regStr += "$" res, err := regexp.MatchString(regStr, path) // Map regexp's error to filepath's so no one knows we're not using filepath if err != nil { err = filepath.ErrBadPattern } return res, err }
func isEOF(in *scanner.Scanner) bool { return in.Peek() == scanner.EOF }