Implemented extern functions
This commit is contained in:
54
src/scanner/scanExtern.go
Normal file
54
src/scanner/scanExtern.go
Normal file
@ -0,0 +1,54 @@
|
||||
package scanner
|
||||
|
||||
import (
|
||||
"git.akyoto.dev/cli/q/src/errors"
|
||||
"git.akyoto.dev/cli/q/src/fs"
|
||||
"git.akyoto.dev/cli/q/src/token"
|
||||
)
|
||||
|
||||
// scanExtern scans a block of external function declarations.
|
||||
func (s *Scanner) scanExtern(file *fs.File, tokens token.List, i int) (int, error) {
|
||||
i++
|
||||
|
||||
if tokens[i].Kind != token.Identifier {
|
||||
return i, errors.New(errors.ExpectedDLLName, file, tokens[i].Position)
|
||||
}
|
||||
|
||||
dllName := tokens[i].Text(file.Bytes)
|
||||
i++
|
||||
|
||||
if tokens[i].Kind != token.BlockStart {
|
||||
return i, errors.New(errors.MissingBlockStart, file, tokens[i].Position)
|
||||
}
|
||||
|
||||
i++
|
||||
closed := false
|
||||
|
||||
for i < len(tokens) {
|
||||
if tokens[i].Kind == token.Identifier {
|
||||
function, j, err := scanFunctionSignature(file, tokens, i, token.NewLine)
|
||||
|
||||
if err != nil {
|
||||
return j, err
|
||||
}
|
||||
|
||||
i = j
|
||||
function.Package = dllName
|
||||
function.UniqueName = dllName + "." + function.Name
|
||||
s.functions <- function
|
||||
}
|
||||
|
||||
if tokens[i].Kind == token.BlockEnd {
|
||||
closed = true
|
||||
break
|
||||
}
|
||||
|
||||
i++
|
||||
}
|
||||
|
||||
if !closed {
|
||||
return i, errors.New(errors.MissingBlockEnd, file, tokens[i].Position)
|
||||
}
|
||||
|
||||
return i, nil
|
||||
}
|
@ -37,6 +37,8 @@ func (s *Scanner) scanFile(path string, pkg string) error {
|
||||
i, err = s.scanStruct(file, tokens, i)
|
||||
case token.Identifier:
|
||||
i, err = s.scanFunction(file, tokens, i)
|
||||
case token.Extern:
|
||||
i, err = s.scanExtern(file, tokens, i)
|
||||
case token.EOF:
|
||||
return nil
|
||||
case token.Invalid:
|
||||
|
@ -1,7 +1,6 @@
|
||||
package scanner
|
||||
|
||||
import (
|
||||
"git.akyoto.dev/cli/q/src/core"
|
||||
"git.akyoto.dev/cli/q/src/errors"
|
||||
"git.akyoto.dev/cli/q/src/fs"
|
||||
"git.akyoto.dev/cli/q/src/token"
|
||||
@ -9,84 +8,17 @@ import (
|
||||
|
||||
// scanFunction scans a function.
|
||||
func (s *Scanner) scanFunction(file *fs.File, tokens token.List, i int) (int, error) {
|
||||
function, i, err := scanFunctionSignature(file, tokens, i, token.BlockStart)
|
||||
|
||||
if err != nil {
|
||||
return i, err
|
||||
}
|
||||
|
||||
var (
|
||||
groupLevel = 0
|
||||
blockLevel = 0
|
||||
nameStart = i
|
||||
paramsStart = -1
|
||||
paramsEnd = -1
|
||||
bodyStart = -1
|
||||
typeStart = -1
|
||||
typeEnd = -1
|
||||
blockLevel = 0
|
||||
bodyStart = -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 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 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 i, errors.New(errors.MissingGroupEnd, file, tokens[i].Position)
|
||||
}
|
||||
|
||||
if paramsStart == -1 {
|
||||
return i, errors.New(errors.ExpectedFunctionParameters, file, tokens[i].Position)
|
||||
}
|
||||
|
||||
return i, nil
|
||||
}
|
||||
|
||||
if groupLevel > 0 {
|
||||
i++
|
||||
continue
|
||||
}
|
||||
|
||||
return 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 != token.BlockStart {
|
||||
i++
|
||||
}
|
||||
|
||||
typeEnd = i
|
||||
}
|
||||
|
||||
// Function definition
|
||||
for i < len(tokens) {
|
||||
if tokens[i].Kind == token.ReturnType {
|
||||
@ -144,47 +76,7 @@ func (s *Scanner) scanFunction(file *fs.File, tokens token.List, i int) (int, er
|
||||
return i, errors.New(errors.ExpectedFunctionDefinition, file, tokens[i].Position)
|
||||
}
|
||||
|
||||
name := tokens[nameStart].Text(file.Bytes)
|
||||
body := tokens[bodyStart:i]
|
||||
function := core.NewFunction(file.Package, name, file, body)
|
||||
|
||||
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 {
|
||||
function.Output = append(function.Output, core.NewOutput(tokens))
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return 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())
|
||||
}
|
||||
|
||||
function.Input = append(function.Input, core.NewInput(tokens))
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return i, err
|
||||
}
|
||||
|
||||
function.Body = tokens[bodyStart:i]
|
||||
s.functions <- function
|
||||
i++
|
||||
return i, nil
|
||||
|
125
src/scanner/scanFunctionSignature.go
Normal file
125
src/scanner/scanFunctionSignature.go
Normal file
@ -0,0 +1,125 @@
|
||||
package scanner
|
||||
|
||||
import (
|
||||
"git.akyoto.dev/cli/q/src/core"
|
||||
"git.akyoto.dev/cli/q/src/errors"
|
||||
"git.akyoto.dev/cli/q/src/fs"
|
||||
"git.akyoto.dev/cli/q/src/token"
|
||||
)
|
||||
|
||||
// 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)
|
||||
function := core.NewFunction(file.Package, name, file, nil)
|
||||
|
||||
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 {
|
||||
function.Output = append(function.Output, core.NewOutput(tokens))
|
||||
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())
|
||||
}
|
||||
|
||||
function.Input = append(function.Input, core.NewInput(tokens))
|
||||
return nil
|
||||
})
|
||||
|
||||
return function, i, err
|
||||
}
|
Reference in New Issue
Block a user