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 Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 // names, trademarks, service marks, or product names of the Licensor
11 // and its affiliates, except as required to comply with Section 4(c) of
12 // the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 // http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 #ifndef PXR_USD_SDF_VARIABLE_EXPRESSION
25 #define PXR_USD_SDF_VARIABLE_EXPRESSION
26 
27 /// \file sdf/variableExpression.h
28 
29 #include "pxr/pxr.h"
30 #include "pxr/usd/sdf/api.h"
31 
32 #include "pxr/base/vt/array.h"
33 #include "pxr/base/vt/dictionary.h"
34 #include "pxr/base/vt/value.h"
35 
36 #include <memory>
37 #include <string>
38 #include <unordered_set>
39 #include <vector>
40 
42 
43 namespace Sdf_VariableExpressionImpl {
44  class Node;
45 }
46 
47 /// \class SdfVariableExpression
48 ///
49 /// Class responsible for parsing and evaluating variable expressions.
50 ///
51 /// Variable expressions are written in a custom language and
52 /// represented in scene description as a string surrounded by backticks (`).
53 /// These expressions may refer to "expression variables", which are key-value
54 /// pairs provided by clients. For example, when evaluating an expression like:
55 ///
56 /// \code
57 /// `"a_${NAME}_string"`
58 /// \endcode
59 ///
60 /// The "${NAME}" portion of the string with the value of expression variable
61 /// "NAME".
62 ///
63 /// Expression variables may be any of these supported types:
64 ///
65 /// - std::string
66 /// - int64_t (int is accepted but coerced to int64_t)
67 /// - bool
68 /// - VtArrays containing any of the above types.
69 /// - None (represented by an empty VtValue)
70 ///
71 /// Expression variables are typically authored in scene description as layer
72 /// metadata under the 'expressionVariables' field. Higher levels of the system
73 /// (e.g., composition) are responsible for examining fields that support
74 /// variable expressions, evaluating them with the appropriate variables (via
75 /// this class) and consuming the results.
76 ///
77 /// See \ref Sdf_Page_VariableExpressions "Variable Expressions"
78 /// or more information on the expression language and areas of the system
79 /// where expressions may be used.
81 {
82 public:
83  /// Construct using the expression \p expr. If the expression cannot be
84  /// parsed, this object represents an invalid expression. Parsing errors
85  /// will be accessible via GetErrors.
86  SDF_API
87  explicit SdfVariableExpression(const std::string& expr);
88 
89  /// Construct an object representing an invalid expression.
90  SDF_API
92 
93  SDF_API
95 
96  /// Returns true if \p s is a variable expression, false otherwise.
97  /// A variable expression is a string surrounded by backticks (`).
98  ///
99  /// A return value of true does not guarantee that \p s is a valid
100  /// expression. This function is meant to be used as an initial check
101  /// to determine if a string should be considered as an expression.
102  SDF_API
103  static bool IsExpression(const std::string& s);
104 
105  /// Returns true if \p value holds a type that is supported by
106  /// variable expressions, false otherwise. If this function returns
107  /// true, \p value may be used for an expression variable supplied to
108  /// the Evaluate function. \p value may also be authored into the
109  /// 'expressionVariables' dictionary, unless it is an empty VtValue
110  /// representing the None value. See class documentation for list of
111  /// supported types.
112  SDF_API
113  static bool IsValidVariableType(const VtValue& value);
114 
115  /// Returns true if this object represents a valid expression, false
116  /// if it represents an invalid expression.
117  ///
118  /// A return value of true does not mean that evaluation of this
119  /// expression is guaranteed to succeed. For example, an expression may
120  /// refer to a variable whose value is an invalid expression.
121  /// Errors like this can only be discovered by calling Evaluate.
122  SDF_API
123  explicit operator bool() const;
124 
125  /// Returns the expression string used to construct this object.
126  SDF_API
127  const std::string& GetString() const;
128 
129  /// Returns a list of errors encountered when parsing this expression.
130  ///
131  /// If the expression was parsed successfully, this list will be empty.
132  /// However, additional errors may be encountered when evaluating the e
133  /// expression.
134  SDF_API
135  const std::vector<std::string>& GetErrors() const;
136 
137  /// \class EmptyList
138  /// A result value representing an empty list.
139  class EmptyList { };
140 
141  /// \class Result
142  class Result
143  {
144  public:
145  /// The result of evaluating the expression. This value may be
146  /// empty if the expression yielded no value. It may also be empty
147  /// if errors occurred during evaluation. In this case, the errors
148  /// field will be populated with error messages.
149  ///
150  /// If the value is not empty, it will contain one of the supported
151  /// types listed in the class documentation.
153 
154  /// Errors encountered while evaluating the expression.
155  std::vector<std::string> errors;
156 
157  /// Set of variables that were used while evaluating
158  /// the expression. For example, for an expression like
159  /// `"example_${VAR}_expression"`, this set will contain "VAR".
160  ///
161  /// This set will also contain variables from subexpressions.
162  /// In the above example, if the value of "VAR" was another
163  /// expression like `"sub_${SUBVAR}_expression"`, this set will
164  /// contain both "VAR" and "SUBVAR".
165  std::unordered_set<std::string> usedVariables;
166  };
167 
168  /// Evaluates this expression using the variables in
169  /// \p variables and returns a Result object with the final
170  /// value. If an error occurs during evaluation, the value field
171  /// in the Result object will be an empty VtValue and error messages
172  /// will be added to the errors field.
173  ///
174  /// If the expression evaluates to an empty list, the value field
175  /// in the Result object will contain an EmptyList object instead
176  /// of an empty VtArray<T>, as the expression language does not
177  /// provide syntax for specifying the expected element types in
178  /// an empty list.
179  ///
180  /// If this object represents an invalid expression, calling this
181  /// function will return a Result object with an empty value and the
182  /// errors from GetErrors().
183  ///
184  /// If any values in \p variables used by this expression
185  /// are themselves expressions, they will be parsed and evaluated.
186  /// If an error occurs while evaluating any of these subexpressions,
187  /// evaluation of this expression fails and the encountered errors
188  /// will be added in the Result's list of errors.
189  SDF_API
190  Result Evaluate(const VtDictionary& variables) const;
191 
192  /// Evaluates this expression using the variables in
193  /// \p variables and returns a Result object with the final
194  /// value.
195  ///
196  /// This is a convenience function that calls Evaluate and ensures that
197  /// the value in the Result object is either an empty VtValue or is
198  /// holding the specified ResultType. If this is not the case, the
199  /// Result value will be set to an empty VtValue an error message
200  /// indicating the unexpected type will be added to the Result's error
201  /// list. Otherwise, the Result will be returned as-is.
202  ///
203  /// If the expression evaluates to an empty list and the ResultType
204  /// is a VtArray<T>, the value in the Result object will be an empty
205  /// VtArray<T>. This differs from Evaluate, which would return an
206  /// untyped EmptyList object instead.
207  ///
208  /// ResultType must be one of the supported types listed in the
209  /// class documentation.
210  template <class ResultType>
211  Result EvaluateTyped(const VtDictionary& variables) const
212  {
213  Result r = Evaluate(variables);
214 
216  r.value = VtValue(ResultType());
217  }
218  else if (!r.value.IsEmpty() && !r.value.IsHolding<ResultType>()) {
219  r.errors.push_back(
220  _FormatUnexpectedTypeError(r.value, VtValue(ResultType())));
221  r.value = VtValue();
222  }
223  return r;
224  }
225 
226 private:
227  SDF_API
228  static std::string
229  _FormatUnexpectedTypeError(const VtValue& got, const VtValue& expected);
230 
231  std::vector<std::string> _errors;
232  std::shared_ptr<Sdf_VariableExpressionImpl::Node> _expression;
233  std::string _expressionStr;
234 };
235 
236 inline bool
240 {
241  return true;
242 }
243 
244 inline bool
248 {
249  return false;
250 }
251 
253 
254 #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 GLchar *const * string
Definition: glcorearb.h:814
GLdouble s
Definition: glad.h:3009
bool IsEmpty() const
Returns true iff this value is empty.
Definition: value.h:1300
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:39
#define SDF_API
Definition: api.h:40
std::vector< std::string > errors
Errors encountered while evaluating the expression.
PXR_NAMESPACE_CLOSE_SCOPE PXR_NAMESPACE_OPEN_SCOPE
Definition: path.h:1432
bool IsHolding() const
Definition: value.h:1081
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:91
Definition: core.h:1131
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:164
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