HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PY_CompiledCode.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * COMMENTS:
7  * This class represents a compiled piece of python code that
8  * can be evaluated.
9  */
10 
11 #ifndef __PY_CompiledCode_h__
12 #define __PY_CompiledCode_h__
13 
14 #include "PY_API.h"
15 #include "PY_Result.h"
16 #include "PY_InterpreterAutoLock.h"
17 #include "PY_EvaluationContext.h"
18 #include <UT/UT_Array.h>
19 #include <UT/UT_NonCopyable.h>
20 #include <UT/UT_String.h>
21 #include <iosfwd>
22 class PY_EvaluationCache;
23 class UT_IStream;
24 
25 #define ALLOW_DIFFERENT_CONSTRUCTOR_AND_EVAL_THREADS
26 
28 {
29 public:
30  enum CodeType { STATEMENTS, EXPRESSION };
31 
32  // Python code can be compiled as either an expression or a (list of)
33  // statements. Statements do not return anything -- even if the last
34  // statement is an expression, evaluating code as statements will never
35  // return a value. See the compile() python builtin for more information;
36  // expressions correspond to 'eval' and statements correspond to 'exec'.
37  //
38  // The python code is compiled when this class is instanced. Check
39  // for syntax errors with hasSyntaxErrors() and syntaxErrors(). You
40  // can always access the code regardless of whether or not there were
41  // syntax errors.
42  //
43  // as_file is the file name used when reporting syntax errors.
44  //
45  // If allow_function_bodies is true, code_type is EXPRESSION, and the
46  // Python code contains multiple lines, it will be interpreted as the
47  // body of a Python expression.
48  //
49  // NOTE: It's important to call the evaluate*() methods from the
50  // same thread from which this object is constructed.
52  const char *python_code,
53  CodeType code_type,
54  const char *as_file = NULL,
55  bool allow_function_bodies = false);
56 
57  // This constructor reads in compiled python code from a stream.
59  UT_IStream &is,
60  CodeType code_type);
61 
62  ~PY_CompiledCode();
63 
65 
66  // Normally this is called from PY_CompiledCode's constructor.
67  // If you create this class in one thread but then evaluate it from a
68  // different thread, then you need to call this from the other thread prior
69  // to evaluation in order to ensure that the correct evaluation cache stack
70  // is used.
71  void setEvaluationCacheStackForCurrentThread();
72 
73  // This can't get the size of any compiled code object from
74  // Python, but can still count this, its strings, and its
75  // evaluation cache.
76  int64 getMemoryUsage(bool inclusive) const;
77 
78  // The syntax errors will be empty if there are none.
79  bool hasSyntaxErrors() const;
80  const UT_String &syntaxErrors() const;
81 
82  // Get the code that was compiled.
83  const UT_String &code() const;
84 
85  // Use marchalling to convert the compiled code object to a string.
86  // We use a UT_WorkBuffer because the returned string may have null
87  // characters in it.
88  void compiledCodeAsString(UT_WorkBuffer &result) const;
89 
90  // This method saves the compiled form of our code.
91  bool saveCompiledCode(std::ostream &os);
92 
93  // Evaluate the compiled python code. The desired result type really
94  // only has an effect if the compiled code is an expression.
95  //
96  // Evaluating code that had syntax errors will set the result type to
97  // PY_ResultType::ERR, with the string containing the syntax errors.
98  void evaluate(
99  PY_Result::Type desired_result_type, PY_Result &result) const;
100 
101  // Evaluate using a custom dictionary for both the global and local
102  // dictionary
103  void evaluateWithDict(
104  PY_Result::Type desired_result_type,
105  void* opaque_dict,
106  PY_Result &result) const
107  {
108  PY_InterpreterAutoLock auto_lock;
109  evaluateUsingDicts(desired_result_type,
110  opaque_dict, opaque_dict, result);
111  }
112 
113  // evaluateInContext() is the same as evaluate() except it uses the
114  // local and global dictionaries from the context passed to it. This
115  // way, any code run won't set variables in the __main__ module's global
116  // dictionary. It is inlined for speed.
118  PY_Result::Type desired_result_type,
119  PY_EvaluationContext &context,
120  PY_Result &result) const
121  {
122  PY_InterpreterAutoLock auto_lock;
123  evaluateUsingDicts(desired_result_type,
124  context.myOpaqueGlobalsDict, context.myOpaqueGlobalsDict, result);
125  }
126 
127  // Similar to the above, but an additional local variable dictionary can
128  // be passed in. This is used along with the global dictionary from the
129  // context.
131  PY_Result::Type desired_result_type,
132  PY_EvaluationContext &context,
133  void* opaque_locals_dict,
134  PY_Result &result) const
135  {
136  PY_InterpreterAutoLock auto_lock;
137  evaluateUsingDicts(desired_result_type,
138  context.myOpaqueGlobalsDict, opaque_locals_dict, result);
139  }
140 
141  // These convenience versions of evaluate() and evaluateInContext() return
142  // the PY_Result by value, instead of passing it in by reference.
143  // These versions can be used by code that isn't performance-critical.
144  PY_Result evaluate(PY_Result::Type desired_result_type) const
145  {
147  evaluate(desired_result_type, result);
148  return result;
149  }
150 
152  PY_Result::Type desired_result_type,
153  PY_EvaluationContext &context) const
154  {
156  evaluateInContext(desired_result_type, context, result);
157  return result;
158  }
159 
160  inline bool isPureCompiled()
161  {
162  return !myCode.isstring() && !mySyntaxErrors.isstring() && myOpaqueCodeObject;
163  }
164 
165  inline CodeType codeType() const
166  {
167  return myCodeType;
168  }
169 
170 private:
171 
172  void initializeThreadInfoAndEvalCache();
173 
174  PY_Result evaluateUsingDicts(
175  PY_Result::Type desired_result_type,
176  void *opaque_globals_dict,
177  void *opaque_locals_dict) const;
178  void evaluateUsingDicts(
179  PY_Result::Type desired_result_type,
180  void *opaque_globals_dict,
181  void *opaque_locals_dict,
182  PY_Result &result) const;
183 
184  int startInterruptableEvaluation() const;
185  void endInterruptableEvaluation(int id) const;
186 
187  void *myOpaqueCodeObject;
188  CodeType myCodeType;
189  UT_String myCode;
190  UT_String mySyntaxErrors;
191 
192 #ifndef ALLOW_DIFFERENT_CONSTRUCTOR_AND_EVAL_THREADS
193  UT_Array<PY_EvaluationCache *> *myEvaluationCacheStack;
194 #endif
195  mutable PY_EvaluationCache *myEvaluationCache;
196 };
197 
198 #endif
void evaluateInContext(PY_Result::Type desired_result_type, PY_EvaluationContext &context, void *opaque_locals_dict, PY_Result &result) const
CodeType codeType() const
void
Definition: png.h:1083
void evaluateInContext(PY_Result::Type desired_result_type, PY_EvaluationContext &context, PY_Result &result) const
**But if you need a result
Definition: thread.h:613
PY_Result evaluateInContext(PY_Result::Type desired_result_type, PY_EvaluationContext &context) const
#define UT_NON_COPYABLE(CLASS)
Define deleted copy constructor and assignment operator inside a class.
#define PY_API
Definition: PY_API.h:10
long long int64
Definition: SYS_Types.h:116
PY_Result evaluate(PY_Result::Type desired_result_type) const