diff --git a/arguments/arguments.go b/arguments/arguments.go new file mode 100644 index 0000000000000000000000000000000000000000..f28634dfb8936ec7d5b29de15798d4477318716e --- /dev/null +++ b/arguments/arguments.go @@ -0,0 +1,84 @@ +// Copyright 2020 Tymoteusz Blazejczyk +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package arguments + +import ( + "errors" + "os" + "path/filepath" + + "github.com/alexflint/go-arg" + "gitlab.com/tymonx/go-error/rterror" + "gitlab.com/tymonx/xlogic-toolchain/define" + "gitlab.com/tymonx/xlogic-toolchain/file" + "gitlab.com/tymonx/xlogic-toolchain/header" + "gitlab.com/tymonx/xlogic-toolchain/include" + "gitlab.com/tymonx/xlogic-toolchain/mode" + "gitlab.com/tymonx/xlogic-toolchain/path" + "gitlab.com/tymonx/xlogic-toolchain/undefine" +) + +// These constants define default values for compiler arguments. +const ( + DefaultOutput = "output.json" + DefaultMode = mode.Executable + DefaultProgramName = "xlogic-compiler" +) + +// Arguments defines compiler arguments. +type Arguments struct { + Append bool `arg:"-a,--append" help:"Append file"` + Mode mode.Mode `arg:"-m,--mode" help:"Compiler mode: object, archive, library, executable" default:"executable"` + Output path.Path `arg:"-o,--output" help:"Place output in file" default:"output.json" placeholder:"FILE"` + Defines []define.Define `arg:"-D,--define,separate" help:"Set preprocessor define" placeholder:"NAME[=VALUE]"` + Undefines []undefine.Undefine `arg:"-U,--undefine,separate" help:"Unset preprocessor define" placeholder:"NAME"` + Headers []header.Header `arg:"-H,--header,separate" help:"Include header file" placeholder:"FILE"` + Includes []include.Include `arg:"-I,--include,separate" help:"Directory to search for includes" placeholder:"DIR"` + Files []file.File `arg:"positional" help:"Input files" placeholder:"FILE"` +} + +// New creates a new compiler arguments object. +func New() *Arguments { + return &Arguments{ + Mode: DefaultMode, + Output: DefaultOutput, + } +} + +// Parse parses arguments. +func (a *Arguments) Parse(args ...string) (err error) { + var parser *arg.Parser + + config := arg.Config{} + + if len(args) == 0 { + args = os.Args[1:] + config.Program = filepath.Base(os.Args[0]) + } else { + config.Program = DefaultProgramName + } + + if parser, err = arg.NewParser(arg.Config{}, a); err != nil { + return rterror.New("error occurred while creating parser", err) + } + + if err = parser.Parse(args); errors.Is(err, arg.ErrHelp) { + parser.WriteHelp(os.Stdout) + } else if err != nil { + return rterror.New("error occurred while parsing arguments", err) + } + + return nil +} diff --git a/cmd/xlogic-compiler/main.go b/cmd/xlogic-compiler/main.go index 9e5d8e398730dc7b568613194d5b3cf96674cfbe..550ec904cf5d978ae7a9e47bf2b5e68090e8c9c6 100644 --- a/cmd/xlogic-compiler/main.go +++ b/cmd/xlogic-compiler/main.go @@ -15,199 +15,45 @@ package main import ( - "flag" - "fmt" - "os" - "path/filepath" - - "gitlab.com/tymonx/xlogic-toolchain/cerr" - "gitlab.com/tymonx/xlogic-toolchain/option" - "gitlab.com/tymonx/xlogic-toolchain/path" - "gitlab.com/tymonx/xlogic-toolchain/resource" - "gitlab.com/tymonx/xlogic-toolchain/resource/kind" + "gitlab.com/tymonx/xlogic-toolchain/arguments" + "gitlab.com/tymonx/xlogic-toolchain/file" + "gitlab.com/tymonx/xlogic-toolchain/file/kind" + "gitlab.com/tymonx/xlogic-toolchain/mode" ) -func usage(f *flag.FlagSet) { - fmt.Println("Usage:", filepath.Base(os.Args[0])) - fmt.Println(f.Name()) - fmt.Println() - - fmt.Println("Options:") - f.PrintDefaults() -} - -func createObject(opt *option.Option, args []string) (r *resource.Resource, err error) { - r = resource.New(kind.Object) - o := r.Object() - - o.Header = opt.Headers - o.Define = opt.Defines - o.Include = opt.Includes - - for _, arg := range args { - var res *resource.Resource - - if res, err = resource.Load(path.Path(arg)); err != nil { - return nil, err - } - - switch res.Kind { - case kind.Source: - o.Source = append(o.Source, res.Source()) - default: - return nil, cerr.InvalidArgument - } - } - - return r, nil -} - -func createArchive(opt *option.Option, args []string) (r *resource.Resource, err error) { - r = resource.New(kind.Archive) - - if opt.Append { - if erro := r.Load(opt.Output); erro != nil { - return nil, erro - } - } - - a := r.Archive() - - for _, arg := range args { - var res *resource.Resource - - if res, err = resource.Load(path.Path(arg)); err != nil { - return nil, err - } - - switch res.Kind { - case kind.Object: - a.Object = append(a.Object, res.Object()) - default: - return nil, cerr.InvalidArgument - } - } - - return r, nil -} - -func createLibrary(opt *option.Option, args []string) (r *resource.Resource, err error) { - r = resource.New(kind.Library) - l := r.Library() - - l.Header = opt.Headers - l.Define = opt.Defines - l.Include = opt.Includes - - for _, arg := range args { - var res *resource.Resource - - if res, err = resource.Load(path.Path(arg)); err != nil { - return nil, err - } - - switch res.Kind { - case kind.Source: - l.Source = append(l.Source, res.Source()) - case kind.Object: - l.Object = append(l.Object, res.Object()) - case kind.Archive: - l.Archive = append(l.Archive, res.Archive()) - default: - return nil, cerr.InvalidArgument - } - } - - return r, nil -} - -func createExecutable(opt *option.Option, args []string) (r *resource.Resource, err error) { - r = resource.New(kind.Executable) - e := r.Executable() - - e.Header = opt.Headers - e.Define = opt.Defines - e.Include = opt.Includes - - for _, arg := range args { - var res *resource.Resource - - if res, err = resource.Load(path.Path(arg)); err != nil { - return nil, err - } - - switch res.Kind { - case kind.Source: - e.Source = append(e.Source, res.Source()) - case kind.Object: - e.Object = append(e.Object, res.Object()) - case kind.Archive: - e.Archive = append(e.Archive, res.Archive()) - case kind.Library: - e.Library = append(e.Library, res.Library()) - default: - return nil, cerr.InvalidArgument - } - } - - return r, nil -} - -func createOutput(opt *option.Option, args []string) (r *resource.Resource, err error) { - if opt.Compile { - if r, err = createObject(opt, args); err != nil { - return nil, err - } +func main() { + args := arguments.New() - return r, nil + if err := args.Parse(); err != nil { + panic(err) } - if opt.Static { - if r, err = createArchive(opt, args); err != nil { - return nil, err - } - - return r, nil - } + output := file.New(args.Output) - if opt.Shared { - if r, err = createLibrary(opt, args); err != nil { - return nil, err + if args.Append { + if err := output.Load(args.Output); err != nil { + panic(err) } - - return r, nil } - if r, err = createExecutable(opt, args); err != nil { - return nil, err + switch args.Mode { + case mode.Object: + output.Kind = kind.Object + case mode.Archive: + output.Kind = kind.Archive + case mode.Library: + output.Kind = kind.Library + case mode.Executable: + output.Kind = kind.Executable } - return r, nil -} - -func main() { - var r *resource.Resource - - f := flag.NewFlagSet("HDL compiler wrapper", flag.ExitOnError) - - opt := option.New().FlagSet(f) - - if err := f.Parse(os.Args[1:]); err != nil { - panic(err) - } - - if opt.Help { - usage(f) - return - } - - var err error - - if r, err = createOutput(opt, f.Args()); err != nil { - panic(err) - } + output.Files = append(output.Files, args.Files...) + output.Defines = append(output.Defines, args.Defines...) + output.Headers = append(output.Headers, args.Headers...) + output.Includes = append(output.Includes, args.Includes...) + output.Undefines = append(output.Undefines, args.Undefines...) - if err := r.Dump(opt.Output); err != nil { + if err := output.Dump(args.Output); err != nil { panic(err) } } diff --git a/resource/source/sources.go b/compiler/compiler.go similarity index 68% rename from resource/source/sources.go rename to compiler/compiler.go index 857e07542ca58160d9afb9b35936688da21caa74..bd8c3dc957b135ce4cbbc43099708e93f8696c20 100644 --- a/resource/source/sources.go +++ b/compiler/compiler.go @@ -12,16 +12,19 @@ // See the License for the specific language governing permissions and // limitations under the License. -package source +package compiler import ( - "gitlab.com/tymonx/xlogic-toolchain/path" + "gitlab.com/tymonx/xlogic-toolchain/file" ) -// Sources defines a list of source files. -type Sources []*Source +// Compiler defines a generic compiler interface. +type Compiler interface { + CreateObject(f *file.File) error -// Add adds source file. -func (s *Sources) Add(file path.Path) { - *s = append(*s, New(file)) + CreateArchive(f *file.File) error + + CreateLibrary(f *file.File) error + + CreateExecutable(f *file.File) error } diff --git a/resource/define/define.go b/define/define.go similarity index 64% rename from resource/define/define.go rename to define/define.go index 4c6ca57545941690d004571ea84dd17aa5c52f4e..3dcc2a60abafffbf7f61944090c078b8083436ec 100644 --- a/resource/define/define.go +++ b/define/define.go @@ -18,14 +18,13 @@ import ( "encoding/json" "strings" - "gitlab.com/tymonx/xlogic-toolchain/cerr" + "gitlab.com/tymonx/go-error/rterror" ) // Define defines define. type Define struct { Name string `json:"name,omitempty"` Value string `json:"value,omitempty"` - Unset bool `json:"unset,omitempty"` } // New creates a new define object. @@ -43,12 +42,6 @@ func New(value string) *Define { return d } -// Undef sets unset flag. -func (d *Define) Undef() *Define { - d.Unset = true - return d -} - // String returns define as string. func (d *Define) String() string { if d.Value == "" { @@ -58,42 +51,36 @@ func (d *Define) String() string { return d.Name + "=" + d.Value } +// UnmarshalText decodes text to define. +func (d *Define) UnmarshalText(data []byte) error { + *d = *New(string(data)) + return nil +} + // UnmarshalJSON decodes JSON to define. func (d *Define) UnmarshalJSON(data []byte) error { switch data[0] { - case '"': - *d = *New(strings.Trim(string(data), `"`)) case '{': - object := make(map[string]interface{}) - - if err := json.Unmarshal(data, &object); err != nil { - return err - } - - var def Define - - if val, ok := object["name"]; ok { - if def.Name, ok = val.(string); !ok { - return cerr.InvalidValue - } - } - - if val, ok := object["value"]; ok { - if def.Value, ok = val.(string); !ok { - return cerr.InvalidValue - } - } + case '"': + return d.UnmarshalText(data[1 : len(data)-1]) + case 'n': + *d = Define{} + return nil + default: + return rterror.New("invalid JSON type") + } - if val, ok := object["unset"]; ok { - if def.Unset, ok = val.(bool); !ok { - return cerr.InvalidValue - } - } + object := new(struct { + Name string `json:"name"` + Value string `json:"value"` + }) - *d = def - default: - return cerr.InvalidValue + if err := json.Unmarshal(data, object); err != nil { + return rterror.New("error occurred while decoding JSON", err) } + d.Name = strings.TrimSpace(object.Name) + d.Value = strings.TrimSpace(object.Value) + return nil } diff --git a/resource/define/define_test.go b/define/define_test.go similarity index 53% rename from resource/define/define_test.go rename to define/define_test.go index 0ba4fa3f2cde9769a5e7f8407d3662a8aac36c56..5d62c494571e76b21c44c346f50746c4826eddac 100644 --- a/resource/define/define_test.go +++ b/define/define_test.go @@ -19,77 +19,75 @@ import ( "testing" "github.com/stretchr/testify/assert" - "gitlab.com/tymonx/xlogic-toolchain/resource/define" + "gitlab.com/tymonx/xlogic-toolchain/define" ) func TestDefineNew(test *testing.T) { - want := "FOO" + want := "Name=value" d := define.New(want) - assert.Equal(test, want, d.Name) - assert.Empty(test, d.Value) + assert.NotNil(test, d) + assert.Equal(test, "Name", d.Name) + assert.Equal(test, "value", d.Value) + assert.Equal(test, want, d.String()) } -func TestDefineSetValue(test *testing.T) { - d := define.New("FAB=BAR") +func TestDefineString(test *testing.T) { + want := "NAME=5" - assert.Equal(test, "FAB", d.Name) - assert.Equal(test, "BAR", d.Value) + assert.NotNil(test, want, define.New(want).String()) } -func TestDefineString(test *testing.T) { - var d define.Define +func TestDefineUnmarshalText(test *testing.T) { + want := " MYDEF = text " - want := "XYZ" + d := new(define.Define) - d.Name = want + assert.NoError(test, json.Unmarshal([]byte(` "`+want+`" `), d)) - assert.Equal(test, want, d.String()) + assert.Equal(test, "MYDEF=text", d.String()) + assert.Equal(test, "MYDEF", d.Name) + assert.Equal(test, "text", d.Value) } -func TestDefineStringValue(test *testing.T) { - var d define.Define - - d.Name = "GOO" - d.Value = "Test" - - assert.Equal(test, "GOO=Test", d.String()) -} +func TestDefineUnmarshalJSONObject(test *testing.T) { + want := "DEFINE" -func TestDefineUnmarshalJSONString(test *testing.T) { - var d define.Define + d := new(define.Define) - want := "ABC=Test" + assert.NoError(test, json.Unmarshal([]byte(` { "name": "`+want+`" } `), d)) - assert.NoError(test, json.Unmarshal([]byte(` " `+want+` " `), &d)) assert.Equal(test, want, d.String()) - assert.Equal(test, "ABC", d.Name) - assert.Equal(test, "Test", d.Value) + assert.Equal(test, want, d.Name) + assert.Empty(test, d.Value) } -func TestDefineUnmarshalJSONObject(test *testing.T) { - var d define.Define +func TestDefineUnmarshalJSONNull(test *testing.T) { + d := new(define.Define) - assert.NoError(test, json.Unmarshal([]byte(` {"name": "Y", "value": "A"} `), &d)) - assert.Equal(test, "Y=A", d.String()) - assert.Equal(test, "Y", d.Name) - assert.Equal(test, "A", d.Value) + assert.NoError(test, json.Unmarshal([]byte(` null `), d)) + + assert.Empty(test, d.String()) + assert.Empty(test, d.Name) + assert.Empty(test, d.Value) } -func TestDefineUnmarshalJSONObjectInvalid(test *testing.T) { - var d define.Define +func TestDefineUnmarshalJSONError(test *testing.T) { + d := new(define.Define) + + assert.Error(test, json.Unmarshal([]byte(`{"name":5}`), d)) - assert.Error(test, json.Unmarshal([]byte(` {"name": "Y", "value": []} `), &d)) assert.Empty(test, d.String()) assert.Empty(test, d.Name) assert.Empty(test, d.Value) } func TestDefineUnmarshalJSONInvalid(test *testing.T) { - var d define.Define + d := new(define.Define) + + assert.Error(test, json.Unmarshal([]byte(`true`), d)) - assert.Error(test, json.Unmarshal([]byte(` 3 `), &d)) assert.Empty(test, d.String()) assert.Empty(test, d.Name) assert.Empty(test, d.Value) diff --git a/define/defines.go b/define/defines.go new file mode 100644 index 0000000000000000000000000000000000000000..a3abbbcdf4795bf9bcc3cfad7ab4d54fe15a6b5b --- /dev/null +++ b/define/defines.go @@ -0,0 +1,65 @@ +// Copyright 2020 Tymoteusz Blazejczyk +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package define + +import ( + "encoding/json" + + "gitlab.com/tymonx/go-error/rterror" +) + +// Defines defines a list of defines. +type Defines []Define + +// UnmarshalText decodes text to define. +func (d *Defines) UnmarshalText(data []byte) error { + *d = Defines{*New(string(data))} + + return nil +} + +// UnmarshalJSON decodes JSON to define. +func (d *Defines) UnmarshalJSON(data []byte) error { + switch data[0] { + case '[': + case '{': + object := new(Define) + + if err := json.Unmarshal(data, object); err != nil { + return err + } + + *d = Defines{*object} + + return nil + case '"': + return d.UnmarshalText(data[1 : len(data)-1]) + case 'n': + *d = Defines{} + return nil + default: + return rterror.New("invalid JSON type") + } + + defines := []Define{} + + if err := json.Unmarshal(data, &defines); err != nil { + return rterror.New("error occurred while decoding JSON", err) + } + + *d = defines + + return nil +} diff --git a/define/defines_test.go b/define/defines_test.go new file mode 100644 index 0000000000000000000000000000000000000000..1b36ed3f0fa4591657eeb4bd923523ffea2169dd --- /dev/null +++ b/define/defines_test.go @@ -0,0 +1,93 @@ +// Copyright 2020 Tymoteusz Blazejczyk +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package define_test + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" + "gitlab.com/tymonx/xlogic-toolchain/define" +) + +func TestDefinesUnmarshalText(test *testing.T) { + want := "DEFF=6" + + var d define.Defines + + assert.NoError(test, json.Unmarshal([]byte(` "`+want+`" `), &d)) + + assert.Len(test, d, 1) + assert.Equal(test, "DEFF", d[0].Name) + assert.Equal(test, "6", d[0].Value) + assert.Equal(test, want, d[0].String()) +} + +func TestDefinesUnmarshalJSON(test *testing.T) { + var d define.Defines + + assert.NoError(test, json.Unmarshal([]byte(` ["A=1", { "name": "B" }]`), &d)) + + assert.Len(test, d, 2) + + assert.Equal(test, "A", d[0].Name) + assert.Equal(test, "1", d[0].Value) + assert.Equal(test, "A=1", d[0].String()) + + assert.Equal(test, "B", d[1].Name) + assert.Empty(test, d[1].Value) + assert.Equal(test, "B", d[1].String()) +} + +func TestDefinesUnmarshalJSONObject(test *testing.T) { + want := "C" + + var d define.Defines + + assert.NoError(test, json.Unmarshal([]byte(` { "name": "`+want+`" } `), &d)) + + assert.Len(test, d, 1) + assert.Equal(test, "C", d[0].String()) + assert.Equal(test, "C", d[0].Name) + assert.Empty(test, d[0].Value) +} + +func TestDefinesUnmarshalJSONNull(test *testing.T) { + var d define.Defines + + assert.NoError(test, json.Unmarshal([]byte(` null `), &d)) + assert.Empty(test, d) +} + +func TestDefinesUnmarshalJSONError(test *testing.T) { + var d define.Defines + + assert.Error(test, json.Unmarshal([]byte(`[5]`), &d)) + assert.Empty(test, d) +} + +func TestDefinesUnmarshalJSONObjectError(test *testing.T) { + var d define.Defines + + assert.Error(test, json.Unmarshal([]byte(`{"name":5}`), &d)) + assert.Empty(test, d) +} + +func TestDefinesUnmarshalJSONInvalid(test *testing.T) { + var d define.Defines + + assert.Error(test, json.Unmarshal([]byte(`true`), &d)) + assert.Empty(test, d) +} diff --git a/docker-run.sh b/docker-run.sh deleted file mode 100755 index eb7c996bfe7f23fb6f733bf06bc59205769ccd6b..0000000000000000000000000000000000000000 --- a/docker-run.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env sh -# -# Copyright 2020 Tymoteusz Blazejczyk -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Exit on error -set -e - -# Create a temporary directory for all downloaded Go modules. To have -# the correct file mode permissions with proper user and group, -# this directory must be created before running the docker run command -# with the --volume argument. Otherwise, docker will create directory -# for us with directory properties from container. Mostly of time it is -# unwanted root:root -mkdir -p /tmp/go/ - -# Run Docker image as container. Mount current working directory to container. -# This will allow all commands from Docker to have access to files and -# directories under current working directory, mostly of time it is a project -# workspace. All created files and directories will have proper mode file -# permissions from current user who invokes this script -docker run \ - --rm \ - --tty \ - --interactive \ - --user "$(id -u):$(id -g)" \ - --volume "$(pwd):$(pwd)" \ - --volume "/tmp/:/tmp/" \ - --volume "/tmp/go/:/go/" \ - --volume "/etc/group:/etc/group:ro" \ - --volume "/etc/passwd:/etc/passwd:ro" \ - --workdir "$(pwd)" \ - --publish "${GODOC_PORT:-6060}:6060" \ - --entrypoint /bin/bash \ - --security-opt=label:disable \ - "registry.gitlab.com/tymonx/docker-go:1.14.3" \ - ${@:+-c "$*"} diff --git a/factory/factory.go b/factory/factory.go new file mode 100644 index 0000000000000000000000000000000000000000..081bf91ee8d683c4ca2dd3f1b423ac1549f7cf10 --- /dev/null +++ b/factory/factory.go @@ -0,0 +1,101 @@ +// Copyright 2020 Tymoteusz Blazejczyk +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package factory + +import ( + "sync" + + "gitlab.com/tymonx/xlogic-toolchain/cerr" +) + +// Constructor defines a custom constructor function for creating objects. +type Constructor func(arguments ...interface{}) (object interface{}, err error) + +// Factory defines a factory instance that can create registered object types. +type Factory struct { + constructors map[string]Constructor +} + +var gInstance *Factory // nolint: gochecknoglobals +var gMutex sync.RWMutex // nolint: gochecknoglobals +var gOnce sync.Once // nolint: gochecknoglobals + +// New creates a new factory instance. +func New() *Factory { + return &Factory{ + constructors: make(map[string]Constructor), + } +} + +// Registry registries a new constructor with a given unique id to factory. +func (f *Factory) Registry(name string, constructor Constructor) error { + if constructor == nil { + return cerr.InvalidArgument + } + + if _, ok := f.constructors[name]; ok { + return cerr.InvalidArgument + } + + f.constructors[name] = constructor + + return nil +} + +// Create creates a new object based on given name type. +func (f *Factory) Create(name string, arguments ...interface{}) (object interface{}, err error) { + var constructor Constructor + + var ok bool + + if constructor, ok = f.constructors[name]; !ok { + return nil, cerr.InvalidArgument + } + + if object, err = constructor(arguments...); err != nil { + return nil, cerr.InvalidArgument + } + + if object == nil { + return nil, cerr.InvalidArgument + } + + return object, nil +} + +// Registry registries a new constructor with a given unique id to factory. +func Registry(name string, constructor Constructor) error { + gMutex.Lock() + defer gMutex.Unlock() + + return get().Registry(name, constructor) +} + +// Create creates a new object based on given name type. +func Create(name string, arguments ...interface{}) (object interface{}, err error) { + gMutex.RLock() + defer gMutex.RUnlock() + + return get().Create(name, arguments...) +} + +// get returns global factory instance. +func get() *Factory { + gOnce.Do(func() { + gInstance = New() + }) + + return gInstance +} diff --git a/factory/factory_test.go b/factory/factory_test.go new file mode 100644 index 0000000000000000000000000000000000000000..587f933f2b3493fb64497d22b2a6a23960c4a281 --- /dev/null +++ b/factory/factory_test.go @@ -0,0 +1,123 @@ +// Copyright 2020 Tymoteusz Blazejczyk +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package factory_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "gitlab.com/tymonx/xlogic-toolchain/cerr" + "gitlab.com/tymonx/xlogic-toolchain/factory" +) + +func TestFactoryNew(test *testing.T) { + assert.NotNil(test, factory.New()) +} + +func TestFactoryRegistry(test *testing.T) { + constructor := func(...interface{}) (interface{}, error) { + return new(struct{}), nil + } + + assert.NoError(test, factory.New().Registry("type", constructor)) +} + +func TestFactoryRegistryGlobal(test *testing.T) { + constructor := func(...interface{}) (interface{}, error) { + return new(struct{}), nil + } + + assert.NoError(test, factory.Registry("type", constructor)) +} + +func TestFactoryRegistryAlreadyRegistered(test *testing.T) { + f := factory.New() + + constructor := func(...interface{}) (interface{}, error) { + return new(struct{}), nil + } + + assert.NoError(test, f.Registry("type", constructor)) + assert.Error(test, f.Registry("type", constructor)) +} + +func TestFactoryRegistryInvalidConstructor(test *testing.T) { + assert.Error(test, factory.New().Registry("type", nil)) +} + +func TestFactoryCreate(test *testing.T) { + f := factory.New() + + constructor := func(...interface{}) (interface{}, error) { + return new(struct{}), nil + } + + assert.NoError(test, f.Registry("type", constructor)) + + object, err := f.Create("type") + + assert.NoError(test, err) + assert.NotNil(test, object) +} + +func TestFactoryCreateGlobal(test *testing.T) { + constructor := func(...interface{}) (interface{}, error) { + return new(struct{}), nil + } + + assert.NoError(test, factory.Registry("type-2", constructor)) + + object, err := factory.Create("type-2") + + assert.NoError(test, err) + assert.NotNil(test, object) +} + +func TestFactoryCreateNotRegistered(test *testing.T) { + object, err := factory.New().Create("type") + + assert.Error(test, err) + assert.Nil(test, object) +} + +func TestFactoryCreateError(test *testing.T) { + f := factory.New() + + constructor := func(...interface{}) (interface{}, error) { + return nil, cerr.InvalidValue + } + + assert.NoError(test, f.Registry("type", constructor)) + + object, err := f.Create("type") + + assert.Error(test, err) + assert.Nil(test, object) +} + +func TestFactoryCreateNotCreated(test *testing.T) { + f := factory.New() + + constructor := func(...interface{}) (interface{}, error) { + return nil, nil + } + + assert.NoError(test, f.Registry("type", constructor)) + + object, err := f.Create("type") + + assert.Error(test, err) + assert.Nil(test, object) +} diff --git a/file/file.go b/file/file.go new file mode 100644 index 0000000000000000000000000000000000000000..5e0d99041678696b3dc9eece1f2cf17272807236 --- /dev/null +++ b/file/file.go @@ -0,0 +1,133 @@ +// Copyright 2020 Tymoteusz Blazejczyk +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package file + +import ( + "encoding/json" + "io/ioutil" + + "gitlab.com/tymonx/go-error/rterror" + "gitlab.com/tymonx/xlogic-toolchain/define" + "gitlab.com/tymonx/xlogic-toolchain/file/kind" + "gitlab.com/tymonx/xlogic-toolchain/header" + "gitlab.com/tymonx/xlogic-toolchain/id" + "gitlab.com/tymonx/xlogic-toolchain/include" + "gitlab.com/tymonx/xlogic-toolchain/path" + "gitlab.com/tymonx/xlogic-toolchain/undefine" +) + +// Marshal is used only in testing and mocking. +var Marshal = json.Marshal // nolint: gochecknoglobals + +// File defines a generic object that describes input or generated output file. +type File struct { + ID id.ID `json:"id"` + Kind kind.Kind `json:"kind"` + Path path.Path `json:"path"` + Headers header.Headers `json:"header"` + Defines define.Defines `json:"define"` + Includes include.Includes `json:"include"` + Undefines undefine.Undefines `json:"undefine"` + Files Files `json:"file"` +} + +// New creates a new file object. +func New(p path.Path) *File { + return &File{ + ID: id.New(), + Kind: kind.FromPath(p), + Path: p, + } +} + +// Load loads file content. +func (f *File) Load(p path.Path) (err error) { + if k := kind.FromPath(p); (k != kind.JSON) && (k != kind.Unknown) { + f.ID = id.New() + f.Kind = k + f.Path = p + + return nil + } + + var data []byte + + if data, err = ioutil.ReadFile(p.String()); err != nil { + return rterror.New("cannot read file", p, err) + } + + if err := json.Unmarshal(data, f); err != nil { + return rterror.New("cannot decode JSON to file", err) + } + + return nil +} + +// Dump dumps file content. +func (f *File) Dump(p path.Path) (err error) { + var data []byte + + if data, err = Marshal(f); err != nil { + return rterror.New("cannot encode file to JSON", err) + } + + if err := ioutil.WriteFile(string(p), data, 0600); err != nil { + return rterror.New("cannot write to file", p, err) + } + + return nil +} + +// UnmarshalText decodes text to file. +func (f *File) UnmarshalText(data []byte) error { + return f.Load(path.Path(data)) +} + +// UnmarshalJSON decides JSON to file. +func (f *File) UnmarshalJSON(data []byte) error { + switch data[0] { + case '{': + case '"': + return f.UnmarshalText(data[1 : len(data)-1]) + case 'n': + *f = File{} + return nil + default: + return rterror.New("invalid JSON type") + } + + object := new(struct { + ID id.ID `json:"id"` + Kind kind.Kind `json:"kind"` + Path path.Path `json:"path"` + Headers header.Headers `json:"header"` + Defines define.Defines `json:"define"` + Includes include.Includes `json:"include"` + Undefines undefine.Undefines `json:"undefine"` + Files Files `json:"file"` + }) + + if err := json.Unmarshal(data, object); err != nil { + return rterror.New("error occurred while decoding JSON", err) + } + + *f = *object + + if f.Kind == kind.Unknown { + f.Kind = kind.FromPath(f.Path) + } + + return nil +} diff --git a/file/file_test.go b/file/file_test.go new file mode 100644 index 0000000000000000000000000000000000000000..ae0ed82aec917a11bc3929cd58ce78af106dc47c --- /dev/null +++ b/file/file_test.go @@ -0,0 +1,222 @@ +// Copyright 2020 Tymoteusz Blazejczyk +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package file_test + +import ( + "encoding/json" + "io/ioutil" + "os" + "testing" + + "github.com/stretchr/testify/assert" + "gitlab.com/tymonx/go-error/rterror" + "gitlab.com/tymonx/xlogic-toolchain/file" + "gitlab.com/tymonx/xlogic-toolchain/file/kind" + "gitlab.com/tymonx/xlogic-toolchain/path" +) + +func TestFileNew(test *testing.T) { + want := "dir/file.sv" + + f := file.New(path.Path(want)) + + assert.NotNil(test, f) + assert.Equal(test, want, f.Path.String()) + assert.Equal(test, kind.SystemVerilog, f.Kind) + assert.NotEmpty(test, f.ID) +} + +func TestFileLoad(test *testing.T) { // nolint: dupl + h, err := ioutil.TempFile("", "*.c") + + defer assert.NoError(test, os.Remove(h.Name())) + defer assert.NoError(test, h.Close()) + + f := file.New("") + + assert.NoError(test, err) + assert.NoError(test, ioutil.WriteFile(h.Name(), []byte(`{}`), 0600)) + assert.NoError(test, f.Load(path.Path(h.Name()))) + + assert.Equal(test, h.Name(), f.Path.String()) + assert.Equal(test, kind.C, f.Kind) + assert.NotEmpty(test, f.ID) +} + +func TestFileLoadJSON(test *testing.T) { + h, err := ioutil.TempFile("", "*.json") + + defer assert.NoError(test, os.Remove(h.Name())) + defer assert.NoError(test, h.Close()) + + f := file.New("") + + assert.NoError(test, err) + assert.NoError(test, ioutil.WriteFile(h.Name(), []byte(`{"id": "id", "kind": "object", "path": "file.o"}`), 0600)) + assert.NoError(test, f.Load(path.Path(h.Name()))) + + assert.Equal(test, "file.o", f.Path.String()) + assert.Equal(test, kind.Object, f.Kind) + assert.Equal(test, "id", f.ID.String()) +} + +func TestFileLoadJSONError(test *testing.T) { + h, err := ioutil.TempFile("", "*.json") + + defer assert.NoError(test, os.Remove(h.Name())) + defer assert.NoError(test, h.Close()) + + f := file.New("") + + assert.NoError(test, err) + assert.NoError(test, ioutil.WriteFile(h.Name(), []byte(`{"id": true}`), 0600)) + assert.Error(test, f.Load(path.Path(h.Name()))) + + assert.Empty(test, f.Path) + assert.Equal(test, kind.Unknown, f.Kind) + assert.NotEmpty(test, f.ID) +} + +func TestFileLoadReadError(test *testing.T) { + f := file.New("") + + assert.Error(test, f.Load("invalid")) + + assert.Empty(test, f.Path) + assert.Equal(test, kind.Unknown, f.Kind) + assert.NotEmpty(test, f.ID) +} + +func TestFileLoadUnmarshalError(test *testing.T) { // nolint: dupl + h, err := ioutil.TempFile("", "*.v") + + defer assert.NoError(test, os.Remove(h.Name())) + defer assert.NoError(test, h.Close()) + + f := file.New("") + + assert.NoError(test, err) + assert.NoError(test, ioutil.WriteFile(h.Name(), []byte(`{ "data": 5 }`), 0600)) + assert.NoError(test, f.Load(path.Path(h.Name()))) + + assert.Equal(test, h.Name(), f.Path.String()) + assert.Equal(test, kind.Verilog, f.Kind) + assert.NotEmpty(test, f.ID) +} + +func TestFileDump(test *testing.T) { // nolint: dupl + h, err := ioutil.TempFile("", "*.json") + + defer assert.NoError(test, os.Remove(h.Name())) + defer assert.NoError(test, h.Close()) + + f := file.New("file.o") + + assert.NoError(test, err) + assert.NoError(test, f.Dump(path.Path(h.Name()))) + + object := &struct { + ID string `json:"id"` + Path string `json:"path"` + Kind string `json:"kind"` + }{} + + data, err := ioutil.ReadFile(h.Name()) + + assert.NotNil(test, data) + assert.NoError(test, err) + assert.NoError(test, json.Unmarshal(data, object)) + assert.Equal(test, "file.o", object.Path) + assert.Equal(test, "object", object.Kind) + assert.NotEmpty(test, object.ID) +} + +func TestFileDumpError(test *testing.T) { // nolint: dupl + h, err := ioutil.TempFile("", "*.json") + + defer assert.NoError(test, os.Remove(h.Name())) + defer assert.NoError(test, h.Close()) + + f := file.New("file.o") + + assert.NoError(test, err) + assert.NoError(test, f.Dump(path.Path(h.Name()))) + + object := &struct { + ID string `json:"id"` + Path string `json:"path"` + Kind string `json:"kind"` + }{} + + data, err := ioutil.ReadFile(h.Name()) + + assert.NotNil(test, data) + assert.NoError(test, err) + assert.NoError(test, json.Unmarshal(data, object)) + assert.Equal(test, "file.o", object.Path) + assert.Equal(test, "object", object.Kind) + assert.NotEmpty(test, object.ID) +} + +func TestFileDumpWriteError(test *testing.T) { + d, err := ioutil.TempDir("", "") + + defer assert.NoError(test, os.Remove(d)) + + f := file.New("file.o") + + assert.NoError(test, err) + assert.Error(test, f.Dump(path.Path(d+"/"))) +} + +func TestFileDumpMarshalError(test *testing.T) { + defer func() { + file.Marshal = json.Marshal + }() + + file.Marshal = func(interface{}) ([]byte, error) { + return nil, rterror.New("error") + } + + assert.Error(test, file.New("").Dump("")) +} + +func TestFileUnmarshalText(test *testing.T) { + h, err := ioutil.TempFile("", "*.json") + + defer assert.NoError(test, os.Remove(h.Name())) + defer assert.NoError(test, h.Close()) + + var f file.File + + assert.NoError(test, err) + assert.NoError(test, ioutil.WriteFile(h.Name(), []byte(`{"path": "file.o"}`), 0600)) + assert.NoError(test, json.Unmarshal([]byte(`"`+h.Name()+`"`), &f)) + assert.Equal(test, "file.o", f.Path.String()) +} + +func TestFileUnmarshalNull(test *testing.T) { + var f file.File + + assert.NoError(test, json.Unmarshal([]byte(` null `), &f)) + assert.Empty(test, f) +} + +func TestFileUnmarshalInvalid(test *testing.T) { + var f file.File + + assert.Error(test, json.Unmarshal([]byte(` true `), &f)) + assert.Empty(test, f) +} diff --git a/file/files.go b/file/files.go new file mode 100644 index 0000000000000000000000000000000000000000..90c760c79edf5d3920f5c92b6c7625c09f8722d7 --- /dev/null +++ b/file/files.go @@ -0,0 +1,72 @@ +// Copyright 2020 Tymoteusz Blazejczyk +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package file + +import ( + "encoding/json" + + "gitlab.com/tymonx/go-error/rterror" + "gitlab.com/tymonx/xlogic-toolchain/path" +) + +// Files defines a list of generic objects that describes input or generated output files. +type Files []File + +// UnmarshalText decodes text to file path. +func (f *Files) UnmarshalText(data []byte) error { + object := new(File) + + if err := object.Load(path.Path(data)); err != nil { + return rterror.New("error occurred while decoding text", string(data), err) + } + + *f = Files{*object} + + return nil +} + +// UnmarshalJSON decodes JSON to file path. +func (f *Files) UnmarshalJSON(data []byte) error { + switch data[0] { + case '[': + case '{': + object := new(File) + + if err := json.Unmarshal(data, object); err != nil { + return err + } + + *f = Files{*object} + + return nil + case '"': + return f.UnmarshalText(data[1 : len(data)-1]) + case 'n': + *f = Files{} + return nil + default: + return rterror.New("invalid JSON type") + } + + files := []File{} + + if err := json.Unmarshal(data, &files); err != nil { + return rterror.New("error occurred while decoding JSON", err) + } + + *f = files + + return nil +} diff --git a/file/files_test.go b/file/files_test.go new file mode 100644 index 0000000000000000000000000000000000000000..b2833fa9385392e9f8a782d5dfbfd153ab70b6c6 --- /dev/null +++ b/file/files_test.go @@ -0,0 +1,101 @@ +// Copyright 2020 Tymoteusz Blazejczyk +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, foftware +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package file_test + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" + "gitlab.com/tymonx/xlogic-toolchain/file" + "gitlab.com/tymonx/xlogic-toolchain/file/kind" +) + +func TestFilesUnmarshalText(test *testing.T) { + want := "dir/file.c++" + + var f file.Files + + assert.NoError(test, json.Unmarshal([]byte(` "`+want+`" `), &f)) + + assert.Len(test, f, 1) + assert.Equal(test, kind.Cxx, f[0].Kind) + assert.Equal(test, "c++", f[0].Kind.String()) + assert.Equal(test, want, f[0].Path.String()) +} + +func TestFilesUnmarshalTextError(test *testing.T) { + var f file.Files + + assert.Error(test, json.Unmarshal([]byte(` "invalid" `), &f)) + assert.Empty(test, f) +} + +func TestFilesUnmarshalJSON(test *testing.T) { + var f file.Files + + assert.NoError(test, json.Unmarshal([]byte(` ["dir/file.c", { "path": "file.tcl" }]`), &f)) + + assert.Len(test, f, 2) + + assert.Equal(test, kind.C, f[0].Kind) + assert.Equal(test, "c", f[0].Kind.String()) + assert.Equal(test, "dir/file.c", f[0].Path.String()) + + assert.Equal(test, kind.TCL, f[1].Kind) + assert.Equal(test, "tcl", f[1].Kind.String()) + assert.Equal(test, "file.tcl", f[1].Path.String()) +} + +func TestFilesUnmarshalJSONObject(test *testing.T) { + want := "dir/file.json" + + var f file.Files + + assert.NoError(test, json.Unmarshal([]byte(` { "path": "`+want+`" } `), &f)) + + assert.Len(test, f, 1) + assert.Equal(test, want, f[0].Path.String()) + assert.Equal(test, kind.JSON, f[0].Kind) + assert.Equal(test, "json", f[0].Kind.String()) +} + +func TestFilesUnmarshalJSONNull(test *testing.T) { + var f file.Files + + assert.NoError(test, json.Unmarshal([]byte(` null `), &f)) + assert.Empty(test, f) +} + +func TestFilesUnmarshalJSONError(test *testing.T) { + var f file.Files + + assert.Error(test, json.Unmarshal([]byte(`[5]`), &f)) + assert.Empty(test, f) +} + +func TestFilesUnmarshalJSONObjectError(test *testing.T) { + var f file.Files + + assert.Error(test, json.Unmarshal([]byte(`{"path":5}`), &f)) + assert.Empty(test, f) +} + +func TestFilesUnmarshalJSONInvalid(test *testing.T) { + var f file.Files + + assert.Error(test, json.Unmarshal([]byte(`true`), &f)) + assert.Empty(test, f) +} diff --git a/resource/source/kind/kind.go b/file/kind/kind.go similarity index 58% rename from resource/source/kind/kind.go rename to file/kind/kind.go index 270cc9546dbcbab2d98479541e09fdc289c23aa5..7be2f808648703f3376bbba408218b2f128f1059 100644 --- a/resource/source/kind/kind.go +++ b/file/kind/kind.go @@ -20,21 +20,29 @@ import ( "gitlab.com/tymonx/xlogic-toolchain/path" ) -// These constants define values for source file. +// These constants define values for file. const ( Unknown Kind = 0 - C Kind = 1 - IP Kind = 2 - Cxx Kind = 3 - TCL Kind = 4 - JSON Kind = 5 - VHDL Kind = 6 - Verilog Kind = 7 - SystemVerilog Kind = 8 + Object Kind = 1 + Archive Kind = 2 + Library Kind = 3 + Executable Kind = 4 + C Kind = 5 + IP Kind = 6 + Cxx Kind = 7 + TCL Kind = 8 + JSON Kind = 9 + VHDL Kind = 10 + Verilog Kind = 11 + SystemVerilog Kind = 12 ) var gToString = map[Kind]string{ // nolint: gochecknoglobals Unknown: "", + Object: "object", + Archive: "archive", + Library: "library", + Executable: "executable", C: "c", IP: "ip", Cxx: "c++", @@ -47,6 +55,10 @@ var gToString = map[Kind]string{ // nolint: gochecknoglobals var gFromString = map[string]Kind{ // nolint: gochecknoglobals "": Unknown, + "object": Object, + "archive": Archive, + "library": Library, + "executable": Executable, "c": C, "ip": IP, "c++": Cxx, @@ -54,14 +66,21 @@ var gFromString = map[string]Kind{ // nolint: gochecknoglobals "json": JSON, "vhdl": VHDL, "verilog": Verilog, - "sv": SystemVerilog, "systemverilog": SystemVerilog, } var gFromExtension = map[string]Kind{ // nolint: gochecknoglobals ".c": C, + ".o": Object, + ".a": Archive, + ".lib": Archive, + ".so": Library, + ".dll": Library, + ".exe": Executable, ".ip": IP, + ".C": Cxx, ".cc": Cxx, + ".cp": Cxx, ".cxx": Cxx, ".cpp": Cxx, ".c++": Cxx, @@ -73,12 +92,12 @@ var gFromExtension = map[string]Kind{ // nolint: gochecknoglobals ".sv": SystemVerilog, } -// Kind defines source file kind. +// Kind defines file kind. type Kind int -// Is returns true if path is a source file, otherwise it returns false. -func Is(file path.Path) bool { - return gFromExtension[strings.ToLower(file.Extension())] != Unknown +// Is returns true if path is a file, otherwise it returns false. +func Is(p path.Path) bool { + return fromExtension(p) != Unknown } // FromString returns kind from given string. @@ -87,8 +106,8 @@ func FromString(str string) Kind { } // FromPath returns kind from given file path. -func FromPath(file path.Path) Kind { - return gFromExtension[strings.ToLower(file.Extension())] +func FromPath(p path.Path) Kind { + return fromExtension(p) } // String returns kind as string. @@ -96,14 +115,23 @@ func (k *Kind) String() string { return gToString[*k] } -// UnmarshalJSON decodes from JSON to kind. -func (k *Kind) UnmarshalJSON(data []byte) error { - *k = FromString(strings.Trim(string(data), `"`)) - +// UnmarshalText decodes from text to kind. +func (k *Kind) UnmarshalText(data []byte) error { + *k = FromString(string(data)) return nil } -// MarshalJSON decodes from kind to JSON. -func (k *Kind) MarshalJSON() (data []byte, err error) { - return []byte(`"` + k.String() + `"`), nil +// MarshalText decodes from kind to text. +func (k *Kind) MarshalText() (data []byte, err error) { + return []byte(k.String()), nil +} + +func fromExtension(p path.Path) Kind { + extension := p.Extension() + + if k, ok := gFromExtension[extension]; ok { + return k + } + + return gFromExtension[strings.ToLower(extension)] } diff --git a/resource/source/kind/kind_test.go b/file/kind/kind_test.go similarity index 90% rename from resource/source/kind/kind_test.go rename to file/kind/kind_test.go index bb34f90265470a81920e2d40e18810f44bc890d9..717580c87cf577c3642d252accc814ce94628c31 100644 --- a/resource/source/kind/kind_test.go +++ b/file/kind/kind_test.go @@ -20,7 +20,7 @@ import ( "github.com/stretchr/testify/assert" - "gitlab.com/tymonx/xlogic-toolchain/resource/source/kind" + "gitlab.com/tymonx/xlogic-toolchain/file/kind" ) func TestKindFromString(test *testing.T) { @@ -36,6 +36,7 @@ func TestKindFromString(test *testing.T) { func TestKindFromPath(test *testing.T) { assert.Equal(test, kind.C, kind.FromPath("dir/file.c")) assert.Equal(test, kind.IP, kind.FromPath("dir/file.ip")) + assert.Equal(test, kind.Cxx, kind.FromPath("dir/file.C")) assert.Equal(test, kind.Cxx, kind.FromPath("dir/file.cc")) assert.Equal(test, kind.Cxx, kind.FromPath("dir/file.cpp")) assert.Equal(test, kind.Cxx, kind.FromPath("dir/file.cxx")) @@ -46,6 +47,11 @@ func TestKindFromPath(test *testing.T) { assert.Equal(test, kind.SystemVerilog, kind.FromPath("dir/file.sV")) } +func TestKindIs(test *testing.T) { + assert.True(test, kind.Is("dir/file.vhd")) + assert.False(test, kind.Is("dir/dir2")) +} + func TestKindString(test *testing.T) { k := kind.FromPath("dir/file.sv") diff --git a/go.mod b/go.mod index d0b2f66f7546178c3b2862e0fa4123f52d0cdb48..297d40ee92e39fdd000b6570c9216e54b5d15fe6 100644 --- a/go.mod +++ b/go.mod @@ -16,4 +16,8 @@ module gitlab.com/tymonx/xlogic-toolchain go 1.14 -require github.com/stretchr/testify v1.6.1 +require ( + github.com/alexflint/go-arg v1.3.0 + github.com/stretchr/testify v1.6.1 + gitlab.com/tymonx/go-error v1.1.0 +) diff --git a/go.sum b/go.sum index 56d62e7c224382f01538913c7d996c2f2fc7cbb6..aa3c1fd4a3793d111eebe9a7cd91f3b13f65c24c 100644 --- a/go.sum +++ b/go.sum @@ -1,10 +1,21 @@ +github.com/alexflint/go-arg v1.3.0 h1:UfldqSdFWeLtoOuVRosqofU4nmhI1pYEbT4ZFS34Bdo= +github.com/alexflint/go-arg v1.3.0/go.mod h1:9iRbDxne7LcR/GSvEr7ma++GLpdIU1zrghf2y2768kM= +github.com/alexflint/go-scalar v1.0.0 h1:NGupf1XV/Xb04wXskDFzS0KWOLH632W/EO4fAFi+A70= +github.com/alexflint/go-scalar v1.0.0/go.mod h1:GpHzbCOZXEKMEcygYQ5n/aa4Aq84zbxjy3MxYW0gjYw= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +gitlab.com/tymonx/go-error v1.1.0 h1:ynB2GC1Hw3pVhDAoAeAiMmSDBtoM0OXYffWrRIGmDOE= +gitlab.com/tymonx/go-error v1.1.0/go.mod h1:hN0YcBOqVJCinZxDlKg2xn94U4F+h/yQZtsgPa6jpmY= +gitlab.com/tymonx/go-formatter v1.0.0 h1:OMq9YE+kQfPQExX4tW/3/9A5SjJqvxqVRNezOh35qDI= +gitlab.com/tymonx/go-formatter v1.0.0/go.mod h1:mgO1gntIZoYP8XyxVGYwfMe7PTctf0DBc/BIFaFwlOM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/resource/header/header.go b/header/header.go similarity index 52% rename from resource/header/header.go rename to header/header.go index ad803f3f78a09c6e2e553a860cf68b95af20ebda..0159c411937c564853e98776eccee95b5d1312cf 100644 --- a/resource/header/header.go +++ b/header/header.go @@ -15,8 +15,11 @@ package header import ( + "encoding/json" + + "gitlab.com/tymonx/go-error/rterror" + "gitlab.com/tymonx/xlogic-toolchain/header/kind" "gitlab.com/tymonx/xlogic-toolchain/path" - "gitlab.com/tymonx/xlogic-toolchain/resource/header/kind" ) // Header defines single header file. @@ -37,3 +40,48 @@ func New(file path.Path) *Header { Path: file, } } + +// String returns path string. +func (h *Header) String() string { + return h.Path.String() +} + +// UnmarshalText decodes text to header file path. +func (h *Header) UnmarshalText(data []byte) error { + h.Path = path.Path(data) + h.Kind = kind.FromPath(h.Path) + + return nil +} + +// UnmarshalJSON decodes JSON to header file path. +func (h *Header) UnmarshalJSON(data []byte) error { + switch data[0] { + case '{': + case '"': + return h.UnmarshalText(data[1 : len(data)-1]) + case 'n': + *h = Header{} + return nil + default: + return rterror.New("invalid JSON type") + } + + object := new(struct { + Kind kind.Kind `json:"kind"` + Path path.Path `json:"path"` + }) + + if err := json.Unmarshal(data, object); err != nil { + return rterror.New("error occurred while decoding JSON", err) + } + + h.Kind = object.Kind + h.Path = object.Path + + if h.Kind == kind.Unknown { + h.Kind = kind.FromPath(h.Path) + } + + return nil +} diff --git a/header/header_test.go b/header/header_test.go new file mode 100644 index 0000000000000000000000000000000000000000..0c8af2b64e80a6642dae30e5d575a449b968d6b8 --- /dev/null +++ b/header/header_test.go @@ -0,0 +1,101 @@ +// Copyright 2020 Tymoteusz Blazejczyk +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package header_test + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" + "gitlab.com/tymonx/xlogic-toolchain/header" + "gitlab.com/tymonx/xlogic-toolchain/header/kind" + "gitlab.com/tymonx/xlogic-toolchain/path" +) + +func TestHeaderNew(test *testing.T) { + want := "file.h" + + h := header.New(path.Path(want)) + + assert.NotNil(test, h) + assert.Equal(test, kind.C, h.Kind) + assert.Equal(test, "c", h.Kind.String()) + assert.Equal(test, want, h.Path.String()) +} + +func TestHeaderString(test *testing.T) { + want := "file.svh" + + assert.NotNil(test, want, header.New(path.Path(want)).String()) +} + +func TestHeaderIs(test *testing.T) { + assert.True(test, header.Is("dir/file.hpp")) + assert.False(test, header.Is("/dir/dir")) +} + +func TestHeaderUnmarshalText(test *testing.T) { + want := "dir/file.svh" + + h := new(header.Header) + + assert.NoError(test, json.Unmarshal([]byte(` "`+want+`" `), h)) + + assert.Equal(test, want, h.Path.String()) + assert.Equal(test, kind.SystemVerilog, h.Kind) + assert.Equal(test, "systemverilog", h.Kind.String()) +} + +func TestHeaderUnmarshalJSONObject(test *testing.T) { + want := "dir/file.h++" + + h := new(header.Header) + + assert.NoError(test, json.Unmarshal([]byte(` { "path": "`+want+`" } `), h)) + + assert.Equal(test, want, h.Path.String()) + assert.Equal(test, kind.Cxx, h.Kind) + assert.Equal(test, "c++", h.Kind.String()) +} + +func TestHeaderUnmarshalJSONNull(test *testing.T) { + h := new(header.Header) + + assert.NoError(test, json.Unmarshal([]byte(` null `), h)) + + assert.Empty(test, h.Path.String()) + assert.Empty(test, h.Kind.String()) + assert.Equal(test, kind.Unknown, h.Kind) +} + +func TestHeaderUnmarshalJSONError(test *testing.T) { + h := new(header.Header) + + assert.Error(test, json.Unmarshal([]byte(`{"path":5}`), h)) + + assert.Empty(test, h.Path.String()) + assert.Empty(test, h.Kind.String()) + assert.Equal(test, kind.Unknown, h.Kind) +} + +func TestHeaderUnmarshalJSONInvalid(test *testing.T) { + h := new(header.Header) + + assert.Error(test, json.Unmarshal([]byte(`true`), h)) + + assert.Empty(test, h.Path.String()) + assert.Empty(test, h.Kind.String()) + assert.Equal(test, kind.Unknown, h.Kind) +} diff --git a/header/headers.go b/header/headers.go new file mode 100644 index 0000000000000000000000000000000000000000..59249349c721aaffb01ceb13e091dc85e480a9b1 --- /dev/null +++ b/header/headers.go @@ -0,0 +1,66 @@ +// Copyright 2020 Tymoteusz Blazejczyk +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package header + +import ( + "encoding/json" + + "gitlab.com/tymonx/go-error/rterror" + "gitlab.com/tymonx/xlogic-toolchain/path" +) + +// Headers defines a list of header files. +type Headers []Header + +// UnmarshalText decodes text to header file path. +func (h *Headers) UnmarshalText(data []byte) error { + *h = Headers{*New(path.Path(data))} + + return nil +} + +// UnmarshalJSON decodes JSON to header file path. +func (h *Headers) UnmarshalJSON(data []byte) error { + switch data[0] { + case '[': + case '{': + object := new(Header) + + if err := json.Unmarshal(data, object); err != nil { + return err + } + + *h = Headers{*object} + + return nil + case '"': + return h.UnmarshalText(data[1 : len(data)-1]) + case 'n': + *h = Headers{} + return nil + default: + return rterror.New("invalid JSON type") + } + + headers := []Header{} + + if err := json.Unmarshal(data, &headers); err != nil { + return rterror.New("error occurred while decoding JSON", err) + } + + *h = headers + + return nil +} diff --git a/header/headers_test.go b/header/headers_test.go new file mode 100644 index 0000000000000000000000000000000000000000..c97d98462b39f9120a3b5d22380c0d50648f3324 --- /dev/null +++ b/header/headers_test.go @@ -0,0 +1,94 @@ +// Copyright 2020 Tymoteusz Blazejczyk +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package header_test + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" + "gitlab.com/tymonx/xlogic-toolchain/header" + "gitlab.com/tymonx/xlogic-toolchain/header/kind" +) + +func TestHeadersUnmarshalText(test *testing.T) { + want := "dir/file.hpp" + + var h header.Headers + + assert.NoError(test, json.Unmarshal([]byte(` "`+want+`" `), &h)) + + assert.Len(test, h, 1) + assert.Equal(test, kind.Cxx, h[0].Kind) + assert.Equal(test, "c++", h[0].Kind.String()) + assert.Equal(test, want, h[0].Path.String()) +} + +func TestHeadersUnmarshalJSON(test *testing.T) { + var h header.Headers + + assert.NoError(test, json.Unmarshal([]byte(` ["dir/file.h", { "path": "file.svh" }]`), &h)) + + assert.Len(test, h, 2) + + assert.Equal(test, kind.C, h[0].Kind) + assert.Equal(test, "c", h[0].Kind.String()) + assert.Equal(test, "dir/file.h", h[0].Path.String()) + + assert.Equal(test, kind.SystemVerilog, h[1].Kind) + assert.Equal(test, "systemverilog", h[1].Kind.String()) + assert.Equal(test, "file.svh", h[1].Path.String()) +} + +func TestHeadersUnmarshalJSONObject(test *testing.T) { + want := "dir/file.vh" + + var h header.Headers + + assert.NoError(test, json.Unmarshal([]byte(` { "path": "`+want+`" } `), &h)) + + assert.Len(test, h, 1) + assert.Equal(test, want, h[0].Path.String()) + assert.Equal(test, kind.Verilog, h[0].Kind) + assert.Equal(test, "verilog", h[0].Kind.String()) +} + +func TestHeadersUnmarshalJSONNull(test *testing.T) { + var h header.Headers + + assert.NoError(test, json.Unmarshal([]byte(` null `), &h)) + assert.Empty(test, h) +} + +func TestHeadersUnmarshalJSONError(test *testing.T) { + var h header.Headers + + assert.Error(test, json.Unmarshal([]byte(`[5]`), &h)) + assert.Empty(test, h) +} + +func TestHeadersUnmarshalJSONObjectError(test *testing.T) { + var h header.Headers + + assert.Error(test, json.Unmarshal([]byte(`{"path":5}`), &h)) + assert.Empty(test, h) +} + +func TestHeadersUnmarshalJSONInvalid(test *testing.T) { + var h header.Headers + + assert.Error(test, json.Unmarshal([]byte(`true`), &h)) + assert.Empty(test, h) +} diff --git a/resource/header/kind/kind.go b/header/kind/kind.go similarity index 87% rename from resource/header/kind/kind.go rename to header/kind/kind.go index b0109b7cdca927c07fcf1220e2a59d9a690013bd..27fcb90c512c9ae64aeb09fbc7165b0fc5f6edd6 100644 --- a/resource/header/kind/kind.go +++ b/header/kind/kind.go @@ -78,14 +78,13 @@ func (k *Kind) String() string { return gToString[*k] } -// UnmarshalJSON decodes from JSON to kind. -func (k *Kind) UnmarshalJSON(data []byte) error { - *k = FromString(strings.Trim(string(data), `"`)) - +// UnmarshalText decodes from text to kind. +func (k *Kind) UnmarshalText(data []byte) error { + *k = FromString(string(data)) return nil } -// MarshalJSON decodes from kind to JSON. -func (k *Kind) MarshalJSON() (data []byte, err error) { - return []byte(`"` + k.String() + `"`), nil +// MarshalText decodes from kind to text. +func (k *Kind) MarshalText() (data []byte, err error) { + return []byte(k.String()), nil } diff --git a/resource/header/kind/kind_test.go b/header/kind/kind_test.go similarity index 91% rename from resource/header/kind/kind_test.go rename to header/kind/kind_test.go index f954e6b4e748879adab772c2957a1dd27b725c4b..cb3793f849cf0b5ec283dc689a9a2ae0222e808b 100644 --- a/resource/header/kind/kind_test.go +++ b/header/kind/kind_test.go @@ -20,7 +20,7 @@ import ( "github.com/stretchr/testify/assert" - "gitlab.com/tymonx/xlogic-toolchain/resource/header/kind" + "gitlab.com/tymonx/xlogic-toolchain/header/kind" ) func TestKindFromString(test *testing.T) { @@ -40,6 +40,11 @@ func TestKindFromPath(test *testing.T) { assert.Equal(test, kind.SystemVerilog, kind.FromPath("dir/file.sVh")) } +func TestKindIs(test *testing.T) { + assert.True(test, kind.Is("dir/file.svh")) + assert.False(test, kind.Is("dir/file.sv")) +} + func TestKindString(test *testing.T) { k := kind.FromPath("dir/file.svh") diff --git a/resource/id/id.go b/id/id.go similarity index 100% rename from resource/id/id.go rename to id/id.go diff --git a/resource/id/id_test.go b/id/id_test.go similarity index 95% rename from resource/id/id_test.go rename to id/id_test.go index e191f6acf1e601a96931e9de39e30c8d193895a3..fbcaed5a4a4250f9d0531ad358e6b13b1b426e77 100644 --- a/resource/id/id_test.go +++ b/id/id_test.go @@ -20,7 +20,7 @@ import ( "testing" "github.com/stretchr/testify/assert" - "gitlab.com/tymonx/xlogic-toolchain/resource/id" + "gitlab.com/tymonx/xlogic-toolchain/id" ) func TestIDGenerate(test *testing.T) { diff --git a/resource/id/id_utils_test.go b/id/id_utils_test.go similarity index 100% rename from resource/id/id_utils_test.go rename to id/id_utils_test.go diff --git a/resource/include/include.go b/include/include.go similarity index 53% rename from resource/include/include.go rename to include/include.go index 085e79c908ee22f75fa5fa6bb99719fef9152dc9..14ba87e701e8343e5f6a4fcb538a815efb7568c5 100644 --- a/resource/include/include.go +++ b/include/include.go @@ -15,10 +15,13 @@ package include import ( + "encoding/json" + + "gitlab.com/tymonx/go-error/rterror" "gitlab.com/tymonx/xlogic-toolchain/path" ) -// Include defines a single include path. +// Include defines a single include directory path. type Include struct { Path path.Path `json:"path,omitempty"` } @@ -34,3 +37,41 @@ func New(dir path.Path) *Include { Path: dir, } } + +// String returns path string. +func (i *Include) String() string { + return i.Path.String() +} + +// UnmarshalText decodes text to include directory path. +func (i *Include) UnmarshalText(data []byte) error { + i.Path = path.Path(data) + + return nil +} + +// UnmarshalJSON decodes JSON to include directory path. +func (i *Include) UnmarshalJSON(data []byte) error { + switch data[0] { + case '{': + case '"': + return i.UnmarshalText(data[1 : len(data)-1]) + case 'n': + *i = Include{} + return nil + default: + return rterror.New("invalid JSON type") + } + + object := new(struct { + Path path.Path `json:"path"` + }) + + if err := json.Unmarshal(data, object); err != nil { + return rterror.New("error occurred while decoding JSON", err) + } + + i.Path = object.Path + + return nil +} diff --git a/include/include_test.go b/include/include_test.go new file mode 100644 index 0000000000000000000000000000000000000000..f57a9a7dd94db9e47f6c313cfb3650f2bbc598bc --- /dev/null +++ b/include/include_test.go @@ -0,0 +1,83 @@ +// Copyright 2020 Tymoteusz Blazejczyk +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package include_test + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" + "gitlab.com/tymonx/xlogic-toolchain/include" + "gitlab.com/tymonx/xlogic-toolchain/path" +) + +func TestIncludeNew(test *testing.T) { + want := "dir/dir/dir" + + i := include.New(path.Path(want)) + + assert.NotNil(test, i) + assert.Equal(test, want, i.Path.String()) +} + +func TestIncludeString(test *testing.T) { + want := "dirA" + + assert.NotNil(test, want, include.New(path.Path(want)).String()) +} + +func TestIncludeIs(test *testing.T) { + assert.True(test, include.Is("dir/")) + assert.False(test, include.Is("file.c")) +} + +func TestIncludeUnmarshalText(test *testing.T) { + want := "dirB" + + i := new(include.Include) + + assert.NoError(test, json.Unmarshal([]byte(` "`+want+`" `), i)) + assert.Equal(test, want, i.Path.String()) +} + +func TestIncludeUnmarshalJSONObject(test *testing.T) { + want := "dirC" + + i := new(include.Include) + + assert.NoError(test, json.Unmarshal([]byte(` { "path": "`+want+`" } `), i)) + assert.Equal(test, want, i.Path.String()) +} + +func TestIncludeUnmarshalJSONNull(test *testing.T) { + i := new(include.Include) + + assert.NoError(test, json.Unmarshal([]byte(` null `), i)) + assert.Empty(test, i.Path.String()) +} + +func TestIncludeUnmarshalJSONError(test *testing.T) { + i := new(include.Include) + + assert.Error(test, json.Unmarshal([]byte(`{"path":5}`), i)) + assert.Empty(test, i.Path.String()) +} + +func TestIncludeUnmarshalJSONInvalid(test *testing.T) { + i := new(include.Include) + + assert.Error(test, json.Unmarshal([]byte(`true`), i)) + assert.Empty(test, i.Path.String()) +} diff --git a/include/includes.go b/include/includes.go new file mode 100644 index 0000000000000000000000000000000000000000..cc584840d95dbbcaad278d90fa44e0c8c35cb8d7 --- /dev/null +++ b/include/includes.go @@ -0,0 +1,66 @@ +// Copyright 2020 Tymoteusz Blazejczyk +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package include + +import ( + "encoding/json" + + "gitlab.com/tymonx/go-error/rterror" + "gitlab.com/tymonx/xlogic-toolchain/path" +) + +// Includes defines a list of include directory paths. +type Includes []Include + +// UnmarshalText decodes text to include directory path. +func (i *Includes) UnmarshalText(data []byte) error { + *i = Includes{*New(path.Path(data))} + + return nil +} + +// UnmarshalJSON decodes JSON to include directory path. +func (i *Includes) UnmarshalJSON(data []byte) error { + switch data[0] { + case '[': + case '{': + object := new(Include) + + if err := json.Unmarshal(data, object); err != nil { + return err + } + + *i = Includes{*object} + + return nil + case '"': + return i.UnmarshalText(data[1 : len(data)-1]) + case 'n': + *i = Includes{} + return nil + default: + return rterror.New("invalid JSON type") + } + + includes := []Include{} + + if err := json.Unmarshal(data, &includes); err != nil { + return rterror.New("error occurred while decoding JSON", err) + } + + *i = includes + + return nil +} diff --git a/include/includes_test.go b/include/includes_test.go new file mode 100644 index 0000000000000000000000000000000000000000..180afa639c60f364ef74e859ba58d4a83029094a --- /dev/null +++ b/include/includes_test.go @@ -0,0 +1,83 @@ +// Copyright 2020 Tymoteusz Blazejczyk +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package include_test + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" + "gitlab.com/tymonx/xlogic-toolchain/include" +) + +func TestIncludesUnmarshalText(test *testing.T) { + want := "dirA/dirB" + + var i include.Includes + + assert.NoError(test, json.Unmarshal([]byte(` "`+want+`" `), &i)) + + assert.Len(test, i, 1) + assert.Equal(test, want, i[0].Path.String()) +} + +func TestIncludesUnmarshalJSON(test *testing.T) { + var i include.Includes + + assert.NoError(test, json.Unmarshal([]byte(` ["dirB", { "path": "dirC/dirD" }]`), &i)) + + assert.Len(test, i, 2) + assert.Equal(test, "dirB", i[0].Path.String()) + assert.Equal(test, "dirC/dirD", i[1].Path.String()) +} + +func TestIncludesUnmarshalJSONObject(test *testing.T) { + want := "dirE/dirF" + + var i include.Includes + + assert.NoError(test, json.Unmarshal([]byte(` { "path": "`+want+`" } `), &i)) + + assert.Len(test, i, 1) + assert.Equal(test, want, i[0].Path.String()) +} + +func TestIncludesUnmarshalJSONNull(test *testing.T) { + var i include.Includes + + assert.NoError(test, json.Unmarshal([]byte(` null `), &i)) + assert.Empty(test, i) +} + +func TestIncludesUnmarshalJSONError(test *testing.T) { + var i include.Includes + + assert.Error(test, json.Unmarshal([]byte(`[5]`), &i)) + assert.Empty(test, i) +} + +func TestIncludesUnmarshalJSONObjectError(test *testing.T) { + var i include.Includes + + assert.Error(test, json.Unmarshal([]byte(`{"path":5}`), &i)) + assert.Empty(test, i) +} + +func TestIncludesUnmarshalJSONInvalid(test *testing.T) { + var i include.Includes + + assert.Error(test, json.Unmarshal([]byte(`true`), &i)) + assert.Empty(test, i) +} diff --git a/mode/mode.go b/mode/mode.go new file mode 100644 index 0000000000000000000000000000000000000000..fb698850637844e8caf9b5165c019bd5e6b9ae3b --- /dev/null +++ b/mode/mode.go @@ -0,0 +1,73 @@ +// Copyright 2020 Tymoteusz Blazejczyk +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mode + +import ( + "strings" + + "gitlab.com/tymonx/go-error/rterror" +) + +// These constants define compiler modes. +const ( + Executable Mode = 0 + Library Mode = 1 + Archive Mode = 2 + Object Mode = 3 +) + +var gFromString = map[string]Mode{ // nolint: gochecknoglobals + "": Executable, + "link": Executable, + "create": Executable, + "default": Executable, + "executable": Executable, + "library": Library, + "shared": Library, + "archive": Archive, + "static": Archive, + "object": Object, + "compile": Object, +} + +var gToString = map[Mode]string{ // nolint: gochecknoglobals + Executable: "executable", + Library: "library", + Archive: "archive", + Object: "object", +} + +// Mode defines compiler mode like creating executable, library, archive or object. +type Mode int + +// String returns compiler mode as a string. +func (m Mode) String() string { + return gToString[m] +} + +// UnmarshalText decodes text to compiler mode. +func (m *Mode) UnmarshalText(data []byte) error { + if value, ok := gFromString[strings.TrimSpace(strings.ToLower(string(data)))]; ok { + *m = value + return nil + } + + return rterror.New("error occurred while decoding text to compiler mode", string(data)) +} + +// MarshalText encodes compiler mode to text. +func (m Mode) MarshalText() (data []byte, err error) { + return []byte(m.String()), nil +} diff --git a/mode/mode_test.go b/mode/mode_test.go new file mode 100644 index 0000000000000000000000000000000000000000..7958f488ff37fb5892d6f48e3fce4b02edf13b25 --- /dev/null +++ b/mode/mode_test.go @@ -0,0 +1,51 @@ +// Copyright 2020 Tymoteusz Blazejczyk +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mode_test + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" + "gitlab.com/tymonx/xlogic-toolchain/mode" +) + +func TestModeString(test *testing.T) { + assert.Equal(test, "object", mode.Object.String()) + assert.Equal(test, "archive", mode.Archive.String()) + assert.Equal(test, "library", mode.Library.String()) + assert.Equal(test, "executable", mode.Executable.String()) +} + +func TestModeUnmarshalText(test *testing.T) { + var m mode.Mode + + assert.NoError(test, json.Unmarshal([]byte(` " object" `), &m)) + assert.Equal(test, mode.Object, m) +} + +func TestModeUnmarshalTextError(test *testing.T) { + var m mode.Mode + + assert.Error(test, json.Unmarshal([]byte(`"invalid"`), &m)) + assert.Equal(test, mode.Executable, m) +} + +func TestModeMarshalText(test *testing.T) { + data, err := json.Marshal(mode.Archive) + + assert.NoError(test, err) + assert.Equal(test, []byte(`"archive"`), data) +} diff --git a/option/option.go b/option/option.go deleted file mode 100644 index da3be191bdccfdb3088222eabf97f082bb5bf936..0000000000000000000000000000000000000000 --- a/option/option.go +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2020 Tymoteusz Blazejczyk -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package option - -import ( - "flag" - - "gitlab.com/tymonx/xlogic-toolchain/path" - "gitlab.com/tymonx/xlogic-toolchain/resource/define" - "gitlab.com/tymonx/xlogic-toolchain/resource/header" - "gitlab.com/tymonx/xlogic-toolchain/resource/include" -) - -// Option defines compiler options. -type Option struct { - Compile bool - Append bool - Static bool - Shared bool - Help bool - Output path.Path - Defines define.Defines - Headers header.Headers - Includes include.Includes -} - -// New creates a new option object. -func New() *Option { - return &Option{} -} - -// FlagSet sets flags. -func (o *Option) FlagSet(f *flag.FlagSet) *Option { - f.BoolVar(&o.Help, - "help", - false, - "Print help", - ) - - f.StringVar((*string)(&o.Output), - "o", - "output.json", - "Place output in file", - ) - - f.Var(&o.Includes, - "I", - "Directory to search for includes", - ) - - f.Var(&o.Headers, - "include", - "Process file as if appeared as the first line of the primary source file", - ) - - f.Var(&o.Defines, - "D", - "Set preprocessor define as NAME or NAME=VALUE", - ) - - f.Var(&define.Undefines{Defines: &o.Defines}, - "U", - "Undefine preprocessor define NAME", - ) - - f.BoolVar(&o.Compile, - "c", - false, - "Compile or assemble the source files, but do not link", - ) - - f.BoolVar(&o.Append, - "append", - false, - "Add files to existing archive", - ) - - f.BoolVar(&o.Static, - "static", - false, - "Prevents linking with the shared libraries", - ) - - f.BoolVar(&o.Shared, - "shared", - false, - "Produce a shared object which can then be linked with other objects to form an executable", - ) - - return o -} diff --git a/path/path.go b/path/path.go index c5cb2377e90c25d8b48ee0ddcbd06c87dc371ae0..f37475b2c81633ad226dd7d98feb8bdad274eb08 100644 --- a/path/path.go +++ b/path/path.go @@ -120,6 +120,17 @@ func (p *Path) IsAbsolute() bool { return filepath.IsAbs(p.String()) } +// UnmarshalText decodes text to file path. +func (p *Path) UnmarshalText(data []byte) error { + *p = Path(data) + return nil +} + +// MarshalText encodes file path to text. +func (p *Path) MarshalText() (data []byte, err error) { + return []byte(p.String()), nil +} + // Load loads object fields from file. func (p *Path) Load(object interface{}) (err error) { var data []byte diff --git a/path/path_test.go b/path/path_test.go index 454593d9b0baa979c255345e7a3c7b642f659fce..b9d299796c25d3f79b3335a028c934fb3e418def 100644 --- a/path/path_test.go +++ b/path/path_test.go @@ -204,7 +204,7 @@ func TestPathMarshalJSONInvalid(test *testing.T) { assert.Equal(test, []byte(`"`+want+`"`), data) } -func TestPatpDump(test *testing.T) { +func TestPathDump(test *testing.T) { object := &struct { Value int `json:"value"` }{ @@ -214,6 +214,7 @@ func TestPatpDump(test *testing.T) { file, err := ioutil.TempFile("", "tmp*") defer assert.NoError(test, os.Remove(file.Name())) + defer assert.NoError(test, file.Close()) assert.NoError(test, err) @@ -222,7 +223,7 @@ func TestPatpDump(test *testing.T) { assert.NoError(test, p.Dump(object)) } -func TestPatpDumpError(test *testing.T) { +func TestPathDumpError(test *testing.T) { object := &struct { Chan chan struct{} }{} @@ -230,6 +231,7 @@ func TestPatpDumpError(test *testing.T) { file, err := ioutil.TempFile("", "tmp*") defer assert.NoError(test, os.Remove(file.Name())) + defer assert.NoError(test, file.Close()) assert.NoError(test, err) @@ -237,3 +239,32 @@ func TestPatpDumpError(test *testing.T) { assert.Error(test, p.Dump(object)) } + +func TestPathLoad(test *testing.T) { + object := &struct { + Value int `json:"value"` + }{} + + file, err := ioutil.TempFile("", "tmp*") + + defer assert.NoError(test, os.Remove(file.Name())) + defer assert.NoError(test, file.Close()) + + p := path.Path(file.Name()) + + assert.NoError(test, err) + assert.NoError(test, ioutil.WriteFile(file.Name(), []byte(`{ "value": 4 }`), 0600)) + assert.NoError(test, p.Load(&object)) + assert.Equal(test, 4, object.Value) +} + +func TestPathLoadError(test *testing.T) { + object := &struct { + Value int `json:"value"` + }{} + + p := path.Path("invalid") + + assert.Error(test, p.Load(&object)) + assert.Zero(test, object.Value) +} diff --git a/path/paths.go b/path/paths.go index 6fc8693197cb2cbf47eae15a507e3c4754c8b0d2..7fadef2cfc657e2fd865888605b01fdd31dfb1bc 100644 --- a/path/paths.go +++ b/path/paths.go @@ -16,8 +16,3 @@ package path // Paths defines a list of file paths. type Paths []Path - -// Add adds path. -func (p *Paths) Add(file Path) { - *p = append(*p, file) -} diff --git a/resource/archive/acrhives.go b/resource/archive/acrhives.go deleted file mode 100644 index 7f7552208d1cba294666193a4efe3ae34563918e..0000000000000000000000000000000000000000 --- a/resource/archive/acrhives.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2020 Tymoteusz Blazejczyk -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package archive - -// Archives defines a list of archive files with compiled source files. -type Archives []*Archive diff --git a/resource/archive/archive.go b/resource/archive/archive.go deleted file mode 100644 index dc76d7c9948b3a5df7f564f7ca42e9f1a945a202..0000000000000000000000000000000000000000 --- a/resource/archive/archive.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2020 Tymoteusz Blazejczyk -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package archive - -import ( - "strings" - - "gitlab.com/tymonx/xlogic-toolchain/path" - "gitlab.com/tymonx/xlogic-toolchain/resource/object" -) - -var gExtension = map[string]bool{ // nolint: gochecknoglobals - ".a": true, - ".lib": true, -} - -// Archive defines storage to archive compiled object files. -type Archive struct { - Path path.Path `json:"path,omitempty"` - Object object.Objects `json:"object,omitempty"` -} - -// Is returns true if path is a archive file, otherwise it returns false. -func Is(file path.Path) bool { - return gExtension[strings.ToLower(file.Extension())] -} - -// New creates a new archive object. -func New(file path.Path) *Archive { - return &Archive{ - Path: file, - } -} diff --git a/resource/define/defines.go b/resource/define/defines.go deleted file mode 100644 index 9ab025a13b8e5315db63df74386f8fdb5c6a8e11..0000000000000000000000000000000000000000 --- a/resource/define/defines.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2020 Tymoteusz Blazejczyk -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package define - -// Defines defines a list of defines. -type Defines []*Define - -// Strings returns string representation. -func (*Defines) String() string { - return "" -} - -// Set is called once, in command line order, for each flag present. -func (d *Defines) Set(value string) error { - *d = append(*d, New(value)) - - return nil -} diff --git a/resource/define/defines_test.go b/resource/define/defines_test.go deleted file mode 100644 index b0207ce83cac4be5e4492121e8eec8fbf0d9df24..0000000000000000000000000000000000000000 --- a/resource/define/defines_test.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2020 Tymoteusz Blazejczyk -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package define_test - -import ( - "flag" - "testing" - - "github.com/stretchr/testify/assert" - "gitlab.com/tymonx/xlogic-toolchain/resource/define" -) - -func TestSourcesSet(test *testing.T) { - var d define.Defines - - fs := flag.NewFlagSet("example", flag.ExitOnError) - fs.Var(&d, "D", "") - - assert.NoError(test, fs.Parse([]string{"-D", "ABC=BAR", "-D", "XYZ", "-D", "X=4", "file"})) - assert.Len(test, d, 3) - assert.Equal(test, "ABC", d[0].Name) - assert.Equal(test, "BAR", d[0].Value) - assert.Equal(test, "XYZ", d[1].Name) - assert.Empty(test, d[1].Value) - assert.Equal(test, "X", d[2].Name) - assert.Equal(test, "4", d[2].Value) -} - -func TestSourcesUndefine(test *testing.T) { - var d define.Defines - - fs := flag.NewFlagSet("example", flag.ExitOnError) - fs.Var(&define.Undefines{Defines: &d}, "U", "") - - assert.NoError(test, fs.Parse([]string{"-U", "FOO=BAR", "-U", "XYZ", "file"})) - assert.Len(test, d, 2) - assert.Equal(test, "FOO", d[0].Name) - assert.Equal(test, "BAR", d[0].Value) - assert.Equal(test, "XYZ", d[1].Name) - assert.Empty(test, d[1].Value) -} diff --git a/resource/define/undefines.go b/resource/define/undefines.go deleted file mode 100644 index ff84a72d78a16bfacc18b009f682cb00d290a17f..0000000000000000000000000000000000000000 --- a/resource/define/undefines.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2020 Tymoteusz Blazejczyk -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package define - -// Undefines provides an undefine wrapper around define object. -type Undefines struct { - Defines *Defines -} - -// Strings returns string representation. -func (*Undefines) String() string { - return "" -} - -// Set is called once, in command line order, for each flag present. -func (u *Undefines) Set(value string) error { - *u.Defines = append(*u.Defines, New(value).Undef()) - - return nil -} diff --git a/resource/executable/executable.go b/resource/executable/executable.go deleted file mode 100644 index ac79b5573adad5edb7a0ef52803d4a3e2d7d2eac..0000000000000000000000000000000000000000 --- a/resource/executable/executable.go +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2020 Tymoteusz Blazejczyk -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package executable - -import ( - "strings" - - "gitlab.com/tymonx/xlogic-toolchain/path" - "gitlab.com/tymonx/xlogic-toolchain/resource/archive" - "gitlab.com/tymonx/xlogic-toolchain/resource/define" - "gitlab.com/tymonx/xlogic-toolchain/resource/header" - "gitlab.com/tymonx/xlogic-toolchain/resource/include" - "gitlab.com/tymonx/xlogic-toolchain/resource/library" - "gitlab.com/tymonx/xlogic-toolchain/resource/object" - "gitlab.com/tymonx/xlogic-toolchain/resource/source" -) - -var gExtension = map[string]bool{ // nolint: gochecknoglobals - "": true, - ".exe": true, -} - -// Executable defines an executable. -type Executable struct { - Path path.Path `json:"path,omitempty"` - Object object.Objects `json:"object,omitempty"` - Source source.Sources `json:"source,omitempty"` - Define define.Defines `json:"define,omitempty"` - Header header.Headers `json:"header,omitempty"` - Include include.Includes `json:"include,omitempty"` - Archive archive.Archives `json:"archive,omitempty"` - Library library.Libraries `json:"library,omitempty"` -} - -// Is returns true if path is an executable, otherwise it returns false. -func Is(file path.Path) bool { - return gExtension[strings.ToLower(file.Extension())] -} - -// New creates a new executable object. -func New(file path.Path) *Executable { - return &Executable{ - Path: file, - } -} diff --git a/resource/header/headers.go b/resource/header/headers.go deleted file mode 100644 index 00cce43a6c42441061348bd2a9951f38ff3afbe9..0000000000000000000000000000000000000000 --- a/resource/header/headers.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2020 Tymoteusz Blazejczyk -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package header - -import ( - "gitlab.com/tymonx/xlogic-toolchain/path" -) - -// Headers defines a list of header files. -type Headers []*Header - -// Strings returns string representation. -func (*Headers) String() string { - return "" -} - -// Set is called once, in command line order, for each flag present. -func (h *Headers) Set(value string) error { - *h = append(*h, New(path.Path(value))) - - return nil -} diff --git a/resource/header/headers_test.go b/resource/header/headers_test.go deleted file mode 100644 index dd8757ba127ab77b9510ce1a22c66b9338b7e9c2..0000000000000000000000000000000000000000 --- a/resource/header/headers_test.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2020 Tymoteusz Blazejczyk -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package header_test - -import ( - "flag" - "testing" - - "github.com/stretchr/testify/assert" - "gitlab.com/tymonx/xlogic-toolchain/resource/header" -) - -func TestSourcesSet(test *testing.T) { - var h header.Headers - - fs := flag.NewFlagSet("example", flag.ExitOnError) - fs.Var(&h, "include", "") - - assert.NoError(test, fs.Parse([]string{"-include", "/dir/file.h", "-include", "file.h", "file"})) - assert.Len(test, h, 2) - assert.Equal(test, "/dir/file.h", h[0].Path.String()) - assert.Equal(test, "file.h", h[1].Path.String()) -} diff --git a/resource/include/includes.go b/resource/include/includes.go deleted file mode 100644 index a9cf512f860624e175eed61ee8d704104410e280..0000000000000000000000000000000000000000 --- a/resource/include/includes.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2020 Tymoteusz Blazejczyk -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package include - -import ( - "gitlab.com/tymonx/xlogic-toolchain/path" -) - -// Includes defines a list of include paths. -type Includes []*Include - -// Strings returns string representation. -func (*Includes) String() string { - return "" -} - -// Set is called once, in command line order, for each flag present. -func (i *Includes) Set(value string) error { - *i = append(*i, New(path.Path(value))) - - return nil -} diff --git a/resource/include/includes_test.go b/resource/include/includes_test.go deleted file mode 100644 index 7d2e8da74908b020edf6c6f59b697249749052d4..0000000000000000000000000000000000000000 --- a/resource/include/includes_test.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2020 Tymoteusz Blazejczyk -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package include_test - -import ( - "flag" - "testing" - - "github.com/stretchr/testify/assert" - "gitlab.com/tymonx/xlogic-toolchain/resource/include" -) - -func TestSourcesSet(test *testing.T) { - var i include.Includes - - fs := flag.NewFlagSet("example", flag.ExitOnError) - fs.Var(&i, "I", "") - - assert.NoError(test, fs.Parse([]string{"-I", "/dir/dir", "-I", "/dir", "file"})) - assert.Len(test, i, 2) - assert.Equal(test, "/dir/dir", i[0].Path.String()) - assert.Equal(test, "/dir", i[1].Path.String()) -} diff --git a/resource/kind/kind.go b/resource/kind/kind.go deleted file mode 100644 index c6b2eebd6e4c9bb6d91958e54e1c99d3b5535b11..0000000000000000000000000000000000000000 --- a/resource/kind/kind.go +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2020 Tymoteusz Blazejczyk -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package kind - -import ( - "strings" -) - -// These constants define values for single resource. -const ( - Unknown Kind = 0 - Generic Kind = 1 - Source Kind = 2 - Header Kind = 3 - Define Kind = 4 - Output Kind = 5 - Object Kind = 6 - Include Kind = 7 - Archive Kind = 8 - Library Kind = 9 - Executable Kind = 10 -) - -var gToString = map[Kind]string{ // nolint: gochecknoglobals - Unknown: "", - Generic: "generic", - Source: "source", - Header: "header", - Define: "define", - Output: "output", - Object: "object", - Include: "include", - Archive: "archive", - Library: "library", - Executable: "executable", -} - -var gFromString = map[string]Kind{ // nolint: gochecknoglobals - "": Unknown, - "generic": Generic, - "source": Source, - "header": Header, - "define": Define, - "output": Output, - "object": Object, - "include": Include, - "archive": Archive, - "library": Library, - "executable": Executable, -} - -// Kind defines resource kind. -type Kind int - -// New returns a new kind from given string. -func New(str string) Kind { - return gFromString[strings.TrimSpace(strings.ToLower(str))] -} - -// String returns kind as string. -func (k *Kind) String() string { - return gToString[*k] -} - -// UnmarshalJSON decodes from JSON to kind. -func (k *Kind) UnmarshalJSON(data []byte) error { - *k = New(strings.Trim(string(data), `"`)) - - return nil -} - -// MarshalJSON decodes from kind to JSON. -func (k *Kind) MarshalJSON() (data []byte, err error) { - return []byte(`"` + k.String() + `"`), nil -} diff --git a/resource/kind/kind_test.go b/resource/kind/kind_test.go deleted file mode 100644 index cbe10d6c8b142bc3cc92729bf4c70f3960c0a947..0000000000000000000000000000000000000000 --- a/resource/kind/kind_test.go +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2020 Tymoteusz Blazejczyk -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package kind_test - -import ( - "encoding/json" - "testing" - - "github.com/stretchr/testify/assert" - - "gitlab.com/tymonx/xlogic-toolchain/resource/kind" -) - -func TestKindFromString(test *testing.T) { - assert.Equal(test, kind.Archive, kind.New(" archiVe ")) - assert.Equal(test, kind.Define, kind.New(" define")) - assert.Equal(test, kind.Executable, kind.New("executable")) - assert.Equal(test, kind.Header, kind.New("Header")) - assert.Equal(test, kind.Library, kind.New(" library ")) -} - -func TestKindString(test *testing.T) { - k := kind.New(" ArchiVe") - - assert.Equal(test, "archive", k.String()) -} - -func TestKindUnmarshalJSON(test *testing.T) { - var k kind.Kind - - assert.NoError(test, json.Unmarshal([]byte(` " object " `), &k)) - assert.Equal(test, kind.Object, k) -} - -func TestKindMarshalJSON(test *testing.T) { - k := kind.New("SouRCE") - - data, err := json.Marshal(&k) - - assert.NoError(test, err) - assert.Equal(test, []byte(`"source"`), data) -} diff --git a/resource/library/libraries.go b/resource/library/libraries.go deleted file mode 100644 index 5137337396ca6f249a2287ce3d1275705dcf84dd..0000000000000000000000000000000000000000 --- a/resource/library/libraries.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2020 Tymoteusz Blazejczyk -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package library - -// Libraries returns a list of shared libraries. -type Libraries []*Library diff --git a/resource/library/library.go b/resource/library/library.go deleted file mode 100644 index 7e0ccbf90d81fab7c89ec1eabcbcc76839209244..0000000000000000000000000000000000000000 --- a/resource/library/library.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2020 Tymoteusz Blazejczyk -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package library - -import ( - "strings" - - "gitlab.com/tymonx/xlogic-toolchain/path" - "gitlab.com/tymonx/xlogic-toolchain/resource/archive" - "gitlab.com/tymonx/xlogic-toolchain/resource/define" - "gitlab.com/tymonx/xlogic-toolchain/resource/header" - "gitlab.com/tymonx/xlogic-toolchain/resource/include" - "gitlab.com/tymonx/xlogic-toolchain/resource/object" - "gitlab.com/tymonx/xlogic-toolchain/resource/source" -) - -var gExtension = map[string]bool{ // nolint: gochecknoglobals - ".so": true, - ".dll": true, -} - -// Library defines a shared library. -type Library struct { - Path path.Path `json:"path,omitempty"` - Object object.Objects `json:"object,omitempty"` - Source source.Sources `json:"source,omitempty"` - Define define.Defines `json:"define,omitempty"` - Header header.Headers `json:"header,omitempty"` - Include include.Includes `json:"include,omitempty"` - Archive archive.Archives `json:"archive,omitempty"` -} - -// Is returns true if path is a library file, otherwise it returns false. -func Is(file path.Path) bool { - return gExtension[strings.ToLower(file.Extension())] -} - -// New creates a new library object. -func New(file path.Path) *Library { - return &Library{ - Path: file, - } -} diff --git a/resource/object/object.go b/resource/object/object.go deleted file mode 100644 index c7a9101e0d653b6b072bed109a3d66e1f611cc3d..0000000000000000000000000000000000000000 --- a/resource/object/object.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2020 Tymoteusz Blazejczyk -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package object - -import ( - "strings" - - "gitlab.com/tymonx/xlogic-toolchain/path" - "gitlab.com/tymonx/xlogic-toolchain/resource/define" - "gitlab.com/tymonx/xlogic-toolchain/resource/header" - "gitlab.com/tymonx/xlogic-toolchain/resource/include" - "gitlab.com/tymonx/xlogic-toolchain/resource/output" - "gitlab.com/tymonx/xlogic-toolchain/resource/source" -) - -var gExtension = map[string]bool{ // nolint: gochecknoglobals - ".o": true, - ".obj": true, -} - -// Object defines compiled source file or files to object. -type Object struct { - Path path.Path `json:"path,omitempty"` - Source source.Sources `json:"source,omitempty"` - Define define.Defines `json:"define,omitempty"` - Header header.Headers `json:"header,omitempty"` - Output output.Outputs `json:"output,omitempty"` - Include include.Includes `json:"include,omitempty"` -} - -// Is returns true if path is a archive file, otherwise it returns false. -func Is(file path.Path) bool { - return gExtension[strings.ToLower(file.Extension())] -} - -// New creates a new object. -func New(file path.Path) *Object { - return &Object{ - Path: file, - } -} diff --git a/resource/object/objects.go b/resource/object/objects.go deleted file mode 100644 index b997e3d8bcff4e4a98040be45f3dedb13af0e7dc..0000000000000000000000000000000000000000 --- a/resource/object/objects.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2020 Tymoteusz Blazejczyk -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package object - -// Objects defines a list of compiled object files. -type Objects []*Object diff --git a/resource/output/kind/kind.go b/resource/output/kind/kind.go deleted file mode 100644 index 2556f44af6a4b858e0b88a9f1c63fb713b504c07..0000000000000000000000000000000000000000 --- a/resource/output/kind/kind.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2020 Tymoteusz Blazejczyk -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package kind - -import ( - "strings" - - "gitlab.com/tymonx/xlogic-toolchain/path" -) - -// These constants define values for generted output file. -const ( - Unknown Kind = 0 - File Kind = 1 - Text Kind = 2 - Binary Kind = 3 - Object Kind = 4 - Source Kind = 5 - Header Kind = 6 - Script Kind = 7 - Executable Kind = 8 -) - -var gToString = map[Kind]string{ // nolint: gochecknoglobals - Unknown: "", - File: "file", - Text: "text", - Binary: "binary", - Object: "object", - Source: "source", - Header: "header", - Script: "script", - Executable: "executable", -} - -var gFromString = map[string]Kind{ // nolint: gochecknoglobals - "": Unknown, - "file": File, - "text": Text, - "binary": Binary, - "object": Object, - "source": Source, - "header": Header, - "script": Script, - "executable": Executable, -} - -var gFromExtension = map[string]Kind{ // nolint: gochecknoglobals - ".txt": Text, - ".o": Object, - ".exe": Executable, -} - -// Kind defines generated output file kind. -type Kind int - -// FromString returns kind from given string. -func FromString(str string) Kind { - return gFromString[strings.TrimSpace(strings.ToLower(str))] -} - -// FromPath returns kind from given file path. -func FromPath(file path.Path) Kind { - return gFromExtension[strings.ToLower(file.Extension())] -} - -// String returns kind as string. -func (k *Kind) String() string { - return gToString[*k] -} - -// UnmarshalJSON decodes from JSON to kind. -func (k *Kind) UnmarshalJSON(data []byte) error { - *k = FromString(strings.Trim(string(data), `"`)) - - return nil -} - -// MarshalJSON decodes from kind to JSON. -func (k *Kind) MarshalJSON() (data []byte, err error) { - return []byte(`"` + k.String() + `"`), nil -} diff --git a/resource/output/kind/kind_test.go b/resource/output/kind/kind_test.go deleted file mode 100644 index 7d8e2605ad4d8b1c4fec4adc3382275a13f42437..0000000000000000000000000000000000000000 --- a/resource/output/kind/kind_test.go +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2020 Tymoteusz Blazejczyk -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package kind_test - -import ( - "encoding/json" - "testing" - - "github.com/stretchr/testify/assert" - - "gitlab.com/tymonx/xlogic-toolchain/resource/output/kind" -) - -func TestKindFromString(test *testing.T) { - assert.Equal(test, kind.File, kind.FromString(" file")) - assert.Equal(test, kind.Text, kind.FromString("teXt")) - assert.Equal(test, kind.Binary, kind.FromString(" BinaRY")) - assert.Equal(test, kind.Executable, kind.FromString(" executable")) -} - -func TestKindFromPath(test *testing.T) { - assert.Equal(test, kind.Text, kind.FromPath("dir/file.txt")) - assert.Equal(test, kind.Executable, kind.FromPath("dir/file.exe")) -} - -func TestKindString(test *testing.T) { - k := kind.FromPath("dir/file.o") - - assert.Equal(test, "object", k.String()) -} - -func TestKindUnmarshalJSON(test *testing.T) { - var k kind.Kind - - assert.NoError(test, json.Unmarshal([]byte(` " Script " `), &k)) - assert.Equal(test, kind.Script, k) -} - -func TestKindMarshalJSON(test *testing.T) { - k := kind.FromPath("dir/file.o") - - data, err := json.Marshal(&k) - - assert.NoError(test, err) - assert.Equal(test, []byte(`"object"`), data) -} diff --git a/resource/output/metadata/metadata.go b/resource/output/metadata/metadata.go deleted file mode 100644 index 19c55bde2073427754e2e791ee78dcde95d3594e..0000000000000000000000000000000000000000 --- a/resource/output/metadata/metadata.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2020 Tymoteusz Blazejczyk -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package metadata - -// Metadata defines metadata for generated output file. -type Metadata map[string]interface{} diff --git a/resource/output/output.go b/resource/output/output.go deleted file mode 100644 index 7f231cd9b89aac95d608446cddb3efa26bfa13af..0000000000000000000000000000000000000000 --- a/resource/output/output.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2020 Tymoteusz Blazejczyk -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package output - -import ( - "gitlab.com/tymonx/xlogic-toolchain/path" - "gitlab.com/tymonx/xlogic-toolchain/resource/output/kind" - "gitlab.com/tymonx/xlogic-toolchain/resource/output/metadata" -) - -// Output defines single generated output file. -type Output struct { - Kind kind.Kind `json:"kind,omitempty"` - Path path.Path `json:"path,omitempty"` - Metadata metadata.Metadata `json:"metadata,omitempty"` -} - -// New creates a new generated output file object from given file path. -func New(file path.Path) *Output { - return &Output{ - Kind: kind.FromPath(file), - Path: file, - } -} diff --git a/resource/output/outputs.go b/resource/output/outputs.go deleted file mode 100644 index 2bbcf07849a31a70328c624729162186ae9592c1..0000000000000000000000000000000000000000 --- a/resource/output/outputs.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2020 Tymoteusz Blazejczyk -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package output - -// Outputs defines a list of generated output files. -type Outputs []*Output diff --git a/resource/resource.go b/resource/resource.go deleted file mode 100644 index 7d460aecd8eaf687c1a11ce4dc8d577742fb4b7f..0000000000000000000000000000000000000000 --- a/resource/resource.go +++ /dev/null @@ -1,242 +0,0 @@ -// Copyright 2020 Tymoteusz Blazejczyk -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package resource - -import ( - "encoding/json" - "strings" - - "gitlab.com/tymonx/xlogic-toolchain/cerr" - "gitlab.com/tymonx/xlogic-toolchain/path" - "gitlab.com/tymonx/xlogic-toolchain/resource/archive" - "gitlab.com/tymonx/xlogic-toolchain/resource/define" - "gitlab.com/tymonx/xlogic-toolchain/resource/executable" - "gitlab.com/tymonx/xlogic-toolchain/resource/header" - "gitlab.com/tymonx/xlogic-toolchain/resource/id" - "gitlab.com/tymonx/xlogic-toolchain/resource/include" - "gitlab.com/tymonx/xlogic-toolchain/resource/kind" - "gitlab.com/tymonx/xlogic-toolchain/resource/library" - "gitlab.com/tymonx/xlogic-toolchain/resource/object" - "gitlab.com/tymonx/xlogic-toolchain/resource/output" - "gitlab.com/tymonx/xlogic-toolchain/resource/source" -) - -var gExtension = map[string]bool{ // nolint: gochecknoglobals - ".json": true, -} - -// Resource defines a single resource. JSON API compatibility. -type Resource struct { - Kind kind.Kind `json:"type"` - ID id.ID `json:"id"` - Attributes interface{} `json:"attributes,omitempty"` -} - -// Is returns true if path is a resource file, otherwise it returns false. -func Is(file path.Path) bool { - return gExtension[strings.ToLower(file.Extension())] -} - -// New creates a new resource. -func New(k kind.Kind) *Resource { - return &Resource{ - ID: id.New(), - Kind: k, - Attributes: create(k), - } -} - -func newWith(k kind.Kind, attributes interface{}) *Resource { - return &Resource{ - ID: id.New(), - Kind: k, - Attributes: attributes, - } -} - -// Load loads resource from file. -func Load(file path.Path) (r *Resource, err error) { - if Is(file) { - r = new(Resource) - - if err := r.Load(file); err != nil { - return nil, err - } - - return r, nil - } - - if library.Is(file) { - return newWith(kind.Library, library.New(file)), nil - } - - if archive.Is(file) { - return newWith(kind.Archive, archive.New(file)), nil - } - - if object.Is(file) { - return newWith(kind.Object, object.New(file)), nil - } - - if source.Is(file) { - return newWith(kind.Source, source.New(file)), nil - } - - if header.Is(file) { - return newWith(kind.Header, header.New(file)), nil - } - - if include.Is(file) { - return newWith(kind.Include, include.New(file)), nil - } - - r = new(Resource) - - if err := r.Load(file); err != nil { - return nil, err - } - - return r, nil -} - -// Loads loads resources from given files. -func Loads(files path.Paths) (r Resources, err error) { - r = make(Resources, len(files)) - - for i, file := range files { - if r[i], err = Load(file); err != nil { - return nil, err - } - } - - return r, nil -} - -// Generic returns generic resource. -func (r *Resource) Generic() map[string]interface{} { - return r.Attributes.(map[string]interface{}) -} - -// Archive returns archive resource. -func (r *Resource) Archive() *archive.Archive { - return r.Attributes.(*archive.Archive) -} - -// Library returns library resource. -func (r *Resource) Library() *library.Library { - return r.Attributes.(*library.Library) -} - -// Define returns define resource. -func (r *Resource) Define() *define.Define { - return r.Attributes.(*define.Define) -} - -// Header returns header resource. -func (r *Resource) Header() *header.Header { - return r.Attributes.(*header.Header) -} - -// Include returns include resource. -func (r *Resource) Include() *include.Include { - return r.Attributes.(*include.Include) -} - -// Object returns object resource. -func (r *Resource) Object() *object.Object { - return r.Attributes.(*object.Object) -} - -// Output returns output resource. -func (r *Resource) Output() *output.Output { - return r.Attributes.(*output.Output) -} - -// Source returns source resource. -func (r *Resource) Source() *source.Source { - return r.Attributes.(*source.Source) -} - -// Executable returns executable resource. -func (r *Resource) Executable() *executable.Executable { - return r.Attributes.(*executable.Executable) -} - -// Load loads from file. -func (r *Resource) Load(file path.Path) error { - return file.Load(r) -} - -// Dump dumps to file. -func (r *Resource) Dump(file path.Path) error { - return file.Dump(r) -} - -// UnmarshalJSON decodes JSON to resource. -func (r *Resource) UnmarshalJSON(data []byte) error { - if data[0] != '{' { - return cerr.InvalidValue - } - - obj := &struct { - ID id.ID `json:"id"` - Kind kind.Kind `json:"type"` - }{} - - if err := json.Unmarshal(data, obj); err != nil { - return err - } - - attrs := &struct { - Attributes interface{} `json:"attributes"` - }{ - Attributes: create(obj.Kind), - } - - if err := json.Unmarshal(data, attrs); err != nil { - return err - } - - r.ID = obj.ID - r.Kind = obj.Kind - r.Attributes = attrs.Attributes - - return nil -} - -func create(k kind.Kind) interface{} { - switch k { - case kind.Source: - return new(source.Source) - case kind.Object: - return new(object.Object) - case kind.Archive: - return new(archive.Archive) - case kind.Library: - return new(library.Library) - case kind.Include: - return new(include.Include) - case kind.Define: - return new(define.Define) - case kind.Header: - return new(header.Header) - case kind.Output: - return new(output.Output) - case kind.Executable: - return new(executable.Executable) - default: - return make(map[string]interface{}) - } -} diff --git a/resource/resources.go b/resource/resources.go deleted file mode 100644 index df64e03480a01e10c6c57460e955625321d1ce94..0000000000000000000000000000000000000000 --- a/resource/resources.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2020 Tymoteusz Blazejczyk -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package resource - -// Resources defines a list of resources. JSON API compatibility. -type Resources []*Resource diff --git a/resource/source/source.go b/resource/source/source.go deleted file mode 100644 index e3a80b1b3912e0bcd7bb3df9270d0765422fc706..0000000000000000000000000000000000000000 --- a/resource/source/source.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2020 Tymoteusz Blazejczyk -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package source - -import ( - "gitlab.com/tymonx/xlogic-toolchain/path" - "gitlab.com/tymonx/xlogic-toolchain/resource/source/kind" -) - -// Source defines single source file. -type Source struct { - Kind kind.Kind `json:"kind,omitempty"` - Path path.Path `json:"path,omitempty"` -} - -// New creates a new source object. -func New(file path.Path) *Source { - return &Source{ - Kind: kind.FromPath(file), - Path: file, - } -} - -// Is returns true if path is a source file, otherwise it returns false. -func Is(file path.Path) bool { - return kind.Is(file) -} - -// String returns path string. -func (s *Source) String() string { - return s.Path.String() -} diff --git a/resource/source/sources_test.go b/resource/source/sources_test.go deleted file mode 100644 index ec39833460579a888afec14b4b8219f3433e619f..0000000000000000000000000000000000000000 --- a/resource/source/sources_test.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2020 Tymoteusz Blazejczyk -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package source_test - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "gitlab.com/tymonx/xlogic-toolchain/path" - "gitlab.com/tymonx/xlogic-toolchain/resource/source" -) - -func TestSourceNew(test *testing.T) { - assert.NotNil(test, source.New("file.c")) -} - -func TestSourceString(test *testing.T) { - want := "file.sv" - - assert.NotNil(test, want, source.New(path.Path(want)).String()) -} diff --git a/undefine/undefine.go b/undefine/undefine.go new file mode 100644 index 0000000000000000000000000000000000000000..48acae99ffde7ea71d9b7638ad029254f2240b68 --- /dev/null +++ b/undefine/undefine.go @@ -0,0 +1,71 @@ +// Copyright 2020 Tymoteusz Blazejczyk +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package undefine + +import ( + "encoding/json" + "strings" + + "gitlab.com/tymonx/go-error/rterror" +) + +// Undefine undefines undefine. +type Undefine struct { + Name string `json:"name,omitempty"` +} + +// New creates a new undefine object. +func New(name string) *Undefine { + return &Undefine{ + Name: strings.TrimSpace(name), + } +} + +// String returns undefine as string. +func (u *Undefine) String() string { + return u.Name +} + +// UnmarshalText decodes text to undefine. +func (u *Undefine) UnmarshalText(data []byte) error { + u.Name = strings.TrimSpace(string(data)) + return nil +} + +// UnmarshalJSON decodes JSON to undefine. +func (u *Undefine) UnmarshalJSON(data []byte) error { + switch data[0] { + case '{': + case '"': + return u.UnmarshalText(data[1 : len(data)-1]) + case 'n': + *u = Undefine{} + return nil + default: + return rterror.New("invalid JSON type") + } + + object := new(struct { + Name string `json:"name"` + }) + + if err := json.Unmarshal(data, object); err != nil { + return rterror.New("error occurred while decoding JSON", err) + } + + u.Name = strings.TrimSpace(object.Name) + + return nil +} diff --git a/undefine/undefine_test.go b/undefine/undefine_test.go new file mode 100644 index 0000000000000000000000000000000000000000..867a026269b6e15867462c0823ff3e03bc46604c --- /dev/null +++ b/undefine/undefine_test.go @@ -0,0 +1,88 @@ +// Copyright 2020 Tymoteusz Blazejczyk +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implieu. +// See the License for the specific language governing permissions and +// limitations under the License. + +package undefine_test + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" + "gitlab.com/tymonx/xlogic-toolchain/undefine" +) + +func TestUndefineNew(test *testing.T) { + want := "Name" + + u := undefine.New(want) + + assert.NotNil(test, u) + assert.Equal(test, "Name", u.Name) + assert.Equal(test, want, u.String()) +} + +func TestUndefineString(test *testing.T) { + want := "NAME" + + assert.NotNil(test, want, undefine.New(want).String()) +} + +func TestUndefineUnmarshalText(test *testing.T) { + want := "MYDEF" + + u := new(undefine.Undefine) + + assert.NoError(test, json.Unmarshal([]byte(` " `+want+` " `), u)) + + assert.Equal(test, want, u.String()) + assert.Equal(test, want, u.Name) +} + +func TestUndefineUnmarshalJSONObject(test *testing.T) { + want := "DEFINE" + + u := new(undefine.Undefine) + + assert.NoError(test, json.Unmarshal([]byte(` { "name": "`+want+`" } `), u)) + + assert.Equal(test, want, u.String()) + assert.Equal(test, want, u.Name) +} + +func TestUndefineUnmarshalJSONNull(test *testing.T) { + u := new(undefine.Undefine) + + assert.NoError(test, json.Unmarshal([]byte(` null `), u)) + + assert.Empty(test, u.String()) + assert.Empty(test, u.Name) +} + +func TestUndefineUnmarshalJSONError(test *testing.T) { + u := new(undefine.Undefine) + + assert.Error(test, json.Unmarshal([]byte(`{"name":5}`), u)) + + assert.Empty(test, u.String()) + assert.Empty(test, u.Name) +} + +func TestUndefineUnmarshalJSONInvalid(test *testing.T) { + u := new(undefine.Undefine) + + assert.Error(test, json.Unmarshal([]byte(`true`), u)) + + assert.Empty(test, u.String()) + assert.Empty(test, u.Name) +} diff --git a/undefine/undefines.go b/undefine/undefines.go new file mode 100644 index 0000000000000000000000000000000000000000..cca7c44270c736fd3a8280d60de05341f85a3d3d --- /dev/null +++ b/undefine/undefines.go @@ -0,0 +1,65 @@ +// Copyright 2020 Tymoteusz Blazejczyk +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package undefine + +import ( + "encoding/json" + + "gitlab.com/tymonx/go-error/rterror" +) + +// Undefines undefines a list of undefines. +type Undefines []Undefine + +// UnmarshalText decodes text to undefine. +func (u *Undefines) UnmarshalText(data []byte) error { + *u = Undefines{*New(string(data))} + + return nil +} + +// UnmarshalJSON decodes JSON to undefine. +func (u *Undefines) UnmarshalJSON(data []byte) error { + switch data[0] { + case '[': + case '{': + object := new(Undefine) + + if err := json.Unmarshal(data, object); err != nil { + return err + } + + *u = Undefines{*object} + + return nil + case '"': + return u.UnmarshalText(data[1 : len(data)-1]) + case 'n': + *u = Undefines{} + return nil + default: + return rterror.New("invalid JSON type") + } + + undefines := []Undefine{} + + if err := json.Unmarshal(data, &undefines); err != nil { + return rterror.New("error occurred while decoding JSON", err) + } + + *u = undefines + + return nil +} diff --git a/undefine/undefines_test.go b/undefine/undefines_test.go new file mode 100644 index 0000000000000000000000000000000000000000..df24e59654dd8dffcc9b0f4ecad6e5bf18a9a6c4 --- /dev/null +++ b/undefine/undefines_test.go @@ -0,0 +1,89 @@ +// Copyright 2020 Tymoteusz Blazejczyk +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package undefine_test + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" + "gitlab.com/tymonx/xlogic-toolchain/undefine" +) + +func TestUndefinesUnmarshalText(test *testing.T) { + want := "DEFF" + + var u undefine.Undefines + + assert.NoError(test, json.Unmarshal([]byte(` "`+want+`" `), &u)) + + assert.Len(test, u, 1) + assert.Equal(test, want, u[0].Name) + assert.Equal(test, want, u[0].String()) +} + +func TestUndefinesUnmarshalJSON(test *testing.T) { + var u undefine.Undefines + + assert.NoError(test, json.Unmarshal([]byte(` ["A", { "name": "B" }]`), &u)) + + assert.Len(test, u, 2) + + assert.Equal(test, "A", u[0].Name) + assert.Equal(test, "A", u[0].String()) + + assert.Equal(test, "B", u[1].Name) + assert.Equal(test, "B", u[1].String()) +} + +func TestUndefinesUnmarshalJSONObject(test *testing.T) { + want := "C" + + var u undefine.Undefines + + assert.NoError(test, json.Unmarshal([]byte(` { "name": "`+want+`" } `), &u)) + + assert.Len(test, u, 1) + assert.Equal(test, want, u[0].String()) + assert.Equal(test, want, u[0].Name) +} + +func TestUndefinesUnmarshalJSONNull(test *testing.T) { + var u undefine.Undefines + + assert.NoError(test, json.Unmarshal([]byte(` null `), &u)) + assert.Empty(test, u) +} + +func TestUndefinesUnmarshalJSONError(test *testing.T) { + var u undefine.Undefines + + assert.Error(test, json.Unmarshal([]byte(`[5]`), &u)) + assert.Empty(test, u) +} + +func TestUndefinesUnmarshalJSONObjectError(test *testing.T) { + var u undefine.Undefines + + assert.Error(test, json.Unmarshal([]byte(`{"name":5}`), &u)) + assert.Empty(test, u) +} + +func TestUndefinesUnmarshalJSONInvalid(test *testing.T) { + var u undefine.Undefines + + assert.Error(test, json.Unmarshal([]byte(`true`), &u)) + assert.Empty(test, u) +}