classad

package
v0.20.3 Latest Latest
Warning

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

Go to latest
Published: Jul 27, 2026 License: Apache-2.0 Imports: 16 Imported by: 13

Documentation

Overview

Package classad provides a public API for working with HTCondor ClassAds. It mimics the C++ ClassAd library API from HTCondor.

Package classad provides ClassAd matching functionality.

Package classad provides ClassAd matching functionality.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func All

func All(r io.Reader) iter.Seq[*ClassAd]

All returns an iterator over all ClassAds from an io.Reader. This function is compatible with Go 1.23+ range-over-function syntax.

Example usage (Go 1.23+):

file, _ := os.Open("jobs.classads")
defer file.Close()
for ad := range classad.All(file) {
    // Process ad...
}

For earlier Go versions, use the traditional pattern:

reader := classad.NewReader(file)
for reader.Next() {
    ad := reader.ClassAd()
    // Process ad...
}

func AllOld

func AllOld(r io.Reader) iter.Seq[*ClassAd]

AllOld returns an iterator over all old-style ClassAds from an io.Reader. This function is compatible with Go 1.23+ range-over-function syntax.

Example usage (Go 1.23+):

file, _ := os.Open("machines.classads")
defer file.Close()
for ad := range classad.AllOld(file) {
    // Process ad...
}

func AllOldWithError

func AllOldWithError(r io.Reader, errPtr *error) iter.Seq[*ClassAd]

AllOldWithError returns an iterator for old-style ClassAds that captures any error.

func AllOldWithIndex

func AllOldWithIndex(r io.Reader) iter.Seq2[int, *ClassAd]

AllOldWithIndex returns an iterator over all old-style ClassAds with their index. This function is compatible with Go 1.23+ range-over-function syntax.

func AllWithError

func AllWithError(r io.Reader, errPtr *error) iter.Seq[*ClassAd]

AllWithError returns an iterator that yields ClassAds and captures any error. Use this when you need error handling with the iterator pattern.

Example usage:

file, _ := os.Open("jobs.classads")
defer file.Close()
var err error
for ad := range classad.AllWithError(file, &err) {
    // Process ad...
}
if err != nil {
    log.Fatal(err)
}

func AllWithIndex

func AllWithIndex(r io.Reader) iter.Seq2[int, *ClassAd]

AllWithIndex returns an iterator over all ClassAds with their index. This function is compatible with Go 1.23+ range-over-function syntax.

Example usage (Go 1.23+):

file, _ := os.Open("jobs.classads")
defer file.Close()
for i, ad := range classad.AllWithIndex(file) {
    fmt.Printf("ClassAd #%d\n", i)
    // Process ad...
}

func FoldConstants added in v0.2.0

func FoldConstants(e ast.Expr) ast.Expr

FoldConstants returns e with its constant sub-expressions pre-computed (e.g. Memory > 2048*1024 becomes Memory > 2147483648), evaluating against an empty scope so attribute references are left intact. It is a thin bridge over the flattener (see ClassAd.Flatten) for query planners that pattern-match normalized expressions. Returns nil for a nil input.

func GetAs

func GetAs[T any](c *ClassAd, name string) (T, bool)

GetAs retrieves and evaluates an attribute, converting it to the specified type. This is a type-safe generic getter that handles type conversions automatically. Returns the zero value and false if the attribute doesn't exist or conversion fails.

Example:

cpus, ok := classad.GetAs[int](ad, "cpus")
name, ok := classad.GetAs[string](ad, "name")
price, ok := classad.GetAs[float64](ad, "price")
tags, ok := classad.GetAs[[]string](ad, "tags")
config, ok := classad.GetAs[*classad.ClassAd](ad, "config")

func GetOr

func GetOr[T any](c *ClassAd, name string, defaultValue T) T

GetOr retrieves and evaluates an attribute with a default value. If the attribute doesn't exist or conversion fails, returns the default value. This is a type-safe generic getter with fallback.

Example:

cpus := classad.GetOr(ad, "cpus", 1)           // Defaults to 1
name := classad.GetOr(ad, "name", "unknown")   // Defaults to "unknown"
timeout := classad.GetOr(ad, "timeout", 300)   // Defaults to 300

func InsertAttrList

func InsertAttrList[T int64 | float64 | string | bool | *ClassAd | *Expr](c *ClassAd, name string, values []T)

InsertAttrList inserts an attribute with a list of values using generics. Supported types are: int64, float64, string, bool, *ClassAd, and *Expr.

Example:

ad := classad.New()
InsertAttrList(ad, "numbers", []int64{1, 2, 3, 4, 5})
InsertAttrList(ad, "names", []string{"Alice", "Bob", "Charlie"})
InsertAttrList(ad, "flags", []bool{true, false, true})
InsertAttrList(ad, "values", []float64{1.5, 2.7, 3.14})

