/
jsvar.h
846 lines (718 loc) · 48.5 KB
/
jsvar.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
/*
* This file is part of Espruino, a JavaScript interpreter for Microcontrollers
*
* Copyright (C) 2013 Gordon Williams <gw@pur3.co.uk>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* ----------------------------------------------------------------------------
* Variables
* ----------------------------------------------------------------------------
*/
#ifndef JSVAR_H_
#define JSVAR_H_
#include "jsutils.h"
/* Some functions can be inlined and should increase execution speed. However
it's not huge - maybe 2% speed at the expense of 10% code size. On most platforms it's
worth having the small speed impact to allow more memory. */
#ifdef JSVAR_FORCE_NO_INLINE
#define JSV_INLINEABLE NO_INLINE
#elif defined(JSVAR_FORCE_INLINE)
#define JSV_INLINEABLE ALWAYS_INLINE
#else
#define JSV_INLINEABLE
#endif
/** These flags are at the top of each JsVar and provide information about what it is, as
* well as how many Locks it has. Everything is packed in as much as possible to allow us to
* get down to within 2 bytes. */
typedef enum {
JSV_UNUSED = 0, ///< Variable not used for anything - THIS ENUM MUST BE ZERO
JSV_ROOT = JSV_UNUSED+1, ///< The root of everything - there is only one of these
// UNDEFINED is now just stored using '0' as the variable Ref
JSV_NULL = JSV_ROOT+1, ///< it seems null is its own data type
JSV_ARRAY, ///< A JavaScript Array Buffer - Implemented just like a String at the moment
JSV_ARRAYBUFFER, ///< An arraybuffer (see varData.arraybuffer)
JSV_OBJECT,
#ifndef ESPR_NO_GET_SET
JSV_GET_SET, ///< Getter/setter (an object with get/set fields)
#endif
JSV_FUNCTION,
JSV_NATIVE_FUNCTION,
JSV_FUNCTION_RETURN, ///< A simple function that starts with `return` (which is implicit)
JSV_INTEGER, ///< integer number (note JSV_NUMERICMASK)
_JSV_NUMERIC_START = JSV_INTEGER, ///< --------- Start of numeric variable types
JSV_FLOAT = JSV_INTEGER+1, ///< floating point double (note JSV_NUMERICMASK)
JSV_BOOLEAN = JSV_FLOAT+1, ///< boolean (note JSV_NUMERICMASK)
#ifndef ESPR_EMBED
JSV_PIN, ///< pin (note JSV_NUMERICMASK)
#endif
JSV_ARRAYBUFFERNAME, ///< used for indexing into an ArrayBuffer. varData is an INT in this case
_JSV_NAME_START = JSV_ARRAYBUFFERNAME, ///< ---------- Start of NAMEs (names of variables, object fields/etc)
JSV_NAME_INT = JSV_ARRAYBUFFERNAME+1, ///< integer array/object index
_JSV_NAME_INT_START = JSV_NAME_INT,
JSV_NAME_INT_INT = JSV_NAME_INT+1, ///< integer array/object index WITH integer value
_JSV_NAME_WITH_VALUE_START = JSV_NAME_INT_INT, ///< ---------- Start of names that have literal values, NOT references, in firstChild
JSV_NAME_INT_BOOL = JSV_NAME_INT_INT+1, ///< integer array/object index WITH boolean value
_JSV_NAME_INT_END = JSV_NAME_INT_BOOL,
_JSV_NUMERIC_END = JSV_NAME_INT_BOOL, ///< --------- End of numeric variable types
JSV_NAME_STRING_INT_0 = JSV_NAME_INT_BOOL+1, // array/object index as string of length 0 WITH integer value
_JSV_STRING_START = JSV_NAME_STRING_INT_0,
JSV_NAME_STRING_INT_MAX = JSV_NAME_STRING_INT_0+JSVAR_DATA_STRING_NAME_LEN,
_JSV_NAME_WITH_VALUE_END = JSV_NAME_STRING_INT_MAX, ///< ---------- End of names that have literal values, NOT references, in firstChild
#ifdef ESPR_UNICODE_SUPPORT
JSV_NAME_UTF8_STRING, ///< UTF8 name that just points to a normal string with lastChild, but just tag that the string is a unicode one
#endif
JSV_NAME_STRING_0, // array/object index as string of length 0
JSV_NAME_STRING_MAX = JSV_NAME_STRING_0+JSVAR_DATA_STRING_NAME_LEN,
_JSV_NAME_END = JSV_NAME_STRING_MAX, ///< ---------- End of NAMEs (names of variables, object fields/etc)
JSV_STRING_0 = JSV_NAME_STRING_MAX+1, // simple string value of length 0
JSV_STRING_MAX = JSV_STRING_0+JSVAR_DATA_STRING_LEN,
JSV_FLAT_STRING = JSV_STRING_MAX+1, ///< Flat strings store the length (in chars) as an int, and then the subsequent JsVars (in memory) store data
JSV_NATIVE_STRING = JSV_FLAT_STRING+1, ///< Native strings store an address and length, and reference the underlying data directly
#ifdef ESPR_UNICODE_SUPPORT
JSV_UTF8_STRING, ///< UTF8 that just pointss to a normal string with lastChild, but just tag that the string is a unicode one
#endif
#ifdef SPIFLASH_BASE
JSV_FLASH_STRING, ///< Like a native String, but not writable and uses jshFlashRead
_JSV_STRING_END = JSV_FLASH_STRING,
#else
_JSV_STRING_END = JSV_NATIVE_STRING,
#endif
JSV_STRING_EXT_0 = _JSV_STRING_END+1, ///< extra character data for string (if it didn't fit in first JsVar). These use unused pointer fields for extra characters
JSV_STRING_EXT_MAX = JSV_STRING_EXT_0+JSVAR_DATA_STRING_MAX_LEN,
_JSV_VAR_END = JSV_STRING_EXT_MAX, ///< End of variable types
// _JSV_VAR_END is:
// 39 on systems with 8 bit JsVarRefs
// 43 on systems with 16 bit JsVarRefs
// 51 on systems with 32 bit JsVarRefs
// 81 on a 64 bit platform
JSV_VARTYPEMASK = NEXT_POWER_2(_JSV_VAR_END)-1, // probably this is 63
JSV_CONSTANT = JSV_VARTYPEMASK+1, ///< to specify if this variable is a constant or not. Only used for NAMEs
JSV_NATIVE = JSV_CONSTANT<<1, ///< to specify if this is a function parameter
JSV_GARBAGE_COLLECT = JSV_NATIVE<<1, ///< When garbage collecting, this flag is true IF we should GC!
JSV_IS_RECURSING = JSV_GARBAGE_COLLECT<<1, ///< used to stop recursive loops in jsvTrace
JSV_LOCK_ONE = JSV_IS_RECURSING<<1,
JSV_LOCK_MASK = JSV_LOCK_MAX * JSV_LOCK_ONE,
JSV_LOCK_SHIFT = GET_BIT_NUMBER(JSV_LOCK_ONE), ///< The amount of bits we must shift to get the number of locks - forced to be a constant
JSV_VARIABLEINFOMASK = JSV_VARTYPEMASK | JSV_NATIVE | JSV_CONSTANT, // if we're copying a variable, this is all the stuff we want to copy
} PACKED_FLAGS JsVarFlags; // aiming to get this in 2 bytes!
typedef enum {
ARRAYBUFFERVIEW_UNDEFINED = 0,
ARRAYBUFFERVIEW_MASK_SIZE = 15,
ARRAYBUFFERVIEW_SIGNED = 16,
ARRAYBUFFERVIEW_FLOAT = 32,
ARRAYBUFFERVIEW_CLAMPED = 64, // As in Uint8ClampedArray - clamp to the acceptable bounds
ARRAYBUFFERVIEW_ARRAYBUFFER = 1 | 128, ///< Basic ArrayBuffer type
ARRAYBUFFERVIEW_UINT8 = 1,
ARRAYBUFFERVIEW_INT8 = 1 | ARRAYBUFFERVIEW_SIGNED,
ARRAYBUFFERVIEW_UINT16 = 2,
ARRAYBUFFERVIEW_INT16 = 2 | ARRAYBUFFERVIEW_SIGNED,
ARRAYBUFFERVIEW_UINT24 = 3,
ARRAYBUFFERVIEW_UINT32 = 4,
ARRAYBUFFERVIEW_INT32 = 4 | ARRAYBUFFERVIEW_SIGNED,
ARRAYBUFFERVIEW_FLOAT32 = 4 | ARRAYBUFFERVIEW_FLOAT,
ARRAYBUFFERVIEW_FLOAT64 = 8 | ARRAYBUFFERVIEW_FLOAT,
} PACKED_FLAGS JsVarDataArrayBufferViewType;
#define JSV_ARRAYBUFFER_GET_SIZE(T) (size_t)((T)&ARRAYBUFFERVIEW_MASK_SIZE)
#define JSV_ARRAYBUFFER_IS_SIGNED(T) (((T)&ARRAYBUFFERVIEW_SIGNED)!=0)
#define JSV_ARRAYBUFFER_IS_FLOAT(T) (((T)&ARRAYBUFFERVIEW_FLOAT)!=0)
#define JSV_ARRAYBUFFER_IS_CLAMPED(T) (((T)&ARRAYBUFFERVIEW_CLAMPED)!=0)
#if JSVAR_DATA_NATIVESTR_LEN<8 // only enough space for a 16 bit length
typedef uint16_t JsVarDataNativeStrLength;
#define JSV_NATIVE_STR_MAX_LENGTH 65535
#else // enough space for 32 bits
typedef uint32_t JsVarDataNativeStrLength;
#define JSV_NATIVE_STR_MAX_LENGTH 0xFFFFFFFF
#endif
#if JSVAR_DATA_STRING_LEN<8 // only enough space for a 16 bit length
typedef uint16_t JsVarArrayBufferLength;
#define JSV_ARRAYBUFFER_MAX_LENGTH 65535
#define JSV_ARRAYBUFFER_LENGTH_BITS
#else // enough space for 24 bit length
typedef uint32_t JsVarArrayBufferLength;
#define JSV_ARRAYBUFFER_MAX_LENGTH 0xFFFFFF
#define JSV_ARRAYBUFFER_LENGTH_BITS : 24
#endif
/// Data for ArrayBuffers. Max size here is 6 bytes in most cases (4 byte data + 2x JsVarRef)
typedef struct {
unsigned short byteOffset;
JsVarArrayBufferLength length JSV_ARRAYBUFFER_LENGTH_BITS;
JsVarDataArrayBufferViewType type;
} PACKED_FLAGS JsVarDataArrayBufferView;
/// Data for native functions. Has to fit behind firstChild
typedef struct {
void (*ptr)(void); ///< Function pointer - this may not be the real address - see jsvGetNativeFunctionPtr
uint16_t argTypes; ///< Actually a list of JsnArgumentType
} PACKED_FLAGS JsVarDataNative;
/// Data for native strings. Has to fit behind refCount
typedef struct {
char *ptr;
JsVarDataNativeStrLength len;
} PACKED_FLAGS JsVarDataNativeStr;
/// References
typedef struct {
/* padding for data. Must be big enough for an int */
int8_t pad[JSVAR_DATA_STRING_NAME_LEN_]; // use JSVAR_DATA_STRING_NAME_LEN_ not JSVAR_DATA_STRING_NAME_LEN here so EMBED builds can handle 64 bit
/* For Variable NAMES (e.g. Object/Array keys) these store actual next/previous pointers for a linked list or 0.
* - if nextSibling==prevSibling==!0 then they point to the object that should contain this name if it ever gets set to anything that's not undefined
* For STRING_EXT - extra characters
* Not used for other stuff
*/
JsVarRef nextSibling : JSVARREF_BITS;
JsVarRef prevSibling : JSVARREF_BITS;
/**
* For OBJECT/ARRAY/FUNCTION - this is the first child
* For NAMES and REF - this is a link to the variable it points to
* For STRING_EXT - extra character data (NOT a link)
* For ARRAYBUFFER - a link to a string containing the data for the array buffer
* For CHILD_OF - a link to the variable pointed to
*/
JsVarRef firstChild : JSVARREF_BITS;
#if JSVARREFCOUNT_PACK_BITS
JsVarRef __packing : JSVARREFCOUNT_PACK_BITS;
#endif
/** The number of references held to this - used for automatic garbage collection. NOT USED for STRINGEXT though (it is just extra characters) */
JsVarRefCounter refs : JSVARREFCOUNT_BITS;
/**
* For OBJECT/ARRAY/FUNCTION - this is the last child
* For STRINGS/STRING_EXT/NAME+STRING - this is a link to more string data if it is needed
* For REF - this is the 'parent' that the firstChild is a member of
* For CHILD_OF - a link to the object that should contain the variable
*/
JsVarRef lastChild : JSVARREF_BITS;
} PACKED_FLAGS JsVarDataRef;
/** Union that contains all the different types of data. This should all
be JSVAR_DATA_STRING_MAX_LEN long.
*/
typedef union {
char str[JSVAR_DATA_STRING_MAX_LEN]; ///< The contents of this variable if it is a string
/* NOTE: For str above, we INTENTIONALLY OVERFLOW str (and hence data) in the case of STRING_EXTS
* to overwrite 3 references in order to grab another 6 bytes worth of string data */
JsVarInt integer; ///< The contents of this variable if it is an int
JsVarFloat floating; ///< The contents of this variable if it is a double
JsVarDataArrayBufferView arraybuffer; ///< information for array buffer views.
JsVarDataNative native; ///< A native function
JsVarDataNativeStr nativeStr; ///< A native string (or flash string)
JsVarDataRef ref; ///< References
} PACKED_FLAGS JsVarData;
typedef struct JsVarStruct {
/** The actual variable data, as well as references (see below). Put first so word aligned */
JsVarData varData;
/** the flags determine the type of the variable - int/double/string/etc. */
volatile JsVarFlags flags;
} PACKED_FLAGS JsVar;
/* We have a few different types:
*
* OBJECT/ARRAY - uses firstChild/lastChild to link to NAMEs.
* BUILT-IN OBJECT - as above, but we use varData to store the name as well. This means built in object names must be LESS THAN 8 CHARACTERS
* FUNCTION - uses firstChild/lastChild to link to NAMEs, and callback is used
* NAME - use nextSibling/prevSibling linking to other NAMEs, and firstChild to link to a Variable of some kind
* STRING - use firstChild to link to other STRINGs if String value is too long
* INT/DOUBLE - firstChild never used
*/
/* For 'normal' JsVars used on Espruino Board (Linux are different to allow more storage and 64 bit pointers):
Both INT and STRING can also be names:
The size of vars depends on how many variables we need to reference. The bits
for references are packed into a JsVarDataRef structure.
sizeof(JsVar) is between 10 and 16bytes depending on JSVARREF_BITS. As an example, for a 16 byte JsVar:
| Offset | Size | Name | STRING | STR_EXT | NAME_STR | NAME_INT | INT | DOUBLE | OBJ/FUNC/ARRAY | ARRAYBUFFER | NATIVE_STR | FLAT_STR |
| 16b | | | | | | | | | | | FLASH_STR | |
|--------|------|---------|--------|----------|----------|----------|------|---------|----------------|-------------|------------|----------|
| 0 - 3 | 4 | varData | data | data | data | data | data | data | nativePtr | size | ptr | charLen |
| 4 - 5 | ? | next | data | data | next | next | - | data | argTypes | format | len | - |
| 6 - 7 | ? | prev | data | data | prev | prev | - | data | argTypes | format | ..len | - |
| 8 - 9 | ? | first | data | data | child | child | - | data? | first | stringPtr | ..len | - |
| 10-11 | ? | refs | refs | data | refs | refs | refs | refs | refs | refs | refs | refs |
| 12-13 | ? | last | nextPtr| nextPtr | nextPtr | - | - | - | last | - | - | - |
| 14-15 | 2 | Flags | Flags | Flags | Flags | Flags | Flags| Flags | Flags | Flags | Flags | Flags |
* NAME_INT_INT/NAME_INT_BOOL are the same as NAME_INT, except 'child' contains the value rather than a pointer
* NAME_STRING_INT is the same as NAME_STRING, except 'child' contains the value rather than a pointer
* FLAT_STRING uses the variable blocks that follow it as flat storage for all the data
* NATIVE_FUNCTION's nativePtr is a pointer to code if there is no child called JSPARSE_FUNCTION_CODE_NAME, but if there is one, it's an index into that child
*
* For Objects that represent hardware devices, 'nativePtr' is actually set to a special string that
* contains the device number. See jsiGetDeviceFromClass/jspNewObject
*/
JSV_INLINEABLE JsVarRef jsvGetFirstChild(const JsVar *v);
JSV_INLINEABLE JsVarRefSigned jsvGetFirstChildSigned(const JsVar *v);
JSV_INLINEABLE JsVarRef jsvGetLastChild(const JsVar *v);
JSV_INLINEABLE JsVarRef jsvGetNextSibling(const JsVar *v);
JSV_INLINEABLE JsVarRef jsvGetPrevSibling(const JsVar *v);
JSV_INLINEABLE void jsvSetFirstChild(JsVar *v, JsVarRef r);
JSV_INLINEABLE void jsvSetLastChild(JsVar *v, JsVarRef r);
JSV_INLINEABLE void jsvSetNextSibling(JsVar *v, JsVarRef r);
JSV_INLINEABLE void jsvSetPrevSibling(JsVar *v, JsVarRef r);
JSV_INLINEABLE JsVarRefCounter jsvGetRefs(JsVar *v);
JSV_INLINEABLE void jsvSetRefs(JsVar *v, JsVarRefCounter refs);
JSV_INLINEABLE unsigned char jsvGetLocks(JsVar *v);
// For debugging/testing ONLY - maximum # of vars we are allowed to use
void jsvSetMaxVarsUsed(unsigned int size);
// Init/kill vars as a whole. If JSVAR_MALLOC is defined, a size can be specified (or 0 uses the old size)
void jsvInit(unsigned int size);
void jsvKill();
void jsvSoftInit(); ///< called when loading from flash
void jsvSoftKill(); ///< called when saving to flash
JsVar *jsvFindOrCreateRoot(); ///< Find or create the ROOT variable item - used mainly if recovering from a saved state.
unsigned int jsvGetMemoryUsage(); ///< Get number of memory records (JsVars) used
unsigned int jsvGetMemoryTotal(); ///< Get total amount of memory records
bool jsvIsMemoryFull(); ///< Get whether memory is full or not
bool jsvMoreFreeVariablesThan(unsigned int vars); ///< Return whether there are more free variables than the parameter (faster than checking no of vars used)
void jsvShowAllocated(); ///< Show what is still allocated, for debugging memory problems
/// Try and allocate more memory - only works if RESIZABLE_JSVARS is defined
void jsvSetMemoryTotal(unsigned int jsNewVarCount);
/// Scan memory to find any JsVar that references a specific memory range, and if so update what it points to to p[oint to the new address
void jsvUpdateMemoryAddress(size_t oldAddr, size_t length, size_t newAddr);
// Note that jsvNew* don't REF a variable for you, but the do LOCK it
JsVar *jsvNewWithFlags(JsVarFlags flags); ///< Create a new variable with the given flags
JsVar *jsvNewFlatStringOfLength(unsigned int byteLength); ///< Try and create a special flat string, return 0 on failure
JsVar *jsvNewFromString(const char *str); ///< Create a new string
JsVar *jsvNewNameFromString(const char *str); ///< Create a new name from a string
JsVar *jsvNewStringOfLength(unsigned int byteLength, const char *initialData); ///< Create a new string of the given length - full of 0s (or initialData if specified)
static ALWAYS_INLINE JsVar *jsvNewFromEmptyString() { return jsvNewWithFlags(JSV_STRING_0); } ;///< Create a new empty string
#ifdef ESPR_UNICODE_SUPPORT
JsVar *jsvNewUTF8String(JsVar* dataString); ///< Create a new unicode string using the given data string for backing
JsVar *jsvNewUTF8StringAndUnLock(JsVar* dataString); ///< Create a new unicode string using the given data string for backing
#endif
static ALWAYS_INLINE JsVar *jsvNewNull() { return jsvNewWithFlags(JSV_NULL); } ;///< Create a new null variable
/** Create a new variable from a substring. argument must be a string. stridx = start char or str, maxLength = max number of characters (can be JSVAPPENDSTRINGVAR_MAXLENGTH) */
JsVar *jsvNewFromStringVar(const JsVar *str, size_t stridx, size_t maxLength);
JsVar *jsvNewFromStringVarComplete(JsVar *var);
JsVar *jsvNewFromInteger(JsVarInt value);
JsVar *jsvNewFromBool(bool value);
JsVar *jsvNewFromFloat(JsVarFloat value);
/// Create an integer (or float) from this value, depending on whether it'll fit in 32 bits or not.
JsVar *jsvNewFromLongInteger(long long value);
JsVar *jsvNewObject(); ///< Create a new object
JsVar *jsvNewEmptyArray(); ///< Create a new array
JsVar *jsvNewArray(JsVar **elements, int elementCount); ///< Create an array containing the given elements
JsVar *jsvNewArrayFromBytes(uint8_t *elements, int elementCount); ///< Create an array containing the given bytes
JsVar *jsvNewNativeFunction(void (*ptr)(void), unsigned short argTypes); ///< Create an array containing the given elements
JsVar *jsvNewNativeString(char *ptr, size_t len); ///< Create a Native String pointing to the given memory area
#ifdef SPIFLASH_BASE
JsVar *jsvNewFlashString(char *ptr, size_t len); ///< Create a Flash String pointing to the given memory area
#endif
JsVar *jsvNewArrayBufferFromString(JsVar *str, unsigned int lengthOrZero); ///< Create a new ArrayBuffer backed by the given string. If length is not specified, it will be worked out
#ifndef ESPR_EMBED
JsVar *jsvNewFromPin(int pin);
#endif
/// Turns var into a Variable name that links to the given value (or return a new var that is a name)... No need for the caller to unlock var.
JsVar *jsvMakeIntoVariableName(JsVar *var, JsVar *valueOrZero);
/// Turns var into a 'function parameter' that the parser recognises when parsing a function
JsVar *jsvMakeFunctionParameter(JsVar *v);
/// Add a new function parameter to a function (name may be 0) - use this when binding function arguments This unlocks paramName if specified, but not value.
void jsvAddFunctionParameter(JsVar *fn, JsVar *name, JsVar *value);
void *jsvGetNativeFunctionPtr(const JsVar *function); ///< Get the actual pointer from a native function - this may not be the contents of varData.native.ptr
/// Get a reference from a var - SAFE for null vars
JSV_INLINEABLE JsVarRef jsvGetRef(JsVar *var);
/// SCARY - only to be used for vital stuff like load/save
JSV_INLINEABLE JsVar *_jsvGetAddressOf(JsVarRef ref);
/// Lock this reference and return a pointer - UNSAFE for null refs
JSV_INLINEABLE JsVar *jsvLock(JsVarRef ref);
/// Lock this reference and return a pointer, or 0
JsVar *jsvLockSafe(JsVarRef ref);
/// Lock this pointer and return a pointer - UNSAFE for null pointer
JSV_INLINEABLE JsVar *jsvLockAgain(JsVar *var);
/// Lock this pointer and return a pointer - SAFE for null pointer
JSV_INLINEABLE JsVar *jsvLockAgainSafe(JsVar *var);
/// Unlock this variable - this is SAFE for null variables
JSV_INLINEABLE void jsvUnLock(JsVar *var);
/// Unlock 2 variables in one go
NO_INLINE void jsvUnLock2(JsVar *var1, JsVar *var2);
/// Unlock 3 variables in one go
NO_INLINE void jsvUnLock3(JsVar *var1, JsVar *var2, JsVar *var3);
/// Unlock 4 variables in one go
NO_INLINE void jsvUnLock4(JsVar *var1, JsVar *var2, JsVar *var3, JsVar *var4);
/// Unlock an array of variables
NO_INLINE void jsvUnLockMany(unsigned int count, JsVar **vars);
/// Reference - set this variable as used by something
JsVar *jsvRef(JsVar *v);
/// Unreference - set this variable as not used by anything
void jsvUnRef(JsVar *var);
/// Helper fn, Reference - set this variable as used by something
JsVarRef jsvRefRef(JsVarRef ref);
/// Helper fn, Unreference - set this variable as not used by anything
JsVarRef jsvUnRefRef(JsVarRef ref);
bool jsvIsRoot(const JsVar *v);
bool jsvIsPin(const JsVar *v);
bool jsvIsSimpleInt(const JsVar *v); ///< is just a very basic integer value
bool jsvIsInt(const JsVar *v);
bool jsvIsFloat(const JsVar *v);
bool jsvIsBoolean(const JsVar *v);
bool jsvIsString(const JsVar *v); ///< String, or a NAME too
bool jsvIsUTF8String(const JsVar *v); ///< Just a unicode string (UTF8 JsVar, pointing to a string)
bool jsvIsBasicString(const JsVar *v); ///< Just a string (NOT a name)
bool jsvIsStringExt(const JsVar *v); ///< The extra bits dumped onto the end of a string to store more data
bool jsvIsFlatString(const JsVar *v);
bool jsvIsNativeString(const JsVar *v);
bool jsvIsConstant(const JsVar *v);
bool jsvIsFlashString(const JsVar *v);
bool jsvIsNumeric(const JsVar *v);
bool jsvIsFunction(const JsVar *v);
bool jsvIsFunctionReturn(const JsVar *v); ///< Is this a function with an implicit 'return' at the start?
bool jsvIsFunctionParameter(const JsVar *v);
bool jsvIsObject(const JsVar *v);
bool jsvIsArray(const JsVar *v);
bool jsvIsArrayBuffer(const JsVar *v);
bool jsvIsArrayBufferName(const JsVar *v);
bool jsvIsNativeFunction(const JsVar *v);
bool jsvIsUndefined(const JsVar *v);
bool jsvIsNull(const JsVar *v);
bool jsvIsNullish(const JsVar *v);
bool jsvIsBasic(const JsVar *v); ///< Is this *not* an array/object/etc
bool jsvIsName(const JsVar *v); ///< NAMEs are what's used to name a variable (it is not the data itself)
bool jsvIsBasicName(const JsVar *v); ///< Simple NAME that links to a variable via firstChild
/// Names with values have firstChild set to a value - AND NOT A REFERENCE
bool jsvIsNameWithValue(const JsVar *v);
bool jsvIsNameInt(const JsVar *v); ///< Is this a NAME pointing to an Integer value
bool jsvIsNameIntInt(const JsVar *v);
bool jsvIsNameIntBool(const JsVar *v);
/// What happens when we access a variable that doesn't exist. We get a NAME where the next + previous siblings point to the object that may one day contain them
bool jsvIsNewChild(const JsVar *v);
/// Returns true if v is a getter/setter
bool jsvIsGetterOrSetter(const JsVar *v);
/// Are var.varData.ref.* (excl pad) used for data (so we expect them not to be empty)
bool jsvIsRefUsedForData(const JsVar *v);
/// Can the given variable be converted into an integer without loss of precision
bool jsvIsIntegerish(const JsVar *v);
bool jsvIsIterable(const JsVar *v);
/** Does this string contain only Numeric characters (with optional whitespace and/or '-'/'+' at the front)? NOT '.'/'e' and similar (allowDecimalPoint is for '.' only) */
bool jsvIsStringNumericInt(const JsVar *var, bool allowDecimalPoint);
/** Does this string contain only Numeric characters? This is for arrays
* and makes the assertion that int_to_string(string_to_int(var))==var */
bool jsvIsStringNumericStrict(const JsVar *var);
// TODO: maybe isName shouldn't include ArrayBufferName?
bool jsvHasCharacterData(const JsVar *v); ///< does the v->data union contain character data?
/// Does this variable use lastChild to point to a StringExt?
bool jsvHasStringExt(const JsVar *v);
/// Does this variable use firstChild/lastChild to point to multiple children
bool jsvHasChildren(const JsVar *v);
/// Is this variable a type that uses firstChild to point to a single Variable (ie. it doesn't have multiple children)
bool jsvHasSingleChild(const JsVar *v);
/// See jsvIsNewChild - for fields that don't exist yet
JsVar *jsvCreateNewChild(JsVar *parent, JsVar *index, JsVar *child);
/// Does this variable have a 'ref' argument? Stringexts use it for extra character data
static ALWAYS_INLINE bool jsvHasRef(const JsVar *v) { return !jsvIsStringExt(v); }
/** Return the is the number of characters this one JsVar can contain, NOT string length (eg, a chain of JsVars)
* This will return an invalid length when applied to Flat Strings */
size_t jsvGetMaxCharactersInVar(const JsVar *v);
/// This is the number of characters a JsVar can contain, NOT string length
size_t jsvGetCharactersInVar(const JsVar *v);
/// This is the number of characters a JsVar can contain, NOT string length
void jsvSetCharactersInVar(JsVar *v, size_t chars);
/** Check if two Basic Variables are equal (this IGNORES the value that is pointed to,
* so 'a=5'=='a=7' but 'a=5'!='b=5')
*/
bool jsvIsBasicVarEqual(JsVar *a, JsVar *b);
/** Check if two things are equal. Basic vars are done by value,
* for anything else the reference/pointer must be equal */
bool jsvIsEqual(JsVar *a, JsVar *b);
const char *jsvGetConstString(const JsVar *v); ///< Get a const string representing this variable - if we can. Otherwise return 0
const char *jsvGetTypeOf(const JsVar *v); ///< Return the 'type' of the JS variable (eg. JS's typeof operator)
JsVar *jsvGetValueOf(JsVar *v); ///< Return the JsVar, or if it's an object and has a valueOf function, call that
/** Save this var as a string to the given buffer, and return how long it was (return val doesn't include terminating 0)
If the buffer length is exceeded, the returned value will == len */
size_t jsvGetString(const JsVar *v, char *str, size_t len);
size_t jsvGetStringChars(const JsVar *v, size_t startChar, char *str, size_t len); ///< Get len bytes of string data from this string. Does not error if string len is not equal to len, no terminating 0
void jsvSetString(JsVar *v, const char *str, size_t len); ///< Set the Data in this string. This must JUST overwrite - not extend or shrink
JsVar *jsvAsString(JsVar *var); ///< If var is a string, lock and return it, else create a new string
JsVar *jsvAsStringAndUnLock(JsVar *var); ///< Same as jsvAsString, but unlocks 'var'
JsVar *jsvAsFlatString(JsVar *var); ///< Create a flat string from the given variable (or return it if it is already a flat string). NOTE: THIS CONVERTS VIA A STRING
bool jsvIsEmptyString(JsVar *v); ///< Returns true if the string is empty - faster than jsvGetStringLength(v)==0
size_t jsvGetStringLength(const JsVar *v); ///< Get the length of this string, IF it is a string
size_t jsvGetFlatStringBlocks(const JsVar *v); ///< return the number of blocks used by the given flat string - EXCLUDING the first data block
char *jsvGetFlatStringPointer(JsVar *v); ///< Get a pointer to the data in this flat string
JsVar *jsvGetFlatStringFromPointer(char *v); ///< Given a pointer to the first element of a flat string, return the flat string itself (DANGEROUS!)
char *jsvGetDataPointer(JsVar *v, size_t *len); ///< If the variable points to a *flat* area of memory, return a pointer (and set length). Otherwise return 0.
size_t jsvGetLinesInString(JsVar *v); ///< IN A STRING get the number of lines in the string (min=1)
size_t jsvGetCharsOnLine(JsVar *v, size_t line); ///< IN A STRING Get the number of characters on a line - lines start at 1
void jsvGetLineAndCol(JsVar *v, size_t charIdx, size_t *line, size_t *col); ///< IN A STRING, get the 1-based line and column of the given character. Both values must be non-null
size_t jsvGetIndexFromLineAndCol(JsVar *v, size_t line, size_t col); ///< IN A STRING, get a character index from a line and column
/// Like jsvIsStringEqualOrStartsWith, but starts comparing at some offset (not the beginning of the string)
bool jsvIsStringEqualOrStartsWithOffset(JsVar *var, const char *str, bool isStartsWith, size_t startIdx, bool ignoreCase);
/**
Compare a string with a C string. Returns 0 if A is not a string.
`jsvIsStringEqualOrStartsWith(A, B, false)` is a proper `A==B`
`jsvIsStringEqualOrStartsWith(A, B, true)` is `A.startsWith(B)`
*/
bool jsvIsStringEqualOrStartsWith(JsVar *var, const char *str, bool isStartsWith);
bool jsvIsStringEqual(JsVar *var, const char *str); ///< is string equal. see jsvIsStringEqualOrStartsWith
bool jsvIsStringIEqualAndUnLock(JsVar *var, const char *str); ///< is string equal (ignoring case). see jsvIsStringEqualOrStartsWithOffset
int jsvCompareString(JsVar *va, JsVar *vb, size_t starta, size_t startb, bool equalAtEndOfString); ///< Compare 2 strings, starting from the given character positions
/// Return a new string containing just the characters that are shared between two strings.
JsVar *jsvGetCommonCharacters(JsVar *va, JsVar *vb);
int jsvCompareInteger(JsVar *va, JsVar *vb); ///< Compare 2 integers, >0 if va>vb, <0 if va<vb. If compared with a non-integer, that gets put later
void jsvAppendString(JsVar *var, const char *str); ///< Append the given string to this one
void jsvAppendStringBuf(JsVar *var, const char *str, size_t length); ///< Append the given string to this one - but does not use null-terminated strings
void jsvAppendPrintf(JsVar *var, const char *fmt, ...); ///< Append the formatted string to a variable (see vcbprintf)
JsVar *jsvVarPrintf( const char *fmt, ...); ///< Create a var from the formatted string
static ALWAYS_INLINE void jsvAppendCharacter(JsVar *var, char ch) { jsvAppendStringBuf(var, &ch, 1); }; ///< Append the given character to this string
#ifdef ESPR_UNICODE_SUPPORT
///< Append the given UTF8 character to this string
static ALWAYS_INLINE void jsvAppendUTF8Character(JsVar *var, int ch) {
char utf8buf[4];
unsigned int utf8len = jsUTF8Encode(ch, utf8buf);
jsvAppendStringBuf(var, utf8buf, utf8len);
}
#endif
#define JSVAPPENDSTRINGVAR_MAXLENGTH (0x7FFFFFFF)
void jsvAppendStringVar(JsVar *var, const JsVar *str, size_t stridx, size_t maxLength); ///< Append str to var. Both must be strings. stridx = start char or str, maxLength = max number of characters (can be JSVAPPENDSTRINGVAR_MAXLENGTH)
void jsvAppendStringVarComplete(JsVar *var, const JsVar *str); ///< Append all of str to var. Both must be strings.
int jsvGetCharInString(JsVar *v, size_t idx); ///< Get a character at the given index in the String (handles unicode)
void jsvSetCharInString(JsVar *v, size_t idx, char ch, bool bitwiseOR); ///< Set a character at the given index in the String. If bitwiseOR, ch will be ORed with the character already at that position.
int jsvGetStringIndexOf(JsVar *str, char ch); ///< Get the index of a character in a string, or -1
#ifdef ESPR_UNICODE_SUPPORT
/// If we have a UTF8 string return the string behind it, or just return what was passed in
JsVar *jsvGetUTF8BackingString(JsVar *str);
/// Converts the given string of bytes to UTF8 encoding. Doesn't tag the resulting string with UTF8 though
JsVar *jsvConvertToUTF8AndUnLock(JsVar *str);
#endif
/// Convert an UTF8 index in a String to a String index in the backing String. THIS IS SLOW. On non-UTF8 builds it passes straight through
int jsvConvertFromUTF8Index(JsVar *str, int idx);
/// Convert a String index in the backing String into a UTF8 index in a String. THIS IS SLOW. On non-UTF8 builds it passes straight through
int jsvConvertToUTF8Index(JsVar *str, int idx);
JsVarInt jsvGetInteger(const JsVar *v);
void jsvSetInteger(JsVar *v, JsVarInt value); ///< Set an integer value (use carefully!)
JsVarFloat jsvGetFloat(const JsVar *v); ///< Get the floating point representation of this var
bool jsvGetBool(const JsVar *v);
long long jsvGetLongInteger(const JsVar *v);
JsVar *jsvAsNumber(JsVar *var); ///< Convert the given variable to a number
JsVar *jsvAsNumberAndUnLock(JsVar *v); ///< Convert the given variable to a number, unlock v after
static ALWAYS_INLINE JsVarInt _jsvGetIntegerAndUnLock(JsVar *v) { JsVarInt i = jsvGetInteger(v); jsvUnLock(v); return i; }
static ALWAYS_INLINE JsVarFloat _jsvGetFloatAndUnLock(JsVar *v) { JsVarFloat f = jsvGetFloat(v); jsvUnLock(v); return f; }
static ALWAYS_INLINE bool _jsvGetBoolAndUnLock(JsVar *v) { bool b = jsvGetBool(v); jsvUnLock(v); return b; }
JsVarInt jsvGetIntegerAndUnLock(JsVar *v);
JsVarFloat jsvGetFloatAndUnLock(JsVar *v);
bool jsvGetBoolAndUnLock(JsVar *v);
long long jsvGetLongIntegerAndUnLock(JsVar *v);
#ifndef ESPR_NO_GET_SET
// Executes the given getter, or if there are problems returns undefined
JsVar *jsvExecuteGetter(JsVar *parent, JsVar *getset);
// Executes the given setter
void jsvExecuteSetter(JsVar *parent, JsVar *getset, JsVar *value);
/// Add a named getter or setter to an object
void jsvAddGetterOrSetter(JsVar *obj, JsVar *varName, bool isGetter, JsVar *method);
#endif
/* Set the value of the given variable. This is sort of like
* jsvSetValueOfName except it deals with all the non-standard
* stuff like ArrayBuffers, variables that haven't been allocated
* yet, setters, etc.
*/
void jsvReplaceWith(JsVar *dst, JsVar *src);
/* See jsvReplaceWith - this does the same but will
* shove the variable in execInfo.root if it hasn't
* been defined yet */
void jsvReplaceWithOrAddToRoot(JsVar *dst, JsVar *src);
/** Get the item at the given location in the array buffer and return the result */
size_t jsvGetArrayBufferLength(const JsVar *arrayBuffer);
/** Get the String the contains the data for this arrayBuffer. Is ok with being passed a String in the first place. Offset is the offset in the backing string of this arraybuffer. */
JsVar *jsvGetArrayBufferBackingString(JsVar *arrayBuffer, uint32_t *offset);
/** Get the item at the given location in the array buffer and return the result */
JsVar *jsvArrayBufferGet(JsVar *arrayBuffer, size_t index);
/** Set the item at the given location in the array buffer */
void jsvArrayBufferSet(JsVar *arrayBuffer, size_t index, JsVar *value);
/** Given an integer name that points to an arraybuffer or an arraybufferview, evaluate it and return the result */
JsVar *jsvArrayBufferGetFromName(JsVar *name);
/** Return an array containing the arguments of the given function */
JsVar *jsvGetFunctionArgumentLength(JsVar *function);
/** Is this variable actually defined? eg, can we pass it into `jsvSkipName`
* without getting a ReferenceError? This also returns false if the variable
* if ok, but has the value `undefined`. */
bool jsvIsVariableDefined(JsVar *a);
/* If this is a simple name (that links to another var) the
* return that var, else 0. */
JsVar *jsvGetValueOfName(JsVar *name);
/* Check for and trigger a ReferenceError on a variable if it's a name that doesn't exist */
void jsvCheckReferenceError(JsVar *a);
/** If a is a name skip it and go to what it points to - and so on (if repeat=true).
* ALWAYS locks - so must unlock what it returns. It MAY
* return 0. Throws a ReferenceError if variable is not defined,
* but you can check if it will with jsvIsReferenceError */
JsVar *jsvSkipNameWithParent(JsVar *a, bool repeat, JsVar *parent);
/** If a is a name skip it and go to what it points to - and so on.
* ALWAYS locks - so must unlock what it returns. It MAY
* return 0. Throws a ReferenceError if variable is not defined,
* but you can check if it will with jsvIsReferenceError */
JsVar *jsvSkipName(JsVar *a);
/** If a is a name skip it and go to what it points to.
* ALWAYS locks - so must unlock what it returns. It MAY
* return 0. Throws a ReferenceError if variable is not defined,
* but you can check if it will with jsvIsReferenceError */
JsVar *jsvSkipOneName(JsVar *a);
/** If a is a's child is a name skip it and go to what it points to.
* ALWAYS locks - so must unlock what it returns. */
JsVar *jsvSkipToLastName(JsVar *a);
/** Same as jsvSkipName, but ensures that 'a' is unlocked */
JsVar *jsvSkipNameAndUnLock(JsVar *a);
/** Same as jsvSkipOneName, but ensures that 'a' is unlocked */
JsVar *jsvSkipOneNameAndUnLock(JsVar *a);
/** Given a JsVar meant to be an index to an array, convert it to
* the actual variable type we'll use to access the array. For example
* a["0"] is actually translated to a[0]
*/
JsVar *jsvAsArrayIndex(JsVar *index);
/** Same as jsvAsArrayIndex, but ensures that 'index' is unlocked */
JsVar *jsvAsArrayIndexAndUnLock(JsVar *a);
/** Try and turn the supplied variable into a name. If not, make a new one. The result is locked but
* the parameter should still be unlocked by the caller. */
JsVar *jsvAsName(JsVar *var);
/// MATHS!
JsVar *jsvMathsOpSkipNames(JsVar *a, JsVar *b, int op);
bool jsvMathsOpTypeEqual(JsVar *a, JsVar *b);
JsVar *jsvMathsOp(JsVar *a, JsVar *b, int op);
/// Negates an integer/double value
JsVar *jsvNegateAndUnLock(JsVar *v);
/** If the given element is found, return the path to it as a string of
* the form 'foo.bar', else return 0. If we would have returned a.b and
* ignoreParent is a, don't! */
JsVar *jsvGetPathTo(JsVar *root, JsVar *element, int maxDepth, JsVar *ignoreParent);
/// Copy this variable and return the locked copy
JsVar *jsvCopy(JsVar *src, bool copyChildren);
/** Copy only a name, not what it points to. ALTHOUGH the link to what it points to is maintained unless linkChildren=false.
If keepAsName==false, this will be converted into a normal variable */
JsVar *jsvCopyNameOnly(JsVar *src, bool linkChildren, bool keepAsName);
/// Tree related stuff
void jsvAddName(JsVar *parent, JsVar *nameChild); // Add a child, which is itself a name
JsVar *jsvAddNamedChild(JsVar *parent, JsVar *value, const char *name); // Add a child, and create a name for it. Returns a LOCKED var. DOES NOT CHECK FOR DUPLICATES
void jsvAddNamedChildAndUnLock(JsVar *parent, JsVar *value, const char *name); // Add a child, and create a name for it AND unlock the value and name. DOES NOT CHECK FOR DUPLICATES
JsVar *jsvSetValueOfName(JsVar *name, JsVar *src); // Set the value of a child created with jsvAddName,jsvAddNamedChild. Returns the UNLOCKED name argument
JsVar *jsvFindChildFromString(JsVar *parent, const char *name); // Non-recursive finding of child with name. Returns a LOCKED var
JsVar *jsvFindOrAddChildFromString(JsVar *parent, const char *name); // Non-recursive finding of child with name. Returns a LOCKED var
JsVar *jsvFindChildFromStringI(JsVar *parent, const char *name); ///< Find a child with a matching name using a case insensitive search
JsVar *jsvFindChildFromVar(JsVar *parent, JsVar *childName, bool addIfNotFound); ///< Non-recursive finding of child with name. Returns a LOCKED var
/// Remove a child - note that the child MUST ACTUALLY BE A CHILD! and should be a name, not a value.
void jsvRemoveChild(JsVar *parent, JsVar *child);
/// See jsvRemoveChild (this just unlocks child after)
void jsvRemoveChildAndUnLock(JsVar *parent, JsVar *child);
void jsvRemoveAllChildren(JsVar *parent);
/// Get the named child of an object. If createChild!=0 then create the child
JsVar *jsvObjectGetChild(JsVar *obj, const char *name, JsVarFlags createChild);
/// Get the named child of an object, or return 0
JsVar *jsvObjectGetChildIfExists(JsVar *obj, const char *name);
/// Get the named child of an object using a case-insensitive search
JsVar *jsvObjectGetChildI(JsVar *obj, const char *name);
/// Same as jsvGetBoolAndUnLock(jsvObjectGetChildIfExists(obj, name))
bool jsvObjectGetBoolChild(JsVar *obj, const char *name);
/// Same as jsvGetIntegerAndUnLock(jsvObjectGetChildIfExists(obj, name))
JsVarInt jsvObjectGetIntegerChild(JsVar *obj, const char *name);
/// Same as jsvGetFloatAndUnLock(jsvObjectGetChildIfExists(obj, name))
JsVarFloat jsvObjectGetFloatChild(JsVar *obj, const char *name);
/// Set the named child of an object, and return the child (so you can choose to unlock it if you want)
JsVar *jsvObjectSetChild(JsVar *obj, const char *name, JsVar *child);
/// Set the named child of an object, and return the child (so you can choose to unlock it if you want)
JsVar *jsvObjectSetChildVar(JsVar *obj, JsVar *name, JsVar *child);
/// Set the named child of an object, and unlock the child
void jsvObjectSetChildAndUnLock(JsVar *obj, const char *name, JsVar *child);
/// Remove the named child of an Object
void jsvObjectRemoveChild(JsVar *parent, const char *name);
/** Set the named child of an object, and return the child (so you can choose to unlock it if you want).
* If the child is 0, the 'name' is also removed from the object */
JsVar *jsvObjectSetOrRemoveChild(JsVar *obj, const char *name, JsVar *child);
/** Append all keys from the source object to the target object. Will ignore hidden/internal fields */
void jsvObjectAppendAll(JsVar *target, JsVar *source);
int jsvGetChildren(const JsVar *v); ///< number of children of a variable. also see jsvGetArrayLength and jsvGetLength
JsVar *jsvGetFirstName(JsVar *v); ///< Get the first child's name from an object,array or function
/// Check if the given name is a child of the parent
bool jsvIsChild(JsVar *parent, JsVar *child);
JsVarInt jsvGetArrayLength(const JsVar *arr); ///< Not the same as GetChildren, as it can be a sparse array
JsVarInt jsvSetArrayLength(JsVar *arr, JsVarInt length, bool truncate); ///< set an array's length, optionally truncating if the array becomes shorter
JsVarInt jsvGetLength(const JsVar *src); ///< General purpose length function. Does the 'right' thing
size_t jsvCountJsVarsUsed(JsVar *v); ///< Count the amount of JsVars used. Mostly useful for debugging
JsVar *jsvGetArrayIndex(const JsVar *arr, JsVarInt index); ///< Get a 'name' at the specified index in the array if it exists (and lock it)
JsVar *jsvGetArrayItem(const JsVar *arr, JsVarInt index); ///< Get an item at the specified index in the array if it exists (and lock it)
JsVar *jsvGetLastArrayItem(const JsVar *arr); ///< Returns the last item in the given array (with string OR numeric index)
void jsvSetArrayItem(JsVar *arr, JsVarInt index, JsVar *item); ///< Set an array item at the specified index in the array
void jsvGetArrayItems(JsVar *arr, unsigned int itemCount, JsVar **itemPtr); ///< Get all elements from arr and put them in itemPtr (unless it'd overflow). Makes sure all of itemPtr either contains a JsVar or 0
JsVar *jsvGetIndexOfFull(JsVar *arr, JsVar *value, bool matchExact, bool matchIntegerIndices, int startIdx); ///< Get the index of the value in the array (matchExact==use pointer not equality check, matchIntegerIndices = don't check non-integers)
JsVar *jsvGetIndexOf(JsVar *arr, JsVar *value, bool matchExact); ///< Get the index of the value in the array or object (matchExact==use pointer, not equality check)
JsVarInt jsvArrayAddToEnd(JsVar *arr, JsVar *value, JsVarInt initialValue); ///< Adds new elements to the end of an array, and returns the new length. initialValue is the item index when no items are currently in the array.
JsVarInt jsvArrayPush(JsVar *arr, JsVar *value); ///< Adds a new element to the end of an array, and returns the new length
JsVarInt jsvArrayPushAndUnLock(JsVar *arr, JsVar *value); ///< Adds a new element to the end of an array, unlocks it, and returns the new length
JsVarInt jsvArrayPushString(JsVar *arr, const char *string); ///< Adds a new String element to the end of an array, and returns the new length. Same as jsvArrayPushAndUnLock(arr, jsvNewFromString(str))
void jsvArrayPush2Int(JsVar *arr, JsVarInt a, JsVarInt b); ///< Push 2 integers onto the end of an array
void jsvArrayPushAll(JsVar *target, JsVar *source, bool checkDuplicates); ///< Append all values from the source array to the target array
JsVar *jsvArrayPop(JsVar *arr); ///< Removes the last element of an array, and returns that element (or 0 if empty). includes the NAME
JsVar *jsvArrayPopFirst(JsVar *arr); ///< Removes the first element of an array, and returns that element (or 0 if empty) includes the NAME. DOES NOT RENUMBER.
void jsvArrayAddUnique(JsVar *arr, JsVar *v); ///< Adds a new variable element to the end of an array (IF it was not already there). Return true if successful
JsVar *jsvArrayJoin(JsVar *arr, JsVar *filler, bool ignoreNull); ///< Join all elements of an array together into a string
void jsvArrayInsertBefore(JsVar *arr, JsVar *beforeIndex, JsVar *element); ///< Insert a new element before beforeIndex, DOES NOT UPDATE INDICES
static ALWAYS_INLINE bool jsvArrayIsEmpty(JsVar *arr) { assert(jsvIsArray(arr)); return !jsvGetFirstChild(arr); } ///< Return true is array is empty
/** Write debug info for this Var out to the console */
void jsvTrace(JsVar *var, int indent);
/** Run a garbage collection sweep - return nonzero if things have been freed */
int jsvGarbageCollect();
/** Defragement memory - this could take a while with interrupts turned off! */
void jsvDefragment();
// Dump any locked variables that aren't referenced from `global` - for debugging memory leaks
void jsvDumpLockedVars();
// Dump the free list - in order
void jsvDumpFreeList();
/** Remove whitespace to the right of a string - on MULTIPLE LINES */
JsVar *jsvStringTrimRight(JsVar *srcString);
typedef bool (*JsvIsInternalChecker)(JsVar*);
/** If v is the key of a function, return true if it is internal and shouldn't be visible to the user */
bool jsvIsInternalFunctionKey(JsVar *v);
/// If v is the key of an object, return true if it is internal and shouldn't be visible to the user
bool jsvIsInternalObjectKey(JsVar *v);
/// Get the correct checker function for the given variable. see jsvIsInternalFunctionKey/jsvIsInternalObjectKey
JsvIsInternalChecker jsvGetInternalFunctionCheckerFor(JsVar *v);
/// See jsvReadConfigObject
typedef struct {
char *name; ///< The name of the option to search for
JsVarFlags type; ///< The type of ptr - JSV_PIN/BOOLEAN/INTEGER/FLOAT or JSV_OBJECT for a variable
void *ptr; ///< A pointer to the variable to set
} jsvConfigObject;
/** Using 'configs', this reads 'object' into the given pointers, returns true on success.
* If object is not undefined and not an object, an error is raised.
* If there are fields that are not in the list of configs, an error is raised
*/
bool jsvReadConfigObject(JsVar *object, jsvConfigObject *configs, int nConfigs);
/** Using data in the format passed to jsvReadConfigObject, reconstruct a new object */
JsVar *jsvCreateConfigObject(jsvConfigObject *configs, int nConfigs);
/// Is the variable an instance of the given class. Eg. `jsvIsInstanceOf(e, "Error")` - does a simple, non-recursive check that doesn't take account of builtins like String
bool jsvIsInstanceOf(JsVar *var, const char *constructorName);
/// Create a new typed array of the given type and length
JsVar *jsvNewTypedArray(JsVarDataArrayBufferViewType type, JsVarInt length);
/// Create a new DataView of the given length (in elements), and fill it with the given data (if set)
JsVar *jsvNewDataViewWithData(JsVarInt length, unsigned char *data);
/** Create a new arraybuffer of the given type and length, also return a pointer
* to the contiguous memory area containing it. Returns 0 if it was unable to
* allocate it. */
JsVar *jsvNewArrayBufferWithPtr(unsigned int length, char **ptr);
/** create an arraybuffer containing the given data - this allocates new memory and copies 'data' */
JsVar *jsvNewArrayBufferWithData(JsVarInt length, unsigned char *data);
/** Allocate a flat area of memory inside Espruino's Variable storage space.
* This may return 0 on failure.
*
* **Note:** Memory allocated this way MUST be freed before `jsvKill` is called
* (eg. when saving, loading, resetting). To do this, use a JSON wrapper for
* 'kill' (and one for 'init' if you need to allocate at startup)
*/
void *jsvMalloc(size_t size);
/** Deallocate a flat area of memory allocated by jsvMalloc. See jsvMalloc
* for more information. */
void jsvFree(void *ptr);
/** Get the given JsVar as a character array. If it's a flat string, return a
* pointer to it, or if it isn't allocate data on the stack and copy the data.
*
* This has to be a macro - if alloca is called from within another function
* the data will be lost when we return. */
#define JSV_GET_AS_CHAR_ARRAY(TARGET_PTR, TARGET_LENGTH, DATA) \
size_t TARGET_LENGTH = 0; \
char *TARGET_PTR = jsvGetDataPointer(DATA, &TARGET_LENGTH); \
if (DATA && !TARGET_PTR) { \
TARGET_LENGTH = (size_t)jsvIterateCallbackCount(DATA); \
if (TARGET_LENGTH+256 > jsuGetFreeStack()) { \
jsExceptionHere(JSET_ERROR, "Not enough stack memory for data"); \
} else { \
TARGET_PTR = (char *)alloca(TARGET_LENGTH); \
jsvIterateCallbackToBytes(DATA, (unsigned char *)TARGET_PTR, \
(unsigned int)TARGET_LENGTH); \
} \
}
#if defined(JSVAR_MALLOC)
extern unsigned int jsVarsSize;
extern JsVar *jsVars;
#endif
#endif /* JSVAR_H_ */