Moved error types to their respective packages
All checks were successful
/ test (push) Successful in 13s

This commit is contained in:
Eduard Urbach 2025-06-20 12:46:53 +02:00
parent 735246bd38
commit 6dfa7ca00d
Signed by: akyoto
GPG key ID: 49226B848C78F6C8
19 changed files with 134 additions and 118 deletions

View file

@ -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
}

View file

@ -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)
}

View file

@ -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
View file

@ -0,0 +1,7 @@
package compiler
import "git.urbach.dev/cli/q/src/errors"
var (
NoInputFiles = errors.String("No input files")
)

View file

@ -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"}
)

View file

@ -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

View file

@ -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)

View file

@ -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)
}

View file

@ -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)
}

View file

@ -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)
}

View file

@ -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
View 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
}

View file

@ -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
View 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)
}

View file

@ -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) {

View file

@ -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 {

View file

@ -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]

View file

@ -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)

View file

@ -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))