package scanner import ( "git.urbach.dev/cli/q/src/core" "git.urbach.dev/cli/q/src/errors" "git.urbach.dev/cli/q/src/fs" "git.urbach.dev/cli/q/src/token" ) // scanFunctionSignature scans only the function signature without the body. func scanFunctionSignature(file *fs.File, pkg string, tokens token.List, i int, delimiter token.Kind) (*core.Function, int, error) { var ( groupLevel = 0 nameStart = i inputStart = -1 inputEnd = -1 outputStart = -1 outputEnd = -1 ) i++ // Function parameters for i < len(tokens) { if tokens[i].Kind == token.GroupStart { groupLevel++ i++ if groupLevel == 1 { inputStart = i } continue } if tokens[i].Kind == token.GroupEnd { groupLevel-- if groupLevel < 0 { return nil, i, errors.NewAt(MissingGroupStart, file, tokens[i].Position) } if groupLevel == 0 { inputEnd = i i++ break } i++ continue } if tokens[i].Kind == token.Invalid { return nil, i, errors.NewAt(&InvalidCharacter{Character: tokens[i].StringFrom(file.Bytes)}, file, tokens[i].Position) } if tokens[i].Kind == token.EOF { if groupLevel > 0 { return nil, i, errors.NewAt(MissingGroupEnd, file, tokens[i].Position) } return nil, i, errors.NewAt(InvalidFunctionDefinition, file, tokens[i].Position) } if groupLevel > 0 { i++ continue } return nil, i, errors.NewAt(InvalidFunctionDefinition, file, tokens[i].Position) } // Return type if i < len(tokens) && tokens[i].Kind == token.ReturnType { outputStart = i + 1 for i < len(tokens) && tokens[i].Kind != delimiter { i++ } outputEnd = i } name := tokens[nameStart].StringFrom(file.Bytes) function := core.NewFunction(name, pkg, file) parameters := tokens[inputStart:inputEnd] for position, param := range parameters.Split { if len(param) == 0 { return nil, i, errors.NewAt(MissingParameter, file, position) } if len(param) == 1 { return nil, i, errors.NewAt(MissingParameterType, file, param[0].End()) } if param[0].Kind != token.Identifier { return nil, i, errors.New(InvalidParameterName, file, param[0]) } function.AddInput(param, token.NewSource(position, param[0].End())) } if outputStart == -1 { return function, i, nil } if tokens[outputStart].Kind == token.GroupStart { if tokens[outputEnd-1].Kind == token.GroupEnd { outputStart++ outputEnd-- } else { return nil, i, errors.NewAt(MissingGroupEnd, file, tokens[outputEnd-1].Position) } } outputTokens := tokens[outputStart:outputEnd] if len(outputTokens) == 0 { return nil, i, errors.NewAt(MissingParameter, file, tokens[outputStart].Position) } for position, param := range outputTokens.Split { if len(param) == 0 { return nil, i, errors.NewAt(MissingParameter, file, position) } function.AddOutput(param, token.NewSource(position, param[len(param)-1].End())) } return function, i, nil }