Added compiler and scanner packages
All checks were successful
/ test (push) Successful in 15s

This commit is contained in:
Eduard Urbach 2025-06-19 13:05:55 +02:00
parent f1457af6be
commit e5baba175b
Signed by: akyoto
GPG key ID: 49226B848C78F6C8
12 changed files with 221 additions and 4 deletions

View file

@ -10,6 +10,7 @@ type Build struct {
Files []string
Arch Arch
OS OS
Dry bool
}
// Executable returns the path to the executable.

View file

@ -8,7 +8,7 @@ func Exec(args []string) int {
switch args[0] {
case "build":
return build(args[1:])
return _build(args[1:])
case "run":
return run(args[1:])

View file

@ -11,6 +11,15 @@ func TestExec(t *testing.T) {
assert.Equal(t, cli.Exec(nil), 2)
assert.Equal(t, cli.Exec([]string{"_"}), 2)
assert.Equal(t, cli.Exec([]string{"build"}), 0)
assert.Equal(t, cli.Exec([]string{"run"}), 0)
assert.Equal(t, cli.Exec([]string{"build", "--invalid-parameter"}), 2)
assert.Equal(t, cli.Exec([]string{"build", "../../examples/hello", "--invalid-parameter"}), 2)
assert.Equal(t, cli.Exec([]string{"build", "../../examples/hello", "--dry"}), 0)
assert.Equal(t, cli.Exec([]string{"build", "../../examples/hello", "--dry", "--os", "linux"}), 0)
assert.Equal(t, cli.Exec([]string{"build", "../../examples/hello", "--dry", "--os", "mac"}), 0)
assert.Equal(t, cli.Exec([]string{"build", "../../examples/hello", "--dry", "--os", "windows"}), 0)
assert.Equal(t, cli.Exec([]string{"build", "../../examples/hello", "--dry", "--arch", "arm"}), 0)
assert.Equal(t, cli.Exec([]string{"build", "../../examples/hello", "--dry", "--arch", "x86"}), 0)
assert.Equal(t, cli.Exec([]string{"build", "../../examples/hello/hello.q", "--dry"}), 0)
assert.Equal(t, cli.Exec([]string{"help"}), 0)
assert.Equal(t, cli.Exec([]string{"run"}), 0)
}

View file

@ -1,6 +1,94 @@
package cli
// build parses the arguments and creates a build.
func build(args []string) int {
import (
"runtime"
"strings"
"git.urbach.dev/cli/q/src/build"
"git.urbach.dev/cli/q/src/compiler"
"git.urbach.dev/cli/q/src/scanner"
)
// _build parses the arguments and creates a build.
func _build(args []string) int {
b, err := newBuildFromArgs(args)
if err != nil {
return exit(err)
}
_, err = compiler.Compile(scanner.Scan(b))
if err != nil {
return exit(err)
}
return 0
}
// newBuildFromArgs creates a new build with the given arguments.
func newBuildFromArgs(args []string) (*build.Build, error) {
b := build.New()
for i := 0; i < len(args); i++ {
switch args[i] {
case "--arch":
i++
if i >= len(args) {
return b, &expectedParameterError{Parameter: "arch"}
}
switch args[i] {
case "arm":
b.Arch = build.ARM
case "x86":
b.Arch = build.X86
default:
return b, &invalidValueError{Value: args[i], Parameter: "arch"}
}
case "--dry":
b.Dry = true
case "--os":
i++
if i >= len(args) {
return b, &expectedParameterError{Parameter: "os"}
}
switch args[i] {
case "linux":
b.OS = build.Linux
case "mac":
b.OS = build.Mac
case "windows":
b.OS = build.Windows
default:
return b, &invalidValueError{Value: args[i], Parameter: "os"}
}
default:
if strings.HasPrefix(args[i], "-") {
return b, &unknownParameterError{Parameter: args[i]}
}
b.Files = append(b.Files, args[i])
}
}
if b.OS == build.UnknownOS {
return b, &invalidValueError{Value: runtime.GOOS, Parameter: "os"}
}
if b.Arch == build.UnknownArch {
return b, &invalidValueError{Value: runtime.GOARCH, Parameter: "arch"}
}
if len(b.Files) == 0 {
b.Files = append(b.Files, ".")
}
return b, nil
}

34
src/cli/errors.go Normal file
View file

@ -0,0 +1,34 @@
package cli
import "fmt"
// expectedParameterError is created when a command line parameter is missing.
type expectedParameterError struct {
Parameter string
}
// Error implements the error interface.
func (err *expectedParameterError) Error() string {
return fmt.Sprintf("Expected parameter '%s'", err.Parameter)
}
// invalidValueError is created when a parameter has an invalid value.
type invalidValueError struct {
Value string
Parameter string
}
// Error implements the error interface.
func (err *invalidValueError) Error() string {
return fmt.Sprintf("Invalid value '%s' for parameter '%s'", err.Value, err.Parameter)
}
// unknownParameterError is created when a command line parameter is not recognized.
type unknownParameterError struct {
Parameter string
}
// Error implements the error interface.
func (err *unknownParameterError) Error() string {
return fmt.Sprintf("Unknown parameter '%s'", err.Parameter)
}

30
src/cli/exit.go Normal file
View file

@ -0,0 +1,30 @@
package cli
import (
"errors"
"fmt"
"os"
"os/exec"
)
// exit returns the exit code depending on the error type.
func exit(err error) int {
fmt.Fprintln(os.Stderr, err)
var (
exit *exec.ExitError
expectedParameter *expectedParameterError
unknownParameter *unknownParameterError
invalidValue *invalidValueError
)
if errors.As(err, &exit) {
return exit.ExitCode()
}
if errors.As(err, &expectedParameter) || errors.As(err, &unknownParameter) || errors.As(err, &invalidValue) {
return 2
}
return 1
}

8
src/compiler/Compile.go Normal file
View file

@ -0,0 +1,8 @@
package compiler
import "git.urbach.dev/cli/q/src/scanner"
// Compile waits for the scan to finish and compiles all functions.
func Compile(scan scanner.Result) (Result, error) {
return Result{}, nil
}

View file

@ -0,0 +1,16 @@
package compiler_test
import (
"testing"
"git.urbach.dev/cli/q/src/build"
"git.urbach.dev/cli/q/src/compiler"
"git.urbach.dev/cli/q/src/scanner"
"git.urbach.dev/go/assert"
)
func TestCompile(t *testing.T) {
b := build.New("../../examples/hello")
_, err := compiler.Compile(scanner.Scan(b))
assert.Nil(t, err)
}

4
src/compiler/Result.go Normal file
View file

@ -0,0 +1,4 @@
package compiler
// Result contains everything we need to write an executable file to disk.
type Result struct{}

4
src/scanner/Result.go Normal file
View file

@ -0,0 +1,4 @@
package scanner
// Result contains everything the compiler needs to start a build.
type Result struct{}

10
src/scanner/Scan.go Normal file
View file

@ -0,0 +1,10 @@
package scanner
import (
"git.urbach.dev/cli/q/src/build"
)
// Scan scans all the files included in the build.
func Scan(b *build.Build) Result {
return Result{}
}

13
src/scanner/Scan_test.go Normal file
View file

@ -0,0 +1,13 @@
package scanner_test
import (
"testing"
"git.urbach.dev/cli/q/src/build"
"git.urbach.dev/cli/q/src/scanner"
)
func TestScan(t *testing.T) {
b := build.New("../../examples/hello")
scanner.Scan(b)
}