// Also works with ClassAds
ad1, ad2 := classad.New(), classad.New()
ad1.InsertAttr("x", 1)
ad2.InsertAttr("y", 2)
InsertAttrList(ad, "items", []*classad.ClassAd{ad1, ad2})

// And with expressions
expr1, _ := classad.ParseExpr("\"hello\"")
expr2, _ := classad.ParseExpr("42")
InsertAttrList(ad, "mixed", []*classad.Expr{expr1, expr2})

func IsPrivateAttribute added in v0.4.0

func IsPrivateAttribute(name string) bool

IsPrivateAttribute reports whether name is a private (secret) attribute of either kind, and so must not be serialized to a client by default. This is the predicate every serialization layer shares.

func IsPrivateAttributeV1 added in v0.4.0

func IsPrivateAttributeV1(name string) bool

IsPrivateAttributeV1 reports whether name is one of HTCondor's fixed private attributes (a claim capability or transfer key).

func IsPrivateAttributeV2 added in v0.4.0

func IsPrivateAttributeV2(name string) bool

IsPrivateAttributeV2 reports whether name is a "_condor_priv"-prefixed private attribute (matched case-insensitively).

func Marshal

func Marshal(v interface{}) (string, error)

Marshal converts a Go value to a ClassAd string representation. It works similarly to encoding/json.Marshal but produces ClassAd format. Struct fields can use "classad" struct tags to control marshaling behavior. If no "classad" tag is present, it falls back to the "json" tag.

Supported struct tag options:

  • Field name: classad:"custom_name" or json:"custom_name"
  • Omit field: classad:"-" or json:"-"
  • Omit if empty: classad:"name,omitempty" or json:"name,omitempty"

Example:

type Job struct {
    ID       int    `classad:"JobId"`
    Name     string `classad:"Name"`
    CPUs     int    `json:"cpus"`  // falls back to json tag
    Priority int    // uses field name "Priority"
}
job := Job{ID: 123, Name: "test", CPUs: 4, Priority: 10}
classadStr, err := classad.Marshal(job)
// Result: [JobId = 123; Name = "test"; cpus = 4; Priority = 10]

func MarshalClassAd

func MarshalClassAd(v interface{}) (string, error)

MarshalClassAd is an alias for Marshal for clarity

func Quote

func Quote(s string) string

Quote escapes a string for safe use in ClassAd expressions. It adds surrounding quotes and escapes special characters according to ClassAd syntax.

Example:

quoted := classad.Quote(`value with "quotes"`)
// Returns: "value with \"quotes\""

func RecoverCyclic added in v0.2.0

func RecoverCyclic(result *Value)

RecoverCyclic converts a cyclic-reference panic raised during evaluation into an error value, matching the tree-walker's top-level entry points. Use it as `defer classad.RecoverCyclic(&result)` around a bytecode run so a cyclic reference resolves to error rather than crashing.

func Unmarshal

func Unmarshal(data string, v interface{}) error

Unmarshal parses a ClassAd string and stores the result in the value pointed to by v. It works similarly to encoding/json.Unmarshal but expects ClassAd format. Struct fields can use "classad" struct tags to control unmarshaling behavior. If no "classad" tag is present, it falls back to the "json" tag.

Example:

type Job struct {
    ID   int    `classad:"JobId"`
    Name string `classad:"Name"`
}
var job Job
err := classad.Unmarshal("[JobId = 123; Name = \"test\"]", &job)

func UnmarshalClassAd

func UnmarshalClassAd(data string, v interface{}) error

UnmarshalClassAd is an alias for Unmarshal for clarity

func Unquote

func Unquote(s string) (string, error)

Unquote removes ClassAd string quoting and unescapes special characters. It expects the input to be a quoted string (with surrounding quotes).

Example:

original, err := classad.Unquote(`"value with \"quotes\""`)
// Returns: value with "quotes"

Types

type ClassAd

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

ClassAd represents a ClassAd with attributes that can be evaluated. This is the main type for working with ClassAds.

func FromAST added in v0.2.0

func FromAST(a *ast.ClassAd) *ClassAd

FromAST wraps an ast.ClassAd in a ClassAd. The ast.ClassAd is adopted (not copied); callers should not mutate it afterward. It is the inverse of AST for serialization layers that decode to an ast.ClassAd.

func New

func New() *ClassAd

New creates a new empty ClassAd.

func Parse

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

Parse parses a ClassAd string and returns a ClassAd object.

func ParseOld

func ParseOld(input string) (*ClassAd, error)

