Compare commits
27 Commits
simplify_c
...
ast
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a8a271e014 | ||
|
|
91761c03e6 | ||
|
|
5a479cc765 | ||
|
|
97a003e025 | ||
|
|
20f14abd17 | ||
|
|
19ba184fec | ||
|
|
7909b11f6b | ||
|
|
27229c675c | ||
|
|
64d234ee35 | ||
|
|
e861d73eec | ||
|
|
a24331aae5 | ||
|
|
c1cb922b64 | ||
|
|
aacb0b48bf | ||
|
|
b38aec95b6 | ||
|
|
b29d3c2fe0 | ||
|
|
1cc3005b68 | ||
|
|
b86cd042fc | ||
|
|
8b7af0c22a | ||
|
|
f71f6a296b | ||
|
|
9bd764b11b | ||
|
|
058cdfd2e4 | ||
|
|
1ef837c6ff | ||
|
|
cd21de3d70 | ||
|
|
a98faa4dbb | ||
|
|
08559234c4 | ||
|
|
c3dc27eac6 | ||
|
|
7170a9c7eb |
@@ -65,6 +65,7 @@ scripts = [
|
|||||||
'net/enet.c',
|
'net/enet.c',
|
||||||
'wildstar.c',
|
'wildstar.c',
|
||||||
'archive/miniz.c',
|
'archive/miniz.c',
|
||||||
|
'source/cJSON.c'
|
||||||
]
|
]
|
||||||
|
|
||||||
foreach file: scripts
|
foreach file: scripts
|
||||||
|
|||||||
3191
source/cJSON.c
Normal file
3191
source/cJSON.c
Normal file
File diff suppressed because it is too large
Load Diff
306
source/cJSON.h
Normal file
306
source/cJSON.h
Normal file
@@ -0,0 +1,306 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef cJSON__h
|
||||||
|
#define cJSON__h
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
|
||||||
|
#define __WINDOWS__
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __WINDOWS__
|
||||||
|
|
||||||
|
/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options:
|
||||||
|
|
||||||
|
CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols
|
||||||
|
CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default)
|
||||||
|
CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol
|
||||||
|
|
||||||
|
For *nix builds that support visibility attribute, you can define similar behavior by
|
||||||
|
|
||||||
|
setting default visibility to hidden by adding
|
||||||
|
-fvisibility=hidden (for gcc)
|
||||||
|
or
|
||||||
|
-xldscope=hidden (for sun cc)
|
||||||
|
to CFLAGS
|
||||||
|
|
||||||
|
then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CJSON_CDECL __cdecl
|
||||||
|
#define CJSON_STDCALL __stdcall
|
||||||
|
|
||||||
|
/* export symbols by default, this is necessary for copy pasting the C and header file */
|
||||||
|
#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS)
|
||||||
|
#define CJSON_EXPORT_SYMBOLS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CJSON_HIDE_SYMBOLS)
|
||||||
|
#define CJSON_PUBLIC(type) type CJSON_STDCALL
|
||||||
|
#elif defined(CJSON_EXPORT_SYMBOLS)
|
||||||
|
#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL
|
||||||
|
#elif defined(CJSON_IMPORT_SYMBOLS)
|
||||||
|
#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL
|
||||||
|
#endif
|
||||||
|
#else /* !__WINDOWS__ */
|
||||||
|
#define CJSON_CDECL
|
||||||
|
#define CJSON_STDCALL
|
||||||
|
|
||||||
|
#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY)
|
||||||
|
#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type
|
||||||
|
#else
|
||||||
|
#define CJSON_PUBLIC(type) type
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* project version */
|
||||||
|
#define CJSON_VERSION_MAJOR 1
|
||||||
|
#define CJSON_VERSION_MINOR 7
|
||||||
|
#define CJSON_VERSION_PATCH 19
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
/* cJSON Types: */
|
||||||
|
#define cJSON_Invalid (0)
|
||||||
|
#define cJSON_False (1 << 0)
|
||||||
|
#define cJSON_True (1 << 1)
|
||||||
|
#define cJSON_NULL (1 << 2)
|
||||||
|
#define cJSON_Number (1 << 3)
|
||||||
|
#define cJSON_String (1 << 4)
|
||||||
|
#define cJSON_Array (1 << 5)
|
||||||
|
#define cJSON_Object (1 << 6)
|
||||||
|
#define cJSON_Raw (1 << 7) /* raw json */
|
||||||
|
|
||||||
|
#define cJSON_IsReference 256
|
||||||
|
#define cJSON_StringIsConst 512
|
||||||
|
|
||||||
|
/* The cJSON structure: */
|
||||||
|
typedef struct cJSON
|
||||||
|
{
|
||||||
|
/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
|
||||||
|
struct cJSON *next;
|
||||||
|
struct cJSON *prev;
|
||||||
|
/* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
|
||||||
|
struct cJSON *child;
|
||||||
|
|
||||||
|
/* The type of the item, as above. */
|
||||||
|
int type;
|
||||||
|
|
||||||
|
/* The item's string, if type==cJSON_String and type == cJSON_Raw */
|
||||||
|
char *valuestring;
|
||||||
|
/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
|
||||||
|
int valueint;
|
||||||
|
/* The item's number, if type==cJSON_Number */
|
||||||
|
double valuedouble;
|
||||||
|
|
||||||
|
/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
|
||||||
|
char *string;
|
||||||
|
} cJSON;
|
||||||
|
|
||||||
|
typedef struct cJSON_Hooks
|
||||||
|
{
|
||||||
|
/* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */
|
||||||
|
void *(CJSON_CDECL *malloc_fn)(size_t sz);
|
||||||
|
void (CJSON_CDECL *free_fn)(void *ptr);
|
||||||
|
} cJSON_Hooks;
|
||||||
|
|
||||||
|
typedef int cJSON_bool;
|
||||||
|
|
||||||
|
/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them.
|
||||||
|
* This is to prevent stack overflows. */
|
||||||
|
#ifndef CJSON_NESTING_LIMIT
|
||||||
|
#define CJSON_NESTING_LIMIT 1000
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Limits the length of circular references can be before cJSON rejects to parse them.
|
||||||
|
* This is to prevent stack overflows. */
|
||||||
|
#ifndef CJSON_CIRCULAR_LIMIT
|
||||||
|
#define CJSON_CIRCULAR_LIMIT 10000
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* returns the version of cJSON as a string */
|
||||||
|
CJSON_PUBLIC(const char*) cJSON_Version(void);
|
||||||
|
|
||||||
|
/* Supply malloc, realloc and free functions to cJSON */
|
||||||
|
CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);
|
||||||
|
|
||||||
|
/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */
|
||||||
|
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */
|
||||||
|
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
|
||||||
|
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length);
|
||||||
|
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
|
||||||
|
/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */
|
||||||
|
CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
|
||||||
|
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated);
|
||||||
|
|
||||||
|
/* Render a cJSON entity to text for transfer/storage. */
|
||||||
|
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
|
||||||
|
/* Render a cJSON entity to text for transfer/storage without any formatting. */
|
||||||
|
CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
|
||||||
|
/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
|
||||||
|
CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);
|
||||||
|
/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */
|
||||||
|
/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */
|
||||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);
|
||||||
|
/* Delete a cJSON entity and all subentities. */
|
||||||
|
CJSON_PUBLIC(void) cJSON_Delete(cJSON *item);
|
||||||
|
|
||||||
|
/* Returns the number of items in an array (or object). */
|
||||||
|
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
|
||||||
|
/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */
|
||||||
|
CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
|
||||||
|
/* Get item "string" from object. Case insensitive. */
|
||||||
|
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
|
||||||
|
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string);
|
||||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string);
|
||||||
|
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
|
||||||
|
CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
|
||||||
|
|
||||||
|
/* Check item type and return its value */
|
||||||
|
CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item);
|
||||||
|
CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item);
|
||||||
|
|
||||||
|
/* These functions check the type of an item */
|
||||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
|
||||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
|
||||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
|
||||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);
|
||||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);
|
||||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);
|
||||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);
|
||||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);
|
||||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item);
|
||||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item);
|
||||||
|
|
||||||
|
/* These calls create a cJSON item of the appropriate type. */
|
||||||
|
CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
|
||||||
|
CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
|
||||||
|
CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
|
||||||
|
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
|
||||||
|
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
|
||||||
|
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
|
||||||
|
/* raw json */
|
||||||
|
CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
|
||||||
|
CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
|
||||||
|
CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
|
||||||
|
|
||||||
|
/* Create a string where valuestring references a string so
|
||||||
|
* it will not be freed by cJSON_Delete */
|
||||||
|
CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string);
|
||||||
|
/* Create an object/array that only references it's elements so
|
||||||
|
* they will not be freed by cJSON_Delete */
|
||||||
|
CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
|
||||||
|
CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);
|
||||||
|
|
||||||
|
/* These utilities create an Array of count items.
|
||||||
|
* The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/
|
||||||
|
CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
|
||||||
|
CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
|
||||||
|
CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
|
||||||
|
CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count);
|
||||||
|
|
||||||
|
/* Append item to the specified array/object. */
|
||||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item);
|
||||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
|
||||||
|
/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object.
|
||||||
|
* WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before
|
||||||
|
* writing to `item->string` */
|
||||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
|
||||||
|
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
|
||||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
|
||||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
|
||||||
|
|
||||||
|
/* Remove/Detach items from Arrays/Objects. */
|
||||||
|
CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item);
|
||||||
|
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
|
||||||
|
CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
|
||||||
|
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
|
||||||
|
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
|
||||||
|
CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
|
||||||
|
CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);
|
||||||
|
|
||||||
|
/* Update array items. */
|
||||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
|
||||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement);
|
||||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
|
||||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
|
||||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem);
|
||||||
|
|
||||||
|
/* Duplicate a cJSON item */
|
||||||
|
CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse);
|
||||||
|
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
|
||||||
|
* need to be released. With recurse!=0, it will duplicate any children connected to the item.
|
||||||
|
* The item->next and ->prev pointers are always zero on return from Duplicate. */
|
||||||
|
/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal.
|
||||||
|
* case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */
|
||||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive);
|
||||||
|
|
||||||
|
/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings.
|
||||||
|
* The input pointer json cannot point to a read-only address area, such as a string constant,
|
||||||
|
* but should point to a readable and writable address area. */
|
||||||
|
CJSON_PUBLIC(void) cJSON_Minify(char *json);
|
||||||
|
|
||||||
|
/* Helper functions for creating and adding items to an object at the same time.
|
||||||
|
* They return the added item or NULL on failure. */
|
||||||
|
CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name);
|
||||||
|
CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
|
||||||
|
CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
|
||||||
|
CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);
|
||||||
|
CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
|
||||||
|
CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
|
||||||
|
CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
|
||||||
|
CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
|
||||||
|
CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name);
|
||||||
|
|
||||||
|
/* When assigning an integer value, it needs to be propagated to valuedouble too. */
|
||||||
|
#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
|
||||||
|
/* helper for the cJSON_SetNumberValue macro */
|
||||||
|
CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
|
||||||
|
#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))
|
||||||
|
/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */
|
||||||
|
CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring);
|
||||||
|
|
||||||
|
/* If the object is not a boolean type this does nothing and returns cJSON_Invalid else it returns the new type*/
|
||||||
|
#define cJSON_SetBoolValue(object, boolValue) ( \
|
||||||
|
(object != NULL && ((object)->type & (cJSON_False|cJSON_True))) ? \
|
||||||
|
(object)->type=((object)->type &(~(cJSON_False|cJSON_True)))|((boolValue)?cJSON_True:cJSON_False) : \
|
||||||
|
cJSON_Invalid\
|
||||||
|
)
|
||||||
|
|
||||||
|
/* Macro for iterating over an array or object */
|
||||||
|
#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)
|
||||||
|
|
||||||
|
/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */
|
||||||
|
CJSON_PUBLIC(void *) cJSON_malloc(size_t size);
|
||||||
|
CJSON_PUBLIC(void) cJSON_free(void *object);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
427
source/cell.c
427
source/cell.c
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include "cell.h"
|
#include "cell.h"
|
||||||
#include "cell_internal.h"
|
#include "cell_internal.h"
|
||||||
|
#include "cJSON.h"
|
||||||
|
|
||||||
#define ENGINE "internal/engine.cm"
|
#define ENGINE "internal/engine.cm"
|
||||||
#define CELL_SHOP_DIR ".cell"
|
#define CELL_SHOP_DIR ".cell"
|
||||||
@@ -104,6 +105,35 @@ static char* load_core_file(const char *filename, size_t *out_size) {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int print_json_errors(const char *json) {
|
||||||
|
if (!json) return 0;
|
||||||
|
cJSON *root = cJSON_Parse(json);
|
||||||
|
if (!root) return 0;
|
||||||
|
cJSON *errors = cJSON_GetObjectItemCaseSensitive(root, "errors");
|
||||||
|
if (!cJSON_IsArray(errors) || cJSON_GetArraySize(errors) == 0) {
|
||||||
|
cJSON_Delete(root);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const char *filename = "<unknown>";
|
||||||
|
cJSON *fname = cJSON_GetObjectItemCaseSensitive(root, "filename");
|
||||||
|
if (cJSON_IsString(fname))
|
||||||
|
filename = fname->valuestring;
|
||||||
|
cJSON *e;
|
||||||
|
cJSON_ArrayForEach(e, errors) {
|
||||||
|
const char *msg = cJSON_GetStringValue(
|
||||||
|
cJSON_GetObjectItemCaseSensitive(e, "message"));
|
||||||
|
cJSON *line = cJSON_GetObjectItemCaseSensitive(e, "line");
|
||||||
|
cJSON *col = cJSON_GetObjectItemCaseSensitive(e, "column");
|
||||||
|
if (msg && cJSON_IsNumber(line) && cJSON_IsNumber(col))
|
||||||
|
fprintf(stderr, "%s:%d:%d: error: %s\n",
|
||||||
|
filename, (int)line->valuedouble, (int)col->valuedouble, msg);
|
||||||
|
else if (msg)
|
||||||
|
fprintf(stderr, "%s: error: %s\n", filename, msg);
|
||||||
|
}
|
||||||
|
cJSON_Delete(root);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
// Get the core path for use by scripts
|
// Get the core path for use by scripts
|
||||||
const char* cell_get_core_path(void) {
|
const char* cell_get_core_path(void) {
|
||||||
return core_path;
|
return core_path;
|
||||||
@@ -340,6 +370,403 @@ int cell_init(int argc, char **argv)
|
|||||||
return run_test_suite(heap_size);
|
return run_test_suite(heap_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check for --ast flag to output AST JSON */
|
||||||
|
if (argc >= 3 && strcmp(argv[1], "--ast") == 0) {
|
||||||
|
const char *script_or_file = argv[2];
|
||||||
|
char *script = NULL;
|
||||||
|
char *allocated_script = NULL;
|
||||||
|
const char *filename = "<eval>";
|
||||||
|
|
||||||
|
struct stat st;
|
||||||
|
if (stat(script_or_file, &st) == 0 && S_ISREG(st.st_mode)) {
|
||||||
|
FILE *f = fopen(script_or_file, "r");
|
||||||
|
if (!f) {
|
||||||
|
printf("Failed to open file: %s\n", script_or_file);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
allocated_script = malloc(st.st_size + 1);
|
||||||
|
if (!allocated_script) {
|
||||||
|
fclose(f);
|
||||||
|
printf("Failed to allocate memory for script\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
size_t read_size = fread(allocated_script, 1, st.st_size, f);
|
||||||
|
fclose(f);
|
||||||
|
allocated_script[read_size] = '\0';
|
||||||
|
script = allocated_script;
|
||||||
|
filename = script_or_file;
|
||||||
|
} else {
|
||||||
|
script = (char *)script_or_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSRuntime *rt = JS_NewRuntime();
|
||||||
|
if (!rt) {
|
||||||
|
printf("Failed to create JS runtime\n");
|
||||||
|
free(allocated_script);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
JSContext *ctx = JS_NewContext(rt);
|
||||||
|
if (!ctx) {
|
||||||
|
printf("Failed to create JS context\n");
|
||||||
|
JS_FreeRuntime(rt);
|
||||||
|
free(allocated_script);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *json = JS_AST(ctx, script, strlen(script), filename);
|
||||||
|
if (json) {
|
||||||
|
int has_errors = print_json_errors(json);
|
||||||
|
printf("%s\n", json);
|
||||||
|
free(json);
|
||||||
|
JS_FreeContext(ctx);
|
||||||
|
JS_FreeRuntime(rt);
|
||||||
|
free(allocated_script);
|
||||||
|
return has_errors ? 1 : 0;
|
||||||
|
} else {
|
||||||
|
printf("Failed to parse AST\n");
|
||||||
|
JS_FreeContext(ctx);
|
||||||
|
JS_FreeRuntime(rt);
|
||||||
|
free(allocated_script);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for --tokenize flag to output token array JSON */
|
||||||
|
if (argc >= 3 && strcmp(argv[1], "--tokenize") == 0) {
|
||||||
|
const char *script_or_file = argv[2];
|
||||||
|
char *script = NULL;
|
||||||
|
char *allocated_script = NULL;
|
||||||
|
const char *filename = "<eval>";
|
||||||
|
|
||||||
|
struct stat st;
|
||||||
|
if (stat(script_or_file, &st) == 0 && S_ISREG(st.st_mode)) {
|
||||||
|
FILE *f = fopen(script_or_file, "r");
|
||||||
|
if (!f) {
|
||||||
|
printf("Failed to open file: %s\n", script_or_file);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
allocated_script = malloc(st.st_size + 1);
|
||||||
|
if (!allocated_script) {
|
||||||
|
fclose(f);
|
||||||
|
printf("Failed to allocate memory for script\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
size_t read_size = fread(allocated_script, 1, st.st_size, f);
|
||||||
|
fclose(f);
|
||||||
|
allocated_script[read_size] = '\0';
|
||||||
|
script = allocated_script;
|
||||||
|
filename = script_or_file;
|
||||||
|
} else {
|
||||||
|
script = (char *)script_or_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSRuntime *rt = JS_NewRuntime();
|
||||||
|
if (!rt) {
|
||||||
|
printf("Failed to create JS runtime\n");
|
||||||
|
free(allocated_script);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
JSContext *ctx = JS_NewContext(rt);
|
||||||
|
if (!ctx) {
|
||||||
|
printf("Failed to create JS context\n");
|
||||||
|
JS_FreeRuntime(rt);
|
||||||
|
free(allocated_script);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *json = JS_Tokenize(ctx, script, strlen(script), filename);
|
||||||
|
if (json) {
|
||||||
|
int has_errors = print_json_errors(json);
|
||||||
|
printf("%s\n", json);
|
||||||
|
free(json);
|
||||||
|
JS_FreeContext(ctx);
|
||||||
|
JS_FreeRuntime(rt);
|
||||||
|
free(allocated_script);
|
||||||
|
return has_errors ? 1 : 0;
|
||||||
|
} else {
|
||||||
|
printf("Failed to tokenize\n");
|
||||||
|
JS_FreeContext(ctx);
|
||||||
|
JS_FreeRuntime(rt);
|
||||||
|
free(allocated_script);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for --mach flag to output machine code JSON */
|
||||||
|
if (argc >= 3 && strcmp(argv[1], "--mach") == 0) {
|
||||||
|
const char *script_or_file = argv[2];
|
||||||
|
char *script = NULL;
|
||||||
|
char *allocated_script = NULL;
|
||||||
|
const char *filename = "<eval>";
|
||||||
|
|
||||||
|
struct stat st;
|
||||||
|
if (stat(script_or_file, &st) == 0 && S_ISREG(st.st_mode)) {
|
||||||
|
FILE *f = fopen(script_or_file, "r");
|
||||||
|
if (!f) {
|
||||||
|
printf("Failed to open file: %s\n", script_or_file);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
allocated_script = malloc(st.st_size + 1);
|
||||||
|
if (!allocated_script) {
|
||||||
|
fclose(f);
|
||||||
|
printf("Failed to allocate memory for script\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
size_t read_size = fread(allocated_script, 1, st.st_size, f);
|
||||||
|
fclose(f);
|
||||||
|
allocated_script[read_size] = '\0';
|
||||||
|
script = allocated_script;
|
||||||
|
filename = script_or_file;
|
||||||
|
} else {
|
||||||
|
script = (char *)script_or_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSRuntime *rt = JS_NewRuntime();
|
||||||
|
if (!rt) {
|
||||||
|
printf("Failed to create JS runtime\n");
|
||||||
|
free(allocated_script);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
JSContext *ctx = JS_NewContext(rt);
|
||||||
|
if (!ctx) {
|
||||||
|
printf("Failed to create JS context\n");
|
||||||
|
JS_FreeRuntime(rt);
|
||||||
|
free(allocated_script);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *ast_json = JS_AST(ctx, script, strlen(script), filename);
|
||||||
|
if (!ast_json) {
|
||||||
|
printf("Failed to parse AST\n");
|
||||||
|
JS_FreeContext(ctx);
|
||||||
|
JS_FreeRuntime(rt);
|
||||||
|
free(allocated_script);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (print_json_errors(ast_json)) {
|
||||||
|
free(ast_json);
|
||||||
|
JS_FreeContext(ctx);
|
||||||
|
JS_FreeRuntime(rt);
|
||||||
|
free(allocated_script);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *mach_json = JS_Mach(ctx, ast_json);
|
||||||
|
free(ast_json);
|
||||||
|
|
||||||
|
if (mach_json) {
|
||||||
|
if (print_json_errors(mach_json)) {
|
||||||
|
free(mach_json);
|
||||||
|
JS_FreeContext(ctx);
|
||||||
|
JS_FreeRuntime(rt);
|
||||||
|
free(allocated_script);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
printf("%s\n", mach_json);
|
||||||
|
free(mach_json);
|
||||||
|
} else {
|
||||||
|
printf("Failed to generate machine code\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
JS_FreeContext(ctx);
|
||||||
|
JS_FreeRuntime(rt);
|
||||||
|
free(allocated_script);
|
||||||
|
return mach_json ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for --vmcode flag to dump linked register VM bytecode */
|
||||||
|
if (argc >= 3 && strcmp(argv[1], "--vmcode") == 0) {
|
||||||
|
const char *script_or_file = argv[2];
|
||||||
|
char *script = NULL;
|
||||||
|
char *allocated_script = NULL;
|
||||||
|
const char *filename = "<eval>";
|
||||||
|
|
||||||
|
struct stat st;
|
||||||
|
if (stat(script_or_file, &st) == 0 && S_ISREG(st.st_mode)) {
|
||||||
|
FILE *f = fopen(script_or_file, "r");
|
||||||
|
if (!f) {
|
||||||
|
printf("Failed to open file: %s\n", script_or_file);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
allocated_script = malloc(st.st_size + 1);
|
||||||
|
if (!allocated_script) {
|
||||||
|
fclose(f);
|
||||||
|
printf("Failed to allocate memory for script\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
size_t read_size = fread(allocated_script, 1, st.st_size, f);
|
||||||
|
fclose(f);
|
||||||
|
allocated_script[read_size] = '\0';
|
||||||
|
script = allocated_script;
|
||||||
|
filename = script_or_file;
|
||||||
|
} else {
|
||||||
|
script = (char *)script_or_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSRuntime *rt = JS_NewRuntime();
|
||||||
|
if (!rt) {
|
||||||
|
printf("Failed to create JS runtime\n");
|
||||||
|
free(allocated_script);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
JSContext *ctx = JS_NewContext(rt);
|
||||||
|
if (!ctx) {
|
||||||
|
printf("Failed to create JS context\n");
|
||||||
|
JS_FreeRuntime(rt);
|
||||||
|
free(allocated_script);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *ast_json = JS_AST(ctx, script, strlen(script), filename);
|
||||||
|
if (!ast_json) {
|
||||||
|
printf("Failed to parse AST\n");
|
||||||
|
JS_FreeContext(ctx);
|
||||||
|
JS_FreeRuntime(rt);
|
||||||
|
free(allocated_script);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (print_json_errors(ast_json)) {
|
||||||
|
free(ast_json);
|
||||||
|
JS_FreeContext(ctx);
|
||||||
|
JS_FreeRuntime(rt);
|
||||||
|
free(allocated_script);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *mach_json = JS_Mach(ctx, ast_json);
|
||||||
|
free(ast_json);
|
||||||
|
|
||||||
|
if (mach_json) {
|
||||||
|
if (print_json_errors(mach_json)) {
|
||||||
|
free(mach_json);
|
||||||
|
JS_FreeContext(ctx);
|
||||||
|
JS_FreeRuntime(rt);
|
||||||
|
free(allocated_script);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
JS_DumpRegisterMach(ctx, mach_json, JS_NULL);
|
||||||
|
free(mach_json);
|
||||||
|
} else {
|
||||||
|
printf("Failed to generate machine code\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
JS_FreeContext(ctx);
|
||||||
|
JS_FreeRuntime(rt);
|
||||||
|
free(allocated_script);
|
||||||
|
return mach_json ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for --mach-run flag to generate and run machine code through register VM */
|
||||||
|
if (argc >= 3 && strcmp(argv[1], "--mach-run") == 0) {
|
||||||
|
const char *script_or_file = argv[2];
|
||||||
|
char *script = NULL;
|
||||||
|
char *allocated_script = NULL;
|
||||||
|
const char *filename = "<eval>";
|
||||||
|
|
||||||
|
struct stat st;
|
||||||
|
if (stat(script_or_file, &st) == 0 && S_ISREG(st.st_mode)) {
|
||||||
|
FILE *f = fopen(script_or_file, "r");
|
||||||
|
if (!f) {
|
||||||
|
printf("Failed to open file: %s\n", script_or_file);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
allocated_script = malloc(st.st_size + 1);
|
||||||
|
if (!allocated_script) {
|
||||||
|
fclose(f);
|
||||||
|
printf("Failed to allocate memory for script\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
size_t read_size = fread(allocated_script, 1, st.st_size, f);
|
||||||
|
fclose(f);
|
||||||
|
allocated_script[read_size] = '\0';
|
||||||
|
script = allocated_script;
|
||||||
|
filename = script_or_file;
|
||||||
|
} else {
|
||||||
|
script = (char *)script_or_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSRuntime *rt = JS_NewRuntime();
|
||||||
|
if (!rt) {
|
||||||
|
printf("Failed to create JS runtime\n");
|
||||||
|
free(allocated_script);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
JSContext *ctx = JS_NewContext(rt);
|
||||||
|
if (!ctx) {
|
||||||
|
printf("Failed to create JS context\n");
|
||||||
|
JS_FreeRuntime(rt);
|
||||||
|
free(allocated_script);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse to AST */
|
||||||
|
char *ast_json = JS_AST(ctx, script, strlen(script), filename);
|
||||||
|
if (!ast_json) {
|
||||||
|
printf("Failed to parse AST\n");
|
||||||
|
JS_FreeContext(ctx);
|
||||||
|
JS_FreeRuntime(rt);
|
||||||
|
free(allocated_script);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (print_json_errors(ast_json)) {
|
||||||
|
free(ast_json);
|
||||||
|
JS_FreeContext(ctx);
|
||||||
|
JS_FreeRuntime(rt);
|
||||||
|
free(allocated_script);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generate machine code */
|
||||||
|
char *mach_json = JS_Mach(ctx, ast_json);
|
||||||
|
free(ast_json);
|
||||||
|
|
||||||
|
if (!mach_json) {
|
||||||
|
printf("Failed to generate machine code\n");
|
||||||
|
JS_FreeContext(ctx);
|
||||||
|
JS_FreeRuntime(rt);
|
||||||
|
free(allocated_script);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (print_json_errors(mach_json)) {
|
||||||
|
free(mach_json);
|
||||||
|
JS_FreeContext(ctx);
|
||||||
|
JS_FreeRuntime(rt);
|
||||||
|
free(allocated_script);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Execute through register VM */
|
||||||
|
JSValue result = JS_IntegrateRegister(ctx, mach_json, JS_NULL);
|
||||||
|
free(mach_json);
|
||||||
|
|
||||||
|
int exit_code = 0;
|
||||||
|
if (JS_IsException(result)) {
|
||||||
|
JSValue exc = JS_GetException(ctx);
|
||||||
|
const char *err_str = JS_ToCString(ctx, exc);
|
||||||
|
if (err_str) {
|
||||||
|
printf("Error: %s\n", err_str);
|
||||||
|
JS_FreeCString(ctx, err_str);
|
||||||
|
}
|
||||||
|
exit_code = 1;
|
||||||
|
} else if (!JS_IsNull(result)) {
|
||||||
|
/* Print result */
|
||||||
|
const char *str = JS_ToCString(ctx, result);
|
||||||
|
if (str) {
|
||||||
|
printf("%s\n", str);
|
||||||
|
JS_FreeCString(ctx, str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JS_FreeContext(ctx);
|
||||||
|
JS_FreeRuntime(rt);
|
||||||
|
free(allocated_script);
|
||||||
|
return exit_code;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check for -e or --eval flag to run immediate script */
|
/* Check for -e or --eval flag to run immediate script */
|
||||||
/* Also check for -p flag to print bytecode */
|
/* Also check for -p flag to print bytecode */
|
||||||
/* -s / --serializers flag provides json, nota, wota in env */
|
/* -s / --serializers flag provides json, nota, wota in env */
|
||||||
|
|||||||
6812
source/quickjs.c
6812
source/quickjs.c
File diff suppressed because it is too large
Load Diff
@@ -1218,6 +1218,28 @@ CellModule *cell_module_from_bytecode (JSContext *ctx, JSFunctionBytecode *main_
|
|||||||
Returns allocated CellModule (caller must free with cell_module_free), or NULL on error. */
|
Returns allocated CellModule (caller must free with cell_module_free), or NULL on error. */
|
||||||
CellModule *JS_CompileModule (JSContext *ctx, const char *input, size_t input_len, const char *filename);
|
CellModule *JS_CompileModule (JSContext *ctx, const char *input, size_t input_len, const char *filename);
|
||||||
|
|
||||||
|
/* Parse source code and return AST as JSON string.
|
||||||
|
Returns malloc'd JSON string (caller must free), or NULL on error. */
|
||||||
|
char *JS_AST (JSContext *ctx, const char *source, size_t len, const char *filename);
|
||||||
|
|
||||||
|
/* Tokenize source code and return token array as JSON string.
|
||||||
|
Returns malloc'd JSON string (caller must free), or NULL on error. */
|
||||||
|
char *JS_Tokenize (JSContext *ctx, const char *source, size_t len, const char *filename);
|
||||||
|
|
||||||
|
/* Generate register-based machine code from AST JSON.
|
||||||
|
Returns malloc'd JSON string (caller must free), or NULL on error. */
|
||||||
|
char *JS_Mach (JSContext *ctx, const char *ast_json);
|
||||||
|
|
||||||
|
/* Link and execute register-based machine code.
|
||||||
|
mach_json: JSON output from JS_Mach
|
||||||
|
env: stone record for external variable resolution (or JS_NULL)
|
||||||
|
Returns result of execution, or JS_EXCEPTION on error. */
|
||||||
|
JSValue JS_IntegrateRegister (JSContext *ctx, const char *mach_json, JSValue env);
|
||||||
|
|
||||||
|
/* Dump linked register VM bytecode to stdout for debugging.
|
||||||
|
Links mach_json and prints the resulting bytecode with resolved labels. */
|
||||||
|
void JS_DumpRegisterMach (JSContext *ctx, const char *mach_json, JSValue env);
|
||||||
|
|
||||||
/* Integrate a CellModule with an environment and execute.
|
/* Integrate a CellModule with an environment and execute.
|
||||||
Returns callable function value, or JS_EXCEPTION on error. */
|
Returns callable function value, or JS_EXCEPTION on error. */
|
||||||
JSValue cell_module_integrate (JSContext *ctx, CellModule *mod, JSValue env);
|
JSValue cell_module_integrate (JSContext *ctx, CellModule *mod, JSValue env);
|
||||||
|
|||||||
392
source/suite.c
392
source/suite.c
@@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "quickjs.h"
|
#include "quickjs.h"
|
||||||
|
#include "cJSON.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
@@ -2132,6 +2133,360 @@ TEST(cell_module_string_constant) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ============================================================================
|
||||||
|
ERROR RECOVERY TESTS - Helper macros
|
||||||
|
============================================================================ */
|
||||||
|
|
||||||
|
#define ASSERT_HAS_ERRORS(json_str, min_count) do { \
|
||||||
|
cJSON *_root = cJSON_Parse(json_str); \
|
||||||
|
ASSERT_MSG(_root != NULL, "failed to parse JSON output"); \
|
||||||
|
cJSON *_errs = cJSON_GetObjectItem(_root, "errors"); \
|
||||||
|
if (!_errs || !cJSON_IsArray(_errs) || cJSON_GetArraySize(_errs) < (min_count)) { \
|
||||||
|
printf("[line %d: expected at least %d error(s), got %d] ", __LINE__, (min_count), \
|
||||||
|
_errs && cJSON_IsArray(_errs) ? cJSON_GetArraySize(_errs) : 0); \
|
||||||
|
cJSON_Delete(_root); \
|
||||||
|
return 0; \
|
||||||
|
} \
|
||||||
|
cJSON_Delete(_root); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define ASSERT_NO_ERRORS(json_str) do { \
|
||||||
|
cJSON *_root = cJSON_Parse(json_str); \
|
||||||
|
ASSERT_MSG(_root != NULL, "failed to parse JSON output"); \
|
||||||
|
cJSON *_errs = cJSON_GetObjectItem(_root, "errors"); \
|
||||||
|
if (_errs && cJSON_IsArray(_errs) && cJSON_GetArraySize(_errs) > 0) { \
|
||||||
|
cJSON *_first = cJSON_GetArrayItem(_errs, 0); \
|
||||||
|
const char *_msg = cJSON_GetStringValue(cJSON_GetObjectItem(_first, "message")); \
|
||||||
|
printf("[line %d: expected no errors, got: %s] ", __LINE__, _msg ? _msg : "?"); \
|
||||||
|
cJSON_Delete(_root); \
|
||||||
|
return 0; \
|
||||||
|
} \
|
||||||
|
cJSON_Delete(_root); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define ASSERT_ERROR_MSG_CONTAINS(json_str, substring) do { \
|
||||||
|
cJSON *_root = cJSON_Parse(json_str); \
|
||||||
|
ASSERT_MSG(_root != NULL, "failed to parse JSON output"); \
|
||||||
|
cJSON *_errs = cJSON_GetObjectItem(_root, "errors"); \
|
||||||
|
int _found = 0; \
|
||||||
|
if (_errs && cJSON_IsArray(_errs)) { \
|
||||||
|
cJSON *_e; \
|
||||||
|
cJSON_ArrayForEach(_e, _errs) { \
|
||||||
|
const char *_msg = cJSON_GetStringValue(cJSON_GetObjectItem(_e, "message")); \
|
||||||
|
if (_msg && strstr(_msg, (substring))) { _found = 1; break; } \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
if (!_found) { \
|
||||||
|
printf("[line %d: no error containing '%s'] ", __LINE__, (substring)); \
|
||||||
|
cJSON_Delete(_root); \
|
||||||
|
return 0; \
|
||||||
|
} \
|
||||||
|
cJSON_Delete(_root); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
/* ============================================================================
|
||||||
|
TOKENIZER ERROR TESTS
|
||||||
|
============================================================================ */
|
||||||
|
|
||||||
|
TEST(tokenize_unterminated_string) {
|
||||||
|
const char *src = "var x = \"hello";
|
||||||
|
char *json = JS_Tokenize(ctx, src, strlen(src), "<test>");
|
||||||
|
ASSERT_MSG(json != NULL, "JS_Tokenize returned NULL");
|
||||||
|
ASSERT_ERROR_MSG_CONTAINS(json, "unterminated string");
|
||||||
|
free(json);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(tokenize_unterminated_template) {
|
||||||
|
const char *src = "var x = `hello";
|
||||||
|
char *json = JS_Tokenize(ctx, src, strlen(src), "<test>");
|
||||||
|
ASSERT_MSG(json != NULL, "JS_Tokenize returned NULL");
|
||||||
|
ASSERT_ERROR_MSG_CONTAINS(json, "unterminated template");
|
||||||
|
free(json);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(tokenize_unterminated_block_comment) {
|
||||||
|
const char *src = "var x /* comment";
|
||||||
|
char *json = JS_Tokenize(ctx, src, strlen(src), "<test>");
|
||||||
|
ASSERT_MSG(json != NULL, "JS_Tokenize returned NULL");
|
||||||
|
ASSERT_ERROR_MSG_CONTAINS(json, "unterminated block comment");
|
||||||
|
free(json);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(tokenize_malformed_hex) {
|
||||||
|
const char *src = "var x = 0x";
|
||||||
|
char *json = JS_Tokenize(ctx, src, strlen(src), "<test>");
|
||||||
|
ASSERT_MSG(json != NULL, "JS_Tokenize returned NULL");
|
||||||
|
ASSERT_ERROR_MSG_CONTAINS(json, "malformed hex");
|
||||||
|
free(json);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(tokenize_malformed_binary) {
|
||||||
|
const char *src = "var x = 0b";
|
||||||
|
char *json = JS_Tokenize(ctx, src, strlen(src), "<test>");
|
||||||
|
ASSERT_MSG(json != NULL, "JS_Tokenize returned NULL");
|
||||||
|
ASSERT_ERROR_MSG_CONTAINS(json, "malformed binary");
|
||||||
|
free(json);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(tokenize_malformed_exponent) {
|
||||||
|
const char *src = "var x = 1e+";
|
||||||
|
char *json = JS_Tokenize(ctx, src, strlen(src), "<test>");
|
||||||
|
ASSERT_MSG(json != NULL, "JS_Tokenize returned NULL");
|
||||||
|
ASSERT_ERROR_MSG_CONTAINS(json, "no digits after exponent");
|
||||||
|
free(json);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(tokenize_valid_no_errors) {
|
||||||
|
const char *src = "var x = 42";
|
||||||
|
char *json = JS_Tokenize(ctx, src, strlen(src), "<test>");
|
||||||
|
ASSERT_MSG(json != NULL, "JS_Tokenize returned NULL");
|
||||||
|
ASSERT_NO_ERRORS(json);
|
||||||
|
free(json);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================================================
|
||||||
|
PARSER ERROR TESTS
|
||||||
|
============================================================================ */
|
||||||
|
|
||||||
|
TEST(ast_missing_identifier_after_var) {
|
||||||
|
const char *src = "var = 1";
|
||||||
|
char *json = JS_AST(ctx, src, strlen(src), "<test>");
|
||||||
|
ASSERT_MSG(json != NULL, "JS_AST returned NULL");
|
||||||
|
ASSERT_ERROR_MSG_CONTAINS(json, "expected identifier");
|
||||||
|
free(json);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ast_missing_initializer_def) {
|
||||||
|
const char *src = "def x";
|
||||||
|
char *json = JS_AST(ctx, src, strlen(src), "<test>");
|
||||||
|
ASSERT_MSG(json != NULL, "JS_AST returned NULL");
|
||||||
|
ASSERT_ERROR_MSG_CONTAINS(json, "missing initializer");
|
||||||
|
free(json);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ast_recovery_continues_after_error) {
|
||||||
|
const char *src = "var = 1; var y = 2";
|
||||||
|
char *json = JS_AST(ctx, src, strlen(src), "<test>");
|
||||||
|
ASSERT_MSG(json != NULL, "JS_AST returned NULL");
|
||||||
|
ASSERT_HAS_ERRORS(json, 1);
|
||||||
|
/* Check that 'y' statement is present in the AST */
|
||||||
|
ASSERT_MSG(strstr(json, "\"y\"") != NULL, "recovery failed: 'y' not in AST");
|
||||||
|
free(json);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ast_valid_no_errors) {
|
||||||
|
const char *src = "var x = 1; var y = 2";
|
||||||
|
char *json = JS_AST(ctx, src, strlen(src), "<test>");
|
||||||
|
ASSERT_MSG(json != NULL, "JS_AST returned NULL");
|
||||||
|
ASSERT_NO_ERRORS(json);
|
||||||
|
free(json);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================================================
|
||||||
|
AST SEMANTIC ERROR TESTS
|
||||||
|
============================================================================ */
|
||||||
|
|
||||||
|
TEST(ast_sem_assign_to_const) {
|
||||||
|
const char *src = "def x = 5; x = 3";
|
||||||
|
char *json = JS_AST(ctx, src, strlen(src), "<test>");
|
||||||
|
ASSERT_MSG(json != NULL, "JS_AST returned NULL");
|
||||||
|
ASSERT_ERROR_MSG_CONTAINS(json, "cannot assign to constant");
|
||||||
|
free(json);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ast_sem_assign_to_arg) {
|
||||||
|
const char *src = "function(x) { x = 5; }";
|
||||||
|
char *json = JS_AST(ctx, src, strlen(src), "<test>");
|
||||||
|
ASSERT_MSG(json != NULL, "JS_AST returned NULL");
|
||||||
|
ASSERT_ERROR_MSG_CONTAINS(json, "cannot assign to constant");
|
||||||
|
free(json);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ast_sem_redeclare_const) {
|
||||||
|
const char *src = "def x = 1; def x = 2";
|
||||||
|
char *json = JS_AST(ctx, src, strlen(src), "<test>");
|
||||||
|
ASSERT_MSG(json != NULL, "JS_AST returned NULL");
|
||||||
|
ASSERT_ERROR_MSG_CONTAINS(json, "cannot redeclare constant");
|
||||||
|
free(json);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ast_sem_break_outside_loop) {
|
||||||
|
const char *src = "break";
|
||||||
|
char *json = JS_AST(ctx, src, strlen(src), "<test>");
|
||||||
|
ASSERT_MSG(json != NULL, "JS_AST returned NULL");
|
||||||
|
ASSERT_ERROR_MSG_CONTAINS(json, "outside of loop");
|
||||||
|
free(json);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ast_sem_continue_outside_loop) {
|
||||||
|
const char *src = "continue";
|
||||||
|
char *json = JS_AST(ctx, src, strlen(src), "<test>");
|
||||||
|
ASSERT_MSG(json != NULL, "JS_AST returned NULL");
|
||||||
|
ASSERT_ERROR_MSG_CONTAINS(json, "outside of loop");
|
||||||
|
free(json);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ast_sem_break_inside_loop_ok) {
|
||||||
|
const char *src = "while (true) { break; }";
|
||||||
|
char *json = JS_AST(ctx, src, strlen(src), "<test>");
|
||||||
|
ASSERT_MSG(json != NULL, "JS_AST returned NULL");
|
||||||
|
ASSERT_NO_ERRORS(json);
|
||||||
|
free(json);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ast_sem_increment_const) {
|
||||||
|
const char *src = "def x = 1; x++";
|
||||||
|
char *json = JS_AST(ctx, src, strlen(src), "<test>");
|
||||||
|
ASSERT_MSG(json != NULL, "JS_AST returned NULL");
|
||||||
|
ASSERT_ERROR_MSG_CONTAINS(json, "cannot assign to constant");
|
||||||
|
free(json);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ast_sem_shadow_var_ok) {
|
||||||
|
const char *src = "var array = []; array";
|
||||||
|
char *json = JS_AST(ctx, src, strlen(src), "<test>");
|
||||||
|
ASSERT_MSG(json != NULL, "JS_AST returned NULL");
|
||||||
|
ASSERT_NO_ERRORS(json);
|
||||||
|
free(json);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ast_sem_var_assign_ok) {
|
||||||
|
const char *src = "var x = 1; x = x + 1";
|
||||||
|
char *json = JS_AST(ctx, src, strlen(src), "<test>");
|
||||||
|
ASSERT_MSG(json != NULL, "JS_AST returned NULL");
|
||||||
|
ASSERT_NO_ERRORS(json);
|
||||||
|
free(json);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ast_sem_nested_function_scope) {
|
||||||
|
const char *src = "var x = 1; function f(x) { return x + 1; }";
|
||||||
|
char *json = JS_AST(ctx, src, strlen(src), "<test>");
|
||||||
|
ASSERT_MSG(json != NULL, "JS_AST returned NULL");
|
||||||
|
ASSERT_NO_ERRORS(json);
|
||||||
|
free(json);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================================================
|
||||||
|
CODEGEN/SEMANTIC ERROR TESTS
|
||||||
|
============================================================================ */
|
||||||
|
|
||||||
|
TEST(mach_assign_to_const) {
|
||||||
|
const char *src = "def x = 1; x = 2";
|
||||||
|
char *ast_json = JS_AST(ctx, src, strlen(src), "<test>");
|
||||||
|
ASSERT_MSG(ast_json != NULL, "JS_AST returned NULL");
|
||||||
|
char *mach_json = JS_Mach(ctx, ast_json);
|
||||||
|
free(ast_json);
|
||||||
|
ASSERT_MSG(mach_json != NULL, "JS_Mach returned NULL");
|
||||||
|
ASSERT_ERROR_MSG_CONTAINS(mach_json, "cannot assign to constant");
|
||||||
|
free(mach_json);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(mach_assign_to_arg) {
|
||||||
|
const char *src = "function f(x) { x = 5 }";
|
||||||
|
char *ast_json = JS_AST(ctx, src, strlen(src), "<test>");
|
||||||
|
ASSERT_MSG(ast_json != NULL, "JS_AST returned NULL");
|
||||||
|
char *mach_json = JS_Mach(ctx, ast_json);
|
||||||
|
free(ast_json);
|
||||||
|
ASSERT_MSG(mach_json != NULL, "JS_Mach returned NULL");
|
||||||
|
ASSERT_ERROR_MSG_CONTAINS(mach_json, "cannot assign to function argument");
|
||||||
|
free(mach_json);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(mach_redeclare_const) {
|
||||||
|
const char *src = "def x = 1; def x = 2";
|
||||||
|
char *ast_json = JS_AST(ctx, src, strlen(src), "<test>");
|
||||||
|
ASSERT_MSG(ast_json != NULL, "JS_AST returned NULL");
|
||||||
|
char *mach_json = JS_Mach(ctx, ast_json);
|
||||||
|
free(ast_json);
|
||||||
|
ASSERT_MSG(mach_json != NULL, "JS_Mach returned NULL");
|
||||||
|
ASSERT_ERROR_MSG_CONTAINS(mach_json, "cannot redeclare constant");
|
||||||
|
free(mach_json);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(mach_break_outside_loop) {
|
||||||
|
const char *src = "break";
|
||||||
|
char *ast_json = JS_AST(ctx, src, strlen(src), "<test>");
|
||||||
|
ASSERT_MSG(ast_json != NULL, "JS_AST returned NULL");
|
||||||
|
char *mach_json = JS_Mach(ctx, ast_json);
|
||||||
|
free(ast_json);
|
||||||
|
ASSERT_MSG(mach_json != NULL, "JS_Mach returned NULL");
|
||||||
|
ASSERT_ERROR_MSG_CONTAINS(mach_json, "outside of loop");
|
||||||
|
free(mach_json);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(mach_continue_outside_loop) {
|
||||||
|
const char *src = "continue";
|
||||||
|
char *ast_json = JS_AST(ctx, src, strlen(src), "<test>");
|
||||||
|
ASSERT_MSG(ast_json != NULL, "JS_AST returned NULL");
|
||||||
|
char *mach_json = JS_Mach(ctx, ast_json);
|
||||||
|
free(ast_json);
|
||||||
|
ASSERT_MSG(mach_json != NULL, "JS_Mach returned NULL");
|
||||||
|
ASSERT_ERROR_MSG_CONTAINS(mach_json, "outside of loop");
|
||||||
|
free(mach_json);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(mach_assign_unbound_var) {
|
||||||
|
const char *src = "x = 42";
|
||||||
|
char *ast_json = JS_AST(ctx, src, strlen(src), "<test>");
|
||||||
|
ASSERT_MSG(ast_json != NULL, "JS_AST returned NULL");
|
||||||
|
char *mach_json = JS_Mach(ctx, ast_json);
|
||||||
|
free(ast_json);
|
||||||
|
ASSERT_MSG(mach_json != NULL, "JS_Mach returned NULL");
|
||||||
|
ASSERT_ERROR_MSG_CONTAINS(mach_json, "not declared");
|
||||||
|
free(mach_json);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(mach_shadow_is_ok) {
|
||||||
|
const char *src = "var array = []; array";
|
||||||
|
char *ast_json = JS_AST(ctx, src, strlen(src), "<test>");
|
||||||
|
ASSERT_MSG(ast_json != NULL, "JS_AST returned NULL");
|
||||||
|
char *mach_json = JS_Mach(ctx, ast_json);
|
||||||
|
free(ast_json);
|
||||||
|
ASSERT_MSG(mach_json != NULL, "JS_Mach returned NULL");
|
||||||
|
ASSERT_NO_ERRORS(mach_json);
|
||||||
|
free(mach_json);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(mach_valid_no_errors) {
|
||||||
|
const char *src = "var x = 1; x = x + 1";
|
||||||
|
char *ast_json = JS_AST(ctx, src, strlen(src), "<test>");
|
||||||
|
ASSERT_MSG(ast_json != NULL, "JS_AST returned NULL");
|
||||||
|
char *mach_json = JS_Mach(ctx, ast_json);
|
||||||
|
free(ast_json);
|
||||||
|
ASSERT_MSG(mach_json != NULL, "JS_Mach returned NULL");
|
||||||
|
ASSERT_NO_ERRORS(mach_json);
|
||||||
|
free(mach_json);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* ============================================================================
|
/* ============================================================================
|
||||||
MAIN TEST RUNNER
|
MAIN TEST RUNNER
|
||||||
============================================================================ */
|
============================================================================ */
|
||||||
@@ -2348,6 +2703,43 @@ int run_c_test_suite(JSContext *ctx)
|
|||||||
RUN_TEST(cell_module_roundtrip_execute);
|
RUN_TEST(cell_module_roundtrip_execute);
|
||||||
RUN_TEST(cell_module_string_constant);
|
RUN_TEST(cell_module_string_constant);
|
||||||
|
|
||||||
|
printf("\nTokenizer Errors:\n");
|
||||||
|
RUN_TEST(tokenize_unterminated_string);
|
||||||
|
RUN_TEST(tokenize_unterminated_template);
|
||||||
|
RUN_TEST(tokenize_unterminated_block_comment);
|
||||||
|
RUN_TEST(tokenize_malformed_hex);
|
||||||
|
RUN_TEST(tokenize_malformed_binary);
|
||||||
|
RUN_TEST(tokenize_malformed_exponent);
|
||||||
|
RUN_TEST(tokenize_valid_no_errors);
|
||||||
|
|
||||||
|
printf("\nParser Errors:\n");
|
||||||
|
RUN_TEST(ast_missing_identifier_after_var);
|
||||||
|
RUN_TEST(ast_missing_initializer_def);
|
||||||
|
RUN_TEST(ast_recovery_continues_after_error);
|
||||||
|
RUN_TEST(ast_valid_no_errors);
|
||||||
|
|
||||||
|
printf("\nAST Semantic Errors:\n");
|
||||||
|
RUN_TEST(ast_sem_assign_to_const);
|
||||||
|
RUN_TEST(ast_sem_assign_to_arg);
|
||||||
|
RUN_TEST(ast_sem_redeclare_const);
|
||||||
|
RUN_TEST(ast_sem_break_outside_loop);
|
||||||
|
RUN_TEST(ast_sem_continue_outside_loop);
|
||||||
|
RUN_TEST(ast_sem_break_inside_loop_ok);
|
||||||
|
RUN_TEST(ast_sem_increment_const);
|
||||||
|
RUN_TEST(ast_sem_shadow_var_ok);
|
||||||
|
RUN_TEST(ast_sem_var_assign_ok);
|
||||||
|
RUN_TEST(ast_sem_nested_function_scope);
|
||||||
|
|
||||||
|
printf("\nCodegen Errors:\n");
|
||||||
|
RUN_TEST(mach_assign_to_const);
|
||||||
|
RUN_TEST(mach_assign_to_arg);
|
||||||
|
RUN_TEST(mach_redeclare_const);
|
||||||
|
RUN_TEST(mach_break_outside_loop);
|
||||||
|
RUN_TEST(mach_continue_outside_loop);
|
||||||
|
RUN_TEST(mach_assign_unbound_var);
|
||||||
|
RUN_TEST(mach_shadow_is_ok);
|
||||||
|
RUN_TEST(mach_valid_no_errors);
|
||||||
|
|
||||||
printf("\n=================================\n");
|
printf("\n=================================\n");
|
||||||
printf("Results: %d passed, %d failed\n", tests_passed, tests_failed);
|
printf("Results: %d passed, %d failed\n", tests_passed, tests_failed);
|
||||||
printf("=================================\n\n");
|
printf("=================================\n\n");
|
||||||
|
|||||||
1
vm_test/arrow_block.txt
Normal file
1
vm_test/arrow_block.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var f = x => { return x }; f(1)
|
||||||
1
vm_test/arrow_default.txt
Normal file
1
vm_test/arrow_default.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var f = (x = 10) => x; f()
|
||||||
1
vm_test/arrow_expr.txt
Normal file
1
vm_test/arrow_expr.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var f = x => x * 2; f(5)
|
||||||
1
vm_test/arrow_multi.txt
Normal file
1
vm_test/arrow_multi.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var f = (a, b) => a + b; f(2, 3)
|
||||||
1
vm_test/arrow_no_param.txt
Normal file
1
vm_test/arrow_no_param.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var f = () => 42; f()
|
||||||
1
vm_test/assign_add.txt
Normal file
1
vm_test/assign_add.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var x = 5; x += 3; x
|
||||||
1
vm_test/assign_and.txt
Normal file
1
vm_test/assign_and.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var x = 7; x &= 3; x
|
||||||
1
vm_test/assign_div.txt
Normal file
1
vm_test/assign_div.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var x = 6; x /= 2; x
|
||||||
1
vm_test/assign_land.txt
Normal file
1
vm_test/assign_land.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var x = 5; x &&= 10; x
|
||||||
1
vm_test/assign_lor.txt
Normal file
1
vm_test/assign_lor.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var x = 0; x ||= 10; x
|
||||||
1
vm_test/assign_mod.txt
Normal file
1
vm_test/assign_mod.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var x = 7; x %= 3; x
|
||||||
1
vm_test/assign_mul.txt
Normal file
1
vm_test/assign_mul.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var x = 5; x *= 3; x
|
||||||
1
vm_test/assign_nullish.txt
Normal file
1
vm_test/assign_nullish.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var x = null; x ??= 10; x
|
||||||
1
vm_test/assign_or.txt
Normal file
1
vm_test/assign_or.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var x = 5; x |= 2; x
|
||||||
1
vm_test/assign_power.txt
Normal file
1
vm_test/assign_power.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var x = 2; x **= 3; x
|
||||||
1
vm_test/assign_shl.txt
Normal file
1
vm_test/assign_shl.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var x = 2; x <<= 3; x
|
||||||
1
vm_test/assign_shr.txt
Normal file
1
vm_test/assign_shr.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var x = 8; x >>= 2; x
|
||||||
1
vm_test/assign_shru.txt
Normal file
1
vm_test/assign_shru.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var x = -8; x >>>= 2; x
|
||||||
1
vm_test/assign_sub.txt
Normal file
1
vm_test/assign_sub.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var x = 5; x -= 3; x
|
||||||
1
vm_test/assign_xor.txt
Normal file
1
vm_test/assign_xor.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var x = 5; x ^= 3; x
|
||||||
1
vm_test/chained_assign.txt
Normal file
1
vm_test/chained_assign.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var x, y; x = y = 5; x + y
|
||||||
1
vm_test/closure_basic.txt
Normal file
1
vm_test/closure_basic.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var f = function(x) { return function() { return x } }; f(5)()
|
||||||
11
vm_test/closure_mutate.txt
Normal file
11
vm_test/closure_mutate.txt
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
var counter = function() {
|
||||||
|
var n = 0
|
||||||
|
return function() {
|
||||||
|
n = n + 1
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var c = counter()
|
||||||
|
c()
|
||||||
|
c()
|
||||||
|
c()
|
||||||
3
vm_test/comment.txt
Normal file
3
vm_test/comment.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
// simple test that comments work
|
||||||
|
var x = 5
|
||||||
|
// other comment
|
||||||
1
vm_test/comment_block.txt
Normal file
1
vm_test/comment_block.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/* comment */ 5
|
||||||
1
vm_test/comment_multi.txt
Normal file
1
vm_test/comment_multi.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
1 /* a */ + /* b */ 2
|
||||||
1
vm_test/def_basic.txt
Normal file
1
vm_test/def_basic.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
def x = 5; x
|
||||||
1
vm_test/do_while.txt
Normal file
1
vm_test/do_while.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var i = 0; do { i = i + 1 } while (i < 3); i
|
||||||
1
vm_test/do_while_continue.txt
Normal file
1
vm_test/do_while_continue.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var s = 0; var i = 0; do { i = i + 1; if (i == 2) continue; s = s + i } while (i < 5); s
|
||||||
1
vm_test/empty_statement.txt
Normal file
1
vm_test/empty_statement.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
;;; 5
|
||||||
1
vm_test/for_basic.txt
Normal file
1
vm_test/for_basic.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var s = 0; for (var i = 0; i < 3; i++) s = s + i; s
|
||||||
1
vm_test/for_break.txt
Normal file
1
vm_test/for_break.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var s = 0; for (var i = 0; i < 10; i++) { if (i == 4) break; s = s + i }; s
|
||||||
1
vm_test/for_continue.txt
Normal file
1
vm_test/for_continue.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var s = 0; for (var i = 0; i < 5; i++) { if (i == 2) continue; s = s + i }; s
|
||||||
1
vm_test/func_expr.txt
Normal file
1
vm_test/func_expr.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var f = function(x) { return x * 2 }; f(3)
|
||||||
1
vm_test/func_iife.txt
Normal file
1
vm_test/func_iife.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
(function(x) { return x * 2 })(5)
|
||||||
1
vm_test/func_recursive.txt
Normal file
1
vm_test/func_recursive.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
function fac(n) { if (n <= 1) return 1; return n * fac(n - 1) }; fac(5)
|
||||||
2
vm_test/go_basic.txt
Normal file
2
vm_test/go_basic.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
function a() { go b() }
|
||||||
|
function b() { 1 }
|
||||||
2
vm_test/go_method.txt
Normal file
2
vm_test/go_method.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
var o = {m: function() { 1 }}
|
||||||
|
function f() { go o.m() }
|
||||||
1
vm_test/if_basic.txt
Normal file
1
vm_test/if_basic.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var x = 0; if (true) x = 1; x
|
||||||
1
vm_test/if_else.txt
Normal file
1
vm_test/if_else.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
if (false) 1 else 2
|
||||||
1
vm_test/intrisic_link.txt
Normal file
1
vm_test/intrisic_link.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
print("a")
|
||||||
1
vm_test/label_break.txt
Normal file
1
vm_test/label_break.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var x = 0; outer: { x = 1; break outer; x = 2 }; x
|
||||||
1
vm_test/label_continue.txt
Normal file
1
vm_test/label_continue.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var s = 0; outer: for (var i = 0; i < 3; i++) { for (var j = 0; j < 3; j++) { if (j == 1) continue outer; s = s + 1 } }; s
|
||||||
1
vm_test/multi_var.txt
Normal file
1
vm_test/multi_var.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var x = 1, y = 2; x + y
|
||||||
1
vm_test/nested_block.txt
Normal file
1
vm_test/nested_block.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var x = 1; { var y = 2; { var z = 3; x = x + y + z } }; x
|
||||||
1
vm_test/num_binary.txt
Normal file
1
vm_test/num_binary.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
0b1010
|
||||||
1
vm_test/num_exp.txt
Normal file
1
vm_test/num_exp.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
1e3
|
||||||
1
vm_test/num_float.txt
Normal file
1
vm_test/num_float.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
3.14
|
||||||
1
vm_test/num_hex.txt
Normal file
1
vm_test/num_hex.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
0xff
|
||||||
1
vm_test/num_octal.txt
Normal file
1
vm_test/num_octal.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
0o17
|
||||||
1
vm_test/num_underscore.txt
Normal file
1
vm_test/num_underscore.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
1_000_000
|
||||||
1
vm_test/op_arith.txt
Normal file
1
vm_test/op_arith.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
1 + 2 * 3
|
||||||
1
vm_test/op_bitwise.txt
Normal file
1
vm_test/op_bitwise.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
5 & 3
|
||||||
1
vm_test/op_bitwise_not.txt
Normal file
1
vm_test/op_bitwise_not.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
~5
|
||||||
1
vm_test/op_bitwise_or.txt
Normal file
1
vm_test/op_bitwise_or.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
5 | 2
|
||||||
1
vm_test/op_bitwise_xor.txt
Normal file
1
vm_test/op_bitwise_xor.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
5 ^ 3
|
||||||
1
vm_test/op_comma.txt
Normal file
1
vm_test/op_comma.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
(1, 2, 3)
|
||||||
1
vm_test/op_compare.txt
Normal file
1
vm_test/op_compare.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
5 > 3
|
||||||
1
vm_test/op_compare_eq.txt
Normal file
1
vm_test/op_compare_eq.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
3 == 3
|
||||||
1
vm_test/op_compare_gte.txt
Normal file
1
vm_test/op_compare_gte.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
5 >= 5
|
||||||
1
vm_test/op_compare_lt.txt
Normal file
1
vm_test/op_compare_lt.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
3 < 5
|
||||||
1
vm_test/op_compare_lte.txt
Normal file
1
vm_test/op_compare_lte.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
3 <= 3
|
||||||
1
vm_test/op_compare_neq.txt
Normal file
1
vm_test/op_compare_neq.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
3 != 4
|
||||||
1
vm_test/op_decrement_post.txt
Normal file
1
vm_test/op_decrement_post.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var x = 5; x--; x
|
||||||
1
vm_test/op_decrement_pre.txt
Normal file
1
vm_test/op_decrement_pre.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var x = 5; --x
|
||||||
1
vm_test/op_delete.txt
Normal file
1
vm_test/op_delete.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var o = {x: 1}; delete o.x; o.x
|
||||||
1
vm_test/op_in.txt
Normal file
1
vm_test/op_in.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var o = {x: 1}; "x" in o
|
||||||
1
vm_test/op_increment_post.txt
Normal file
1
vm_test/op_increment_post.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var x = 5; x++; x
|
||||||
1
vm_test/op_increment_pre.txt
Normal file
1
vm_test/op_increment_pre.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var x = 5; ++x
|
||||||
1
vm_test/op_logical.txt
Normal file
1
vm_test/op_logical.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
true && false
|
||||||
1
vm_test/op_logical_not.txt
Normal file
1
vm_test/op_logical_not.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
!false
|
||||||
1
vm_test/op_logical_or.txt
Normal file
1
vm_test/op_logical_or.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
false || true
|
||||||
1
vm_test/op_nullish.txt
Normal file
1
vm_test/op_nullish.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
null ?? 5
|
||||||
1
vm_test/op_power.txt
Normal file
1
vm_test/op_power.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
2 ** 3
|
||||||
1
vm_test/op_shift_left.txt
Normal file
1
vm_test/op_shift_left.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
2 << 3
|
||||||
1
vm_test/op_shift_right.txt
Normal file
1
vm_test/op_shift_right.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
8 >> 2
|
||||||
1
vm_test/op_shift_right_unsigned.txt
Normal file
1
vm_test/op_shift_right_unsigned.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
-8 >>> 2
|
||||||
1
vm_test/op_ternary.txt
Normal file
1
vm_test/op_ternary.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
true ? 1 : 2
|
||||||
1
vm_test/op_typeof.txt
Normal file
1
vm_test/op_typeof.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
typeof 5
|
||||||
1
vm_test/op_unary_minus.txt
Normal file
1
vm_test/op_unary_minus.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
-5
|
||||||
1
vm_test/op_unary_plus.txt
Normal file
1
vm_test/op_unary_plus.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
+"5"
|
||||||
1
vm_test/op_void.txt
Normal file
1
vm_test/op_void.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
void 0
|
||||||
1
vm_test/optional_bracket.txt
Normal file
1
vm_test/optional_bracket.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var o = {a: 1}; o?.["a"]
|
||||||
1
vm_test/optional_call.txt
Normal file
1
vm_test/optional_call.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var o = {f: () => 1}; o.f?.()
|
||||||
1
vm_test/optional_null.txt
Normal file
1
vm_test/optional_null.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var o = null; o?.a
|
||||||
1
vm_test/optional_prop.txt
Normal file
1
vm_test/optional_prop.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var o = {a: 1}; o?.a
|
||||||
1
vm_test/paren_precedence.txt
Normal file
1
vm_test/paren_precedence.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
(1 + 2) * 3
|
||||||
1
vm_test/record_bracket.txt
Normal file
1
vm_test/record_bracket.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var a = {x: 1}; a["x"]
|
||||||
1
vm_test/record_chain.txt
Normal file
1
vm_test/record_chain.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var o = {a: {b: {c: 1}}}; o.a.b.c
|
||||||
1
vm_test/record_computed.txt
Normal file
1
vm_test/record_computed.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var k = "x"; var a = {x: 1}; a[k]
|
||||||
1
vm_test/record_dot.txt
Normal file
1
vm_test/record_dot.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var a = {x: 1}; a.x
|
||||||
1
vm_test/record_nested.txt
Normal file
1
vm_test/record_nested.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var o = {a: {b: 1}}; o.a.b
|
||||||
1
vm_test/record_numeric_key.txt
Normal file
1
vm_test/record_numeric_key.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var o = {1: "one"}; o[1]
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user