qapischema

package
v1.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 9, 2023 License: Apache-2.0 Imports: 5 Imported by: 0

README

qapi-schema

Package qapi-schema is a fully compliant[^1] QAPI^2 schema language parser. The QAPI schema language looks approximately like JSON, but it differs slightly in many ways, which can confuse a regular JSON parser.

Usage

If you want to parse QAPI schema from your Go code, all you have to do is called qapischema.Parse:

input := `{ 'struct': 'DiskThing',
            'data': {
                'diskname': {
                    'type':'str',
                    'if':'DISKS_HAVE_NAMES' } } }`
schema, _ := qapischema.Parse(input)

The above code snippet would produce a *qapischema.Tree that looks like this:

&qapischema.Tree{
  Node: qapischema.Root{  },
  Children: []*qapischema.Tree{
    {
      Node: &qapischema.Struct{
        Name: "DiskThing",
        Members: []qapischema.Member{
          {
            Name: "diskname",
            Type: qapischema.TypeRef{
              Type: "str",
            },
            If: &qapischema.Cond{
              If: &qapischema.CondIf("DISKS_HAVE_NAMES"),
            },
          },
        },
      },
    },
  },
}

Once the QAPI has been parsed, you can walk the *qapischema.Tree and do whatever it is that you need to do.

The Node field in *qapischema.Tree is an interface type, and so a type assertion is required to identify and access the QAPI-type-specific data in the node you're visiting within the tree.

func visit(tree *qapischema.Tree) {
	switch data := tree.Node.(type) {
	// Root node, no data, traverse the subtrees in the .Children field.
	case qapischema.Root:
	case qapischema.Include:
	case qapischema.Pragma:
	case *qapischema.Struct:
	case *qapischema.Union:
	case *qapischema.Event:
	case *qapischema.Command:
	case *qapischema.Alternate:
	}

	// Process the rest of the document
	for _, t := range tree.Children {
		visit(t)
	}
}

func main() {
	tree, _ := qapischema.Parse(input)

	visit(tree)
}

Reporting defects

There is a lot of room for improvement with how this parser emits diagnostic information. That is, it doesn't emit any at all. The parser will simply stop parsing when it's not able to parse something. It won't complain, it will just stop.

So, when it comes to identifying which part of the document the parser did not understand, just compare the input schema to the output until you find the first element in the input schema that is missing from the parse tree.

There are two utilities included in this module: qapilex and qapiparse.

qapiparse parses QAPI from its stdin and prints a pretty string representation of the parse tree to stdout. This can be very helpful for figuring out where the parser stopped.

In your bug report, please include the QAPI input that surfaced the failure to parse. If possible, try to reduce the QAPI input down to a minimal viable reproducer.

Acknowledgements

Many thanks to:

  • Thorsten Ball, the author of Writing an Interpreter in Go^3. The lessons in that book's chapter on lexing were directly applied to create package internal/lex.
  • Jeremy Brown, whose GopherCon 2022 talk[^4] demonstrated simple and elegant ways to write parser combinators in Go, which directly inspired much of package internal/parse.

[^1]: At least, it's intended to be fully compliant. If it is not, please file a bug.

[^4]: GopherCon 2022: Jeremy Brown - Parsing w/o Code Generators: Parser Combinators in Go with Generics

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Alternate

type Alternate struct {
	Name     string
	Data     []Alternative
	If       *Cond
	Features []Feature
}

Alternate is a QAPI type that describes what types can be suitable alternates.

func (*Alternate) QAPINode

func (a *Alternate) QAPINode()

QAPINode marks Alternate as a QAPI node.

type Alternative

type Alternative struct {
	Name string
	Type TypeRef
	If   *Cond
}

Alternative is one such alternative that could be contained in an Alternate.

type Branch

type Branch struct {
	Name string
	Type TypeRef
	If   *Cond
}

Branch describes one of the active variants for the Union type.

type Command

type Command struct {
	Name            string
	Data            CommandData
	Returns         *TypeRef
	SuccessResponse *bool
	Gen             *bool
	AllowOOB        *bool
	AllowPreconfig  *bool
	Coroutine       *bool
	Boxed           *bool
	If              *Cond
	Features        []Feature
}

Command is a QAPI type that describes a QMP command that can be sent to the QEMU process.

func (*Command) QAPINode

func (c *Command) QAPINode()

QAPINode marks Command as a QAPI node.

type CommandData

type CommandData struct {
	Embed *CommandDataEmbed
	Ref   *CommandDataRef
}

CommandData contains the Command's fields.

type CommandDataEmbed

type CommandDataEmbed struct {
	Members []Member
}

