2025-02-12 00:04:30 +01:00
|
|
|
package scanner
|
|
|
|
|
|
|
|
import (
|
2025-02-25 17:16:09 +01:00
|
|
|
"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"
|
2025-02-12 00:04:30 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
// scanFunctionSignature scans a function declaration without the body.
|
|
|
|
func scanFunctionSignature(file *fs.File, tokens token.List, i int, delimiter token.Kind) (*core.Function, int, error) {
|
|
|
|
var (
|
|
|
|
groupLevel = 0
|
|
|
|
nameStart = i
|
|
|
|
paramsStart = -1
|
|
|
|
paramsEnd = -1
|
|
|
|
typeStart = -1
|
|
|
|
typeEnd = -1
|
|
|
|
)
|
|
|
|
|
|
|
|
i++
|
|
|
|
|
|
|
|
// Function parameters
|
|
|
|
for i < len(tokens) {
|
|
|
|
if tokens[i].Kind == token.GroupStart {
|
|
|
|
groupLevel++
|
|
|
|
i++
|
|
|
|
|
|
|
|
if groupLevel == 1 {
|
|
|
|
paramsStart = i
|
|
|
|
}
|
|
|
|
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if tokens[i].Kind == token.GroupEnd {
|
|
|
|
groupLevel--
|
|
|
|
|
|
|
|
if groupLevel < 0 {
|
|
|
|
return nil, i, errors.New(errors.MissingGroupStart, file, tokens[i].Position)
|
|
|
|
}
|
|
|
|
|
|
|
|
if groupLevel == 0 {
|
|
|
|
paramsEnd = i
|
|
|
|
i++
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
i++
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if tokens[i].Kind == token.Invalid {
|
|
|
|
return nil, i, errors.New(&errors.InvalidCharacter{Character: tokens[i].Text(file.Bytes)}, file, tokens[i].Position)
|
|
|
|
}
|
|
|
|
|
|
|
|
if tokens[i].Kind == token.EOF {
|
|
|
|
if groupLevel > 0 {
|
|
|
|
return nil, i, errors.New(errors.MissingGroupEnd, file, tokens[i].Position)
|
|
|
|
}
|
|
|
|
|
|
|
|
if paramsStart == -1 {
|
|
|
|
return nil, i, errors.New(errors.ExpectedFunctionParameters, file, tokens[i].Position)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil, i, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if groupLevel > 0 {
|
|
|
|
i++
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil, i, errors.New(errors.ExpectedFunctionParameters, file, tokens[i].Position)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return type
|
|
|
|
if i < len(tokens) && tokens[i].Kind == token.ReturnType {
|
|
|
|
typeStart = i + 1
|
|
|
|
|
|
|
|
for i < len(tokens) && tokens[i].Kind != delimiter {
|
|
|
|
i++
|
|
|
|
}
|
|
|
|
|
|
|
|
typeEnd = i
|
|
|
|
}
|
|
|
|
|
|
|
|
name := tokens[nameStart].Text(file.Bytes)
|
2025-02-13 16:58:59 +01:00
|
|
|
function := core.NewFunction(file.Package, name, file)
|
2025-02-12 00:04:30 +01:00
|
|
|
|
|
|
|
if typeStart != -1 {
|
|
|
|
if tokens[typeStart].Kind == token.GroupStart && tokens[typeEnd-1].Kind == token.GroupEnd {
|
|
|
|
typeStart++
|
|
|
|
typeEnd--
|
|
|
|
}
|
|
|
|
|
|
|
|
outputTokens := tokens[typeStart:typeEnd]
|
|
|
|
|
|
|
|
err := outputTokens.Split(func(tokens token.List) error {
|
2025-02-12 17:34:48 +01:00
|
|
|
function.Output = append(function.Output, core.NewParameter(tokens))
|
2025-02-12 00:04:30 +01:00
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, i, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
parameters := tokens[paramsStart:paramsEnd]
|
|
|
|
|
|
|
|
err := parameters.Split(func(tokens token.List) error {
|
|
|
|
if len(tokens) == 0 {
|
|
|
|
return errors.New(errors.MissingParameter, file, parameters[0].Position)
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(tokens) == 1 {
|
|
|
|
return errors.New(errors.MissingType, file, tokens[0].End())
|
|
|
|
}
|
|
|
|
|
2025-02-12 17:34:48 +01:00
|
|
|
function.Input = append(function.Input, core.NewParameter(tokens))
|
2025-02-12 00:04:30 +01:00
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
|
|
|
return function, i, err
|
|
|
|
}
|