Added scanner tests
All checks were successful
/ test (push) Successful in 26s

This commit is contained in:
Eduard Urbach 2025-06-20 11:57:43 +02:00
parent c2b8db238e
commit 735246bd38
Signed by: akyoto
GPG key ID: 49226B848C78F6C8
36 changed files with 129 additions and 111 deletions

View file

@ -3,12 +3,13 @@ package compiler
import (
"git.urbach.dev/cli/q/src/build"
"git.urbach.dev/cli/q/src/errors"
"git.urbach.dev/cli/q/src/scanner"
)
// Compile waits for the scan to finish and compiles all functions.
func Compile(b *build.Build) (Result, error) {
result := Result{}
all, err := scan(b)
all, err := scanner.Scan(b)
if err != nil {
return result, err
@ -18,7 +19,6 @@ func Compile(b *build.Build) (Result, error) {
return result, errors.NoInputFiles
}
// Resolve the types
for _, function := range all.Functions {
err := function.ResolveTypes()
@ -27,8 +27,6 @@ func Compile(b *build.Build) (Result, error) {
}
}
// Parallel compilation
compileFunctions(all.Functions)
return result, nil
}

View file

@ -1,47 +0,0 @@
package compiler
import (
"git.urbach.dev/cli/q/src/build"
"git.urbach.dev/cli/q/src/core"
"git.urbach.dev/cli/q/src/fs"
"git.urbach.dev/cli/q/src/scanner"
)
func scan(b *build.Build) (*core.Environment, error) {
functions, files, errs := scanner.Scan(b)
all := &core.Environment{
Files: make([]*fs.File, 0, 8),
Functions: make(map[string]*core.Function, 32),
}
for functions != nil || files != nil || errs != nil {
select {
case f, ok := <-functions:
if !ok {
functions = nil
continue
}
all.Functions[f.String()] = f
case file, ok := <-files:
if !ok {
files = nil
continue
}
all.Files = append(all.Files, file)
case err, ok := <-errs:
if !ok {
errs = nil
continue
}
return all, err
}
}
return all, nil
}

View file

@ -3,7 +3,7 @@ package errors
var (
ExpectedFunctionDefinition = &String{"Expected function definition"}
ExpectedPackageName = &String{"Expected package name"}
InvalidDefinition = &String{"Invalid definition"}
InvalidFunctionDefinition = &String{"Invalid function definition"}
MissingBlockStart = &String{"Missing '{'"}
MissingBlockEnd = &String{"Missing '}'"}
MissingGroupStart = &String{"Missing '('"}

View file

@ -7,7 +7,7 @@ import (
)
// Scan scans all the files included in the build.
func Scan(b *build.Build) (<-chan *core.Function, <-chan *fs.File, <-chan error) {
func Scan(b *build.Build) (*core.Environment, error) {
s := scanner{
functions: make(chan *core.Function),
files: make(chan *fs.File),
@ -23,5 +23,38 @@ func Scan(b *build.Build) (<-chan *core.Function, <-chan *fs.File, <-chan error)
close(s.errors)
}()
return s.functions, s.files, s.errors
all := &core.Environment{
Files: make([]*fs.File, 0, 8),
Functions: make(map[string]*core.Function, 32),
}
for s.functions != nil || s.files != nil || s.errors != nil {
select {
case f, ok := <-s.functions:
if !ok {
s.functions = nil
continue
}
all.Functions[f.String()] = f
case file, ok := <-s.files:
if !ok {
s.files = nil
continue
}
all.Files = append(all.Files, file)
case err, ok := <-s.errors:
if !ok {
s.errors = nil
continue
}
return all, err
}
}
return all, nil
}

View file

@ -4,70 +4,24 @@ import (
"testing"
"git.urbach.dev/cli/q/src/build"
"git.urbach.dev/cli/q/src/core"
"git.urbach.dev/cli/q/src/fs"
"git.urbach.dev/cli/q/src/scanner"
"git.urbach.dev/go/assert"
)
func TestScanDirectory(t *testing.T) {
b := build.New("testdata")
functions, files, errors := scanner.Scan(b)
err := consume(t, functions, files, errors)
assert.Nil(t, err)
}
func TestScanFile(t *testing.T) {
b := build.New("testdata/file.q")
functions, files, errors := scanner.Scan(b)
err := consume(t, functions, files, errors)
assert.Nil(t, err)
}
func TestScanNotExisting(t *testing.T) {
func TestNotExisting(t *testing.T) {
b := build.New("_")
functions, files, errors := scanner.Scan(b)
err := consume(t, functions, files, errors)
_, err := scanner.Scan(b)
assert.NotNil(t, err)
}
func TestMultiPlatform(t *testing.T) {
b := build.New("testdata/platforms")
_, err := scanner.Scan(b)
assert.Nil(t, err)
}
func TestScanHelloExample(t *testing.T) {
b := build.New("../../examples/hello")
functions, files, errors := scanner.Scan(b)
err := consume(t, functions, files, errors)
_, err := scanner.Scan(b)
assert.Nil(t, err)
}
func consume(t *testing.T, functions <-chan *core.Function, files <-chan *fs.File, errors <-chan error) error {
var lastError error
for functions != nil || files != nil || errors != nil {
select {
case function, ok := <-functions:
if !ok {
functions = nil
continue
}
t.Log(function)
case file, ok := <-files:
if !ok {
files = nil
continue
}
t.Log(file)
case err, ok := <-errors:
if !ok {
errors = nil
continue
}
lastError = err
}
}
return lastError
}

View file

@ -0,0 +1,50 @@
package scanner_test
import (
"path/filepath"
"strings"
"testing"
"git.urbach.dev/cli/q/src/build"
"git.urbach.dev/cli/q/src/errors"
"git.urbach.dev/cli/q/src/scanner"
"git.urbach.dev/go/assert"
)
var errs = []struct {
File string
ExpectedError error
}{
{"ExpectedFunctionDefinition.q", errors.ExpectedFunctionDefinition},
{"ExpectedPackageName.q", errors.ExpectedPackageName},
{"InvalidCharacter.q", &errors.InvalidCharacter{Character: "@"}},
{"InvalidCharacter2.q", &errors.InvalidCharacter{Character: "@"}},
{"InvalidCharacter3.q", &errors.InvalidCharacter{Character: "@"}},
{"InvalidCharacter4.q", &errors.InvalidCharacter{Character: "+++"}},
{"InvalidFunctionDefinition.q", errors.InvalidFunctionDefinition},
{"InvalidTopLevel.q", &errors.InvalidTopLevel{Instruction: "123"}},
{"InvalidTopLevel2.q", &errors.InvalidTopLevel{Instruction: "\"Hello\""}},
{"InvalidTopLevel3.q", &errors.InvalidTopLevel{Instruction: "+"}},
{"MissingBlockEnd.q", errors.MissingBlockEnd},
{"MissingBlockEnd2.q", errors.MissingBlockEnd},
{"MissingBlockStart.q", errors.MissingBlockStart},
{"MissingGroupEnd.q", errors.MissingGroupEnd},
{"MissingGroupStart.q", errors.MissingGroupStart},
{"MissingParameter.q", errors.MissingParameter},
{"MissingParameter2.q", errors.MissingParameter},
{"MissingParameter3.q", errors.MissingParameter},
{"MissingType.q", errors.MissingType},
}
func TestErrors(t *testing.T) {
for _, test := range errs {
name := strings.TrimSuffix(test.File, ".q")
t.Run(name, func(t *testing.T) {
b := build.New(filepath.Join("testdata", "errors", test.File))
_, err := scanner.Scan(b)
assert.NotNil(t, err)
assert.Contains(t, err.Error(), test.ExpectedError.Error())
})
}
}

View file

@ -60,7 +60,7 @@ func scanSignature(file *fs.File, tokens token.List, i int, delimiter token.Kind
}
if paramsStart == -1 {
return nil, i, errors.New(errors.InvalidDefinition, file, tokens[i].Position)
return nil, i, errors.New(errors.InvalidFunctionDefinition, file, tokens[i].Position)
}
return nil, i, nil
@ -71,7 +71,7 @@ func scanSignature(file *fs.File, tokens token.List, i int, delimiter token.Kind
continue
}
return nil, i, errors.New(errors.InvalidDefinition, file, tokens[i].Position)
return nil, i, errors.New(errors.InvalidFunctionDefinition, file, tokens[i].Position)
}
// Return type

View file

@ -0,0 +1 @@
main()

View file

@ -0,0 +1 @@
import

View file

@ -0,0 +1 @@
@

View file

@ -0,0 +1 @@
main@

View file

@ -0,0 +1 @@
main()@

View file

@ -0,0 +1,4 @@
main() {
x := 123 +++ 456
syscall(60, x)
}

View file

@ -0,0 +1,3 @@
main() {
if 42 {}
}

View file

@ -0,0 +1,3 @@
main() {
syscall(+, -, *, /)
}

View file

@ -0,0 +1 @@
main

View file

@ -0,0 +1 @@
123

View file

@ -0,0 +1 @@
"Hello"

View file

@ -0,0 +1 @@
+

View file

@ -0,0 +1 @@
main(){

View file

@ -0,0 +1,3 @@
main() {
loop {
}

View file

@ -0,0 +1 @@
main()}

View file

@ -0,0 +1 @@
main(

View file

@ -0,0 +1 @@
main)

View file

@ -0,0 +1 @@
f(,) {}

View file

@ -0,0 +1 @@
f(a int,) -> int { return a }

View file

@ -0,0 +1 @@
f(,a int) {}

View file

@ -0,0 +1 @@
f(a) {}