Adaptive Framework  0.9.0
All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
afw_compile_lexical.c
Go to the documentation of this file.
1 // See the 'COPYING' file in the project root for licensing information.
2 /*
3  * Adaptive Framework Compiler Lexical Analyzer
4  *
5  * Copyright (c) 2010-2023 Clemson University
6  *
7  */
8 
14 #include "afw_internal.h"
15 
16 typedef void (*impl_lexical_cb_t) (afw_compile_parser_t *parser);
17 
18 /* Static declarations. */
19 
20 static afw_octet_t
21 impl_get_octet(afw_compile_parser_t *parser);
22 
23 static afw_boolean_t
24 impl_consume_matching_octets_z(afw_compile_parser_t *parser,
25  const afw_utf8_z_t *s);
26 
27 static int
28 impl_get_required_HexDigit(afw_compile_parser_t *parser);
29 
30 static int
31 impl_get_BinaryDigit(afw_compile_parser_t *parser);
32 
33 static int
34 impl_get_HexDigit(afw_compile_parser_t *parser);
35 
36 static int
37 impl_get_OctalDigit(afw_compile_parser_t *parser);
38 
39 static const afw_utf8_t *
40 impl_get_identifier(afw_compile_parser_t *parser);
41 
42 static void
43 impl_parse_String(afw_compile_parser_t *parser);
44 
45 static afw_boolean_t
46 impl_parse_number(afw_compile_parser_t *parser);
47 
48 static void
49 impl_parse_identifier(afw_compile_parser_t *parser);
50 
51 static void
52 impl_parse_u(afw_compile_parser_t *parser);
53 
54 
55 
56 /* Static functions. */
57 
58 /* Get a utf-8 octet. Set cursor_eof to cursor + 1 if at end. */
59 static afw_octet_t
60 impl_get_octet(afw_compile_parser_t *parser)
61 {
62  afw_utf8_octet_t result;
63  const afw_utf8_octet_t *s;
64  afw_size_t len;
65  int rv;
66 
67  /* If eof already, this is an error. */
68  if (parser->last_octet_eof) {
69  AFW_COMPILE_THROW_ERROR_Z("impl_get_octet() called after eof");
70  }
71 
72  if (parser->all_eof && (parser->cursor == parser->cursor_eof)) {
73  parser->last_octet_eof = true;
74  return 0;
75  }
76 
77  /* If first call, set up source. */
78  if (!parser->full_source) {
79  parser->full_source = afw_pool_calloc_type(
80  parser->p, afw_utf8_t, parser->xctx);
81 
82  /* If passed source, set source point to it. */
83  if (parser->passed_source) {
84  parser->full_source->s = parser->passed_source->s;
85  parser->full_source->len = parser->passed_source->len;
86  }
87 
88  /*
89  * If callback specified, make an array to hold source. If passed
90  * source is also specified, add it to array.
91  *
92  * The s and len in parser->source will always be updated to contain
93  * source_buffer->elts and parser->source_buffer->nelts respectively.
94  */
95  if (parser->callback) {
100  if (parser->estimated_size != (int)parser->estimated_size) {
101  AFW_THROW_ERROR_Z(general, "Limitation", parser->xctx);
102  }
103  parser->source_buffer = apr_array_make(parser->apr_p,
104  (int)parser->estimated_size, sizeof(afw_utf8_octet_t));
105  if (parser->passed_source) {
106  for (s = parser->passed_source->s,
107  len = parser->passed_source->len;
108  len > 0;
109  s++, len--)
110  {
111  APR_ARRAY_PUSH(parser->source_buffer, afw_utf8_octet_t) =
112  *s;
113  }
114  }
115  parser->full_source->s =
116  (const afw_utf8_octet_t *)parser->source_buffer->elts;
117  parser->full_source->len = parser->source_buffer->nelts;
118  }
119  }
120 
121  /* If cursor is not past source length, return octet and update cursor. */
122  if (parser->cursor < parser->full_source->len) {
123  result = parser->full_source->s[parser->cursor];
124  (parser->cursor)++;
125  }
126 
127  /* If source exhausted, eof. */
128  else if (!parser->callback || parser->callback_eof) {
129  parser->all_eof = true;
130  parser->last_octet_eof = true;
131  parser->cursor_eof = parser->cursor;
132  result = 0;
133  }
134 
135  /* If callback has never been called and scanning for residual, eof. */
136  else if (!parser->has_called_callback && parser->scanning_for_residual) {
137  parser->callback_eof = true;
138  parser->all_eof = true;
139  parser->last_octet_eof = true;
140  parser->cursor_eof = parser->cursor;
141  result = 0;
142  }
143 
144  /* If there is a callback, call it to get next octet. If eof, indicate. */
145  else {
146  parser->has_called_callback = true;
147 
148  rv = parser->callback(&result, parser->callback_data,
149  parser->xctx);
150 
151  if (rv < 0)
152  {
153  parser->callback_eof = true;
154  parser->all_eof = true;
155  parser->last_octet_eof = true;
156  parser->cursor_eof = parser->cursor;
157  result = 0;
158  }
159 
160  else {
161  APR_ARRAY_PUSH(parser->source_buffer, afw_utf8_octet_t) = result;
162  parser->full_source->s =
163  (const afw_utf8_octet_t *)parser->source_buffer->elts;
164  parser->full_source->len = parser->source_buffer->nelts;
165  (parser->cursor)++;
166  }
167  }
168 
169  /* Return result. */
170  return result;
171 }
172 
173 
174 /*
175  * Consume matching octets. If not a match, cursor will be reset to entry
176  * value and false will be returned.
177  */
178 static afw_boolean_t
179 impl_consume_matching_octets_z(afw_compile_parser_t *parser,
180  const afw_utf8_z_t *s)
181 {
182  afw_boolean_t result;
183  afw_size_t save;
184 
185  result = true;
186  afw_compile_save_cursor(save);
187 
188  for (; *s; s++) {
189  if (impl_get_octet(parser) != *s) {
190  afw_compile_restore_cursor(save);
191  result = false;
192  break;
193  }
194  }
195 
196  return result;
197 }
198 
199 /*ebnf>>>
200  *
201  * HexDigit ::= [0-9a-fA-F]
202  *
203  *<<<ebnf*/
204 static int
205 impl_get_required_HexDigit(afw_compile_parser_t *parser)
206 {
208 
209  o = impl_get_octet(parser);
210  if (afw_compile_is_at_eof()) {
211  goto error;
212  }
213 
214  if (o >= '0' && o <= '9') {
215  return o - '0';
216  }
217 
218  if (o >= 'a' && o <= 'f') {
219  return (o - 'a') + 10;
220  }
221 
222  if (o >= 'A' && o <= 'F') {
223  return (o - 'A') + 10;
224  }
225 
226 error:
227  AFW_COMPILE_THROW_ERROR_Z("Invalid hex digit");
228 }
229 
230 
231 
232 static int
233 impl_get_HexDigit(afw_compile_parser_t *parser)
234 {
236 
237  o = impl_get_octet(parser);
238  if (afw_compile_is_at_eof()) {
239  return -1;
240  }
241 
242  if (o >= '0' && o <= '9') {
243  return o - '0';
244  }
245 
246  if (o >= 'a' && o <= 'f') {
247  return (o - 'a') + 10;
248  }
249 
250  if (o >= 'A' && o <= 'F') {
251  return (o - 'A') + 10;
252  }
253 
254  parser->cursor--;
255  return -1;
256 }
257 
258 
259 
260 /*ebnf>>>
261  *
262  * BinaryDigit ::= [0-1]
263  *
264  *<<<ebnf*/
265 static int
266 impl_get_BinaryDigit(afw_compile_parser_t *parser)
267 {
269 
270  o = impl_get_octet(parser);
271 
272  if (afw_compile_is_at_eof()) {
273  return -1;
274  }
275 
276  if (o >= '0' && o <= '1') {
277  return o - '0';
278  }
279 
280  parser->cursor--;
281  return -1;
282 }
283 
284 
285 
286 /*ebnf>>>
287  *
288  * OctalDigit ::= [0-7]
289  *
290  *<<<ebnf*/
291 static int
292 impl_get_OctalDigit(afw_compile_parser_t *parser)
293 {
295 
296  o = impl_get_octet(parser);
297 
298  if (afw_compile_is_at_eof()) {
299  return -1;
300  }
301 
302  if (o >= '0' && o <= '7') {
303  return o - '0';
304  }
305 
306  parser->cursor--;
307  return -1;
308 }
309 
310 
311 /* Push cp on parser->s */
313 afw_compile_internal_s_push_code_point(
314  afw_compile_parser_t *parser,
315  afw_code_point_t cp)
316 {
317  afw_utf8_octet_t utf8_z[5];
318  const afw_utf8_octet_t *c;
319 
320  if (cp < 127) {
321  APR_ARRAY_PUSH(parser->s, afw_utf8_octet_t) = (afw_octet_t)cp;
322  return;
323  }
324 
325  /* Convert code point to utf-8 and push on utf-8 bytes on parser->s */
326  if (!afw_utf8_from_code_point(utf8_z, cp, parser->xctx)) {
327  AFW_COMPILE_THROW_ERROR_Z("Invalid codepoint");
328  }
329  c = &utf8_z[0];
330  do {
331  APR_ARRAY_PUSH(parser->s, afw_utf8_octet_t) = *c;
332  } while (*++c);
333 }
334 
335 
336 
337 /*ebnf>>>
338  *
339 
340  *#
341  *
342  *# Tab character
343  * TAB ::= #x0009
344  *
345  *# Vertical tab
346  * VT ::= #x000B
347  *
348  *# Forms feed
349  * FF ::= #x000C
350  *
351  *# Line feed
352  * LF ::= #x000A
353  *
354  *# Carriage return
355  * CR ::= #x000D
356  *
357  *# No break space
358  * NBSP ::= #x00A0
359  *
360  *# Line Separator
361  * LS ::= #x2028
362  *
363  *# Paragraph Separator
364  * PS ::= #x2029
365  *
366  *# Space Separator code point
367  * USP ::= "Any Unicode Space_Separator code point"
368  *
369  *# Zero Width No-Break Space (Unicode word join)
370  * ZWNBSP ::= #xFEFF
371  *
372  *# Whitespace
373  * Whitespace ::= ( TAB | VT | FF | ZWNBSP | USP )+
374  *
375  *# Line Terminators
376  * EOL ::= LF | CR | LS | PS
377  *
378  *# Whitespace in source (between any production tokens without ws: explicit)
379  * WhitespaceBetweenTokens ::= ( Whitespace | EOL | Comment )+
380  *
381  *# Comment is not allowed in strict mode.
382  * Comment ::= InlineComment | BlockComment
383  */
384 //* InlineComment ::= '/*' ( [^*] | '*'+ [^*/] )* '*'* '*/'
385 /*
386  * BlockComment ::= '//' [^\n]* EOL
387  *
388  *<<<ebnf*/
389 
390 
391 /* Skip whitespace. */
393 afw_compile_skip_ws(afw_compile_parser_t *parser)
394 {
395  afw_size_t start_offset;
396  afw_size_t start_offset_first_slash;
397  afw_code_point_t cp;
398 
399  enum {
400  state_ws,
401  state_finished,
402  state_first_slash,
403  state_block_comment,
404  state_block_comment_asterisk,
405  state_inline_comment,
406  } state;
407 
408  state = state_ws;
409  parser->get_token_found_eol = false;
410  if (!afw_compile_is_at_eof()) do {
411 
412  afw_compile_save_cursor(start_offset);
413  cp = afw_compile_get_code_point();
414 
415  switch (state) {
416 
417  case state_ws:
418 
419  if (afw_compile_is_at_eof()) {
420  parser->last_octet_eof = false;
421  state = state_finished;
422  }
423 
424  else if (cp == '/') {
425  if (!parser->strict) {
426  start_offset_first_slash = start_offset;
427  state = state_first_slash;
428  }
429  else {
430  afw_compile_restore_cursor(start_offset);
431  state = state_finished;
432  }
433  }
434 
436  {
437  afw_compile_restore_cursor(start_offset);
438  state = state_finished;
439  }
440 
441  break;
442 
443  case state_first_slash:
444 
445  if (afw_compile_is_at_eof()) {
446  parser->last_octet_eof = false;
447  state = state_finished;
448  }
449 
450  else if (cp == '/') {
451  state = state_inline_comment;
452  }
453 
454  else if (cp == '*') {
455  state = state_block_comment;
456  }
457 
458  else {
459  afw_compile_restore_cursor(start_offset_first_slash);
460  state = state_finished;
461  }
462 
463  break;
464 
465  case state_block_comment:
466 
467  if (afw_compile_is_at_eof()) {
468  AFW_COMPILE_THROW_ERROR_Z("Block comment not terminated");
469  }
470 
471  if (cp == '*') {
472  state = state_block_comment_asterisk;
473  }
474 
475  break;
476 
477  case state_block_comment_asterisk:
478 
479  if (afw_compile_is_at_eof()) {
480  AFW_COMPILE_THROW_ERROR_Z("Block comment not terminated");
481  }
482 
483  if (cp == '/') {
484  state = state_ws;
485  }
486 
487  else if (cp == '*') {
488  state = state_block_comment_asterisk;
489  }
490 
491  else {
492  state = state_block_comment;
493  }
494 
495  break;
496 
497  case state_inline_comment:
498 
499  if (afw_compile_is_at_eof()) {
500  parser->last_octet_eof = false;
501  state = state_finished;
502  }
503  else if (afw_compile_code_point_is_EOL(cp)) {
504  state = state_ws;
505  if (parser->get_token_before_eol) {
506  parser->get_token_found_eol = true;
507  state = state_finished;
508  }
509  }
510  break;
511 
512  case state_finished:
513  break;
514  }
515 
516  } while (state != state_finished);
517 }
518 
519 
520 
521 /*ebnf>>>*/
522 
523 //* U ::= '\u' ( ( HexDigit HexDigit HexDigit HexDigit ) |
524 //* ( '{' HexDigit+ '}' ) ) /* ws: explicit */
525 
526 /*<<<ebnf*/
527 /*
528  * Cursor starts after '\u'.
529  *
530  * Parse a \uxxxx. If surrogate pair, parse \uxxxx\uxxxx.
531  */
532 static void
533 impl_parse_u(afw_compile_parser_t *parser)
534 {
535  afw_code_point_t cp, cp2;
536  afw_utf8_octet_t utf8_z[5];
537  const afw_utf8_octet_t *c;
539  int digit;
540 
541  /* Code point from /u{x...}. */
542  o = impl_get_octet(parser);
543  if (afw_compile_is_at_eof()) {
544  AFW_COMPILE_THROW_ERROR_Z("Expecting hex digit or '{'");
545  }
546  if (o == '{') {
547  cp = 0;
548  digit = impl_get_HexDigit(parser);
549  if (digit < 0) {
550  AFW_COMPILE_THROW_ERROR_Z("Expecting hex digit");
551  }
552  for (;;) {
553  cp <<= 4;
554  cp += digit;
555  if (cp > 0x10FFFF) {
556  AFW_COMPILE_THROW_ERROR_Z("Codepoint is out of range");
557  }
558  digit = impl_get_HexDigit(parser);
559  if (afw_compile_is_at_eof()) {
560  AFW_COMPILE_THROW_ERROR_Z("Expecting hex digit or '}'");
561  }
562  if (digit < 0) {
563  o = impl_get_octet(parser);
564  if (afw_compile_is_at_eof() || o != '}') {
565  AFW_COMPILE_THROW_ERROR_Z("Expecting hex digit or '}'");
566  }
567  break;
568  }
569  }
570  }
571 
572  /* Code point from /uxxxx with optional surrogate /uxxxx. */
573  else {
574  parser->cursor--;
575 
576  cp =
577  impl_get_required_HexDigit(parser) * 0x1000 +
578  impl_get_required_HexDigit(parser) * 0x100 +
579  impl_get_required_HexDigit(parser) * 0x10 +
580  impl_get_required_HexDigit(parser);
581 
582  /* If code point is a utf-16 surrogate, it must be paired. */
583  if (cp >= 0xD800 && cp <= 0xDFFF)
584  {
585  if (cp >= 0xDC00)
586  {
587  goto error;
588  }
589  o = impl_get_octet(parser);
590  if (o != '\\')
591  {
592  goto error;
593  }
594  o = impl_get_octet(parser);
595  if (o != 'u')
596  {
597  goto error;
598  }
599  cp2 =
600  impl_get_required_HexDigit(parser) * 0x1000 +
601  impl_get_required_HexDigit(parser) * 0x100 +
602  impl_get_required_HexDigit(parser) * 0x10 +
603  impl_get_required_HexDigit(parser);
604  if (cp2 < 0xDC00 || cp2 > 0xDFFF)
605  {
606  goto error;
607  }
608  cp = ((cp - 0xD800) << 10) + (cp2 - 0xDC00) + 0x10000;
609  }
610  }
611 
612  /* Convert code point to utf-8 and push on utf-8 bytes on parser->s */
613  if (!afw_utf8_from_code_point(utf8_z, cp, parser->xctx)) {
614  AFW_COMPILE_THROW_ERROR_Z("Invalid codepoint");
615  }
616  c = &utf8_z[0];
617  do {
618  APR_ARRAY_PUSH(parser->s, afw_utf8_octet_t) = *c;
619  } while (*++c);
620 
621  /* Return. */
622  return;
623 
624 error:
625  AFW_COMPILE_THROW_ERROR_Z("Invalid surrogate pair");
626 }
627 
628 
629 
630 /*ebnf>>>
631  *
632  * String ::= '"' Char* '"'
633  *
634  * Char ::= [^\#x0-#x20] | '\"' | "\'" | '\`' | "\\" | '\/' |
635  * '\b' | '\f' | '\n' | '\r' | '\t' | U
636  *
637  * UnicodeCodePoint ::= #x0-#x10FFFF
638  *
639  * UnicodeNonControl ::= (UnicodeCodePoint - [^\#x0-#x1f] )
640  *
641  * UnicodeNonSpaceNonControl ::= (UnicodeCodePoint - [^\#x0-#x20] )
642  *
643  *<<<ebnf*/
644 /*
645  * Translate a UTF-8 JSON string. Remove containing quotes and convert escaped
646  * characters. Input string must begin with either a single or double quote.
647  * Whichever one is used, it must be escaped if contained within the string.
648  * The binary value of control characters is allowed in the string as well
649  * as the escaped form. \uxxxx and utf16be surrogates are supported.
650  */
651 static void
652 impl_parse_String(afw_compile_parser_t *parser)
653 {
654  afw_utf8_octet_t quot, o;
655 
656  /* Clear array used for building string. */
657  apr_array_clear(parser->s);
658 
659  /* First octet is quote to use. */
660  quot = impl_get_octet(parser);
661  parser->token->string_quote_character = quot;
662 
663  /* Set token type to utf8_string. */
664  parser->token->type = (quot == '`')
665  ? afw_compile_token_type_template_string
666  : afw_compile_token_type_utf8_string;
667 
668  /* Keep going until last quote located or input exhausted. */
669  for (;;) {
670  o = impl_get_octet(parser);
671  if (afw_compile_is_at_eof()) break;
672  if (o == quot) break;
673 
674  /* If '\', convert escaped code. */
675  if (o == '\\') {
676 
677  /* If escape, get next octet and break if eof.*/
678  o = impl_get_octet(parser);
679  if (afw_compile_is_at_eof()) break;
680 
681  /* Process based on octet after \. */
682  switch (o) {
683 
684  case '"':
685  case '\'':
686  case '`':
687  case '\\':
688  case '/':
689  APR_ARRAY_PUSH(parser->s, afw_utf8_octet_t) = o;
690  break;
691 
692  case 'b':
693  APR_ARRAY_PUSH(parser->s, afw_utf8_octet_t) = AFW_ASCII_BS;
694  break;
695 
696  case 'f':
697  APR_ARRAY_PUSH(parser->s, afw_utf8_octet_t) = AFW_ASCII_FF;
698  break;
699 
700  case 'n':
701  APR_ARRAY_PUSH(parser->s, afw_utf8_octet_t) = AFW_ASCII_LF;
702  break;
703 
704  case 'r':
705  APR_ARRAY_PUSH(parser->s, afw_utf8_octet_t) = AFW_ASCII_CR;
706  break;
707 
708  case 't':
709  APR_ARRAY_PUSH(parser->s, afw_utf8_octet_t) = AFW_ASCII_HT;
710  break;
711 
712  case 'v':
713  APR_ARRAY_PUSH(parser->s, afw_utf8_octet_t) = AFW_ASCII_VT;
714  break;
715 
716  case 'u':
717  impl_parse_u(parser);
718  break;
719 
720  default:
721  AFW_COMPILE_THROW_ERROR_Z("Invalid escape code");
722  }
723  }
724 
725  /* If not '\', just copy character from input to output. */
726  else {
727  APR_ARRAY_PUSH(parser->s, afw_utf8_octet_t) = o;
728  }
729 
730  }
731 
732  /* If string didn't end with a quote, it's an error. */
733  if (afw_compile_is_at_eof() || o != quot) {
734  AFW_COMPILE_THROW_ERROR_Z("String missing ending quote");
735  }
736 
737  /* Create token.string making sure it is NFC utf-8 normalized. */
738  parser->token->string = afw_compile_get_string_literal(
739  parser,
740  (const afw_utf8_octet_t *)parser->s->elts,
741  (afw_size_t)parser->s->nelts);
742 }
743 
744 
745 /*ebnf>>>
746  *
747  *# Only DecimalIntegerLiteral is allowed in strict mode.
748  * Integer ::= '-'? (
749  * DecimalIntegerLiteral |
750  * BinaryIntegerLiteral |
751  * HexIntegerLiteral |
752  * OctetIntegerLiteral )
753  *
754  * DecimalIntegerLiteral ::= '0' | ( [1-9] [0-9]* )
755  *
756  * BinaryIntegerLiteral ::= '0' ('b' | 'B' ) BinaryDigit+
757  *
758  * HexIntegerLiteral ::= '0' ('x' | 'X' ) HexDigit+
759  *
760  * OctalIntegerLiteral ::= '0' ('o' | 'O' ) OctalDigit+
761  *
762  *# Infinity, INF and NaN are not allowed in strict mode.
763  *
764  * Double ::= '-'? ( ( DecimalIntegerLiteral '.' [0-9]+ ([eE] [+-]? [0-9]+)? ) |
765  * 'Infinity' | 'INF' | 'NaN' )
766  *
767  *<<<ebnf*/
768 /*
769  * Parse a number.
770  *
771  * Note: Infinity, INF, and NaN are handled by impl_parse_identifier(), but
772  * if they are preceded by a '-', they are handled here.
773  */
774 
775 static afw_integer_t
776 impl_parse_BinaryIntegerLiteral(afw_compile_parser_t *parser)
777 {
778  int digit;
779  afw_integer_t result;
780 
781  digit = impl_get_BinaryDigit(parser);
782  if (digit < 0) {
783  AFW_COMPILE_THROW_ERROR_Z("Invalid binary digit");
784  }
785  result = digit;
786 
787  for (;;) {
788  digit = impl_get_BinaryDigit(parser);
789  if (digit < 0) {
790  return result;
791  }
792  if (result > AFW_INTEGER_MAX / 2)
793  {
794  AFW_COMPILE_THROW_ERROR_Z("Integer is out of range");
795  }
796  result <<= 1;
797  if (result > AFW_INTEGER_MAX - digit) {
798  AFW_COMPILE_THROW_ERROR_Z("Integer is out of range");
799  }
800  result += digit;
801  }
802 }
803 
804 
805 
806 static afw_integer_t
807 impl_parse_HexIntegerLiteral(afw_compile_parser_t *parser)
808 {
809  int digit;
810  afw_integer_t result;
811 
812  digit = impl_get_HexDigit(parser);
813  if (digit < 0) {
814  AFW_COMPILE_THROW_ERROR_Z("Invalid hex digit");
815  }
816  result = digit;
817 
818  for (;;) {
819  digit = impl_get_HexDigit(parser);
820  if (digit < 0) {
821  return result;
822  }
823  if (result > AFW_INTEGER_MAX / 16)
824  {
825  AFW_COMPILE_THROW_ERROR_Z("Integer is out of range");
826  }
827  result <<= 4;
828  if (result > AFW_INTEGER_MAX - digit) {
829  AFW_COMPILE_THROW_ERROR_Z("Integer is out of range");
830  }
831  result += digit;
832  }
833 }
834 
835 
836 
837 static afw_integer_t
838 impl_parse_OctalIntegerLiteral(afw_compile_parser_t *parser)
839 {
840  int digit;
841  afw_integer_t result;
842 
843  digit = impl_get_OctalDigit(parser);
844  if (digit < 0) {
845  AFW_COMPILE_THROW_ERROR_Z("Invalid octal digit");
846  }
847  result = digit;
848 
849  for (;;) {
850  digit = impl_get_OctalDigit(parser);
851  if (digit < 0) {
852  return result;
853  }
854  if (result > AFW_INTEGER_MAX / 8)
855  {
856  AFW_COMPILE_THROW_ERROR_Z("Integer is out of range");
857  }
858  result <<= 3;
859  if (result > AFW_INTEGER_MAX - digit) {
860  AFW_COMPILE_THROW_ERROR_Z("Integer is out of range");
861  }
862  result += digit;
863  }
864 }
865 
866 
867 
868 static afw_boolean_t
869 impl_parse_number(afw_compile_parser_t *parser)
870 {
871  afw_size_t start_offset;
872  const afw_utf8_octet_t *s;
873  afw_integer_t negative;
874  afw_boolean_t is_negative;
875  afw_boolean_t is_integer;
876  afw_boolean_t is_zero;
878  afw_code_point_t cp;
879 
880  afw_compile_save_cursor(start_offset);
881  negative = 0;
882  is_negative = false;
883  is_integer = true;
884  is_zero = true;
885 
886  /* Determine if negative and handle reserved identifiers. */
887  o = impl_get_octet(parser);
888 
889  /* Error if '+' and strict, otherwise just ignore it. */
890  if (o == '+') {
891  if (parser->strict) {
892  goto error;
893  }
894  }
895 
896  /* Error if '-' indicate minus and handle special negative strings. */
897  else if (o == '-') {
898  is_negative = true;
899 
900  if (impl_consume_matching_octets_z(parser, "Infinity") ||
901  impl_consume_matching_octets_z(parser, "INF"))
902  {
903  parser->token->type = afw_compile_token_type_number;
904  parser->token->number = parser->xctx->env->minus_infinity;
905  goto reserved_identifier;
906  }
907 
908  if (impl_consume_matching_octets_z(parser, "NaN")) {
909  parser->token->type = afw_compile_token_type_number;
910  parser->token->number = parser->xctx->env->NaN;
911  goto reserved_identifier;
912  }
913  }
914 
915  /* If not + or -, restore cursor. */
916  else {
917  afw_compile_restore_cursor(start_offset);
918  }
919 
920  /* Parse integer part and prescan floating point part. */
921  do {
922  o = impl_get_octet(parser);
923 
924  /* Number can't end here. */
925  if (afw_compile_is_at_eof()) {
926  goto error;
927  }
928 
929  /* Can be '0' or digits'1'-'9' followed by additional digits '0'-'9'. */
930  if (o >= '1' && o <= '9') {
931  is_zero = false;
932  /* Sum digits as a negative number. Negative is one larger. */
933  negative = -(o - '0');
934  for (;;) {
935  o = impl_get_octet(parser);
936  if (afw_compile_is_at_eof()) {
937  break;
938  }
939  if (o < '0' || o > '9') {
940  parser->cursor--;
941  break;
942  }
943  if (negative < AFW_INTEGER_MIN / 10)
944  {
945  AFW_COMPILE_THROW_ERROR_Z("Integer is out of range");
946  }
947  negative = (negative * 10);
948  if (negative < AFW_INTEGER_MIN + (o - '0'))
949  {
950  AFW_COMPILE_THROW_ERROR_Z("Integer is out of range");
951  }
952  negative -= (o - '0');
953  }
954  }
955  else if (o == '0') {
956  o = impl_get_octet(parser);
957  if (afw_compile_is_at_eof()) {
958  break;
959  }
960 
961  /* Decimal literal can not start with a '0'. */
962  if (o >= '0' && o <= '9') {
963  goto error;
964  }
965 
966  /* If not strict mode, can be binary, hex, or octal literal. */
967  if (!parser->strict) {
968  if (o == 'b' || o == 'B') {
969  parser->token->type = afw_compile_token_type_integer;
970  parser->token->integer =
971  impl_parse_BinaryIntegerLiteral(parser);
972  if (is_negative) {
973  parser->token->integer = -parser->token->integer;
974  }
975  return true;
976  }
977  if (o == 'x' || o == 'X') {
978  parser->token->type = afw_compile_token_type_integer;
979  parser->token->integer =
980  impl_parse_HexIntegerLiteral(parser);
981  if (is_negative) {
982  parser->token->integer = -parser->token->integer;
983  }
984  return true;
985  }
986  if (o == 'o' || o == 'O') {
987  parser->token->type = afw_compile_token_type_integer;
988  parser->token->integer =
989  impl_parse_OctalIntegerLiteral(parser);
990  if (is_negative) {
991  parser->token->integer = -parser->token->integer;
992  }
993  return true;
994  }
995  }
996 
997  /* Parse as double or decimal integer. */
998  parser->cursor--;
999  }
1000  else {
1001  goto error;
1002  }
1003 
1004  /* Number is an integer if at end of eof. */
1005  if (afw_compile_is_at_eof()) {
1006  break;
1007  }
1008 
1009  /* Next can be an optional period followed by digits '0'-'9'. */
1010  o = impl_get_octet(parser);
1011  if (afw_compile_is_at_eof()) {
1012  break;
1013  }
1014  if (o != '.') {
1015  parser->cursor--;
1016  }
1017  else {
1018  is_integer = false;
1019  o = impl_get_octet(parser);
1020  /* Number can't end here. */
1021  if (afw_compile_is_at_eof() || o < '0' || o > '9') {
1022  goto error;
1023  }
1024  if (o != '0') {
1025  is_zero = false;
1026  }
1027  for (;;) {
1028  o = impl_get_octet(parser);
1029  if (afw_compile_is_at_eof()) {
1030  break;
1031  }
1032  if (o < '0' || o > '9') {
1033  parser->cursor--;
1034  break;
1035  }
1036  if (o != '0') {
1037  is_zero = false;
1038  }
1039  }
1040  }
1041 
1042  /* Number can end here. */
1043  if (afw_compile_is_at_eof()) {
1044  break;
1045  }
1046 
1047  /*
1048  * Next can be an 'e' or 'E' followed by optional '-' or '+' followed
1049  * by digits '0' - '9'.
1050  */
1051  o = impl_get_octet(parser);
1052  if (o != 'e' && o != 'E') {
1053  parser->cursor--;
1054  }
1055  else {
1056  is_integer = false;
1057  o = impl_get_octet(parser);
1058 
1059  /* Number can't end here. */
1060  if (afw_compile_is_at_eof()) {
1061  goto error;
1062  }
1063 
1064  /* Skip '+' or '-'. */
1065  if (o == '+' || o == '-') {
1066  o = impl_get_octet(parser);
1067  }
1068 
1069  /* Number can't end here. */
1070  if (afw_compile_is_at_eof() || o < '0' || o > '9') goto error;
1071 
1072  /* Skip digits. */
1073  for (;;) {
1074  o = impl_get_octet(parser);
1075  if (afw_compile_is_at_eof()) {
1076  break;
1077  }
1078  if (o < '0' || o > '9') {
1079  parser->cursor--;
1080  break;
1081  }
1082  }
1083  }
1084  } while (0);
1085 
1086  /*
1087  * If is_integer (no '.', 'e', or 'E'), return integer.
1088  *
1089  * Note: javascript treats all numbers as double, but adaptive
1090  * frameworks treats integers as afw_integer_t.
1091  */
1092  if (is_integer) {
1093  parser->token->type = afw_compile_token_type_integer;
1094  if (is_negative) {
1095  parser->token->integer = negative;
1096  }
1097  else if (negative != AFW_INTEGER_MIN) {
1098  parser->token->integer = -negative;
1099  }
1100  else {
1101  goto error;
1102  }
1103  return true;
1104  }
1105 
1106 
1107  /*
1108  * Not integer, create a double value. Use atof to convert number if it
1109  * is not zero.
1110  */
1111  if (is_negative)
1112  parser->token->number = -0.0;
1113  else
1114  parser->token->number = 0;
1115  parser->token->type = afw_compile_token_type_number;
1116  if (!is_zero) {
1117  s = apr_pstrndup(parser->apr_p,
1118  parser->full_source->s + start_offset,
1119  parser->cursor - start_offset);
1120  errno = 0;
1121  parser->token->number = strtod(s, NULL);
1122  if (errno != 0) goto error;
1123  }
1124 
1125  return true;
1126 
1127 reserved_identifier:
1128  /* Make sure reserved identifier is not followed by id_continue cp. */
1129  afw_compile_save_cursor(start_offset);
1130  cp = afw_compile_get_code_point();
1132  afw_compile_restore_cursor(start_offset);
1133  return true;
1134 
1135 error:
1136  return false;
1137 }
1138 
1139 static const afw_utf8_t *
1140 impl_get_identifier(afw_compile_parser_t *parser)
1141 {
1142  afw_code_point_t cp;
1143  afw_size_t start_offset;
1144  afw_size_t save;
1145  const afw_utf8_t *result;
1146 
1147  /* Scan for end of identifier. */
1148  afw_compile_save_cursor(start_offset);
1149  cp = afw_compile_get_code_point();
1151  AFW_COMPILE_THROW_ERROR_Z("Invalid start code point for identifier");
1152  }
1153  for (;;) {
1154  afw_compile_save_cursor(save);
1155  cp = afw_compile_get_code_point();
1156  if (cp < 0) break;
1158  afw_compile_restore_cursor(save);
1159  break;
1160  }
1161  }
1162 
1163  /* Create string for identifier. */
1164  result = afw_compile_get_string_literal(
1165  parser,
1166  parser->full_source->s + start_offset,
1167  parser->cursor - start_offset);
1168 
1169 
1170  /* Return result. */
1171  return result;
1172 }
1173 
1174 
1175 /*ebnf>>>
1176  *
1177  *# ZWNJ - Unicode Zero-width non-joiner (0x200c)
1178  *# ZWJ - Unicode Zero-width joiner (0x200d)
1179  *# ID_START is any codepoint with ID_START flag
1180  *# ID_CONTINUE is any codepoint with ID_CONTINUE flag
1181  *
1182  * IdentifierStart ::= ID_START | '$' | '_'
1183  *
1184  * IdentifierContinue ::= ID_CONTINUE | '$' | ZWNJ | ZWJ
1185  *
1186  * Identifier ::= IdentifierStart IdentifierContinue*
1187  *
1188  *<<<ebnf*/
1189 /*
1190  * This function returns the literal evaluated value of special identifiers
1191  * like true and NaN if parser->next_identifier_is_not_special_literal is not
1192  * true.
1193  */
1194 static void
1195 impl_parse_identifier(afw_compile_parser_t *parser)
1196 {
1197  afw_code_point_t cp;
1198  afw_size_t start_cursor;
1199  afw_size_t save_cursor;
1200 
1201  afw_compile_save_cursor(start_cursor);
1202 
1203  /* Set token type. */
1204  parser->token->type = afw_compile_token_type_identifier;
1205 
1206  /* Get identifier_name. */
1207  parser->token->identifier_name = impl_get_identifier(parser);
1208  parser->token->identifier = parser->token->identifier_name;
1209 
1210  /* Qualified identifier, get qualifier. */
1211  if (!afw_compile_is_at_eof()) {
1212  afw_compile_save_cursor(save_cursor);
1213  cp = afw_compile_get_code_point();
1214  if (cp != ':') {
1215  afw_compile_restore_cursor(save_cursor);
1216  }
1217  else {
1218  cp = afw_compile_get_code_point();
1219  if (cp != ':') {
1220  afw_compile_restore_cursor(save_cursor);
1221  }
1222  else {
1223  parser->token->identifier_qualifier =
1224  parser->token->identifier_name;
1225  parser->token->identifier_name = impl_get_identifier(parser);
1226  parser->token->identifier = afw_compile_get_string_literal(
1227  parser,
1228  parser->full_source->s + start_cursor,
1229  parser->cursor - start_cursor);
1230  }
1231  }
1232  }
1233 
1234  if (parser->token->identifier_qualifier ||
1235  parser->next_identifier_is_not_special_literal)
1236  {
1237  return;
1238  }
1239 
1240  /* Handle reserved identifier true. */
1241  if (afw_utf8_equal_utf8_z(parser->token->identifier_name, "true")) {
1242  parser->token->type = afw_compile_token_type_boolean;
1243  parser->token->boolean = true;
1244  }
1245 
1246  /* Handle reserved identifier false. */
1247  else if (afw_utf8_equal_utf8_z(parser->token->identifier_name, "false")) {;
1248  parser->token->type = afw_compile_token_type_boolean;
1249  parser->token->boolean = false;
1250  }
1251 
1252  /* Handle reserved identifier null. */
1253  else if (afw_utf8_equal_utf8_z(parser->token->identifier_name, "null")) {
1254  parser->token->type = afw_compile_token_type_null;
1255  parser->token->null = NULL;
1256  }
1257 
1258  /* Handle reserved identifier undefined. */
1259  else if (afw_utf8_equal_utf8_z(parser->token->identifier_name, "undefined"))
1260  {
1261  parser->token->type = afw_compile_token_type_undefined;
1262  }
1263 
1264  /* Handle reserved identifier Infinity and INF. */
1265  else if (
1266  afw_utf8_equal_utf8_z(parser->token->identifier_name, "Infinity") ||
1267  afw_utf8_equal_utf8_z(parser->token->identifier_name, "INF"))
1268  {
1269  parser->token->type = afw_compile_token_type_number;
1270  parser->token->number = parser->xctx->env->infinity;
1271  }
1272 
1273  /* Handle reserved identifier NaN. */
1274  else if (afw_utf8_equal_utf8_z(parser->token->identifier_name, "NaN")) {
1275  parser->token->type = afw_compile_token_type_number;
1276  parser->token->number = parser->xctx->env->NaN;
1277  }
1278 }
1279 
1280 
1281 
1282 /*ebnf>>>
1283  *
1284  * ReservedWords ::=
1285  * 'false' |
1286  * 'Infinity' |
1287  * 'null' |
1288  * 'NaN' |
1289  * 'true' |
1290  * 'undefined' |
1291  * 'break' |
1292  * 'case' |
1293  * 'catch' |
1294  * 'const' |
1295  * 'continue' |
1296  * 'do' |
1297  * 'else' |
1298  * 'finally' |
1299  * 'for' |
1300  * 'foreach' |
1301  * 'function' |
1302  * 'if' |
1303  * 'in' |
1304  * 'instanceof' |
1305  * 'interface' |
1306  * 'loc' |
1307  * 'return' |
1308  * 'switch' |
1309  * 'throw' |
1310  * 'try' |
1311  * 'typeof' |
1312  * 'type' |
1313  * 'while'
1314  *
1315  *<<<ebnf*/
1317 afw_compile_is_reserved_word(
1318  afw_compile_parser_t *parser,
1319  const afw_utf8_t *s)
1320 {
1321  if (
1322  afw_utf8_equal(s, &afw_s_true) ||
1323  afw_utf8_equal(s, &afw_s_false) ||
1324  afw_utf8_equal(s, &afw_s_Infinity) ||
1325  afw_utf8_equal(s, &afw_s_INF) ||
1326  afw_utf8_equal(s, &afw_s_null) ||
1327  afw_utf8_equal(s, &afw_s_NaN) ||
1328  afw_utf8_equal(s, &afw_s_undefined) ||
1329 
1330  afw_utf8_equal(s, &afw_s_break) ||
1331  afw_utf8_equal(s, &afw_s_case) ||
1332  afw_utf8_equal(s, &afw_s_catch) ||
1333  afw_utf8_equal(s, &afw_s_const) ||
1334  afw_utf8_equal(s, &afw_s_continue) ||
1335  afw_utf8_equal(s, &afw_s_do) ||
1336  afw_utf8_equal(s, &afw_s_else) ||
1337  afw_utf8_equal(s, &afw_s_finally) ||
1338  afw_utf8_equal(s, &afw_s_for) ||
1339  afw_utf8_equal(s, &afw_s_foreach) ||
1340  afw_utf8_equal(s, &afw_s_function) ||
1341  afw_utf8_equal(s, &afw_s_if) ||
1342  afw_utf8_equal(s, &afw_s_in) ||
1343  afw_utf8_equal(s, &afw_s_instanceof) ||
1344  afw_utf8_equal(s, &afw_s_interface) ||
1345  afw_utf8_equal(s, &afw_s_loc) ||
1346  afw_utf8_equal(s, &afw_s_return) ||
1347  afw_utf8_equal(s, &afw_s_switch) ||
1348  afw_utf8_equal(s, &afw_s_throw) ||
1349  afw_utf8_equal(s, &afw_s_try) ||
1350  afw_utf8_equal(s, &afw_s_typeof) ||
1351  afw_utf8_equal(s, &afw_s_type) ||
1352  afw_utf8_equal(s, &afw_s_while)
1353  )
1354  {
1355  return true;
1356  }
1357 
1358  return false;
1359 }
1360 
1361 
1362 
1363 /* Internal functions. */
1364 
1366 afw_compile_get_code_point_impl(afw_compile_parser_t *parser)
1367 {
1368  afw_code_point_t result;
1369  afw_octet_t o;
1370 
1371  o = impl_get_octet(parser);
1372  if (afw_compile_is_at_eof()) return -1;
1373 
1374  if (o <= 127) {
1375  result = o;
1376  }
1377 
1378  else if (o >= 0xf0 /* 11110000 */) {
1379  o &= 0x0f;
1380  if (o > 0x07) goto error;
1381  result = o << 18;
1382 
1383  o = impl_get_octet(parser);
1384  if (afw_compile_is_at_eof()) goto error;
1385  if (o < 0x80) goto error;
1386  o &= 0x7f;
1387  if (o > 0x3f) goto error;
1388  result += o << 12;
1389 
1390  o = impl_get_octet(parser);
1391  if (afw_compile_is_at_eof()) goto error;
1392  if (o < 0x80) goto error;
1393  o &= 0x7f;
1394  if (o > 0x3f) goto error;
1395  result += o << 6;
1396 
1397  o = impl_get_octet(parser);
1398  if (afw_compile_is_at_eof()) goto error;
1399  if (o < 0x80) goto error;
1400  o &= 0x7f;
1401  if (o > 0x3f) goto error;
1402  result += o ;
1403  }
1404 
1405  else if (o >= 0xe0 /* 11100000 */) {
1406  o &= 0x1f;
1407  if (o > 0x0f) goto error;
1408  result = o << 12;
1409 
1410  o = impl_get_octet(parser);
1411  if (afw_compile_is_at_eof()) goto error;
1412  if (o < 0x80) goto error;
1413  o &= 0x7f;
1414  if (o > 0x3f) goto error;
1415  result += o << 6;
1416 
1417  o = impl_get_octet(parser);
1418  if (afw_compile_is_at_eof()) goto error;
1419  if (o < 0x80) goto error;
1420  o &= 0x7f;
1421  if (o > 0x3f) goto error;
1422  result += o ;
1423  }
1424 
1425  else {
1426  o &= 0x3f;
1427  if (o > 0x1f) goto error;
1428  result = o << 6;
1429 
1430  o = impl_get_octet(parser);
1431  if (afw_compile_is_at_eof()) goto error;
1432  if (o < 0x80) goto error;
1433  o &= 0x7f;
1434  if (o > 0x3f) goto error;
1435  result += o ;
1436  }
1437 
1438  return result;
1439 
1440 error:
1441  AFW_COMPILE_THROW_ERROR_Z("Invalid utf-8");
1442 
1443 }
1444 
1445 
1446 static afw_code_point_t
1447 impl_unescaped(afw_compile_parser_t *parser)
1448 {
1449  afw_utf8_octet_t o;
1450  afw_code_point_t cp, cp2;
1451 
1452  /* If escape, get next octet and break if eof.*/
1453  o = impl_get_octet(parser);
1454  if (afw_compile_is_at_eof()) {
1455  AFW_COMPILE_THROW_ERROR_Z("Invalid escape code");
1456  }
1457 
1458  /* Process based on octet after \. */
1459  switch (o) {
1460 
1461  case '"':
1462  case '\'':
1463  case '`':
1464  case '\\':
1465  case '/':
1466  cp = o;
1467  break;
1468 
1469  case 'b':
1470  cp = AFW_ASCII_BS;
1471  break;
1472 
1473  case 'f':
1474  cp = AFW_ASCII_FF;
1475  break;
1476 
1477  case 'n':
1478  cp = AFW_ASCII_LF;
1479  break;
1480 
1481  case 'r':
1482  cp = AFW_ASCII_CR;
1483  break;
1484 
1485  case 't':
1486  cp = AFW_ASCII_HT;
1487  break;
1488 
1489  case 'v':
1490  cp = AFW_ASCII_VT;
1491  break;
1492 
1493  case 'u':
1494  /* Code point for /uxxxx. */
1495  cp =
1496  impl_get_required_HexDigit(parser) * 0x1000 +
1497  impl_get_required_HexDigit(parser) * 0x100 +
1498  impl_get_required_HexDigit(parser) * 0x10 +
1499  impl_get_required_HexDigit(parser);
1500 
1501  /* If code point is a utf-16 surrogate, it must be paired. */
1502  if (cp >= 0xD800 && cp <= 0xDFFF) {
1503  if (cp >= 0xDC00) goto error;
1504  o = impl_get_octet(parser);
1505  if (o != '\\') goto error;
1506  o = impl_get_octet(parser);
1507  if (o != 'u') goto error;
1508  cp2 =
1509  impl_get_required_HexDigit(parser) * 0x1000 +
1510  impl_get_required_HexDigit(parser) * 0x100 +
1511  impl_get_required_HexDigit(parser) * 0x10 +
1512  impl_get_required_HexDigit(parser);
1513  if (cp2 < 0xDC00 || cp2 > 0xDFFF) goto error;
1514  cp = ((cp - 0xD800) << 10) + (cp2 - 0xDC00) + 0x10000;
1515  }
1516 
1517  break;
1518 
1519  default:
1520  goto error;
1521  }
1522 
1523  return cp;
1524 
1525 error:
1526  AFW_COMPILE_THROW_ERROR_Z("Invalid escape code");
1527 }
1528 
1529 
1530 
1532 afw_compile_get_unescaped_code_point_impl(afw_compile_parser_t *parser)
1533 {
1534  afw_code_point_t cp;
1535 
1536  cp = afw_compile_get_code_point();
1537 
1538  if (cp == '\\') {
1539  cp = impl_unescaped(parser);
1540  }
1541 
1542  return cp;
1543 }
1544 
1545 
1547 afw_compile_next_raw_starts_with_impl(
1548  afw_compile_parser_t *parser,
1549  const afw_utf8_t *s)
1550 {
1551  afw_size_t cursor;
1552  afw_size_t i;
1553  afw_utf8_octet_t o;
1554  afw_boolean_t result;
1555 
1556  afw_compile_save_cursor(cursor);
1557  for (result = true, i = 0; i < s->len; i++) {
1558  o = impl_get_octet(parser);
1559  if (afw_compile_is_at_eof() || o != s->s[i]) {
1560  result = false;
1561  break;
1562  }
1563  }
1564  afw_compile_restore_cursor(cursor);
1565 
1566  return result;
1567 }
1568 
1569 
1571 afw_compile_next_raw_starts_with_z_impl(
1572  afw_compile_parser_t *parser,
1573  const afw_utf8_z_t *s_z)
1574 {
1575  afw_utf8_t s;
1576 
1577  s.s = s_z;
1578  s.len = strlen(s_z);
1579  return afw_compile_next_raw_starts_with_impl(parser, &s);
1580 }
1581 
1582 
1583 
1584 AFW_DEFINE_INTERNAL(void)
1585 afw_compile_get_raw_line_impl(
1586  afw_compile_parser_t *parser,
1587  afw_utf8_t *line)
1588 {
1589  afw_size_t cursor;
1590  afw_utf8_octet_t o;
1591 
1592  if (parser->last_octet_eof) {
1593  line->s = NULL;
1594  line->len = 0;
1595  return;
1596  }
1597 
1598  afw_compile_save_cursor(cursor);
1599 
1600  /* Get next token after whitespace. */
1601  parser->current_cursor_index++;
1602  if (parser->current_cursor_index >= AFW_COMPILE_MAX_TOKENS) {
1603  parser->current_cursor_index = 0;
1604  }
1605  parser->cursors[parser->current_cursor_index] = parser->cursor;
1606  parser->cursor_count++;
1607  if (parser->cursor_count > AFW_COMPILE_MAX_TOKENS) {
1608  parser->cursor_count = AFW_COMPILE_MAX_TOKENS;
1609  }
1610  parser->token->token_source_offset = parser->cursor;
1611 
1612 
1613  for (;;) {
1614  o = impl_get_octet(parser);
1615  if (afw_compile_is_at_eof() || o == '\n') {
1616  break;
1617  }
1618  }
1619 
1620  line->s = parser->full_source->s + cursor;
1621  line->len = parser->cursor - cursor;
1622  if (line->len > 0 && o != -1 && !afw_compile_is_at_eof())
1623  {
1624  (line->len)--;
1625  }
1626 
1627  parser->token->type = afw_compile_token_type_raw_line;
1628  parser->token->token_source_offset = cursor;
1629  parser->token->token_source_len = line->len;
1630  parser->token->raw_line.len = line->len;
1631  parser->token->raw_line.s = line->s;
1632 
1633 
1634  /* Set token source length. */
1635  parser->token->token_source_len =
1636  parser->cursor - parser->token->token_source_offset;
1637 
1638 }
1639 
1640 
1641 /*ebnf>>>
1642  *
1643  *# End of source
1644  * END ::=
1645  *
1646  *<<<ebnf*/
1647 AFW_DEFINE_INTERNAL(void)
1648 afw_compile_get_token_impl(afw_compile_parser_t *parser)
1649 {
1650  afw_code_point_t cp, cp2;
1651  afw_size_t entry_cursor, temp_cursor;
1652 
1653  /* Clear token and skip whitespace. */
1654  memset(parser->token, 0, sizeof(afw_compile_token_t));
1655  afw_compile_skip_ws(parser);
1656 
1657  /*
1658  * If call by afw_compile_get_token_before_eol() and only whitespace
1659  * was found before end of line, just return eol token.
1660  */
1661  parser->get_token_before_eol = false;
1662  if (parser->get_token_found_eol) {
1663  parser->token->type = afw_compile_token_type_eol;
1664  return;
1665  }
1666 
1667  /* Get next token after whitespace. */
1668  parser->current_cursor_index++;
1669  if (parser->current_cursor_index >= AFW_COMPILE_MAX_TOKENS) {
1670  parser->current_cursor_index = 0;
1671  }
1672  parser->cursors[parser->current_cursor_index] = parser->cursor;
1673  parser->cursor_count++;
1674  if (parser->cursor_count > AFW_COMPILE_MAX_TOKENS) {
1675  parser->cursor_count = AFW_COMPILE_MAX_TOKENS;
1676  }
1677  parser->token->token_source_offset = entry_cursor = parser->cursor;
1678  cp = (afw_compile_is_at_eof()) ? -1 : afw_compile_get_code_point();
1679  switch (cp) {
1680 
1681  case -1:
1682  parser->token->type = afw_compile_token_type_end;
1683  break;
1684 
1685  case '"':
1686  case '\'':
1687  afw_compile_restore_cursor(entry_cursor);
1688  impl_parse_String(parser);
1689  break;
1690 
1691  case '`':
1692  if (parser->next_can_be_template_string) {
1693  afw_compile_restore_cursor(entry_cursor);
1694  impl_parse_String(parser);
1695  }
1696  else {
1697  parser->token->type = afw_compile_token_type_grave;
1698  }
1699  break;
1700 
1701  case '0':
1702  case '1':
1703  case '2':
1704  case '3':
1705  case '4':
1706  case '5':
1707  case '6':
1708  case '7':
1709  case '8':
1710  case '9':
1711  afw_compile_restore_cursor(entry_cursor);
1712  if (!impl_parse_number(parser)) {
1713  AFW_COMPILE_THROW_ERROR_Z("Invalid number");
1714  };
1715  break;
1716 
1717  /* $ and ${ */
1718  case '$':
1719  afw_compile_save_cursor(temp_cursor);
1720  cp2 = afw_compile_get_code_point();
1721  if (cp2 == '{') {
1722  parser->token->type =
1723  afw_compile_token_type_substitute_start;
1724  }
1725  else {
1726  afw_compile_restore_cursor(temp_cursor);
1727  parser->token->type = afw_compile_token_type_dollar_sign;
1728  }
1729  break;
1730 
1731  /* . and ... */
1732  case '.':
1733  afw_compile_save_cursor(temp_cursor);
1734  cp2 = afw_compile_get_code_point();
1735  if (cp2 == '.') {
1736  cp2 = afw_compile_get_code_point();
1737  if (cp2 == '.') {
1738  parser->token->type = afw_compile_token_type_ellipsis;
1739  }
1740  else {
1741  afw_compile_restore_cursor(temp_cursor);
1742  parser->token->type = afw_compile_token_type_period;
1743  }
1744  }
1745  else {
1746  afw_compile_restore_cursor(temp_cursor);
1747  parser->token->type = afw_compile_token_type_period;
1748  }
1749  break;
1750 
1751  /* +, positive number literal, += ( token type of + determined by context) */
1752  case '+':
1753  afw_compile_save_cursor(temp_cursor);
1754  cp2 = afw_compile_get_code_point();
1755  if (cp2 == '=') {
1756  parser->token->type = afw_compile_token_type_plus_equal;
1757  }
1758  else if (cp2 == '+') {
1759  parser->token->type = afw_compile_token_type_increment;
1760  }
1761  else {
1762  afw_compile_restore_cursor(temp_cursor);
1763  if (parser->next_can_be_nonunary_operator) {
1764  parser->token->type = afw_compile_token_type_add;
1765  }
1766  else {
1767  if (!impl_parse_number(parser)) {
1768  afw_compile_restore_cursor(temp_cursor);
1769  parser->token->type = afw_compile_token_type_unary_plus;
1770  }
1771  }
1772  }
1773  break;
1774 
1775  /* -, negative number literal, -= ( token type of - determined by context) */
1776  case '-':
1777  afw_compile_save_cursor(temp_cursor);
1778  cp2 = afw_compile_get_code_point();
1779  if (cp2 == '=') {
1780  parser->token->type = afw_compile_token_type_minus_equal;
1781  }
1782  else if (cp2 == '-') {
1783  parser->token->type = afw_compile_token_type_decrement;
1784  }
1785  else if (cp2 == '>') {
1786  parser->token->type = afw_compile_token_type_thin_arrow;
1787  }
1788  else {
1789  afw_compile_restore_cursor(temp_cursor);
1790  if (parser->next_can_be_nonunary_operator) {
1791  parser->token->type = afw_compile_token_type_subtract;
1792  }
1793  else {
1794  afw_compile_restore_cursor(entry_cursor);
1795  if (!impl_parse_number(parser)) {
1796  afw_compile_restore_cursor(temp_cursor);
1797  parser->token->type = afw_compile_token_type_unary_minus;
1798  }
1799  }
1800  }
1801  break;
1802 
1803  /* *, **, *=, **= */
1804  case '*':
1805  afw_compile_save_cursor(temp_cursor);
1806  cp2 = afw_compile_get_code_point();
1807  if (cp2 == '=') {
1808  parser->token->type = afw_compile_token_type_multiply_equal;
1809  }
1810  else if (cp2 == '*') {
1811  afw_compile_save_cursor(temp_cursor);
1812  cp2 = afw_compile_get_code_point();
1813  if (cp2 == '=') {
1814  parser->token->type = afw_compile_token_type_exponentiation_equal;
1815  }
1816  else {
1817  afw_compile_restore_cursor(temp_cursor);
1818  parser->token->type = afw_compile_token_type_exponentiation;
1819  }
1820  }
1821  else {
1822  afw_compile_restore_cursor(temp_cursor);
1823  parser->token->type = afw_compile_token_type_multiply;
1824  }
1825  break;
1826 
1827  /* / and /= */
1828  case '/':
1829  afw_compile_save_cursor(temp_cursor);
1830  cp2 = afw_compile_get_code_point();
1831  if (cp2 == '=') {
1832  parser->token->type = afw_compile_token_type_divide_equal;
1833  }
1834  else {
1835  afw_compile_restore_cursor(temp_cursor);
1836  parser->token->type = (parser->next_can_be_nonunary_operator)
1837  ? afw_compile_token_type_divide
1838  : afw_compile_token_type_slash;
1839  parser->token->type = afw_compile_token_type_divide;
1840  }
1841  break;
1842 
1843  /* % and %= ( token type of % determined by context) */
1844  case '%':
1845  afw_compile_save_cursor(temp_cursor);
1846  cp2 = afw_compile_get_code_point();
1847  if (cp2 == '=') {
1848  parser->token->type = afw_compile_token_type_modulus_equal;
1849  }
1850  else {
1851  afw_compile_restore_cursor(temp_cursor);
1852  parser->token->type = (parser->next_can_be_nonunary_operator)
1853  ? afw_compile_token_type_modulus
1854  : afw_compile_token_type_percent;
1855  }
1856  break;
1857 
1858  /* = == => === */
1859  case '=':
1860  afw_compile_save_cursor(temp_cursor);
1861  cp2 = afw_compile_get_code_point();
1862  if (cp2 == '=') {
1863  afw_compile_save_cursor(temp_cursor);
1864  cp2 = afw_compile_get_code_point();
1865  if (cp2 == '=') {
1866  parser->token->type =
1867  afw_compile_token_type_equal_value_and_type;
1868  }
1869  else {
1870  afw_compile_restore_cursor(temp_cursor);
1871  parser->token->type = afw_compile_token_type_equal_to;
1872  }
1873  }
1874  else if (cp2 == '>') {
1875  parser->token->type = afw_compile_token_type_fat_arrow;
1876  }
1877  else {
1878  afw_compile_restore_cursor(temp_cursor);
1879  parser->token->type = afw_compile_token_type_equal;
1880  }
1881  break;
1882 
1883  /* ! != !== */
1884  case '!':
1885  afw_compile_save_cursor(temp_cursor);
1886  cp2 = afw_compile_get_code_point();
1887  if (cp2 == '=') {
1888  afw_compile_save_cursor(temp_cursor);
1889  cp2 = afw_compile_get_code_point();
1890  if (cp2 == '=') {
1891  parser->token->type =
1892  afw_compile_token_type_not_equal_value_and_type;
1893  }
1894  else {
1895  afw_compile_restore_cursor(temp_cursor);
1896  parser->token->type = afw_compile_token_type_not_equal_to;
1897  }
1898  }
1899  else {
1900  afw_compile_restore_cursor(temp_cursor);
1901  parser->token->type = afw_compile_token_type_unary_not;
1902  }
1903  break;
1904 
1905  /* < and <= ( token type of < determined by context) */
1906  case '<':
1907  afw_compile_save_cursor(temp_cursor);
1908  cp2 = afw_compile_get_code_point();
1909  if (cp2 == '=') {
1910  parser->token->type = afw_compile_token_type_less_than_or_equal_to;
1911  }
1912  else {
1913  afw_compile_restore_cursor(temp_cursor);
1914  parser->token->type = (parser->next_can_be_nonunary_operator)
1915  ? afw_compile_token_type_less_than
1916  : afw_compile_token_type_open_angle_bracket;
1917  }
1918  break;
1919 
1920  /* > and >= ( token type of > determined by context) */
1921  case '>':
1922  afw_compile_save_cursor(temp_cursor);
1923  cp2 = afw_compile_get_code_point();
1924  if (cp2 == '=') {
1925  parser->token->type =
1926  afw_compile_token_type_greater_than_or_equal_to;
1927  }
1928  else {
1929  afw_compile_restore_cursor(temp_cursor);
1930  parser->token->type = (parser->next_can_be_nonunary_operator)
1931  ? afw_compile_token_type_greater_than
1932  : afw_compile_token_type_close_angle_bracket;
1933  }
1934  break;
1935 
1936  case '&':
1937  afw_compile_save_cursor(temp_cursor);
1938  cp2 = afw_compile_get_code_point();
1939  if (cp2 == '&') {
1940  afw_compile_save_cursor(temp_cursor);
1941  cp2 = afw_compile_get_code_point();
1942  if (cp2 == '=') {
1943  parser->token->type = afw_compile_token_type_and_equal;
1944  }
1945  else {
1946  afw_compile_restore_cursor(temp_cursor);
1947  parser->token->type = afw_compile_token_type_and;
1948  }
1949  }
1950  else {
1951  afw_compile_restore_cursor(temp_cursor);
1952  parser->token->type = afw_compile_token_type_ampersand;
1953  }
1954  break;
1955 
1956  case '|':
1957  afw_compile_save_cursor(temp_cursor);
1958  cp2 = afw_compile_get_code_point();
1959  if (cp2 == '|') {
1960  afw_compile_save_cursor(temp_cursor);
1961  cp2 = afw_compile_get_code_point();
1962  if (cp2 == '=') {
1963  parser->token->type = afw_compile_token_type_or_equal;
1964  }
1965  else {
1966  afw_compile_restore_cursor(temp_cursor);
1967  parser->token->type = afw_compile_token_type_or;
1968  }
1969  }
1970  else {
1971  afw_compile_restore_cursor(temp_cursor);
1972  parser->token->type = afw_compile_token_type_vertical_bar;
1973  }
1974  break;
1975 
1976  case '\\':
1977  parser->token->type = afw_compile_token_type_back_slash;
1978  break;
1979 
1980  case '^':
1981  parser->token->type = afw_compile_token_type_caret;
1982  break;
1983 
1984  case ':':
1985  parser->token->type = afw_compile_token_type_colon;
1986  break;
1987 
1988  case ',':
1989  parser->token->type = afw_compile_token_type_comma;
1990  break;
1991 
1992  case '?':
1993  afw_compile_save_cursor(temp_cursor);
1994  cp2 = afw_compile_get_code_point();
1995  if (cp2 == '?') {
1996  afw_compile_save_cursor(temp_cursor);
1997  cp2 = afw_compile_get_code_point();
1998  if (cp2 == '=') {
1999  parser->token->type = afw_compile_token_type_nullish_equal;
2000  }
2001  else {
2002  afw_compile_restore_cursor(temp_cursor);
2003  parser->token->type = afw_compile_token_type_nullish_coalescing;
2004  }
2005  }
2006  else if (cp2 == '.') {
2007  parser->token->type = afw_compile_token_type_optional_chaining;
2008  }
2009  else if (cp2 == '-') {
2010  cp2 = afw_compile_get_code_point();
2011  if (cp2 == '>') {
2012  parser->token->type =
2013  afw_compile_token_type_optional_chaining_thin_arrow;
2014  }
2015  else {
2016  afw_compile_restore_cursor(temp_cursor);
2017  parser->token->type = afw_compile_token_type_question_mark;
2018  }
2019  }
2020  else {
2021  afw_compile_restore_cursor(temp_cursor);
2022  parser->token->type = afw_compile_token_type_question_mark;
2023  }
2024  break;
2025 
2026  case ';':
2027  parser->token->type = afw_compile_token_type_semicolon;
2028  break;
2029 
2030  case '~':
2031  parser->token->type = afw_compile_token_type_tilde;
2032  break;
2033 
2034  case '{':
2035  parser->token->type = afw_compile_token_type_open_brace;
2036  break;
2037 
2038  case '}':
2039  parser->token->type = afw_compile_token_type_close_brace;
2040  break;
2041 
2042  case '(':
2043  parser->token->type = afw_compile_token_type_open_parenthesis;
2044  break;
2045 
2046  case ')':
2047  parser->token->type = afw_compile_token_type_close_parenthesis;
2048  break;
2049 
2050  case '[':
2051  parser->token->type = afw_compile_token_type_open_bracket;
2052  break;
2053 
2054  case ']':
2055  parser->token->type = afw_compile_token_type_close_bracket;
2056  break;
2057 
2058  default:
2060  afw_compile_restore_cursor(entry_cursor);
2061  impl_parse_identifier(parser);
2062  }
2063  else {
2064  parser->token->type = afw_compile_token_type_invalid;
2065  }
2066  }
2067 
2068  /* Reset next_can_be_* */
2069  parser->next_can_be_nonunary_operator = false;
2070  parser->next_can_be_template_string = false;
2071  parser->next_identifier_is_not_special_literal = false;
2072 
2073  /* Set token source length. */
2074  parser->token->token_source_len =
2075  parser->cursor - parser->token->token_source_offset;
2076 }
2077 
2078 
2079 AFW_DEFINE_INTERNAL(void)
2080 afw_compile_reuse_token_impl(afw_compile_parser_t *parser)
2081 {
2082  /* Ignore reuse token is last one is end of line. */
2083  if (parser->get_token_found_eol) {
2084  parser->get_token_found_eol = false;
2085  return;
2086  }
2087 
2088  /* Reset to previous token. */
2089  if (parser->cursor_count > 0) {
2090  parser->cursor_count--;
2091  parser->cursor = parser->cursors[parser->current_cursor_index];
2092  parser->current_cursor_index--;
2093  if (parser->current_cursor_index < 0) {
2094  parser->current_cursor_index = AFW_COMPILE_MAX_TOKENS - 1;
2095  }
2096  parser->last_octet_eof = false;
2097  parser->token->type = afw_compile_token_type_invalid;
2098  }
2099  else {
2100  AFW_THROW_ERROR_Z(general, "No token to reuse", parser->xctx);
2101  }
2102 }
2103 
2104 
2105 AFW_DEFINE_INTERNAL(afw_compile_internal_token_type_t)
2106 afw_compile_peek_next_token_impl(afw_compile_parser_t *parser)
2107 {
2108  afw_compile_internal_token_type_t result;
2109 
2110  afw_compile_get_token_impl(parser);
2111  result = parser->token->type;
2112  afw_compile_reuse_token_impl(parser);
2113 
2114  return result;
2115 }
2116 
2117 
2118 /* Make sure there is no residual data. */
2119 AFW_DEFINE_INTERNAL(void)
2120 afw_compile_check_for_residual(afw_compile_parser_t *parser)
2121 {
2122  afw_octet_t o;
2123  afw_size_t save;
2124 
2125  parser->scanning_for_residual = true;
2126 
2127  switch (parser->residual_check) {
2128 
2129  case afw_compile_residual_check_none:
2130  break;
2131 
2132  case afw_compile_residual_check_to_newline:
2133  if (!afw_compile_is_at_eof()) for (;;) {
2134  o = impl_get_octet(parser);
2135  if (afw_compile_is_at_eof() || o == '\n') break;
2136  if (!afw_ascii_is_whitespace(o)) {
2137  afw_compile_save_cursor(save);
2138  goto error;
2139  }
2140  }
2141  break;
2142 
2143  case afw_compile_residual_check_to_full:
2144  if (afw_compile_is_at_eof()) break;
2145  afw_compile_skip_ws(parser);
2146  afw_compile_save_cursor(save);
2147  if (!afw_compile_next_is_at_eof()) goto error;
2148  break;
2149 
2150  default:
2151  AFW_THROW_ERROR_Z(general, "Invalid residual_check value",
2152  parser->xctx);
2153  }
2154 
2155  return;
2156 
2157 error:
2158  AFW_THROW_ERROR_FZ(syntax, parser->xctx,
2159  "Residual data beginning at offset %" AFW_SIZE_T_FMT,
2160  save);
2161 
2162 }
2163 
2164 
2165 
2166 /* Created a struct for sharing resources by multiple compiles. */
2169  const afw_pool_t *p,
2170  afw_xctx_t *xctx)
2171 {
2172  afw_compile_shared_t *shared;
2173 
2174  shared = afw_pool_calloc_type(p, afw_compile_shared_t, xctx);
2175  shared->p = p;
2176  shared->temp_p = afw_pool_create(p, xctx);
2177  shared->string_literals = apr_hash_make(
2178  afw_pool_get_apr_pool(shared->temp_p));
2179 
2180  return shared;
2181 }
2182 
2183 
2184 
2185 /* Create a parser. */
2187 afw_compile_lexical_parser_create(
2188  const afw_utf8_t *source,
2189  afw_utf8_octet_get_cb_t callback,
2190  void *callback_data,
2191  const afw_utf8_t *source_location,
2192  afw_compile_type_t compile_type,
2193  afw_compile_residual_check_t residual_check,
2194  afw_boolean_t cede_p,
2195  const afw_value_compiled_value_t *parent,
2196  const afw_compile_shared_t *shared,
2197  const afw_pool_t *p,
2198  afw_xctx_t *xctx)
2199 {
2200  afw_compile_parser_t *parser;
2201 
2202  /* Initialize parser work area. */
2204  if (cede_p && ( shared || parent)) {
2205  AFW_THROW_ERROR_Z(general,
2206  "afw_compile_lexical_parser_create() parameter cede_p true when "
2207  "parent or shared is not NULL",
2208  xctx);
2209  }
2210  if (!p && !shared && !parent) {
2211  AFW_THROW_ERROR_Z(general,
2212  "afw_compile_lexical_parser_create() either "
2213  "parent, shared or p must be non-NULL",
2214  xctx);
2215  }
2216  if (shared) {
2217  parser->p = shared->p;
2218  parser->shared = shared;
2219  }
2220  else {
2221  if (parent) {
2222  parser->p = parent->p;
2223  }
2224  else if (cede_p) {
2225  parser->p = p;
2226  }
2227  else {
2228  parser->p = afw_pool_create(p, xctx);
2229  }
2230  parser->shared = afw_compile_shared_create(parser->p, xctx);
2231  }
2232  parser->apr_p = afw_pool_get_apr_pool(parser->p);
2233  parser->xctx = xctx;
2234  parser->cede_p = cede_p;
2235  parser->error = xctx->error;
2236  parser->passed_source = source;
2237  parser->callback = callback,
2238  parser->callback_data = callback_data,
2239  parser->strict = compile_type == afw_compile_type_json;
2240  parser->compile_type = compile_type;
2241  parser->residual_check = residual_check;
2242  parser->contextual.source_location = source_location;
2243  parser->s = apr_array_make(parser->apr_p, 256,
2244  sizeof(afw_utf8_octet_t));
2245  parser->values = apr_array_make(parser->apr_p, 10,
2246  sizeof(afw_value_t *));
2247 
2248  parser->estimated_size = 4096;
2249  parser->token = &parser->token_storage;
2250 
2251  /* Initialize parser->compiled_value. */
2252  parser->compiled_value = afw_pool_calloc_type(parser->p,
2254  parser->compiled_value->inf = &afw_value_compiled_value_inf;
2255  parser->compiled_value->p = parser->p;
2256  if (source_location) {
2257  parser->compiled_value->source_location =
2258  afw_utf8_clone(source_location, parser->p, xctx);
2259  }
2260  if (parent) {
2261  parser->compiled_value->parent = parent;
2262  parser->compiled_value->top_block = parent->current_block;
2263  parser->compiled_value->current_block = parent->current_block;
2264  }
2265 
2266  return parser;
2267 }
2268 
2269 
2270 AFW_DEFINE_INTERNAL(void)
2271 afw_compile_lexical_parser_finish_and_release(
2272  afw_compile_parser_t *parser,
2273  afw_xctx_t *xctx)
2274 {
2275 
2276 }
2277 
2278 
2279 
2281 afw_compile_get_string_literal(
2282  afw_compile_parser_t *parser,
2283  const afw_utf8_octet_t *s,
2284  afw_size_t len)
2285 {
2286  const afw_utf8_t *result;
2287 
2288  result = apr_hash_get(parser->shared->string_literals, s, len);
2289  if (!result) {
2290  result = afw_utf8_create_copy(s, len,
2291  parser->p, parser->xctx);
2292  apr_hash_set(parser->shared->string_literals,
2293  (const void *)result->s,
2294  (apr_ssize_t)result->len,
2295  (const void *)result);
2296  }
2297 
2298  return result;
2299 }
2300 
2301 
2303 afw_compile_current_raw_token(
2304  afw_compile_parser_t* parser)
2305 {
2306  return afw_compile_get_string_literal(parser,
2307  parser->full_source->s + parser->token->token_source_offset,
2308  parser->token->token_source_len);
2309 }
AFW_DEFINE(const afw_object_t *)
#define AFW_DEFINE_INTERNAL(type)
Define an internal function for /src/afw/ source*.c files.
Adaptive Framework Core Internal.
#define AFW_ASCII_VT
Vertical Tab.
Definition: afw_ascii.h:66
#define AFW_ASCII_FF
Form Feed.
Definition: afw_ascii.h:69
#define AFW_ASCII_CR
Carriage Return.
Definition: afw_ascii.h:72
#define AFW_ASCII_HT
Horizontal Tab.
Definition: afw_ascii.h:60
#define AFW_ASCII_LF
Line Feed.
Definition: afw_ascii.h:63
#define afw_ascii_is_whitespace(v)
Determine if octet is white space.
Definition: afw_ascii.h:238
#define AFW_ASCII_BS
BackSpace (non-destructive)
Definition: afw_ascii.h:57
afw_compile_code_point_is_IdentifierContinue(afw_code_point_t cp)
Determine if codepoint matches AFW IdentifierContinue production.
afw_compile_code_point_is_IdentifierStart(afw_code_point_t cp)
Determine if codepoint matches AFW IdentifierStart production.
afw_compile_code_point_is_EOL(afw_code_point_t cp)
Determine if codepoint matches AFW EOL production.
afw_compile_code_point_is_WhitespaceOrEOL(afw_code_point_t cp)
Determine if codepoint matches AFW Whitespace or EOL productions.
_Bool afw_boolean_t
Definition: afw_common.h:373
afw_int32_t afw_code_point_t
Unicode code point.
Definition: afw_common.h:205
int(* afw_utf8_octet_get_cb_t)(afw_utf8_octet_t *octet, void *data, afw_xctx_t *xctx)
Get an utf-8 octet (8 bits).
Definition: afw_common.h:255
afw_utf8_octet_t afw_utf8_z_t
NFC normalized UTF-8 null terminated string.
Definition: afw_common.h:523
enum afw_compile_type_e afw_compile_type_t
Compile type enum.
char afw_utf8_octet_t
8 bits of utf-8 codepoint.
Definition: afw_common.h:236
apr_size_t afw_size_t
size_t.
Definition: afw_common.h:151
unsigned char afw_octet_t
8 bits (unsigned).
Definition: afw_common.h:211
#define AFW_SIZE_T_FMT
Format string specifier used for afw_size_t.
Definition: afw_common.h:341
#define AFW_INTEGER_MAX
largest afw_integer_t
Definition: afw_common.h:281
#define AFW_INTEGER_MIN
smallest afw_integer_t
Definition: afw_common.h:291
apr_int64_t afw_integer_t
typedef for big signed int.
Definition: afw_common.h:321
#define AFW_COMPILE_THROW_ERROR_Z(message_z)
enum afw_compile_residual_check_e afw_compile_residual_check_t
Residual checking options.
afw_compile_shared_create(const afw_pool_t *p, afw_xctx_t *xctx)
Created a struct for sharing resources by multiple compiles.
#define AFW_THROW_ERROR_FZ(code, xctx, format_z,...)
Macro used to set error and 0 rv in xctx and throw it.
Definition: afw_error.h:319
#define AFW_THROW_ERROR_Z(code, message_z, xctx)
Macro used to set error and 0 rv in xctx and throw it.
Definition: afw_error.h:283
#define afw_pool_get_apr_pool(instance)
Call method get_apr_pool of interface afw_pool.
#define afw_pool_calloc_type(instance, type, xctx)
Macro to allocate cleared memory to hold type in pool.
Definition: afw_pool.h:167
const afw_pool_t * afw_pool_create(const afw_pool_t *parent, afw_xctx_t *xctx)
Create a new pool.
afw_boolean_t afw_utf8_equal_utf8_z(const afw_utf8_t *s1, const afw_utf8_z_t *s2_z)
Check to see if a string equals a utf8_z string.
#define afw_utf8_create_copy(s, len, p, xctx)
Make a utf-8 sting from chars in pool specified.
Definition: afw_utf8.h:369
afw_boolean_t afw_utf8_equal(const afw_utf8_t *s1, const afw_utf8_t *s2)
Check to see if a string equals another string.
afw_utf8_from_code_point(afw_utf8_octet_t utf8_z[5], afw_code_point_t cp, afw_xctx_t *xctx)
Convert a code point to utf8.
Definition: afw_utf8.c:64
const afw_utf8_t * afw_utf8_clone(const afw_utf8_t *string, const afw_pool_t *p, afw_xctx_t *xctx)
Clone a utf-8 string into a specific pool.
Definition: afw_utf8.h:347
afw_value_compiled_value_inf
Value call inf.
Definition: afw_value.h:249
#define afw_xctx_calloc_type(type, xctx)
Macro to allocate cleared memory to hold type in xctx's pool.
Definition: afw_xctx.h:199
Resources that can be shared by multiple compiles.
const afw_utf8_t * source_location
Source location.
afw_double_t minus_infinity
Double minus infinity.
Definition: afw_common.h:1437
afw_double_t NaN
Double NaN.
Definition: afw_common.h:1443
afw_double_t infinity
Double infinity.
Definition: afw_common.h:1431
Interface afw_pool public struct.
NFC normalized UTF-8 string.
Definition: afw_common.h:545
Struct for compiled value value.
const afw_value_compiled_value_t * parent
The parent compiled value or NULL.
const afw_pool_t * p
Pool containing value.
const afw_utf8_t * source_location
Source location provided to compiler.
Interface afw_value public struct.
Interface afw_xctx public struct.