package
0.0.0-20250212194115-ee9b0668d242
Repository: https://github.com/digitalocean/go-qemu.git
Documentation: pkg.go.dev

# README

qapi-schema

Package qapi-schema is a fully compliant1 QAPI2 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 Go3. The lessons in that book's chapter on lexing were directly applied to create package internal/lex.
  • Jeremy Brown, whose GopherCon 2022 talk4 demonstrated simple and elegant ways to write parser combinators in Go, which directly inspired much of package internal/parse.

Footnotes

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

  2. https://qemu.readthedocs.io/en/latest/devel/qapi-code-gen.html#introduction

  3. https://interpreterbook.com/

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

# Packages

No description provided by the author

# Functions

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

# Structs

Alternate is a QAPI type that describes what types can be suitable alternates.
Alternative is one such alternative that could be contained in an Alternate.
Branch describes one of the active variants for the Union type.
Command is a QAPI type that describes a QMP command that can be sent to the QEMU process.
CommandData contains the Command's fields.
CommandDataEmbed refers to the fields to embed in the Command.
Cond expresses the conditions under which the upstream QEMU code generator will include a type or field.
Enum is a QAPI type whose value is only one of many defined variants.
EnumValue is one possible variant for a QAPI enum.
Event is a QAPI type that describes something that has happened.
EventData contains an Event's data.
EventDataSelector contains the name of the event's boxed type or its own fields that comprise the event.
EventDataUnboxed contains the event's own fields, rather than embedding another type's fields as its fields.
Feature specifies a QAPI document feature.
Member is a field type for a QAPI object.
Pragma is a QAPI node that parameterizes the upstream QEMU QAPI code generator.
Root is the root of the QAPI document.
Struct is a QAPI type that is a combined record of many other types.
Tree is a QAPI parse tree.
TypeRef refers to a QAPI type or an array of a QAPI type.
Union is a QAPI type that is like a sum-type enum.
UnionBase is the base object of the union.

# Interfaces

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

# Type aliases

CommandDataRef refers to another QAPI type that should be used as the argument for this Command.
CondAll will result in code generation if all of the specified config options are set.
CondAny will result in code generation if any of the specified config options are set.
CondIf will result in code generation if the specified config option is set.
CondNot will result in code generation if the specified config option is not set.
Include is a QAPI node that refers to another QAPI document that contains dependent types.
TypeRefArray is a stronger Go type for expressing a string that is meant to represent an array of a QAPI type.