cfad47cfa3/tads3/vmpat.cpp

4b825dc642cb6eb9a060e54bf8d69288fbee4904cfad47cfa334b206c65f22086bcc5d63e6f70944
1
/* 
2
 *   Copyright (c) 2002 by Michael J. Roberts.  All Rights Reserved.
3
 *   
4
 *   Please see the accompanying license file, LICENSE.TXT, for information
5
 *   on using and copying this software.  
6
 */
7
/*
8
Name
9
  vmpat.cpp - regular-expression compiled pattern object
10
Function
11
  
12
Notes
13
  
14
Modified
15
  08/27/02 MJRoberts  - Creation
16
*/
17
18
#include <stdlib.h>
19
#include <os.h>
20
#include "vmtype.h"
21
#include "vmobj.h"
22
#include "vmmeta.h"
23
#include "vmglob.h"
24
#include "vmregex.h"
25
#include "vmpat.h"
26
#include "vmstack.h"
27
#include "vmbif.h"
28
#include "vmbiftad.h"
29
#include "vmfile.h"
30
31
32
/* ------------------------------------------------------------------------ */
33
/*
34
 *   Statics 
35
 */
36
static CVmMetaclassPattern metaclass_reg_obj;
37
CVmMetaclass *CVmObjPattern::metaclass_reg_ = &metaclass_reg_obj;
38
39
/* function table */
40
int (CVmObjPattern::
41
     *CVmObjPattern::func_table_[])(VMG_ vm_obj_id_t self,
42
                                    vm_val_t *retval, uint *argc) =
43
{
44
    &CVmObjPattern::getp_undef,
45
    &CVmObjPattern::getp_get_str
46
};
47
48
/* ------------------------------------------------------------------------ */
49
/*
50
 *   create 
51
 */
52
CVmObjPattern::CVmObjPattern(VMG_ re_compiled_pattern *pat,
53
                             const vm_val_t *src_str)
54
{
55
    /* allocate my extension data */
56
    ext_ = (char *)G_mem->get_var_heap()
57
           ->alloc_mem(sizeof(vmobj_pat_ext), this);
58
59
    /* remember my source data */
60
    set_orig_str(src_str);
61
62
    /* remember the compiled pattern */
63
    set_pattern(pat);
64
}
65
66
/* ------------------------------------------------------------------------ */
67
/*
68
 *   notify of deletion 
69
 */
70
void CVmObjPattern::notify_delete(VMG_ int in_root_set)
71
{
72
    /* free my extension data */
73
    if (ext_ != 0)
74
    {
75
        /* 
76
         *   Free my pattern, if I've compiled it.  (Note that we must not
77
         *   call get_pattern() here, because doing so would unnecessarily
78
         *   create a pattern if we haven't already done so - that would be
79
         *   stupid, because the only reason we're asking for it is so that
80
         *   we can delete it.)  
81
         */
82
        if (get_ext()->pat != 0)
83
            CRegexParser::free_pattern(get_ext()->pat);
84
85
        /* free the extension */
86
        if (!in_root_set)
87
            G_mem->get_var_heap()->free_mem(ext_);
88
    }
89
}
90
91
/* ------------------------------------------------------------------------ */
92
/*
93
 *   Create from the stack 
94
 */
95
vm_obj_id_t CVmObjPattern::create_from_stack(VMG_ const uchar **pc_ptr,
96
                                             uint argc)
97
{
98
    const char *strval;
99
    re_status_t stat;
100
    re_compiled_pattern *pat;
101
    vm_obj_id_t id;
102
103
    /* check arguments */
104
    if (argc != 1)
105
        err_throw(VMERR_WRONG_NUM_OF_ARGS);
106
107
    /* retrieve the string, but leave it on the stack */
108
    strval = G_stk->get(0)->get_as_string(vmg0_);
109
    if (strval == 0)
110
        err_throw(VMERR_STRING_VAL_REQD);
111
112
    /* compile the string */
113
    stat = G_bif_tads_globals->rex_parser->compile_pattern(
114
        strval + VMB_LEN, vmb_get_len(strval), &pat);
115
116
    /* if we failed to compile the pattern, throw an error */
117
    if (stat != RE_STATUS_SUCCESS)
118
        err_throw(VMERR_BAD_TYPE_BIF);
119
120
    /* create a new pattern object to hold the pattern */
121
    id = vm_new_id(vmg_ FALSE, TRUE, FALSE);
122
    new (vmg_ id) CVmObjPattern(vmg_ pat, G_stk->get(0));
123
124
    /* discard arguments */
125
    G_stk->discard();
126
127
    /* return the new object */
128
    return id;
129
}
130
131
/* ------------------------------------------------------------------------ */
132
/* 
133
 *   set a property 
134
 */
135
void CVmObjPattern::set_prop(VMG_ class CVmUndo *,
136
                             vm_obj_id_t, vm_prop_id_t,
137
                             const vm_val_t *)
138
{
139
    /* we have no properties to set */
140
    err_throw(VMERR_INVALID_SETPROP);
141
}
142
143
/* ------------------------------------------------------------------------ */
144
/*
145
 *   Get a property 
146
 */
147
int CVmObjPattern::get_prop(VMG_ vm_prop_id_t prop, vm_val_t *val,
148
                            vm_obj_id_t self, vm_obj_id_t *source_obj,
149
                            uint *argc)
150
{
151
    uint func_idx;
152
    
153
    /* translate the property into a function vector index */
154
    func_idx = G_meta_table
155
               ->prop_to_vector_idx(metaclass_reg_->get_reg_idx(), prop);
156
157
    /* call the function, if we found it */
158
    if ((this->*func_table_[func_idx])(vmg_ self, val, argc))
159
    {
160
        *source_obj = metaclass_reg_->get_class_obj(vmg0_);
161
        return TRUE;
162
    }
163
164
    /* not found - inherit default handling */
165
    return CVmObject::get_prop(vmg_ prop, val, self, source_obj, argc);
166
}
167
168
169
/* ------------------------------------------------------------------------ */
170
/*
171
 *   Mark references 
172
 */
173
void CVmObjPattern::mark_refs(VMG_ uint state)
174
{
175
    const vm_val_t *valp;
176
    
177
    /* if our source value is an object reference, mark it */
178
    if (get_ext() != 0
179
        && (valp = get_orig_str())->typ == VM_OBJ
180
        && valp->val.obj != VM_INVALID_OBJ)
181
    {
182
        /* it's a reference, so mark it */
183
        G_obj_table->mark_all_refs(valp->val.obj, state);
184
    }
185
}
186
187
/* ------------------------------------------------------------------------ */
188
/*
189
 *   Load from an image file 
190
 */
191
void CVmObjPattern::load_from_image(VMG_ vm_obj_id_t self, const char *ptr,
192
                                    size_t len)
193
{
194
    /* if we don't already have an extension, allocate one */
195
    if (ext_ == 0)
196
        ext_ = (char *)G_mem->get_var_heap()
197
               ->alloc_mem(sizeof(vmobj_pat_ext), this);
198
199
    /* get our source value */
200
    vmb_get_dh(ptr, &get_ext()->str);
201
202
    /* 
203
     *   We haven't compiled our pattern yet.  Note that it might not be
204
     *   possible to obtain the text of our string at this point, because it
205
     *   might be another object and thus might not have been loaded yet.
206
     *   So, note that we have no pattern yet, and request post-load
207
     *   initialization, so that we can compile our pattern after we know all
208
     *   of the other objects have been loaded.  
209
     */
210
    set_pattern(0);
211
    G_obj_table->request_post_load_init(self);
212
}
213
214
/* ------------------------------------------------------------------------ */
215
/*
216
 *   Perform post-load initialization: we compile our pattern here.  Note
217
 *   that we need to wait until now to compile our pattern, since our source
218
 *   string could be another object, which isn't guaranteed to have been
219
 *   loaded until we get here.  
220
 */
221
void CVmObjPattern::post_load_init(VMG_ vm_obj_id_t self)
222
{
223
    const vm_val_t *origval;
224
    const char *strval;
225
226
    /* make sure the original string object is initialized */
227
    origval = get_orig_str();
228
    if (origval->typ == VM_OBJ)
229
        G_obj_table->ensure_post_load_init(vmg_ origval->val.obj);
230
231
    /* get the string value */
232
    strval = get_orig_str()->get_as_string(vmg0_);
233
    if (strval != 0)
234
    {
235
        /* if we already have a compiled pattern, delete it */
236
        if (get_ext()->pat != 0)
237
            CRegexParser::free_pattern(get_ext()->pat);
238
239
        /* compile the pattern and store the result */
240
        G_bif_tads_globals->rex_parser->compile_pattern(
241
            strval + VMB_LEN, vmb_get_len(strval), &get_ext()->pat);
242
    }
243
}
244
245
/* ------------------------------------------------------------------------ */
246
/* 
247
 *   save to a file 
248
 */
249
void CVmObjPattern::save_to_file(VMG_ class CVmFile *fp)
250
{
251
    char buf[VMB_DATAHOLDER];
252
    
253
    /* write the source string reference */
254
    vmb_put_dh(buf, get_orig_str());
255
    fp->write_bytes(buf, VMB_DATAHOLDER);
256
}
257
258
/* ------------------------------------------------------------------------ */
259
/* 
260
 *   restore from a file 
261
 */
262
void CVmObjPattern::restore_from_file(VMG_ vm_obj_id_t self,
263
                                      class CVmFile *fp, CVmObjFixup *fixups)
264
{
265
    char buf[VMB_DATAHOLDER];
266
267
    /* if we don't already have an extension, allocate one */
268
    if (ext_ == 0)
269
        ext_ = (char *)G_mem->get_var_heap()
270
               ->alloc_mem(sizeof(vmobj_pat_ext), this);
271
272
    /* read the source string reference */
273
    fp->read_bytes(buf, VMB_DATAHOLDER);
274
275
    /* fix it up */
276
    fixups->fix_dh(vmg_ buf);
277
278
    /* remember it in our extension */
279
    vmb_get_dh(buf, &get_ext()->str);
280
281
    /* 
282
     *   clear out our pattern and request post-load initialization - we
283
     *   can't necessarily compile it yet, because we might not have loaded
284
     *   the source string data, so just make a note that we need to compile
285
     *   it the next time we need it 
286
     */
287
    set_pattern(0);
288
    G_obj_table->request_post_load_init(self);
289
}
290
291
/* ------------------------------------------------------------------------ */
292
/* 
293
 *   property evaluator - get my original string 
294
 */
295
int CVmObjPattern::getp_get_str(VMG_ vm_obj_id_t self,
296
                                vm_val_t *retval, uint *argc)
297
{
298
    static CVmNativeCodeDesc desc(0);
299
300
    /* check arguments */
301
    if (get_prop_check_argc(retval, argc, &desc))
302
        return TRUE;
303
304
    /* retrieve my original string value */
305
    *retval = *get_orig_str();
306
307
    /* handled */
308
    return TRUE;
309
}