wsstree.c
上传用户:gzpyjq
上传日期:2013-01-31
资源大小:1852k
文件大小:43k
源码类别:

手机WAP编程

开发平台:

WINDOWS

  1. /*
  2.  *
  3.  * wsstree.c
  4.  *
  5.  * Author: Markku Rossi <mtr@iki.fi>
  6.  *
  7.  * Copyright (c) 1999-2000 WAPIT OY LTD.
  8.  *  All rights reserved.
  9.  *
  10.  * Syntax tree creation, manipulation and byte-code assembler
  11.  * generation.
  12.  *
  13.  */
  14. #include "wsint.h"
  15. #include "wsgram.h"
  16. /* TODO: Constant folding. */
  17. /********************* Misc syntax tree structures **********************/
  18. WsVarDec *ws_variable_declaration(WsCompilerPtr compiler,
  19.                                   char *name, WsExpression *expr)
  20. {
  21.     WsVarDec *vardec = ws_f_malloc(compiler->pool_stree, sizeof(*vardec));
  22.     if (vardec == NULL)
  23.         ws_error_memory(compiler);
  24.     else {
  25.         vardec->name = name;
  26.         vardec->expr = expr;
  27.     }
  28.     return vardec;
  29. }
  30. WsFormalParm *ws_formal_parameter(WsCompilerPtr compiler,
  31.                                   WsUInt32 line, char *name)
  32. {
  33.     WsFormalParm *parm = ws_f_malloc(compiler->pool_stree, sizeof(*parm));
  34.     if (parm == NULL)
  35.         ws_error_memory(compiler);
  36.     else {
  37.         parm->line = line;
  38.         parm->name = name;
  39.     }
  40.     return parm;
  41. }
  42. /********************* Linked list **************************************/
  43. WsList *ws_list_new(WsCompiler *compiler)
  44. {
  45.     WsList *list = ws_f_calloc(compiler->pool_stree, 1, sizeof(*list));
  46.     if (list == NULL)
  47.         ws_error_memory(compiler);
  48.     return list;
  49. }
  50. void ws_list_append(WsCompiler *compiler, WsList *list, void *value)
  51. {
  52.     WsListItem *item;
  53.     if (list == NULL)
  54.         /* A recovery code for previous memory allocation problems. */
  55.         return;
  56.     item = ws_f_calloc(compiler->pool_stree, 1, sizeof(*item));
  57.     if (item == NULL) {
  58.         ws_error_memory(compiler);
  59.         return;
  60.     }
  61.     item->data = value;
  62.     if (list->tail) {
  63.         list->tail->next = item;
  64.         list->tail = item;
  65.     } else
  66.         list->head = list->tail = item;
  67.     list->num_items++;
  68. }
  69. /********************* Namespace for arguments and locals ***************/
  70. static void variable_hash_destructor(void *item, void *context)
  71. {
  72.     ws_free(item);
  73. }
  74. WsHashPtr ws_variable_hash_create(void)
  75. {
  76.     return ws_hash_create(variable_hash_destructor, NULL);
  77. }
  78. WsNamespace *ws_variable_define(WsCompilerPtr compiler, WsUInt32 line,
  79.                                 WsBool variablep, char *name)
  80. {
  81.     WsNamespace *ns;
  82.     /* Is the symbol already defined? */
  83.     ns = ws_hash_get(compiler->variables_hash, name);
  84.     if (ns) {
  85.         ws_src_error(compiler, line, "redeclaration of `%s'", name);
  86.         ws_src_error(compiler, ns->line, "`%s' previously declared here", name);
  87.         return NULL;
  88.     }
  89.     /* Can we still define more variables? */
  90.     if (compiler->next_vindex > 255) {
  91.         /* No we can't. */
  92.         ws_src_error(compiler, line, "too many local variables");
  93.         return NULL;
  94.     }
  95.     ns = ws_calloc(1, sizeof(*ns));
  96.     if (ns == NULL) {
  97.         ws_error_memory(compiler);
  98.         return NULL;
  99.     }
  100.     ns->line = line;
  101.     ns->vindex = compiler->next_vindex++;
  102.     if (!ws_hash_put(compiler->variables_hash, name, ns)) {
  103.         ws_free(ns);
  104.         ws_error_memory(compiler);
  105.         return NULL;
  106.     }
  107.     return ns;
  108. }
  109. WsNamespace *ws_variable_lookup(WsCompilerPtr compiler, char *name)
  110. {
  111.     return ws_hash_get(compiler->variables_hash, name);
  112. }
  113. /********************* Top-level declarations ***************************/
  114. /* External compilation units. */
  115. static void pragma_use_hash_destructor(void *item, void *context)
  116. {
  117.     ws_free(item);
  118. }
  119. WsHashPtr ws_pragma_use_hash_create(void)
  120. {
  121.     return ws_hash_create(pragma_use_hash_destructor, NULL);
  122. }
  123. void ws_pragma_use(WsCompilerPtr compiler, WsUInt32 line, char *identifier,
  124.                    WsUtf8String *url)
  125. {
  126.     WsPragmaUse *u = ws_calloc(1, sizeof(*u));
  127.     WsPragmaUse *uold;
  128.     /* Do we already know this pragma? */
  129.     uold = ws_hash_get(compiler->pragma_use_hash, identifier);
  130.     if (uold) {
  131.         ws_src_error(compiler, line, "redefinition of pragma `%s'", identifier);
  132.         ws_src_error(compiler, uold->line, "`%s' previously defined here",
  133.                      identifier);
  134.         goto error_cleanup;
  135.     }
  136.     if (u == NULL)
  137.         goto error;
  138.     u->line = line;
  139.     /* Insert the URL to the byte-code module. */
  140.     if (!ws_bc_add_const_utf8_string(compiler->bc, &u->urlindex, url->data,
  141.                                      url->len))
  142.         goto error;
  143.     /* Add it to the use pragma hash. */
  144.     if (!ws_hash_put(compiler->pragma_use_hash, identifier, u))
  145.         goto error;
  146.     /* Cleanup. */
  147.     ws_lexer_free_block(compiler, identifier);
  148.     ws_lexer_free_utf8(compiler, url);
  149.     return;
  150.     /* Error handling. */
  151. error:
  152.     ws_error_memory(compiler);
  153. error_cleanup:
  154.     ws_free(u);
  155.     ws_lexer_free_block(compiler, identifier);
  156.     ws_lexer_free_utf8(compiler, url);
  157. }
  158. /* MetaBody of the `use meta' pragmas. */
  159. WsPragmaMetaBody *ws_pragma_meta_body(WsCompilerPtr compiler,
  160.                                       WsUtf8String *property_name,
  161.                                       WsUtf8String *content,
  162.                                       WsUtf8String *scheme)
  163. {
  164.     WsPragmaMetaBody *mb = ws_calloc(1, sizeof(*mb));
  165.     if (mb == NULL) {
  166.         ws_error_memory(compiler);
  167.         return NULL;
  168.     }
  169.     mb->property_name = property_name;
  170.     mb->content = content;
  171.     mb->scheme = scheme;
  172.     return mb;
  173. }
  174. void ws_pragma_meta_body_free(WsCompilerPtr compiler, WsPragmaMetaBody *mb)
  175. {
  176.     if (mb == NULL)
  177.         return;
  178.     ws_lexer_free_utf8(compiler, mb->property_name);
  179.     ws_lexer_free_utf8(compiler, mb->content);
  180.     ws_lexer_free_utf8(compiler, mb->scheme);
  181.     ws_free(mb);
  182. }
  183. /* Functions. */
  184. static void function_hash_destructor(void *item, void *context)
  185. {
  186.     ws_free(item);
  187. }
  188. WsHashPtr ws_function_hash_create(void)
  189. {
  190.     return ws_hash_create(function_hash_destructor, NULL);
  191. }
  192. WsFunctionHash *ws_function_hash(WsCompilerPtr compiler, char *name)
  193. {
  194.     WsFunctionHash *i = ws_hash_get(compiler->functions_hash, name);
  195.     if (i)
  196.         return i;
  197.     /* Must create a new mapping. */
  198.     i = ws_calloc(1, sizeof(*i));
  199.     if (i == NULL) {
  200.         ws_error_memory(compiler);
  201.         return NULL;
  202.     }
  203.     if (!ws_hash_put(compiler->functions_hash, name, i)) {
  204.         ws_free(i);
  205.         ws_error_memory(compiler);
  206.         return NULL;
  207.     }
  208.     return i;
  209. }
  210. void ws_function(WsCompiler *compiler, WsBool externp, char *name,
  211.                  WsUInt32 line, WsList *params, WsList *block)
  212. {
  213.     WsFunctionHash *hash;
  214.     WsFunction *f = ws_realloc(compiler->functions,
  215.                                ((compiler->num_functions + 1)
  216.                                 * sizeof(WsFunction)));
  217.     if (f == NULL) {
  218.         ws_free(name);
  219.         ws_error_memory(compiler);
  220.         return;
  221.     }
  222.     if (externp)
  223.         compiler->num_extern_functions++;
  224.     else
  225.         compiler->num_local_functions++;
  226.     compiler->functions = f;
  227.     f = &compiler->functions[compiler->num_functions];
  228.     f->findex = compiler->num_functions++;
  229.     f->externp = externp;
  230.     f->name = name;
  231.     f->line = line;
  232.     f->params = params;
  233.     f->block = block;
  234.     /* Update the function name hash. */
  235.     hash = ws_function_hash(compiler, name);
  236.     if (hash == NULL) {
  237.         ws_error_memory(compiler);
  238.         return;
  239.     }
  240.     if (hash->defined) {
  241.         ws_src_error(compiler, line, "redefinition of `%s'", name);
  242.         ws_src_error(compiler,
  243.                      compiler->functions[hash->findex].line,
  244.                      "`%s' previously defined here", name);
  245.         return;
  246.     }
  247.     hash->defined = WS_TRUE;
  248.     hash->findex = f->findex;
  249. }
  250. /********************* Expressions **************************************/
  251. void ws_expr_linearize(WsCompiler *compiler, WsExpression *expr)
  252. {
  253.     WsListItem *li;
  254.     WsAsmIns *ins;
  255.     switch (expr->type) {
  256.     case WS_EXPR_COMMA:
  257.         /* Linearize left. */
  258.         ws_expr_linearize(compiler, expr->u.comma.left);
  259.         /* Pop its result. */
  260.         ws_asm_link(compiler, ws_asm_ins(compiler, expr->line, WS_ASM_POP));
  261.         /* Linearize right */
  262.         ws_expr_linearize(compiler, expr->u.comma.right);
  263.         break;
  264.     case WS_EXPR_ASSIGN:
  265.         {
  266.             WsNamespace *ns = ws_variable_lookup(compiler,
  267.                                                  expr->u.assign.identifier);
  268.             if (ns == NULL) {
  269.                 /* Unknown identifier. */
  270.                 ws_src_error(compiler, expr->line, "unknown variable `%s'",
  271.                              expr->u.symbol);
  272.                 return;
  273.             }
  274.             if (expr->u.assign.op == '=') {
  275.                 /* Evaluate the expression. */
  276.                 ws_expr_linearize(compiler, expr->u.assign.expr);
  277.                 /* Store the value to the variable. */
  278.                 ws_asm_link(compiler,
  279.                             ws_asm_variable(compiler, expr->line,
  280.                                             WS_ASM_P_STORE_VAR, ns->vindex));
  281.             } else if (expr->u.assign.op == tADDA) {
  282.                 /* Linearize the expression. */
  283.                 ws_expr_linearize(compiler, expr->u.assign.expr);
  284.                 /* Add it to the variable. */
  285.                 ws_asm_link(compiler,
  286.                             ws_asm_variable(compiler, expr->line,
  287.                                             WS_ASM_ADD_ASG, ns->vindex));
  288.             } else if (expr->u.assign.op == tSUBA) {
  289.                 /* Linearize the expression. */
  290.                 ws_expr_linearize(compiler, expr->u.assign.expr);
  291.                 /* Substract it from the variable. */
  292.                 ws_asm_link(compiler,
  293.                             ws_asm_variable(compiler, expr->line,
  294.                                             WS_ASM_SUB_ASG, ns->vindex));
  295.             } else {
  296.                 /* Load the old value from the variable. */
  297.                 ws_asm_link(compiler,
  298.                             ws_asm_variable(compiler, expr->line,
  299.                                             WS_ASM_P_LOAD_VAR, ns->vindex));
  300.                 /* Evaluate the expression. */
  301.                 ws_expr_linearize(compiler, expr->u.assign.expr);
  302.                 /* Perform the operand. */
  303.                 ins = NULL;
  304.                 switch (expr->u.assign.op) {
  305.                 case tMULA:
  306.                     ins = ws_asm_ins(compiler, expr->line, WS_ASM_MUL);
  307.                     break;
  308.                 case tDIVA:
  309.                     ins = ws_asm_ins(compiler, expr->line, WS_ASM_DIV);
  310.                     break;
  311.                 case tREMA:
  312.                     ins = ws_asm_ins(compiler, expr->line, WS_ASM_REM);
  313.                     break;
  314.                 case tADDA:
  315.                     ins = ws_asm_ins(compiler, expr->line, WS_ASM_ADD);
  316.                     break;
  317.                 case tSUBA:
  318.                     ins = ws_asm_ins(compiler, expr->line, WS_ASM_SUB);
  319.                     break;
  320.                 case tLSHIFTA:
  321.                     ins = ws_asm_ins(compiler, expr->line, WS_ASM_B_LSHIFT);
  322.                     break;
  323.                 case tRSSHIFTA:
  324.                     ins = ws_asm_ins(compiler, expr->line, WS_ASM_B_RSSHIFT);
  325.                     break;
  326.                 case tRSZSHIFTA:
  327.                     ins = ws_asm_ins(compiler, expr->line, WS_ASM_B_RSZSHIFT);
  328.                     break;
  329.                 case tANDA:
  330.                     ins = ws_asm_ins(compiler, expr->line, WS_ASM_B_AND);
  331.                     break;
  332.                 case tXORA:
  333.                     ins = ws_asm_ins(compiler, expr->line, WS_ASM_B_XOR);
  334.                     break;
  335.                 case tORA:
  336.                     ins = ws_asm_ins(compiler, expr->line, WS_ASM_B_OR);
  337.                     break;
  338.                 case tIDIVA:
  339.                     ins = ws_asm_ins(compiler, expr->line, WS_ASM_IDIV);
  340.                     break;
  341.                 default:
  342.                     ws_fatal("ws_expr_linearize(): unknown assignment operand %x",
  343.                              expr->u.assign.op);
  344.                     break;
  345.                 }
  346.                 ws_asm_link(compiler, ins);
  347.                 /* Store the value to the variable. */
  348.                 ws_asm_link(compiler,
  349.                             ws_asm_variable(compiler, expr->line,
  350.                                             WS_ASM_P_STORE_VAR, ns->vindex));
  351.             }
  352.             /* The value of the assignment expression is the value
  353.                assigned.  So, we must load the value from the variable.
  354.                This would also be a good place for the `dup' operand but
  355.                we lose since we don't have it. */
  356.             ws_asm_link(compiler, ws_asm_variable(compiler, expr->line,
  357.                                                   WS_ASM_P_LOAD_VAR, ns->vindex));
  358.         }
  359.         break;
  360.     case WS_EXPR_CONDITIONAL:
  361.         {
  362.             WsAsmIns *l_else = ws_asm_label(compiler, expr->line);
  363.             WsAsmIns *l_end = ws_asm_label(compiler, expr->line);
  364.             /* Linearize condition. */
  365.             ws_expr_linearize(compiler, expr->u.conditional.e_cond);
  366.             /* If the result if false, jump to the else-branch. */
  367.             ws_asm_link(compiler, ws_asm_branch(compiler, expr->line,
  368.                                                 WS_ASM_P_TJUMP, l_else));
  369.             /* Linearize the then-expression and jump out. */
  370.             ws_expr_linearize(compiler, expr->u.conditional.e_then);
  371.             ws_asm_link(compiler, ws_asm_branch(compiler, expr->line,
  372.                                                 WS_ASM_P_JUMP, l_end));
  373.             /* The else-branch. */
  374.             ws_asm_link(compiler, l_else);
  375.             ws_expr_linearize(compiler, expr->u.conditional.e_else);
  376.             /* Insert the end label. */
  377.             ws_asm_link(compiler, l_end);
  378.         }
  379.         break;
  380.     case WS_EXPR_LOGICAL:
  381.         {
  382.             WsAsmIns *l_out = ws_asm_label(compiler, expr->line);
  383.             /* Linearize the left-hand size expression. */
  384.             ws_expr_linearize(compiler, expr->u.logical.left);
  385.             /* Short-circuit check.  The type of the logical expression is
  386.                       the short-circuit byte-code operand. */
  387.             ws_asm_link(compiler, ws_asm_ins(compiler, expr->line,
  388.                                              expr->u.logical.type));
  389.             ws_asm_link(compiler, ws_asm_branch(compiler, expr->line,
  390.                                                 WS_ASM_P_TJUMP, l_out));
  391.             /* Linearize the right-hand size expression. */
  392.             ws_expr_linearize(compiler, expr->u.logical.right);
  393.             /* The result of a logical expression should be boolean.
  394.              * Control statements do automatic conversion, but typeof()
  395.      * does not. */
  396.             ws_asm_link(compiler, ws_asm_ins(compiler, expr->line,
  397.                                          WS_ASM_TOBOOL));
  398.             /* Insert the end label. */
  399.             ws_asm_link(compiler, l_out);
  400.         }
  401.         break;
  402.     case WS_EXPR_BINARY:
  403.         /* Linearize left and right. */
  404.         ws_expr_linearize(compiler, expr->u.binary.left);
  405.         ws_expr_linearize(compiler, expr->u.binary.right);
  406.         /* The type of the binary expression is the byte-code opcode. */
  407.         ws_asm_link(compiler, ws_asm_ins(compiler, expr->line,
  408.                                          expr->u.binary.type));
  409.         break;
  410.     case WS_EXPR_UNARY:
  411.         /* Linearize the expression. */
  412.         ws_expr_linearize(compiler, expr->u.unary.expr);
  413.         /* The type of the unary expression is the byte-code opcode. */
  414.         ws_asm_link(compiler, ws_asm_ins(compiler, expr->line,
  415.                                          expr->u.unary.type));
  416.         break;
  417.     case WS_EXPR_UNARY_VAR:
  418.         {
  419.             WsNamespace *ns = ws_variable_lookup(compiler,
  420.                                                  expr->u.unary_var.variable);
  421.             if (ns == NULL) {
  422.                 /* An unknown identifier. */
  423.                 ws_src_error(compiler, expr->line, "unknown variable `%s'",
  424.                              expr->u.unary_var.variable);
  425.                 return;
  426.             }
  427.             /* First, do the operation. */
  428.             if (expr->u.unary_var.addp)
  429.                 ws_asm_link(compiler,
  430.                             ws_asm_variable(compiler, expr->line, WS_ASM_P_INCR_VAR,
  431.                                             ns->vindex));
  432.             else
  433.                 ws_asm_link(compiler,
  434.                             ws_asm_variable(compiler, expr->line, WS_ASM_DECR_VAR,
  435.                                             ns->vindex));
  436.             /* Second, load the new value of the variable. */
  437.             ws_asm_link(compiler, ws_asm_variable(compiler, expr->line,
  438.                                                   WS_ASM_P_LOAD_VAR, ns->vindex));
  439.         }
  440.         break;
  441.     case WS_EXPR_POSTFIX_VAR:
  442.         {
  443.             WsNamespace *ns = ws_variable_lookup(compiler,
  444.                                                  expr->u.postfix_var.variable);
  445.             if (ns == NULL) {
  446.                 /* An unknown identifier. */
  447.                 ws_src_error(compiler, expr->line, "unknown variable `%s'",
  448.                              expr->u.postfix_var.variable);
  449.                 return;
  450.             }
  451.             /* First, load the old value of the variable. */
  452.             ws_asm_link(compiler, ws_asm_variable(compiler, expr->line,
  453.                                                   WS_ASM_P_LOAD_VAR, ns->vindex));
  454.             /* Second, do the operation. */
  455.             if (expr->u.unary_var.addp)
  456.                 ws_asm_link(compiler,
  457.                             ws_asm_variable(compiler, expr->line, WS_ASM_P_INCR_VAR,
  458.                                             ns->vindex));
  459.             else
  460.                 ws_asm_link(compiler,
  461.                             ws_asm_variable(compiler, expr->line, WS_ASM_DECR_VAR,
  462.                                             ns->vindex));
  463.         }
  464.         break;
  465.     case WS_EXPR_CALL:
  466.         /* First, evaluate the arguments. */
  467.         for (li = expr->u.call.arguments->head; li; li = li->next)
  468.             ws_expr_linearize(compiler, li->data);
  469.         /* Second, emit the call instruction. */
  470.         switch (expr->u.call.type) {
  471.         case ' ':  /* LocalScriptFunctionCall */
  472.             {
  473.                 WsFunctionHash *f = ws_function_hash(compiler, expr->u.call.name);
  474.                 if (f == NULL || !f->defined)
  475.                 {
  476.                     ws_src_error(compiler, expr->line,
  477.                                  "unknown local function `%s'",
  478.                                  expr->u.call.name);
  479.                     return;
  480.                 }
  481.                 /* Check that the function is called with correct amount
  482.                           of arguments. */
  483.                 if (expr->u.call.arguments->num_items
  484.                     != compiler->functions[f->findex].params->num_items)
  485.                 {
  486.                     ws_src_error(compiler, expr->line,
  487.                                  "invalid amount of arguments for `%s': "
  488.                                  "expected %u, got %u",
  489.                                  expr->u.call.name,
  490.                                  compiler->functions[f->findex].params->num_items,
  491.                                  expr->u.call.arguments->num_items);
  492.                     return;
  493.                 }
  494.                 /* Emit assembler. */
  495.                 ws_asm_link(compiler, ws_asm_call(compiler, expr->line,
  496.                                                   f->findex));
  497.             }
  498.             break;
  499.         case '#':  /* ExternalScriptFunctionCall */
  500.             {
  501.                 WsPragmaUse *use = ws_hash_get(compiler->pragma_use_hash,
  502.                                                expr->u.call.base);
  503.                 WsUInt16 findex;
  504.                 if (use == NULL)
  505.                 {
  506.                     ws_src_error(compiler, expr->line,
  507.                                  "unknown external compilation unit `%s'",
  508.                                  expr->u.call.base);
  509.                     return;
  510.                 }
  511.                 /* Insert the function name to the byte-code pool. */
  512.                 if (!ws_bc_add_const_utf8_string(
  513.                         compiler->bc, &findex,
  514.                         (unsigned char *) expr->u.call.name,
  515.                         strlen(expr->u.call.name)))
  516.                 {
  517.                     ws_error_memory(compiler);
  518.                     return;
  519.                 }
  520.                 /* Emit assembler. */
  521.                 ws_asm_link(compiler,
  522.                             ws_asm_call_url(compiler, expr->line,
  523.                                             findex, use->urlindex,
  524.                                             expr->u.call.arguments->num_items));
  525.             }
  526.             break;
  527.         case '.':  /* LibraryFunctionCall */
  528.             {
  529.                 WsUInt16 lindex;
  530.                 WsUInt8 findex;
  531.                 WsUInt8 num_args;
  532.                 WsBool lindex_found;
  533.                 WsBool findex_found;
  534.                 if (!ws_stdlib_function(expr->u.call.base, expr->u.call.name,
  535.                                         &lindex, &findex, &num_args,
  536.                                         &lindex_found, &findex_found))
  537.                 {
  538.                     if (!lindex_found)
  539.                         ws_src_error(compiler, expr->line,
  540.                                      "unknown system library `%s'",
  541.                                      expr->u.call.base);
  542.                     else
  543.                         ws_src_error(compiler, expr->line,
  544.                                      "unknown library function `%s.%s'",
  545.                                      expr->u.call.base, expr->u.call.name);
  546.                     return;
  547.                 }
  548.                 /* Check the argument count. */
  549.                 if (expr->u.call.arguments->num_items != num_args)
  550.                 {
  551.                     ws_src_error(compiler, expr->line,
  552.                                  "invalid amount of arguments for `%s.%s': "
  553.                                  "expected %u, got %u",
  554.                                  expr->u.call.base, expr->u.call.name,
  555.                                  num_args, expr->u.call.arguments->num_items);
  556.                     return;
  557.                 }
  558.                 /* Emit assembler. */
  559.                 ws_asm_link(compiler, ws_asm_call_lib(compiler, expr->line, findex,
  560.                                                       lindex));
  561.             }
  562.             break;
  563.         default:
  564.             ws_fatal("ws_expr_linearize(): unknown call expression type %x",
  565.                      expr->u.call.type);
  566.             break;
  567.         }
  568.         break;
  569.     case WS_EXPR_SYMBOL:
  570.         {
  571.             WsNamespace *ns = ws_variable_lookup(compiler, expr->u.symbol);
  572.             if (ns == NULL) {
  573.                 /* An unknown identifier. */
  574.                 ws_src_error(compiler, expr->line, "unknown variable `%s'",
  575.                              expr->u.symbol);
  576.                 return;
  577.             }
  578.             /* Create a load instruction for the variable. */
  579.             ws_asm_link(compiler, ws_asm_variable(compiler, expr->line,
  580.                                                   WS_ASM_P_LOAD_VAR, ns->vindex));
  581.         }
  582.         break;
  583.     case WS_EXPR_CONST_INVALID:
  584.         ws_asm_link(compiler, ws_asm_ins(compiler, expr->line,
  585.                                          WS_ASM_CONST_INVALID));
  586.         break;
  587.     case WS_EXPR_CONST_TRUE:
  588.         ws_asm_link(compiler, ws_asm_ins(compiler, expr->line,
  589.                                          WS_ASM_CONST_TRUE));
  590.         break;
  591.     case WS_EXPR_CONST_FALSE:
  592.         ws_asm_link(compiler, ws_asm_ins(compiler, expr->line,
  593.                                          WS_ASM_CONST_FALSE));
  594.         break;
  595.     case WS_EXPR_CONST_INTEGER:
  596.         if (expr->u.integer.ival == 0)
  597.             ins = ws_asm_ins(compiler, expr->line, WS_ASM_CONST_0);
  598.         else if (expr->u.integer.ival == 1 && expr->u.integer.sign == 1)
  599.             ins = ws_asm_ins(compiler, expr->line, WS_ASM_CONST_1);
  600.         else {
  601.             WsUInt16 cindex;
  602.     WsInt32 ival;
  603.             if (expr->u.integer.sign >= 0) {
  604. if (expr->u.integer.ival > (WsUInt32) WS_INT32_MAX)
  605.     ws_src_error(compiler, expr->line,
  606.                                  "integer literal too large");
  607.                 ival = expr->u.integer.ival;
  608.     } else {
  609.                 if (expr->u.integer.ival > (WsUInt32) WS_INT32_MAX + 1)
  610.     ws_src_error(compiler, expr->line, "integer too small");
  611.                 ival = - (WsInt32) expr->u.integer.ival;
  612.     }
  613.             if (!ws_bc_add_const_int(compiler->bc, &cindex, ival)) {
  614.                 ws_error_memory(compiler);
  615.                 return;
  616.             }
  617.             ins = ws_asm_load_const(compiler, expr->line, cindex);
  618.         }
  619.         ws_asm_link(compiler, ins);
  620.         break;
  621.     case WS_EXPR_CONST_FLOAT:
  622.         {
  623.             WsUInt16 cindex;
  624.             if (!ws_bc_add_const_float(compiler->bc, &cindex, expr->u.fval)) {
  625.                 ws_error_memory(compiler);
  626.                 return;
  627.             }
  628.             ws_asm_link(compiler, ws_asm_load_const(compiler, expr->line, cindex));
  629.         }
  630.         break;
  631.     case WS_EXPR_CONST_STRING:
  632.         if (expr->u.string.len == 0)
  633.             ins = ws_asm_ins(compiler, expr->line, WS_ASM_CONST_ES);
  634.         else {
  635.             WsUInt16 cindex;
  636.             if (!ws_bc_add_const_utf8_string(compiler->bc, &cindex,
  637.                                              expr->u.string.data,
  638.                                              expr->u.string.len)) {
  639.                 ws_error_memory(compiler);
  640.                 return;
  641.             }
  642.             ins = ws_asm_load_const(compiler, expr->line, cindex);
  643.         }
  644.         ws_asm_link(compiler, ins);
  645.         break;
  646.     }
  647. }
  648. /* Constructors. */
  649. static WsExpression *expr_alloc(WsCompiler *compiler,
  650.                                 WsExpressionType type, WsUInt32 line)
  651. {
  652.     WsExpression *expr = ws_f_calloc(compiler->pool_stree, 1, sizeof(*expr));
  653.     if (expr == NULL)
  654.         ws_error_memory(compiler);
  655.     else {
  656.         expr->type = type;
  657.         expr->line = line;
  658.     }
  659.     return expr;
  660. }
  661. WsExpression *ws_expr_comma(WsCompilerPtr compiler, WsUInt32 line,
  662.                             WsExpression *left, WsExpression *right)
  663. {
  664.     WsExpression *expr = expr_alloc(compiler, WS_EXPR_COMMA, line);
  665.     if (expr) {
  666.         expr->u.comma.left = left;
  667.         expr->u.comma.right = right;
  668.     }
  669.     return expr;
  670. }
  671. WsExpression *ws_expr_assign(WsCompilerPtr compiler, WsUInt32 line,
  672.                              char *identifier, int op, WsExpression *expr)
  673. {
  674.     WsExpression *e = expr_alloc(compiler, WS_EXPR_ASSIGN, line);
  675.     if (e) {
  676.         e->u.assign.identifier = ws_f_strdup(compiler->pool_stree, identifier);
  677.         if (e->u.assign.identifier == NULL)
  678.             ws_error_memory(compiler);
  679.         e->u.assign.op = op;
  680.         e->u.assign.expr = expr;
  681.     }
  682.     /* Free the identifier symbol since it allocated from the system
  683.        heap. */
  684.     ws_lexer_free_block(compiler, identifier);
  685.     return e;
  686. }
  687. WsExpression *ws_expr_conditional(WsCompilerPtr compiler, WsUInt32 line,
  688.                                   WsExpression *e_cond, WsExpression *e_then,
  689.                                   WsExpression *e_else)
  690. {
  691.     WsExpression *e = expr_alloc(compiler, WS_EXPR_CONDITIONAL, line);
  692.     if (e) {
  693.         e->u.conditional.e_cond = e_cond;
  694.         e->u.conditional.e_then = e_then;
  695.         e->u.conditional.e_else = e_else;
  696.     }
  697.     return e;
  698. }
  699. WsExpression *ws_expr_logical(WsCompilerPtr compiler, WsUInt32 line,
  700.                               int type, WsExpression *left, WsExpression *right)
  701. {
  702.     WsExpression *expr = expr_alloc(compiler, WS_EXPR_LOGICAL, line);
  703.     if (expr) {
  704.         expr->u.logical.type = type;
  705.         expr->u.logical.left = left;
  706.         expr->u.logical.right = right;
  707.     }
  708.     return expr;
  709. }
  710. WsExpression *ws_expr_binary(WsCompilerPtr compiler, WsUInt32 line,
  711.                              int type, WsExpression *left, WsExpression *right)
  712. {
  713.     WsExpression *expr = expr_alloc(compiler, WS_EXPR_BINARY, line);
  714.     if (expr) {
  715.         expr->u.binary.type = type;
  716.         expr->u.binary.left = left;
  717.         expr->u.binary.right = right;
  718.     }
  719.     return expr;
  720. }
  721. WsExpression *ws_expr_unary(WsCompilerPtr compiler, WsUInt32 line, int type,
  722.                             WsExpression *expression)
  723. {
  724.     WsExpression *expr;
  725.     /* Handle negative integers here as a special case of constant folding,
  726.      * in order to get -2147483648 right. */
  727.     if (type == WS_ASM_UMINUS && expression->type == WS_EXPR_CONST_INTEGER) {
  728.         expression->u.integer.sign = - expression->u.integer.sign;
  729.         return expression;
  730.     }
  731.     expr = expr_alloc(compiler, WS_EXPR_UNARY, line);
  732.     if (expr) {
  733.         expr->u.unary.type = type;
  734.         expr->u.unary.expr = expression;
  735.     }
  736.     return expr;
  737. }
  738. WsExpression *ws_expr_unary_var(WsCompilerPtr compiler, WsUInt32 line,
  739.                                 WsBool addp, char *variable)
  740. {
  741.     WsExpression *expr = expr_alloc(compiler, WS_EXPR_UNARY_VAR, line);
  742.     if (expr) {
  743.         expr->u.unary_var.addp = addp;
  744.         expr->u.unary_var.variable = ws_f_strdup(compiler->pool_stree, variable);
  745.         if (expr->u.unary_var.variable == NULL)
  746.             ws_error_memory(compiler);
  747.     }
  748.     ws_lexer_free_block(compiler, variable);
  749.     return expr;
  750. }
  751. WsExpression *ws_expr_postfix_var(WsCompilerPtr compiler, WsUInt32 line,
  752.                                   WsBool addp, char *variable)
  753. {
  754.     WsExpression *expr = expr_alloc(compiler, WS_EXPR_POSTFIX_VAR, line);
  755.     if (expr) {
  756.         expr->u.postfix_var.addp = addp;
  757.         expr->u.postfix_var.variable = ws_f_strdup(compiler->pool_stree,
  758.                                        variable);
  759.         if (expr->u.postfix_var.variable == NULL)
  760.             ws_error_memory(compiler);
  761.     }
  762.     ws_lexer_free_block(compiler, variable);
  763.     return expr;
  764. }
  765. WsExpression *ws_expr_call(WsCompiler *compiler, WsUInt32 line,
  766.                            int type, char *base, char *name, WsList *arguments)
  767. {
  768.     WsExpression *expr = expr_alloc(compiler, WS_EXPR_CALL, line);
  769.     if (expr) {
  770.         expr->u.call.type = type;
  771.         expr->u.call.base = ws_f_strdup(compiler->pool_stree, base);
  772.         expr->u.call.name = ws_f_strdup(compiler->pool_stree, name);
  773.         expr->u.call.arguments = arguments;
  774.         if ((base && expr->u.call.base == NULL)
  775.             || (name && expr->u.call.name == NULL))
  776.             ws_error_memory(compiler);
  777.     }
  778.     ws_lexer_free_block(compiler, base);
  779.     ws_lexer_free_block(compiler, name);
  780.     return expr;
  781. }
  782. WsExpression *ws_expr_symbol(WsCompiler *compiler, WsUInt32 line,
  783.                              char *identifier)
  784. {
  785.     WsExpression *expr = expr_alloc(compiler, WS_EXPR_SYMBOL, line);
  786.     if (expr) {
  787.         expr->u.symbol = ws_f_strdup(compiler->pool_stree, identifier);
  788.         if (expr->u.symbol == NULL)
  789.             ws_error_memory(compiler);
  790.     }
  791.     ws_lexer_free_block(compiler, identifier);
  792.     return expr;
  793. }
  794. WsExpression *ws_expr_const_invalid(WsCompiler *compiler, WsUInt32 line)
  795. {
  796.     return expr_alloc(compiler, WS_EXPR_CONST_INVALID, line);
  797. }
  798. WsExpression *ws_expr_const_true(WsCompiler *compiler, WsUInt32 line)
  799. {
  800.     return expr_alloc(compiler, WS_EXPR_CONST_TRUE, line);
  801. }
  802. WsExpression *ws_expr_const_false(WsCompiler *compiler, WsUInt32 line)
  803. {
  804.     return expr_alloc(compiler, WS_EXPR_CONST_FALSE, line);
  805. }
  806. WsExpression *ws_expr_const_integer(WsCompiler *compiler, WsUInt32 line,
  807.                                     WsUInt32 ival)
  808. {
  809.     WsExpression *expr = expr_alloc(compiler, WS_EXPR_CONST_INTEGER, line);
  810.     if (expr) {
  811.         expr->u.integer.sign = 1;
  812.         expr->u.integer.ival = ival;
  813.     }
  814.     return expr;
  815. }
  816. WsExpression *ws_expr_const_float(WsCompiler *compiler, WsUInt32 line,
  817.                                   WsFloat fval)
  818. {
  819.     WsExpression *expr = expr_alloc(compiler, WS_EXPR_CONST_FLOAT, line);
  820.     if (expr)
  821.         expr->u.fval = fval;
  822.     return expr;
  823. }
  824. WsExpression *ws_expr_const_string(WsCompiler *compiler, WsUInt32 line,
  825.                                    WsUtf8String *string)
  826. {
  827.     WsExpression *expr = expr_alloc(compiler, WS_EXPR_CONST_STRING, line);
  828.     if (expr) {
  829.         expr->u.string.len = string->len;
  830.         expr->u.string.data = ws_f_memdup(compiler->pool_stree,
  831.                                           string->data, string->len);
  832.         if (expr->u.string.data == NULL)
  833.             ws_error_memory(compiler);
  834.     }
  835.     ws_lexer_free_utf8(compiler, string);
  836.     return expr;
  837. }
  838. /********************* Statements ***************************************/
  839. /* Linearize the variable declaration list `list'. */
  840. static void linearize_variable_init(WsCompiler *compiler, WsList *list,
  841.                                     WsUInt32 line)
  842. {
  843.     WsNamespace *ns;
  844.     WsListItem *li;
  845.     /* For each variable, declared with this list. */
  846.     for (li = list->head; li; li = li->next) {
  847.         WsVarDec *vardec = li->data;
  848.         ns = ws_variable_define(compiler, line, WS_TRUE, vardec->name);
  849.         if (ns && vardec->expr) {
  850.             ws_expr_linearize(compiler, vardec->expr);
  851.             /* Emit an instruction to store the initialization
  852.                value to the variable. */
  853.             ws_asm_link(compiler,
  854.                         ws_asm_variable(compiler, line, WS_ASM_P_STORE_VAR,
  855.                                         ns->vindex));
  856.         }
  857.     }
  858. }
  859. void ws_stmt_linearize(WsCompiler *compiler, WsStatement *stmt)
  860. {
  861.     WsListItem *li;
  862.     WsAsmIns *ins;
  863.     switch (stmt->type) {
  864.     case WS_STMT_BLOCK:
  865.         for (li = stmt->u.block->head; li; li = li->next)
  866.             ws_stmt_linearize(compiler, li->data);
  867.         break;
  868.     case WS_STMT_VARIABLE:
  869.         linearize_variable_init(compiler, stmt->u.var, stmt->first_line);
  870.         break;
  871.     case WS_STMT_EMPTY:
  872.         /* Nothing here. */
  873.         break;
  874.     case WS_STMT_EXPR:
  875.         ws_expr_linearize(compiler, stmt->u.expr);
  876.         /* Pop the expressions result from the stack.  Otherwise loops
  877.            could eventually cause stack overflows. */
  878.         ws_asm_link(compiler, ws_asm_ins(compiler, stmt->last_line, WS_ASM_POP));
  879.         break;
  880.     case WS_STMT_IF:
  881.         {
  882.             WsAsmIns *l_else = ws_asm_label(compiler,
  883.                                             (stmt->u.s_if.s_else
  884.                                              ? stmt->u.s_if.s_else->first_line
  885.                                              : stmt->last_line));
  886.             WsAsmIns *l_end = ws_asm_label(compiler, stmt->last_line);
  887.             /* Linearize the expression. */
  888.             ws_expr_linearize(compiler, stmt->u.s_if.expr);
  889.             /* If the result is false, jump to the else-branch. */
  890.             ws_asm_link(compiler, ws_asm_branch(compiler, stmt->first_line,
  891.                                                 WS_ASM_P_TJUMP, l_else));
  892.             /* Else, execute the then-branch and jump to the end. */
  893.             ws_stmt_linearize(compiler, stmt->u.s_if.s_then);
  894.             ws_asm_link(compiler, ws_asm_branch(compiler, stmt->last_line,
  895.                                                 WS_ASM_P_JUMP, l_end));
  896.             /* Then else-branch. */
  897.             ws_asm_link(compiler, l_else);
  898.             /* Linearize the else-branch if it is present. */
  899.             if (stmt->u.s_if.s_else)
  900.                 ws_stmt_linearize(compiler, stmt->u.s_if.s_else);
  901.             /* Insert the end label. */
  902.             ws_asm_link(compiler, l_end);
  903.         }
  904.         break;
  905.     case WS_STMT_FOR:
  906.         {
  907.             WsAsmIns *l_loop = ws_asm_label(compiler, stmt->first_line);
  908.             WsAsmIns *l_cont = ws_asm_label(compiler, stmt->first_line);
  909.             WsAsmIns *l_break = ws_asm_label(compiler, stmt->first_line);
  910.             WsContBreak *cb;
  911.             /* Store the labels to the compiler. */
  912.             cb = ws_f_calloc(compiler->pool_stree, 1, sizeof(*cb));
  913.             if (cb == NULL) {
  914.                 ws_error_memory(compiler);
  915.                 return;
  916.             }
  917.             cb->next = compiler->cont_break;
  918.             compiler->cont_break = cb;
  919.             cb->l_cont = l_cont;
  920.             cb->l_break = l_break;
  921.             /* Linearize the possible init code. */
  922.             if (stmt->u.s_for.init)
  923.                 linearize_variable_init(compiler, stmt->u.s_for.init,
  924.                                         stmt->first_line);
  925.             else if (stmt->u.s_for.e1) {
  926.                 /* Linearize the init. */
  927.                 ws_expr_linearize(compiler, stmt->u.s_for.e1);
  928.                 /* Pop the result. */
  929.                 ws_asm_link(compiler, ws_asm_ins(compiler, stmt->first_line,
  930.                                                  WS_ASM_POP));
  931.             }
  932.             /* Insert the loop label. */
  933.             ws_asm_link(compiler, l_loop);
  934.             /* Linearize the condition. */
  935.             if (stmt->u.s_for.e2) {
  936.                 ws_expr_linearize(compiler, stmt->u.s_for.e2);
  937.                 /* If false, jump out. */
  938.                 ws_asm_link(compiler, ws_asm_branch(compiler, stmt->first_line,
  939.                                                     WS_ASM_P_TJUMP, l_break));
  940.             }
  941.             /* Linearize the body statement. */
  942.             ws_stmt_linearize(compiler, stmt->u.s_for.stmt);
  943.             /* Link the continue label. */
  944.             ws_asm_link(compiler, l_cont);
  945.             /* Linearize the update expression. */
  946.             if (stmt->u.s_for.e3) {
  947.                 ws_expr_linearize(compiler, stmt->u.s_for.e3);
  948.                 /* Pop the result. */
  949.                 ws_asm_link(compiler, ws_asm_ins(compiler, stmt->first_line,
  950.                                                  WS_ASM_POP));
  951.             }
  952.             /* Jump to the loop label to check the condition. */
  953.             ws_asm_link(compiler, ws_asm_branch(compiler, stmt->last_line,
  954.                                                 WS_ASM_P_JUMP, l_loop));
  955.             /* Insert the break label. */
  956.             ws_asm_link(compiler, l_break);
  957.             /* Pop the cont-break block. */
  958.             compiler->cont_break = compiler->cont_break->next;
  959.         }
  960.         break;
  961.     case WS_STMT_WHILE:
  962.         {
  963.             WsAsmIns *l_cont = ws_asm_label(compiler, stmt->first_line);
  964.             WsAsmIns *l_break = ws_asm_label(compiler,
  965.                                              stmt->u.s_while.stmt->last_line);
  966.             WsContBreak *cb;
  967.             /* Store the labels to the compiler. */
  968.             cb = ws_f_calloc(compiler->pool_stree, 1, sizeof(*cb));
  969.             if (cb == NULL) {
  970.                 ws_error_memory(compiler);
  971.                 return;
  972.             }
  973.             cb->next = compiler->cont_break;
  974.             compiler->cont_break = cb;
  975.             cb->l_cont = l_cont;
  976.             cb->l_break = l_break;
  977.             /* Insert the continue label. */
  978.             ws_asm_link(compiler, l_cont);
  979.             /* Linearize the expression. */
  980.             ws_expr_linearize(compiler, stmt->u.s_while.expr);
  981.             /* If false, jump out. */
  982.             ws_asm_link(compiler, ws_asm_branch(compiler, stmt->first_line,
  983.                                                 WS_ASM_P_TJUMP, l_break));
  984.             /* Linearize the body statement. */
  985.             ws_stmt_linearize(compiler, stmt->u.s_while.stmt);
  986.             /* And jump to the continue label to check the expression. */
  987.             ws_asm_link(compiler, ws_asm_branch(compiler, stmt->last_line,
  988.                                                 WS_ASM_P_JUMP, l_cont));
  989.             /* Insert the break label. */
  990.             ws_asm_link(compiler, l_break);
  991.             /* Pop the cont-break block. */
  992.             compiler->cont_break = compiler->cont_break->next;
  993.         }
  994.         break;
  995.     case WS_STMT_CONTINUE:
  996.         if (compiler->cont_break == NULL)
  997.             ws_src_error(compiler, stmt->first_line,
  998.                          "continue statement not within a loop");
  999.         ws_asm_link(compiler, ws_asm_branch(compiler, stmt->first_line,
  1000.                                             WS_ASM_P_JUMP,
  1001.                                             compiler->cont_break->l_cont));
  1002.         break;
  1003.     case WS_STMT_BREAK:
  1004.         if (compiler->cont_break == NULL)
  1005.             ws_src_error(compiler, stmt->first_line,
  1006.                          "break statement not within a loop");
  1007.         ws_asm_link(compiler, ws_asm_branch(compiler, stmt->first_line,
  1008.                                             WS_ASM_P_JUMP,
  1009.                                             compiler->cont_break->l_break));
  1010.         break;
  1011.     case WS_STMT_RETURN:
  1012.         if (stmt->u.expr) {
  1013.             /* Linearize the return value and return it. */
  1014.             ws_expr_linearize(compiler, stmt->u.expr);
  1015.             ins = ws_asm_ins(compiler, stmt->first_line, WS_ASM_RETURN);
  1016.         } else
  1017.             /* Return an empty string. */
  1018.             ins = ws_asm_ins(compiler, stmt->first_line, WS_ASM_RETURN_ES);
  1019.         ws_asm_link(compiler, ins);
  1020.         break;
  1021.     }
  1022. }
  1023. /* Constructors. */
  1024. static WsStatement *stmt_alloc(WsCompiler *compiler, WsStatementType type,
  1025.                                WsUInt32 first_line, WsUInt32 last_line)
  1026. {
  1027.     WsStatement *stmt = ws_f_calloc(compiler->pool_stree, 1, sizeof(*stmt));
  1028.     if (stmt == NULL)
  1029.         ws_error_memory(compiler);
  1030.     else {
  1031.         stmt->type = type;
  1032.         stmt->first_line = first_line;
  1033.         stmt->last_line = last_line;
  1034.     }
  1035.     return stmt;
  1036. }
  1037. WsStatement *ws_stmt_block(WsCompiler *compiler, WsUInt32 fline,
  1038.                            WsUInt32 lline, WsList *block)
  1039. {
  1040.     WsStatement *stmt = stmt_alloc(compiler, WS_STMT_BLOCK, fline, lline);
  1041.     if (stmt)
  1042.         stmt->u.block = block;
  1043.     return stmt;
  1044. }
  1045. WsStatement *ws_stmt_variable(WsCompilerPtr compiler, WsUInt32 line,
  1046.                               WsList *variables)
  1047. {
  1048.     WsStatement *stmt = stmt_alloc(compiler, WS_STMT_VARIABLE, line, line);
  1049.     if (stmt)
  1050.         stmt->u.var = variables;
  1051.     return stmt;
  1052. }
  1053. WsStatement *ws_stmt_empty(WsCompiler *compiler, WsUInt32 line)
  1054. {
  1055.     return stmt_alloc(compiler, WS_STMT_EMPTY, line, line);
  1056. }
  1057. WsStatement *ws_stmt_expr(WsCompiler *compiler, WsUInt32 line,
  1058.                           WsExpression *expr)
  1059. {
  1060.     WsStatement *stmt = stmt_alloc(compiler, WS_STMT_EXPR, line, line);
  1061.     if (stmt)
  1062.         stmt->u.expr = expr;
  1063.     return stmt;
  1064. }
  1065. WsStatement *ws_stmt_if(WsCompiler *compiler, WsUInt32 line,
  1066.                         WsExpression *expr, WsStatement *s_then,
  1067.                         WsStatement *s_else)
  1068. {
  1069.     WsStatement *stmt = stmt_alloc(compiler, WS_STMT_IF, line, line);
  1070.     if (stmt) {
  1071.         stmt->u.s_if.expr = expr;
  1072.         stmt->u.s_if.s_then = s_then;
  1073.         stmt->u.s_if.s_else = s_else;
  1074.     }
  1075.     return stmt;
  1076. }
  1077. WsStatement *ws_stmt_for(WsCompilerPtr compiler, WsUInt32 line, WsList *init,
  1078.                          WsExpression *e1, WsExpression *e2, WsExpression *e3,
  1079.                          WsStatement *stmt_body)
  1080. {
  1081.     WsStatement *stmt = stmt_alloc(compiler, WS_STMT_FOR, line, line);
  1082.     if (stmt) {
  1083.         stmt->u.s_for.init = init;
  1084.         stmt->u.s_for.e1 = e1;
  1085.         stmt->u.s_for.e2 = e2;
  1086.         stmt->u.s_for.e3 = e3;
  1087.         stmt->u.s_for.stmt = stmt_body;
  1088.     }
  1089.     return stmt;
  1090. }
  1091. WsStatement *ws_stmt_while(WsCompiler *compiler, WsUInt32 line,
  1092.                            WsExpression *expr, WsStatement *stmt_arg)
  1093. {
  1094.     WsStatement *stmt = stmt_alloc(compiler, WS_STMT_WHILE, line, line);
  1095.     if (stmt) {
  1096.         stmt->u.s_while.expr = expr;
  1097.         stmt->u.s_while.stmt = stmt_arg;
  1098.     }
  1099.     return stmt;
  1100. }
  1101. WsStatement *ws_stmt_continue(WsCompiler *compiler, WsUInt32 line)
  1102. {
  1103.     return stmt_alloc(compiler, WS_STMT_CONTINUE, line, line);
  1104. }
  1105. WsStatement *ws_stmt_break(WsCompiler *compiler, WsUInt32 line)
  1106. {
  1107.     return stmt_alloc(compiler, WS_STMT_BREAK, line, line);
  1108. }
  1109. WsStatement *ws_stmt_return(WsCompilerPtr compiler, WsUInt32 line,
  1110.                             WsExpression *expr)
  1111. {
  1112.     WsStatement *stmt = stmt_alloc(compiler, WS_STMT_RETURN, line, line);
  1113.     if (stmt)
  1114.         stmt->u.expr = expr;
  1115.     return stmt;
  1116. }