Initial commit
This commit is contained in:
commit
7781cf26b5
21
Makefile
Normal file
21
Makefile
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
GO_MODULE_IMPORT := go.datafortress.dev/pkg/central-arch-spec-models
|
||||||
|
GO_MODELS_PKG := spec
|
||||||
|
|
||||||
|
SPEC_XML_NS := https://datafortress.dev/xml/central-arch-specification
|
||||||
|
SPEC_SCHEMA_DIR := ../central-arch-spec-schema
|
||||||
|
SPEC_SCHEMA_FILE := specification.xsd
|
||||||
|
|
||||||
|
.PHONY: all
|
||||||
|
all: tests
|
||||||
|
|
||||||
|
.PHONY: tests
|
||||||
|
tests:
|
||||||
|
go test $(shell find . -type f -name '*_test.go' -print)
|
||||||
|
|
||||||
|
.PHONY: deps
|
||||||
|
deps:
|
||||||
|
go install github.com/gocomply/xsd2go/cli/gocomply_xsd2go@latest
|
||||||
|
|
||||||
|
.PHONY: generate
|
||||||
|
generate:
|
||||||
|
gocomply_xsd2go convert --xmlns-override=${SPEC_XML_NS}=${GO_MODELS_PKG} ${SPEC_SCHEMA_DIR}/${SPEC_SCHEMA_FILE} ${GO_MODULE_IMPORT} .
|
||||||
9
README.md
Normal file
9
README.md
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# Central Arch: XML Specification Models
|
||||||
|
## Install GoComply Xsd2Go
|
||||||
|
```bash
|
||||||
|
make deps
|
||||||
|
```
|
||||||
|
## Regenerate data model from XSD
|
||||||
|
```bash
|
||||||
|
make models
|
||||||
|
```
|
||||||
11
go.mod
Normal file
11
go.mod
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
module go.datafortress.dev/pkg/central-arch-spec-models
|
||||||
|
|
||||||
|
go 1.23.2
|
||||||
|
|
||||||
|
require github.com/stretchr/testify v1.11.1
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
)
|
||||||
10
go.sum
Normal file
10
go.sum
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
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/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||||
|
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
116
query/indexer.go
Normal file
116
query/indexer.go
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
package query
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type IndexedElement struct {
|
||||||
|
Name string
|
||||||
|
DisplayName *string
|
||||||
|
ReferencedData any
|
||||||
|
Parent *IndexedContainer
|
||||||
|
Containers []*IndexedContainer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *IndexedElement) Init() {
|
||||||
|
for _, container := range e.Containers {
|
||||||
|
container.Parent = e
|
||||||
|
container.Init()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *IndexedElement) String() string {
|
||||||
|
if e.Parent == nil {
|
||||||
|
panic("IndexedElement has no parent!")
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s:%s", e.Parent.Parent, e.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *IndexedElement) PrintableName() string {
|
||||||
|
var result = e.Name
|
||||||
|
if e.DisplayName != nil {
|
||||||
|
result = *e.DisplayName
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *IndexedElement) Find(c *Container) QueryResult {
|
||||||
|
return findInContainers(c, e.Containers)
|
||||||
|
}
|
||||||
|
|
||||||
|
type IndexedContainer struct {
|
||||||
|
Name string
|
||||||
|
Parent *IndexedElement
|
||||||
|
Elements []*IndexedElement
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *IndexedContainer) Init() {
|
||||||
|
for _, element := range c.Elements {
|
||||||
|
element.Parent = c
|
||||||
|
element.Init()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *IndexedContainer) String() string {
|
||||||
|
var parentStr = ""
|
||||||
|
|
||||||
|
if c.Parent != nil {
|
||||||
|
parentStr = c.Parent.String()
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s%s", parentStr, c.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *IndexedContainer) PrintableName() string {
|
||||||
|
return c.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *IndexedContainer) Find(e *Element) QueryResult {
|
||||||
|
for _, element := range c.Elements {
|
||||||
|
if e.Name == element.Name {
|
||||||
|
if e.NextContainer != nil {
|
||||||
|
// If the element is found but the query expression continues
|
||||||
|
// with a container query, delegate the search to the element
|
||||||
|
return element.Find(e.NextContainer)
|
||||||
|
} else {
|
||||||
|
// If not, return the found element
|
||||||
|
return QueryResult{element}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Return an empty list if the element is not found
|
||||||
|
return make(QueryResult, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// A query tree is a bipartite graph composed of containers and elements.
|
||||||
|
// Only elements can be queried.
|
||||||
|
type IndexedRoot struct {
|
||||||
|
Containers []*IndexedContainer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *IndexedRoot) Find(q *Query) QueryResult {
|
||||||
|
return findInContainers(&q.Container, r.Containers)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *IndexedRoot) FindByRef(ref Reference) (QueryResult, error) {
|
||||||
|
var query, err = ref.Parse()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return r.Find(query), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func findInContainers(queried *Container, containers []*IndexedContainer) QueryResult {
|
||||||
|
for _, container := range containers {
|
||||||
|
if queried.Name == container.Name {
|
||||||
|
if queried.NextElement != nil {
|
||||||
|
// If the container is found but the query expression continues
|
||||||
|
// with an element query, delegate the search to the container
|
||||||
|
return container.Find(queried.NextElement)
|
||||||
|
} else {
|
||||||
|
// If not, return all the elements in the found container
|
||||||
|
return container.Elements
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Return an empty list if the container is not found
|
||||||
|
return make(QueryResult, 0)
|
||||||
|
}
|
||||||
229
query/ref.go
Normal file
229
query/ref.go
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
package query
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"unicode"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
A reference is composed of one or more matchers separated by periods.
|
||||||
|
A matcher can be composed by a single container name or by both a
|
||||||
|
container name and an element identifier.
|
||||||
|
A matcher only composed of a container name can only appear as the last
|
||||||
|
matcher of a reference.
|
||||||
|
|
||||||
|
A reference the last matcher of which is composed of both a container
|
||||||
|
name and an element identifier is a fully qualified reference.
|
||||||
|
|
||||||
|
A reference the last matcher of which is only composed of a container
|
||||||
|
returns all elements inside the container or an empty list.
|
||||||
|
A reference the last matcher of which is composed of both a container
|
||||||
|
name and an element identifier returns only the referenced element or
|
||||||
|
an empty list.
|
||||||
|
|
||||||
|
Example, given the following query tree:
|
||||||
|
|
||||||
|
(with "r:" meaning "root", "c:" container and "e:" element).
|
||||||
|
|
||||||
|
<r: />-+--<c: format>-+--<e: T1>
|
||||||
|
| |--<e: T2>
|
||||||
|
|
|
||||||
|
+--<c: instr>--+--<e: BKPT>-+--<c: binding>
|
||||||
|
|
||||||
|
Ref: "format"
|
||||||
|
Returns: [T1, T2]
|
||||||
|
|
||||||
|
Ref: "format:T1"
|
||||||
|
Returns: [T1]
|
||||||
|
|
||||||
|
Ref: "instr:BKPT"
|
||||||
|
Returns: [BKPT]
|
||||||
|
|
||||||
|
Ref: "instr:BKPT.binding"
|
||||||
|
Returns: []
|
||||||
|
|
||||||
|
Ref: "instr:BKPT.binding:base"
|
||||||
|
Returns: []
|
||||||
|
|
||||||
|
Ref: "instr.binding"
|
||||||
|
Returns: Error
|
||||||
|
=> Container-only matcher can only be used as the last matcher in a reference.
|
||||||
|
*/
|
||||||
|
type Reference string
|
||||||
|
|
||||||
|
func (ref *Reference) Parse() (*Query, error) {
|
||||||
|
var container, err = parseContainerComponent(*ref, 0)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &Query{Container: *container}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ref *Reference) IsValid() bool {
|
||||||
|
var _, err = ref.Parse()
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ref *Reference) IsFullyQualified() bool {
|
||||||
|
var query, err = ref.Parse()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return query.IsFullyQualified()
|
||||||
|
}
|
||||||
|
|
||||||
|
type RefParseError struct {
|
||||||
|
Ref Reference
|
||||||
|
Index int
|
||||||
|
Msg string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err *RefParseError) Error() string {
|
||||||
|
var error_fmt = `Parsing error at character %d in the following query reference:
|
||||||
|
"%s"
|
||||||
|
%s^
|
||||||
|
Error: %s`
|
||||||
|
|
||||||
|
return fmt.Sprintf(error_fmt, err.Index+1, err.Ref, strings.Repeat(" ", err.Index), err.Msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isValidNameChar(r rune) bool {
|
||||||
|
return unicode.IsLetter(r) || unicode.IsDigit(r) || r == '_' || r == '-'
|
||||||
|
}
|
||||||
|
|
||||||
|
func isMatcherSeparator(r rune) bool {
|
||||||
|
return r == '.'
|
||||||
|
}
|
||||||
|
|
||||||
|
func isElementIdSeparator(r rune) bool {
|
||||||
|
return r == ':'
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseContainerComponent(ref Reference, index int) (*Container, error) {
|
||||||
|
var currentName = ""
|
||||||
|
|
||||||
|
if index >= len(ref) {
|
||||||
|
return nil, &RefParseError{
|
||||||
|
Ref: ref,
|
||||||
|
Index: index,
|
||||||
|
Msg: "Expected a container name but reached end of reference",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, w := index, 0; i < len(ref); i += w {
|
||||||
|
var runeValue, width = utf8.DecodeRuneInString(string(ref[i:]))
|
||||||
|
w = width
|
||||||
|
|
||||||
|
if isElementIdSeparator(runeValue) {
|
||||||
|
if len(currentName) > 0 {
|
||||||
|
var e, err = parseElementComponent(ref, index)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &Container{Name: currentName, NextElement: e}, nil
|
||||||
|
} else {
|
||||||
|
return nil, &RefParseError{
|
||||||
|
Ref: ref,
|
||||||
|
Index: index,
|
||||||
|
Msg: "Expected a container name before an element identifier",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if isMatcherSeparator(runeValue) {
|
||||||
|
if len(currentName) > 0 {
|
||||||
|
return nil, &RefParseError{
|
||||||
|
Ref: ref,
|
||||||
|
Index: index,
|
||||||
|
Msg: "Expected an element identifier before another container name",
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return nil, &RefParseError{
|
||||||
|
Ref: ref,
|
||||||
|
Index: index,
|
||||||
|
Msg: "Expected both a container name and an element identifier before another container name",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if isValidNameChar(runeValue) {
|
||||||
|
currentName += string(runeValue)
|
||||||
|
} else {
|
||||||
|
return nil, &RefParseError{
|
||||||
|
Ref: ref,
|
||||||
|
Index: index,
|
||||||
|
Msg: fmt.Sprintf("Character '%c' is not permitted in a container name", runeValue),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Container{Name: currentName, NextElement: nil}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseElementComponent(ref Reference, index int) (*Element, error) {
|
||||||
|
var currentName = ""
|
||||||
|
|
||||||
|
if index >= len(ref) {
|
||||||
|
return nil, &RefParseError{
|
||||||
|
Ref: ref,
|
||||||
|
Index: index,
|
||||||
|
Msg: "Expected an element identifier but reached end of reference",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, w := index, 0; i < len(ref); i += w {
|
||||||
|
var runeValue, width = utf8.DecodeRuneInString(string(ref[i:]))
|
||||||
|
w = width
|
||||||
|
|
||||||
|
if isElementIdSeparator(runeValue) {
|
||||||
|
if len(currentName) > 0 {
|
||||||
|
return nil, &RefParseError{
|
||||||
|
Ref: ref,
|
||||||
|
Index: index,
|
||||||
|
Msg: "Expected a container name before another element identifier",
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return nil, &RefParseError{
|
||||||
|
Ref: ref,
|
||||||
|
Index: index,
|
||||||
|
Msg: "Expected both a container name and an element identifier before another element identifier",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if isMatcherSeparator(runeValue) {
|
||||||
|
if len(currentName) > 0 {
|
||||||
|
var e, err = parseContainerComponent(ref, index)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &Element{Name: currentName, NextContainer: e}, nil
|
||||||
|
} else {
|
||||||
|
return nil, &RefParseError{
|
||||||
|
Ref: ref,
|
||||||
|
Index: index,
|
||||||
|
Msg: "Expected an element identifier before a container name",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if isValidNameChar(runeValue) {
|
||||||
|
currentName += string(runeValue)
|
||||||
|
} else {
|
||||||
|
return nil, &RefParseError{
|
||||||
|
Ref: ref,
|
||||||
|
Index: index,
|
||||||
|
Msg: fmt.Sprintf("Character '%c' is not permitted in an element identifier", runeValue),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Element{Name: currentName, NextContainer: nil}, nil
|
||||||
|
}
|
||||||
31
query/ref_test.go
Normal file
31
query/ref_test.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package query_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"go.datafortress.dev/pkg/central-arch-spec-models/query"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
MULTIPLE_LEVELS_QUERY_REF = "instruction:LDR_Base_Offset.binding:base"
|
||||||
|
FULLY_QUALIFIED_QUERY_REF = "c1:e1.c2:e2"
|
||||||
|
NOT_FULLY_QUALIFIED_QUERY_REF = "c1:e1.c2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRefParsing(t *testing.T) {
|
||||||
|
var ref query.Reference = MULTIPLE_LEVELS_QUERY_REF
|
||||||
|
var query, err = ref.Parse()
|
||||||
|
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
var instrContainer = query.Container
|
||||||
|
require.Equal(t, "instruction", instrContainer.Name)
|
||||||
|
require.NotNil(t, instrContainer.NextElement)
|
||||||
|
|
||||||
|
var instrElement = instrContainer.NextElement
|
||||||
|
require.Equal(t, "LDR_Base_Offset", instrElement.Name)
|
||||||
|
require.NotNil(t, instrElement.NextContainer)
|
||||||
|
|
||||||
|
// TODO Continue testing
|
||||||
|
}
|
||||||
61
query/tree.go
Normal file
61
query/tree.go
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
package query
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type QueryResult []*IndexedElement
|
||||||
|
|
||||||
|
type Element struct {
|
||||||
|
Name string
|
||||||
|
NextContainer *Container
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Element) String() string {
|
||||||
|
var containerStr = ""
|
||||||
|
|
||||||
|
if e.NextContainer != nil {
|
||||||
|
containerStr = fmt.Sprintf(".%s", e.NextContainer)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s%s", e.Name, containerStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Container struct {
|
||||||
|
Name string
|
||||||
|
NextElement *Element
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Container) String() string {
|
||||||
|
var elementStr = ""
|
||||||
|
|
||||||
|
if c.NextElement != nil {
|
||||||
|
elementStr = fmt.Sprintf(":%s", c.NextElement)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s%s", c.Name, elementStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Query struct {
|
||||||
|
Container Container
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Query) String() string {
|
||||||
|
return q.Container.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Query) IsFullyQualified() bool {
|
||||||
|
var container *Container = &q.Container
|
||||||
|
|
||||||
|
for container != nil {
|
||||||
|
if container.NextElement == nil {
|
||||||
|
// Current container has no next element, so the query ended on a container.
|
||||||
|
// Thus, it is not fully qualified.
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
container = container.NextElement.NextContainer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next container is nil, so the query ended on an element.
|
||||||
|
// Thus, it is fully qualified.
|
||||||
|
return true
|
||||||
|
}
|
||||||
307
spec/models.go
Normal file
307
spec/models.go
Normal file
@ -0,0 +1,307 @@
|
|||||||
|
// Code generated by https://github.com/gocomply/xsd2go; DO NOT EDIT.
|
||||||
|
// Models for https://datafortress.dev/xml/central-arch-specification
|
||||||
|
package spec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/xml"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Element
|
||||||
|
type Specification struct {
|
||||||
|
XMLName xml.Name `xml:"specification"`
|
||||||
|
|
||||||
|
Exceptions ExceptionList `xml:"exceptions"`
|
||||||
|
|
||||||
|
Formats FormatList `xml:"formats"`
|
||||||
|
|
||||||
|
Instructions InstructionList `xml:"instructions"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// XSD ComplexType declarations
|
||||||
|
|
||||||
|
// SpecificationType: Central Architecture CPU XML Specification file.
|
||||||
|
type SpecificationType struct {
|
||||||
|
XMLName xml.Name
|
||||||
|
|
||||||
|
Exceptions ExceptionList `xml:"exceptions"`
|
||||||
|
|
||||||
|
Formats FormatList `xml:"formats"`
|
||||||
|
|
||||||
|
Instructions InstructionList `xml:"instructions"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormatList: Supported instruction encoding formats.
|
||||||
|
type FormatList struct {
|
||||||
|
XMLName xml.Name
|
||||||
|
|
||||||
|
Format []Format `xml:",any"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstructionList: Supported instructions.
|
||||||
|
type InstructionList struct {
|
||||||
|
XMLName xml.Name
|
||||||
|
|
||||||
|
Instruction []Instruction `xml:",any"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExceptionList: Supported exceptions.
|
||||||
|
type ExceptionList struct {
|
||||||
|
XMLName xml.Name
|
||||||
|
|
||||||
|
Exception []Exception `xml:",any"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DocText: Documentation text.
|
||||||
|
type DocText struct {
|
||||||
|
XMLName xml.Name
|
||||||
|
|
||||||
|
Ref []RefText `xml:"ref"`
|
||||||
|
|
||||||
|
Todo []TodoText `xml:"todo"`
|
||||||
|
|
||||||
|
InnerXml string `xml:",innerxml"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RefText: A reference to an element.
|
||||||
|
type RefText struct {
|
||||||
|
XMLName xml.Name
|
||||||
|
|
||||||
|
// Type: Reference type. Used to set a specific styling to the reference text. Can also generate a link to a reference in the documentation.
|
||||||
|
Type string `xml:"type,attr"`
|
||||||
|
|
||||||
|
Text string `xml:",chardata"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// TodoText: A TODO annotation.
|
||||||
|
type TodoText struct {
|
||||||
|
XMLName xml.Name
|
||||||
|
|
||||||
|
Text string `xml:",chardata"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exception: The specification of an exception.
|
||||||
|
type Exception struct {
|
||||||
|
XMLName xml.Name
|
||||||
|
|
||||||
|
// Id: The unique identifier of this exception.
|
||||||
|
Id string `xml:"id,attr"`
|
||||||
|
|
||||||
|
// DisplayName: The name of the exception that will be displayed in the documentation.
|
||||||
|
DisplayName string `xml:"display-name"`
|
||||||
|
|
||||||
|
// Brief: A brief description of this exception.
|
||||||
|
Brief DocText `xml:"brief"`
|
||||||
|
|
||||||
|
// Details: Details about this exception. Used to give info about where the exception handler PSW is stored and what are the info given to it by the system.
|
||||||
|
Details DocText `xml:"details"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format: The specification of an instruction encoding format.
|
||||||
|
type Format struct {
|
||||||
|
XMLName xml.Name
|
||||||
|
|
||||||
|
// Id: The unique identifier of an instruction encoding format.
|
||||||
|
Id string `xml:"id,attr"`
|
||||||
|
|
||||||
|
// DisplayName: The name of the instruction encoding format as it will be displayed in the documentation.
|
||||||
|
DisplayName string `xml:"display-name"`
|
||||||
|
|
||||||
|
Description DocText `xml:"description"`
|
||||||
|
|
||||||
|
Fields FormatFieldList `xml:"fields"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormatFieldList: The fields used in this instruction encoding format.
|
||||||
|
type FormatFieldList struct {
|
||||||
|
XMLName xml.Name
|
||||||
|
|
||||||
|
Field []FormatField `xml:",any"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormatField: Description of a field in this instruction encoding format.
|
||||||
|
type FormatField struct {
|
||||||
|
XMLName xml.Name
|
||||||
|
|
||||||
|
// Bits: Field length, in bits.
|
||||||
|
Bits int64 `xml:"bits,attr"`
|
||||||
|
|
||||||
|
Type FormatFieldType `xml:"type,attr"`
|
||||||
|
|
||||||
|
// Name: Field name. Ignored for opcode and condition fields.
|
||||||
|
Name string `xml:"name,attr,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Instruction: The specification of an instruction.
|
||||||
|
type Instruction struct {
|
||||||
|
XMLName xml.Name
|
||||||
|
|
||||||
|
// Id: The unique identifier of this instruction.
|
||||||
|
Id string `xml:"id,attr"`
|
||||||
|
|
||||||
|
// Opcode: The opcode of this instruction.
|
||||||
|
Opcode uint8 `xml:"opcode,attr"`
|
||||||
|
|
||||||
|
// Format: The encoding format of the instruction.
|
||||||
|
Format string `xml:"format,attr"`
|
||||||
|
|
||||||
|
// DisplayName: The name of the instruction as it will be displayed in the documentation.
|
||||||
|
DisplayName string `xml:"display-name"`
|
||||||
|
|
||||||
|
// Description: The description of this instruction.
|
||||||
|
Description DocText `xml:"description"`
|
||||||
|
|
||||||
|
Syntax Syntax `xml:"syntax"`
|
||||||
|
|
||||||
|
Examples ExampleList `xml:"examples"`
|
||||||
|
|
||||||
|
Bindings BindingList `xml:"bindings"`
|
||||||
|
|
||||||
|
Operation Operation `xml:"operation"`
|
||||||
|
|
||||||
|
Exceptions InstructionExceptionList `xml:"exceptions"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Syntax: The assembler syntax of the instruction.
|
||||||
|
type Syntax struct {
|
||||||
|
XMLName xml.Name
|
||||||
|
|
||||||
|
Mnemonic Mnemonic `xml:",any"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MnemonicArgRegister: A register passed as an argument of the instruction.
|
||||||
|
type MnemonicArgRegister struct {
|
||||||
|
XMLName xml.Name
|
||||||
|
|
||||||
|
Binding BindingName `xml:"binding,attr"`
|
||||||
|
|
||||||
|
Ref []RefText `xml:"ref"`
|
||||||
|
|
||||||
|
Todo []TodoText `xml:"todo"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MnemonicArgImmediate: An immediate value passed as an argument of the instruction.
|
||||||
|
type MnemonicArgImmediate struct {
|
||||||
|
XMLName xml.Name
|
||||||
|
|
||||||
|
Ref BindingName `xml:"ref,attr"`
|
||||||
|
|
||||||
|
RefElm []RefText `xml:"ref"`
|
||||||
|
|
||||||
|
Todo []TodoText `xml:"todo"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MnemonicArgGroup: A group of both registers and immediate values passed as arguments of the instruction.
|
||||||
|
type MnemonicArgGroup struct {
|
||||||
|
XMLName xml.Name
|
||||||
|
|
||||||
|
Register []MnemonicArgRegister `xml:"register"`
|
||||||
|
|
||||||
|
Immediate []MnemonicArgImmediate `xml:"immediate"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExampleList: Instruction syntax examples.
|
||||||
|
type ExampleList struct {
|
||||||
|
XMLName xml.Name
|
||||||
|
|
||||||
|
Example []Example `xml:",any"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Example: An example of the instruction syntax.
|
||||||
|
type Example struct {
|
||||||
|
XMLName xml.Name
|
||||||
|
|
||||||
|
Code Code `xml:"code"`
|
||||||
|
|
||||||
|
Comment CodeComment `xml:"comment"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CodeComment: Comment about the assembly code of the example.
|
||||||
|
type CodeComment struct {
|
||||||
|
XMLName xml.Name
|
||||||
|
|
||||||
|
Ref []RefText `xml:"ref"`
|
||||||
|
|
||||||
|
Todo []TodoText `xml:"todo"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// BindingList: Value bindings to instruction fields.
|
||||||
|
type BindingList struct {
|
||||||
|
XMLName xml.Name
|
||||||
|
|
||||||
|
Binding []Binding `xml:",any"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Binding: A value binding to an instruction field.
|
||||||
|
type Binding struct {
|
||||||
|
XMLName xml.Name
|
||||||
|
|
||||||
|
Name BindingName `xml:"name,attr"`
|
||||||
|
|
||||||
|
// Field: Reference to the instruction field to bind the value to.
|
||||||
|
Field string `xml:"field,attr"`
|
||||||
|
|
||||||
|
// Aligned: Optional immediate value alignement, must be a power of 2. Dictates how the value is encoded: an alignment of 2 means that the value is bitshifted right by one bit, an alignment of 4 means that it is bitshifted right by two bits, etc... Defaults to 1, i.e. no bitshifting is involved.
|
||||||
|
Aligned uint64 `xml:"aligned,attr"`
|
||||||
|
|
||||||
|
// MinusOne: Specifies whether the value is "-1 encoded". As an example, if an 8-bits value is -1 encoded then it means that one can use values in the range 1..256 and it will be encoded in the range 0..255. Defaults to false.
|
||||||
|
MinusOne bool `xml:"minus-one,attr"`
|
||||||
|
|
||||||
|
// Signed: Indicate whether the immediate value is signed. Defaults to false.
|
||||||
|
Signed bool `xml:"signed,attr"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstructionExceptionList: The exceptions that can be generated during execution of this instruction.
|
||||||
|
type InstructionExceptionList struct {
|
||||||
|
XMLName xml.Name
|
||||||
|
|
||||||
|
Exception []InstructionException `xml:",any"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstructionException: An exception that can be generated during the execution of this instruction.
|
||||||
|
type InstructionException struct {
|
||||||
|
XMLName xml.Name
|
||||||
|
|
||||||
|
// Ref: The unique identifier of the exception.
|
||||||
|
Ref string `xml:"ref,attr"`
|
||||||
|
|
||||||
|
RefElm []RefText `xml:"ref"`
|
||||||
|
|
||||||
|
Todo []TodoText `xml:"todo"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// XSD SimpleType declarations
|
||||||
|
|
||||||
|
// FormatFieldType: Field type.
|
||||||
|
type FormatFieldType string
|
||||||
|
|
||||||
|
const FormatFieldTypeOpcode FormatFieldType = "opcode"
|
||||||
|
|
||||||
|
const FormatFieldTypeRegister FormatFieldType = "register"
|
||||||
|
|
||||||
|
const FormatFieldTypeRegisterSrc FormatFieldType = "register.src"
|
||||||
|
|
||||||
|
const FormatFieldTypeRegisterDest FormatFieldType = "register.dest"
|
||||||
|
|
||||||
|
const FormatFieldTypeRegisterOffset FormatFieldType = "register.offset"
|
||||||
|
|
||||||
|
const FormatFieldTypeImmediate FormatFieldType = "immediate"
|
||||||
|
|
||||||
|
const FormatFieldTypeImmediateOffset FormatFieldType = "immediate.offset"
|
||||||
|
|
||||||
|
const FormatFieldTypeCondition FormatFieldType = "condition"
|
||||||
|
|
||||||
|
const FormatFieldTypeFlag FormatFieldType = "flag"
|
||||||
|
|
||||||
|
const FormatFieldTypeUnused FormatFieldType = "unused"
|
||||||
|
|
||||||
|
// Mnemonic: Instruction mnemonic.
|
||||||
|
type Mnemonic string
|
||||||
|
|
||||||
|
// Code: Single-line assembly code of the example.
|
||||||
|
type Code string
|
||||||
|
|
||||||
|
// BindingName: The name of the value binding.
|
||||||
|
type BindingName string
|
||||||
|
|
||||||
|
// Operation: Instruction microcoded operation.
|
||||||
|
type Operation string
|
||||||
5
spec/visitor.go
Normal file
5
spec/visitor.go
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package spec
|
||||||
|
|
||||||
|
type SpecVisitor interface {
|
||||||
|
VisitSpecification(node *Specification)
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user