func Example() { const src = ` // This is scanned code. if a > 10 { someParsable = text }` var s scanner.Scanner s.Filename = "example" s.Init(strings.NewReader(src)) var tok rune for tok != scanner.EOF { tok = s.Scan() fmt.Println("At position", s.Pos(), ":", s.TokenText()) } // Output: // At position example:3:4 : if // At position example:3:6 : a // At position example:3:8 : > // At position example:3:11 : 10 // At position example:3:13 : { // At position example:4:15 : someParsable // At position example:4:17 : = // At position example:4:22 : text // At position example:5:3 : } // At position example:5:3 : }
func resolveImportsRec(asts []ast, path string, imported []string, download bool) ([]ast, error) { var newAsts []ast top := true // Imports are required to be at the top of the file. for _, ast := range asts { name := parseImport(ast) if name == "" { newAsts = append(newAsts, ast) top = false continue } if !top { return nil, errors.New("import must be begin the module") } // Check for any import cycles. for _, importedModule := range imported { if name == importedModule { return nil, fmt.Errorf("import cycle: %s", append(imported, name)) } } modulePath := filepath.Join(path, name+".spec") var sc scanner.Scanner sc.Filename = modulePath if _, err := os.Stat(modulePath); os.IsNotExist(err) && download { GetSpec(name) } f, err := util.Open(modulePath) if err != nil { return nil, fmt.Errorf("unable to open import %s", name) } defer f.Close() sc.Init(bufio.NewReader(f)) parsed, err := parse(sc) if err != nil { return nil, err } // Rename module name to last name in import path name = filepath.Base(name) parsed, err = resolveImportsRec(parsed, path, append(imported, name), download) if err != nil { return nil, err } module := astModule{body: parsed, moduleName: astString(name)} newAsts = append(newAsts, module) } return newAsts, nil }
func newLexer(stream io.Reader, fn string) *lexer { var s scanner.Scanner s.Init(stream) s.Whitespace = 1<<'\t' | 1<<'\n' | 1<<'\r' | 1<<' ' s.Filename = fn return &lexer{ scanner: s, } }
func parsePo(r io.Reader, filename string) (*Po, error) { comment := false s := new(scanner.Scanner) var err error s.Init(r) s.Filename = filename s.Error = func(s *scanner.Scanner, msg string) { if !comment { err = fmt.Errorf("error parsing %s: %s", s.Pos(), msg) } } s.Mode = scanner.ScanIdents | scanner.ScanStrings | scanner.ScanInts tok := s.Scan() po := &Po{Attrs: make(map[string]string)} var trans *Translation for tok != scanner.EOF && err == nil { if tok == '#' { // Skip until EOL comment = true s.Whitespace = whitespace for tok != '\n' && tok != scanner.EOF { tok = s.Scan() } s.Whitespace = scanner.GoWhitespace comment = false tok = s.Scan() continue } if tok != scanner.Ident { err = unexpected(s, tok) break } text := s.TokenText() switch text { case "msgctxt": if trans != nil { if len(trans.Translations) == 0 { err = unexpected(s, tok) break } po.addTranslation(trans) } trans = &Translation{Context: readString(s, &tok, &err)} case "msgid": if trans != nil { if len(trans.Translations) > 0 || trans.Singular != "" { po.addTranslation(trans) } else if trans.Context != "" { trans.Singular = readString(s, &tok, &err) break } } trans = &Translation{Singular: readString(s, &tok, &err)} case "msgid_plural": if trans == nil || trans.Plural != "" { err = unexpected(s, tok) break } trans.Plural = readString(s, &tok, &err) case "msgstr": str := readString(s, &tok, &err) if tok == '[' { tok = s.Scan() if tok != scanner.Int { err = unexpected(s, tok) break } ii, _ := strconv.Atoi(s.TokenText()) if ii != len(trans.Translations) { err = unexpected(s, tok) break } if tok = s.Scan(); tok != ']' { err = unexpected(s, tok) break } str = readString(s, &tok, &err) } trans.Translations = append(trans.Translations, str) default: err = unexpected(s, tok) } } if trans != nil { po.addTranslation(trans) } if err != nil { return nil, err } for _, v := range po.Messages { if v.Context == "" && v.Singular == "" { if len(v.Translations) > 0 { meta := v.Translations[0] for _, line := range strings.Split(meta, "\n") { colon := strings.Index(line, ":") if colon > 0 { key := strings.TrimSpace(line[:colon]) value := strings.TrimSpace(line[colon+1:]) po.Attrs[key] = value } } } break } } return po, nil }