1 module as.context;
2 import as.def;
3 import as.engine;
4 import as.func;
5 
6 enum ContextState : asEContextState {
7 	Finished = asEContextState.asEXECUTION_FINISHED,
8 	Suspended = asEContextState.asEXECUTION_SUSPENDED,
9 	Aborted = asEContextState.asEXECUTION_ABORTED,
10 	Exception = asEContextState.asEXECUTION_EXCEPTION,
11 	Prepared = asEContextState.asEXECUTION_PREPARED,
12 	Uninitialized = asEContextState.asEXECUTION_UNINITIALIZED,
13 	Active = asEContextState.asEXECUTION_ACTIVE,
14 	Error = asEContextState.asEXECUTION_ERROR
15 }
16 
17 /**
18     A script execution context
19 */
20 class ScriptContext {
21 private:
22     ScriptEngine engine;
23 
24     ~this() {
25         // Make sure we don't try to destroy the engine
26         this.engine = null;
27 
28         // Release the context
29         asContext_Release(ctx);
30     }
31 
32 package(as):
33     asIScriptContext* ctx;
34     
35     this(ScriptEngine engine, asIScriptContext* ctx) {
36         this.engine = engine;
37         this.ctx = ctx;
38     }
39 
40 public:
41     /**
42         Adds a reference to this script context
43     */
44     int addRef() {
45         return asContext_AddRef(ctx);
46     }
47 
48     /**
49         Releases a reference to this script context
50     */
51     int release() {
52         return asContext_Release(ctx);
53     }
54 
55     /**
56         Gets the script engine this context belongs to
57     */
58     ScriptEngine getEngine() {
59         return engine;
60     }
61 
62     /**
63         Prepares this context
64     */
65     void prepare(Function func) {
66         int err = asContext_Prepare(ctx, func.func);
67         assert(err != asERetCodes.asCONTEXT_ACTIVE, "The context is still active or suspended");
68         assert(err != asERetCodes.asNO_FUNCTION, "Function pointer is null");
69         assert(err != asERetCodes.asINVALID_ARG, "Function is from a different engine than context");
70         assert(err != asERetCodes.asOUT_OF_MEMORY, "Context ran out of memory while allocating call stack");
71     }
72 
73     /**
74         Un-prepares this context
75     */
76     void unprepare() {
77         int err = asContext_Unprepare(ctx);
78         assert(err != asERetCodes.asCONTEXT_ACTIVE, "The context is still active or suspended");
79     }
80 
81     /**
82         Executes this context
83     */
84     ContextState execute() {
85         int err = asContext_Execute(ctx);
86         assert(err != asERetCodes.asCONTEXT_NOT_PREPARED, "The context is still active or not suspended");
87         return cast(ContextState)err;
88     }
89 
90     /**
91         Aborts this context
92     */
93     void abort() {
94         int err = asContext_Abort(ctx);
95         assert(err != asERetCodes.asERROR, "Invalid context");
96     }
97 
98     /**
99         Suspends this context
100     */
101     void suspend() {
102        int err = asContext_Suspend(ctx);
103         assert(err != asERetCodes.asERROR, "Invalid context");
104     }
105 
106     /**
107         Gets the current state of the context
108     */
109     ContextState getState() {
110         return cast(ContextState)asContext_GetState(ctx);
111     }
112 
113     /**
114         Backups current state and prepares state for a nested call
115     */
116     void pushState() {
117         int err = asContext_PushState(ctx);
118         assert(err != asERetCodes.asERROR, "Context not active");
119         assert(err != asERetCodes.asOUT_OF_MEMORY, "Could not allocate memory for state");
120     }
121 
122     /**
123         Restores previous execution state
124     */
125     void popState() {
126         int err = asContext_PopState(ctx);
127         assert(err != asERetCodes.asERROR, "Could not restore state");
128     }
129 
130     /**
131         Gets whether the context has any nested calls
132     */
133     bool isNested(ref uint nestCount) {
134         return asContext_IsNested(ctx, &nestCount);
135     }
136 
137     /**
138         Sets object for class method call
139     */
140     void setObject(void* obj) {
141         asContext_SetObject(ctx, obj);
142     }
143 
144     /**
145         Sets a base type argument
146 
147         Notes:
148         To set object argument values, use setArgObject
149         To set variable arguments, use setArgVarType
150     */
151     void setArg(T)(asUINT arg, T value) {
152         static if (isPointer!T) {
153             int err = asContext_SetArgAddress(ctx, arg, value);
154         } else static if (T.sizeof == 1) {
155             int err = asContext_SetArgByte(ctx, arg, cast(ubyte)value);
156         } else static if (T.sizeof == 2) {
157             int err = asContext_SetArgWord(ctx, arg, cast(asWORD)value);
158         } else static if (T.sizeof == 4) {
159             int err = asContext_SetArgDWord(ctx, arg, cast(asDWORD)value);
160         } else static if (T.sizeof == 8) {
161             int err = asContext_SetArgQWord(ctx, arg, cast(asQWORD)value);
162         } else static if (is(T : float)) {
163             int err = asContext_SetArgFloat(ctx, arg, value);
164         } else static if (is(T : double)) {
165             int err = asContext_SetArgDouble(ctx, arg, value);
166         } else {
167             assert(0, "Type not supported by setArg");
168         }
169         assert(err != asERetCodes.asCONTEXT_NOT_PREPARED, "The context is not in a prepared state");
170         assert(err != asERetCodes.asINVALID_ARG, "Argument is outside function argument bounds");
171         assert(err != asERetCodes.asINVALID_TYPE, "Value type does not fit argument type");
172     }
173 
174     /**
175         Sets object/handle argument value
176     */
177     void setArgObject(asUINT arg, void* value) {
178         int err = asContext_SetArgObject(ctx, arg, value);
179         assert(err != asERetCodes.asCONTEXT_NOT_PREPARED, "The context is not in a prepared state");
180         assert(err != asERetCodes.asINVALID_ARG, "Argument is outside function argument bounds");
181         assert(err != asERetCodes.asINVALID_TYPE, "Argument is not a object or handle");
182     }
183 
184     /**
185         Sets the variable argument value and type
186     */
187     void setArgVarType(T)(asUINT arg, T* ptr, int typeId) {
188         int err = asContext_SetArgVarType(ctx, arg, ptr, typeId);
189         assert(err != asERetCodes.asCONTEXT_NOT_PREPARED, "The context is not in a prepared state");
190         assert(err != asERetCodes.asINVALID_ARG, "Argument is outside function argument bounds");
191         assert(err != asERetCodes.asINVALID_TYPE, "Argument is not a variable type");
192     }
193 
194     /**
195         Gets the address of an argument
196     */
197     void* getAddressOfArg(asUINT arg) {
198         return asContext_GetAddressOfArg(ctx, arg);
199     }
200 
201     /**
202         Gets the size of the callstack
203     */
204     asUINT getCallstackSize() {
205         return asContext_GetCallstackSize(ctx);
206     }
207 
208     /**
209         Gets the line number based on stackLevel which the context is currently executing
210     */
211     int getLineNumber(asUINT stackLevel = 0) {
212         return getLineNumber(stackLevel, null);
213     }
214     
215     /**
216         Gets the line number, column and sectino name based on stackLevel which the context is currently executing
217     */
218     int getLineNumber(asUINT stackLevel, int* column) {
219         
220         // Get the line number and extra stuff
221         int ln = asContext_GetLineNumber(ctx, stackLevel, column, null);
222         return ln;
223     }
224 
225     /**
226         Sets the user data
227     */
228     void* setUserData(void* data) {
229         return asContext_SetUserData(ctx, data);
230     }
231 
232     /**
233         Gets the user data
234     */
235     void* getUserData() {
236         return asContext_GetUserData(ctx);
237     }
238 }