package scanner import ( "os" "git.urbach.dev/cli/q/src/errors" "git.urbach.dev/cli/q/src/fs" "git.urbach.dev/cli/q/src/token" ) // scanFile scans a single file. func (s *Scanner) scanFile(path string, pkg string) error { contents, err := os.ReadFile(path) if err != nil { return err } tokens := token.Tokenize(contents) file := &fs.File{ Path: path, Bytes: contents, Tokens: tokens, Package: pkg, } s.files <- file for i := 0; i < len(tokens); i++ { switch tokens[i].Kind { case token.NewLine: case token.Comment: case token.Identifier: if i+1 >= len(tokens) { return errors.New(errors.InvalidDefinition, file, tokens[i].End()) } next := tokens[i+1] switch next.Kind { case token.GroupStart: i, err = s.scanFunction(file, tokens, i) case token.BlockStart: i, err = s.scanStruct(file, tokens, i) case token.GroupEnd: return errors.New(errors.MissingGroupStart, file, next.Position) case token.BlockEnd: return errors.New(errors.MissingBlockStart, file, next.Position) case token.Invalid: return errors.New(&errors.InvalidCharacter{Character: next.Text(file.Bytes)}, file, next.Position) default: return errors.New(errors.InvalidDefinition, file, next.Position) } case token.Import: i, err = s.scanImport(file, tokens, i) case token.Extern: i, err = s.scanExtern(file, tokens, i) case token.Const: i, err = s.scanConst(file, tokens, i) case token.EOF: return nil case token.Invalid: return errors.New(&errors.InvalidCharacter{Character: tokens[i].Text(file.Bytes)}, file, tokens[i].Position) default: return errors.New(&errors.InvalidInstruction{Instruction: tokens[i].Text(file.Bytes)}, file, tokens[i].Position) } if err != nil { return err } } return nil }