diff --git a/src/compiler/Compile.go b/src/compiler/Compile.go index 5dea2cd..eef2adb 100644 --- a/src/compiler/Compile.go +++ b/src/compiler/Compile.go @@ -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 } \ No newline at end of file diff --git a/src/compiler/scan.go b/src/compiler/scan.go deleted file mode 100644 index 95c2d40..0000000 --- a/src/compiler/scan.go +++ /dev/null @@ -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 -} \ No newline at end of file diff --git a/src/errors/Common.go b/src/errors/Common.go index 71ceb0f..8d72ef2 100644 --- a/src/errors/Common.go +++ b/src/errors/Common.go @@ -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 '('"} diff --git a/src/scanner/Scan.go b/src/scanner/Scan.go index 710dddf..d46798b 100644 --- a/src/scanner/Scan.go +++ b/src/scanner/Scan.go @@ -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 } \ No newline at end of file diff --git a/src/scanner/Scan_test.go b/src/scanner/Scan_test.go index 1066652..407b63a 100644 --- a/src/scanner/Scan_test.go +++ b/src/scanner/Scan_test.go @@ -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 } \ No newline at end of file diff --git a/src/scanner/errors_test.go b/src/scanner/errors_test.go new file mode 100644 index 0000000..c98f1b8 --- /dev/null +++ b/src/scanner/errors_test.go @@ -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()) + }) + } +} \ No newline at end of file diff --git a/src/scanner/scanSignature.go b/src/scanner/scanSignature.go index 4ec6ffb..e62e3cc 100644 --- a/src/scanner/scanSignature.go +++ b/src/scanner/scanSignature.go @@ -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 diff --git a/src/scanner/testdata/errors/ExpectedFunctionDefinition.q b/src/scanner/testdata/errors/ExpectedFunctionDefinition.q new file mode 100644 index 0000000..ac72fa7 --- /dev/null +++ b/src/scanner/testdata/errors/ExpectedFunctionDefinition.q @@ -0,0 +1 @@ +main() \ No newline at end of file diff --git a/src/scanner/testdata/errors/ExpectedPackageName.q b/src/scanner/testdata/errors/ExpectedPackageName.q new file mode 100644 index 0000000..efca996 --- /dev/null +++ b/src/scanner/testdata/errors/ExpectedPackageName.q @@ -0,0 +1 @@ +import \ No newline at end of file diff --git a/src/scanner/testdata/errors/InvalidCharacter.q b/src/scanner/testdata/errors/InvalidCharacter.q new file mode 100644 index 0000000..b516b2c --- /dev/null +++ b/src/scanner/testdata/errors/InvalidCharacter.q @@ -0,0 +1 @@ +@ \ No newline at end of file diff --git a/src/scanner/testdata/errors/InvalidCharacter2.q b/src/scanner/testdata/errors/InvalidCharacter2.q new file mode 100644 index 0000000..f870343 --- /dev/null +++ b/src/scanner/testdata/errors/InvalidCharacter2.q @@ -0,0 +1 @@ +main@ \ No newline at end of file diff --git a/src/scanner/testdata/errors/InvalidCharacter3.q b/src/scanner/testdata/errors/InvalidCharacter3.q new file mode 100644 index 0000000..5f777b8 --- /dev/null +++ b/src/scanner/testdata/errors/InvalidCharacter3.q @@ -0,0 +1 @@ +main()@ \ No newline at end of file diff --git a/src/scanner/testdata/errors/InvalidCharacter4.q b/src/scanner/testdata/errors/InvalidCharacter4.q new file mode 100644 index 0000000..a97c489 --- /dev/null +++ b/src/scanner/testdata/errors/InvalidCharacter4.q @@ -0,0 +1,4 @@ +main() { + x := 123 +++ 456 + syscall(60, x) +} \ No newline at end of file diff --git a/src/scanner/testdata/errors/InvalidCondition.q b/src/scanner/testdata/errors/InvalidCondition.q new file mode 100644 index 0000000..8d76be8 --- /dev/null +++ b/src/scanner/testdata/errors/InvalidCondition.q @@ -0,0 +1,3 @@ +main() { + if 42 {} +} \ No newline at end of file diff --git a/src/scanner/testdata/errors/InvalidExpression.q b/src/scanner/testdata/errors/InvalidExpression.q new file mode 100644 index 0000000..77e99f8 --- /dev/null +++ b/src/scanner/testdata/errors/InvalidExpression.q @@ -0,0 +1,3 @@ +main() { + syscall(+, -, *, /) +} \ No newline at end of file diff --git a/src/scanner/testdata/errors/InvalidFunctionDefinition.q b/src/scanner/testdata/errors/InvalidFunctionDefinition.q new file mode 100644 index 0000000..88d050b --- /dev/null +++ b/src/scanner/testdata/errors/InvalidFunctionDefinition.q @@ -0,0 +1 @@ +main \ No newline at end of file diff --git a/src/scanner/testdata/errors/InvalidTopLevel.q b/src/scanner/testdata/errors/InvalidTopLevel.q new file mode 100644 index 0000000..d800886 --- /dev/null +++ b/src/scanner/testdata/errors/InvalidTopLevel.q @@ -0,0 +1 @@ +123 \ No newline at end of file diff --git a/src/scanner/testdata/errors/InvalidTopLevel2.q b/src/scanner/testdata/errors/InvalidTopLevel2.q new file mode 100644 index 0000000..5638d8b --- /dev/null +++ b/src/scanner/testdata/errors/InvalidTopLevel2.q @@ -0,0 +1 @@ +"Hello" \ No newline at end of file diff --git a/src/scanner/testdata/errors/InvalidTopLevel3.q b/src/scanner/testdata/errors/InvalidTopLevel3.q new file mode 100644 index 0000000..9b26e9b --- /dev/null +++ b/src/scanner/testdata/errors/InvalidTopLevel3.q @@ -0,0 +1 @@ ++ \ No newline at end of file diff --git a/src/scanner/testdata/errors/MissingBlockEnd.q b/src/scanner/testdata/errors/MissingBlockEnd.q new file mode 100644 index 0000000..48a9f79 --- /dev/null +++ b/src/scanner/testdata/errors/MissingBlockEnd.q @@ -0,0 +1 @@ +main(){ \ No newline at end of file diff --git a/src/scanner/testdata/errors/MissingBlockEnd2.q b/src/scanner/testdata/errors/MissingBlockEnd2.q new file mode 100644 index 0000000..5562918 --- /dev/null +++ b/src/scanner/testdata/errors/MissingBlockEnd2.q @@ -0,0 +1,3 @@ +main() { + loop { +} \ No newline at end of file diff --git a/src/scanner/testdata/errors/MissingBlockStart.q b/src/scanner/testdata/errors/MissingBlockStart.q new file mode 100644 index 0000000..006988a --- /dev/null +++ b/src/scanner/testdata/errors/MissingBlockStart.q @@ -0,0 +1 @@ +main()} \ No newline at end of file diff --git a/src/scanner/testdata/errors/MissingGroupEnd.q b/src/scanner/testdata/errors/MissingGroupEnd.q new file mode 100644 index 0000000..189300d --- /dev/null +++ b/src/scanner/testdata/errors/MissingGroupEnd.q @@ -0,0 +1 @@ +main( \ No newline at end of file diff --git a/src/scanner/testdata/errors/MissingGroupStart.q b/src/scanner/testdata/errors/MissingGroupStart.q new file mode 100644 index 0000000..83e9712 --- /dev/null +++ b/src/scanner/testdata/errors/MissingGroupStart.q @@ -0,0 +1 @@ +main) \ No newline at end of file diff --git a/src/scanner/testdata/errors/MissingParameter.q b/src/scanner/testdata/errors/MissingParameter.q new file mode 100644 index 0000000..a3247e3 --- /dev/null +++ b/src/scanner/testdata/errors/MissingParameter.q @@ -0,0 +1 @@ +f(,) {} \ No newline at end of file diff --git a/src/scanner/testdata/errors/MissingParameter2.q b/src/scanner/testdata/errors/MissingParameter2.q new file mode 100644 index 0000000..827b8d8 --- /dev/null +++ b/src/scanner/testdata/errors/MissingParameter2.q @@ -0,0 +1 @@ +f(a int,) -> int { return a } \ No newline at end of file diff --git a/src/scanner/testdata/errors/MissingParameter3.q b/src/scanner/testdata/errors/MissingParameter3.q new file mode 100644 index 0000000..839bf40 --- /dev/null +++ b/src/scanner/testdata/errors/MissingParameter3.q @@ -0,0 +1 @@ +f(,a int) {} \ No newline at end of file diff --git a/src/scanner/testdata/errors/MissingType.q b/src/scanner/testdata/errors/MissingType.q new file mode 100644 index 0000000..214c35e --- /dev/null +++ b/src/scanner/testdata/errors/MissingType.q @@ -0,0 +1 @@ +f(a) {} \ No newline at end of file diff --git a/src/scanner/testdata/file.q b/src/scanner/testdata/platforms/file.q similarity index 100% rename from src/scanner/testdata/file.q rename to src/scanner/testdata/platforms/file.q diff --git a/src/scanner/testdata/file_arm.q b/src/scanner/testdata/platforms/file_arm.q similarity index 100% rename from src/scanner/testdata/file_arm.q rename to src/scanner/testdata/platforms/file_arm.q diff --git a/src/scanner/testdata/file_custom.q b/src/scanner/testdata/platforms/file_custom.q similarity index 100% rename from src/scanner/testdata/file_custom.q rename to src/scanner/testdata/platforms/file_custom.q diff --git a/src/scanner/testdata/file_linux.q b/src/scanner/testdata/platforms/file_linux.q similarity index 100% rename from src/scanner/testdata/file_linux.q rename to src/scanner/testdata/platforms/file_linux.q diff --git a/src/scanner/testdata/file_mac.q b/src/scanner/testdata/platforms/file_mac.q similarity index 100% rename from src/scanner/testdata/file_mac.q rename to src/scanner/testdata/platforms/file_mac.q diff --git a/src/scanner/testdata/file_unix.q b/src/scanner/testdata/platforms/file_unix.q similarity index 100% rename from src/scanner/testdata/file_unix.q rename to src/scanner/testdata/platforms/file_unix.q diff --git a/src/scanner/testdata/file_windows.q b/src/scanner/testdata/platforms/file_windows.q similarity index 100% rename from src/scanner/testdata/file_windows.q rename to src/scanner/testdata/platforms/file_windows.q diff --git a/src/scanner/testdata/file_x86.q b/src/scanner/testdata/platforms/file_x86.q similarity index 100% rename from src/scanner/testdata/file_x86.q rename to src/scanner/testdata/platforms/file_x86.q