pcore

package module
v0.0.0-...-c8e1b1c Latest Latest
Warning

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

Go to latest
Published: Jul 10, 2026 License: BSD-3-Clause Imports: 9 Imported by: 0

README

go-pcore

go-pcore

Puppet's Pcore type system in pure Go — the type calculus, parser, value model and assignability lattice, no cgo.

Go Reference Docs


go-pcore/pcore is a pure-Go (no cgo) reimplementation of Pcore, the data-type and value model that underpins Puppet, Hiera and Facter values. It gives a Go program the Puppet type calculus: a type model, a type parser, a value model, and the load-bearing operations — instance-of, assignability (subtyping), inference and rich-data serialization — with names and semantics that track Puppet's Puppet::Pops::Types so it is a drop-in for Puppet type expressions.

t, _ := pcore.Parse("Variant[Integer[0,10], Enum['a','b']]")

pcore.IsInstance(t, int64(7))          // true
pcore.IsInstance(t, "a")               // true
pcore.IsInstance(t, int64(99))         // false

data, _ := pcore.Parse("Data")
arr, _ := pcore.Parse("Array[Integer]")
pcore.IsAssignable(data, arr)                    // true — Array[Integer] <: Data
pcore.Infer([]pcore.Value{int64(1), int64(2)})   // Array[Integer[1, 2], 2, 2]
t.String()                                       // round-trips through Parse

What it provides

Area API
Parse a type expression Parse(string) (Type, error)
Instance check (value ∈ type) IsInstance(t Type, v Value) bool
Assignability (subtype lattice) IsAssignable(a, b Type) bool
Infer a value's most specific type Infer(v Value) Type
Generalize / CommonType Generalize(Type) Type, CommonType(a, b Type) Type
Rich-data serialization ToData(Value) (Value, error), FromData(Value) (Value, error)
Canonical string form Type.String() — round-trips through Parse

The type calculus

The full Pcore type set is implemented:

  • Scalar: Integer[min,max], Float[min,max], Numeric, String[min,max], Boolean, Undef, Default, Scalar, ScalarData, Data, RichData, RichDataKey, Any.
  • Collection: Array[T,min,max], Hash[K,V,min,max], Tuple[...], Struct[{k=>V}], Collection[min,max].
  • Abstract: Variant[...], Optional[T], NotUndef[T], Enum[...], Pattern[/re/], Regexp, Type[T], Sensitive[T], Init[T, args...], Iterable[T], Iterator[T], Callable[params..., block].
  • Rich data: Timestamp[from,to], Timespan[from,to], Binary, SemVer[ranges...], SemVerRange, Runtime['go', name], URI[scheme], Error[kind, issue_code].
  • Nominal / named: Object[{name=>..., parent=>..., attributes=>{...}}], type aliases (type X = <expr>, including recursive), and TypeSet[{name=>..., version=>..., types=>{...}, references=>{...}}].

Type aliases (recursive) and TypeSet

Aliases live in a Loader type environment that resolves forward and recursive references transparently through Parse/IsInstance/IsAssignable/Infer:

l := pcore.NewLoader()
l.Declare("type Tree = Hash[String, Variant[Tree, Integer]]")
tree, _ := l.Parse("Tree")

pcore.IsInstance(tree, map[string]pcore.Value{
    "a": int64(1),
    "b": map[string]pcore.Value{"c": int64(2)},
}) // true

ts, _ := l.Parse(`TypeSet[{
    name => 'MyMod::Types', version => '1.0.0',
    types => { Age => Integer[0,130], Person => Struct[{'age' => Age}] },
}]`)

Value model

Scalars are plain Go values (bool, int64, float64, string); arrays are []pcore.Value; hashes are *pcore.Hash (or a map[string]Value); and the rest are wrapper types — Undef, Default, Sensitive (redacts on String() and on serialization), Regexp, Binary, Timestamp, Timespan.

Consumers

go-pcore is the foundational type layer for go-puppet (the Puppet DSL evaluator) and for go-ruby-puppet, which marshals rbgo.Value ↔ pcore.Value across the rich-data protocol.

Principles

  • Pure Go, zero cgo. Cross-compiles and embeds anywhere; a static binary by default. CI is green across the six 64-bit Go targets (amd64, arm64, riscv64, loong64, ppc64le, s390x).
  • Faithful to Pcore. Type names, the grammar, the assignability rules and the rich-data protocol track Puppet's specification.
  • Round-trippable. Every Type.String() parses back through Parse.
  • 100% test coverage, enforced as a CI gate, including every parse-error, assignability arm and serialization path.

Status

