HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
variableExpression.h
Go to the documentation of this file.
1 //
2 // Copyright 2023 Pixar
3 //
4 // Licensed under the terms set forth in the LICENSE.txt file available at
5 // https://openusd.org/license.
6 //
7 #ifndef PXR_USD_SDF_VARIABLE_EXPRESSION
8 #define PXR_USD_SDF_VARIABLE_EXPRESSION
9 
10 /// \file sdf/variableExpression.h
11 
12 #include "pxr/pxr.h"
13 #include "pxr/usd/sdf/api.h"
14 
15 #include "pxr/base/vt/array.h"
16 #include "pxr/base/vt/dictionary.h"
17 #include "pxr/base/vt/value.h"
18 
19 #include <memory>
20 #include <string>
21 #include <unordered_set>
22 #include <vector>
23 
25 
26 namespace Sdf_VariableExpressionImpl {
27  class Node;
28 }
29 
30 /// \class SdfVariableExpression
31 ///
32 /// Class responsible for parsing and evaluating variable expressions.
33 ///
34 /// Variable expressions are written in a custom language and
35 /// represented in scene description as a string surrounded by backticks (`).
36 /// These expressions may refer to "expression variables", which are key-value
37 /// pairs provided by clients. For example, when evaluating an expression like:
38 ///
39 /// \code
40 /// `"a_${NAME}_string"`
41 /// \endcode
42 ///
43 /// The "${NAME}" portion of the string with the value of expression variable
44 /// "NAME".
45 ///
46 /// Expression variables may be any of these supported types:
47 ///
48 /// - std::string
49 /// - int64_t (int is accepted but coerced to int64_t)
50 /// - bool
51 /// - VtArrays containing any of the above types.
52 /// - None (represented by an empty VtValue)
53 ///
54 /// Expression variables are typically authored in scene description as layer
55 /// metadata under the 'expressionVariables' field. Higher levels of the system
56 /// (e.g., composition) are responsible for examining fields that support
57 /// variable expressions, evaluating them with the appropriate variables (via
58 /// this class) and consuming the results.
59 ///
60 /// See \ref Sdf_Page_VariableExpressions "Variable Expressions"
61 /// or more information on the expression language and areas of the system
62 /// where expressions may be used.
64 {
65 public:
66  /// Construct using the expression \p expr. If the expression cannot be
67  /// parsed, this object represents an invalid expression. Parsing errors
68  /// will be accessible via GetErrors.
69  SDF_API
70  explicit SdfVariableExpression(const std::string& expr);
71 
72  /// Construct an object representing an invalid expression.
73  SDF_API
75 
76  SDF_API
78 
79  /// Returns true if \p s is a variable expression, false otherwise.
80  /// A variable expression is a string surrounded by backticks (`).
81  ///
82  /// A return value of true does not guarantee that \p s is a valid
83  /// expression. This function is meant to be used as an initial check
84  /// to determine if a string should be considered as an expression.
85  SDF_API
86  static bool IsExpression(const std::string& s);
87 
88  /// Returns true if \p value holds a type that is supported by
89  /// variable expressions, false otherwise. If this function returns
90  /// true, \p value may be used for an expression variable supplied to
91  /// the Evaluate function. \p value may also be authored into the
92  /// 'expressionVariables' dictionary, unless it is an empty VtValue
93  /// representing the None value. See class documentation for list of
94  /// supported types.
95  SDF_API
96  static bool IsValidVariableType(const VtValue& value);
97 
98  /// Returns true if this object represents a valid expression, false
99  /// if it represents an invalid expression.
100  ///
101  /// A return value of true does not mean that evaluation of this
102  /// expression is guaranteed to succeed. For example, an expression may
103  /// refer to a variable whose value is an invalid expression.
104  /// Errors like this can only be discovered by calling Evaluate.
105  SDF_API
106  explicit operator bool() const;
107 
108  /// Returns the expression string used to construct this object.
109  SDF_API
110  const std::string& GetString() const;
111 
112  /// Returns a list of errors encountered when parsing this expression.
113  ///
114  /// If the expression was parsed successfully, this list will be empty.
115  /// However, additional errors may be encountered when evaluating the e
116  /// expression.
117  SDF_API
118  const std::vector<std::string>& GetErrors() const;
119 
120  /// \class EmptyList
121  /// A result value representing an empty list.
122  class EmptyList { };
123 
124  /// \class Result
125  class Result
126  {
127  public:
128  /// The result of evaluating the expression. This value may be
129  /// empty if the expression yielded no value. It may also be empty
130  /// if errors occurred during evaluation. In this case, the errors
131  /// field will be populated with error messages.
132  ///
133  /// If the value is not empty, it will contain one of the supported
134  /// types listed in the class documentation.
136 
137  /// Errors encountered while evaluating the expression.
138  std::vector<std::string> errors;
139 
140  /// Set of variables that were used while evaluating
141  /// the expression. For example, for an expression like
142  /// `"example_${VAR}_expression"`, this set will contain "VAR".
143  ///
144  /// This set will also contain variables from subexpressions.
145  /// In the above example, if the value of "VAR" was another
146  /// expression like `"sub_${SUBVAR}_expression"`, this set will
147  /// contain both "VAR" and "SUBVAR".
148  std::unordered_set<std::string> usedVariables;
149  };
150 
151  /// Evaluates this expression using the variables in
152  /// \p variables and returns a Result object with the final
153  /// value. If an error occurs during evaluation, the value field
154  /// in the Result object will be an empty VtValue and error messages
155  /// will be added to the errors field.
156  ///
157  /// If the expression evaluates to an empty list, the value field
158  /// in the Result object will contain an EmptyList object instead
159  /// of an empty VtArray<T>, as the expression language does not
160  /// provide syntax for specifying the expected element types in
161  /// an empty list.
162  ///
163  /// If this object represents an invalid expression, calling this
164  /// function will return a Result object with an empty value and the
165  /// errors from GetErrors().
166  ///
167  /// If any values in \p variables used by this expression
168  /// are themselves expressions, they will be parsed and evaluated.
169  /// If an error occurs while evaluating any of these subexpressions,
170  /// evaluation of this expression fails and the encountered errors
171  /// will be added in the Result's list of errors.
172  SDF_API
173  Result Evaluate(const VtDictionary& variables) const;
174 
175  /// Evaluates this expression using the variables in
176  /// \p variables and returns a Result object with the final
177  /// value.
178  ///
179  /// This is a convenience function that calls Evaluate and ensures that
180  /// the value in the Result object is either an empty VtValue or is
181  /// holding the specified ResultType. If this is not the case, the
182  /// Result value will be set to an empty VtValue an error message
183  /// indicating the unexpected type will be added to the Result's error
184  /// list. Otherwise, the Result will be returned as-is.
185  ///
186  /// If the expression evaluates to an empty list and the ResultType
187  /// is a VtArray<T>, the value in the Result object will be an empty
188  /// VtArray<T>. This differs from Evaluate, which would return an
189  /// untyped EmptyList object instead.
190  ///
191  /// ResultType must be one of the supported types listed in the
192  /// class documentation.
193  template <class ResultType>
194  Result EvaluateTyped(const VtDictionary& variables) const
195  {
196  Result r = Evaluate(variables);
197 
199  r.value = VtValue(ResultType());
200  }
201  else if (!r.value.IsEmpty() && !r.value.IsHolding<ResultType>()) {
202  r.errors.push_back(
203  _FormatUnexpectedTypeError(r.value, VtValue(ResultType())));
204  r.value = VtValue();
205  }
206  return r;
207  }
208 
209 private:
210  SDF_API
211  static std::string
212  _FormatUnexpectedTypeError(const VtValue& got, const VtValue& expected);
213 
214  std::vector<std::string> _errors;
215  std::shared_ptr<Sdf_VariableExpressionImpl::Node> _expression;
216  std::string _expressionStr;
217 };
218 
219 inline bool
223 {
224  return true;
225 }
226 
227 inline bool
231 {
232  return false;
233 }
234 
236 
237 #endif
SDF_API SdfVariableExpression()
Construct an object representing an invalid expression.
SDF_API Result Evaluate(const VtDictionary &variables) const
Definition: Node.h:52
std::unordered_set< std::string > usedVariables
SDF_API ~SdfVariableExpression()
static SDF_API bool IsExpression(const std::string &s)
GLsizei const GLfloat * value
Definition: glcorearb.h:824
GLdouble s
Definition: glad.h:3009
bool IsEmpty() const
Returns true iff this value is empty.
Definition: value.h:1285
OutGridT const XformOp bool bool
SDF_API const std::vector< std::string > & GetErrors() const
bool operator!=(const Mat3< T0 > &m0, const Mat3< T1 > &m1)
Inequality operator, does exact floating point comparisons.
Definition: Mat3.h:556
static SDF_API bool IsValidVariableType(const VtValue &value)
Array concept. By default, types are not arrays.
Definition: traits.h:22
#define SDF_API
Definition: api.h:23
std::vector< std::string > errors
Errors encountered while evaluating the expression.
PXR_NAMESPACE_CLOSE_SCOPE PXR_NAMESPACE_OPEN_SCOPE
Definition: path.h:1425
bool IsHolding() const
Definition: value.h:1064
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74
GLboolean r
Definition: glcorearb.h:1222
SDF_API const std::string & GetString() const
Returns the expression string used to construct this object.
Definition: value.h:146
bool operator==(const Mat3< T0 > &m0, const Mat3< T1 > &m1)
Equality operator, does exact floating point comparisons.
Definition: Mat3.h:542
Result EvaluateTyped(const VtDictionary &variables) const