ParseOld parses a ClassAd in the "old" HTCondor format and returns a ClassAd object. Old ClassAds have attributes separated by newlines without surrounding brackets. Example:

Foo = 3
Bar = "hello"
Moo = Foo =!= Undefined

func (*ClassAd) AST added in v0.2.0

func (c *ClassAd) AST() *ast.ClassAd

AST returns the underlying ast.ClassAd. It is intended for serialization layers (e.g. collections/wire) that need the attribute expressions directly. The returned value aliases the ClassAd's internal storage and must not be mutated; attributes are sorted by normalized name.

func (*ClassAd) Clear

func (c *ClassAd) Clear()

Clear removes all attributes from the ClassAd.

func (*ClassAd) Delete

func (c *ClassAd) Delete(name string) bool

Delete removes an attribute from the ClassAd. Returns true if the attribute was found and deleted.

func (*ClassAd) Equal

func (c *ClassAd) Equal(other *ClassAd) bool

Equal reports whether two ClassAds have the same attributes and values, ignoring attribute order and casing of attribute names.

func (*ClassAd) EvaluateAttr

func (c *ClassAd) EvaluateAttr(name string) (result Value)

EvaluateAttr evaluates an attribute and returns its value.

func (*ClassAd) EvaluateAttrBool

func (c *ClassAd) EvaluateAttrBool(name string) (bool, bool)

EvaluateAttrBool evaluates an attribute as a boolean. Returns true if the attribute evaluated to a boolean.

func (*ClassAd) EvaluateAttrInt

func (c *ClassAd) EvaluateAttrInt(name string) (int64, bool)

EvaluateAttrInt evaluates an attribute as an integer. Returns true if the attribute evaluated to an integer.

func (*ClassAd) EvaluateAttrNumber

func (c *ClassAd) EvaluateAttrNumber(name string) (float64, bool)

EvaluateAttrNumber evaluates an attribute as a number (int or real). Returns true if the attribute evaluated to a number. Integers are promoted to float64.

func (*ClassAd) EvaluateAttrReal

func (c *ClassAd) EvaluateAttrReal(name string) (float64, bool)

EvaluateAttrReal evaluates an attribute as a real number. Returns true if the attribute evaluated to a real.

func (*ClassAd) EvaluateAttrString

func (c *ClassAd) EvaluateAttrString(name string) (string, bool)

EvaluateAttrString evaluates an attribute as a string. Returns true if the attribute evaluated to a string.

func (*ClassAd) EvaluateExpr

func (c *ClassAd) EvaluateExpr(expr ast.Expr) (result Value)

EvaluateExpr evaluates an arbitrary expression in the context of this ClassAd.

func (*ClassAd) EvaluateExprString

func (c *ClassAd) EvaluateExprString(exprStr string) (Value, error)

EvaluateExprString parses and evaluates an expression string.

func (*ClassAd) EvaluateExprWithTarget

func (c *ClassAd) EvaluateExprWithTarget(expr *Expr, target *ClassAd) Value

EvaluateExprWithTarget evaluates an Expr in the context of this ClassAd with a target. This ClassAd serves as the MY scope, and the target parameter serves as the TARGET scope. This is useful for match-making operations where expressions reference both ClassAds.

Example:

expr, _ := classad.ParseExpr("MY.Cpus > TARGET.Cpus")
result := jobAd.EvaluateExprWithTarget(expr, machineAd)

func (*ClassAd) ExternalRefs

func (c *ClassAd) ExternalRefs(expr *Expr) []string

ExternalRefs returns a list of attribute names referenced in the expression but not defined in this ClassAd. This is useful for validating that a ClassAd has all required attributes before evaluation.

Example:

ad, _ := classad.Parse("[Cpus = 4; Memory = 8192]")
expr, _ := classad.ParseExpr("Cpus * 2 + ExternalAttr")
external := ad.ExternalRefs(expr)  // Returns: ["ExternalAttr"]

func (*ClassAd) Flatten

func (c *ClassAd) Flatten(expr *Expr) *Expr

Flatten partially evaluates an expression in the context of this ClassAd. Attributes that are defined in the ClassAd are evaluated and replaced with their values. Undefined attributes are left as references. This is useful for optimizing expressions by pre-computing constant sub-expressions.

Example:

ad, _ := classad.Parse("[RequestMemory = 2048]")
expr, _ := classad.ParseExpr("RequestMemory * 1024 * 1024")
flattened := ad.Flatten(expr)  // Returns expression equivalent to: 2147483648

func (*ClassAd) GetAttributes

func (c *ClassAd) GetAttributes() []string

GetAttributes returns a list of all attribute names.

func (*ClassAd) GetParent

func (c *ClassAd) GetParent() *ClassAd

GetParent returns the parent ClassAd, if any.

func (*ClassAd) GetTarget

func (c *ClassAd) GetTarget() *ClassAd

GetTarget returns the target ClassAd, if any.

func (*ClassAd) Insert

func (c *ClassAd) Insert(name string, expr ast.Expr)

Insert inserts an attribute with an expression into the ClassAd.

func (*ClassAd) InsertAttr

func (c *ClassAd) InsertAttr(name string, value int64)

InsertAttr inserts an attribute with an integer value.

func (*ClassAd) InsertAttrBool

func (c *ClassAd) InsertAttrBool(name string, value bool)

InsertAttrBool inserts an attribute with a boolean value.

func (*ClassAd) InsertAttrClassAd

func (c *ClassAd) InsertAttrClassAd(name string, value *ClassAd)

InsertAttrClassAd inserts an attribute with a nested ClassAd value. The provided ClassAd will be embedded as a record literal.

func (*ClassAd) InsertAttrFloat

func (c *ClassAd) InsertAttrFloat(name string, value float64)

InsertAttrFloat inserts an attribute with a float value.

func (*ClassAd) InsertAttrString

func (c *ClassAd) InsertAttrString(name, value string)

InsertAttrString inserts an attribute with a string value.

func (*ClassAd) InsertExpr

func (c *ClassAd) InsertExpr(name string, expr *Expr)

InsertExpr inserts an attribute with an Expr value into the ClassAd. This allows you to copy expressions between ClassAds without evaluating them.

Example:

expr, _ := sourceAd.Lookup("Formula")
targetAd.InsertExpr("Formula", expr)

func (*ClassAd) InsertListElement

func (c *ClassAd) InsertListElement(name string, element *Expr)

InsertListElement inserts an element into a list attribute. If the attribute doesn't exist, it creates a new list with the element. If the attribute exists and is a list, it appends the element to the existing list. If the attribute exists but is not a list, it replaces it with a new list containing the element.

Example:

ad := classad.New()
expr1, _ := classad.ParseExpr("\"first\"")
expr2, _ := classad.ParseExpr("\"second\"")
ad.InsertListElement("items", expr1)
ad.InsertListElement("items", expr2)
// Result: items = {"first", "second"}

func (*ClassAd) InternalRefs

func (c *ClassAd) InternalRefs(expr *Expr) []string

InternalRefs returns a list of attribute names referenced in the expression that are defined in this ClassAd.

Example:

ad, _ := classad.Parse("[Cpus = 4; Memory = 8192]")
expr, _ := classad.ParseExpr("Cpus * 2 + ExternalAttr")
internal := ad.InternalRefs(expr)  // Returns: ["Cpus"]

func (*ClassAd) Lookup

func (c *ClassAd) Lookup(name string) (*Expr, bool)

Lookup returns the unevaluated expression for an attribute. Returns nil if the attribute doesn't exist. This is useful for inspecting or copying expressions without evaluating them.

Example:

ad, _ := classad.Parse("[x = 10; y = x * 2]")
expr, ok := ad.Lookup("y")  // Returns expression for "x * 2"
if ok {
    fmt.Println(expr.String())  // Prints: x * 2
}

func (*ClassAd) MarshalJSON

func (c *ClassAd) MarshalJSON() ([]byte, error)

MarshalJSON implements the json.Marshaler interface for ClassAd. ClassAds are serialized as JSON objects where:

  • Attribute names are JSON keys
  • Simple values (strings, numbers, booleans) are JSON values
  • Lists are JSON arrays
  • Nested ClassAds are JSON objects
  • Expressions are serialized as strings with the format "/Expr(<expression>)/" (which appears as "\/Expr(<expression>)\/" in JSON due to escaping)

Example:

ad, _ := classad.Parse(`[x = 5; y = x + 3; name = "test"]`)
jsonBytes, _ := json.Marshal(ad)
// {"name":"test","x":5,"y":"\/Expr(x + 3)\/"}

MarshalJSON implements json.Marshaler, excluding private (secret) attributes so that any HTTP/JSON response that marshals a ClassAd is default-safe -- a job's ClaimId or a slot's Capability never reaches a client through json.Marshal. Use MarshalJSONWithPrivate where the full ad is required. See IsPrivateAttribute.

func (*ClassAd) MarshalJSONWithPrivate added in v0.4.0

func (c *ClassAd) MarshalJSONWithPrivate() ([]byte, error)

MarshalJSONWithPrivate is MarshalJSON including private attributes. Prefer MarshalJSON for anything client-facing.

func (*ClassAd) MarshalOld

func (c *ClassAd) MarshalOld() string

ToOldFormat serializes the ClassAd to old HTCondor format (newline-delimited). Old format has one attribute per line without surrounding brackets.

Example:

ad, _ := classad.Parse("[Cpus = 4; Memory = 8192]")
oldFmt := ad.MarshalOld()
// Returns: "Cpus = 4\nMemory = 8192"

MarshalOld excludes private (secret) attributes; use MarshalOldWithPrivate for the full ad. See IsPrivateAttribute.

func (*ClassAd) MarshalOldWithPrivate added in v0.4.0

func (c *ClassAd) MarshalOldWithPrivate() string

MarshalOldWithPrivate is MarshalOld including private attributes. Prefer MarshalOld for anything client-facing.

func (*ClassAd) Redacted added in v0.4.0

func (c *ClassAd) Redacted() *ClassAd

Redacted returns a copy of the ClassAd with every private attribute removed (see IsPrivateAttribute), leaving the original -- and its stored secrets -- untouched. It is the explicit form to hand to a client where a boundary does not already redact. A nil ad (or one with no attributes) is returned as-is; the returned copy shares attribute values with the original and must be treated as read-only.

func (*ClassAd) Set

func (c *ClassAd) Set(name string, value any) error

Set is a generic method that accepts any Go value and inserts it as an attribute. This provides a more idiomatic alternative to the type-specific Insert* methods. Supported types: int/int64/etc., float64, string, bool, []T, *ClassAd, *Expr, and structs.

Example:

ad := classad.New()
ad.Set("cpus", 4)                    // int
ad.Set("name", "job-1")              // string
ad.Set("price", 3.14)                // float64
ad.Set("enabled", true)              // bool
ad.Set("tags", []string{"a", "b"})   // slice
ad.Set("config", nestedClassAd)      // *ClassAd

func (*ClassAd) SetParent

func (c *ClassAd) SetParent(parent *ClassAd)

SetParent sets the parent ClassAd for this ClassAd. The parent is used for PARENT.attr references during evaluation.

func (*ClassAd) SetTarget

func (c *ClassAd) SetTarget(target *ClassAd)

SetTarget sets the target ClassAd for this ClassAd. The target is used for TARGET.attr references during evaluation.

func (*ClassAd) Size

func (c *ClassAd) Size() int

Size returns the number of attributes in the ClassAd.

func (*ClassAd) String

func (c *ClassAd) String() string

String renders the ClassAd in new (bracketed) format, excluding private (secret) attributes -- the default-safe form for any output that may reach a client. Use StringWithPrivate where the full ad, including secrets, is required (internal diagnostics, an authorized private channel).

func (*ClassAd) StringWithPrivate added in v0.4.0

func (c *ClassAd) StringWithPrivate() string

StringWithPrivate is String including private attributes. Prefer String for anything client-facing; see IsPrivateAttribute.

func (*ClassAd) UnmarshalJSON

func (c *ClassAd) UnmarshalJSON(data []byte) error

UnmarshalJSON implements the json.Unmarshaler interface for ClassAd. Deserializes JSON into a ClassAd, handling the special expression format. Strings matching the pattern "/Expr(<expression>)/" are parsed as expressions. Note: When unmarshaling from JSON, the Go json package automatically unescapes "\/Expr(...)\/" to "/Expr(...)/" so only the unescaped format is checked.

Example:

jsonStr := `{"name":"test","x":5,"y":"\/Expr(x + 3)\/"}`
var ad ClassAd
json.Unmarshal([]byte(jsonStr), &ad)

type Evaluator

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

Evaluator handles evaluation of ClassAd expressions.

func NewEvaluator

func NewEvaluator(ad *ClassAd) *Evaluator

NewEvaluator creates a new evaluator for the given ClassAd.

func (*Evaluator) ApplyBinaryOp added in v0.2.0

func (e *Evaluator) ApplyBinaryOp(op string, left, right Value) Value

ApplyBinaryOp applies a binary operator to two already-evaluated operand values, returning the same result the tree-walking evaluator would for the corresponding *ast.BinaryOp. It covers arithmetic, comparison, bitwise, the meta-equality operators ("is"/"isnt"), and the logical operators ("&&"/"||").

For "&&"/"||" the caller is responsible for short-circuiting (see ShortCircuit): when both operands are supplied here, the full three-valued truth table is applied, which is correct only if the caller already decided the right operand had to be evaluated.

func (*Evaluator) ApplyUnaryOp added in v0.2.0

func (e *Evaluator) ApplyUnaryOp(op string, operand Value) Value

ApplyUnaryOp applies a unary operator to an already-evaluated operand value.

func (*Evaluator) Evaluate

func (e *Evaluator) Evaluate(expr ast.Expr) Value

Evaluate evaluates an expression in the context of the ClassAd.