v0.2 — full Pcore type calculus. The complete Puppet Puppet::Pops::Types set is implemented: type model, parser, value model, IsInstance/ IsAssignable/Infer/Generalize/CommonType, rich-data serialization, recursive type aliases and TypeSet via a Loader type environment, Timestamp/Timespan ranges, SemVer/SemVerRange, Init, Object, RichData, Runtime, URI, Iterable/Iterator, Error and Callable. 100% test coverage (enforced), gofmt + go vet clean, CI green across all six 64-bit Go arches. See BENCHMARKS.md for the perf harness and the differential-vs-MRI-Puppet methodology.

BSD-3-Clause.

Documentation

Overview

Package pcore is a pure-Go (cgo-free) reimplementation of Puppet's Pcore type system — the data-type and value model that underpins Puppet, Hiera and Facter values.

It provides four things a Puppet-family tool needs:

Every Type's String method round-trips through Type: for any t, Type(t.String()) equals t.

The names and semantics deliberately track Puppet's Puppet::Pops::Types so the package is a drop-in for Puppet type expressions.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func IsAssignable

func IsAssignable(a, b Type) bool

IsAssignable reports whether b is a subtype of a, i.e. every instance of b is an instance of a. It is the core lattice operation.

func IsInstance

func IsInstance(t Type, v Value) bool

IsInstance reports whether v is an instance of t.

Types

type Binary

type Binary struct {
	// contains filtered or unexported fields
}

Binary is a Pcore binary value (a byte string).

func NewBinary

func NewBinary(b []byte) *Binary

NewBinary wraps b as a Binary value.

func (*Binary) Bytes

func (b *Binary) Bytes() []byte

Bytes returns the underlying bytes.

func (*Binary) String

func (b *Binary) String() string

String renders the byte length (content is not dumped).

type Callable

type Callable struct {
	// contains filtered or unexported fields
}

Callable is a Pcore callable value carrying its signature type.

func NewCallable

func NewCallable(t Type) (*Callable, error)

NewCallable builds a callable value whose signature is the Callable type t.

func (*Callable) String

func (c *Callable) String() string

String renders the callable value by its signature.

type ErrorValue

type ErrorValue struct {
	// contains filtered or unexported fields
}

ErrorValue is a Pcore Error value.

func NewError

func NewError(message, kind, issueCode string) *ErrorValue

NewError builds an Error value.

func (*ErrorValue) IssueCode

func (e *ErrorValue) IssueCode() string

IssueCode returns the error issue code.

func (*ErrorValue) Kind

func (e *ErrorValue) Kind() string

Kind returns the error kind.

func (*ErrorValue) Message

func (e *ErrorValue) Message() string

Message returns the error message.

func (*ErrorValue) String

func (e *ErrorValue) String() string

String renders the error.

type Hash

type Hash struct {
	// contains filtered or unexported fields
}

Hash is a Pcore hash: an ordered collection of key/value pairs whose keys may be any value (not just strings).

func NewHash

func NewHash(entries ...HashEntry) *Hash

NewHash builds a Hash from ordered entries.

func (*Hash) Entries

func (h *Hash) Entries() []HashEntry

Entries returns the ordered entries.

func (*Hash) Get

func (h *Hash) Get(k Value) (Value, bool)

Get returns the value stored under a key equal to k, and whether it was present.

func (*Hash) Len

func (h *Hash) Len() int

Len returns the number of entries.

func (*Hash) String

func (h *Hash) String() string

String renders the hash Puppet-style.

type HashEntry

type HashEntry struct{ Key, Value Value }

HashEntry is one key/value pair of a Hash.

type Iterator

type Iterator struct {
	// contains filtered or unexported fields
}

Iterator is a Pcore iterator value over a fixed element sequence.

func NewIterator

func NewIterator(elem Type, items ...Value) *Iterator

NewIterator builds an iterator over items with declared element type elem.

func (*Iterator) Items

func (it *Iterator) Items() []Value

Items returns the iterator's elements.

func (*Iterator) String

func (it *Iterator) String() string

String renders the iterator.

type Loader

type Loader struct {
	// contains filtered or unexported fields
}

Loader is a type environment: a registry of named type aliases (and TypeSet members) that resolves alias references, including forward and recursive references. It mirrors the role of Puppet's Loader / TypeSet scope for the type calculus.

func NewLoader

func NewLoader() *Loader

NewLoader returns an empty type environment.

func (*Loader) Declare

func (l *Loader) Declare(decl string) error

Declare registers a type alias from a declaration of the form "type Name = <type-expr>". Forward and recursive references are permitted; use Loader.Parse or Loader.Validate afterwards to confirm every reference resolves.

func (*Loader) Parse

