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 ¶
- func All(r io.Reader) iter.Seq[*ClassAd]
- func AllOld(r io.Reader) iter.Seq[*ClassAd]
- func AllOldWithError(r io.Reader, errPtr *error) iter.Seq[*ClassAd]
- func AllOldWithIndex(r io.Reader) iter.Seq2[int, *ClassAd]
- func AllWithError(r io.Reader, errPtr *error) iter.Seq[*ClassAd]
- func AllWithIndex(r io.Reader) iter.Seq2[int, *ClassAd]
- func FoldConstants(e ast.Expr) ast.Expr
- func GetAs[T any](c *ClassAd, name string) (T, bool)
- func GetOr[T any](c *ClassAd, name string, defaultValue T) T
- func InsertAttrList[T int64 | float64 | string | bool | *ClassAd | *Expr](c *ClassAd, name string, values []T)
- func IsPrivateAttribute(name string) bool
- func IsPrivateAttributeV1(name string) bool
- func IsPrivateAttributeV2(name string) bool
- func Marshal(v interface{}) (string, error)
- func MarshalClassAd(v interface{}) (string, error)
- func Quote(s string) string
- func RecoverCyclic(result *Value)
- func Unmarshal(data string, v interface{}) error
- func UnmarshalClassAd(data string, v interface{}) error
- func Unquote(s string) (string, error)
- type ClassAd
- func (c *ClassAd) AST() *ast.ClassAd
- func (c *ClassAd) Clear()
- func (c *ClassAd) Delete(name string) bool
- func (c *ClassAd) Equal(other *ClassAd) bool
- func (c *ClassAd) EvaluateAttr(name string) (result Value)
- func (c *ClassAd) EvaluateAttrBool(name string) (bool, bool)
- func (c *ClassAd) EvaluateAttrInt(name string) (int64, bool)
- func (c *ClassAd) EvaluateAttrNumber(name string) (float64, bool)
- func (c *ClassAd) EvaluateAttrReal(name string) (float64, bool)
- func (c *ClassAd) EvaluateAttrString(name string) (string, bool)
- func (c *ClassAd) EvaluateExpr(expr ast.Expr) (result Value)
- func (c *ClassAd) EvaluateExprString(exprStr string) (Value, error)
- func (c *ClassAd) EvaluateExprWithTarget(expr *Expr, target *ClassAd) Value
- func (c *ClassAd) ExternalRefs(expr *Expr) []string
- func (c *ClassAd) Flatten(expr *Expr) *Expr
- func (c *ClassAd) GetAttributes() []string
- func (c *ClassAd) GetParent() *ClassAd
- func (c *ClassAd) GetTarget() *ClassAd
- func (c *ClassAd) Insert(name string, expr ast.Expr)
- func (c *ClassAd) InsertAttr(name string, value int64)
- func (c *ClassAd) InsertAttrBool(name string, value bool)
- func (c *ClassAd) InsertAttrClassAd(name string, value *ClassAd)
- func (c *ClassAd) InsertAttrFloat(name string, value float64)
- func (c *ClassAd) InsertAttrString(name, value string)
- func (c *ClassAd) InsertExpr(name string, expr *Expr)
- func (c *ClassAd) InsertListElement(name string, element *Expr)
- func (c *ClassAd) InternalRefs(expr *Expr) []string
- func (c *ClassAd) Lookup(name string) (*Expr, bool)
- func (c *ClassAd) MarshalJSON() ([]byte, error)
- func (c *ClassAd) MarshalJSONWithPrivate() ([]byte, error)
- func (c *ClassAd) MarshalOld() string
- func (c *ClassAd) MarshalOldWithPrivate() string
- func (c *ClassAd) Redacted() *ClassAd
- func (c *ClassAd) Set(name string, value any) error
- func (c *ClassAd) SetParent(parent *ClassAd)
- func (c *ClassAd) SetTarget(target *ClassAd)
- func (c *ClassAd) Size() int
- func (c *ClassAd) String() string
- func (c *ClassAd) StringWithPrivate() string
- func (c *ClassAd) UnmarshalJSON(data []byte) error
- type Evaluator
- func (e *Evaluator) ApplyBinaryOp(op string, left, right Value) Value
- func (e *Evaluator) ApplyUnaryOp(op string, operand Value) Value
- func (e *Evaluator) Evaluate(expr ast.Expr) Value
- func (e *Evaluator) ResolveRef(name string, scope ast.AttributeScope) Value
- func (e *Evaluator) SetResolver(fn func(name string, scope ast.AttributeScope) Value)
- func (e *Evaluator) SetScope(ad *ClassAd)
- func (e *Evaluator) ShortCircuit(op string, left Value) (result Value, done bool)
- type Expr
- type Marshaler
- type MatchClassAd
- func (m *MatchClassAd) EvaluateAttrLeft(name string) Value
- func (m *MatchClassAd) EvaluateAttrRight(name string) Value
- func (m *MatchClassAd) EvaluateExprLeft(expr ast.Expr) Value
- func (m *MatchClassAd) EvaluateExprRight(expr ast.Expr) Value
- func (m *MatchClassAd) EvaluateRankLeft() (float64, bool)
- func (m *MatchClassAd) EvaluateRankRight() (float64, bool)
- func (m *MatchClassAd) GetLeftAd() *ClassAd
- func (m *MatchClassAd) GetRightAd() *ClassAd
- func (m *MatchClassAd) Match() bool
- func (m *MatchClassAd) ReplaceLeftAd(left *ClassAd)
- func (m *MatchClassAd) ReplaceRightAd(right *ClassAd)
- func (m *MatchClassAd) Symmetry(leftReqAttr, rightReqAttr string) bool
- type Reader
- type Unmarshaler
- type Value
- func Avg(values []Value) Value
- func Max(values []Value) Value
- func Min(values []Value) Value
- func NewBoolValue(b bool) Value
- func NewClassAdValue(ad *ClassAd) Value
- func NewErrorValue() Value
- func NewIntValue(i int64) Value
- func NewListValue(list []Value) Value
- func NewRealValue(r float64) Value
- func NewStringValue(s string) Value
- func NewUndefinedValue() Value
- func Sum(values []Value) Value
- func (v Value) BoolValue() (bool, error)
- func (v Value) ClassAdValue() (*ClassAd, error)
- func (v Value) IntValue() (int64, error)
- func (v Value) IsBool() bool
- func (v Value) IsClassAd() bool
- func (v Value) IsError() bool
- func (v Value) IsInteger() bool
- func (v Value) IsList() bool
- func (v Value) IsNumber() bool
- func (v Value) IsReal() bool
- func (v Value) IsString() bool
- func (v Value) IsUndefined() bool
- func (v Value) ListValue() ([]Value, error)
- func (v Value) NumberValue() (float64, error)
- func (v Value) RealValue() (float64, error)
- func (v Value) String() string
- func (v Value) StringValue() (string, error)
- func (v Value) Type() ValueType
- type ValueType
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func All ¶
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 ¶
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 ¶
AllOldWithError returns an iterator for old-style ClassAds that captures any error.
func AllOldWithIndex ¶
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 ¶
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 ¶
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
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 ¶
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 ¶
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
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
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
IsPrivateAttributeV2 reports whether name is a "_condor_priv"-prefixed private attribute (matched case-insensitively).
func Marshal ¶
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 ¶
MarshalClassAd is an alias for Marshal for clarity
func Quote ¶
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 ¶
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 ¶
UnmarshalClassAd is an alias for Unmarshal for clarity
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
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 ParseOld ¶
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
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) Delete ¶
Delete removes an attribute from the ClassAd. Returns true if the attribute was found and deleted.
func (*ClassAd) Equal ¶
Equal reports whether two ClassAds have the same attributes and values, ignoring attribute order and casing of attribute names.
func (*ClassAd) EvaluateAttr ¶
EvaluateAttr evaluates an attribute and returns its value.
func (*ClassAd) EvaluateAttrBool ¶
EvaluateAttrBool evaluates an attribute as a boolean. Returns true if the attribute evaluated to a boolean.
func (*ClassAd) EvaluateAttrInt ¶
EvaluateAttrInt evaluates an attribute as an integer. Returns true if the attribute evaluated to an integer.
func (*ClassAd) EvaluateAttrNumber ¶
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 ¶
EvaluateAttrReal evaluates an attribute as a real number. Returns true if the attribute evaluated to a real.
func (*ClassAd) EvaluateAttrString ¶
EvaluateAttrString evaluates an attribute as a string. Returns true if the attribute evaluated to a string.
func (*ClassAd) EvaluateExpr ¶
EvaluateExpr evaluates an arbitrary expression in the context of this ClassAd.
func (*ClassAd) EvaluateExprString ¶
EvaluateExprString parses and evaluates an expression string.
func (*ClassAd) EvaluateExprWithTarget ¶
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 ¶
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 ¶
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 ¶
GetAttributes returns a list of all attribute names.
func (*ClassAd) InsertAttr ¶
InsertAttr inserts an attribute with an integer value.
func (*ClassAd) InsertAttrBool ¶
InsertAttrBool inserts an attribute with a boolean value.
func (*ClassAd) InsertAttrClassAd ¶
InsertAttrClassAd inserts an attribute with a nested ClassAd value. The provided ClassAd will be embedded as a record literal.
func (*ClassAd) InsertAttrFloat ¶
InsertAttrFloat inserts an attribute with a float value.
func (*ClassAd) InsertAttrString ¶
InsertAttrString inserts an attribute with a string value.
func (*ClassAd) InsertExpr ¶
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 ¶
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 ¶
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 ¶
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 ¶
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
MarshalJSONWithPrivate is MarshalJSON including private attributes. Prefer MarshalJSON for anything client-facing.
func (*ClassAd) MarshalOld ¶
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
MarshalOldWithPrivate is MarshalOld including private attributes. Prefer MarshalOld for anything client-facing.
func (*ClassAd) Redacted ¶ added in v0.4.0
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 ¶
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 ¶
SetParent sets the parent ClassAd for this ClassAd. The parent is used for PARENT.attr references during evaluation.
func (*ClassAd) SetTarget ¶
SetTarget sets the target ClassAd for this ClassAd. The target is used for TARGET.attr references during evaluation.
func (*ClassAd) 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
StringWithPrivate is String including private attributes. Prefer String for anything client-facing; see IsPrivateAttribute.
func (*ClassAd) UnmarshalJSON ¶
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 ¶
NewEvaluator creates a new evaluator for the given ClassAd.
func (*Evaluator) ApplyBinaryOp ¶ added in v0.2.0
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
ApplyUnaryOp applies a unary operator to an already-evaluated operand value.
func (*Evaluator) Evaluate ¶
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
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
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 ¶
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) Eval ¶
Eval evaluates the expression in the context of the given ClassAd. This is equivalent to calling classad.EvaluateExpr(expr).
func (*Expr) EvalWithContext ¶
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)
type Marshaler ¶
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 ¶
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 ¶
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 ¶
ClassAd returns the current ClassAd. This should be called after Next() returns true.
type Unmarshaler ¶
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 Max ¶ added in v0.6.0
Max returns the numeric maximum under the ClassAd coercion rules (see Sum).
func Min ¶ added in v0.6.0
Min returns the numeric minimum under the ClassAd coercion rules (see Sum).
func NewClassAdValue ¶
NewClassAdValue creates a ClassAd value.
func NewUndefinedValue ¶
func NewUndefinedValue() Value
NewUndefinedValue creates an undefined value.
func Sum ¶ added in v0.6.0
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) ClassAdValue ¶
ClassAdValue returns the ClassAd value. Returns error if not a ClassAd.
func (Value) IsUndefined ¶
IsUndefined returns true if the value is undefined.
func (Value) NumberValue ¶
NumberValue returns the numeric value as a float64, converting integers if needed.
func (Value) StringValue ¶
StringValue returns the string value. Returns error if not a string.
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 )