Depth is tracked to bound recursion (a cyclic reference or a pathologically deep expression panics with cyclicEvalError once maxEvalDepth is reached). The increment/decrement is done inline rather than with `defer e.depth--`: this function recurses once per AST node, and because a recover() sits in an ancestor frame (the recoverCyclic at every evaluation entry point) the Go compiler cannot open-code those defers, so a per-node defer put the whole tree-walk on the slow stack-defer path -- ~25% of matchmaking CPU. On the cyclic-panic path the decrement is skipped (depth is left inflated), which is harmless: every terminal entry point recovers into a fresh or SetScope-reset evaluator, and the one recover-and-continue caller (evalRecoveringCyclic, for lazy-list elements) saves and restores depth around each element.

func (*Evaluator) ResolveRef added in v0.2.0

func (e *Evaluator) ResolveRef(name string, scope ast.AttributeScope) Value

ResolveRef resolves an attribute reference (with the given scope) in the evaluator's ClassAd, exactly as the evaluator resolves an *ast.AttributeReference: scope-chain search for an unscoped name, MY/TARGET/PARENT handling, evaluation of the referenced attribute's expression, and cyclic-reference detection.

func (*Evaluator) SetResolver added in v0.2.0

func (e *Evaluator) SetResolver(fn func(name string, scope ast.AttributeScope) Value)

SetResolver installs (or clears, with nil) a custom attribute resolver. While set, every attribute reference the evaluator resolves is delegated to fn(name, scope) instead of being looked up in the ClassAd scope, so a bytecode program can be evaluated against an alternate backing (e.g. an encoded ad) without materializing a ClassAd. fn should return the attribute's value, or undefined if absent. The Evaluator is not safe for concurrent use.

func (*Evaluator) SetScope added in v0.2.0

func (e *Evaluator) SetScope(ad *ClassAd)

SetScope rebinds the evaluator to a new scope ClassAd and resets its recursion depth, so one Evaluator can be reused across many evaluations (e.g. a bytecode Matcher scanning a collection) instead of allocating a fresh one per ad.

Cyclic-reference state is tracked per ClassAd (in ClassAd.evaluating), not on the Evaluator, and each attribute evaluation removes its own marker on the way out, so nothing carries over between scopes. Depth is balanced by Evaluate's deferred decrement even when a cyclic panic unwinds, so it is 0 here after any completed or recovered evaluation; the reset is a defensive guarantee. The Evaluator is not safe for concurrent use.

func (*Evaluator) ShortCircuit added in v0.2.0

func (e *Evaluator) ShortCircuit(op string, left Value) (result Value, done bool)

ShortCircuit reports whether the left operand of a logical operator already determines the result without evaluating the right operand, mirroring the evaluator's short-circuit rules:

"&&": left false  -> false ; left error -> error
"||": left true   -> true  ; left error -> error

If done is true, result is the operator's value and the right operand must not be evaluated. If done is false, the caller must evaluate the right operand and combine with ApplyBinaryOp. This lets the interpreter reproduce short-circuit behaviour (including its interaction with cyclic references) exactly.

type Expr

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

Expr represents an unevaluated ClassAd expression. It provides methods to evaluate the expression in different contexts and to inspect its structure.

func ParseExpr

func ParseExpr(input string) (*Expr, error)

ParseExpr parses a ClassAd expression string and returns an Expr object. This allows you to work with expressions without evaluating them immediately.

Example:

expr, err := classad.ParseExpr("Cpus * 2 + Memory / 1024")
if err != nil {
    log.Fatal(err)
}

func (*Expr) Equal

func (e *Expr) Equal(other *Expr) bool

Equal reports structural equality between two expressions.

func (*Expr) Eval

func (e *Expr) Eval(scope *ClassAd) (result Value)

Eval evaluates the expression in the context of the given ClassAd. This is equivalent to calling classad.EvaluateExpr(expr).

func (*Expr) EvalWithContext

func (e *Expr) EvalWithContext(scope, target *ClassAd) (result Value)

EvalWithContext evaluates the expression with explicit MY (scope) and TARGET contexts. The scope parameter provides the context for MY.attr references. The target parameter provides the context for TARGET.attr references. Either parameter may be nil if not needed.

Example:

expr, _ := classad.ParseExpr("MY.Cpus > TARGET.Cpus")
result := expr.EvalWithContext(jobAd, machineAd)

func (*Expr) String

func (e *Expr) String() string

String returns the string representation of the expression.

type Marshaler

type Marshaler interface {
	MarshalClassAd() (string, error)
}

Marshaler is the interface implemented by types that can marshal themselves into ClassAd format. This is similar to json.Marshaler.

type MatchClassAd

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

MatchClassAd represents a pair of ClassAds for matching. Inspired by the HTCondor C++ MatchClassAd implementation. See: https://github.com/htcondor/htcondor/blob/main/src/classad/classad/matchClassad.h

In HTCondor, matching typically involves a job ClassAd and a machine ClassAd. Each can reference the other using TARGET.attr syntax.

func NewMatchClassAd

func NewMatchClassAd(left, right *ClassAd) *MatchClassAd

NewMatchClassAd creates a new MatchClassAd with two ClassAds. The left ClassAd can reference the right using TARGET.attr The right ClassAd can reference the left using TARGET.attr

func (*MatchClassAd) EvaluateAttrLeft

func (m *MatchClassAd) EvaluateAttrLeft(name string) Value

EvaluateAttrLeft evaluates an attribute in the left ClassAd.

func (*MatchClassAd) EvaluateAttrRight

func (m *MatchClassAd) EvaluateAttrRight(name string) Value

EvaluateAttrRight evaluates an attribute in the right ClassAd.

func (*MatchClassAd) EvaluateExprLeft

func (m *MatchClassAd) EvaluateExprLeft(expr ast.Expr) Value

EvaluateExprLeft evaluates an expression in the context of the left ClassAd.

func (*MatchClassAd) EvaluateExprRight

func (m *MatchClassAd) EvaluateExprRight(expr ast.Expr) Value

EvaluateExprRight evaluates an expression in the context of the right ClassAd.

func (*MatchClassAd) EvaluateRankLeft

func (m *MatchClassAd) EvaluateRankLeft() (float64, bool)

EvaluateRankLeft evaluates the left ClassAd's rank expression. In HTCondor, Rank is used to prefer certain matches over others.

func (*MatchClassAd) EvaluateRankRight

func (m *MatchClassAd) EvaluateRankRight() (float64, bool)

EvaluateRankRight evaluates the right ClassAd's rank expression.

func (*MatchClassAd) GetLeftAd

func (m *MatchClassAd) GetLeftAd() *ClassAd

GetLeftAd returns the left ClassAd.

func (*MatchClassAd) GetRightAd

func (m *MatchClassAd) GetRightAd() *ClassAd

GetRightAd returns the right ClassAd.

func (*MatchClassAd) Match

func (m *MatchClassAd) Match() bool

Match checks if the ClassAds match using default "Requirements" attribute. This is equivalent to Symmetry("Requirements", "Requirements").

func (*MatchClassAd) ReplaceLeftAd

func (m *MatchClassAd) ReplaceLeftAd(left *ClassAd)

ReplaceLeftAd replaces the left ClassAd. Updates TARGET references appropriately.

func (*MatchClassAd) ReplaceRightAd

func (m *MatchClassAd) ReplaceRightAd(right *ClassAd)

ReplaceRightAd replaces the right ClassAd. Updates TARGET references appropriately.

func (*MatchClassAd) Symmetry

func (m *MatchClassAd) Symmetry(leftReqAttr, rightReqAttr string) bool

Symmetry checks if both ClassAds' Requirements evaluate to true. This is the core matching operation in HTCondor. Returns true only if BOTH: - left.Requirements evaluates to true (with TARGET = right) - right.Requirements evaluates to true (with TARGET = left)

type Reader

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

Reader provides an iterator for parsing multiple ClassAds from an io.Reader. It supports both new-style (bracketed) and old-style (newline-delimited) formats. New-style ClassAds can be concatenated without delimiters or whitespace.

func NewOldReader

func NewOldReader(r io.Reader) *Reader

NewOldReader creates a new Reader for parsing old-style ClassAds (newline-delimited). Each ClassAd is separated by a blank line. Example format:

Foo = 1
Bar = 2

Baz = 3
Qux = 4

func NewReader

func NewReader(r io.Reader) *Reader

NewReader creates a new Reader for parsing new-style ClassAds (with brackets). ClassAds may be concatenated directly; whitespace and comments are optional. Example format:

[Foo = 1; Bar = 2]
[Baz = 3; Qux = 4]

func (*Reader) ClassAd

func (r *Reader) ClassAd() *ClassAd

ClassAd returns the current ClassAd. This should be called after Next() returns true.

func (*Reader) Err

func (r *Reader) Err() error

Err returns the error that occurred during iteration, if any. This should be called after Next() returns false to distinguish between EOF and an actual error.

func (*Reader) Next

func (r *Reader) Next() bool

Next advances to the next ClassAd and returns true if one was found. It returns false when there are no more ClassAds or an error occurred. Call Err() after Next returns false to check for errors.

type Unmarshaler

type Unmarshaler interface {
	UnmarshalClassAd(data string) error
}

Unmarshaler is the interface implemented by types that can unmarshal a ClassAd representation of themselves. This is similar to json.Unmarshaler.

type Value

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