func (l *Loader) Parse(expr string) (Type, error)

Parse parses a type expression in this loader's scope, resolving alias names, then validates that every referenced alias has been declared.

func (*Loader) Validate

func (l *Loader) Validate() error

Validate reports the first alias that is referenced but never declared, or one whose definition is a non-productive cycle (it resolves only through other aliases back to itself).

type ObjectValue

type ObjectValue struct {
	// contains filtered or unexported fields
}

ObjectValue is an instance of an Object type: a typed record of attributes.

func NewObjectValue

func NewObjectValue(t Type, attrs *Hash) (*ObjectValue, error)

NewObjectValue builds an instance of the Object type t from the given attribute hash. It validates that every non-defaulted attribute is present and type-correct, filling in declared defaults for absent optional attributes.

func (*ObjectValue) Get

func (o *ObjectValue) Get(name string) (Value, bool)

Get returns the value of attribute name.

func (*ObjectValue) String

func (o *ObjectValue) String() string

String renders the object as Name({...}).

type ParseError

type ParseError struct {
	Msg string
	Pos int
}

ParseError describes a failure to parse a Pcore type expression.

func (*ParseError) Error

func (e *ParseError) Error() string

type Regexp

type Regexp struct {
	// contains filtered or unexported fields
}

Regexp is a Pcore regexp value.

func NewRegexp

func NewRegexp(src string) (*Regexp, error)

NewRegexp compiles src into a Regexp value.

func (*Regexp) MatchString

func (r *Regexp) MatchString(s string) bool

MatchString reports whether s matches the pattern.

func (*Regexp) Source

func (r *Regexp) Source() string

Source returns the pattern source (without delimiters).

func (*Regexp) String

func (r *Regexp) String() string

String renders the value in /slash/ form.

type RuntimeValue

type RuntimeValue struct {
	// contains filtered or unexported fields
}

RuntimeValue wraps a foreign (host-language) object with its runtime and name.

func NewRuntimeValue

func NewRuntimeValue(runtime, name string, obj any) *RuntimeValue

NewRuntimeValue tags obj with a runtime and a type name.

func (*RuntimeValue) String

func (r *RuntimeValue) String() string

String renders the runtime value's tag.

func (*RuntimeValue) Unwrap

func (r *RuntimeValue) Unwrap() any

Unwrap returns the wrapped object.

type SemVer

type SemVer struct {
	// contains filtered or unexported fields
}

SemVer is a Pcore SemVer value: a Semantic Versioning 2.0.0 version.

func NewSemVer

func NewSemVer(s string) (*SemVer, error)

NewSemVer parses s (e.g. "1.2.3-rc.1+build.5") into a SemVer.

func (*SemVer) Compare

func (v *SemVer) Compare(o *SemVer) int

Compare returns -1, 0 or +1 as v orders before, equal to, or after o under Semantic Versioning precedence (build metadata is ignored).

func (*SemVer) String

func (v *SemVer) String() string

String renders the version in canonical SemVer form.

type SemVerRange

type SemVerRange struct {
	// contains filtered or unexported fields
}

SemVerRange is a Pcore SemVerRange value: a set of version constraints (npm/semantic_puppet grammar) matched against a SemVer.

func NewSemVerRange

func NewSemVerRange(s string) (*SemVerRange, error)

NewSemVerRange parses a version range expression.

func (*SemVerRange) Includes

func (r *SemVerRange) Includes(v *SemVer) bool

Includes reports whether v satisfies the range.

func (*SemVerRange) String

func (r *SemVerRange) String() string

String renders the range using its original source expression.

type Sensitive

type Sensitive struct {
	// contains filtered or unexported fields
}

Sensitive wraps a value whose content must not be revealed by String or by ToData. The wrapped value is reachable through Unwrap for callers that legitimately need it.

func NewSensitive

func NewSensitive(v Value) *Sensitive

NewSensitive wraps v as a Sensitive value.

func (*Sensitive) String

func (s *Sensitive) String() string

String is deliberately redacting.

func (*Sensitive) Unwrap

func (s *Sensitive) Unwrap() Value

Unwrap returns the wrapped value.

type Timespan

type Timespan struct {
	// contains filtered or unexported fields
}

Timespan is a Pcore timespan (a duration).

func NewTimespan

func NewTimespan(d time.Duration) *Timespan

NewTimespan wraps d as a Timespan value.

func (*Timespan) Duration

func (ts *Timespan) Duration() time.Duration

Duration returns the wrapped duration.

func (*Timespan) String

func (ts *Timespan) String() string

String renders the timespan using Go's duration form.

type Timestamp

type Timestamp struct {
	// contains filtered or unexported fields
}