CommandDataEmbed refers to the fields to embed in the Command.

type CommandDataRef

type CommandDataRef string

CommandDataRef refers to another QAPI type that should be used as the argument for this Command.

type Cond

type Cond struct {
	If  *CondIf
	All *CondAll
	Any *CondAny
	Not *CondNot
}

Cond expresses the conditions under which the upstream QEMU code generator will include a type or field.

type CondAll

type CondAll []string

CondAll will result in code generation if all of the specified config options are set.

type CondAny

type CondAny []string

CondAny will result in code generation if any of the specified config options are set.

type CondIf

type CondIf string

CondIf will result in code generation if the specified config option is set.

type CondNot

type CondNot string

CondNot will result in code generation if the specified config option is not set.

type Enum

type Enum struct {
	Name     string
	Values   []EnumValue
	Prefix   string
	If       *Cond
	Features []Feature
}

Enum is a QAPI type whose value is only one of many defined variants.

func (*Enum) QAPINode

func (e *Enum) QAPINode()

QAPINode marks Enum as a QAPI node.

type EnumValue

type EnumValue struct {
	Value    string
	Cond     *Cond
	Features []Feature
}

EnumValue is one possible variant for a QAPI enum.

type Event

type Event struct {
	Name     string
	Data     EventData
	If       *Cond
	Features []Feature
}

Event is a QAPI type that describes something that has happened.

func (*Event) QAPINode

func (e *Event) QAPINode()

QAPINode marks Event as a QAPI node.

type EventData

type EventData struct {
	Boxed    bool
	Selector EventDataSelector
}

EventData contains an Event's data.

type EventDataSelector

type EventDataSelector struct {
	Ref   string
	Embed *EventDataUnboxed
}

EventDataSelector contains the name of the event's boxed type or its own fields that comprise the event.

type EventDataUnboxed

type EventDataUnboxed struct {
	Type    string
	Members []Member
}

EventDataUnboxed contains the event's own fields, rather than embedding another type's fields as its fields.

type Feature

type Feature struct {
	Name string
	Cond Cond
}

Feature specifies a QAPI document feature.

type Include

type Include string

Include is a QAPI node that refers to another QAPI document that contains dependent types.

func (Include) QAPINode

func (i Include) QAPINode()

QAPINode marks Include as a QAPI node.

type Member

type Member struct {
	Name     string
	Type     TypeRef
	If       *Cond
	Features []Feature
	Optional bool
}

Member is a field type for a QAPI object.

type Node

type Node interface {
	QAPINode()
}

Node is a marker interface that indentifies the implementing concrete type as a QAPI type.

type Pragma

type Pragma struct {
	DocRequired             bool
	CommandNameExceptions   []string
	CommandReturnExceptions []string
	MemberNameExceptions    []string
}

Pragma is a QAPI node that parameterizes the upstream QEMU QAPI code generator.

func (Pragma) QAPINode

func (p Pragma) QAPINode()

QAPINode marks Pragma as a QAPI node.

type Root

type Root struct{}

Root is the root of the QAPI document. On its own, it is unremarkable. Client code will want to visit its subtrees.

func (Root) QAPINode

func (r Root) QAPINode()

QAPINode marks Root as a QAPI node.

type Struct

type Struct struct {
	Name     string
	Members  []Member
	Base     string
	If       *Cond
	Features []Feature
}

Struct is a QAPI type that is a combined record of many other types.

func (*Struct) QAPINode

func (s *Struct) QAPINode()

QAPINode marks Struct as a QAPI node.

type Tree

type Tree struct {
	Node     Node
	Children []*Tree
}

Tree is a QAPI parse tree.

func Parse

func Parse(input string) (*Tree, error)

Parse parses a QAPI input document and returns its parse tree.

type TypeRef

type TypeRef struct {
	Type      string
	TypeArray TypeRefArray
}

TypeRef refers to a QAPI type or an array of a QAPI type. If it is an array type, then TypeArray will be set and Type will be the empty string and vice versa.

type TypeRefArray

type TypeRefArray string

TypeRefArray is a stronger Go type for expressing a string that is meant to represent an array of a QAPI type.

type Union

type Union struct {
	Name          string
	Base          UnionBase
	Discriminator string
	Branches      []Branch
	If            *Cond
	Features      []Feature
}

Union is a QAPI type that is like a sum-type enum.

func (*Union) QAPINode

func (u *Union) QAPINode()

QAPINode marks Union as a QAPI node.

type UnionBase

type UnionBase struct {
	Name    string
	Members []Member
}

UnionBase is the base object of the union.

Directories

Path Synopsis
cmd
internal
lex

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL