ref: a442a0418f06b673559c93a69e3167b4460d6d07
dir: /jsi.h/
#ifndef jsi_h
#define jsi_h
#include "mujs.h"
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdarg.h>
#include <string.h>
#include <setjmp.h>
#include <math.h>
#include <float.h>
#include <limits.h>
/* NOTE: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103052 */
#ifdef __GNUC__
#if (__GNUC__ >= 6)
#pragma GCC optimize ("no-ipa-pure-const")
#endif
#endif
/* Microsoft Visual C */
#ifdef _MSC_VER
#pragma warning(disable:4996) /* _CRT_SECURE_NO_WARNINGS */
#pragma warning(disable:4244) /* implicit conversion from double to int */
#pragma warning(disable:4267) /* implicit conversion of int to smaller int */
#pragma warning(disable:4090) /* broken const warnings */
#define inline __inline
#if _MSC_VER < 1900 /* MSVC 2015 */
#define snprintf jsW_snprintf
#define vsnprintf jsW_vsnprintf
static int jsW_vsnprintf(char *str, size_t size, const char *fmt, va_list ap)
{
int n;
n = _vsnprintf(str, size, fmt, ap);
str[size-1] = 0;
return n;
}
static int jsW_snprintf(char *str, size_t size, const char *fmt, ...)
{
int n;
va_list ap;
va_start(ap, fmt);
n = jsW_vsnprintf(str, size, fmt, ap);
va_end(ap);
return n;
}
#endif
#if _MSC_VER <= 1700 /* <= MSVC 2012 */
#define isnan(x) _isnan(x)
#define isinf(x) (!_finite(x))
#define isfinite(x) _finite(x)
static __inline int signbit(double x) { __int64 i; memcpy(&i, &x, 8); return i>>63; }
#define INFINITY (DBL_MAX+DBL_MAX)
#define NAN (INFINITY-INFINITY)
#endif
#endif
#define soffsetof(x,y) ((int)offsetof(x,y))
#define nelem(a) (int)(sizeof (a) / sizeof (a)[0])
void *js_malloc(js_State *J, int size);
void *js_realloc(js_State *J, void *ptr, int size);
void js_free(js_State *J, void *ptr);
typedef union js_Value js_Value;
typedef struct js_Regexp js_Regexp;
typedef struct js_Object js_Object;
typedef struct js_String js_String;
typedef struct js_Ast js_Ast;
typedef struct js_Function js_Function;
typedef struct js_Environment js_Environment;
typedef struct js_StringNode js_StringNode;
typedef struct js_Jumpbuf js_Jumpbuf;
typedef struct js_StackTrace js_StackTrace;
/* Limits */
#ifndef JS_STACKSIZE
#define JS_STACKSIZE 4096 /* value stack size */
#endif
#ifndef JS_ENVLIMIT
#define JS_ENVLIMIT 1024 /* environment stack size */
#endif
#ifndef JS_TRYLIMIT
#define JS_TRYLIMIT 64 /* exception stack size */
#endif
#ifndef JS_ARRAYLIMIT
#define JS_ARRAYLIMIT (1<<26) /* limit arrays to 64M entries (1G of flat array data) */
#endif
#ifndef JS_GCFACTOR
/*
* GC will try to trigger when memory usage is this value times the minimum
* needed memory. E.g. if there are 100 remaining objects after GC and this
* value is 5.0, then the next GC will trigger when the overall number is 500.
* I.e. a value of 5.0 aims at 80% garbage, 20% remain-used on each GC.
* The bigger the value the less impact GC has on overall performance, but more
* memory is used and individual GC pauses are longer (but fewer).
*/
#define JS_GCFACTOR 5.0 /* memory overhead factor >= 1.0 */
#endif
#ifndef JS_ASTLIMIT
#define JS_ASTLIMIT 400 /* max nested expressions */
#endif
#ifndef JS_STRLIMIT
#define JS_STRLIMIT (1<<28) /* max string length */
#endif
/* instruction size -- change to int if you get integer overflow syntax errors */
#ifdef JS_INSTRUCTION
typedef JS_INSTRUCTION js_Instruction;
#else
typedef unsigned short js_Instruction;
#endif
/* String interning */
char *js_strdup(js_State *J, const char *s);
const char *js_intern(js_State *J, const char *s);
void jsS_dumpstrings(js_State *J);
void jsS_freestrings(js_State *J);
/* Portable strtod and printf float formatting */
void js_fmtexp(char *p, int e);
int js_grisu2(double v, char *buffer, int *K);
double js_strtod(const char *as, char **aas);
double js_strtol(const char *s, char **ep, int radix);
/* Private stack functions */
void js_newarguments(js_State *J);
void js_newfunction(js_State *J, js_Function *function, js_Environment *scope);
void js_newscript(js_State *J, js_Function *function, js_Environment *scope);
void js_loadeval(js_State *J, const char *filename, const char *source);
js_Regexp *js_toregexp(js_State *J, int idx);
int js_isarrayindex(js_State *J, const char *str, int *idx);
int js_runeat(js_State *J, const char *s, int i);
int js_utfptrtoidx(const char *s, const char *p);
const char *js_utfidxtoptr(const char *s, int i);
void js_dup(js_State *J);
void js_dup2(js_State *J);
void js_rot2(js_State *J);
void js_rot3(js_State *J);
void js_rot4(js_State *J);
void js_rot2pop1(js_State *J);
void js_rot3pop2(js_State *J);
void js_dup1rot3(js_State *J);
void js_dup1rot4(js_State *J);
void js_RegExp_prototype_exec(js_State *J, js_Regexp *re, const char *text);
void js_trap(js_State *J, int pc); /* dump stack and environment to stdout */
struct js_StackTrace
{
const char *name;
const char *file;
int line;
};
/* Exception handling */
struct js_Jumpbuf
{
jmp_buf buf;
js_Environment *E;
int envtop;
int tracetop;
int top, bot;
int strict;
js_Instruction *pc;
};
void *js_savetrypc(js_State *J, js_Instruction *pc);
#define js_trypc(J, PC) \
setjmp(js_savetrypc(J, PC))
/* String buffer */
typedef struct js_Buffer { int n, m; char s[64]; } js_Buffer;
void js_putc(js_State *J, js_Buffer **sbp, int c);
void js_puts(js_State *J, js_Buffer **sb, const char *s);
void js_putm(js_State *J, js_Buffer **sb, const char *s, const char *e);
/* State struct */
struct js_State
{
void *actx;
void *uctx;
js_Alloc alloc;
js_Report report;
js_Panic panic;
js_StringNode *strings;
int default_strict;
int strict;
/* parser input source */
const char *filename;
const char *source;
int line;
/* lexer state */
struct { char *text; int len, cap; } lexbuf;
int lexline;
int lexchar;
int lasttoken;
int newline;
/* parser state */
int astdepth;
int lookahead;
const char *text;
double number;
js_Ast *gcast; /* list of allocated nodes to free after parsing */
/* runtime environment */
js_Object *Object_prototype;
js_Object *Array_prototype;
js_Object *Function_prototype;
js_Object *Boolean_prototype;
js_Object *Number_prototype;
js_Object *String_prototype;
js_Object *RegExp_prototype;
js_Object *Date_prototype;
js_Object *Error_prototype;
js_Object *EvalError_prototype;
js_Object *RangeError_prototype;
js_Object *ReferenceError_prototype;
js_Object *SyntaxError_prototype;
js_Object *TypeError_prototype;
js_Object *URIError_prototype;
unsigned int seed; /* Math.random seed */
char scratch[12]; /* scratch buffer for iterating over array indices */
int nextref; /* for js_ref use */
js_Object *R; /* registry of hidden values */
js_Object *G; /* the global object */
js_Environment *E; /* current environment scope */
js_Environment *GE; /* global environment scope (at the root) */
/* execution stack */
int top, bot;
js_Value *stack;
/* garbage collector list */
int gcpause;
int gcmark;
unsigned int gccounter, gcthresh;
js_Environment *gcenv;
js_Function *gcfun;
js_Object *gcobj;
js_String *gcstr;
js_Object *gcroot; /* gc scan list */
/* environments on the call stack but currently not in scope */
int envtop;
js_Environment *envstack[JS_ENVLIMIT];
/* debug info stack trace */
int tracetop;
js_StackTrace trace[JS_ENVLIMIT];
/* exception stack */
int trytop;
js_Jumpbuf trybuf[JS_TRYLIMIT];
};
/* Values */
typedef struct js_Property js_Property;
typedef struct js_Iterator js_Iterator;
/* Hint to ToPrimitive() */
enum {
JS_HNONE,
JS_HNUMBER,
JS_HSTRING
};
enum js_Type {
JS_TSHRSTR, /* type tag doubles as string zero-terminator */
JS_TUNDEFINED,
JS_TNULL,
JS_TBOOLEAN,
JS_TNUMBER,
JS_TLITSTR,
JS_TMEMSTR,
JS_TOBJECT,
};
enum js_Class {
JS_COBJECT,
JS_CARRAY,
JS_CFUNCTION,
JS_CSCRIPT, /* function created from global/eval code */
JS_CCFUNCTION, /* built-in function */
JS_CERROR,
JS_CBOOLEAN,
JS_CNUMBER,
JS_CSTRING,
JS_CREGEXP,
JS_CDATE,
JS_CMATH,
JS_CJSON,
JS_CARGUMENTS,
JS_CITERATOR,
JS_CUSERDATA,
};
/*
Short strings abuse the js_Value struct. By putting the type tag in the
last byte, and using 0 as the tag for short strings, we can use the
entire js_Value as string storage by letting the type tag serve double
purpose as the string zero terminator.
*/
union js_Value
{
struct {
char pad[15];
char type; /* type tag overlaps with final byte of shrstr */
} t;
union {
char shrstr[16];
int boolean;
double number;
const char *litstr;
js_String *memstr;
js_Object *object;
} u;
};
struct js_String
{
js_String *gcnext;
char gcmark;
char p[1];
};
struct js_Regexp
{
void *prog;
char *source;
unsigned short flags;
unsigned short last;
};
struct js_Object
{
enum js_Class type;
int extensible;
js_Property *properties;
int count; /* number of properties, for array sparseness check */
js_Object *prototype;
union {
int boolean;
double number;
struct {
int length;
char *string;
char shrstr[16];
} s;
struct {
int length; /* actual length */
int simple; /* true if array has only non-sparse array properties */
int flat_length; /* used length of simple array part */
int flat_capacity; /* allocated length of simple array part */
js_Value *array;
} a;
struct {
js_Function *function;
js_Environment *scope;
} f;
struct {
const char *name;
js_CFunction function;
js_CFunction constructor;
int length;
void *data;
js_Finalize finalize;
} c;
js_Regexp r;
struct {
js_Object *target;
int i, n; /* for array part */
js_Iterator *head, *current; /* for object part */
} iter;
struct {
const char *tag;
void *data;
js_HasProperty has;
js_Put put;
js_Delete delete;
js_Finalize finalize;
} user;
} u;
js_Object *gcnext; /* allocation list */
js_Object *gcroot; /* scan list */
int gcmark;
};
struct js_Property
{
js_Property *left, *right;
int level;
int atts;
js_Value value;
js_Object *getter;
js_Object *setter;
char name[1];
};
struct js_Iterator
{
js_Iterator *next;
char name[1];
};
struct js_Environment
{
js_Environment *outer;
js_Object *variables;
js_Environment *gcnext;
int gcmark;
};
/* jsrun.c */
js_Environment *jsR_newenvironment(js_State *J, js_Object *variables, js_Environment *outer);
js_String *jsV_newmemstring(js_State *J, const char *s, int n);
js_Value *js_tovalue(js_State *J, int idx);
void js_toprimitive(js_State *J, int idx, int hint);
js_Object *js_toobject(js_State *J, int idx);
void js_pushvalue(js_State *J, js_Value v);
void js_pushobject(js_State *J, js_Object *v);
void jsR_unflattenarray(js_State *J, js_Object *obj);
/* jsvalue.c */
int jsV_toboolean(js_State *J, js_Value *v);
double jsV_tonumber(js_State *J, js_Value *v);
double jsV_tointeger(js_State *J, js_Value *v);
const char *jsV_tostring(js_State *J, js_Value *v);
js_Object *jsV_toobject(js_State *J, js_Value *v);
void jsV_toprimitive(js_State *J, js_Value *v, int preferred);
const char *js_itoa(char *buf, int a);
double js_stringtofloat(const char *s, char **ep);
int jsV_numbertointeger(double n);
int jsV_numbertoint32(double n);
unsigned int jsV_numbertouint32(double n);
short jsV_numbertoint16(double n);
unsigned short jsV_numbertouint16(double n);
const char *jsV_numbertostring(js_State *J, char buf[32], double number);
double jsV_stringtonumber(js_State *J, const char *string);
/* jsproperty.c */
js_Object *jsV_newobject(js_State *J, enum js_Class type, js_Object *prototype);
js_Property *jsV_getownproperty(js_State *J, js_Object *obj, const char *name);
js_Property *jsV_getpropertyx(js_State *J, js_Object *obj, const char *name, int *own);
js_Property *jsV_getproperty(js_State *J, js_Object *obj, const char *name);
js_Property *jsV_setproperty(js_State *J, js_Object *obj, const char *name);
js_Property *jsV_nextproperty(js_State *J, js_Object *obj, const char *name);
void jsV_delproperty(js_State *J, js_Object *obj, const char *name);
js_Object *jsV_newiterator(js_State *J, js_Object *obj, int own);
const char *jsV_nextiterator(js_State *J, js_Object *iter);
void jsV_resizearray(js_State *J, js_Object *obj, int newlen);
void jsV_unflattenarray(js_State *J, js_Object *obj);
void jsV_growarray(js_State *J, js_Object *obj);
/* Lexer */
enum
{
TK_IDENTIFIER = 256,
TK_NUMBER,
TK_STRING,
TK_REGEXP,
/* multi-character punctuators */
TK_LE,
TK_GE,
TK_EQ,
TK_NE,
TK_STRICTEQ,
TK_STRICTNE,
TK_SHL,
TK_SHR,
TK_USHR,
TK_AND,
TK_OR,
TK_ADD_ASS,
TK_SUB_ASS,
TK_MUL_ASS,
TK_DIV_ASS,
TK_MOD_ASS,
TK_SHL_ASS,
TK_SHR_ASS,
TK_USHR_ASS,
TK_AND_ASS,
TK_OR_ASS,
TK_XOR_ASS,
TK_INC,
TK_DEC,
/* keywords */
TK_BREAK,
TK_CASE,
TK_CATCH,
TK_CONTINUE,
TK_DEBUGGER,
TK_DEFAULT,
TK_DELETE,
TK_DO,
TK_ELSE,
TK_FALSE,
TK_FINALLY,
TK_FOR,
TK_FUNCTION,
TK_IF,
TK_IN,
TK_INSTANCEOF,
TK_NEW,
TK_NULL,
TK_RETURN,
TK_SWITCH,
TK_THIS,
TK_THROW,
TK_TRUE,
TK_TRY,
TK_TYPEOF,
TK_VAR,
TK_VOID,
TK_WHILE,
TK_WITH,
};
int jsY_iswhite(int c);
int jsY_isnewline(int c);
int jsY_ishex(int c);
int jsY_tohex(int c);
const char *jsY_tokenstring(int token);
int jsY_findword(const char *s, const char **list, int num);
void jsY_initlex(js_State *J, const char *filename, const char *source);
int jsY_lex(js_State *J);
int jsY_lexjson(js_State *J);
/* Parser */
enum js_AstType
{
AST_LIST,
AST_FUNDEC,
AST_IDENTIFIER,
EXP_IDENTIFIER,
EXP_NUMBER,
EXP_STRING,
EXP_REGEXP,
/* literals */
EXP_ELISION, /* for array elisions */
EXP_NULL,
EXP_TRUE,
EXP_FALSE,
EXP_THIS,
EXP_ARRAY,
EXP_OBJECT,
EXP_PROP_VAL,
EXP_PROP_GET,
EXP_PROP_SET,
EXP_FUN,
/* expressions */
EXP_INDEX,
EXP_MEMBER,
EXP_CALL,
EXP_NEW,
EXP_POSTINC,
EXP_POSTDEC,
EXP_DELETE,
EXP_VOID,
EXP_TYPEOF,
EXP_PREINC,
EXP_PREDEC,
EXP_POS,
EXP_NEG,
EXP_BITNOT,
EXP_LOGNOT,
EXP_MOD,
EXP_DIV,
EXP_MUL,
EXP_SUB,
EXP_ADD,
EXP_USHR,
EXP_SHR,
EXP_SHL,
EXP_IN,
EXP_INSTANCEOF,
EXP_GE,
EXP_LE,
EXP_GT,
EXP_LT,
EXP_STRICTNE,
EXP_STRICTEQ,
EXP_NE,
EXP_EQ,
EXP_BITAND,
EXP_BITXOR,
EXP_BITOR,
EXP_LOGAND,
EXP_LOGOR,
EXP_COND,
EXP_ASS,
EXP_ASS_MUL,
EXP_ASS_DIV,
EXP_ASS_MOD,
EXP_ASS_ADD,
EXP_ASS_SUB,
EXP_ASS_SHL,
EXP_ASS_SHR,
EXP_ASS_USHR,
EXP_ASS_BITAND,
EXP_ASS_BITXOR,
EXP_ASS_BITOR,
EXP_COMMA,
EXP_VAR, /* var initializer */
/* statements */
STM_BLOCK,
STM_EMPTY,
STM_VAR,
STM_IF,
STM_DO,
STM_WHILE,
STM_FOR,
STM_FOR_VAR,
STM_FOR_IN,
STM_FOR_IN_VAR,
STM_CONTINUE,
STM_BREAK,
STM_RETURN,
STM_WITH,
STM_SWITCH,
STM_THROW,
STM_TRY,
STM_DEBUGGER,
STM_LABEL,
STM_CASE,
STM_DEFAULT,
};
typedef struct js_JumpList js_JumpList;
struct js_JumpList
{
enum js_AstType type;
int inst;
js_JumpList *next;
};
struct js_Ast
{
enum js_AstType type;
int line;
js_Ast *parent, *a, *b, *c, *d;
double number;
const char *string;
js_JumpList *jumps; /* list of break/continue jumps to patch */
int casejump; /* for switch case clauses */
js_Ast *gcnext; /* next in alloc list */
};
js_Ast *jsP_parsefunction(js_State *J, const char *filename, const char *params, const char *body);
js_Ast *jsP_parse(js_State *J, const char *filename, const char *source);
void jsP_freeparse(js_State *J);
/* Compiler */
enum js_OpCode
{
OP_POP, /* A -- */
OP_DUP, /* A -- A A */
OP_DUP2, /* A B -- A B A B */
OP_ROT2, /* A B -- B A */
OP_ROT3, /* A B C -- C A B */
OP_ROT4, /* A B C D -- D A B C */
OP_INTEGER, /* -K- (number-32768) */
OP_NUMBER, /* -N- <number> */
OP_STRING, /* -S- <string> */
OP_CLOSURE, /* -F- <closure> */
OP_NEWARRAY,
OP_NEWOBJECT,
OP_NEWREGEXP, /* -S,opts- <regexp> */
OP_UNDEF,
OP_NULL,
OP_TRUE,
OP_FALSE,
OP_THIS,
OP_CURRENT, /* currently executing function object */
OP_GETLOCAL, /* -K- <value> */
OP_SETLOCAL, /* <value> -K- <value> */
OP_DELLOCAL, /* -K- false */
OP_HASVAR, /* -S- ( <value> | undefined ) */
OP_GETVAR, /* -S- <value> */
OP_SETVAR, /* <value> -S- <value> */
OP_DELVAR, /* -S- <success> */
OP_IN, /* <name> <obj> -- <exists?> */
OP_SKIPARRAY, /* <obj> -- <obj> */
OP_INITARRAY, /* <obj> <val> -- <obj> */
OP_INITPROP, /* <obj> <key> <val> -- <obj> */
OP_INITGETTER, /* <obj> <key> <closure> -- <obj> */
OP_INITSETTER, /* <obj> <key> <closure> -- <obj> */
OP_GETPROP, /* <obj> <name> -- <value> */
OP_GETPROP_S, /* <obj> -S- <value> */
OP_SETPROP, /* <obj> <name> <value> -- <value> */
OP_SETPROP_S, /* <obj> <value> -S- <value> */
OP_DELPROP, /* <obj> <name> -- <success> */
OP_DELPROP_S, /* <obj> -S- <success> */
OP_ITERATOR, /* <obj> -- <iobj> */
OP_NEXTITER, /* <iobj> -- ( <iobj> <name> true | false ) */
OP_EVAL, /* <args...> -(numargs)- <returnvalue> */
OP_CALL, /* <closure> <this> <args...> -(numargs)- <returnvalue> */
OP_NEW, /* <closure> <args...> -(numargs)- <returnvalue> */
OP_TYPEOF,
OP_POS,
OP_NEG,
OP_BITNOT,
OP_LOGNOT,
OP_INC, /* <x> -- ToNumber(x)+1 */
OP_DEC, /* <x> -- ToNumber(x)-1 */
OP_POSTINC, /* <x> -- ToNumber(x)+1 ToNumber(x) */
OP_POSTDEC, /* <x> -- ToNumber(x)-1 ToNumber(x) */
OP_MUL,
OP_DIV,
OP_MOD,
OP_ADD,
OP_SUB,
OP_SHL,
OP_SHR,
OP_USHR,
OP_LT,
OP_GT,
OP_LE,
OP_GE,
OP_EQ,
OP_NE,
OP_STRICTEQ,
OP_STRICTNE,
OP_JCASE,
OP_BITAND,
OP_BITXOR,
OP_BITOR,
OP_INSTANCEOF,
OP_THROW,
OP_TRY, /* -ADDR- /jump/ or -ADDR- <exception> */
OP_ENDTRY,
OP_CATCH, /* push scope chain with exception variable */
OP_ENDCATCH,
OP_WITH,
OP_ENDWITH,
OP_DEBUGGER,
OP_JUMP,
OP_JTRUE,
OP_JFALSE,
OP_RETURN,
};
struct js_Function
{
const char *name;
int script;
int lightweight;
int strict;
int arguments;
int numparams;
js_Instruction *code;
int codecap, codelen;
js_Function **funtab;
int funcap, funlen;
const char **vartab;
int varcap, varlen;
const char *filename;
int line, lastline;
js_Function *gcnext;
int gcmark;
};
js_Function *jsC_compilefunction(js_State *J, js_Ast *prog);
js_Function *jsC_compilescript(js_State *J, js_Ast *prog, int default_strict);
/* Builtins */
void jsB_init(js_State *J);
void jsB_initobject(js_State *J);
void jsB_initarray(js_State *J);
void jsB_initfunction(js_State *J);
void jsB_initboolean(js_State *J);
void jsB_initnumber(js_State *J);
void jsB_initstring(js_State *J);
void jsB_initregexp(js_State *J);
void jsB_initerror(js_State *J);
void jsB_initmath(js_State *J);
void jsB_initjson(js_State *J);
void jsB_initdate(js_State *J);
void jsB_propf(js_State *J, const char *name, js_CFunction cfun, int n);
void jsB_propn(js_State *J, const char *name, double number);
void jsB_props(js_State *J, const char *name, const char *string);
#endif