Timestamp is a Pcore timestamp (an instant in time).

func NewTimestamp

func NewTimestamp(t time.Time) *Timestamp

NewTimestamp wraps t as a Timestamp value.

func (*Timestamp) String

func (ts *Timestamp) String() string

String renders the timestamp in RFC 3339 (nanosecond) form.

func (*Timestamp) Time

func (ts *Timestamp) Time() time.Time

Time returns the wrapped time.

type Type

type Type interface {
	// Name is the unparameterized Pcore type name, e.g. "Integer".
	Name() string
	// String is the full, parameterized, canonical form. It round-trips:
	// Type(t.String()) reproduces t.
	String() string
	// contains filtered or unexported methods
}

Type is a Pcore type. The set of implementations is closed to this package; use Type (the parser) or the exported constructors to obtain one.

func AnyFloat

func AnyFloat() Type

AnyFloat returns the unbounded Float type.

func AnyInteger

func AnyInteger() Type

AnyInteger returns the unbounded Integer type.

func AnyString

func AnyString() Type

AnyString returns the unbounded String type.

func AnyT

func AnyT() Type

func BinaryT

func BinaryT() Type

func BooleanT

func BooleanT() Type

func CommonType

func CommonType(a, b Type) Type

CommonType returns the narrowest single type that is a supertype of both a and b.

func DataT

func DataT() Type

func DefaultT

func DefaultT() Type

func Generalize

func Generalize(t Type) Type

Generalize widens a type by dropping its range/size constraints and generalizing its parameters: Integer[3,3] becomes Integer, Array[Integer[1,1], 2, 2] becomes Array[Integer], and so on.

func Infer

func Infer(v Value) Type

Infer returns the most specific Pcore type of which v is an instance.

func NewArray

func NewArray(element Type, minSz, maxSz int64) Type

NewArray returns Array[element, minSz, maxSz].

func NewEnum

func NewEnum(values ...string) Type

NewEnum returns Enum[values...].

func NewFloat

func NewFloat(min, max float64) Type

NewFloat returns Float[min, max].

func NewHashType

func NewHashType(key, value Type, minSz, maxSz int64) Type

NewHashType returns Hash[key, value, minSz, maxSz].

func NewInteger

func NewInteger(min, max int64) Type

NewInteger returns Integer[min, max]. Use minInt / maxInt for open ends via AnyInteger instead when a fully generic Integer is wanted.

func NewOptional

func NewOptional(typ Type) Type

NewOptional returns Optional[typ].

func NewString

func NewString(minLen, maxLen int64) Type

NewString returns String[minLen, maxLen].

func NewVariant

func NewVariant(types ...Type) Type

NewVariant returns Variant[types...].

func NumericT

func NumericT() Type

func Parse

func Parse(s string) (Type, error)

Parse parses a Pcore type expression, e.g. "Array[Integer[0,10], 1]", into a Type. It is the Go rendering of Puppet's Type(string); Go cannot name a function and the Type interface identically, so the parser is Parse.

func RichDataT

func RichDataT() Type

func ScalarT

func ScalarT() Type

func SemVerT

func SemVerT() Type

func TimespanT

func TimespanT() Type

func TimestampT

func TimestampT() Type

func UndefT

func UndefT() Type

type URI

type URI struct {
	// contains filtered or unexported fields
}

URI is a Pcore URI value.

func NewURI

func NewURI(s string) *URI

NewURI wraps s as a URI value.

func (*URI) String

func (u *URI) String() string

String renders the URI value.

func (*URI) Value

func (u *URI) Value() string

Value returns the URI string.

type Value

type Value = any

Value is any Pcore value. Scalars are represented by their natural Go types (bool, int64, float64, string); arrays by []Value; hashes by *Hash (or a map[string]Value for the common string-keyed case); and the remaining kinds by the wrapper types in this package (Undef, Default, Sensitive, Regexp, Binary, Timestamp, Timespan). A Go nil is treated as Undef.

var Default Value = defaultValue{}

Default is the Pcore default value (the literal `default`).

var Undef Value = undefValue{}

Undef is the Pcore undef value. A Go nil is also treated as undef.

func FromData

func FromData(v Value) (Value, error)

FromData reconstructs a Pcore value from its rich-data representation as produced by ToData.

func ToData

func ToData(v Value) (Value, error)

ToData converts an arbitrary Pcore value into its rich-data representation: a tree of data-only values (nil, bool, int64, float64, string, []Value and string-keyed *Hash) in which non-data values are encoded as tagged hashes carrying a "__ptype" key. The result round-trips through FromData, except that Sensitive values are redacted by design.

Jump to

Keyboard shortcuts

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