Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

wsstree.c

Go to the documentation of this file.
00001 /* ==================================================================== 
00002  * The Kannel Software License, Version 1.0 
00003  * 
00004  * Copyright (c) 2001-2008 Kannel Group  
00005  * Copyright (c) 1998-2001 WapIT Ltd.   
00006  * All rights reserved. 
00007  * 
00008  * Redistribution and use in source and binary forms, with or without 
00009  * modification, are permitted provided that the following conditions 
00010  * are met: 
00011  * 
00012  * 1. Redistributions of source code must retain the above copyright 
00013  *    notice, this list of conditions and the following disclaimer. 
00014  * 
00015  * 2. Redistributions in binary form must reproduce the above copyright 
00016  *    notice, this list of conditions and the following disclaimer in 
00017  *    the documentation and/or other materials provided with the 
00018  *    distribution. 
00019  * 
00020  * 3. The end-user documentation included with the redistribution, 
00021  *    if any, must include the following acknowledgment: 
00022  *       "This product includes software developed by the 
00023  *        Kannel Group (http://www.kannel.org/)." 
00024  *    Alternately, this acknowledgment may appear in the software itself, 
00025  *    if and wherever such third-party acknowledgments normally appear. 
00026  * 
00027  * 4. The names "Kannel" and "Kannel Group" must not be used to 
00028  *    endorse or promote products derived from this software without 
00029  *    prior written permission. For written permission, please  
00030  *    contact org@kannel.org. 
00031  * 
00032  * 5. Products derived from this software may not be called "Kannel", 
00033  *    nor may "Kannel" appear in their name, without prior written 
00034  *    permission of the Kannel Group. 
00035  * 
00036  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 
00037  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
00038  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
00039  * DISCLAIMED.  IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS 
00040  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,  
00041  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  
00042  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR  
00043  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
00044  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE  
00045  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  
00046  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
00047  * ==================================================================== 
00048  * 
00049  * This software consists of voluntary contributions made by many 
00050  * individuals on behalf of the Kannel Group.  For more information on  
00051  * the Kannel Group, please see <http://www.kannel.org/>. 
00052  * 
00053  * Portions of this software are based upon software originally written at  
00054  * WapIT Ltd., Helsinki, Finland for the Kannel project.  
00055  */ 
00056 
00057 /*
00058  *
00059  * wsstree.c
00060  *
00061  * Author: Markku Rossi <mtr@iki.fi>
00062  *
00063  * Copyright (c) 1999-2000 WAPIT OY LTD.
00064  *       All rights reserved.
00065  *
00066  * Syntax tree creation, manipulation and byte-code assembler
00067  * generation.
00068  *
00069  */
00070 
00071 #include "wsint.h"
00072 #include "wsgram.h"
00073 
00074 /* TODO: Constant folding. */
00075 
00076 /********************* Misc syntax tree structures **********************/
00077 
00078 WsVarDec *ws_variable_declaration(WsCompilerPtr compiler,
00079                                   char *name, WsExpression *expr)
00080 {
00081     WsVarDec *vardec = ws_f_malloc(compiler->pool_stree, sizeof(*vardec));
00082 
00083     if (vardec == NULL)
00084         ws_error_memory(compiler);
00085     else {
00086         vardec->name = name;
00087         vardec->expr = expr;
00088     }
00089 
00090     return vardec;
00091 }
00092 
00093 WsFormalParm *ws_formal_parameter(WsCompilerPtr compiler,
00094                                   WsUInt32 line, char *name)
00095 {
00096     WsFormalParm *parm = ws_f_malloc(compiler->pool_stree, sizeof(*parm));
00097 
00098     if (parm == NULL)
00099         ws_error_memory(compiler);
00100     else {
00101         parm->line = line;
00102         parm->name = name;
00103     }
00104 
00105     return parm;
00106 }
00107 
00108 /********************* Linked list **************************************/
00109 
00110 WsList *ws_list_new(WsCompiler *compiler)
00111 {
00112     WsList *list = ws_f_calloc(compiler->pool_stree, 1, sizeof(*list));
00113 
00114     if (list == NULL)
00115         ws_error_memory(compiler);
00116 
00117     return list;
00118 }
00119 
00120 
00121 void ws_list_append(WsCompiler *compiler, WsList *list, void *value)
00122 {
00123     WsListItem *item;
00124 
00125     if (list == NULL)
00126         /* A recovery code for previous memory allocation problems. */
00127         return;
00128 
00129     item = ws_f_calloc(compiler->pool_stree, 1, sizeof(*item));
00130     if (item == NULL) {
00131         ws_error_memory(compiler);
00132         return;
00133     }
00134 
00135     item->data = value;
00136 
00137     if (list->tail) {
00138         list->tail->next = item;
00139         list->tail = item;
00140     } else
00141         list->head = list->tail = item;
00142 
00143     list->num_items++;
00144 }
00145 
00146 /********************* Namespace for arguments and locals ***************/
00147 
00148 static void variable_hash_destructor(void *item, void *context)
00149 {
00150     ws_free(item);
00151 }
00152 
00153 
00154 WsHashPtr ws_variable_hash_create(void)
00155 {
00156     return ws_hash_create(variable_hash_destructor, NULL);
00157 }
00158 
00159 
00160 WsNamespace *ws_variable_define(WsCompilerPtr compiler, WsUInt32 line,
00161                                 WsBool variablep, char *name)
00162 {
00163     WsNamespace *ns;
00164 
00165     /* Is the symbol already defined? */
00166     ns = ws_hash_get(compiler->variables_hash, name);
00167     if (ns) {
00168         ws_src_error(compiler, line, "redeclaration of `%s'", name);
00169         ws_src_error(compiler, ns->line, "`%s' previously declared here", name);
00170         return NULL;
00171     }
00172 
00173     /* Can we still define more variables? */
00174     if (compiler->next_vindex > 255) {
00175         /* No we can't. */
00176         ws_src_error(compiler, line, "too many local variables");
00177         return NULL;
00178     }
00179 
00180     ns = ws_calloc(1, sizeof(*ns));
00181     if (ns == NULL) {
00182         ws_error_memory(compiler);
00183         return NULL;
00184     }
00185 
00186     ns->line = line;
00187     ns->vindex = compiler->next_vindex++;
00188 
00189     if (!ws_hash_put(compiler->variables_hash, name, ns)) {
00190         ws_free(ns);
00191         ws_error_memory(compiler);
00192         return NULL;
00193     }
00194 
00195     return ns;
00196 }
00197 
00198 
00199 WsNamespace *ws_variable_lookup(WsCompilerPtr compiler, char *name)
00200 {
00201     return ws_hash_get(compiler->variables_hash, name);
00202 }
00203 
00204 /********************* Top-level declarations ***************************/
00205 
00206 /* External compilation units. */
00207 
00208 static void pragma_use_hash_destructor(void *item, void *context)
00209 {
00210     ws_free(item);
00211 }
00212 
00213 
00214 WsHashPtr ws_pragma_use_hash_create(void)
00215 {
00216     return ws_hash_create(pragma_use_hash_destructor, NULL);
00217 }
00218 
00219 
00220 void ws_pragma_use(WsCompilerPtr compiler, WsUInt32 line, char *identifier,
00221                    WsUtf8String *url)
00222 {
00223     WsPragmaUse *u = ws_calloc(1, sizeof(*u));
00224     WsPragmaUse *uold;
00225 
00226     /* Do we already know this pragma? */
00227     uold = ws_hash_get(compiler->pragma_use_hash, identifier);
00228     if (uold) {
00229         ws_src_error(compiler, line, "redefinition of pragma `%s'", identifier);
00230         ws_src_error(compiler, uold->line, "`%s' previously defined here",
00231                      identifier);
00232         goto error_cleanup;
00233     }
00234 
00235     if (u == NULL)
00236         goto error;
00237 
00238     u->line = line;
00239 
00240     /* Insert the URL to the byte-code module. */
00241     if (!ws_bc_add_const_utf8_string(compiler->bc, &u->urlindex, url->data,
00242                                      url->len))
00243         goto error;
00244 
00245     /* Add it to the use pragma hash. */
00246     if (!ws_hash_put(compiler->pragma_use_hash, identifier, u))
00247         goto error;
00248 
00249     /* Cleanup. */
00250 
00251     ws_lexer_free_block(compiler, identifier);
00252     ws_lexer_free_utf8(compiler, url);
00253 
00254     return;
00255 
00256     /* Error handling. */
00257 
00258 error:
00259 
00260     ws_error_memory(compiler);
00261 
00262 error_cleanup:
00263 
00264     ws_free(u);
00265     ws_lexer_free_block(compiler, identifier);
00266     ws_lexer_free_utf8(compiler, url);
00267 }
00268 
00269 /* MetaBody of the `use meta' pragmas. */
00270 
00271 WsPragmaMetaBody *ws_pragma_meta_body(WsCompilerPtr compiler,
00272                                       WsUtf8String *property_name,
00273                                       WsUtf8String *content,
00274                                       WsUtf8String *scheme)
00275 {
00276     WsPragmaMetaBody *mb = ws_calloc(1, sizeof(*mb));
00277 
00278     if (mb == NULL) {
00279         ws_error_memory(compiler);
00280         return NULL;
00281     }
00282 
00283     mb->property_name = property_name;
00284     mb->content = content;
00285     mb->scheme = scheme;
00286 
00287     return mb;
00288 }
00289 
00290 
00291 void ws_pragma_meta_body_free(WsCompilerPtr compiler, WsPragmaMetaBody *mb)
00292 {
00293     if (mb == NULL)
00294         return;
00295 
00296     ws_lexer_free_utf8(compiler, mb->property_name);
00297     ws_lexer_free_utf8(compiler, mb->content);
00298     ws_lexer_free_utf8(compiler, mb->scheme);
00299 
00300     ws_free(mb);
00301 }
00302 
00303 
00304 /* Functions. */
00305 
00306 static void function_hash_destructor(void *item, void *context)
00307 {
00308     ws_free(item);
00309 }
00310 
00311 
00312 WsHashPtr ws_function_hash_create(void)
00313 {
00314     return ws_hash_create(function_hash_destructor, NULL);
00315 }
00316 
00317 
00318 WsFunctionHash *ws_function_hash(WsCompilerPtr compiler, char *name)
00319 {
00320     WsFunctionHash *i = ws_hash_get(compiler->functions_hash, name);
00321 
00322     if (i)
00323         return i;
00324 
00325     /* Must create a new mapping. */
00326 
00327     i = ws_calloc(1, sizeof(*i));
00328     if (i == NULL) {
00329         ws_error_memory(compiler);
00330         return NULL;
00331     }
00332 
00333     if (!ws_hash_put(compiler->functions_hash, name, i)) {
00334         ws_free(i);
00335         ws_error_memory(compiler);
00336         return NULL;
00337     }
00338 
00339     return i;
00340 }
00341 
00342 
00343 void ws_function(WsCompiler *compiler, WsBool externp, char *name,
00344                  WsUInt32 line, WsList *params, WsList *block)
00345 {
00346     WsFunctionHash *hash;
00347     WsFunction *f = ws_realloc(compiler->functions,
00348                                ((compiler->num_functions + 1)
00349                                 * sizeof(WsFunction)));
00350 
00351     if (f == NULL) {
00352         ws_free(name);
00353         ws_error_memory(compiler);
00354         return;
00355     }
00356 
00357     if (externp)
00358         compiler->num_extern_functions++;
00359     else
00360         compiler->num_local_functions++;
00361 
00362     compiler->functions = f;
00363     f = &compiler->functions[compiler->num_functions];
00364 
00365     f->findex = compiler->num_functions++;
00366 
00367     f->externp = externp;
00368     f->name = name;
00369     f->line = line;
00370     f->params = params;
00371     f->block = block;
00372 
00373     /* Update the function name hash. */
00374 
00375     hash = ws_function_hash(compiler, name);
00376     if (hash == NULL) {
00377         ws_error_memory(compiler);
00378         return;
00379     }
00380 
00381     if (hash->defined) {
00382         ws_src_error(compiler, line, "redefinition of `%s'", name);
00383         ws_src_error(compiler,
00384                      compiler->functions[hash->findex].line,
00385                      "`%s' previously defined here", name);
00386         return;
00387     }
00388 
00389     hash->defined = WS_TRUE;
00390     hash->findex = f->findex;
00391 }
00392 
00393 /********************* Expressions **************************************/
00394 
00395 void ws_expr_linearize(WsCompiler *compiler, WsExpression *expr)
00396 {
00397     WsListItem *li;
00398     WsAsmIns *ins;
00399 
00400     switch (expr->type) {
00401     case WS_EXPR_COMMA:
00402         /* Linearize left. */
00403         ws_expr_linearize(compiler, expr->u.comma.left);
00404 
00405         /* Pop its result. */
00406         ws_asm_link(compiler, ws_asm_ins(compiler, expr->line, WS_ASM_POP));
00407 
00408         /* Linearize right */
00409         ws_expr_linearize(compiler, expr->u.comma.right);
00410         break;
00411 
00412     case WS_EXPR_ASSIGN:
00413         {
00414             WsNamespace *ns = ws_variable_lookup(compiler,
00415                                                  expr->u.assign.identifier);
00416 
00417             if (ns == NULL) {
00418                 /* Unknown identifier. */
00419                 ws_src_error(compiler, expr->line, "unknown variable `%s'",
00420                              expr->u.symbol);
00421                 return;
00422             }
00423 
00424             if (expr->u.assign.op == '=') {
00425                 /* Evaluate the expression. */
00426                 ws_expr_linearize(compiler, expr->u.assign.expr);
00427 
00428                 /* Store the value to the variable. */
00429                 ws_asm_link(compiler,
00430                             ws_asm_variable(compiler, expr->line,
00431                                             WS_ASM_P_STORE_VAR, ns->vindex));
00432             } else if (expr->u.assign.op == tADDA) {
00433                 /* Linearize the expression. */
00434                 ws_expr_linearize(compiler, expr->u.assign.expr);
00435 
00436                 /* Add it to the variable. */
00437                 ws_asm_link(compiler,
00438                             ws_asm_variable(compiler, expr->line,
00439                                             WS_ASM_ADD_ASG, ns->vindex));
00440             } else if (expr->u.assign.op == tSUBA) {
00441                 /* Linearize the expression. */
00442                 ws_expr_linearize(compiler, expr->u.assign.expr);
00443 
00444                 /* Substract it from the variable. */
00445                 ws_asm_link(compiler,
00446                             ws_asm_variable(compiler, expr->line,
00447                                             WS_ASM_SUB_ASG, ns->vindex));
00448             } else {
00449                 /* Load the old value from the variable. */
00450                 ws_asm_link(compiler,
00451                             ws_asm_variable(compiler, expr->line,
00452                                             WS_ASM_P_LOAD_VAR, ns->vindex));
00453 
00454                 /* Evaluate the expression. */
00455                 ws_expr_linearize(compiler, expr->u.assign.expr);
00456 
00457                 /* Perform the operand. */
00458                 ins = NULL;
00459                 switch (expr->u.assign.op) {
00460                 case tMULA:
00461                     ins = ws_asm_ins(compiler, expr->line, WS_ASM_MUL);
00462                     break;
00463 
00464                 case tDIVA:
00465                     ins = ws_asm_ins(compiler, expr->line, WS_ASM_DIV);
00466                     break;
00467 
00468                 case tREMA:
00469                     ins = ws_asm_ins(compiler, expr->line, WS_ASM_REM);
00470                     break;
00471 
00472                 case tADDA:
00473                     ins = ws_asm_ins(compiler, expr->line, WS_ASM_ADD);
00474                     break;
00475 
00476                 case tSUBA:
00477                     ins = ws_asm_ins(compiler, expr->line, WS_ASM_SUB);
00478                     break;
00479 
00480                 case tLSHIFTA:
00481                     ins = ws_asm_ins(compiler, expr->line, WS_ASM_B_LSHIFT);
00482                     break;
00483 
00484                 case tRSSHIFTA:
00485                     ins = ws_asm_ins(compiler, expr->line, WS_ASM_B_RSSHIFT);
00486                     break;
00487 
00488                 case tRSZSHIFTA:
00489                     ins = ws_asm_ins(compiler, expr->line, WS_ASM_B_RSZSHIFT);
00490                     break;
00491 
00492                 case tANDA:
00493                     ins = ws_asm_ins(compiler, expr->line, WS_ASM_B_AND);
00494                     break;
00495 
00496                 case tXORA:
00497                     ins = ws_asm_ins(compiler, expr->line, WS_ASM_B_XOR);
00498                     break;
00499 
00500                 case tORA:
00501                     ins = ws_asm_ins(compiler, expr->line, WS_ASM_B_OR);
00502                     break;
00503 
00504                 case tIDIVA:
00505                     ins = ws_asm_ins(compiler, expr->line, WS_ASM_IDIV);
00506                     break;
00507 
00508                 default:
00509                     ws_fatal("ws_expr_linearize(): unknown assignment operand %x",
00510                              expr->u.assign.op);
00511                     break;
00512                 }
00513                 ws_asm_link(compiler, ins);
00514 
00515                 /* Store the value to the variable. */
00516                 ws_asm_link(compiler,
00517                             ws_asm_variable(compiler, expr->line,
00518                                             WS_ASM_P_STORE_VAR, ns->vindex));
00519             }
00520             /* The value of the assignment expression is the value
00521                assigned.  So, we must load the value from the variable.
00522                This would also be a good place for the `dup' operand but
00523                we lose since we don't have it. */
00524             ws_asm_link(compiler, ws_asm_variable(compiler, expr->line,
00525                                                   WS_ASM_P_LOAD_VAR, ns->vindex));
00526         }
00527         break;
00528 
00529     case WS_EXPR_CONDITIONAL:
00530         {
00531             WsAsmIns *l_else = ws_asm_label(compiler, expr->line);
00532             WsAsmIns *l_end = ws_asm_label(compiler, expr->line);
00533 
00534             /* Linearize condition. */
00535             ws_expr_linearize(compiler, expr->u.conditional.e_cond);
00536 
00537             /* If the result if false, jump to the else-branch. */
00538             ws_asm_link(compiler, ws_asm_branch(compiler, expr->line,
00539                                                 WS_ASM_P_TJUMP, l_else));
00540 
00541             /* Linearize the then-expression and jump out. */
00542             ws_expr_linearize(compiler, expr->u.conditional.e_then);
00543             ws_asm_link(compiler, ws_asm_branch(compiler, expr->line,
00544                                                 WS_ASM_P_JUMP, l_end));
00545 
00546             /* The else-branch. */
00547             ws_asm_link(compiler, l_else);
00548             ws_expr_linearize(compiler, expr->u.conditional.e_else);
00549 
00550             /* Insert the end label. */
00551             ws_asm_link(compiler, l_end);
00552         }
00553         break;
00554 
00555     case WS_EXPR_LOGICAL:
00556         {
00557             WsAsmIns *l_out = ws_asm_label(compiler, expr->line);
00558 
00559             /* Linearize the left-hand size expression. */
00560             ws_expr_linearize(compiler, expr->u.logical.left);
00561 
00562             /* Short-circuit check.  The type of the logical expression is
00563                       the short-circuit byte-code operand. */
00564             ws_asm_link(compiler, ws_asm_ins(compiler, expr->line,
00565                                              expr->u.logical.type));
00566             ws_asm_link(compiler, ws_asm_branch(compiler, expr->line,
00567                                                 WS_ASM_P_TJUMP, l_out));
00568 
00569             /* Linearize the right-hand size expression. */
00570             ws_expr_linearize(compiler, expr->u.logical.right);
00571 
00572             /* The result of a logical expression should be boolean.
00573              * Control statements do automatic conversion, but typeof()
00574          * does not. */
00575             ws_asm_link(compiler, ws_asm_ins(compiler, expr->line,
00576                                          WS_ASM_TOBOOL));
00577 
00578             /* Insert the end label. */
00579             ws_asm_link(compiler, l_out);
00580         }
00581         break;
00582 
00583     case WS_EXPR_BINARY:
00584         /* Linearize left and right. */
00585         ws_expr_linearize(compiler, expr->u.binary.left);
00586         ws_expr_linearize(compiler, expr->u.binary.right);
00587 
00588         /* The type of the binary expression is the byte-code opcode. */
00589         ws_asm_link(compiler, ws_asm_ins(compiler, expr->line,
00590                                          expr->u.binary.type));
00591         break;
00592 
00593     case WS_EXPR_UNARY:
00594         /* Linearize the expression. */
00595         ws_expr_linearize(compiler, expr->u.unary.expr);
00596 
00597         /* The type of the unary expression is the byte-code opcode. */
00598         ws_asm_link(compiler, ws_asm_ins(compiler, expr->line,
00599                                          expr->u.unary.type));
00600         break;
00601 
00602     case WS_EXPR_UNARY_VAR:
00603         {
00604             WsNamespace *ns = ws_variable_lookup(compiler,
00605                                                  expr->u.unary_var.variable);
00606             if (ns == NULL) {
00607                 /* An unknown identifier. */
00608                 ws_src_error(compiler, expr->line, "unknown variable `%s'",
00609                              expr->u.unary_var.variable);
00610                 return;
00611             }
00612 
00613             /* First, do the operation. */
00614             if (expr->u.unary_var.addp)
00615                 ws_asm_link(compiler,
00616                             ws_asm_variable(compiler, expr->line, WS_ASM_P_INCR_VAR,
00617                                             ns->vindex));
00618             else
00619                 ws_asm_link(compiler,
00620                             ws_asm_variable(compiler, expr->line, WS_ASM_DECR_VAR,
00621                                             ns->vindex));
00622 
00623             /* Second, load the new value of the variable. */
00624             ws_asm_link(compiler, ws_asm_variable(compiler, expr->line,
00625                                                   WS_ASM_P_LOAD_VAR, ns->vindex));
00626         }
00627         break;
00628 
00629     case WS_EXPR_POSTFIX_VAR:
00630         {
00631             WsNamespace *ns = ws_variable_lookup(compiler,
00632                                                  expr->u.postfix_var.variable);
00633             if (ns == NULL) {
00634                 /* An unknown identifier. */
00635                 ws_src_error(compiler, expr->line, "unknown variable `%s'",
00636                              expr->u.postfix_var.variable);
00637                 return;
00638             }
00639 
00640             /* First, load the old value of the variable. */
00641             ws_asm_link(compiler, ws_asm_variable(compiler, expr->line,
00642                                                   WS_ASM_P_LOAD_VAR, ns->vindex));
00643 
00644             /* Second, do the operation. */
00645             if (expr->u.unary_var.addp)
00646                 ws_asm_link(compiler,
00647                             ws_asm_variable(compiler, expr->line, WS_ASM_P_INCR_VAR,
00648                                             ns->vindex));
00649             else
00650                 ws_asm_link(compiler,
00651                             ws_asm_variable(compiler, expr->line, WS_ASM_DECR_VAR,
00652                                             ns->vindex));
00653         }
00654         break;
00655 
00656     case WS_EXPR_CALL:
00657         /* First, evaluate the arguments. */
00658         for (li = expr->u.call.arguments->head; li; li = li->next)
00659             ws_expr_linearize(compiler, li->data);
00660 
00661         /* Second, emit the call instruction. */
00662         switch (expr->u.call.type) {
00663         case ' ':       /* LocalScriptFunctionCall */
00664             {
00665                 WsFunctionHash *f = ws_function_hash(compiler, expr->u.call.name);
00666 
00667                 if (f == NULL || !f->defined)
00668                 {
00669                     ws_src_error(compiler, expr->line,
00670                                  "unknown local function `%s'",
00671                                  expr->u.call.name);
00672                     return;
00673                 }
00674 
00675                 /* Check that the function is called with correct amount
00676                           of arguments. */
00677                 if (expr->u.call.arguments->num_items
00678                     != compiler->functions[f->findex].params->num_items)
00679                 {
00680                     ws_src_error(compiler, expr->line,
00681                                  "invalid amount of arguments for `%s': "
00682                                  "expected %u, got %u",
00683                                  expr->u.call.name,
00684                                  compiler->functions[f->findex].params->num_items,
00685                                  expr->u.call.arguments->num_items);
00686                     return;
00687                 }
00688 
00689                 /* Emit assembler. */
00690                 ws_asm_link(compiler, ws_asm_call(compiler, expr->line,
00691                                                   f->findex));
00692             }
00693             break;
00694 
00695         case '#':       /* ExternalScriptFunctionCall */
00696             {
00697                 WsPragmaUse *use = ws_hash_get(compiler->pragma_use_hash,
00698                                                expr->u.call.base);
00699                 WsUInt16 findex;
00700 
00701                 if (use == NULL)
00702                 {
00703                     ws_src_error(compiler, expr->line,
00704                                  "unknown external compilation unit `%s'",
00705                                  expr->u.call.base);
00706                     return;
00707                 }
00708 
00709                 /* Insert the function name to the byte-code pool. */
00710                 if (!ws_bc_add_const_utf8_string(
00711                         compiler->bc, &findex,
00712                         (unsigned char *) expr->u.call.name,
00713                         strlen(expr->u.call.name)))
00714                 {
00715                     ws_error_memory(compiler);
00716                     return;
00717                 }
00718 
00719                 /* Emit assembler. */
00720                 ws_asm_link(compiler,
00721                             ws_asm_call_url(compiler, expr->line,
00722                                             findex, use->urlindex,
00723                                             expr->u.call.arguments->num_items));
00724             }
00725             break;
00726 
00727         case '.':       /* LibraryFunctionCall */
00728             {
00729                 WsUInt16 lindex;
00730                 WsUInt8 findex;
00731                 WsUInt8 num_args;
00732                 WsBool lindex_found;
00733                 WsBool findex_found;
00734 
00735                 if (!ws_stdlib_function(expr->u.call.base, expr->u.call.name,
00736                                         &lindex, &findex, &num_args,
00737                                         &lindex_found, &findex_found))
00738                 {
00739                     if (!lindex_found)
00740                         ws_src_error(compiler, expr->line,
00741                                      "unknown system library `%s'",
00742                                      expr->u.call.base);
00743                     else
00744                         ws_src_error(compiler, expr->line,
00745                                      "unknown library function `%s.%s'",
00746                                      expr->u.call.base, expr->u.call.name);
00747 
00748                     return;
00749                 }
00750                 /* Check the argument count. */
00751                 if (expr->u.call.arguments->num_items != num_args)
00752                 {
00753                     ws_src_error(compiler, expr->line,
00754                                  "invalid amount of arguments for `%s.%s': "
00755                                  "expected %u, got %u",
00756                                  expr->u.call.base, expr->u.call.name,
00757                                  num_args, expr->u.call.arguments->num_items);
00758                     return;
00759                 }
00760 
00761                 /* Emit assembler. */
00762                 ws_asm_link(compiler, ws_asm_call_lib(compiler, expr->line, findex,
00763                                                       lindex));
00764             }
00765             break;
00766 
00767         default:
00768             ws_fatal("ws_expr_linearize(): unknown call expression type %x",
00769                      expr->u.call.type);
00770             break;
00771         }
00772         break;
00773 
00774     case WS_EXPR_SYMBOL:
00775         {
00776             WsNamespace *ns = ws_variable_lookup(compiler, expr->u.symbol);
00777 
00778             if (ns == NULL) {
00779                 /* An unknown identifier. */
00780                 ws_src_error(compiler, expr->line, "unknown variable `%s'",
00781                              expr->u.symbol);
00782                 return;
00783             }
00784 
00785             /* Create a load instruction for the variable. */
00786             ws_asm_link(compiler, ws_asm_variable(compiler, expr->line,
00787                                                   WS_ASM_P_LOAD_VAR, ns->vindex));
00788         }
00789         break;
00790 
00791     case WS_EXPR_CONST_INVALID:
00792         ws_asm_link(compiler, ws_asm_ins(compiler, expr->line,
00793                                          WS_ASM_CONST_INVALID));
00794         break;
00795 
00796     case WS_EXPR_CONST_TRUE:
00797         ws_asm_link(compiler, ws_asm_ins(compiler, expr->line,
00798                                          WS_ASM_CONST_TRUE));
00799         break;
00800 
00801     case WS_EXPR_CONST_FALSE:
00802         ws_asm_link(compiler, ws_asm_ins(compiler, expr->line,
00803                                          WS_ASM_CONST_FALSE));
00804         break;
00805 
00806 
00807     case WS_EXPR_CONST_INTEGER:
00808         if (expr->u.integer.ival == 0)
00809             ins = ws_asm_ins(compiler, expr->line, WS_ASM_CONST_0);
00810         else if (expr->u.integer.ival == 1 && expr->u.integer.sign == 1)
00811             ins = ws_asm_ins(compiler, expr->line, WS_ASM_CONST_1);
00812         else {
00813             WsUInt16 cindex;
00814         WsInt32 ival;
00815 
00816             if (expr->u.integer.sign >= 0) {
00817         if (expr->u.integer.ival > (WsUInt32) WS_INT32_MAX)
00818             ws_src_error(compiler, expr->line,
00819                                  "integer literal too large");
00820                 ival = expr->u.integer.ival;
00821         } else {
00822                 if (expr->u.integer.ival > (WsUInt32) WS_INT32_MAX + 1)
00823             ws_src_error(compiler, expr->line, "integer too small");
00824                 ival = - (WsInt32) expr->u.integer.ival;
00825         }
00826 
00827             if (!ws_bc_add_const_int(compiler->bc, &cindex, ival)) {
00828                 ws_error_memory(compiler);
00829                 return;
00830             }
00831             ins = ws_asm_load_const(compiler, expr->line, cindex);
00832         }
00833 
00834         ws_asm_link(compiler, ins);
00835         break;
00836 
00837     case WS_EXPR_CONST_FLOAT:
00838         {
00839             WsUInt16 cindex;
00840 
00841             if (!ws_bc_add_const_float(compiler->bc, &cindex, expr->u.fval)) {
00842                 ws_error_memory(compiler);
00843                 return;
00844             }
00845 
00846             ws_asm_link(compiler, ws_asm_load_const(compiler, expr->line, cindex));
00847         }
00848         break;
00849 
00850     case WS_EXPR_CONST_STRING:
00851         if (expr->u.string.len == 0)
00852             ins = ws_asm_ins(compiler, expr->line, WS_ASM_CONST_ES);
00853         else {
00854             WsUInt16 cindex;
00855 
00856             if (!ws_bc_add_const_utf8_string(compiler->bc, &cindex,
00857                                              expr->u.string.data,
00858                                              expr->u.string.len)) {
00859                 ws_error_memory(compiler);
00860                 return;
00861             }
00862             ins = ws_asm_load_const(compiler, expr->line, cindex);
00863         }
00864 
00865         ws_asm_link(compiler, ins);
00866         break;
00867     }
00868 }
00869 
00870 
00871 /* Constructors. */
00872 
00873 static WsExpression *expr_alloc(WsCompiler *compiler,
00874                                 WsExpressionType type, WsUInt32 line)
00875 {
00876     WsExpression *expr = ws_f_calloc(compiler->pool_stree, 1, sizeof(*expr));
00877 
00878     if (expr == NULL)
00879         ws_error_memory(compiler);
00880     else {
00881         expr->type = type;
00882         expr->line = line;
00883     }
00884 
00885     return expr;
00886 }
00887 
00888 
00889 WsExpression *ws_expr_comma(WsCompilerPtr compiler, WsUInt32 line,
00890                             WsExpression *left, WsExpression *right)
00891 {
00892     WsExpression *expr = expr_alloc(compiler, WS_EXPR_COMMA, line);
00893 
00894     if (expr) {
00895         expr->u.comma.left = left;
00896         expr->u.comma.right = right;
00897     }
00898 
00899     return expr;
00900 }
00901 
00902 
00903 WsExpression *ws_expr_assign(WsCompilerPtr compiler, WsUInt32 line,
00904                              char *identifier, int op, WsExpression *expr)
00905 {
00906     WsExpression *e = expr_alloc(compiler, WS_EXPR_ASSIGN, line);
00907 
00908     if (e) {
00909         e->u.assign.identifier = ws_f_strdup(compiler->pool_stree, identifier);
00910         if (e->u.assign.identifier == NULL)
00911             ws_error_memory(compiler);
00912 
00913         e->u.assign.op = op;
00914         e->u.assign.expr = expr;
00915     }
00916 
00917     /* Free the identifier symbol since it allocated from the system
00918        heap. */
00919     ws_lexer_free_block(compiler, identifier);
00920 
00921     return e;
00922 }
00923 
00924 
00925 WsExpression *ws_expr_conditional(WsCompilerPtr compiler, WsUInt32 line,
00926                                   WsExpression *e_cond, WsExpression *e_then,
00927                                   WsExpression *e_else)
00928 {
00929     WsExpression *e = expr_alloc(compiler, WS_EXPR_CONDITIONAL, line);
00930 
00931     if (e) {
00932         e->u.conditional.e_cond = e_cond;
00933         e->u.conditional.e_then = e_then;
00934         e->u.conditional.e_else = e_else;
00935     }
00936 
00937     return e;
00938 }
00939 
00940 
00941 WsExpression *ws_expr_logical(WsCompilerPtr compiler, WsUInt32 line,
00942                               int type, WsExpression *left, WsExpression *right)
00943 {
00944     WsExpression *expr = expr_alloc(compiler, WS_EXPR_LOGICAL, line);
00945 
00946     if (expr) {
00947         expr->u.logical.type = type;
00948         expr->u.logical.left = left;
00949         expr->u.logical.right = right;
00950     }
00951 
00952     return expr;
00953 }
00954 
00955 
00956 WsExpression *ws_expr_binary(WsCompilerPtr compiler, WsUInt32 line,
00957                              int type, WsExpression *left, WsExpression *right)
00958 {
00959     WsExpression *expr = expr_alloc(compiler, WS_EXPR_BINARY, line);
00960 
00961     if (expr) {
00962         expr->u.binary.type = type;
00963         expr->u.binary.left = left;
00964         expr->u.binary.right = right;
00965     }
00966 
00967     return expr;
00968 }
00969 
00970 
00971 WsExpression *ws_expr_unary(WsCompilerPtr compiler, WsUInt32 line, int type,
00972                             WsExpression *expression)
00973 {
00974     WsExpression *expr;
00975 
00976     /* Handle negative integers here as a special case of constant folding,
00977      * in order to get -2147483648 right. */
00978     if (type == WS_ASM_UMINUS && expression->type == WS_EXPR_CONST_INTEGER) {
00979         expression->u.integer.sign = - expression->u.integer.sign;
00980         return expression;
00981     }
00982 
00983     expr = expr_alloc(compiler, WS_EXPR_UNARY, line);
00984     if (expr) {
00985         expr->u.unary.type = type;
00986         expr->u.unary.expr = expression;
00987     }
00988 
00989     return expr;
00990 }
00991 
00992 
00993 WsExpression *ws_expr_unary_var(WsCompilerPtr compiler, WsUInt32 line,
00994                                 WsBool addp, char *variable)
00995 {
00996     WsExpression *expr = expr_alloc(compiler, WS_EXPR_UNARY_VAR, line);
00997 
00998     if (expr) {
00999         expr->u.unary_var.addp = addp;
01000         expr->u.unary_var.variable = ws_f_strdup(compiler->pool_stree, variable);
01001         if (expr->u.unary_var.variable == NULL)
01002             ws_error_memory(compiler);
01003     }
01004     ws_lexer_free_block(compiler, variable);
01005 
01006     return expr;
01007 }
01008 
01009 
01010 WsExpression *ws_expr_postfix_var(WsCompilerPtr compiler, WsUInt32 line,
01011                                   WsBool addp, char *variable)
01012 {
01013     WsExpression *expr = expr_alloc(compiler, WS_EXPR_POSTFIX_VAR, line);
01014 
01015     if (expr) {
01016         expr->u.postfix_var.addp = addp;
01017         expr->u.postfix_var.variable = ws_f_strdup(compiler->pool_stree,
01018                                        variable);
01019         if (expr->u.postfix_var.variable == NULL)
01020             ws_error_memory(compiler);
01021     }
01022     ws_lexer_free_block(compiler, variable);
01023 
01024     return expr;
01025 }
01026 
01027 
01028 WsExpression *ws_expr_call(WsCompiler *compiler, WsUInt32 line,
01029                            int type, char *base, char *name, WsList *arguments)
01030 {
01031     WsExpression *expr = expr_alloc(compiler, WS_EXPR_CALL, line);
01032 
01033     if (expr) {
01034         expr->u.call.type = type;
01035         expr->u.call.base = ws_f_strdup(compiler->pool_stree, base);
01036         expr->u.call.name = ws_f_strdup(compiler->pool_stree, name);
01037         expr->u.call.arguments = arguments;
01038 
01039         if ((base && expr->u.call.base == NULL)
01040             || (name && expr->u.call.name == NULL))
01041             ws_error_memory(compiler);
01042     }
01043 
01044     ws_lexer_free_block(compiler, base);
01045     ws_lexer_free_block(compiler, name);
01046 
01047     return expr;
01048 }
01049 
01050 
01051 WsExpression *ws_expr_symbol(WsCompiler *compiler, WsUInt32 line,
01052                              char *identifier)
01053 {
01054     WsExpression *expr = expr_alloc(compiler, WS_EXPR_SYMBOL, line);
01055 
01056     if (expr) {
01057         expr->u.symbol = ws_f_strdup(compiler->pool_stree, identifier);
01058         if (expr->u.symbol == NULL)
01059             ws_error_memory(compiler);
01060     }
01061 
01062     ws_lexer_free_block(compiler, identifier);
01063 
01064     return expr;
01065 }
01066 
01067 
01068 WsExpression *ws_expr_const_invalid(WsCompiler *compiler, WsUInt32 line)
01069 {
01070     return expr_alloc(compiler, WS_EXPR_CONST_INVALID, line);
01071 }
01072 
01073 
01074 WsExpression *ws_expr_const_true(WsCompiler *compiler, WsUInt32 line)
01075 {
01076     return expr_alloc(compiler, WS_EXPR_CONST_TRUE, line);
01077 }
01078 
01079 
01080 WsExpression *ws_expr_const_false(WsCompiler *compiler, WsUInt32 line)
01081 {
01082     return expr_alloc(compiler, WS_EXPR_CONST_FALSE, line);
01083 }
01084 
01085 
01086 WsExpression *ws_expr_const_integer(WsCompiler *compiler, WsUInt32 line,
01087                                     WsUInt32 ival)
01088 {
01089     WsExpression *expr = expr_alloc(compiler, WS_EXPR_CONST_INTEGER, line);
01090 
01091     if (expr) {
01092         expr->u.integer.sign = 1;
01093         expr->u.integer.ival = ival;
01094     }
01095 
01096     return expr;
01097 }
01098 
01099 
01100 WsExpression *ws_expr_const_float(WsCompiler *compiler, WsUInt32 line,
01101                                   WsFloat fval)
01102 {
01103     WsExpression *expr = expr_alloc(compiler, WS_EXPR_CONST_FLOAT, line);
01104 
01105     if (expr)
01106         expr->u.fval = fval;
01107 
01108     return expr;
01109 }
01110 
01111 
01112 WsExpression *ws_expr_const_string(WsCompiler *compiler, WsUInt32 line,
01113                                    WsUtf8String *string)
01114 {
01115     WsExpression *expr = expr_alloc(compiler, WS_EXPR_CONST_STRING, line);
01116 
01117     if (expr) {
01118         expr->u.string.len = string->len;
01119         expr->u.string.data = ws_f_memdup(compiler->pool_stree,
01120                                           string->data, string->len);
01121         if (expr->u.string.data == NULL)
01122             ws_error_memory(compiler);
01123     }
01124 
01125     ws_lexer_free_utf8(compiler, string);
01126 
01127     return expr;
01128 }
01129 
01130 /********************* Statements ***************************************/
01131 
01132 /* Linearize the variable declaration list `list'. */
01133 static void linearize_variable_init(WsCompiler *compiler, WsList *list,
01134                                     WsUInt32 line)
01135 {
01136     WsNamespace *ns;
01137     WsListItem *li;
01138 
01139     /* For each variable, declared with this list. */
01140     for (li = list->head; li; li = li->next) {
01141         WsVarDec *vardec = li->data;
01142 
01143         ns = ws_variable_define(compiler, line, WS_TRUE, vardec->name);
01144         if (ns && vardec->expr) {
01145             ws_expr_linearize(compiler, vardec->expr);
01146 
01147             /* Emit an instruction to store the initialization
01148                value to the variable. */
01149             ws_asm_link(compiler,
01150                         ws_asm_variable(compiler, line, WS_ASM_P_STORE_VAR,
01151                                         ns->vindex));
01152         }
01153     }
01154 }
01155 
01156 
01157 void ws_stmt_linearize(WsCompiler *compiler, WsStatement *stmt)
01158 {
01159     WsListItem *li;
01160     WsAsmIns *ins;
01161 
01162     switch (stmt->type) {
01163     case WS_STMT_BLOCK:
01164         for (li = stmt->u.block->head; li; li = li->next)
01165             ws_stmt_linearize(compiler, li->data);
01166         break;
01167 
01168     case WS_STMT_VARIABLE:
01169         linearize_variable_init(compiler, stmt->u.var, stmt->first_line);
01170         break;
01171 
01172     case WS_STMT_EMPTY:
01173         /* Nothing here. */
01174         break;
01175 
01176     case WS_STMT_EXPR:
01177         ws_expr_linearize(compiler, stmt->u.expr);
01178 
01179         /* Pop the expressions result from the stack.  Otherwise loops
01180            could eventually cause stack overflows. */
01181         ws_asm_link(compiler, ws_asm_ins(compiler, stmt->last_line, WS_ASM_POP));
01182         break;
01183 
01184     case WS_STMT_IF:
01185         {
01186             WsAsmIns *l_else = ws_asm_label(compiler,
01187                                             (stmt->u.s_if.s_else
01188                                              ? stmt->u.s_if.s_else->first_line
01189                                              : stmt->last_line));
01190             WsAsmIns *l_end = ws_asm_label(compiler, stmt->last_line);
01191 
01192             /* Linearize the expression. */
01193             ws_expr_linearize(compiler, stmt->u.s_if.expr);
01194 
01195             /* If the result is false, jump to the else-branch. */
01196             ws_asm_link(compiler, ws_asm_branch(compiler, stmt->first_line,
01197                                                 WS_ASM_P_TJUMP, l_else));
01198 
01199             /* Else, execute the then-branch and jump to the end. */
01200             ws_stmt_linearize(compiler, stmt->u.s_if.s_then);
01201             ws_asm_link(compiler, ws_asm_branch(compiler, stmt->last_line,
01202                                                 WS_ASM_P_JUMP, l_end));
01203 
01204             /* Then else-branch. */
01205             ws_asm_link(compiler, l_else);
01206 
01207             /* Linearize the else-branch if it is present. */
01208             if (stmt->u.s_if.s_else)
01209                 ws_stmt_linearize(compiler, stmt->u.s_if.s_else);
01210 
01211             /* Insert the end label. */
01212             ws_asm_link(compiler, l_end);
01213         }
01214         break;
01215 
01216     case WS_STMT_FOR:
01217         {
01218             WsAsmIns *l_loop = ws_asm_label(compiler, stmt->first_line);
01219             WsAsmIns *l_cont = ws_asm_label(compiler, stmt->first_line);
01220             WsAsmIns *l_break = ws_asm_label(compiler, stmt->first_line);
01221             WsContBreak *cb;
01222 
01223             /* Store the labels to the compiler. */
01224 
01225             cb = ws_f_calloc(compiler->pool_stree, 1, sizeof(*cb));
01226             if (cb == NULL) {
01227                 ws_error_memory(compiler);
01228                 return;
01229             }
01230 
01231             cb->next = compiler->cont_break;
01232             compiler->cont_break = cb;
01233 
01234             cb->l_cont = l_cont;
01235             cb->l_break = l_break;
01236 
01237             /* Linearize the possible init code. */
01238             if (stmt->u.s_for.init)
01239                 linearize_variable_init(compiler, stmt->u.s_for.init,
01240                                         stmt->first_line);
01241             else if (stmt->u.s_for.e1) {
01242                 /* Linearize the init. */
01243                 ws_expr_linearize(compiler, stmt->u.s_for.e1);
01244 
01245                 /* Pop the result. */
01246                 ws_asm_link(compiler, ws_asm_ins(compiler, stmt->first_line,
01247                                                  WS_ASM_POP));
01248             }
01249 
01250             /* Insert the loop label. */
01251             ws_asm_link(compiler, l_loop);
01252 
01253             /* Linearize the condition. */
01254             if (stmt->u.s_for.e2) {
01255                 ws_expr_linearize(compiler, stmt->u.s_for.e2);
01256 
01257                 /* If false, jump out. */
01258                 ws_asm_link(compiler, ws_asm_branch(compiler, stmt->first_line,
01259                                                     WS_ASM_P_TJUMP, l_break));
01260             }
01261 
01262             /* Linearize the body statement. */
01263             ws_stmt_linearize(compiler, stmt->u.s_for.stmt);
01264 
01265             /* Link the continue label. */
01266             ws_asm_link(compiler, l_cont);
01267 
01268             /* Linearize the update expression. */
01269             if (stmt->u.s_for.e3) {
01270                 ws_expr_linearize(compiler, stmt->u.s_for.e3);
01271 
01272                 /* Pop the result. */
01273                 ws_asm_link(compiler, ws_asm_ins(compiler, stmt->first_line,
01274                                                  WS_ASM_POP));
01275             }
01276 
01277             /* Jump to the loop label to check the condition. */
01278             ws_asm_link(compiler, ws_asm_branch(compiler, stmt->last_line,
01279                                                 WS_ASM_P_JUMP, l_loop));
01280 
01281             /* Insert the break label. */
01282             ws_asm_link(compiler, l_break);
01283 
01284             /* Pop the cont-break block. */
01285             compiler->cont_break = compiler->cont_break->next;
01286         }
01287         break;
01288 
01289     case WS_STMT_WHILE:
01290         {
01291             WsAsmIns *l_cont = ws_asm_label(compiler, stmt->first_line);
01292             WsAsmIns *l_break = ws_asm_label(compiler,
01293                                              stmt->u.s_while.stmt->last_line);
01294             WsContBreak *cb;
01295 
01296             /* Store the labels to the compiler. */
01297 
01298             cb = ws_f_calloc(compiler->pool_stree, 1, sizeof(*cb));
01299             if (cb == NULL) {
01300                 ws_error_memory(compiler);
01301                 return;
01302             }
01303 
01304             cb->next = compiler->cont_break;
01305             compiler->cont_break = cb;
01306 
01307             cb->l_cont = l_cont;
01308             cb->l_break = l_break;
01309 
01310             /* Insert the continue label. */
01311             ws_asm_link(compiler, l_cont);
01312 
01313             /* Linearize the expression. */
01314             ws_expr_linearize(compiler, stmt->u.s_while.expr);
01315 
01316             /* If false, jump out. */
01317             ws_asm_link(compiler, ws_asm_branch(compiler, stmt->first_line,
01318                                                 WS_ASM_P_TJUMP, l_break));
01319 
01320             /* Linearize the body statement. */
01321             ws_stmt_linearize(compiler, stmt->u.s_while.stmt);
01322 
01323             /* And jump to the continue label to check the expression. */
01324             ws_asm_link(compiler, ws_asm_branch(compiler, stmt->last_line,
01325                                                 WS_ASM_P_JUMP, l_cont));
01326 
01327             /* Insert the break label. */
01328             ws_asm_link(compiler, l_break);
01329 
01330             /* Pop the cont-break block. */
01331             compiler->cont_break = compiler->cont_break->next;
01332         }
01333         break;
01334 
01335     case WS_STMT_CONTINUE:
01336         if (compiler->cont_break == NULL)
01337             ws_src_error(compiler, stmt->first_line,
01338                          "continue statement not within a loop");
01339 
01340         ws_asm_link(compiler, ws_asm_branch(compiler, stmt->first_line,
01341                                             WS_ASM_P_JUMP,
01342                                             compiler->cont_break->l_cont));
01343         break;
01344 
01345     case WS_STMT_BREAK:
01346         if (compiler->cont_break == NULL)
01347             ws_src_error(compiler, stmt->first_line,
01348                          "break statement not within a loop");
01349 
01350         ws_asm_link(compiler, ws_asm_branch(compiler, stmt->first_line,
01351                                             WS_ASM_P_JUMP,
01352                                             compiler->cont_break->l_break));
01353         break;
01354 
01355     case WS_STMT_RETURN:
01356         if (stmt->u.expr) {
01357             /* Linearize the return value and return it. */
01358             ws_expr_linearize(compiler, stmt->u.expr);
01359             ins = ws_asm_ins(compiler, stmt->first_line, WS_ASM_RETURN);
01360         } else
01361             /* Return an empty string. */
01362             ins = ws_asm_ins(compiler, stmt->first_line, WS_ASM_RETURN_ES);
01363 
01364         ws_asm_link(compiler, ins);
01365         break;
01366     }
01367 }
01368 
01369 
01370 /* Constructors. */
01371 
01372 static WsStatement *stmt_alloc(WsCompiler *compiler, WsStatementType type,
01373                                WsUInt32 first_line, WsUInt32 last_line)
01374 {
01375     WsStatement *stmt = ws_f_calloc(compiler->pool_stree, 1, sizeof(*stmt));
01376 
01377     if (stmt == NULL)
01378         ws_error_memory(compiler);
01379     else {
01380         stmt->type = type;
01381         stmt->first_line = first_line;
01382         stmt->last_line = last_line;
01383     }
01384 
01385     return stmt;
01386 }
01387 
01388 
01389 WsStatement *ws_stmt_block(WsCompiler *compiler, WsUInt32 fline,
01390                            WsUInt32 lline, WsList *block)
01391 {
01392     WsStatement *stmt = stmt_alloc(compiler, WS_STMT_BLOCK, fline, lline);
01393 
01394     if (stmt)
01395         stmt->u.block = block;
01396 
01397     return stmt;
01398 }
01399 
01400 
01401 WsStatement *ws_stmt_variable(WsCompilerPtr compiler, WsUInt32 line,
01402                               WsList *variables)
01403 {
01404     WsStatement *stmt = stmt_alloc(compiler, WS_STMT_VARIABLE, line, line);
01405 
01406     if (stmt)
01407         stmt->u.var = variables;
01408 
01409     return stmt;
01410 }
01411 
01412 
01413 WsStatement *ws_stmt_empty(WsCompiler *compiler, WsUInt32 line)
01414 {
01415     return stmt_alloc(compiler, WS_STMT_EMPTY, line, line);
01416 }
01417 
01418 
01419 WsStatement *ws_stmt_expr(WsCompiler *compiler, WsUInt32 line,
01420                           WsExpression *expr)
01421 {
01422     WsStatement *stmt = stmt_alloc(compiler, WS_STMT_EXPR, line, line);
01423 
01424     if (stmt)
01425         stmt->u.expr = expr;
01426 
01427     return stmt;
01428 }
01429 
01430 
01431 WsStatement *ws_stmt_if(WsCompiler *compiler, WsUInt32 line,
01432                         WsExpression *expr, WsStatement *s_then,
01433                         WsStatement *s_else)
01434 {
01435     WsStatement *stmt = stmt_alloc(compiler, WS_STMT_IF, line, line);
01436 
01437     if (stmt) {
01438         stmt->u.s_if.expr = expr;
01439         stmt->u.s_if.s_then = s_then;
01440         stmt->u.s_if.s_else = s_else;
01441     }
01442 
01443     return stmt;
01444 }
01445 
01446 
01447 WsStatement *ws_stmt_for(WsCompilerPtr compiler, WsUInt32 line, WsList *init,
01448                          WsExpression *e1, WsExpression *e2, WsExpression *e3,
01449                          WsStatement *stmt_body)
01450 {
01451     WsStatement *stmt = stmt_alloc(compiler, WS_STMT_FOR, line, line);
01452 
01453     if (stmt) {
01454         stmt->u.s_for.init = init;
01455         stmt->u.s_for.e1 = e1;
01456         stmt->u.s_for.e2 = e2;
01457         stmt->u.s_for.e3 = e3;
01458         stmt->u.s_for.stmt = stmt_body;
01459     }
01460 
01461     return stmt;
01462 }
01463 
01464 
01465 WsStatement *ws_stmt_while(WsCompiler *compiler, WsUInt32 line,
01466                            WsExpression *expr, WsStatement *stmt_arg)
01467 {
01468     WsStatement *stmt = stmt_alloc(compiler, WS_STMT_WHILE, line, line);
01469 
01470     if (stmt) {
01471         stmt->u.s_while.expr = expr;
01472         stmt->u.s_while.stmt = stmt_arg;
01473     }
01474 
01475     return stmt;
01476 }
01477 
01478 
01479 WsStatement *ws_stmt_continue(WsCompiler *compiler, WsUInt32 line)
01480 {
01481     return stmt_alloc(compiler, WS_STMT_CONTINUE, line, line);
01482 }
01483 
01484 
01485 WsStatement *ws_stmt_break(WsCompiler *compiler, WsUInt32 line)
01486 {
01487     return stmt_alloc(compiler, WS_STMT_BREAK, line, line);
01488 }
01489 
01490 
01491 WsStatement *ws_stmt_return(WsCompilerPtr compiler, WsUInt32 line,
01492                             WsExpression *expr)
01493 {
01494     WsStatement *stmt = stmt_alloc(compiler, WS_STMT_RETURN, line, line);
01495 
01496     if (stmt)
01497         stmt->u.expr = expr;
01498 
01499     return stmt;
01500 }
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.