5 * Created by Alyssa Milburn on Tue May 25 2004.
6 * Copyright (c) 2004 Alyssa Milburn. All rights reserved.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
30 #include <boost/variant.hpp>
31 #include <boost/weak_ptr.hpp>
32 using boost::weak_ptr
;
37 //#define CAOSDEBUGDETAIL
40 unsigned int calculateScriptId(unsigned int message_id
);
46 class badParamException
: public caosException
{
48 badParamException() : caosException("parameter type mismatch") {}
53 struct visit_dump
: public boost::static_visitor
<std::string
> {
54 std::string
operator()(const caosVar
&i
) const {
58 std::string
operator()(caosVar
*i
) const {
59 return std::string("ptr ") + i
->dump();
62 std::string
operator()(const bytestring_t
&bs
) const {
63 std::ostringstream oss
;
65 for (bytestring_t::const_iterator i
= bs
.begin(); i
!= bs
.end(); i
++) {
66 oss
<< (int)*i
<< " ";
73 struct visit_lval
: public boost::static_visitor
<const caosVar
&> {
75 const caosVar
&operator()(const caosVar
&i
) const {
79 const caosVar
&operator()(caosVar
*i
) const {
83 const caosVar
&operator()(const bytestring_t
&) const {
84 throw badParamException();
89 struct visit_bs
: public boost::static_visitor
<bytestring_t
> {
90 bytestring_t
operator()(const bytestring_t
&i
) const {
93 bytestring_t
operator()(caosVar
*i
) const {
94 throw badParamException();
96 bytestring_t
operator()(const caosVar
&i
) const {
97 throw badParamException();
101 boost::variant
<caosVar
, bytestring_t
> value
;
105 vmStackItem(const caosVar
&v
) {
109 vmStackItem(bytestring_t bs
) {
113 vmStackItem(const vmStackItem
&orig
) {
117 const caosVar
&getRVal() const {
119 return boost::apply_visitor(visit_lval(), value
);
120 } catch (boost::bad_visit
&e
) {
121 throw badParamException();
125 bytestring_t
getByteStr() const {
127 return boost::apply_visitor(visit_bs(), value
);
128 } catch (boost::bad_visit
&e
) {
129 throw badParamException();
133 std::string
dump() const {
135 return boost::apply_visitor(visit_dump(), value
);
136 } catch (boost::bad_visit
&e
) {
137 return std::string("ERR::bad_visit");
142 struct callStackItem
{
143 std::vector
<vmStackItem
> valueStack
;
147 typedef class caosVM
*caosVM_p
;
150 // XXX NOT SERIALIZABLE FIXME
152 virtual bool operator()() = 0;
153 virtual ~blockCond() {}
162 void startBlocking(blockCond
*whileWhat
);
165 // nb, ptr is immutable, class is mutable
166 // This is so the stack manipulation macros work in the op classes as well
167 const caosVM_p vm
; // == this
170 shared_ptr
<script
> currentscript
;
171 int nip
, cip
, runops
;
173 bool inst
, lock
, stop_loop
;
176 std::vector
<vmStackItem
> valueStack
;
177 std::vector
<vmStackItem
> auxStack
;
178 std::vector
<callStackItem
> callStack
;
180 std::istream
*inputstream
;
181 std::ostream
*outputstream
;
183 // ...which includes variables accessible to script
184 caosVar var
[100]; // might want to make this a map, for memory efficiency
185 caosVar _p_
[2]; // might want to add this onto the end of above map, if done
186 AgentRef targ
, owner
, _it_
;
189 weak_ptr
<class Camera
> camera
;
190 class Camera
*getCamera();
192 void resetScriptState(); // resets everything except OWNR
201 void setTarg(const AgentRef
&a
) { targ
= a
; }
202 void setVariables(caosVar
&one
, caosVar
&two
) { _p_
[0] = one
; _p_
[1] = two
; }
203 void setOwner(Agent
*a
) { owner
= a
; }
204 void setOutputStream(std::ostream
&o
) { outputstream
= &o
; }
206 class CreatureAgent
*getTargCreatureAgent();
207 class Creature
*getTargCreature();
208 class SpritePart
*getCurrentSpritePart();
209 class AnimatablePart
*getCurrentAnimatablePart();
348 void c_SCRP(); // dummy
349 void c_RSCR(); // dummy
350 void c_ISCR(); // dummy
479 void c_NEW_COMP_c1();
481 void c_NEW_SIMP_c2();
483 void c_NEW_VHCL_c1();
704 void c_STIM_FROM_c1();
705 void c_STIM_SHOU_c2();
706 void c_STIM_SIGN_c2();
707 void c_STIM_TACT_c2();
708 void c_STIM_WRIT_c2();
741 void v_FACE_STRING();
757 void c_NEW_CREA_c1();
758 void c_NEW_CREA_c2();
810 // (attachment locations)
1040 // serialization test functions
1046 void safeJMP(int nip
);
1047 void invoke_cmd(script
*s
, bool is_saver
, int opidx
);
1048 void runOpCore(script
*s
, struct caosOp op
);
1050 void runEntirely(shared_ptr
<script
> s
);
1054 bool fireScript(shared_ptr
<script
> s
, bool nointerrupt
, Agent
*frm
= 0);
1056 caosVM(const AgentRef
&o
);
1059 bool stopped() { return !currentscript
; }
1061 friend void setupCommandPointers();
1064 typedef void (caosVM::*caosVMmethod
)();
1066 class notEnoughParamsException
: public caosException
{
1068 notEnoughParamsException() : caosException("Not enough parameters") {}
1071 class invalidAgentException
: public caosException
{
1073 invalidAgentException() : caosException("Invalid agent handle") {}
1074 invalidAgentException(const char *s
) : caosException(s
) {}
1075 invalidAgentException(const std::string
&s
) : caosException(s
) {}
1078 #define VM_VERIFY_SIZE(n) // no-op, we assert in the pops. orig: if (params.size() != n) { throw notEnoughParamsException(); }
1079 static inline void VM_STACK_CHECK(const caosVM
*vm
) {
1080 if (!vm
->valueStack
.size())
1081 throw notEnoughParamsException();
1084 class caosVM__lval
{
1089 caosVM__lval(caosVM
*vm
) : owner(vm
) {
1091 value
= owner
->valueStack
.back().getRVal();
1092 owner
->valueStack
.pop_back();
1095 owner
->valueStack
.push_back(value
);
1099 #define VM_PARAM_VALUE(name) caosVar name; { VM_STACK_CHECK(vm); \
1100 vmStackItem __x = vm->valueStack.back(); \
1101 name = __x.getRVal(); } vm->valueStack.pop_back();
1102 #define VM_PARAM_STRING(name) std::string name; { VM_STACK_CHECK(vm); vmStackItem __x = vm->valueStack.back(); \
1103 name = __x.getRVal().getString(); } vm->valueStack.pop_back();
1104 #define VM_PARAM_INTEGER(name) int name; { VM_STACK_CHECK(vm); vmStackItem __x = vm->valueStack.back(); \
1105 name = __x.getRVal().getInt(); } vm->valueStack.pop_back();
1106 #define VM_PARAM_FLOAT(name) float name; { VM_STACK_CHECK(vm); vmStackItem __x = vm->valueStack.back(); \
1107 name = __x.getRVal().getFloat(); } vm->valueStack.pop_back();
1108 #define VM_PARAM_VECTOR(name) Vector<float> name; { VM_STACK_CHECK(vm); vmStackItem __x = vm->valueStack.back(); \
1109 name = __x.getRVal().getVector(); } vm->valueStack.pop_back();
1110 #define VM_PARAM_AGENT(name) boost::shared_ptr<Agent> name; { VM_STACK_CHECK(vm); vmStackItem __x = vm->valueStack.back(); \
1111 name = __x.getRVal().getAgent(); } vm->valueStack.pop_back();
1112 // TODO: is usage of valid_agent correct here, or should we be caos_asserting?
1113 #define VM_PARAM_VALIDAGENT(name) VM_PARAM_AGENT(name) valid_agent(name);
1114 #define VM_PARAM_VARIABLE(name) caosVM__lval vm__lval_##name(this); caosVar * const name = &vm__lval_##name.value;
1115 #define VM_PARAM_DECIMAL(name) caosVar name; { VM_STACK_CHECK(vm); vmStackItem __x = vm->valueStack.back(); \
1116 name = __x.getRVal(); } vm->valueStack.pop_back();
1117 #define VM_PARAM_BYTESTR(name) bytestring_t name; { \
1118 VM_STACK_CHECK(vm); \
1119 vmStackItem __x = vm->valueStack.back(); \
1120 name = __x.getByteStr(); } vm->valueStack.pop_back();
1122 #define CAOS_LVALUE(name, check, get, set) \
1123 void caosVM::v_##name() { \
1125 valueStack.push_back((get)); \
1127 void caosVM::s_##name() { \
1129 VM_PARAM_VALUE(newvalue) \
1133 #define CAOS_LVALUE_WITH(name, agent, check, get, set) \
1134 CAOS_LVALUE(name, valid_agent(agent); check, get, set)
1136 #define CAOS_LVALUE_TARG(name, check, get, set) \
1137 CAOS_LVALUE_WITH(name, targ, check, get, set)
1139 #define CAOS_LVALUE_WITH_SIMPLE(name, agent, exp) \
1140 CAOS_LVALUE(name, valid_agent(agent), exp, exp = newvalue)
1142 #define CAOS_LVALUE_SIMPLE(name, exp) \
1143 CAOS_LVALUE(name, (void)0, exp, exp = newvalue)
1145 #define CAOS_LVALUE_TARG_SIMPLE(name, exp) \
1146 CAOS_LVALUE_TARG(name, (void)0, exp, exp = newvalue)
1147 #define STUB throw caosException("stub in " __FILE__)
1149 // FIXME: use do { ... } while (0)
1150 #define valid_agent(x) do { if (!(x)) throw invalidAgentException(boost::str(boost::format("Invalid agent handle: %s thrown from %s:%d") % #x % __FILE__ % __LINE__)); } while(0)
1153 /* vim: set noet: */