From 6dfa7ca00d0bbe17a80eb3feec1caa650defc496 Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Fri, 20 Jun 2025 12:46:53 +0200 Subject: [PATCH] Moved error types to their respective packages --- src/compiler/Compile.go | 7 +++-- src/compiler/Compile_test.go | 22 ++++++++++----- src/compiler/compileFunctions.go | 5 ++-- src/compiler/errors.go | 7 +++++ src/errors/Common.go | 14 ---------- src/errors/FileError.go | 10 ++----- src/errors/FileError_test.go | 6 ++++ src/errors/InvalidCharacter.go | 13 --------- src/errors/InvalidTopLevel.go | 13 --------- src/errors/IsNotDirectory.go | 13 --------- src/errors/String.go | 11 ++------ src/errors/static.go | 11 ++++++++ src/scanner/Scan_test.go | 2 +- src/scanner/errors.go | 47 ++++++++++++++++++++++++++++++++ src/scanner/errors_test.go | 39 +++++++++++++------------- src/scanner/scanFile.go | 4 +-- src/scanner/scanFunction.go | 10 +++---- src/scanner/scanImport.go | 4 +-- src/scanner/scanSignature.go | 14 +++++----- 19 files changed, 134 insertions(+), 118 deletions(-) create mode 100644 src/compiler/errors.go delete mode 100644 src/errors/Common.go delete mode 100644 src/errors/InvalidCharacter.go delete mode 100644 src/errors/InvalidTopLevel.go delete mode 100644 src/errors/IsNotDirectory.go create mode 100644 src/errors/static.go create mode 100644 src/scanner/errors.go diff --git a/src/compiler/Compile.go b/src/compiler/Compile.go index eef2adb..ca29c0d 100644 --- a/src/compiler/Compile.go +++ b/src/compiler/Compile.go @@ -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 } \ No newline at end of file diff --git a/src/compiler/Compile_test.go b/src/compiler/Compile_test.go index cb4cafe..789ca11 100644 --- a/src/compiler/Compile_test.go +++ b/src/compiler/Compile_test.go @@ -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) } \ No newline at end of file diff --git a/src/compiler/compileFunctions.go b/src/compiler/compileFunctions.go index adfdf0d..f44dff9 100644 --- a/src/compiler/compileFunctions.go +++ b/src/compiler/compileFunctions.go @@ -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 } diff --git a/src/compiler/errors.go b/src/compiler/errors.go new file mode 100644 index 0000000..f2144c1 --- /dev/null +++ b/src/compiler/errors.go @@ -0,0 +1,7 @@ +package compiler + +import "git.urbach.dev/cli/q/src/errors" + +var ( + NoInputFiles = errors.String("No input files") +) \ No newline at end of file diff --git a/src/errors/Common.go b/src/errors/Common.go deleted file mode 100644 index 8d72ef2..0000000 --- a/src/errors/Common.go +++ /dev/null @@ -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"} -) \ No newline at end of file diff --git a/src/errors/FileError.go b/src/errors/FileError.go index 742a7d0..faab5ed 100644 --- a/src/errors/FileError.go +++ b/src/errors/FileError.go @@ -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 diff --git a/src/errors/FileError_test.go b/src/errors/FileError_test.go index 96b8f75..607ec9c 100644 --- a/src/errors/FileError_test.go +++ b/src/errors/FileError_test.go @@ -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) diff --git a/src/errors/InvalidCharacter.go b/src/errors/InvalidCharacter.go deleted file mode 100644 index d5d742a..0000000 --- a/src/errors/InvalidCharacter.go +++ /dev/null @@ -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) -} \ No newline at end of file diff --git a/src/errors/InvalidTopLevel.go b/src/errors/InvalidTopLevel.go deleted file mode 100644 index 962b47b..0000000 --- a/src/errors/InvalidTopLevel.go +++ /dev/null @@ -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) -} \ No newline at end of file diff --git a/src/errors/IsNotDirectory.go b/src/errors/IsNotDirectory.go deleted file mode 100644 index 18a1582..0000000 --- a/src/errors/IsNotDirectory.go +++ /dev/null @@ -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) -} \ No newline at end of file diff --git a/src/errors/String.go b/src/errors/String.go index c283b37..78b15fa 100644 --- a/src/errors/String.go +++ b/src/errors/String.go @@ -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} } \ No newline at end of file diff --git a/src/errors/static.go b/src/errors/static.go new file mode 100644 index 0000000..3d154f2 --- /dev/null +++ b/src/errors/static.go @@ -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 +} \ No newline at end of file diff --git a/src/scanner/Scan_test.go b/src/scanner/Scan_test.go index 407b63a..0e1d22f 100644 --- a/src/scanner/Scan_test.go +++ b/src/scanner/Scan_test.go @@ -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) diff --git a/src/scanner/errors.go b/src/scanner/errors.go new file mode 100644 index 0000000..aa92adf --- /dev/null +++ b/src/scanner/errors.go @@ -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) +} \ No newline at end of file diff --git a/src/scanner/errors_test.go b/src/scanner/errors_test.go index c98f1b8..e1661e8 100644 --- a/src/scanner/errors_test.go +++ b/src/scanner/errors_test.go @@ -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) { diff --git a/src/scanner/scanFile.go b/src/scanner/scanFile.go index 30937be..35e0784 100644 --- a/src/scanner/scanFile.go +++ b/src/scanner/scanFile.go @@ -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 { diff --git a/src/scanner/scanFunction.go b/src/scanner/scanFunction.go index 289e875..6f3c822 100644 --- a/src/scanner/scanFunction.go +++ b/src/scanner/scanFunction.go @@ -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] diff --git a/src/scanner/scanImport.go b/src/scanner/scanImport.go index 6d142c7..07c0271 100644 --- a/src/scanner/scanImport.go +++ b/src/scanner/scanImport.go @@ -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) diff --git a/src/scanner/scanSignature.go b/src/scanner/scanSignature.go index e62e3cc..efa2fcf 100644 --- a/src/scanner/scanSignature.go +++ b/src/scanner/scanSignature.go @@ -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))