This commit is contained in:
parent
c2b8db238e
commit
735246bd38
36 changed files with 129 additions and 111 deletions
|
@ -3,12 +3,13 @@ package compiler
|
||||||
import (
|
import (
|
||||||
"git.urbach.dev/cli/q/src/build"
|
"git.urbach.dev/cli/q/src/build"
|
||||||
"git.urbach.dev/cli/q/src/errors"
|
"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.
|
// Compile waits for the scan to finish and compiles all functions.
|
||||||
func Compile(b *build.Build) (Result, error) {
|
func Compile(b *build.Build) (Result, error) {
|
||||||
result := Result{}
|
result := Result{}
|
||||||
all, err := scan(b)
|
all, err := scanner.Scan(b)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return result, err
|
return result, err
|
||||||
|
@ -18,7 +19,6 @@ func Compile(b *build.Build) (Result, error) {
|
||||||
return result, errors.NoInputFiles
|
return result, errors.NoInputFiles
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve the types
|
|
||||||
for _, function := range all.Functions {
|
for _, function := range all.Functions {
|
||||||
err := function.ResolveTypes()
|
err := function.ResolveTypes()
|
||||||
|
|
||||||
|
@ -27,8 +27,6 @@ func Compile(b *build.Build) (Result, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parallel compilation
|
|
||||||
compileFunctions(all.Functions)
|
compileFunctions(all.Functions)
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
|
@ -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
|
|
||||||
}
|
|
|
@ -3,7 +3,7 @@ package errors
|
||||||
var (
|
var (
|
||||||
ExpectedFunctionDefinition = &String{"Expected function definition"}
|
ExpectedFunctionDefinition = &String{"Expected function definition"}
|
||||||
ExpectedPackageName = &String{"Expected package name"}
|
ExpectedPackageName = &String{"Expected package name"}
|
||||||
InvalidDefinition = &String{"Invalid definition"}
|
InvalidFunctionDefinition = &String{"Invalid function definition"}
|
||||||
MissingBlockStart = &String{"Missing '{'"}
|
MissingBlockStart = &String{"Missing '{'"}
|
||||||
MissingBlockEnd = &String{"Missing '}'"}
|
MissingBlockEnd = &String{"Missing '}'"}
|
||||||
MissingGroupStart = &String{"Missing '('"}
|
MissingGroupStart = &String{"Missing '('"}
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Scan scans all the files included in the build.
|
// 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{
|
s := scanner{
|
||||||
functions: make(chan *core.Function),
|
functions: make(chan *core.Function),
|
||||||
files: make(chan *fs.File),
|
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)
|
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
|
||||||
}
|
}
|
|
@ -4,70 +4,24 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.urbach.dev/cli/q/src/build"
|
"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/cli/q/src/scanner"
|
||||||
"git.urbach.dev/go/assert"
|
"git.urbach.dev/go/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestScanDirectory(t *testing.T) {
|
func TestNotExisting(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) {
|
|
||||||
b := build.New("_")
|
b := build.New("_")
|
||||||
functions, files, errors := scanner.Scan(b)
|
_, err := scanner.Scan(b)
|
||||||
err := consume(t, functions, files, errors)
|
|
||||||
assert.NotNil(t, err)
|
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) {
|
func TestScanHelloExample(t *testing.T) {
|
||||||
b := build.New("../../examples/hello")
|
b := build.New("../../examples/hello")
|
||||||
functions, files, errors := scanner.Scan(b)
|
_, err := scanner.Scan(b)
|
||||||
err := consume(t, functions, files, errors)
|
|
||||||
assert.Nil(t, err)
|
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
|
|
||||||
}
|
}
|
50
src/scanner/errors_test.go
Normal file
50
src/scanner/errors_test.go
Normal 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())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -60,7 +60,7 @@ func scanSignature(file *fs.File, tokens token.List, i int, delimiter token.Kind
|
||||||
}
|
}
|
||||||
|
|
||||||
if paramsStart == -1 {
|
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
|
return nil, i, nil
|
||||||
|
@ -71,7 +71,7 @@ func scanSignature(file *fs.File, tokens token.List, i int, delimiter token.Kind
|
||||||
continue
|
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
|
// Return type
|
||||||
|
|
1
src/scanner/testdata/errors/ExpectedFunctionDefinition.q
vendored
Normal file
1
src/scanner/testdata/errors/ExpectedFunctionDefinition.q
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
main()
|
1
src/scanner/testdata/errors/ExpectedPackageName.q
vendored
Normal file
1
src/scanner/testdata/errors/ExpectedPackageName.q
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
import
|
1
src/scanner/testdata/errors/InvalidCharacter.q
vendored
Normal file
1
src/scanner/testdata/errors/InvalidCharacter.q
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
@
|
1
src/scanner/testdata/errors/InvalidCharacter2.q
vendored
Normal file
1
src/scanner/testdata/errors/InvalidCharacter2.q
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
main@
|
1
src/scanner/testdata/errors/InvalidCharacter3.q
vendored
Normal file
1
src/scanner/testdata/errors/InvalidCharacter3.q
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
main()@
|
4
src/scanner/testdata/errors/InvalidCharacter4.q
vendored
Normal file
4
src/scanner/testdata/errors/InvalidCharacter4.q
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
main() {
|
||||||
|
x := 123 +++ 456
|
||||||
|
syscall(60, x)
|
||||||
|
}
|
3
src/scanner/testdata/errors/InvalidCondition.q
vendored
Normal file
3
src/scanner/testdata/errors/InvalidCondition.q
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
main() {
|
||||||
|
if 42 {}
|
||||||
|
}
|
3
src/scanner/testdata/errors/InvalidExpression.q
vendored
Normal file
3
src/scanner/testdata/errors/InvalidExpression.q
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
main() {
|
||||||
|
syscall(+, -, *, /)
|
||||||
|
}
|
1
src/scanner/testdata/errors/InvalidFunctionDefinition.q
vendored
Normal file
1
src/scanner/testdata/errors/InvalidFunctionDefinition.q
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
main
|
1
src/scanner/testdata/errors/InvalidTopLevel.q
vendored
Normal file
1
src/scanner/testdata/errors/InvalidTopLevel.q
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
123
|
1
src/scanner/testdata/errors/InvalidTopLevel2.q
vendored
Normal file
1
src/scanner/testdata/errors/InvalidTopLevel2.q
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
"Hello"
|
1
src/scanner/testdata/errors/InvalidTopLevel3.q
vendored
Normal file
1
src/scanner/testdata/errors/InvalidTopLevel3.q
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
+
|
1
src/scanner/testdata/errors/MissingBlockEnd.q
vendored
Normal file
1
src/scanner/testdata/errors/MissingBlockEnd.q
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
main(){
|
3
src/scanner/testdata/errors/MissingBlockEnd2.q
vendored
Normal file
3
src/scanner/testdata/errors/MissingBlockEnd2.q
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
main() {
|
||||||
|
loop {
|
||||||
|
}
|
1
src/scanner/testdata/errors/MissingBlockStart.q
vendored
Normal file
1
src/scanner/testdata/errors/MissingBlockStart.q
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
main()}
|
1
src/scanner/testdata/errors/MissingGroupEnd.q
vendored
Normal file
1
src/scanner/testdata/errors/MissingGroupEnd.q
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
main(
|
1
src/scanner/testdata/errors/MissingGroupStart.q
vendored
Normal file
1
src/scanner/testdata/errors/MissingGroupStart.q
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
main)
|
1
src/scanner/testdata/errors/MissingParameter.q
vendored
Normal file
1
src/scanner/testdata/errors/MissingParameter.q
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
f(,) {}
|
1
src/scanner/testdata/errors/MissingParameter2.q
vendored
Normal file
1
src/scanner/testdata/errors/MissingParameter2.q
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
f(a int,) -> int { return a }
|
1
src/scanner/testdata/errors/MissingParameter3.q
vendored
Normal file
1
src/scanner/testdata/errors/MissingParameter3.q
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
f(,a int) {}
|
1
src/scanner/testdata/errors/MissingType.q
vendored
Normal file
1
src/scanner/testdata/errors/MissingType.q
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
f(a) {}
|
Loading…
Add table
Add a link
Reference in a new issue