Value represents the result of evaluating a ClassAd expression.

A Value is copied by value constantly -- on every bytecode stack push/pop and every operator call -- so it is kept small: the list payload (which is four words and only used by list values) lives out-of-line behind the list pointer, leaving a Value that is a scalar/string/classad in one compact struct.

func Avg added in v0.6.0

func Avg(values []Value) Value

Avg averages values under the ClassAd coercion rules (see Sum).

func Max added in v0.6.0

func Max(values []Value) Value

Max returns the numeric maximum under the ClassAd coercion rules (see Sum).

func Min added in v0.6.0

func Min(values []Value) Value

Min returns the numeric minimum under the ClassAd coercion rules (see Sum).

func NewBoolValue

func NewBoolValue(b bool) Value

NewBoolValue creates a boolean value.

func NewClassAdValue

func NewClassAdValue(ad *ClassAd) Value

NewClassAdValue creates a ClassAd value.

func NewErrorValue

func NewErrorValue() Value

NewErrorValue creates an error value.

func NewIntValue

func NewIntValue(i int64) Value

NewIntValue creates an integer value.

func NewListValue

func NewListValue(list []Value) Value

NewListValue creates a list value.

func NewRealValue

func NewRealValue(r float64) Value

NewRealValue creates a real value.

func NewStringValue

func NewStringValue(s string) Value

NewStringValue creates a string value.

func NewUndefinedValue

func NewUndefinedValue() Value

NewUndefinedValue creates an undefined value.

func Sum added in v0.6.0

func Sum(values []Value) Value

Sum, Avg, Min, and Max apply HTCondor's ClassAd list-aggregate coercion rules (the sum()/avg()/min()/max() built-ins) to a slice of values: integers stay exact int64 and coerce to real only when a real value is present, booleans coerce to 0/1, undefined elements are skipped, and any error element makes the result an error. min/max are numeric (a string element is an error). An empty or all-undefined list sums/averages to integer 0; min/max of one is undefined. These let callers outside the expression evaluator (e.g. a GROUP BY engine) aggregate with identical semantics.

func (Value) BoolValue

func (v Value) BoolValue() (bool, error)

BoolValue returns the boolean value. Returns error if not a boolean.

func (Value) ClassAdValue

func (v Value) ClassAdValue() (*ClassAd, error)

ClassAdValue returns the ClassAd value. Returns error if not a ClassAd.

func (Value) IntValue

func (v Value) IntValue() (int64, error)

IntValue returns the integer value. Returns error if not an integer.

func (Value) IsBool

func (v Value) IsBool() bool

IsBool returns true if the value is a boolean.

func (Value) IsClassAd

func (v Value) IsClassAd() bool

IsClassAd returns true if the value is a ClassAd.

func (Value) IsError

func (v Value) IsError() bool

IsError returns true if the value is an error.

func (Value) IsInteger

func (v Value) IsInteger() bool

IsInteger returns true if the value is an integer.

func (Value) IsList

func (v Value) IsList() bool

IsList returns true if the value is a list.

func (Value) IsNumber

func (v Value) IsNumber() bool

IsNumber returns true if the value is an integer or real.

func (Value) IsReal

func (v Value) IsReal() bool

IsReal returns true if the value is a real number.

func (Value) IsString

func (v Value) IsString() bool

IsString returns true if the value is a string.

func (Value) IsUndefined

func (v Value) IsUndefined() bool

IsUndefined returns true if the value is undefined.

func (Value) ListValue

func (v Value) ListValue() ([]Value, error)

ListValue returns the list value. Returns error if not a list.

func (Value) NumberValue

func (v Value) NumberValue() (float64, error)

NumberValue returns the numeric value as a float64, converting integers if needed.

func (Value) RealValue

func (v Value) RealValue() (float64, error)

RealValue returns the real value. Returns error if not a real.

func (Value) String

func (v Value) String() string

String returns a string representation of the value.

func (Value) StringValue

func (v Value) StringValue() (string, error)

StringValue returns the string value. Returns error if not a string.

func (Value) Type

func (v Value) Type() ValueType

Type returns the type of the value.

type ValueType

type ValueType int

ValueType represents the type of a ClassAd value.

const (
	// UndefinedValue represents an undefined value
	UndefinedValue ValueType = iota
	// ErrorValue represents an error value
	ErrorValue
	// BooleanValue represents a boolean value
	BooleanValue
	// IntegerValue represents an integer value
	IntegerValue
	// RealValue represents a real (float) value
	RealValue
	// StringValue represents a string value
	StringValue
	// ListValue represents a list value
	ListValue
	// ClassAdValue represents a nested ClassAd value
	ClassAdValue
)

Jump to

Keyboard shortcuts

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