Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. #include "jsi.h"
  2. #include "jslex.h"
  3. #include "utf.h"
  4.  
  5. JS_NORETURN static void jsY_error(js_State *J, const char *fmt, ...) JS_PRINTFLIKE(2,3);
  6.  
  7. static void jsY_error(js_State *J, const char *fmt, ...)
  8. {
  9.         va_list ap;
  10.         char buf[512];
  11.         char msgbuf[256];
  12.  
  13.         va_start(ap, fmt);
  14.         vsnprintf(msgbuf, 256, fmt, ap);
  15.         va_end(ap);
  16.  
  17.         snprintf(buf, 256, "%s:%d: ", J->filename, J->lexline);
  18.         strcat(buf, msgbuf);
  19.  
  20.         js_newsyntaxerror(J, buf);
  21.         js_throw(J);
  22. }
  23.  
  24. static const char *tokenstring[] = {
  25.         "(end-of-file)",
  26.         "'\\x01'", "'\\x02'", "'\\x03'", "'\\x04'", "'\\x05'", "'\\x06'", "'\\x07'",
  27.         "'\\x08'", "'\\x09'", "'\\x0A'", "'\\x0B'", "'\\x0C'", "'\\x0D'", "'\\x0E'", "'\\x0F'",
  28.         "'\\x10'", "'\\x11'", "'\\x12'", "'\\x13'", "'\\x14'", "'\\x15'", "'\\x16'", "'\\x17'",
  29.         "'\\x18'", "'\\x19'", "'\\x1A'", "'\\x1B'", "'\\x1C'", "'\\x1D'", "'\\x1E'", "'\\x1F'",
  30.         "' '", "'!'", "'\"'", "'#'", "'$'", "'%'", "'&'", "'\\''",
  31.         "'('", "')'", "'*'", "'+'", "','", "'-'", "'.'", "'/'",
  32.         "'0'", "'1'", "'2'", "'3'", "'4'", "'5'", "'6'", "'7'",
  33.         "'8'", "'9'", "':'", "';'", "'<'", "'='", "'>'", "'?'",
  34.         "'@'", "'A'", "'B'", "'C'", "'D'", "'E'", "'F'", "'G'",
  35.         "'H'", "'I'", "'J'", "'K'", "'L'", "'M'", "'N'", "'O'",
  36.         "'P'", "'Q'", "'R'", "'S'", "'T'", "'U'", "'V'", "'W'",
  37.         "'X'", "'Y'", "'Z'", "'['", "'\'", "']'", "'^'", "'_'",
  38.         "'`'", "'a'", "'b'", "'c'", "'d'", "'e'", "'f'", "'g'",
  39.         "'h'", "'i'", "'j'", "'k'", "'l'", "'m'", "'n'", "'o'",
  40.         "'p'", "'q'", "'r'", "'s'", "'t'", "'u'", "'v'", "'w'",
  41.         "'x'", "'y'", "'z'", "'{'", "'|'", "'}'", "'~'", "'\\x7F'",
  42.  
  43.         0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
  44.         0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
  45.         0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
  46.         0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
  47.         0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
  48.         0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
  49.         0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
  50.         0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
  51.  
  52.         "(identifier)", "(number)", "(string)", "(regexp)",
  53.  
  54.         "'<='", "'>='", "'=='", "'!='", "'==='", "'!=='",
  55.         "'<<'", "'>>'", "'>>>'", "'&&'", "'||'",
  56.         "'+='", "'-='", "'*='", "'/='", "'%='",
  57.         "'<<='", "'>>='", "'>>>='", "'&='", "'|='", "'^='",
  58.         "'++'", "'--'",
  59.  
  60.         "'break'", "'case'", "'catch'", "'continue'", "'debugger'",
  61.         "'default'", "'delete'", "'do'", "'else'", "'false'", "'finally'", "'for'",
  62.         "'function'", "'if'", "'in'", "'instanceof'", "'new'", "'null'", "'return'",
  63.         "'switch'", "'this'", "'throw'", "'true'", "'try'", "'typeof'", "'var'",
  64.         "'void'", "'while'", "'with'",
  65. };
  66.  
  67. const char *jsY_tokenstring(int token)
  68. {
  69.         if (token >= 0 && token < (int)nelem(tokenstring))
  70.                 if (tokenstring[token])
  71.                         return tokenstring[token];
  72.         return "<unknown>";
  73. }
  74.  
  75. static const char *keywords[] = {
  76.         "break", "case", "catch", "continue", "debugger", "default", "delete",
  77.         "do", "else", "false", "finally", "for", "function", "if", "in",
  78.         "instanceof", "new", "null", "return", "switch", "this", "throw",
  79.         "true", "try", "typeof", "var", "void", "while", "with",
  80. };
  81.  
  82. int jsY_findword(const char *s, const char **list, int num)
  83. {
  84.         int l = 0;
  85.         int r = num - 1;
  86.         while (l <= r) {
  87.                 int m = (l + r) >> 1;
  88.                 int c = strcmp(s, list[m]);
  89.                 if (c < 0)
  90.                         r = m - 1;
  91.                 else if (c > 0)
  92.                         l = m + 1;
  93.                 else
  94.                         return m;
  95.         }
  96.         return -1;
  97. }
  98.  
  99. static int jsY_findkeyword(js_State *J, const char *s)
  100. {
  101.         int i = jsY_findword(s, keywords, nelem(keywords));
  102.         if (i >= 0) {
  103.                 J->text = keywords[i];
  104.                 return TK_BREAK + i; /* first keyword + i */
  105.         }
  106.         J->text = js_intern(J, s);
  107.         return TK_IDENTIFIER;
  108. }
  109.  
  110. int jsY_iswhite(int c)
  111. {
  112.         return c == 0x9 || c == 0xB || c == 0xC || c == 0x20 || c == 0xA0 || c == 0xFEFF;
  113. }
  114.  
  115. int jsY_isnewline(int c)
  116. {
  117.         return c == 0xA || c == 0xD || c == 0x2028 || c == 0x2029;
  118. }
  119.  
  120. #ifndef isalpha
  121. #define isalpha(c) ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
  122. #endif
  123. #ifndef isdigit
  124. #define isdigit(c) (c >= '0' && c <= '9')
  125. #endif
  126. #ifndef ishex
  127. #define ishex(c) ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))
  128. #endif
  129.  
  130. static int jsY_isidentifierstart(int c)
  131. {
  132.         return isalpha(c) || c == '$' || c == '_' || isalpharune(c);
  133. }
  134.  
  135. static int jsY_isidentifierpart(int c)
  136. {
  137.         return isdigit(c) || isalpha(c) || c == '$' || c == '_' || isalpharune(c);
  138. }
  139.  
  140. static int jsY_isdec(int c)
  141. {
  142.         return isdigit(c);
  143. }
  144.  
  145. int jsY_ishex(int c)
  146. {
  147.         return isdigit(c) || ishex(c);
  148. }
  149.  
  150. int jsY_tohex(int c)
  151. {
  152.         if (c >= '0' && c <= '9') return c - '0';
  153.         if (c >= 'a' && c <= 'f') return c - 'a' + 0xA;
  154.         if (c >= 'A' && c <= 'F') return c - 'A' + 0xA;
  155.         return 0;
  156. }
  157.  
  158. static void jsY_next(js_State *J)
  159. {
  160.         Rune c;
  161.         if (*J->source == 0) {
  162.                 J->lexchar = EOF;
  163.                 return;
  164.         }
  165.         J->source += chartorune(&c, J->source);
  166.         /* consume CR LF as one unit */
  167.         if (c == '\r' && *J->source == '\n')
  168.                 ++J->source;
  169.         if (jsY_isnewline(c)) {
  170.                 J->line++;
  171.                 c = '\n';
  172.         }
  173.         J->lexchar = c;
  174. }
  175.  
  176. #define jsY_accept(J, x) (J->lexchar == x ? (jsY_next(J), 1) : 0)
  177.  
  178. #define jsY_expect(J, x) if (!jsY_accept(J, x)) jsY_error(J, "expected '%c'", x)
  179.  
  180. static void jsY_unescape(js_State *J)
  181. {
  182.         if (jsY_accept(J, '\\')) {
  183.                 if (jsY_accept(J, 'u')) {
  184.                         int x = 0;
  185.                         if (!jsY_ishex(J->lexchar)) { goto error; } x |= jsY_tohex(J->lexchar) << 12; jsY_next(J);
  186.                         if (!jsY_ishex(J->lexchar)) { goto error; } x |= jsY_tohex(J->lexchar) << 8; jsY_next(J);
  187.                         if (!jsY_ishex(J->lexchar)) { goto error; } x |= jsY_tohex(J->lexchar) << 4; jsY_next(J);
  188.                         if (!jsY_ishex(J->lexchar)) { goto error; } x |= jsY_tohex(J->lexchar);
  189.                         J->lexchar = x;
  190.                         return;
  191.                 }
  192. error:
  193.                 jsY_error(J, "unexpected escape sequence");
  194.         }
  195. }
  196.  
  197. static void textinit(js_State *J)
  198. {
  199.         if (!J->lexbuf.text) {
  200.                 J->lexbuf.cap = 4096;
  201.                 J->lexbuf.text = js_malloc(J, J->lexbuf.cap);
  202.         }
  203.         J->lexbuf.len = 0;
  204. }
  205.  
  206. static void textpush(js_State *J, Rune c)
  207. {
  208.         int n;
  209.         if (c == EOF)
  210.                 n = 1;
  211.         else
  212.                 n = runelen(c);
  213.         if (J->lexbuf.len + n > J->lexbuf.cap) {
  214.                 J->lexbuf.cap = J->lexbuf.cap * 2;
  215.                 J->lexbuf.text = js_realloc(J, J->lexbuf.text, J->lexbuf.cap);
  216.         }
  217.         if (c == EOF)
  218.                 J->lexbuf.text[J->lexbuf.len++] = 0;
  219.         else
  220.                 J->lexbuf.len += runetochar(J->lexbuf.text + J->lexbuf.len, &c);
  221. }
  222.  
  223. static char *textend(js_State *J)
  224. {
  225.         textpush(J, EOF);
  226.         return J->lexbuf.text;
  227. }
  228.  
  229. static void lexlinecomment(js_State *J)
  230. {
  231.         while (J->lexchar != EOF && J->lexchar != '\n')
  232.                 jsY_next(J);
  233. }
  234.  
  235. static int lexcomment(js_State *J)
  236. {
  237.         /* already consumed initial '/' '*' sequence */
  238.         while (J->lexchar != EOF) {
  239.                 if (jsY_accept(J, '*')) {
  240.                         while (J->lexchar == '*')
  241.                                 jsY_next(J);
  242.                         if (jsY_accept(J, '/'))
  243.                                 return 0;
  244.                 }
  245.                 else
  246.                         jsY_next(J);
  247.         }
  248.         return -1;
  249. }
  250.  
  251. static double lexhex(js_State *J)
  252. {
  253.         double n = 0;
  254.         if (!jsY_ishex(J->lexchar))
  255.                 jsY_error(J, "malformed hexadecimal number");
  256.         while (jsY_ishex(J->lexchar)) {
  257.                 n = n * 16 + jsY_tohex(J->lexchar);
  258.                 jsY_next(J);
  259.         }
  260.         return n;
  261. }
  262.  
  263. #if 0
  264.  
  265. static double lexinteger(js_State *J)
  266. {
  267.         double n = 0;
  268.         if (!jsY_isdec(J->lexchar))
  269.                 jsY_error(J, "malformed number");
  270.         while (jsY_isdec(J->lexchar)) {
  271.                 n = n * 10 + (J->lexchar - '0');
  272.                 jsY_next(J);
  273.         }
  274.         return n;
  275. }
  276.  
  277. static double lexfraction(js_State *J)
  278. {
  279.         double n = 0;
  280.         double d = 1;
  281.         while (jsY_isdec(J->lexchar)) {
  282.                 n = n * 10 + (J->lexchar - '0');
  283.                 d = d * 10;
  284.                 jsY_next(J);
  285.         }
  286.         return n / d;
  287. }
  288.  
  289. static double lexexponent(js_State *J)
  290. {
  291.         double sign;
  292.         if (jsY_accept(J, 'e') || jsY_accept(J, 'E')) {
  293.                 if (jsY_accept(J, '-')) sign = -1;
  294.                 else if (jsY_accept(J, '+')) sign = 1;
  295.                 else sign = 1;
  296.                 return sign * lexinteger(J);
  297.         }
  298.         return 0;
  299. }
  300.  
  301. static int lexnumber(js_State *J)
  302. {
  303.         double n;
  304.         double e;
  305.  
  306.         if (jsY_accept(J, '0')) {
  307.                 if (jsY_accept(J, 'x') || jsY_accept(J, 'X')) {
  308.                         J->number = lexhex(J);
  309.                         return TK_NUMBER;
  310.                 }
  311.                 if (jsY_isdec(J->lexchar))
  312.                         jsY_error(J, "number with leading zero");
  313.                 n = 0;
  314.                 if (jsY_accept(J, '.'))
  315.                         n += lexfraction(J);
  316.         } else if (jsY_accept(J, '.')) {
  317.                 if (!jsY_isdec(J->lexchar))
  318.                         return '.';
  319.                 n = lexfraction(J);
  320.         } else {
  321.                 n = lexinteger(J);
  322.                 if (jsY_accept(J, '.'))
  323.                         n += lexfraction(J);
  324.         }
  325.  
  326.         e = lexexponent(J);
  327.         if (e < 0)
  328.                 n /= pow(10, -e);
  329.         else if (e > 0)
  330.                 n *= pow(10, e);
  331.  
  332.         if (jsY_isidentifierstart(J->lexchar))
  333.                 jsY_error(J, "number with letter suffix");
  334.  
  335.         J->number = n;
  336.         return TK_NUMBER;
  337. }
  338.  
  339. #else
  340.  
  341. static int lexnumber(js_State *J)
  342. {
  343.         const char *s = J->source - 1;
  344.  
  345.         if (jsY_accept(J, '0')) {
  346.                 if (jsY_accept(J, 'x') || jsY_accept(J, 'X')) {
  347.                         J->number = lexhex(J);
  348.                         return TK_NUMBER;
  349.                 }
  350.                 if (jsY_isdec(J->lexchar))
  351.                         jsY_error(J, "number with leading zero");
  352.                 if (jsY_accept(J, '.')) {
  353.                         while (jsY_isdec(J->lexchar))
  354.                                 jsY_next(J);
  355.                 }
  356.         } else if (jsY_accept(J, '.')) {
  357.                 if (!jsY_isdec(J->lexchar))
  358.                         return '.';
  359.                 while (jsY_isdec(J->lexchar))
  360.                         jsY_next(J);
  361.         } else {
  362.                 while (jsY_isdec(J->lexchar))
  363.                         jsY_next(J);
  364.                 if (jsY_accept(J, '.')) {
  365.                         while (jsY_isdec(J->lexchar))
  366.                                 jsY_next(J);
  367.                 }
  368.         }
  369.  
  370.         if (jsY_accept(J, 'e') || jsY_accept(J, 'E')) {
  371.                 if (J->lexchar == '-' || J->lexchar == '+')
  372.                         jsY_next(J);
  373.                 if (jsY_isdec(J->lexchar))
  374.                         while (jsY_isdec(J->lexchar))
  375.                                 jsY_next(J);
  376.                 else
  377.                         jsY_error(J, "missing exponent");
  378.         }
  379.  
  380.         if (jsY_isidentifierstart(J->lexchar))
  381.                 jsY_error(J, "number with letter suffix");
  382.  
  383.         J->number = js_strtod(s, NULL);
  384.         return TK_NUMBER;
  385. }
  386.  
  387. #endif
  388.  
  389. static int lexescape(js_State *J)
  390. {
  391.         int x = 0;
  392.  
  393.         /* already consumed '\' */
  394.  
  395.         if (jsY_accept(J, '\n'))
  396.                 return 0;
  397.  
  398.         switch (J->lexchar) {
  399.         case EOF: jsY_error(J, "unterminated escape sequence");
  400.         case 'u':
  401.                 jsY_next(J);
  402.                 if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar) << 12; jsY_next(J); }
  403.                 if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar) << 8; jsY_next(J); }
  404.                 if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar) << 4; jsY_next(J); }
  405.                 if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar); jsY_next(J); }
  406.                 textpush(J, x);
  407.                 break;
  408.         case 'x':
  409.                 jsY_next(J);
  410.                 if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar) << 4; jsY_next(J); }
  411.                 if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar); jsY_next(J); }
  412.                 textpush(J, x);
  413.                 break;
  414.         case '0': textpush(J, 0); jsY_next(J); break;
  415.         case '\\': textpush(J, '\\'); jsY_next(J); break;
  416.         case '\'': textpush(J, '\''); jsY_next(J); break;
  417.         case '"': textpush(J, '"'); jsY_next(J); break;
  418.         case 'b': textpush(J, '\b'); jsY_next(J); break;
  419.         case 'f': textpush(J, '\f'); jsY_next(J); break;
  420.         case 'n': textpush(J, '\n'); jsY_next(J); break;
  421.         case 'r': textpush(J, '\r'); jsY_next(J); break;
  422.         case 't': textpush(J, '\t'); jsY_next(J); break;
  423.         case 'v': textpush(J, '\v'); jsY_next(J); break;
  424.         default: textpush(J, J->lexchar); jsY_next(J); break;
  425.         }
  426.         return 0;
  427. }
  428.  
  429. static int lexstring(js_State *J)
  430. {
  431.         const char *s;
  432.  
  433.         int q = J->lexchar;
  434.         jsY_next(J);
  435.  
  436.         textinit(J);
  437.  
  438.         while (J->lexchar != q) {
  439.                 if (J->lexchar == EOF || J->lexchar == '\n')
  440.                         jsY_error(J, "string not terminated");
  441.                 if (jsY_accept(J, '\\')) {
  442.                         if (lexescape(J))
  443.                                 jsY_error(J, "malformed escape sequence");
  444.                 } else {
  445.                         textpush(J, J->lexchar);
  446.                         jsY_next(J);
  447.                 }
  448.         }
  449.         jsY_expect(J, q);
  450.  
  451.         s = textend(J);
  452.  
  453.         J->text = js_intern(J, s);
  454.         return TK_STRING;
  455. }
  456.  
  457. /* the ugliest language wart ever... */
  458. static int isregexpcontext(int last)
  459. {
  460.         switch (last) {
  461.         case ']':
  462.         case ')':
  463.         case '}':
  464.         case TK_IDENTIFIER:
  465.         case TK_NUMBER:
  466.         case TK_STRING:
  467.         case TK_FALSE:
  468.         case TK_NULL:
  469.         case TK_THIS:
  470.         case TK_TRUE:
  471.                 return 0;
  472.         default:
  473.                 return 1;
  474.         }
  475. }
  476.  
  477. static int lexregexp(js_State *J)
  478. {
  479.         const char *s;
  480.         int g, m, i;
  481.         int inclass = 0;
  482.  
  483.         /* already consumed initial '/' */
  484.  
  485.         textinit(J);
  486.  
  487.         /* regexp body */
  488.         while (J->lexchar != '/' || inclass) {
  489.                 if (J->lexchar == EOF || J->lexchar == '\n') {
  490.                         jsY_error(J, "regular expression not terminated");
  491.                 } else if (jsY_accept(J, '\\')) {
  492.                         if (jsY_accept(J, '/')) {
  493.                                 textpush(J, '/');
  494.                         } else {
  495.                                 textpush(J, '\\');
  496.                                 if (J->lexchar == EOF || J->lexchar == '\n')
  497.                                         jsY_error(J, "regular expression not terminated");
  498.                                 textpush(J, J->lexchar);
  499.                                 jsY_next(J);
  500.                         }
  501.                 } else {
  502.                         if (J->lexchar == '[' && !inclass)
  503.                                 inclass = 1;
  504.                         if (J->lexchar == ']' && inclass)
  505.                                 inclass = 0;
  506.                         textpush(J, J->lexchar);
  507.                         jsY_next(J);
  508.                 }
  509.         }
  510.         jsY_expect(J, '/');
  511.  
  512.         s = textend(J);
  513.  
  514.         /* regexp flags */
  515.         g = i = m = 0;
  516.  
  517.         while (jsY_isidentifierpart(J->lexchar)) {
  518.                 if (jsY_accept(J, 'g')) ++g;
  519.                 else if (jsY_accept(J, 'i')) ++i;
  520.                 else if (jsY_accept(J, 'm')) ++m;
  521.                 else jsY_error(J, "illegal flag in regular expression: %c", J->lexchar);
  522.         }
  523.  
  524.         if (g > 1 || i > 1 || m > 1)
  525.                 jsY_error(J, "duplicated flag in regular expression");
  526.  
  527.         J->text = js_intern(J, s);
  528.         J->number = 0;
  529.         if (g) J->number += JS_REGEXP_G;
  530.         if (i) J->number += JS_REGEXP_I;
  531.         if (m) J->number += JS_REGEXP_M;
  532.         return TK_REGEXP;
  533. }
  534.  
  535. /* simple "return [no Line Terminator here] ..." contexts */
  536. static int isnlthcontext(int last)
  537. {
  538.         switch (last) {
  539.         case TK_BREAK:
  540.         case TK_CONTINUE:
  541.         case TK_RETURN:
  542.         case TK_THROW:
  543.                 return 1;
  544.         default:
  545.                 return 0;
  546.         }
  547. }
  548.  
  549. static int jsY_lexx(js_State *J)
  550. {
  551.         J->newline = 0;
  552.  
  553.         while (1) {
  554.                 J->lexline = J->line; /* save location of beginning of token */
  555.  
  556.                 while (jsY_iswhite(J->lexchar))
  557.                         jsY_next(J);
  558.  
  559.                 if (jsY_accept(J, '\n')) {
  560.                         J->newline = 1;
  561.                         if (isnlthcontext(J->lasttoken))
  562.                                 return ';';
  563.                         continue;
  564.                 }
  565.  
  566.                 if (jsY_accept(J, '/')) {
  567.                         if (jsY_accept(J, '/')) {
  568.                                 lexlinecomment(J);
  569.                                 continue;
  570.                         } else if (jsY_accept(J, '*')) {
  571.                                 if (lexcomment(J))
  572.                                         jsY_error(J, "multi-line comment not terminated");
  573.                                 continue;
  574.                         } else if (isregexpcontext(J->lasttoken)) {
  575.                                 return lexregexp(J);
  576.                         } else if (jsY_accept(J, '=')) {
  577.                                 return TK_DIV_ASS;
  578.                         } else {
  579.                                 return '/';
  580.                         }
  581.                 }
  582.  
  583.                 if (J->lexchar >= '0' && J->lexchar <= '9') {
  584.                         return lexnumber(J);
  585.                 }
  586.  
  587.                 switch (J->lexchar) {
  588.                 case '(': jsY_next(J); return '(';
  589.                 case ')': jsY_next(J); return ')';
  590.                 case ',': jsY_next(J); return ',';
  591.                 case ':': jsY_next(J); return ':';
  592.                 case ';': jsY_next(J); return ';';
  593.                 case '?': jsY_next(J); return '?';
  594.                 case '[': jsY_next(J); return '[';
  595.                 case ']': jsY_next(J); return ']';
  596.                 case '{': jsY_next(J); return '{';
  597.                 case '}': jsY_next(J); return '}';
  598.                 case '~': jsY_next(J); return '~';
  599.  
  600.                 case '\'':
  601.                 case '"':
  602.                         return lexstring(J);
  603.  
  604.                 case '.':
  605.                         return lexnumber(J);
  606.  
  607.                 case '<':
  608.                         jsY_next(J);
  609.                         if (jsY_accept(J, '<')) {
  610.                                 if (jsY_accept(J, '='))
  611.                                         return TK_SHL_ASS;
  612.                                 return TK_SHL;
  613.                         }
  614.                         if (jsY_accept(J, '='))
  615.                                 return TK_LE;
  616.                         return '<';
  617.  
  618.                 case '>':
  619.                         jsY_next(J);
  620.                         if (jsY_accept(J, '>')) {
  621.                                 if (jsY_accept(J, '>')) {
  622.                                         if (jsY_accept(J, '='))
  623.                                                 return TK_USHR_ASS;
  624.                                         return TK_USHR;
  625.                                 }
  626.                                 if (jsY_accept(J, '='))
  627.                                         return TK_SHR_ASS;
  628.                                 return TK_SHR;
  629.                         }
  630.                         if (jsY_accept(J, '='))
  631.                                 return TK_GE;
  632.                         return '>';
  633.  
  634.                 case '=':
  635.                         jsY_next(J);
  636.                         if (jsY_accept(J, '=')) {
  637.                                 if (jsY_accept(J, '='))
  638.                                         return TK_STRICTEQ;
  639.                                 return TK_EQ;
  640.                         }
  641.                         return '=';
  642.  
  643.                 case '!':
  644.                         jsY_next(J);
  645.                         if (jsY_accept(J, '=')) {
  646.                                 if (jsY_accept(J, '='))
  647.                                         return TK_STRICTNE;
  648.                                 return TK_NE;
  649.                         }
  650.                         return '!';
  651.  
  652.                 case '+':
  653.                         jsY_next(J);
  654.                         if (jsY_accept(J, '+'))
  655.                                 return TK_INC;
  656.                         if (jsY_accept(J, '='))
  657.                                 return TK_ADD_ASS;
  658.                         return '+';
  659.  
  660.                 case '-':
  661.                         jsY_next(J);
  662.                         if (jsY_accept(J, '-'))
  663.                                 return TK_DEC;
  664.                         if (jsY_accept(J, '='))
  665.                                 return TK_SUB_ASS;
  666.                         return '-';
  667.  
  668.                 case '*':
  669.                         jsY_next(J);
  670.                         if (jsY_accept(J, '='))
  671.                                 return TK_MUL_ASS;
  672.                         return '*';
  673.  
  674.                 case '%':
  675.                         jsY_next(J);
  676.                         if (jsY_accept(J, '='))
  677.                                 return TK_MOD_ASS;
  678.                         return '%';
  679.  
  680.                 case '&':
  681.                         jsY_next(J);
  682.                         if (jsY_accept(J, '&'))
  683.                                 return TK_AND;
  684.                         if (jsY_accept(J, '='))
  685.                                 return TK_AND_ASS;
  686.                         return '&';
  687.  
  688.                 case '|':
  689.                         jsY_next(J);
  690.                         if (jsY_accept(J, '|'))
  691.                                 return TK_OR;
  692.                         if (jsY_accept(J, '='))
  693.                                 return TK_OR_ASS;
  694.                         return '|';
  695.  
  696.                 case '^':
  697.                         jsY_next(J);
  698.                         if (jsY_accept(J, '='))
  699.                                 return TK_XOR_ASS;
  700.                         return '^';
  701.  
  702.                 case EOF:
  703.                         return 0; /* EOF */
  704.                 }
  705.  
  706.                 /* Handle \uXXXX escapes in identifiers */
  707.                 jsY_unescape(J);
  708.                 if (jsY_isidentifierstart(J->lexchar)) {
  709.                         textinit(J);
  710.                         textpush(J, J->lexchar);
  711.  
  712.                         jsY_next(J);
  713.                         jsY_unescape(J);
  714.                         while (jsY_isidentifierpart(J->lexchar)) {
  715.                                 textpush(J, J->lexchar);
  716.                                 jsY_next(J);
  717.                                 jsY_unescape(J);
  718.                         }
  719.  
  720.                         textend(J);
  721.  
  722.                         return jsY_findkeyword(J, J->lexbuf.text);
  723.                 }
  724.  
  725.                 if (J->lexchar >= 0x20 && J->lexchar <= 0x7E)
  726.                         jsY_error(J, "unexpected character: '%c'", J->lexchar);
  727.                 jsY_error(J, "unexpected character: \\u%04X", J->lexchar);
  728.         }
  729. }
  730.  
  731. void jsY_initlex(js_State *J, const char *filename, const char *source)
  732. {
  733.         J->filename = filename;
  734.         J->source = source;
  735.         J->line = 1;
  736.         J->lasttoken = 0;
  737.         jsY_next(J); /* load first lookahead character */
  738. }
  739.  
  740. int jsY_lex(js_State *J)
  741. {
  742.         return J->lasttoken = jsY_lexx(J);
  743. }
  744.  
  745. static int lexjsonnumber(js_State *J)
  746. {
  747.         const char *s = J->source - 1;
  748.  
  749.         if (J->lexchar == '-')
  750.                 jsY_next(J);
  751.  
  752.         if (J->lexchar == '0')
  753.                 jsY_next(J);
  754.         else if (J->lexchar >= '1' && J->lexchar <= '9')
  755.                 while (isdigit(J->lexchar))
  756.                         jsY_next(J);
  757.         else
  758.                 jsY_error(J, "unexpected non-digit");
  759.  
  760.         if (jsY_accept(J, '.')) {
  761.                 if (isdigit(J->lexchar))
  762.                         while (isdigit(J->lexchar))
  763.                                 jsY_next(J);
  764.                 else
  765.                         jsY_error(J, "missing digits after decimal point");
  766.         }
  767.  
  768.         if (jsY_accept(J, 'e') || jsY_accept(J, 'E')) {
  769.                 if (J->lexchar == '-' || J->lexchar == '+')
  770.                         jsY_next(J);
  771.                 if (isdigit(J->lexchar))
  772.                         while (isdigit(J->lexchar))
  773.                                 jsY_next(J);
  774.                 else
  775.                         jsY_error(J, "missing digits after exponent indicator");
  776.         }
  777.  
  778.         J->number = js_strtod(s, NULL);
  779.         return TK_NUMBER;
  780. }
  781.  
  782. static int lexjsonescape(js_State *J)
  783. {
  784.         int x = 0;
  785.  
  786.         /* already consumed '\' */
  787.  
  788.         switch (J->lexchar) {
  789.         default: jsY_error(J, "invalid escape sequence");
  790.         case 'u':
  791.                 jsY_next(J);
  792.                 if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar) << 12; jsY_next(J); }
  793.                 if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar) << 8; jsY_next(J); }
  794.                 if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar) << 4; jsY_next(J); }
  795.                 if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar); jsY_next(J); }
  796.                 textpush(J, x);
  797.                 break;
  798.         case '"': textpush(J, '"'); jsY_next(J); break;
  799.         case '\\': textpush(J, '\\'); jsY_next(J); break;
  800.         case '/': textpush(J, '/'); jsY_next(J); break;
  801.         case 'b': textpush(J, '\b'); jsY_next(J); break;
  802.         case 'f': textpush(J, '\f'); jsY_next(J); break;
  803.         case 'n': textpush(J, '\n'); jsY_next(J); break;
  804.         case 'r': textpush(J, '\r'); jsY_next(J); break;
  805.         case 't': textpush(J, '\t'); jsY_next(J); break;
  806.         }
  807.         return 0;
  808. }
  809.  
  810. static int lexjsonstring(js_State *J)
  811. {
  812.         const char *s;
  813.  
  814.         textinit(J);
  815.  
  816.         while (J->lexchar != '"') {
  817.                 if (J->lexchar == EOF)
  818.                         jsY_error(J, "unterminated string");
  819.                 else if (J->lexchar < 32)
  820.                         jsY_error(J, "invalid control character in string");
  821.                 else if (jsY_accept(J, '\\'))
  822.                         lexjsonescape(J);
  823.                 else {
  824.                         textpush(J, J->lexchar);
  825.                         jsY_next(J);
  826.                 }
  827.         }
  828.         jsY_expect(J, '"');
  829.  
  830.         s = textend(J);
  831.  
  832.         J->text = js_intern(J, s);
  833.         return TK_STRING;
  834. }
  835.  
  836. int jsY_lexjson(js_State *J)
  837. {
  838.         while (1) {
  839.                 J->lexline = J->line; /* save location of beginning of token */
  840.  
  841.                 while (jsY_iswhite(J->lexchar) || J->lexchar == '\n')
  842.                         jsY_next(J);
  843.  
  844.                 if ((J->lexchar >= '0' && J->lexchar <= '9') || J->lexchar == '-')
  845.                         return lexjsonnumber(J);
  846.  
  847.                 switch (J->lexchar) {
  848.                 case ',': jsY_next(J); return ',';
  849.                 case ':': jsY_next(J); return ':';
  850.                 case '[': jsY_next(J); return '[';
  851.                 case ']': jsY_next(J); return ']';
  852.                 case '{': jsY_next(J); return '{';
  853.                 case '}': jsY_next(J); return '}';
  854.  
  855.                 case '"':
  856.                         jsY_next(J);
  857.                         return lexjsonstring(J);
  858.  
  859.                 case 'f':
  860.                         jsY_next(J); jsY_expect(J, 'a'); jsY_expect(J, 'l'); jsY_expect(J, 's'); jsY_expect(J, 'e');
  861.                         return TK_FALSE;
  862.  
  863.                 case 'n':
  864.                         jsY_next(J); jsY_expect(J, 'u'); jsY_expect(J, 'l'); jsY_expect(J, 'l');
  865.                         return TK_NULL;
  866.  
  867.                 case 't':
  868.                         jsY_next(J); jsY_expect(J, 'r'); jsY_expect(J, 'u'); jsY_expect(J, 'e');
  869.                         return TK_TRUE;
  870.  
  871.                 case EOF:
  872.                         return 0; /* EOF */
  873.                 }
  874.  
  875.                 if (J->lexchar >= 0x20 && J->lexchar <= 0x7E)
  876.                         jsY_error(J, "unexpected character: '%c'", J->lexchar);
  877.                 jsY_error(J, "unexpected character: \\u%04X", J->lexchar);
  878.         }
  879. }
  880.