/* Numbers.h - the Thunk family of classes - variable accessors for MAXScript * * Copyright (c) John Wainwright, 1996 * * */ #ifndef _H_THUNKS #define _H_THUNKS #include "Name.h" #include "Arrays.h" #include "Rollouts.h" #include "MouseTool.h" #include "UIExtend.h" /* ----------------------- Thunk ---------------------- */ visible_class (Thunk) class Thunk : public Value { public: Value* name; BOOL clear_container; // outer-level prop in a prop sequence, clear current_container when done classof_methods (Thunk, Value); # define is_thunk(o) ((o)->_is_thunk()) # define is_indirect_thunk(o) ((o)->_is_indirect_thunk()) BOOL _is_thunk() { return TRUE; } ScripterExport void gc_trace(); Thunk() : clear_container(FALSE), name(NULL) { } Thunk* to_thunk() {return this; } virtual Thunk* make_free_thunk(int level) { return NULL; } void assign(Value* val) { assign_vf(&val, 1); } ScripterExport Value* get_property(Value** arg_list, int count); ScripterExport Value* set_property(Value** arg_list, int count); }; /* -------------------- GlobalThunk ------------------- */ class GlobalThunk : public Thunk { public: Value* cell; ScripterExport GlobalThunk(Value* init_name) { init(init_name); } ScripterExport GlobalThunk(Value* init_name, Value* init_val); ScripterExport void init(Value* init_name); # define is_globalthunk(p) ((p)->tag == INTERNAL_GLOBAL_THUNK_TAG) ScripterExport Value* eval(); ScripterExport void gc_trace(); void collect() { delete this; } ScripterExport void sprin1(CharStream* s); Value* assign_vf(Value**arg_list, int count); }; class ConstGlobalThunk : public GlobalThunk { public: ConstGlobalThunk(Value* iname) : GlobalThunk(iname) { tag = INTERNAL_CONST_GLOBAL_THUNK_TAG; } ConstGlobalThunk(Value* iname, Value* ival) : GlobalThunk(iname, ival) { tag = INTERNAL_CONST_GLOBAL_THUNK_TAG; } # define is_constglobalthunk(p) ((p)->tag == INTERNAL_CONST_GLOBAL_THUNK_TAG) Value* eval() { return cell->is_const() ? cell->copy_vf(NULL, 0) : cell; } void collect() { delete this; } Value* assign_vf(Value**arg_list, int count) { throw AssignToConstError (this); return &undefined; } }; /* -------------------- SystemGlobalThunk ------------------- */ /* system globals are abstractions over some system state accessing functions, such as * animation_range, current_renderer,e tc. */ class SystemGlobalThunk : public Thunk { Value* (*get_fn)(); Value* (*set_fn)(Value*); public: ScripterExport SystemGlobalThunk(Value* init_name, Value* (*iget)(), Value* (*iset)(Value*)); // LAM 4/1/00 - added following to prevent AF in name clash debugging output in HashTable::put_new() # define is_systemglobalthunk(p) ((p)->tag == INTERNAL_SYS_GLOBAL_THUNK_TAG) ScripterExport Value* eval(); void collect() { delete this; } ScripterExport void sprin1(CharStream* s) { s->printf(_T("SystemGlobal:%s"), name->to_string()); } Value* assign_vf(Value**arg_list, int count); }; /* -------------------- LocalThunk ------------------- */ class LocalThunk : public Thunk { public: int frame_level; // frame nest level at declaration int index; // local var's index in local frame LocalThunk(Value* init_name, int init_index, int iframe_lvl); # define is_localthunk(p) ((p)->tag == INTERNAL_LOCAL_THUNK_TAG) Thunk* make_free_thunk(int level); Value* eval(); void collect() { delete this; } void sprin1(CharStream* s); Value* assign_vf(Value**arg_list, int count); }; class IndirectLocalThunk : public LocalThunk { public: IndirectLocalThunk(Value* init_name, int init_index, int iframe_lvl) : LocalThunk(init_name, init_index, iframe_lvl) { } BOOL _is_indirect_thunk() { return TRUE; } Thunk* make_free_thunk(int level); Value* eval(); void collect() { delete this; } void sprin1(CharStream* s) { s->printf(_T("&")); LocalThunk::sprin1(s); } Value* assign_vf(Value**arg_list, int count); }; // ContextThunk created from an IndirectLocal/FreeThunk on entry to a MAXScript function apply // to contain the callers frame context for evals and assigns class ContextThunk : public Thunk { public: Thunk* thunk; // the wrapped thunk Value** frame; // callers frame ENABLE_STACK_ALLOCATE(ContextLocalThunk); ContextThunk(Thunk* thunk, Value** frame) : thunk(thunk), frame(frame) { } void collect() { delete this; } void sprin1(CharStream* s) { s->printf(_T("&")); thunk->sprin1(s); } Value* eval(); Value* assign_vf(Value**arg_list, int count); }; /* -------------------- FreeThunk ------------------- */ class FreeThunk : public Thunk { public: int level; // how many levels to reach back int index; // index there FreeThunk(Value* init_name, int level, int index); # define is_freethunk(p) ((p)->tag == INTERNAL_FREE_THUNK_TAG) Thunk* make_free_thunk(int level); void collect() { delete this; } void sprin1(CharStream* s); Value* eval(); Value* assign_vf(Value**arg_list, int count); }; class IndirectFreeThunk : public FreeThunk { public: IndirectFreeThunk(Value* init_name, int level, int index) : FreeThunk(init_name, level, index) { } BOOL _is_indirect_thunk() { return TRUE; } Thunk* make_free_thunk(int level); void collect() { delete this; } void sprin1(CharStream* s) { s->printf(_T("&")); FreeThunk::sprin1(s); } Value* eval(); Value* assign_vf(Value**arg_list, int count); }; /* -------------------- ClosureFreeThunk ------------------- */ class ClosureFreeThunk : public Thunk { public: ScripterExport Value* eval(); void gc_trace(); void collect() { delete this; } ScripterExport void sprin1(CharStream* s); ClosureFreeThunk(); ~ClosureFreeThunk(); }; /* -------------------- PropertyThunk ------------------- */ class PropertyThunk : public Thunk { public: Value* target_code; // code to eval to get target Value* property_name; // property name getter_vf getter; // getter virtual fn for built-in properties setter_vf setter; // setter " " " " PropertyThunk(Value* target, Value* prop_name); PropertyThunk(Value* target, Value* prop_name, getter_vf get_fn, setter_vf set_fn); void gc_trace(); void collect() { delete this; } ScripterExport void sprin1(CharStream* s); # define is_propertythunk(p) ((p)->tag == INTERNAL_PROP_THUNK_TAG) ScripterExport Value* eval(); Value* assign_vf(Value**arg_list, int count); Value* op_assign_vf(Value**arg_list, int count); }; // a PropThunk subclass that is used when a Prop access occurs in a function call // this is basically a hack to support OLE client method calls, since OLE IDISPATCH // cannot distinguish methods from props class FnCallPropertyThunk : public PropertyThunk { public: FnCallPropertyThunk(Value* target, Value* prop_name, getter_vf get_fn, setter_vf set_fn) : PropertyThunk (target, prop_name, get_fn, set_fn) {} void collect() { delete this; } ScripterExport Value* eval(); }; #ifdef USE_PROPERTY_PATH_THUNKS /* PropertyPathThunk encodes a multi-level property access, such as $foo.twist.gizmo.pos.x * in a single thunk so that MAXWrapper objects (and others that want) can look-ahead doing the whole path at once and * not need backreferencing leaf-values for some of the funnier pseudo property accesses * allowed in MAXScript */ class PropertyPathThunk : public Thunk { Value* target_code; // code to eval to get target Array* property_path; // list of property names public: PropertyPathThunk(Value* target, Array* prop_path); void gc_trace(); void collect() { delete this; } ScripterExport void sprin1(CharStream* s); Value* append_property(Value* prop_name); ScripterExport Value* eval(); Value* assign_vf(Value**arg_list, int count); }; #endif /* -------------------- IndexThunk ------------------- */ class IndexThunk : public Thunk { Value* target_code; // code to eval to get target Value* index_code; // code to eval to get index public: IndexThunk(Value* index); # define is_indexthunk(o) ((o)->tag == INTERNAL_INDEX_THUNK_TAG) void gc_trace(); void collect() { delete this; } ScripterExport void sprin1(CharStream* s); Value* set_target(Value* targ) { target_code = targ; return this; } ScripterExport Value* eval(); Value* assign_vf(Value**arg_list, int count); }; /* -------------------- RolloutControlThunk ------------------- */ class RolloutControlThunk : public Thunk { public: int index; Rollout* rollout; RolloutControlThunk(Value* name, int control_index, Rollout* rollout); BOOL _is_rolloutthunk() { return 1; } # define is_rolloutthunk(o) ((o)->_is_rolloutthunk()) Value* eval() { return rollout->controls[index]; } void ScripterExport gc_trace(); void collect() { delete this; } ScripterExport void sprin1(CharStream* s); Value* assign_vf(Value**arg_list, int count); }; /* -------------------- RolloutLocalThunk ------------------- */ class RolloutLocalThunk : public Thunk { public: int index; Rollout* rollout; RolloutLocalThunk(Value* name, int control_index, Rollout* rollout); BOOL _is_rolloutthunk() { return 1; } ScripterExport Value* eval(); void gc_trace(); void collect() { delete this; } ScripterExport void sprin1(CharStream* s); Value* assign_vf(Value**arg_list, int count); }; class ConstRolloutLocalThunk : public RolloutLocalThunk { public: ConstRolloutLocalThunk(Value* name, int control_index, Rollout* rollout) : RolloutLocalThunk(name, control_index, rollout) { } void collect() { delete this; } Value* assign_vf(Value**arg_list, int count) { throw AssignToConstError (this); return &undefined; } }; /* -------------------- ToolLocalThunk ------------------- */ class ToolLocalThunk : public Thunk { public: int index; MouseTool* tool; ToolLocalThunk(Value* name, int iindex, MouseTool* tool); ScripterExport Value* eval(); void gc_trace(); void collect() { delete this; } ScripterExport void sprin1(CharStream* s); Value* assign_vf(Value**arg_list, int count); }; /* -------------------- CodeBlockLocalThunk ------------------- */ class CodeBlock; class CodeBlockLocalThunk : public Thunk { public: int index; CodeBlock* block; CodeBlockLocalThunk(Value* name, int iindex, CodeBlock* block); ScripterExport Value* eval(); void gc_trace(); void collect() { delete this; } ScripterExport void sprin1(CharStream* s); Value* assign_vf(Value**arg_list, int count); }; /* -------------------- RCMenuItemThunk ------------------- */ class RCMenuItemThunk : public Thunk { public: int index; RCMenu* rcmenu; RCMenuItemThunk(Value* name, int item_index, RCMenu* menu); BOOL _is_rolloutthunk() { return 1; } # define is_rcmenuthunk(o) ((o)->_is_rcmenuthunk()) Value* eval() { return rcmenu->items[index]; } void ScripterExport gc_trace(); void collect() { delete this; } ScripterExport void sprin1(CharStream* s); Value* assign_vf(Value**arg_list, int count); }; /* -------------------- RCMenuLocalThunk ------------------- */ class RCMenuLocalThunk : public Thunk { public: int index; RCMenu* rcmenu; RCMenuLocalThunk(Value* name, int iindex, RCMenu* menu); BOOL _is_rcmenuthunk() { return 1; } ScripterExport Value* eval(); void gc_trace(); void collect() { delete this; } ScripterExport void sprin1(CharStream* s); Value* assign_vf(Value**arg_list, int count); }; /* -------------------- PluginLocalThunk ------------------- */ class PluginLocalThunk : public Thunk { public: int index; // access via current_plugin thread local BOOL re_init; // indicate whether this local needs re-initialization on a redefinition (say for local rollouts, fns, etc.) PluginLocalThunk(Value* name, int iindex, BOOL re_init = FALSE); # define is_pluginlocalthunk(p) ((p)->tag == INTERNAL_PLUGIN_LOCAL_THUNK_TAG) ScripterExport Value* eval(); void collect() { delete this; } ScripterExport void sprin1(CharStream* s); Value* assign_vf(Value**arg_list, int count); }; class ConstPluginLocalThunk : public PluginLocalThunk { public: ConstPluginLocalThunk(Value* name, int iindex, BOOL re_init = FALSE) : PluginLocalThunk(name, iindex, re_init) { } void collect() { delete this; } Value* assign_vf(Value**arg_list, int count) { throw AssignToConstError (this); return &undefined; } }; /* -------------------- PluginParamThunk ------------------- */ class PluginParamThunk : public Thunk { public: PluginParamThunk(Value* name); ScripterExport Value* eval(); void collect() { delete this; } ScripterExport void sprin1(CharStream* s); Value* assign_vf(Value**arg_list, int count); Value* get_container_property(Value* prop, Value* cur_prop); Value* set_container_property(Value* prop, Value* val, Value* cur_prop); }; #define push_plugin(_pi) \ MSPlugin* _save_cp = thread_local(current_plugin); \ thread_local(current_plugin) = _pi; #define pop_plugin() \ thread_local(current_plugin) = _save_cp; /* -------------------- StructMemberThunk ------------------- */ class StructMemberThunk : public Thunk { public: int index; // access via current_plugin thread local StructMemberThunk(Value* name, int iindex); ScripterExport Value* eval(); void collect() { delete this; } ScripterExport void sprin1(CharStream* s); Value* assign_vf(Value**arg_list, int count); }; /* -------------------- ThunkReference ------------------- */ // indirect thunk (eg, &foo) class ThunkReference : public Thunk { public: Thunk* target; // the target thunk ScripterExport ThunkReference(Thunk* target); # define is_thunkref(p) ((p)->tag == INTERNAL_THUNK_REF_TAG) void gc_trace(); void collect() { delete this; } void sprin1(CharStream* s); Value* eval(); }; class DerefThunk : public Thunk // generated by a '*' prefix operator { public: Value* target; // the target to deref ScripterExport DerefThunk(Value* target); void gc_trace(); void collect() { delete this; } void sprin1(CharStream* s) { s->printf(_T("*")); target->sprin1(s); } Value* eval(); Value* assign_vf(Value**arg_list, int count); }; #endif