Moved error types to their respective packages
All checks were successful
/ test (push) Successful in 13s
All checks were successful
/ test (push) Successful in 13s
This commit is contained in:
parent
735246bd38
commit
6dfa7ca00d
19 changed files with 134 additions and 118 deletions
|
@ -1,8 +1,9 @@
|
|||
package compiler
|
||||
|
||||
import (
|
||||
"maps"
|
||||
|
||||
"git.urbach.dev/cli/q/src/build"
|
||||
"git.urbach.dev/cli/q/src/errors"
|
||||
"git.urbach.dev/cli/q/src/scanner"
|
||||
)
|
||||
|
||||
|
@ -16,7 +17,7 @@ func Compile(b *build.Build) (Result, error) {
|
|||
}
|
||||
|
||||
if len(all.Files) == 0 {
|
||||
return result, errors.NoInputFiles
|
||||
return result, NoInputFiles
|
||||
}
|
||||
|
||||
for _, function := range all.Functions {
|
||||
|
@ -27,6 +28,6 @@ func Compile(b *build.Build) (Result, error) {
|
|||
}
|
||||
}
|
||||
|
||||
compileFunctions(all.Functions)
|
||||
compileFunctions(maps.Values(all.Functions))
|
||||
return result, nil
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package compiler_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"git.urbach.dev/cli/q/src/build"
|
||||
|
@ -8,14 +9,21 @@ import (
|
|||
"git.urbach.dev/go/assert"
|
||||
)
|
||||
|
||||
func TestCompile(t *testing.T) {
|
||||
b := build.New("../../examples/hello")
|
||||
_, err := compiler.Compile(b)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
func TestCompileNotExisting(t *testing.T) {
|
||||
func TestNotExisting(t *testing.T) {
|
||||
b := build.New("_")
|
||||
_, err := compiler.Compile(b)
|
||||
assert.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestNoInputFiles(t *testing.T) {
|
||||
b := build.New(".")
|
||||
_, err := compiler.Compile(b)
|
||||
assert.NotNil(t, err)
|
||||
assert.True(t, errors.Is(err, compiler.NoInputFiles))
|
||||
}
|
||||
|
||||
func TestHelloExample(t *testing.T) {
|
||||
b := build.New("../../examples/hello")
|
||||
_, err := compiler.Compile(b)
|
||||
assert.Nil(t, err)
|
||||
}
|
|
@ -1,16 +1,17 @@
|
|||
package compiler
|
||||
|
||||
import (
|
||||
"iter"
|
||||
"sync"
|
||||
|
||||
"git.urbach.dev/cli/q/src/core"
|
||||
)
|
||||
|
||||
// compileFunctions starts a goroutine for each function compilation and waits for completion.
|
||||
func compileFunctions(functions map[string]*core.Function) {
|
||||
func compileFunctions(functions iter.Seq[*core.Function]) {
|
||||
wg := sync.WaitGroup{}
|
||||
|
||||
for _, function := range functions {
|
||||
for function := range functions {
|
||||
if function.IsExtern() {
|
||||
continue
|
||||
}
|
||||
|
|
7
src/compiler/errors.go
Normal file
7
src/compiler/errors.go
Normal file
|
@ -0,0 +1,7 @@
|
|||
package compiler
|
||||
|
||||
import "git.urbach.dev/cli/q/src/errors"
|
||||
|
||||
var (
|
||||
NoInputFiles = errors.String("No input files")
|
||||
)
|
|
@ -1,14 +0,0 @@
|
|||
package errors
|
||||
|
||||
var (
|
||||
ExpectedFunctionDefinition = &String{"Expected function definition"}
|
||||
ExpectedPackageName = &String{"Expected package name"}
|
||||
InvalidFunctionDefinition = &String{"Invalid function definition"}
|
||||
MissingBlockStart = &String{"Missing '{'"}
|
||||
MissingBlockEnd = &String{"Missing '}'"}
|
||||
MissingGroupStart = &String{"Missing '('"}
|
||||
MissingGroupEnd = &String{"Missing ')'"}
|
||||
MissingParameter = &String{"Missing parameter"}
|
||||
MissingType = &String{"Missing type"}
|
||||
NoInputFiles = &String{"No input files"}
|
||||
)
|
|
@ -2,10 +2,10 @@ package errors
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"git.urbach.dev/cli/q/src/fs"
|
||||
"git.urbach.dev/cli/q/src/global"
|
||||
"git.urbach.dev/cli/q/src/token"
|
||||
)
|
||||
|
||||
|
@ -47,13 +47,7 @@ func (e *FileError) LineColumn() (int, int) {
|
|||
|
||||
// Path returns the relative path of the file to shorten the error message.
|
||||
func (e *FileError) Path() string {
|
||||
cwd, err := os.Getwd()
|
||||
|
||||
if err != nil {
|
||||
return e.file.Path
|
||||
}
|
||||
|
||||
relative, err := filepath.Rel(cwd, e.file.Path)
|
||||
relative, err := filepath.Rel(global.WorkingDirectory, e.file.Path)
|
||||
|
||||
if err != nil {
|
||||
return e.file.Path
|
||||
|
|
|
@ -27,6 +27,12 @@ func TestRelativePath(t *testing.T) {
|
|||
assert.Equal(t, err.Path(), relPath)
|
||||
}
|
||||
|
||||
func TestString(t *testing.T) {
|
||||
msg := "Static error"
|
||||
err := errors.String(msg)
|
||||
assert.Equal(t, err.Error(), msg)
|
||||
}
|
||||
|
||||
func test(t *testing.T, path string) *errors.FileError {
|
||||
contents, oserr := os.ReadFile(path)
|
||||
assert.Nil(t, oserr)
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
package errors
|
||||
|
||||
import "fmt"
|
||||
|
||||
// InvalidCharacter is created when an invalid character appears.
|
||||
type InvalidCharacter struct {
|
||||
Character string
|
||||
}
|
||||
|
||||
// Error implements the error interface.
|
||||
func (err *InvalidCharacter) Error() string {
|
||||
return fmt.Sprintf("Invalid character '%s'", err.Character)
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
package errors
|
||||
|
||||
import "fmt"
|
||||
|
||||
// InvalidTopLevel error is created when a top-level instruction is not valid.
|
||||
type InvalidTopLevel struct {
|
||||
Instruction string
|
||||
}
|
||||
|
||||
// Error implements the error interface.
|
||||
func (err *InvalidTopLevel) Error() string {
|
||||
return fmt.Sprintf("Invalid top level instruction '%s'", err.Instruction)
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
package errors
|
||||
|
||||
import "fmt"
|
||||
|
||||
// IsNotDirectory error is created when a path is not a directory.
|
||||
type IsNotDirectory struct {
|
||||
Path string
|
||||
}
|
||||
|
||||
// Error implements the error interface.
|
||||
func (err *IsNotDirectory) Error() string {
|
||||
return fmt.Sprintf("'%s' is not a directory", err.Path)
|
||||
}
|
|
@ -1,11 +1,6 @@
|
|||
package errors
|
||||
|
||||
// String is used for static errors that have no parameters.
|
||||
type String struct {
|
||||
Message string
|
||||
}
|
||||
|
||||
// Error implements the error interface.
|
||||
func (err *String) Error() string {
|
||||
return err.Message
|
||||
// String creates a static error message without parameters.
|
||||
func String(message string) *static {
|
||||
return &static{Message: message}
|
||||
}
|
11
src/errors/static.go
Normal file
11
src/errors/static.go
Normal file
|
@ -0,0 +1,11 @@
|
|||
package errors
|
||||
|
||||
// static is used for static errors that have no parameters.
|
||||
type static struct {
|
||||
Message string
|
||||
}
|
||||
|
||||
// Error implements the error interface.
|
||||
func (err *static) Error() string {
|
||||
return err.Message
|
||||
}
|
|
@ -20,7 +20,7 @@ func TestMultiPlatform(t *testing.T) {
|
|||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
func TestScanHelloExample(t *testing.T) {
|
||||
func TestHelloExample(t *testing.T) {
|
||||
b := build.New("../../examples/hello")
|
||||
_, err := scanner.Scan(b)
|
||||
assert.Nil(t, err)
|
||||
|
|
47
src/scanner/errors.go
Normal file
47
src/scanner/errors.go
Normal file
|
@ -0,0 +1,47 @@
|
|||
package scanner
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.urbach.dev/cli/q/src/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
ExpectedFunctionDefinition = errors.String("Expected function definition")
|
||||
ExpectedPackageName = errors.String("Expected package name")
|
||||
InvalidFunctionDefinition = errors.String("Invalid function definition")
|
||||
MissingBlockStart = errors.String("Missing '{'")
|
||||
MissingBlockEnd = errors.String("Missing '}'")
|
||||
MissingGroupStart = errors.String("Missing '('")
|
||||
MissingGroupEnd = errors.String("Missing ')'")
|
||||
MissingParameter = errors.String("Missing parameter")
|
||||
MissingType = errors.String("Missing type")
|
||||
NoInputFiles = errors.String("No input files")
|
||||
)
|
||||
|
||||
// InvalidCharacter is created when an invalid character appears.
|
||||
type InvalidCharacter struct {
|
||||
Character string
|
||||
}
|
||||
|
||||
func (err *InvalidCharacter) Error() string {
|
||||
return fmt.Sprintf("Invalid character '%s'", err.Character)
|
||||
}
|
||||
|
||||
// InvalidTopLevel error is created when a top-level instruction is not valid.
|
||||
type InvalidTopLevel struct {
|
||||
Instruction string
|
||||
}
|
||||
|
||||
func (err *InvalidTopLevel) Error() string {
|
||||
return fmt.Sprintf("Invalid top level instruction '%s'", err.Instruction)
|
||||
}
|
||||
|
||||
// IsNotDirectory error is created when a path is not a directory.
|
||||
type IsNotDirectory struct {
|
||||
Path string
|
||||
}
|
||||
|
||||
func (err *IsNotDirectory) Error() string {
|
||||
return fmt.Sprintf("'%s' is not a directory", err.Path)
|
||||
}
|
|
@ -6,7 +6,6 @@ import (
|
|||
"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"
|
||||
)
|
||||
|
@ -15,25 +14,25 @@ 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},
|
||||
{"ExpectedFunctionDefinition.q", scanner.ExpectedFunctionDefinition},
|
||||
{"ExpectedPackageName.q", scanner.ExpectedPackageName},
|
||||
{"InvalidCharacter.q", &scanner.InvalidCharacter{Character: "@"}},
|
||||
{"InvalidCharacter2.q", &scanner.InvalidCharacter{Character: "@"}},
|
||||
{"InvalidCharacter3.q", &scanner.InvalidCharacter{Character: "@"}},
|
||||
{"InvalidCharacter4.q", &scanner.InvalidCharacter{Character: "+++"}},
|
||||
{"InvalidFunctionDefinition.q", scanner.InvalidFunctionDefinition},
|
||||
{"InvalidTopLevel.q", &scanner.InvalidTopLevel{Instruction: "123"}},
|
||||
{"InvalidTopLevel2.q", &scanner.InvalidTopLevel{Instruction: "\"Hello\""}},
|
||||
{"InvalidTopLevel3.q", &scanner.InvalidTopLevel{Instruction: "+"}},
|
||||
{"MissingBlockEnd.q", scanner.MissingBlockEnd},
|
||||
{"MissingBlockEnd2.q", scanner.MissingBlockEnd},
|
||||
{"MissingBlockStart.q", scanner.MissingBlockStart},
|
||||
{"MissingGroupEnd.q", scanner.MissingGroupEnd},
|
||||
{"MissingGroupStart.q", scanner.MissingGroupStart},
|
||||
{"MissingParameter.q", scanner.MissingParameter},
|
||||
{"MissingParameter2.q", scanner.MissingParameter},
|
||||
{"MissingParameter3.q", scanner.MissingParameter},
|
||||
{"MissingType.q", scanner.MissingType},
|
||||
}
|
||||
|
||||
func TestErrors(t *testing.T) {
|
||||
|
|
|
@ -38,9 +38,9 @@ func (s *scanner) scanFile(path string, pkg string) error {
|
|||
case token.EOF:
|
||||
return nil
|
||||
case token.Invalid:
|
||||
return errors.New(&errors.InvalidCharacter{Character: tokens[i].String(file.Bytes)}, file, tokens[i].Position)
|
||||
return errors.New(&InvalidCharacter{Character: tokens[i].String(file.Bytes)}, file, tokens[i].Position)
|
||||
default:
|
||||
return errors.New(&errors.InvalidTopLevel{Instruction: tokens[i].String(file.Bytes)}, file, tokens[i].Position)
|
||||
return errors.New(&InvalidTopLevel{Instruction: tokens[i].String(file.Bytes)}, file, tokens[i].Position)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
|
|
@ -36,7 +36,7 @@ func (s *scanner) scanFunction(file *fs.File, tokens token.List, i int) (int, er
|
|||
blockLevel--
|
||||
|
||||
if blockLevel < 0 {
|
||||
return i, errors.New(errors.MissingBlockStart, file, tokens[i].Position)
|
||||
return i, errors.New(MissingBlockStart, file, tokens[i].Position)
|
||||
}
|
||||
|
||||
if blockLevel == 0 {
|
||||
|
@ -48,16 +48,16 @@ func (s *scanner) scanFunction(file *fs.File, tokens token.List, i int) (int, er
|
|||
}
|
||||
|
||||
if tokens[i].Kind == token.Invalid {
|
||||
return i, errors.New(&errors.InvalidCharacter{Character: tokens[i].String(file.Bytes)}, file, tokens[i].Position)
|
||||
return i, errors.New(&InvalidCharacter{Character: tokens[i].String(file.Bytes)}, file, tokens[i].Position)
|
||||
}
|
||||
|
||||
if tokens[i].Kind == token.EOF {
|
||||
if blockLevel > 0 {
|
||||
return i, errors.New(errors.MissingBlockEnd, file, tokens[i].Position)
|
||||
return i, errors.New(MissingBlockEnd, file, tokens[i].Position)
|
||||
}
|
||||
|
||||
if bodyStart == -1 {
|
||||
return i, errors.New(errors.ExpectedFunctionDefinition, file, tokens[i].Position)
|
||||
return i, errors.New(ExpectedFunctionDefinition, file, tokens[i].Position)
|
||||
}
|
||||
|
||||
return i, nil
|
||||
|
@ -68,7 +68,7 @@ func (s *scanner) scanFunction(file *fs.File, tokens token.List, i int) (int, er
|
|||
continue
|
||||
}
|
||||
|
||||
return i, errors.New(errors.ExpectedFunctionDefinition, file, tokens[i].Position)
|
||||
return i, errors.New(ExpectedFunctionDefinition, file, tokens[i].Position)
|
||||
}
|
||||
|
||||
function.Body = tokens[bodyStart:i]
|
||||
|
|
|
@ -15,7 +15,7 @@ func (s *scanner) scanImport(file *fs.File, tokens token.List, i int) (int, erro
|
|||
i++
|
||||
|
||||
if tokens[i].Kind != token.Identifier {
|
||||
return i, errors.New(errors.ExpectedPackageName, file, tokens[i].Position)
|
||||
return i, errors.New(ExpectedPackageName, file, tokens[i].Position)
|
||||
}
|
||||
|
||||
packageName := tokens[i].String(file.Bytes)
|
||||
|
@ -27,7 +27,7 @@ func (s *scanner) scanImport(file *fs.File, tokens token.List, i int) (int, erro
|
|||
}
|
||||
|
||||
if !stat.IsDir() {
|
||||
return i, errors.New(&errors.IsNotDirectory{Path: fullPath}, file, tokens[i].Position)
|
||||
return i, errors.New(&IsNotDirectory{Path: fullPath}, file, tokens[i].Position)
|
||||
}
|
||||
|
||||
s.queueDirectory(fullPath, packageName)
|
||||
|
|
|
@ -37,7 +37,7 @@ func scanSignature(file *fs.File, tokens token.List, i int, delimiter token.Kind
|
|||
groupLevel--
|
||||
|
||||
if groupLevel < 0 {
|
||||
return nil, i, errors.New(errors.MissingGroupStart, file, tokens[i].Position)
|
||||
return nil, i, errors.New(MissingGroupStart, file, tokens[i].Position)
|
||||
}
|
||||
|
||||
if groupLevel == 0 {
|
||||
|
@ -51,16 +51,16 @@ func scanSignature(file *fs.File, tokens token.List, i int, delimiter token.Kind
|
|||
}
|
||||
|
||||
if tokens[i].Kind == token.Invalid {
|
||||
return nil, i, errors.New(&errors.InvalidCharacter{Character: tokens[i].String(file.Bytes)}, file, tokens[i].Position)
|
||||
return nil, i, errors.New(&InvalidCharacter{Character: tokens[i].String(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)
|
||||
return nil, i, errors.New(MissingGroupEnd, file, tokens[i].Position)
|
||||
}
|
||||
|
||||
if paramsStart == -1 {
|
||||
return nil, i, errors.New(errors.InvalidFunctionDefinition, file, tokens[i].Position)
|
||||
return nil, i, errors.New(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.InvalidFunctionDefinition, file, tokens[i].Position)
|
||||
return nil, i, errors.New(InvalidFunctionDefinition, file, tokens[i].Position)
|
||||
}
|
||||
|
||||
// Return type
|
||||
|
@ -91,11 +91,11 @@ func scanSignature(file *fs.File, tokens token.List, i int, delimiter token.Kind
|
|||
|
||||
for param := range parameters.Split {
|
||||
if len(param) == 0 {
|
||||
return nil, i, errors.New(errors.MissingParameter, file, parameters[0].Position)
|
||||
return nil, i, errors.New(MissingParameter, file, parameters[0].Position)
|
||||
}
|
||||
|
||||
if len(param) == 1 {
|
||||
return nil, i, errors.New(errors.MissingType, file, param[0].End())
|
||||
return nil, i, errors.New(MissingType, file, param[0].End())
|
||||
}
|
||||
|
||||
function.Input = append(function.Input, core.NewParameter(param))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue