jsutils.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. /*
  2. * This file is part of Espruino, a JavaScript interpreter for Microcontrollers
  3. *
  4. * Copyright (C) 2013 Gordon Williams <gw@pur3.co.uk>
  5. *
  6. * This Source Code Form is subject to the terms of the Mozilla Public
  7. * License, v. 2.0. If a copy of the MPL was not distributed with this
  8. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  9. *
  10. * ----------------------------------------------------------------------------
  11. * Misc utils and cheapskate stdlib implementation
  12. * ----------------------------------------------------------------------------
  13. */
  14. #ifndef JSUTILS_H_
  15. #define JSUTILS_H_
  16. #include "platform_config.h"
  17. #ifndef FAKE_STDLIB
  18. #include <string.h>
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #endif
  22. #include <stdarg.h> // for va_args
  23. #define JS_VERSION "1v46"
  24. /*
  25. In code:
  26. TODO - should be fixed
  27. FIXME - will probably break if used
  28. OPT - potential for speed optimisation
  29. */
  30. // surely bool is defined??
  31. #ifdef RT_USING_JS
  32. typedef unsigned int size_t;
  33. #else
  34. #ifdef ARM
  35. typedef unsigned int size_t;
  36. #define alloca(x) __builtin_alloca(x)
  37. #endif
  38. #endif
  39. #if !defined(__USB_TYPE_H) && !defined(CPLUSPLUS) // it is defined in this file too!
  40. typedef enum {FALSE = 0, TRUE = !FALSE} bool;
  41. //typedef unsigned char bool;
  42. //#define TRUE (1)
  43. //#define FALSE (0)
  44. #endif
  45. #define true (1)
  46. #define false (0)
  47. #define NAN (((JsVarFloat)0)/(JsVarFloat)0)
  48. /* Number of Js Variables allowed and Js Reference format.
  49. JsVarRef = char -> 15 bytes/JsVar so JSVAR_CACHE_SIZE = (RAM - 3000) / 15
  50. JsVarRef = short -> 20 bytes/JsVar so JSVAR_CACHE_SIZE = (RAM - 3000) / 20
  51. JsVarRef = int -> 26 bytes/JsVar so JSVAR_CACHE_SIZE = (RAM - 3000) / 26
  52. NOTE: JSVAR_CACHE_SIZE must be at least 2 less than the number we can fit in JsVarRef
  53. See jshardware.c FLASH constants - all this must be able to fit in flash
  54. */
  55. #ifdef RESIZABLE_JSVARS
  56. // probably linux - allow us to allocate more blocks of variables
  57. typedef unsigned int JsVarRef;
  58. #define JSVAR_SIZE 30
  59. #define JSVAR_DATA_STRING_LEN 8 // Actually 9 seems like a good number as 'prototype'==9
  60. #define JSVAR_DATA_STRING_MAX_LEN 24 // (JSVAR_DATA_STRING_LEN + sizeof(JsVarRef)*3 + sizeof(JsVarRefCounter)) - but see JSV_STRING_LEN_MAX - WE HAVE TO CLIP!
  61. #else
  62. /** JsVerRef stores References for variables - We treat 0 as null
  63. * NOTE: we store JSVAR_DATA_STRING_* as actual values so we can do #if on them below
  64. *
  65. */
  66. #if JSVAR_CACHE_SIZE <= 254
  67. typedef unsigned char JsVarRef;
  68. #define JSVAR_SIZE 15
  69. #define JSVAR_DATA_STRING_LEN 8 // Actually 9 seems like a good number as 'prototype'==9
  70. #define JSVAR_DATA_STRING_MAX_LEN 12 // (JSVAR_DATA_STRING_LEN + sizeof(JsVarRef)*3 + sizeof(JsVarRefCounter)) - but see JSV_STRING_LEN_MAX too
  71. #else
  72. typedef unsigned short JsVarRef;
  73. #define JSVAR_SIZE 20
  74. #define JSVAR_DATA_STRING_LEN 8 // Actually 9 seems like a good number as 'prototype'==9
  75. #define JSVAR_DATA_STRING_MAX_LEN 16 // (JSVAR_DATA_STRING_LEN + sizeof(JsVarRef)*3 + sizeof(JsVarRefCounter)) - but see JSV_STRING_LEN_MAX too - WE HAVE TO CLIP!
  76. #endif
  77. #endif
  78. typedef long long JsVarInt;
  79. typedef unsigned long long JsVarIntUnsigned;
  80. #ifdef USE_FLOATS
  81. typedef float JsVarFloat;
  82. #else
  83. typedef double JsVarFloat;
  84. #endif
  85. typedef short JslCharPos;
  86. #define JSSYSTIME_MAX 0x7FFFFFFFFFFFFFFFLL
  87. typedef long long JsSysTime;
  88. #define JSLEX_MAX_TOKEN_LENGTH 64
  89. #define JS_ERROR_BUF_SIZE 64 // size of buffer error messages are written into
  90. #define JS_ERROR_TOKEN_BUF_SIZE 16 // see jslTokenAsString
  91. #define JS_NUMBER_BUFFER_SIZE 24
  92. #define JSPARSE_MAX_SCOPES 8
  93. // Don't restrict number of iterations now
  94. //#define JSPARSE_MAX_LOOP_ITERATIONS 8192
  95. #define STRINGIFY_HELPER(x) #x
  96. #define STRINGIFY(x) STRINGIFY_HELPER(x)
  97. #define NOT_USED(x) ( (void)(x) )
  98. // javascript specific names
  99. #define JSPARSE_RETURN_VAR "return" // variable name used for returning function results
  100. #define JSPARSE_PROTOTYPE_VAR "prototype"
  101. #define JSPARSE_CONSTRUCTOR_VAR "constructor"
  102. #define JSPARSE_INHERITS_VAR "__proto__"
  103. // internal names that hopefully nobody will be able to access
  104. #define JS_HIDDEN_CHAR '>' // initial character of var name determines that we shouldn't see this stuff
  105. #define JS_HIDDEN_CHAR_STR ">"
  106. #define JSPARSE_FUNCTION_CODE_NAME JS_HIDDEN_CHAR_STR"code"
  107. #define JSPARSE_FUNCTION_SCOPE_NAME JS_HIDDEN_CHAR_STR"scope"
  108. #define JSPARSE_MODULE_CACHE_NAME JS_HIDDEN_CHAR_STR"modules"
  109. #if !defined(NO_ASSERT)
  110. #ifdef __STRING
  111. #define assert(X) if (!(X)) jsAssertFail(__FILE__,__LINE__,__STRING(X));
  112. #else
  113. #define assert(X) if (!(X)) jsAssertFail(__FILE__,__LINE__,"");
  114. #endif
  115. #else
  116. #define assert(X)
  117. #endif
  118. /// Used when we have enums we want to squash down
  119. #define PACKED_FLAGS __attribute__ ((__packed__))
  120. /// Used before functions that we want to ensure are not inlined (eg. "void NO_INLINE foo() {}")
  121. #define NO_INLINE __attribute__ ((noinline))
  122. /// Maximum amount of locks we ever expect to have on a variable (this could limit recursion) must be 2^n-1
  123. #define JSV_LOCK_MAX 15
  124. /// preprocessor power of 2 - suitable up to 16 bits
  125. #define NEXT_POWER_2(X) \
  126. (((X) | (X)>>1 | (X)>>2 | (X)>>3 | \
  127. (X)>>4 | (X)>>5 | (X)>>6 | (X)>>7 | \
  128. (X)>>8 | (X)>>9 | (X)>>10 | (X)>>11 | \
  129. (X)>>12 | (X)>>13 | (X)>>14 | (X)>>15)+1)
  130. /// Proprocessor get bit number
  131. #define GET_BIT_NUMBER(X) \
  132. (((X)== 1)? 0: \
  133. ((X)== 2)? 1: \
  134. ((X)== 4)? 2: \
  135. ((X)== 8)? 3: \
  136. ((X)== 16)? 4: \
  137. ((X)== 32)? 5: \
  138. ((X)== 64)? 6: \
  139. ((X)== 128)? 7: \
  140. ((X)== 256)? 8: \
  141. ((X)== 512)? 9: \
  142. ((X)== 1024)?10: \
  143. ((X)== 2048)?11: \
  144. ((X)== 4096)?12: \
  145. ((X)== 8192)?13: \
  146. ((X)==16384)?14: \
  147. ((X)==32768)?15:10000/*error*/)
  148. /** These flags are at the top of each JsVar and provide information about what it is, as
  149. * well as how many Locks it has. Everything is packed in as much as possible to allow us to
  150. * get down to within 2 bytes. */
  151. typedef enum {
  152. JSV_UNUSED = 0, ///< Variable not used for anything
  153. JSV_ROOT = JSV_UNUSED+1, ///< The root of everything - there is only one of these
  154. // UNDEFINED is now just stored using '0' as the variable Ref
  155. JSV_NULL = JSV_ROOT+1, ///< it seems null is its own data type
  156. JSV_STRING = JSV_NULL+1, ///< string
  157. JSV_STRING_0 = JSV_STRING, // string of length 0
  158. JSV_STRING_MAX = JSV_STRING_0+JSVAR_DATA_STRING_LEN,
  159. JSV_STRING_EXT = JSV_STRING_MAX+1, ///< extra character data for string (if it didn't fit in first JsVar). These use unused pointer fields for extra characters
  160. JSV_STRING_EXT_0 = JSV_STRING_EXT,
  161. JSV_STRING_EXT_MAX = JSV_STRING_EXT_0+JSVAR_DATA_STRING_MAX_LEN,
  162. JSV_ARRAY = JSV_STRING_EXT_MAX+1, ///< A JavaScript Array Buffer - Implemented just like a String at the moment
  163. JSV_ARRAYBUFFER = JSV_ARRAY+1,
  164. JSV_OBJECT = JSV_ARRAYBUFFER+1,
  165. JSV_FUNCTION = JSV_OBJECT+1,
  166. JSV_NUMERICSTART = JSV_FUNCTION+1, ///< --------- Start of numeric variable types
  167. JSV_INTEGER = JSV_NUMERICSTART, ///< integer number (note JSV_NUMERICMASK)
  168. JSV_FLOAT = JSV_INTEGER+1, ///< floating point double (note JSV_NUMERICMASK)
  169. JSV_BOOLEAN = JSV_FLOAT+1, ///< boolean (note JSV_NUMERICMASK)
  170. JSV_PIN = JSV_BOOLEAN+1, ///< pin (note JSV_NUMERICMASK)
  171. JSV_NUMERICEND = JSV_PIN, ///< --------- End of numeric variable types
  172. JSV_VAR_END = JSV_NUMERICEND, ///< End of numeric variable types
  173. JSV_VARTYPEMASK = NEXT_POWER_2(JSV_VAR_END)-1,
  174. // names can be STRING,
  175. JSV_NAME = JSV_VARTYPEMASK+1, ///< a NAME of a variable - this isn't a variable itself (and can be an int/string/etc.)
  176. JSV_NATIVE = JSV_NAME<<1, ///< to specify this is a native function, root, function parameter, OR that it should not be freed
  177. JSV_GARBAGE_COLLECT = JSV_NATIVE<<1, ///< When garbage collecting, this flag is true IF we should GC!
  178. JSV_IS_RECURSING = JSV_GARBAGE_COLLECT<<1, ///< used to stop recursive loops in jsvTrace
  179. JSV_LOCK_ONE = JSV_IS_RECURSING<<1,
  180. JSV_LOCK_MASK = JSV_LOCK_MAX * JSV_LOCK_ONE,
  181. JSV_ARRAYBUFFERNAME = JSV_NAME|JSV_ARRAYBUFFER, ///< used for indexing into an ArrayBuffer. varData is an INT in this case
  182. JSV_FUNCTION_PARAMETER = JSV_NATIVE | JSV_NAME, ///< this is inside a function, so it should be quite obvious
  183. } PACKED_FLAGS JsVarFlags; // aiming to get this in 2 bytes!
  184. /// The amount of bits we must shift to get the number of locks - forced to be a constant
  185. static const int JSV_LOCK_SHIFT = GET_BIT_NUMBER(JSV_LOCK_ONE);
  186. typedef enum LEX_TYPES {
  187. LEX_EOF = 0,
  188. LEX_ID = 256,
  189. LEX_INT,
  190. LEX_FLOAT,
  191. LEX_STR,
  192. LEX_UNFINISHED_COMMENT,
  193. LEX_EQUAL,
  194. LEX_TYPEEQUAL,
  195. LEX_NEQUAL,
  196. LEX_NTYPEEQUAL,
  197. LEX_LEQUAL,
  198. LEX_LSHIFT,
  199. LEX_LSHIFTEQUAL,
  200. LEX_GEQUAL,
  201. LEX_RSHIFT,
  202. LEX_RSHIFTUNSIGNED,
  203. LEX_RSHIFTEQUAL,
  204. LEX_RSHIFTUNSIGNEDEQUAL,
  205. LEX_PLUSEQUAL,
  206. LEX_MINUSEQUAL,
  207. LEX_PLUSPLUS,
  208. LEX_MINUSMINUS,
  209. LEX_MULEQUAL,
  210. LEX_DIVEQUAL,
  211. LEX_MODEQUAL,
  212. LEX_ANDEQUAL,
  213. LEX_ANDAND,
  214. LEX_OREQUAL,
  215. LEX_OROR,
  216. LEX_XOREQUAL,
  217. // reserved words
  218. #define LEX_R_LIST_START LEX_R_IF
  219. LEX_R_IF,
  220. LEX_R_ELSE,
  221. LEX_R_DO,
  222. LEX_R_WHILE,
  223. LEX_R_FOR,
  224. LEX_R_BREAK,
  225. LEX_R_CONTINUE,
  226. LEX_R_FUNCTION,
  227. LEX_R_RETURN,
  228. LEX_R_VAR,
  229. LEX_R_THIS,
  230. LEX_R_TRUE,
  231. LEX_R_FALSE,
  232. LEX_R_NULL,
  233. LEX_R_UNDEFINED,
  234. LEX_R_NEW,
  235. LEX_R_IN,
  236. LEX_R_INSTANCEOF,
  237. LEX_R_SWITCH,
  238. LEX_R_CASE,
  239. LEX_R_DEFAULT,
  240. LEX_R_TYPEOF,
  241. LEX_R_VOID,
  242. LEX_R_LIST_END /* always the last entry */
  243. } LEX_TYPES;
  244. // To handle variable size bit fields
  245. #define BITFIELD_DECL(BITFIELD, N) unsigned int BITFIELD[(N+31)/32]
  246. #define BITFIELD_GET(BITFIELD, N) ((BITFIELD[(N)>>5] >> ((N)&31))&1)
  247. #define BITFIELD_SET(BITFIELD, N, VALUE) (BITFIELD[(N)>>5] = (BITFIELD[(N)>>5]& (unsigned int)~(1 << ((N)&31))) | (unsigned int)((VALUE)?(1 << ((N)&31)):0) )
  248. static inline bool isWhitespace(char ch) {
  249. return (ch==' ') || (ch=='\t') || (ch=='\n') || (ch=='\r');
  250. }
  251. static inline bool isNumeric(char ch) {
  252. return (ch>='0') && (ch<='9');
  253. }
  254. static inline bool isHexadecimal(char ch) {
  255. return ((ch>='0') && (ch<='9')) ||
  256. ((ch>='a') && (ch<='f')) ||
  257. ((ch>='A') && (ch<='F'));
  258. }
  259. static inline bool isAlpha(char ch) {
  260. return ((ch>='a') && (ch<='z')) || ((ch>='A') && (ch<='Z')) || ch=='_';
  261. }
  262. bool isIDString(const char *s);
  263. /** escape a character - if it is required. This may return a reference to a static array,
  264. so you can't store the value it returns in a variable and call it again. */
  265. const char *escapeCharacter(char ch);
  266. /* convert a number in the given radix to an int. if radix=0, autodetect */
  267. JsVarInt stringToIntWithRadix(const char *s, int radix, bool *hasError);
  268. /* convert hex, binary, octal or decimal string into an int */
  269. JsVarInt stringToInt(const char *s);
  270. // forward decl
  271. struct JsLex;
  272. // ------------
  273. void jsError(const char *fmt, ...);
  274. void jsErrorInternal(const char *fmt, ...);
  275. void jsErrorAt(const char *message, struct JsLex *lex, int tokenPos);
  276. void jsWarn(const char *fmt, ...);
  277. void jsWarnAt(const char *message, struct JsLex *lex, int tokenPos);
  278. void jsAssertFail(const char *file, int line, const char *expr);
  279. #ifdef FAKE_STDLIB
  280. void exit(int errcode);
  281. char *strncat(char *dst, const char *src, size_t c);
  282. char *strncpy(char *dst, const char *src, size_t c);
  283. size_t strlen(const char *s);
  284. int strcmp(const char *a, const char *b);
  285. void *memcpy(void *dst, const void *src, size_t size);
  286. void *memset(void *dst, int val, size_t size);
  287. #define RAND_MAX (0xFFFFFFFFU)
  288. unsigned int rand();
  289. #else
  290. // FIXME: use itoa/ftoa direct - sprintf is huge
  291. //#define itoa(val,str,base) sprintf(str,"%d",(int)val)
  292. //#define ftoa(val,str) sprintf(str,"%f",val)
  293. #endif
  294. JsVarFloat stringToFloat(const char *str);
  295. #ifndef HAS_STDLIB
  296. void itoa(JsVarInt val,char *str,unsigned int base);
  297. #endif
  298. char itoch(int val);
  299. void ftoa(JsVarFloat val,char *str);
  300. /// Wrap a value so it is always between 0 and size (eg. wrapAround(angle, 360))
  301. JsVarFloat wrapAround(JsVarFloat val, JsVarFloat size);
  302. typedef void (*vcbprintf_callback)(const char *str, void *user_data);
  303. /** Espruino-special printf with a callback
  304. * Supported are:
  305. * %d = int
  306. * %x = int as hex
  307. * %L = JsVarInt
  308. * %Lx = JsVarInt as hex
  309. * %f = JsVarFloat
  310. * %s = string (char *)
  311. * %c = char
  312. * %v = JsVar *
  313. * %p = Pin
  314. *
  315. * Anything else will assert
  316. */
  317. void vcbprintf(vcbprintf_callback user_callback, void *user_data, const char *fmt, va_list argp);
  318. #endif /* JSUTILS_H_ */