1 /*
2  *	ejsVar.h -- EJS Universal Variable Type
3  */
4 
5 /*
6  *	@copy	default
7  *
8  *	Copyright (c) Mbedthis Software LLC, 2003-2006. All Rights Reserved.
9  *	Copyright (c) Michael O'Brien, 1994-1995. All Rights Reserved.
10  *
11  *	This software is distributed under commercial and open source licenses.
12  *	You may use the GPL open source license described below or you may acquire
13  *	a commercial license from Mbedthis Software. You agree to be fully bound
14  *	by the terms of either license. Consult the LICENSE.TXT distributed with
15  *	this software for full details.
16  *
17  *	This software is open source; you can redistribute it and/or modify it
18  *	under the terms of the GNU General Public License as published by the
19  *	Free Software Foundation; either version 2 of the License, or (at your
20  *	option) any later version. See the GNU General Public License for more
21  *	details at: http://www.mbedthis.com/downloads/gplLicense.html
22  *
23  *	This program is distributed WITHOUT ANY WARRANTY; without even the
24  *	implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
25  *
26  *	This GPL license does NOT permit incorporating this software into
27  *	proprietary programs. If you are unable to comply with the GPL, you must
28  *	acquire a commercial license to use this software. Commercial licenses
29  *	for this software and support services are available from Mbedthis
30  *	Software at http://www.mbedthis.com
31  *
32  *	@end
33  */
34 
35 /*
36  *	Variables can efficiently store primitive types and can hold references to
37  *	objects. Objects can store properties which are themselves variables.
38  *	Properties can be primitive data types, other objects or methods.
39  *	Properties are indexed by a character name. A variable may store one of
40  *	the following types:
41  *
42  *		string, integer, integer-64bit, C method, C method with string args,
43  *		 Javascript method, Floating point number, boolean value, Undefined
44  *		value and the Null value.
45  *
46  *	Variables have names while objects may be referenced by multiple variables.
47  *	Objects use reference counting for garbage collection.
48  *
49  *	This module is not thread safe for performance and compactness. It relies
50  *	on upper modules to provide thread synchronization as required. The API
51  *	provides primitives to get variable/object references or to get copies of
52  *	variables which will help minimize required lock times.
53  */
54 
55 #ifndef _h_EJS_VAR
56 #define _h_EJS_VAR 1
57 
58 /********************************* Includes ***********************************/
59 
60 #include	"mpr.h"
61 
62 /********************************** Defines ***********************************/
63 #ifdef __cplusplus
64 extern "C" {
65 #endif
66 
67 /*
68  *	Defined in ejs.h
69  */
70 typedef struct Ejs Ejs;
71 
72 /*
73  *	Constants
74  */
75 #if BLD_FEATURE_SQUEEZE
76  	/**
77 	 *	Maximum property or variable name size
78 	 */
79 	#define EJS_MAX_ID				64
80 
81 	/*
82 	 *	EJS_VAR_HASH_SIZE must be less than the size of the bit field
83 	 * 	propertyIndex in EjsProperty.
84 	 */
85 	#define EJS_OBJ_HASH_SIZE		13
86 
87 	/**
88 	 *	Maximum number of arguments per function call
89 	 */
90 	#define EJS_MAX_ARGS			32
91 	#define EJS_INC_ARGS			8				/* Frame stack increment */
92 
93 #else
94 	#define EJS_MAX_ID				256
95 	#define EJS_OBJ_HASH_SIZE		29
96 	#define EJS_MAX_ARGS			64
97 	#define EJS_INC_ARGS			8
98 #endif
99 
100 #define EJS_VAR_MAX_RECURSE	5						/* Max object loops */
101 
102 #if !DOXYGEN
103 /*
104  *	Forward declare types
105  */
106 struct Ejs;
107 struct EjsObj;
108 struct EjsProperty;
109 struct EjsVar;
110 #endif
111 
112 /**
113  *	@overview EJ primitive variable type
114  *	@description EJ primitive variable values are stored in EjsVar structures.
115  *		The type of the primitive data is described by an EjsType field.
116  *		EjsVar variable types.
117  *  @stability Prototype.
118  *  @library libejs.
119  *	@see EJS_TYPE_UNDEFINED, EJS_TYPE_NULL, EJS_TYPE_BOOL, EJS_TYPE_CMETHOD,
120  *		EJS_TYPE_FLOAT, EJS_TYPE_INT, EJS_TYPE_INT64, EJS_TYPE_OBJECT,
121  *		EJS_TYPE_METHOD, EJS_TYPE_STRING, EJS_TYPE_STRING_CMETHOD, EJS_TYPE_PTR,
122  */
123 typedef uint EjsType;
124 #define EJS_TYPE_UNDEFINED 			0 	/**< Undefined. No value has been set */
125 #define EJS_TYPE_NULL 				1	/**< Value defined to be null. */
126 #define EJS_TYPE_BOOL 				2	/**< Boolean type. */
127 #define EJS_TYPE_CMETHOD 			3	/**< C method */
128 #define EJS_TYPE_FLOAT 				4	/**< Floating point number */
129 #define EJS_TYPE_INT 				5	/**< Integer number */
130 #define EJS_TYPE_INT64 				6	/**< 64-bit Integer number */
131 #define EJS_TYPE_OBJECT 			7	/**< Object reference */
132 #define EJS_TYPE_METHOD 			8	/**< JavaScript method */
133 #define EJS_TYPE_STRING 			9	/**< String (immutable) */
134 #define EJS_TYPE_STRING_CMETHOD 	10	/**< C method with string args */
135 #define EJS_TYPE_PTR	 			11	/**< Opaque pointer */
136 
137 /*
138  *	Create a type for the default number type
139  *	Config.h will define the default number type. For example:
140  *
141  *		BLD_FEATURE_NUM_TYPE=int
142  *		BLD_FEATURE_NUM_TYPE_ID=EJS_TYPE_INT
143  */
144 
145 /**
146  *	Set to the type used for EJS numeric variables. Will equate to int, int64
147  *	or double.
148  */
149 typedef BLD_FEATURE_NUM_TYPE EjsNum;
150 
151 /**
152  *	Set to the EJS_TYPE used for EJS numeric variables. Will equate to
153  *	EJS_TYPE_INT, EJS_TYPE_INT64 or EJS_TYPE_FLOAT.
154  */
155 #define EJS_NUM_VAR BLD_FEATURE_NUM_TYPE_ID
156 #define EJS_TYPE_NUM BLD_FEATURE_NUM_TYPE_ID
157 
158 /*
159  *	Return TRUE if a variable is a method type
160  */
161 #define ejsVarIsMethod(vp) \
162 	((vp)->type == EJS_TYPE_METHOD || (vp)->type == EJS_TYPE_STRING_CMETHOD || \
163 	 (vp)->type == EJS_TYPE_CMETHOD)
164 
165 /*
166  *	Return TRUE if a variable is a numeric type
167  */
168 #define ejsVarIsNumber(vp) \
169 	((vp)->type == EJS_TYPE_INT || (vp)->type == EJS_TYPE_INT64 || \
170 		(vp)->type == EJS_TYPE_FLOAT)
171 
172 /*
173  *	Return TRUE if a variable is a boolean
174  */
175 #define ejsVarIsBoolean(vp) \
176 	((vp)->type == EJS_TYPE_BOOL)
177 
178 /*
179  *	Return TRUE if a variable is an integer type
180  */
181 #define ejsVarIsInteger(vp) ((vp)->type == EJS_TYPE_INT)
182 
183 /*
184  *	Return TRUE if a variable is a string
185  */
186 #define ejsVarIsString(vp) \
187 	((vp)->type == EJS_TYPE_STRING)
188 
189 /*
190  *	Return TRUE if a variable is an object
191  */
192 #define ejsVarIsObject(vp) \
193 	((vp)->type == EJS_TYPE_OBJECT)
194 
195 /*
196  *	Return TRUE if a variable is a floating number
197  */
198 #define ejsVarIsFloating(vp) \
199 	((vp)->type == EJS_TYPE_FLOAT)
200 
201 /*
202  *	Return TRUE if a variable is undefined
203  */
204 #define ejsVarIsUndefined(var) \
205 	((var)->type == EJS_TYPE_UNDEFINED)
206 
207 /*
208  *	Return TRUE if a variable is null
209  */
210 #define ejsVarIsNull(var) \
211 	((var)->type == EJS_TYPE_NULL)
212 
213 /*
214  *	Return TRUE if a variable is a valid type (not null or undefined)
215  */
216 #define ejsVarIsValid(var) \
217 	(((var)->type != EJS_TYPE_NULL) && ((var)->type != EJS_TYPE_UNDEFINED))
218 
219 /*
220  *	Return TRUE if a variable is a ptr type
221  */
222 #define ejsVarIsPtr(vp) \
223 	((vp)->type == EJS_TYPE_PTR)
224 
225 /*	MOB -- convert all ep to ejs */
226 /**
227  *	@overview C Method signature
228  *	@description This is the calling signature for C Methods.
229  *	@param ejs Ejs reference returned from ejsCreateInterp
230  *	@param thisObj Reference to the "this" object. (The object containing the
231  *		method).
232  *	@param argc Number of arguments.
233  *	@param argv Array of arguments. Each argument is held in an EjsVar type.
234  *  @stability Prototype.
235  *  @library libejs.
236  * 	@see ejsCreateCMethodVar
237  */
238 typedef int (*EjsCMethod)(struct Ejs *ejs, struct EjsVar *thisObj,
239 	int argc, struct EjsVar **argv);
240 
241 /**
242  *	C Method with string arguments signature
243  *	@overview C Method with string arguments signature
244  *	@description This is the calling signature for C Methods.
245  *	@param ejs Ejs reference returned from ejsCreateInterp
246  *	@param thisObj Reference to the "this" object (object containing the
247  *		method.
248  *	@param argc Number of arguments.
249  *	@param argv Array of arguments. Each argument is held in an C string
250  *		pointer.
251  *  @stability Prototype.
252  *  @library libejs.
253  * 	@see ejsCreateStringCMethodVar
254  */
255 typedef int (*EjsStringCMethod)(struct Ejs *ep, struct EjsVar *thisObj,
256 	int argc, char **argv);
257 
258 /**
259  *	Flags for types: EJS_TYPE_CMETHOD, EJS_TYPE_STRING_CMETHOD
260  * 	NOTE: flags == 0 means to use the EJS handle on method callbacks
261  */
262 /* Use the primary handle on method callbacks */
263 #define EJS_PRIMARY_HANDLE		0x1
264 
265 /* Use the alternate handle on method callbacks */
266 #define EJS_ALT_HANDLE			0x2
267 
268 /** Method should not create a new local variable block */
269 #define EJS_NO_LOCAL			0x4
270 
271 /* Method is a get accessor */
272 #define EJS_GET_ACCESSOR		0x8
273 
274 /* Method is a set accessor */
275 #define EJS_SET_ACCESSOR		0x10
276 
277 /*
278  *	Flags for E4X (Xml type)
279  */
280 /* Node is a text node */
281 #define EJS_XML_FLAGS_TEXT		0x1
282 
283 /* Node is a processing instruction */
284 #define EJS_XML_FLAGS_PI		0x2
285 
286 /* Node is a comment */
287 #define EJS_XML_FLAGS_COMMENT	0x4
288 
289 /* Node is an attribute */
290 #define EJS_XML_FLAGS_ATTRIBUTE	0x8
291 
292 /* Node is an element */
293 #define EJS_XML_FLAGS_ELEMENT	0x10
294 
295 /**
296  *	Copy depth
297  *	@overview Specifies how an object should be copied
298  *	@description The EjsCopyDepth type specifies how an object's properties
299  *		should be copied. Several routines take EjsCopyDepth parameters to
300  *		control how the properties of an object should be copied. It provides
301  *		three copy options:
302  *	@see ejsWriteVar
303  */
304 typedef enum EjsCopyDepth {
305 	/**
306 	 *	During an object copy, object property references will be copied so
307 	 *	that the original object and the copy will share the same reference to
308 	 *	a property object. Properties containing primitive types including
309 	 *	strings will have their values copied and will not share references.
310 	 */
311 	EJS_SHALLOW_COPY, 			/** Copy strings. Copy object references. */
312 	/*
313 	 *	During an object copy, object properties will be replicated so that
314 	 *	the original object and the copy will not share references to the same
315 	 *	object properties. If the original object's properties are themselves
316 	 *	objects, their properties will not be copied. Only their references
317 	 *	will be copied. i.e. the deep copy is one level deep.
318 	 */
319 	EJS_DEEP_COPY, 				/** Copy strings and copy object contents. */
320 	/*
321 	 *	During an object copy, all object properties will be replicated so that
322 	 *	the original object and the copy will not share references to the same
323 	 *	object properties. If the original object's properties are themselves
324 	 *	objects, their properties will be copied. i.e. the copy is of infinite
325 	 *	depth.
326 	 */
327 	EJS_RECURSIVE_DEEP_COPY		/** Copy strings and copy object contents
328 									recursively (complete copy). */
329 } EjsCopyDepth;
330 
331 
332 /*
333  *	Enumeration flags
334  */
335 /** Enumerate data properties */
336 #define EJS_ENUM_DATA			0x0
337 
338 /** Enumerate sub classes */
339 #define EJS_ENUM_CLASSES		0x1
340 
341 /** Enumerate non-enumerable properties */
342 #define EJS_ENUM_HIDDEN			0x2
343 
344 /** Enumerate all properties */
345 #define EJS_ENUM_ALL			(0x3)
346 
347 /** Magic number when allocated */
348 #define EJS_MAGIC				0xe801e2ec
349 #define EJS_MAGIC_FREE			0xe701e3ea
350 
351 
352 /*
353  *	Garbage Collection Linkage. Free list only uses the next pointers.
354  */
355 typedef struct EjsGCLink {
356 #if BLD_DEBUG
357 	uint				magic;					/* Magic number */
358 #endif
359 #if BLD_FEATURE_ALLOC_LEAK_TRACK
360 	const char			*allocatedBy;			/* Who allocated this */
361 #endif
362 	struct EjsGCLink	*next;					/* Next property */
363 } EjsGCLink;
364 
365 
366 /**
367  *	@overview EJS Variable Type
368  *	@description The EJ language supports an extensive set of primitive types.
369  *	These variable types can efficiently store primitive data types such as
370  *	integers, strings, binary string, booleans, floating point numbers,
371  *	pointer references, and objects. EjsVars are the universal type used by
372  *	EJ to hold objects, classes and properties.
373  *	\n\n
374  *	An EjsVar may store one of the following types:
375  *	@li Boolean
376  *	@li Floating point (if supported in this build)
377  *	@li Integer
378  *	@li 64 bit integer (if supported in this build)
379  *	@li String
380  *	@li Binary string
381  *	@li C function or C++ method
382  *	@li C function with string args
383  *	@li Javascript method
384  *	@li Object
385  *	@li Null value.
386  *	@li Undefined value
387  *	\n\n
388  *	Objects can hold object properties which are themselves EJS variables.
389  *	Properties are hash indexed by the property name and are stored in
390  *	an ordered sequence. i.e. Order of properties is maintained. Objects may
391  *	be referenced by multiple variables and they use garbage collection to
392  *	reclaim memory no longer in use by objects and properties.
393  *
394  *	@warning This module is @e not thread safe for performance and
395  *		compactness. It relies on upper modules to provide thread
396  *		synchronization as required. The API provides primitives to get
397  *		variable/object references or to get copies of variables which should
398  *		help minimize required lock times.
399  *	@stability Prototype.
400  *	@library libejs
401  *	@see Ejs, EjsProperty, ejsCreateStringVar, ejsFreeVar
402  */
403 
404 typedef struct EjsVar {							/* Size 12 bytes */
405 	/*
406 	 *	GC must be first
407 	 */
408 #if BLD_DEBUG || BLD_FEATURE_ALLOC_LEAK_TRACK
409 	EjsGCLink			gc;						/* Garbage collection links */
410 #endif
411 
412 #if BLD_DEBUG
413 	const char			*propertyName;			/* Ptr to property name */
414 #endif
415 
416 	/*
417 	 *	Union of primitive types. When debugging on Linux, don't use unions
418 	 *	as the gdb debugger can't display them.
419 	 */
420 #if (!BLD_DEBUG && !VXWORKS) || WIN || BREW_SIMULATOR
421 	union {
422 #endif
423 		/*
424 		 *	For debugging, we order the common types first
425 		 */
426 		struct EjsObj 	*objectState;			/* Object state information */
427 		int				integer;
428 		bool			boolean;
429 
430 #if BLD_FEATURE_FLOATING_POINT
431 		double			floating;
432 #endif
433 #if BLD_FEATURE_INT64
434 		int64			integer64;
435 #endif
436 
437 		struct {
438 			int			length;					/* String length (sans null) */
439 			/*
440 			 *	All strings always have a trailing null allocated
441 			 */
442 			union {
443 				char	*string;				/* String */
444 				uchar	*ustring;				/* Binary string */
445 			};
446 		};
447 
448 		struct {								/* Javascript methods */
449 			MprArray	*args;					/* Null terminated */
450 			char		*body;
451 		} method;
452 
453 		struct {								/* Method with EjsVar args */
454 			EjsCMethod fn;						/* Method pointer */
455 			void		*userData;				/* User data for method */
456 		} cMethod;
457 
458 		struct {								/* Method with string args */
459 			EjsStringCMethod fn;				/* Method pointer */
460 			void		*userData;				/* User data for method */
461 		} cMethodWithStrings;
462 
463 		struct {
464 			void		*userPtr;				/* Opaque pointer */
465 			int			(*destructor)(Ejs *ejs, struct EjsVar *vp);
466 		} ptr;
467 
468 #if (!BLD_DEBUG && !VXWORKS) || WIN || BREW_SIMULATOR
469 	};
470 #endif
471 
472 	/*
473 	 *	Packed bit field (32 bits)
474 	 */
475 	uint				flags			:  8;	/* Type specific flags */
476 	EjsType				type			:  4;	/* Selector into union */
477 	uint				stringLen		:  4;	/* Length of string if inline */
478 	uint				allocatedData	:  1;	/* Node needs freeing */
479 	uint				isArray			:  1;	/* Var is an array */
480 	uint				isArrayLength	:  1;	/* Var is array.length */
481 	uint				callsSuper		:  1;	/* Method calls super() */
482 	uint				isProperty		:  1;	/* Part of a property */
483 	uint				reserved		: 11;	/* Unused */
484 
485 } EjsVar;
486 
487 
488 /*
489  *	Linkage for the ordered list of properties
490  */
491 typedef struct EjsPropLink {
492 	struct EjsPropLink	*next;						/* Next property */
493 	struct EjsPropLink	*prev;						/* Previous property */
494 
495 	/*
496 	 *	To make debugging easier
497 	 */
498 #if BLD_DEBUG
499 	const char 			*propertyName;				/* Pointer to name */
500 	struct EjsProperty	*property;					/* Pointer to property */
501 	struct EjsPropLink	*head;						/* Dummy head of list */
502 #endif
503 } EjsPropLink;
504 
505 
506 /**
507  *	@overview Object Property Type
508  *	@description The EjsProperty type is used to store all object properties.
509  *		It contains the property name, property linkage, propery attributes
510  *		such as public/private, enumerable and readonly settings. It also
511  *		contains an EjsVar to store the property data value.
512  *	@stability Prototype.
513  *	@library libejs
514  *	@see Ejs, EjsVar
515  */
516 typedef struct EjsProperty {					/* Size 96 bytes in squeeze */
517 	/*
518 	 *	EjsVar must be first. We often take the address of "var" and take
519 	 *	advantage of if an EjsProperty is null, then &prop->var will be null
520 	 *	also. Be WARNED. External users should use ejsGetVarPtr and
521 	 *	ejsGetPropertyPtr to convert between the two.
522 	 */
523 	EjsVar				var;					/* Property value */
524 
525 	/* OPT change this to a pointer to the base class property */
526 	char				name[EJS_MAX_ID];		/* Name */
527 
528 	uint				visited			: 1;	/* Has been traversed */
529 	uint				isPrivate		: 1;	/* Property is private */
530 	uint				isProtected		: 1;	/* Property is protected */
531 	uint				dontEnumerate	: 1;	/* Not enumerable */
532 	uint				dontDelete		: 1;	/* Prevent delete */
533 	uint				readonly		: 1;	/* Unmodifiable */
534 	uint				allowNonUnique	: 1;	/* Multiple of same name ok */
535 	uint				delayedDelete	: 1;
536 	uint				reserved		: 24;
537 
538 	EjsPropLink			link;					/* Ordered linked list */
539 	struct EjsProperty	*hashNext;				/* Hash table linkage */
540 
541 	/* MOB -- is this really required */
542 	struct EjsObj		*parentObj;				/* Pointer to parent object */
543 
544 } EjsProperty;
545 
546 
547 #define EJS_OP_DOT		0x1
548 #define EJS_OP_INDEX	0x2
549 #define EJS_OP_PLUS		0x3
550 #define EJS_OP_MINUS	0x4
551 #define EJS_OP_MULTIPLY	0x5
552 #define EJS_OP_DIVIDE	0x6
553 #define EJS_OP_CALL		0x7
554 
555 typedef struct EjsOp {
556 	int					opType;
557 
558 } EjsOp;
559 
560 /*
561  *	Propety Access Methods. Used per class.
562  *	MOB -- rename EjsHelpers
563  */
564 typedef struct EjsMethods {
565 #if FUTURE
566 	int		(*create)(Ejs *ep, EjsVar *thisObj);
567 	int		(*deleteProperty)(Ejs *ep, EjsVar *thisObj, const char *prop);
568 	EjsVar	*(*getProperty)(Ejs *ep, EjsVar *thisObj, const char *prop);
569 	EjsVar	*(*setProperty)(Ejs *ep, EjsVar *thisObj, const char *prop);
570 	int		(*hasProperty)(Ejs *ep, EjsVar *thisObj, const char *prop);
571 	int		(*hasInstance)(Ejs *ep, EjsVar *thisObj, const char *prop);
572 	int		(*operate)(Ejs *ep, EjsVar *thisObj, EjsOp op, EjsVar *result,
573 				EjsVar *lhs, EjsVar *rhs, int *code);
574 #else
575 
576 	EjsVar		*(*createProperty)(Ejs *ep, EjsVar *obj, const char *property);
577 	int			 (*deleteProperty)(Ejs *ep, EjsVar *obj, const char *property);
578 	EjsVar		*(*getProperty)(Ejs *ep, EjsVar *obj, const char *property);
579 	EjsVar		*(*setProperty)(Ejs *ep, EjsVar *obj, const char *property,
580 					const EjsVar *value);
581 	/*
582 	 *	Other implemented internal properties in ECMA-262 are:
583  	 *
584 	 * 		[[Construct]]		implemented via EjsVar methods
585 	 *		[[Prototype]]		implemented via EjsObj->baseClass
586 	 *		[[Class]]			implemented via EjsObj->baseClass->name
587 	 *		[[Value]]			Implemented via EjsProperty + EjsVar + EjsObj
588 	 */
589 
590 	/*
591  	 *	FUTURE -- not implemented
592 	 */
593 	int			(*canPut)(Ejs *ep, EjsVar *obj, const char *property);
594 	int			(*defaultValue)(Ejs *ep, EjsVar *obj, const char *property,
595 					const char *hint);
596 	int			(*hasProperty)(Ejs *ep, EjsVar *obj, const char *property);
597 	EjsVar		*(*call)(Ejs *ep, EjsVar *obj, const char *property,
598 					EjsVar *args);
599 	int			(*hasInstance)(Ejs *ep, EjsVar *obj, const char *property);
600 	int			(*scope)(Ejs *ep, EjsVar *obj, const char *property);
601 	int			(*match)(Ejs *ep, EjsVar *obj, const char *property,
602 					const char *string, int index);
603 #endif
604 } EjsMethods;
605 
606 
607 /*
608  *	Ejs Object Type
609  */
610 typedef struct EjsObj {
611 	/*
612  	 *	GC must be first
613 	 */
614 	EjsGCLink		gc;						/* Garbage collection links */
615 
616 	union {
617 		char 		*objName;				/* Object name */
618 		char 		*className;				/* Class name */
619 	};
620 
621 	struct EjsVar	*baseClass;				/* Pointer to base class object */
622 
623 	EjsPropLink		link;					/* Ordered list of properties */
624 
625 	/* OPT -- dynamically allocate this only if required */
626 	EjsProperty		*propertyHash[EJS_OBJ_HASH_SIZE]; /* Hash chains */
627 
628 	/* 	OPT -- could save this and store off baseClass only */
629 	EjsMethods		*methods;				/* Property access methods */
630 	void			*nativeData;			/* Native object data */
631 
632 	int				(*destructor)(Ejs *ejs, struct EjsVar *vp);
633 
634 	uint			numProperties	  : 16;	/* Total count of items */
635 	uint			visited			  :  1;	/* Has been traversed */
636 	uint			gcMarked		  :  1;	/* Node marked in-use by GC */
637 	uint			permanent		  :  1;	/* Permanent object, dont GC */
638 	uint			alive			  :  1;	/* Only GC if alive */
639 	uint			noConstructor	  :  1;	/* Object has no constructor */
640 	uint			dirty	 		  :  1;	/* Object has been modified */
641 	uint			hasErrors		  :  1;	/* Update error */
642 	uint			preventDeleteProp :  1;	/* Don't allow prop deletion */
643 	uint			delayedDeleteProp :  1;	/* Delayed delete of props */
644 	uint			reserved		  :  7;	/* Unused */
645 
646 	Ejs				*ejs;					/* Owning interp */
647 
648 #if BLD_FEATURE_MULTITHREAD
649 	MprLock			*mutex;					/* Advisory mutex lock */
650 #endif
651 } EjsObj;
652 
653 
654 /*
655  *	Define a field macro so code an use numbers in a "generic" fashion.
656  */
657 #if EJS_NUM_VAR == EJS_TYPE_INT || DOXYGEN
658 /*
659  *	Default numeric type
660  */
661 #define ejsNumber integer
662 #endif
663 #if EJS_NUM_VAR == EJS_TYPE_INT64
664 /*	Default numeric type */
665 #define ejsNumber integer64
666 #endif
667 #if EJS_NUM_VAR == EJS_TYPE_FLOAT
668 /*	Default numeric type */
669 #define ejsNumber floating
670 #endif
671 
672 typedef BLD_FEATURE_NUM_TYPE EjsNumber;
673 
674 /*
675  *	Memory allocation slabs
676  */
677 #define EJS_SLAB_OBJ		0
678 #define EJS_SLAB_PROPERTY	1
679 #define EJS_SLAB_VAR		2
680 #define EJS_SLAB_MAX		3
681 
682 /**
683  *	Object and pointer property destructory type
684  */
685 typedef int		(*EjsDestructor)(Ejs *ejs, EjsVar *vp);
686 
687 #if BLD_FEATURE_ALLOC_LEAK_TRACK || DOXYGEN
688 /*
689  *	Line number information args and declarations for ejsAlloc.
690  *		Use EJS_LOC_ARGS in normal user code.
691  *		Use EJS_LOC_DEC  in declarations.
692  *		Use EJS_LOC_PASS in layered APIs to pass original line info down.
693  */
694 #define EJS_LOC_ARGS(ejs)		ejs, MPR_LOC
695 #define EJS_LOC_DEC(ejs, loc)	Ejs *ejs, const char *loc
696 #define EJS_LOC_PASS(ejs, loc)	ejs, loc
697 #else
698 #define EJS_LOC_ARGS(ejs)		ejs
699 #define EJS_LOC_DEC(ejs, loc)	Ejs *ejs
700 #define EJS_LOC_PASS(ejs, loc)	ejs
701 #endif
702 
703 /******************************* Internal Prototypes **************************/
704 
705 #define ejsInitVar(vp, varType) \
706 	if (1) { 				 \
707 		(vp)->type = varType; 	 \
708 		(vp)->isArray = 0; 	 \
709 		(vp)->flags = 0; 		 \
710 	} else
711 extern void	 		ejsClearVar(Ejs *ep, EjsVar *vp);
712 
713 extern int 		ejsDestroyObj(Ejs *ep, EjsObj *obj);
714 extern EjsVar 	*ejsCreatePropertyMethod(Ejs *ep, EjsVar *obj,
715 					const char *name);
716 extern EjsVar 	*ejsSetPropertyMethod(Ejs *ep, EjsVar *obj, const char *name,
717 					const EjsVar *value);
718 extern EjsVar 	*ejsGetPropertyMethod(Ejs *ep, EjsVar *obj, const char *name);
719 extern int	 	ejsDeletePropertyMethod(Ejs *ep, EjsVar *obj,
720 					const char *name);
721 extern void 	ejsSetArrayLength(Ejs *ep, EjsVar *obj, const char *creating,
722 					const char *deleting, const EjsVar *setLength);
723 
724 /*
725  *	At the moment, these are the same routine
726  */
727 extern void			ejsSetClassName(Ejs *ep, EjsVar *obj, const char *name);
728 #define ejsSetObjName ejsSetObjName
729 
730 extern bool			ejsIsObjDirty(EjsVar *vp);
731 extern void			ejsResetObjDirtyBit(EjsVar *vp);
732 
733 extern int			ejsObjHasErrors(EjsVar *vp);
734 extern void			ejsClearObjErrors(EjsVar *vp);
735 
736 extern EjsVar		*ejsClearProperty(Ejs *ep, EjsVar *obj, const char *prop);
737 
738 typedef int 		(*EjsSortFn)(Ejs *ep, EjsProperty *p1, EjsProperty *p2,
739 						const char *propertyName, int order);
740 extern void			ejsSortProperties(Ejs *ep, EjsVar *obj, EjsSortFn fn,
741 						const char *propertyName, int order);
742 
743 #if BLD_DEBUG
744 #define 			ejsSetVarName(ep, vp, varName) \
745 						if (1) { \
746 							(vp)->propertyName = varName; \
747 							if ((vp)->type == EJS_TYPE_OBJECT && \
748 								(vp)->objectState && \
749 								((vp)->objectState->objName == 0)) { \
750 									(vp)->objectState->objName = \
751 										mprStrdup(ep, varName); \
752 							} \
753 						} else
754 #else
755 #define 			ejsSetVarName(ep, vp, varName)
756 #endif
757 
758 EjsVar 				*ejsFindProperty(Ejs *ep, EjsVar **obj, char **property,
759 						EjsVar *global, EjsVar *local, const char *fullName,
760 						int create);
761 
762 extern EjsVar 		*ejsCopyProperties(Ejs *ep, EjsVar *dest,
763 						const EjsVar *src, EjsCopyDepth copyDepth);
764 
765 #define EJS_LINK_OFFSET ((uint) (&((EjsProperty*) 0)->link))
766 #define ejsGetPropertyFromLink(lp) \
767 		((EjsProperty*) ((char*) lp - EJS_LINK_OFFSET))
768 
769 #define ejsGetObjPtr(vp) ((EjsObj*) vp->objectState)
770 
771 extern void 		ejsMakePropertyPrivate(EjsProperty *pp, int isPrivate);
772 extern void 		ejsMakePropertyReadOnly(EjsProperty *pp, int readonly);
773 extern void 		ejsMakePropertyUndeleteable(EjsProperty *pp, int deletable);
774 extern int	 		ejsMakeObjLive(EjsVar *vp, bool alive);
775 extern void 		ejsMakeClassNoConstructor(EjsVar *vp);
776 
777 extern bool			ejsBlockInUseInt(EjsVar *vp);
778 #if BLD_DEBUG
779 	#define ejsBlockInUse(vp) ejsBlockInUseInt(vp)
780 #else
781 	#define ejsBlockInUse(vp)
782 #endif
783 
784 /********************************* Prototypes *********************************/
785 
786 /*
787  *	Variable constructors and destructors
788  */
789 extern EjsVar		*ejsCreateBinaryStringVar(Ejs *ep, const uchar *value,
790 						int len);
791 extern EjsVar 		*ejsCreateBoolVar(Ejs *ep, int value);
792 extern EjsVar 		*ejsCreateCMethodVar(Ejs *ep, EjsCMethod fn,
793 						void *userData, int flags);
794 #if BLD_FEATURE_FLOATING_POINT
795 extern EjsVar 		*ejsCreateFloatVar(Ejs *ep, double value);
796 #endif
797 extern EjsVar 		*ejsCreateIntegerVar(Ejs *ep, int value);
798 #if BLD_FEATURE_INT64
799 extern EjsVar 		*ejsCreateInteger64Var(Ejs *ep, int64 value);
800 #endif
801 
802 extern EjsVar 		*ejsCreateMethodVar(Ejs *ep, const char *body,
803 						MprArray *args, int flags);
804 extern EjsVar		*ejsCreateNullVar(Ejs *ep);
805 extern EjsVar 		*ejsCreateNumberVar(Ejs *ep, EjsNumber value);
806 
807 #define ejsCreateObjVar(ep) \
808 					ejsCreateObjVarInternal(EJS_LOC_ARGS(ep))
809 extern EjsVar		*ejsCreateObjVarInternal(EJS_LOC_DEC(ep, loc));
810 
811 extern EjsVar 		*ejsCreatePtrVar(Ejs *ep, void *ptr, EjsDestructor dest);
812 
813 extern EjsVar 		*ejsCreateStringCMethodVar(Ejs *ep, EjsStringCMethod fn,
814 						void *userData, int flags);
815 
816 #define ejsCreateStringVar(ep, value) \
817 					ejsCreateStringVarInternal(EJS_LOC_ARGS(ep), value)
818 extern EjsVar		*ejsCreateStringVarInternal(EJS_LOC_DEC(ep, loc),
819 						const char *value);
820 
821 extern EjsVar		*ejsCreateUndefinedVar(Ejs *ep);
822 
823 /* MOB -- naming. Should be Create/Destroy */
824 extern void	 		ejsFreeVar(Ejs *ep, EjsVar *vp);
825 
826 /*
827  *	Var support routines
828  */
829 extern int			ejsGetVarFlags(EjsVar *vp);
830 extern void			ejsSetVarFlags(EjsVar *obj, int flags);
831 
832 extern EjsType		ejsGetVarType(EjsVar *vp);
833 extern const char 	*ejsGetVarTypeAsString(EjsVar *vp);
834 
835 extern void			*ejsGetCMethodUserData(EjsVar *obj);
836 extern void			ejsSetCMethodUserData(EjsVar *obj, void *userData);
837 
838 extern void			*ejsGetVarUserPtr(EjsVar *vp);
839 extern void			ejsSetVarUserPtr(EjsVar *vp, void *data);
840 
841 
842 /*
843  *	Variable access and manipulation. These work on standalone objects.
844  */
845 #define ejsDupVar(ep, src, copyDepth) \
846 						ejsDupVarInternal(EJS_LOC_ARGS(ep), src, copyDepth)
847 extern EjsVar		*ejsDupVarInternal(EJS_LOC_DEC(ep, loc), EjsVar *src,
848 						EjsCopyDepth copyDepth);
849 #define ejsWriteVar(ep, dest, src, copyDepth) \
850 					ejsWriteVarInternal(EJS_LOC_ARGS(ep), dest, src, copyDepth)
851 extern EjsVar		*ejsWriteVarInternal(EJS_LOC_DEC(ep, loc), EjsVar *dest,
852 						const EjsVar *src, EjsCopyDepth copyDepth);
853 extern EjsVar 		*ejsWriteVarAsBinaryString(Ejs *ep, EjsVar *dest,
854 						const uchar *value, int len);
855 extern EjsVar		*ejsWriteVarAsBoolean(Ejs *ep, EjsVar *dest, bool value);
856 extern EjsVar		*ejsWriteVarAsCMethod(Ejs *ep, EjsVar *dest, EjsCMethod fn,
857 						void *userData, int flags);
858 #if BLD_FEATURE_FLOATING_POINT
859 extern EjsVar		*ejsWriteVarAsFloat(Ejs *ep, EjsVar *dest, double value);
860 #endif
861 extern EjsVar		*ejsWriteVarAsInteger(Ejs *ep, EjsVar *dest, int value);
862 #if BLD_FEATURE_INT64
863 extern EjsVar		*ejsWriteVarAsInteger64(Ejs *ep, EjsVar *dest, int64 value);
864 #endif
865 extern EjsVar		*ejsWriteVarAsMethod(Ejs *ep, EjsVar *dest,
866 						const char *body, MprArray *args);
867 extern EjsVar		*ejsWriteVarAsNull(Ejs *ep, EjsVar *dest);
868 extern EjsVar		*ejsWriteVarAsNumber(Ejs *ep, EjsVar *dest, EjsNum value);
869 #define ejsWriteVarAsString(ep, dest, value) \
870 					ejsWriteVarAsStringInternal(EJS_LOC_ARGS(ep), dest, value)
871 extern EjsVar		*ejsWriteVarAsStringInternal(EJS_LOC_DEC(ep, loc),
872 						EjsVar *dest, const char *value);
873 extern EjsVar		*ejsWriteVarAsStringCMethod(Ejs *ep, EjsVar *dest,
874 						EjsStringCMethod fn, void *userData, int flags);
875 extern EjsVar		*ejsWriteVarAsUndefined(Ejs *ep, EjsVar *dest);
876 
877 /*
878  *	These routines do not convert types
879  */
880 /* MOB -- make this a fn and pass back the length as an arg */
881 #define ejsReadVarAsBinaryString(vp) ((const uchar*) (vp->ustring));
882 #define ejsReadVarAsBoolean(vp) (vp->boolean);
883 #define ejsReadVarAsCMethod(vp) (vp->cMethod);
884 #if BLD_FEATURE_FLOATING_POINT
885 #define ejsReadVarAsFloat(vp) (vp->floating);
886 #endif
887 #define ejsReadVarAsInteger(vp) (vp->integer);
888 #if BLD_FEATURE_INT64
889 #define ejsReadVarAsInteger64(vp) (vp->int64);
890 #endif
891 #define ejsReadVarAsString(vp) ((const char*) (vp->string));
892 #define ejsReadVarAsStringCMethod(vp) (vp->cMethodWithStrings);
893 /* MOB -- remove this fn */
894 #define ejsReadVarStringLength(vp) (vp->length);
895 
896 /*
897  *	Object property creation routines
898  */
899 extern EjsProperty	*ejsCreateProperty(Ejs *ep, EjsVar *obj, const char *prop);
900 extern EjsProperty	*ejsCreateSimpleProperty(Ejs *ep, EjsVar *obj,
901 						const char *prop);
902 extern EjsProperty	*ejsCreateSimpleNonUniqueProperty(Ejs *ep, EjsVar *obj,
903 						const char *prop);
904 /* MOB -- should be destroy */
905 extern int			ejsDeleteProperty(Ejs *ep, EjsVar *obj, const char *prop);
906 
907 
908 /*
909  *	Get property routines
910  */
911 extern EjsProperty 	*ejsGetProperty(Ejs *ep, EjsVar *obj, const char *prop);
912 extern EjsProperty 	*ejsGetSimpleProperty(Ejs *ep, EjsVar *obj,
913 						const char *prop);
914 
915 extern EjsVar		*ejsGetPropertyAsVar(Ejs *ep, EjsVar *obj,
916 						const char *prop);
917 extern int			ejsGetPropertyCount(EjsVar *obj);
918 
919 extern const uchar	*ejsGetPropertyAsBinaryString(Ejs *ep, EjsVar *obj,
920 						const char *prop, int *length);
921 extern bool			ejsGetPropertyAsBoolean(Ejs *ep, EjsVar *obj,
922 						const char *prop);
923 extern int			ejsGetPropertyAsInteger(Ejs *ep, EjsVar *obj,
924 						const char *prop);
925 extern int64		ejsGetPropertyAsInteger64(Ejs *ep, EjsVar *obj,
926 						const char *prop);
927 extern EjsNum 		ejsGetPropertyAsNumber(Ejs *ep, EjsVar *obj,
928 						const char *prop);
929 extern void			*ejsGetPropertyAsPtr(Ejs *ep, EjsVar *obj,
930 						const char *prop);
931 extern const char	*ejsGetPropertyAsString(Ejs *ep, EjsVar *obj,
932 						const char *prop);
933 
934 /*
935  *	Object property update routines
936  */
937 extern EjsProperty	*ejsSetBaseProperty(Ejs *ep, EjsVar *obj, const char *prop,
938 						const EjsVar *value);
939 extern EjsProperty	*ejsSetProperty(Ejs *ep, EjsVar *obj, const char *prop,
940 						const EjsVar *value);
941 extern EjsProperty	*ejsSetPropertyAndFree(Ejs *ep, EjsVar *obj,
942 						const char *prop, EjsVar *value);
943 extern EjsProperty	*ejsSetPropertyToBinaryString(Ejs *ep, EjsVar *obj,
944 						const char *prop, const uchar *value, int len);
945 extern EjsProperty	*ejsSetPropertyToBoolean(Ejs *ep, EjsVar *obj,
946 						const char *prop, bool value);
947 extern EjsProperty	*ejsSetPropertyToCMethod(Ejs *ep, EjsVar *obj,
948 						const char *prop, EjsCMethod fn, void *userData,
949 						int flags);
950 #if BLD_FEATURE_FLOATING_POINT
951 extern EjsProperty	*ejsSetPropertyToFloat(Ejs *ep, EjsVar *obj,
952 						const char *prop, double value);
953 #endif
954 extern EjsProperty	*ejsSetPropertyToInteger(Ejs *ep, EjsVar *obj,
955 						const char *prop, int value);
956 #if BLD_FEATURE_INT64
957 extern EjsProperty	*ejsSetPropertyToInteger64(Ejs *ep, EjsVar *obj,
958 						const char *prop, int64 value);
959 #endif
960 extern EjsProperty	*ejsSetPropertyToMethod(Ejs *ep, EjsVar *obj,
961 						const char *prop, const char *body, MprArray *args,
962 						int flags);
963 extern EjsProperty	*ejsSetPropertyToNewObj(Ejs *ep, EjsVar *obj,
964 						const char *prop, const char *className,
965 						MprArray *args);
966 extern EjsProperty	*ejsSetPropertyToNull(Ejs *ep, EjsVar *obj,
967 						const char *prop);
968 extern EjsProperty	*ejsSetPropertyToNumber(Ejs *ep, EjsVar *obj,
969 						const char *prop, EjsNum value);
970 extern EjsProperty	*ejsSetPropertyToObj(Ejs *ep, EjsVar *obj,
971 						const char *prop);
972 extern EjsProperty	*ejsSetPropertyToPtr(Ejs *ep, EjsVar *obj,
973 						const char *prop, void *ptr, EjsDestructor destructor);
974 
975 extern EjsProperty	*ejsSetPropertyToStringCMethod(Ejs *ep, EjsVar *obj,
976 						const char *prop, EjsStringCMethod fn,
977 						void *userData, int flags);
978 extern EjsProperty	*ejsSetPropertyToString(Ejs *ep, EjsVar *obj,
979 						const char *prop, const char *value);
980 extern EjsProperty	*ejsSetPropertyToUndefined(Ejs *ep, EjsVar *obj,
981 						const char *prop);
982 
983 
984 /* Convenience function */
985 extern EjsVar 		*ejsSetPropertyToObjAsVar(Ejs *ep, EjsVar *obj,
986 						const char *prop);
987 extern void			ejsSetObjDestructor(Ejs *ep, EjsVar *obj,
988 						EjsDestructor destructor);
989 extern void			ejsClearObjDestructor(Ejs *ep, EjsVar *obj);
990 
991 /*
992  *	Enumeration of properties
993  *	MOB -- should these take an ejs parameter to be consistent
994  */
995 extern EjsProperty 	*ejsGetFirstProperty(const EjsVar *obj, int flags);
996 extern EjsProperty 	*ejsGetNextProperty(EjsProperty *last, int flags);
997 
998 /*
999  *	Method definition and control.
1000  */
1001 extern EjsProperty	*ejsDefineMethod(Ejs *ep, EjsVar *obj, const char *prop,
1002 						const char *body, MprArray *args);
1003 extern EjsProperty	*ejsDefineCMethod(Ejs *ep, EjsVar *obj, const char *prop,
1004 						EjsCMethod fn, int flags);
1005 
1006 extern EjsProperty	*ejsDefineStringCMethod(Ejs *ep, EjsVar *obj,
1007 						const char *prop, EjsStringCMethod fn, int flags);
1008 
1009 extern EjsProperty	*ejsDefineAccessors(Ejs *ep, EjsVar *obj,
1010 						const char *prop, const char *getBody,
1011 						const char *setBody);
1012 extern EjsProperty	*ejsDefineCAccessors(Ejs *ep, EjsVar *obj,
1013 						const char *prop, EjsCMethod getFn, EjsCMethod setFn,
1014 						 int flags);
1015 
1016 /*
1017  *	Macro to get the variable value portion of a property
1018  */
1019 #define ejsGetVarPtr(pp) (&((pp)->var))
1020 #define ejsGetPropertyPtr(vp) ((EjsProperty*) vp)
1021 
1022 /* MOB -- take ejs to be consistent */
1023 extern int	 		ejsMakePropertyEnumerable(EjsProperty *pp, bool enumerable);
1024 extern int	 		ejsMakeObjPermanent(EjsVar *vp, bool permanent);
1025 
1026 
1027 /*
1028  *	Var conversion routines
1029  *	MOB -- should these take an Ejs as first arg for consistency
1030  */
1031 extern bool	 	ejsVarToBoolean(EjsVar *vp);
1032 #if BLD_FEATURE_FLOATING_POINT
1033 extern double 	ejsVarToFloat(EjsVar *vp);
1034 #endif
1035 extern int	 	ejsVarToInteger(EjsVar *vp);
1036 #if BLD_FEATURE_INT64
1037 extern int64 	ejsVarToInteger64(EjsVar *vp);
1038 #endif
1039 extern EjsNum 	ejsVarToNumber(EjsVar *vp);
1040 extern char		*ejsVarToString(Ejs *ep, EjsVar *vp);
1041 extern char 	*ejsVarToStringEx(Ejs *ep, EjsVar *vp, bool *alloc);
1042 extern char		*ejsFormatVar(Ejs *ep, const char *fmt, EjsVar *vp);
1043 
1044 #if BLD_FEATURE_FLOATING_POINT
1045 extern double 	ejsParseFloat(const char *str);
1046 #endif
1047 /*
1048  *	Parsing and type range checking routines
1049  */
1050 extern bool	 	ejsParseBoolean(const char *str);
1051 extern int	 	ejsParseInteger(const char *str);
1052 #if BLD_FEATURE_INT64
1053 extern int64 	ejsParseInteger64(const char *str);
1054 #endif
1055 extern EjsNum 	ejsParseNumber(const char *str);
1056 extern EjsVar 	*ejsParseVar(Ejs *ep, const char *str, EjsType prefType);
1057 
1058 #if BLD_FEATURE_FLOATING_POINT
1059 extern bool	 	ejsIsInfinite(double f);
1060 extern bool	 	ejsIsNan(double f);
1061 #endif
1062 
1063 /*
1064  *	Advisory locking support
1065  */
1066 #if BLD_FEATURE_MULTITHREAD
1067 extern void 	ejsLockObj(EjsVar *vp);
1068 extern void 	ejsUnlockObj(EjsVar *vp);
1069 #endif
1070 
1071 /*
1072  *	Just for debugging
1073  */
1074 extern bool 		ejsObjIsCollectable(EjsVar *vp);
1075 
1076 #ifdef __cplusplus
1077 }
1078 #endif
1079 
1080 /*****************************************************************************/
1081 #endif /* _h_EJS_VAR */
1082 
1083 /*
1084  * Local variables:
1085  * tab-width: 4
1086  * c-basic-offset: 4
1087  * End:
1088  * vim:tw=78
1089  * vim600: sw=4 ts=4 fdm=marker
1090  * vim<600: sw=4 ts=4
1091  */
1092