Example #1
0
void ws_function(WsCompiler *compiler, WsBool externp, char *name,
                 WsUInt32 line, WsList *params, WsList *block)
{
    WsFunctionHash *hash;
    WsFunction *f = ws_realloc(compiler->functions,
                               ((compiler->num_functions + 1)
                                * sizeof(WsFunction)));

    if (f == NULL) {
        ws_free(name);
        ws_error_memory(compiler);
        return;
    }

    if (externp)
        compiler->num_extern_functions++;
    else
        compiler->num_local_functions++;

    compiler->functions = f;
    f = &compiler->functions[compiler->num_functions];

    f->findex = compiler->num_functions++;

    f->externp = externp;
    f->name = name;
    f->line = line;
    f->params = params;
    f->block = block;

    /* Update the function name hash. */

    hash = ws_function_hash(compiler, name);
    if (hash == NULL) {
        ws_error_memory(compiler);
        return;
    }

    if (hash->defined) {
        ws_src_error(compiler, line, "redefinition of `%s'", name);
        ws_src_error(compiler,
                     compiler->functions[hash->findex].line,
                     "`%s' previously defined here", name);
        return;
    }

    hash->defined = WS_TRUE;
    hash->findex = f->findex;
}
Example #2
0
static WsUInt32 buffer_to_int(WsCompilerPtr compiler, WsBuffer *buffer)
{
    unsigned char *p;
    unsigned long value;

    /* Terminate the string. */
    if (!ws_buffer_append_space(buffer, &p, 1)) {
        ws_error_memory(compiler);
        return 0;
    }
    p[0] = '\0';

    /* Convert the buffer into an integer number.  The base is taken
       from the bufer. */
    errno = 0;
    value = strtoul((char *) ws_buffer_ptr(buffer), NULL, 0);

    /* Check for overflow.  We accept WS_INT32_MAX + 1 because we might
     * be parsing the numeric part of '-2147483648'. */
    if (errno == ERANGE || value > (WsUInt32) WS_INT32_MAX + 1)
        ws_src_error(compiler, 0, "integer literal too large");

    /* All done. */
    return (WsUInt32) value;
}
Example #3
0
WsList *ws_list_new(WsCompiler *compiler)
{
    WsList *list = ws_f_calloc(compiler->pool_stree, 1, sizeof(*list));

    if (list == NULL)
        ws_error_memory(compiler);

    return list;
}
Example #4
0
static WsAsmIns *asm_alloc(WsCompiler *compiler, WsUInt16 type, WsUInt32 line)
{
    WsAsmIns *ins = ws_f_calloc(compiler->pool_asm, 1, sizeof(*ins));

    if (ins == NULL)
        ws_error_memory(compiler);
    else {
        ins->type = type;
        ins->line = line;
    }

    return ins;
}
Example #5
0
WsFunctionHash *ws_function_hash(WsCompilerPtr compiler, char *name)
{
    WsFunctionHash *i = ws_hash_get(compiler->functions_hash, name);

    if (i)
        return i;

    /* Must create a new mapping. */

    i = ws_calloc(1, sizeof(*i));
    if (i == NULL) {
        ws_error_memory(compiler);
        return NULL;
    }

    if (!ws_hash_put(compiler->functions_hash, name, i)) {
        ws_free(i);
        ws_error_memory(compiler);
        return NULL;
    }

    return i;
}
Example #6
0
WsVarDec *ws_variable_declaration(WsCompilerPtr compiler,
                                  char *name, WsExpression *expr)
{
    WsVarDec *vardec = ws_f_malloc(compiler->pool_stree, sizeof(*vardec));

    if (vardec == NULL)
        ws_error_memory(compiler);
    else {
        vardec->name = name;
        vardec->expr = expr;
    }

    return vardec;
}
Example #7
0
static WsExpression *expr_alloc(WsCompiler *compiler,
                                WsExpressionType type, WsUInt32 line)
{
    WsExpression *expr = ws_f_calloc(compiler->pool_stree, 1, sizeof(*expr));

    if (expr == NULL)
        ws_error_memory(compiler);
    else {
        expr->type = type;
        expr->line = line;
    }

    return expr;
}
Example #8
0
WsFormalParm *ws_formal_parameter(WsCompilerPtr compiler,
                                  WsUInt32 line, char *name)
{
    WsFormalParm *parm = ws_f_malloc(compiler->pool_stree, sizeof(*parm));

    if (parm == NULL)
        ws_error_memory(compiler);
    else {
        parm->line = line;
        parm->name = name;
    }

    return parm;
}
Example #9
0
WsNamespace *ws_variable_define(WsCompilerPtr compiler, WsUInt32 line,
                                WsBool variablep, char *name)
{
    WsNamespace *ns;

    /* Is the symbol already defined? */
    ns = ws_hash_get(compiler->variables_hash, name);
    if (ns) {
        ws_src_error(compiler, line, "redeclaration of `%s'", name);
        ws_src_error(compiler, ns->line, "`%s' previously declared here", name);
        return NULL;
    }

    /* Can we still define more variables? */
    if (compiler->next_vindex > 255) {
        /* No we can't. */
        ws_src_error(compiler, line, "too many local variables");
        return NULL;
    }

    ns = ws_calloc(1, sizeof(*ns));
    if (ns == NULL) {
        ws_error_memory(compiler);
        return NULL;
    }

    ns->line = line;
    ns->vindex = compiler->next_vindex++;

    if (!ws_hash_put(compiler->variables_hash, name, ns)) {
        ws_free(ns);
        ws_error_memory(compiler);
        return NULL;
    }

    return ns;
}
Example #10
0
WsExpression *ws_expr_symbol(WsCompiler *compiler, WsUInt32 line,
                             char *identifier)
{
    WsExpression *expr = expr_alloc(compiler, WS_EXPR_SYMBOL, line);

    if (expr) {
        expr->u.symbol = ws_f_strdup(compiler->pool_stree, identifier);
        if (expr->u.symbol == NULL)
            ws_error_memory(compiler);
    }

    ws_lexer_free_block(compiler, identifier);

    return expr;
}
Example #11
0
static WsStatement *stmt_alloc(WsCompiler *compiler, WsStatementType type,
                               WsUInt32 first_line, WsUInt32 last_line)
{
    WsStatement *stmt = ws_f_calloc(compiler->pool_stree, 1, sizeof(*stmt));

    if (stmt == NULL)
        ws_error_memory(compiler);
    else {
        stmt->type = type;
        stmt->first_line = first_line;
        stmt->last_line = last_line;
    }

    return stmt;
}
Example #12
0
WsExpression *ws_expr_unary_var(WsCompilerPtr compiler, WsUInt32 line,
                                WsBool addp, char *variable)
{
    WsExpression *expr = expr_alloc(compiler, WS_EXPR_UNARY_VAR, line);

    if (expr) {
        expr->u.unary_var.addp = addp;
        expr->u.unary_var.variable = ws_f_strdup(compiler->pool_stree, variable);
        if (expr->u.unary_var.variable == NULL)
            ws_error_memory(compiler);
    }
    ws_lexer_free_block(compiler, variable);

    return expr;
}
Example #13
0
void ws_pragma_use(WsCompilerPtr compiler, WsUInt32 line, char *identifier,
                   WsUtf8String *url)
{
    WsPragmaUse *u = ws_calloc(1, sizeof(*u));
    WsPragmaUse *uold;

    /* Do we already know this pragma? */
    uold = ws_hash_get(compiler->pragma_use_hash, identifier);
    if (uold) {
        ws_src_error(compiler, line, "redefinition of pragma `%s'", identifier);
        ws_src_error(compiler, uold->line, "`%s' previously defined here",
                     identifier);
        goto error_cleanup;
    }

    if (u == NULL)
        goto error;

    u->line = line;

    /* Insert the URL to the byte-code module. */
    if (!ws_bc_add_const_utf8_string(compiler->bc, &u->urlindex, url->data,
                                     url->len))
        goto error;

    /* Add it to the use pragma hash. */
    if (!ws_hash_put(compiler->pragma_use_hash, identifier, u))
        goto error;

    /* Cleanup. */

    ws_lexer_free_block(compiler, identifier);
    ws_lexer_free_utf8(compiler, url);

    return;

    /* Error handling. */

error:

    ws_error_memory(compiler);

error_cleanup:

    ws_free(u);
    ws_lexer_free_block(compiler, identifier);
    ws_lexer_free_utf8(compiler, url);
}
Example #14
0
WsExpression *ws_expr_const_string(WsCompiler *compiler, WsUInt32 line,
                                   WsUtf8String *string)
{
    WsExpression *expr = expr_alloc(compiler, WS_EXPR_CONST_STRING, line);

    if (expr) {
        expr->u.string.len = string->len;
        expr->u.string.data = ws_f_memdup(compiler->pool_stree,
                                          string->data, string->len);
        if (expr->u.string.data == NULL)
            ws_error_memory(compiler);
    }

    ws_lexer_free_utf8(compiler, string);

    return expr;
}
Example #15
0
WsPragmaMetaBody *ws_pragma_meta_body(WsCompilerPtr compiler,
                                      WsUtf8String *property_name,
                                      WsUtf8String *content,
                                      WsUtf8String *scheme)
{
    WsPragmaMetaBody *mb = ws_calloc(1, sizeof(*mb));

    if (mb == NULL) {
        ws_error_memory(compiler);
        return NULL;
    }

    mb->property_name = property_name;
    mb->content = content;
    mb->scheme = scheme;

    return mb;
}
Example #16
0
WsExpression *ws_expr_assign(WsCompilerPtr compiler, WsUInt32 line,
                             char *identifier, int op, WsExpression *expr)
{
    WsExpression *e = expr_alloc(compiler, WS_EXPR_ASSIGN, line);

    if (e) {
        e->u.assign.identifier = ws_f_strdup(compiler->pool_stree, identifier);
        if (e->u.assign.identifier == NULL)
            ws_error_memory(compiler);

        e->u.assign.op = op;
        e->u.assign.expr = expr;
    }

    /* Free the identifier symbol since it allocated from the system
       heap. */
    ws_lexer_free_block(compiler, identifier);

    return e;
}
Example #17
0
static WsBool read_float_from_point(WsCompiler *compiler, WsBuffer *buffer,
                                    WsFloat *result)
{
    WsUInt32 ch;
    unsigned char *p;

    while (ws_stream_getc(compiler->input, &ch)) {
        if (WS_IS_DECIMAL_DIGIT(ch)) {
            if (!ws_buffer_append_space(buffer, &p, 1)) {
                ws_error_memory(compiler);
                return WS_FALSE;
            }
            p[0] = (unsigned char) ch;
        } else {
            ws_stream_ungetc(compiler->input, ch);
            break;
        }
    }

    return read_float_from_exp(compiler, buffer, result);
}
Example #18
0
WsExpression *ws_expr_call(WsCompiler *compiler, WsUInt32 line,
                           int type, char *base, char *name, WsList *arguments)
{
    WsExpression *expr = expr_alloc(compiler, WS_EXPR_CALL, line);

    if (expr) {
        expr->u.call.type = type;
        expr->u.call.base = ws_f_strdup(compiler->pool_stree, base);
        expr->u.call.name = ws_f_strdup(compiler->pool_stree, name);
        expr->u.call.arguments = arguments;

        if ((base && expr->u.call.base == NULL)
            || (name && expr->u.call.name == NULL))
            ws_error_memory(compiler);
    }

    ws_lexer_free_block(compiler, base);
    ws_lexer_free_block(compiler, name);

    return expr;
}
Example #19
0
void ws_list_append(WsCompiler *compiler, WsList *list, void *value)
{
    WsListItem *item;

    if (list == NULL)
        /* A recovery code for previous memory allocation problems. */
        return;

    item = ws_f_calloc(compiler->pool_stree, 1, sizeof(*item));
    if (item == NULL) {
        ws_error_memory(compiler);
        return;
    }

    item->data = value;

    if (list->tail) {
        list->tail->next = item;
        list->tail = item;
    } else
        list->head = list->tail = item;

    list->num_items++;
}
Example #20
0
int ws_yy_lex(YYSTYPE *yylval, YYLTYPE *yylloc, void *context)
{
    WsCompiler *compiler = (WsCompiler *) context;
    WsUInt32 ch, ch2;
    WsBuffer buffer;
    unsigned char *p;
    WsBool success;

    /* Just check that we get the correct amount of arguments. */
    gw_assert(compiler->magic == COMPILER_MAGIC);

    while (ws_stream_getc(compiler->input, &ch)) {
        /* Save the token's line number. */
        yylloc->first_line = compiler->linenum;

        switch (ch) {
        case '\t': 		/* Whitespace characters. */
        case '\v':
        case '\f':
        case ' ':
            continue;

        case '\n': 		/* Line terminators. */
        case '\r':
            if (ch == '\r' && ws_stream_getc(compiler->input, &ch2)) {
                if (ch2 != '\n')
                    ws_stream_ungetc(compiler->input, ch2);
            }
            compiler->linenum++;
            continue;

        case '!': 		/* !, != */
            if (ws_stream_getc(compiler->input, &ch2)) {
                if (ch2 == '=')
                    return tNE;

                ws_stream_ungetc(compiler->input, ch2);
            }
            return '!';

        case '%': 		/* %, %= */
            if (ws_stream_getc(compiler->input, &ch2)) {
                if (ch2 == '=')
                    return tREMA;

                ws_stream_ungetc(compiler->input, ch2);
            }
            return '%';

        case '&': 		/* &, &&, &= */
            if (ws_stream_getc(compiler->input, &ch2)) {
                if (ch2 == '&')
                    return tAND;
                if (ch2 == '=')
                    return tANDA;

                ws_stream_ungetc(compiler->input, ch2);
            }
            return '&';

        case '*': 		/* *, *= */
            if (ws_stream_getc(compiler->input, &ch2)) {
                if (ch2 == '=')
                    return tMULA;

                ws_stream_ungetc(compiler->input, ch2);
            }
            return '*';

        case '+': 		/* +, ++, += */
            if (ws_stream_getc(compiler->input, &ch2)) {
                if (ch2 == '+')
                    return tPLUSPLUS;
                if (ch2 == '=')
                    return tADDA;

                ws_stream_ungetc(compiler->input, ch2);
            }
            return '+';

        case '-': 		/* -, --, -= */
            if (ws_stream_getc(compiler->input, &ch2)) {
                if (ch2 == '-')
                    return tMINUSMINUS;
                if (ch2 == '=')
                    return tSUBA;

                ws_stream_ungetc(compiler->input, ch2);
            }
            return '-';

        case '.':
            if (ws_stream_getc(compiler->input, &ch2)) {
                if (WS_IS_DECIMAL_DIGIT(ch2)) {
                    /* DecimalFloatLiteral. */
                    ws_buffer_init(&buffer);

                    if (!ws_buffer_append_space(&buffer, &p, 2)) {
                        ws_error_memory(compiler);
                        ws_buffer_uninit(&buffer);
                        return EOF;
                    }

                    p[0] = '.';
                    p[1] = (unsigned char) ch2;

                    success = read_float_from_point(compiler, &buffer,
                                                    &yylval->vfloat);
                    ws_buffer_uninit(&buffer);

                    if (!success)
                        return EOF;

                    return tFLOAT;
                }

                ws_stream_ungetc(compiler->input, ch2);
            }
            return '.';

        case '/': 		/* /, /=, block or a single line comment */
            if (ws_stream_getc(compiler->input, &ch2)) {
                if (ch2 == '*') {
                    /* Block comment. */
                    while (1) {
                        if (!ws_stream_getc(compiler->input, &ch)) {
                            ws_src_error(compiler, 0, "EOF in comment");
                            return EOF;
                        }

                        if (ch == '\n' || ch == '\r') {
                            /* Line terminators. */
                            if (ch == '\r' && ws_stream_getc(compiler->input,
                                                             &ch2)) {
                                if (ch2 != '\n')
                                    ws_stream_ungetc(compiler->input, ch2);
                            }
                            compiler->linenum++;

                            /* Continue reading the block comment. */
                            continue;
                        }

                        if (ch == '*' && ws_stream_getc(compiler->input, &ch2)) {
                            if (ch2 == '/')
                                /* The end of the comment found. */
                                break;
                            ws_stream_ungetc(compiler->input, ch2);
                        }
                    }
                    /* Continue after the comment. */
                    continue;
                }
                if (ch2 == '/') {
                    /* Single line comment. */
                    while (1) {
                        if (!ws_stream_getc(compiler->input, &ch))
                            /* The end of input stream reached.  We accept
                               this as a valid comment terminator. */
                            break;

                        if (ch == '\n' || ch == '\r') {
                            /* Line terminators. */
                            if (ch == '\r' && ws_stream_getc(compiler->input,
                                                             &ch2)) {
                                if (ch2 != '\n')
                                    ws_stream_ungetc(compiler->input, ch2);
                            }
                            /* The end of the line (and the comment)
                                                    reached. */
                            compiler->linenum++;
                            break;
                        }
                    }
                    /* Continue after the comment. */
                    continue;
                }
                if (ch2 == '=')
                    return tDIVA;

                ws_stream_ungetc(compiler->input, ch2);
            }
            return '/';

        case '<': 		/* <, <<, <<=, <= */
            if (ws_stream_getc(compiler->input, &ch2)) {
                if (ch2 == '<') {
                    if (ws_stream_getc(compiler->input, &ch2)) {
                        if (ch2 == '=')
                            return tLSHIFTA;

                        ws_stream_ungetc(compiler->input, ch2);
                    }
                    return tLSHIFT;
                }
                if (ch2 == '=')
                    return tLE;

                ws_stream_ungetc(compiler->input, ch2);
            }
            return '<';

        case '=': 		/* =, == */
            if (ws_stream_getc(compiler->input, &ch2)) {
                if (ch2 == '=')
                    return tEQ;

                ws_stream_ungetc(compiler->input, ch2);
            }
            return '=';

        case '>': 		/* >, >=, >>, >>=, >>>, >>>= */
            if (ws_stream_getc(compiler->input, &ch2)) {
                if (ch2 == '>') {
                    if (ws_stream_getc(compiler->input, &ch2)) {
                        if (ch2 == '>') {
                            if (ws_stream_getc(compiler->input, &ch2)) {
                                if (ch2 == '=')
                                    return tRSZSHIFTA;

                                ws_stream_ungetc(compiler->input, ch2);
                            }
                            return tRSZSHIFT;
                        }
                        if (ch2 == '=')
                            return tRSSHIFTA;

                        ws_stream_ungetc(compiler->input, ch2);
                    }
                    return tRSSHIFT;
                }
                if (ch2 == '=')
                    return tGE;

                ws_stream_ungetc(compiler->input, ch2);
            }
            return '>';

        case '^': 		/* ^, ^= */
            if (ws_stream_getc(compiler->input, &ch2)) {
                if (ch2 == '=')
                    return tXORA;

                ws_stream_ungetc(compiler->input, ch2);
            }
            return '^';

        case '|': 		/* |, |=, || */
            if (ws_stream_getc(compiler->input, &ch2)) {
                if (ch2 == '=')
                    return tORA;
                if (ch2 == '|')
                    return tOR;

                ws_stream_ungetc(compiler->input, ch2);
            }
            return '|';

        case '#': 		/* The simple cases. */
        case '(':
        case ')':
        case ',':
        case ':':
        case ';':
        case '?':
        case '{':
        case '}':
        case '~':
            return (int) ch;

        case '\'': 		/* String literals. */
        case '"':
            {
                WsUInt32 string_end_ch = ch;
                WsUtf8String *str = ws_utf8_alloc();

                if (str == NULL) {
                    ws_error_memory(compiler);
                    return EOF;
                }

                while (1) {
                    if (!ws_stream_getc(compiler->input, &ch)) {
eof_in_string_literal:
                        ws_src_error(compiler, 0, "EOF in string literal");
                        ws_utf8_free(str);
                        return EOF;
                    }
                    if (ch == string_end_ch)
                        /* The end of string reached. */
                        break;

                    if (ch == '\\') {
                        /* An escape sequence. */
                        if (!ws_stream_getc(compiler->input, &ch))
                            goto eof_in_string_literal;

                        switch (ch) {
                        case '\'':
                        case '"':
                        case '\\':
                        case '/':
                            /* The character as-is. */
                            break;

                        case 'b':
                            ch = '\b';
                            break;

                        case 'f':
                            ch = '\f';
                            break;

                        case 'n':
                            ch = '\n';
                            break;

                        case 'r':
                            ch = '\r';
                            break;

                        case 't':
                            ch = '\t';
                            break;

                        case 'x':
                        case 'u':
                            {
                                int i, len;
                                int type = ch;

                                if (ch == 'x')
                                    len = 2;
                                else
                                    len = 4;

                                ch = 0;
                                for (i = 0; i < len; i++) {
                                    if (!ws_stream_getc(compiler->input, &ch2))
                                        goto eof_in_string_literal;
                                    if (!WS_IS_HEX_DIGIT(ch2)) {
                                        ws_src_error(compiler, 0,
                                                     "malformed `\\%c' escape in "
                                                     "string literal", (char) type);
                                        ch = 0;
                                        break;
                                    }
                                    ch *= 16;
                                    ch += WS_HEX_TO_INT(ch2);
                                }
                            }
                            break;

                        default:
                            if (WS_IS_OCTAL_DIGIT(ch)) {
                                int i;
                                int limit = 3;

                                ch = WS_OCTAL_TO_INT(ch);
                                if (ch > 3)
                                    limit = 2;

                                for (i = 1; i < limit; i++) {
                                    if (!ws_stream_getc(compiler->input, &ch2))
                                        goto eof_in_string_literal;
                                    if (!WS_IS_OCTAL_DIGIT(ch2)) {
                                        ws_stream_ungetc(compiler->input, ch2);
                                        break;
                                    }

                                    ch *= 8;
                                    ch += WS_OCTAL_TO_INT(ch2);
                                }
                            } else {
                                ws_src_error(compiler, 0,
                                             "unknown escape sequence `\\%c' in "
                                             "string literal", (char) ch);
                                ch = 0;
                            }
                            break;
                        }
                        /* FALLTHROUGH */
                    }

                    if (!ws_utf8_append_char(str, ch)) {
                        ws_error_memory(compiler);
                        ws_utf8_free(str);
                        return EOF;
                    }
                }

                if (!ws_lexer_register_utf8(compiler, str)) {
                    ws_error_memory(compiler);
                    ws_utf8_free(str);
                    return EOF;
                }

                gw_assert(str != NULL);
                yylval->string = str;

                return tSTRING;
            }
            break;

        default:
            /* Identifiers, keywords and number constants. */

            if (WS_IS_IDENTIFIER_LETTER(ch)) {
                WsBool got;
                int token;
                unsigned char *p;
                unsigned char *np;
                size_t len = 0;

                /* An identifier or a keyword.  We start with a 256
                 * bytes long buffer but it is expanded dynamically if
                 * needed.  However, 256 should be enought for most
                 * cases since the byte-code format limits the function
                 * names to 255 characters. */
                p = ws_malloc(256);
                if (p == NULL) {
                    ws_error_memory(compiler);
                    return EOF;
                }

                do {
                    /* Add one extra for the possible terminator
                       character. */
                    np = ws_realloc(p, len + 2);
                    if (np == NULL) {
                        ws_error_memory(compiler);
                        ws_free(p);
                        return EOF;
                    }

                    p = np;

                    /* This is ok since the only valid identifier names
                     * can be written in 7 bit ASCII. */
                    p[len++] = (unsigned char) ch;
                } while ((got = ws_stream_getc(compiler->input, &ch))
                         && (WS_IS_IDENTIFIER_LETTER(ch)
                             || WS_IS_DECIMAL_DIGIT(ch)));

                if (got)
                    /* Put back the terminator character. */
                    ws_stream_ungetc(compiler->input, ch);

                /* Is it a keyword? */
                if (lookup_keyword((char *) p, len, &token)) {
                    /* Yes it is... */
                    ws_free(p);

                    /* ...except one case: `div='. */
                    if (token == tIDIV) {
                        if (ws_stream_getc(compiler->input, &ch)) {
                            if (ch == '=')
                                return tIDIVA;

                            ws_stream_ungetc(compiler->input, ch);
                        }
                    }

                    /* Return the token value. */
                    return token;
                }

                /* It is a normal identifier.  Let's pad the name with a
                          null-character.  We have already allocated space for
                          it. */
                p[len] = '\0';

                if (!ws_lexer_register_block(compiler, p)) {
                    ws_error_memory(compiler);
                    ws_free(p);
                    return EOF;
                }

                gw_assert(p != NULL);
                yylval->identifier = (char *) p;

                return tIDENTIFIER;
            }

            if (WS_IS_NON_ZERO_DIGIT(ch)) {
                /* A decimal integer literal or a decimal float
                          literal. */

                ws_buffer_init(&buffer);
                if (!ws_buffer_append_space(&buffer, &p, 1)) {
number_error_memory:
                    ws_error_memory(compiler);
                    ws_buffer_uninit(&buffer);
                    return EOF;
                }
                p[0] = ch;

                while (ws_stream_getc(compiler->input, &ch)) {
                    if (WS_IS_DECIMAL_DIGIT(ch)) {
                        if (!ws_buffer_append_space(&buffer, &p, 1))
                            goto number_error_memory;
                        p[0] = ch;
                    } else if (ch == '.' || ch == 'e' || ch == 'E') {
                        /* DecimalFloatLiteral. */
                        if (ch == '.') {
                            if (!ws_buffer_append_space(&buffer, &p, 1))
                                goto number_error_memory;
                            p[0] = '.';

                            success = read_float_from_point(compiler, &buffer,
                                                            &yylval->vfloat);
                        } else {
                            ws_stream_ungetc(compiler->input, ch);

                            success = read_float_from_exp(compiler, &buffer,
                                                          &yylval->vfloat);
                        }
                        ws_buffer_uninit(&buffer);

                        if (!success)
                            return EOF;

                        return tFLOAT;
                    } else {
                        ws_stream_ungetc(compiler->input, ch);
                        break;
                    }
                }

                /* Now the buffer contains an integer number as a
                          string.  Let's convert it to an integer number. */
                yylval->integer = buffer_to_int(compiler, &buffer);
                ws_buffer_uninit(&buffer);

                /* Read a DecimalIntegerLiteral. */
                return tINTEGER;
            }

            if (ch == '0') {
                /* The integer constant 0, an octal number or a
                   HexIntegerLiteral. */
                if (ws_stream_getc(compiler->input, &ch2)) {
                    if (ch2 == 'x' || ch2 == 'X') {
                        /* HexIntegerLiteral. */

                        ws_buffer_init(&buffer);
                        if (!ws_buffer_append_space(&buffer, &p, 2))
                            goto number_error_memory;

                        p[0] = '0';
                        p[1] = 'x';

                        while (ws_stream_getc(compiler->input, &ch)) {
                            if (WS_IS_HEX_DIGIT(ch)) {
                                if (!ws_buffer_append_space(&buffer, &p, 1))
                                    goto number_error_memory;
                                p[0] = ch;
                            } else {
                                ws_stream_ungetc(compiler->input, ch);
                                break;
                            }
                        }

                        if (ws_buffer_len(&buffer) == 2) {
                            ws_buffer_uninit(&buffer);
                            ws_src_error(compiler, 0,
                                         "numeric constant with no digits");
                            yylval->integer = 0;
                            return tINTEGER;
                        }

                        /* Now the buffer contains an integer number as
                         * a string.  Let's convert it to an integer
                         * number. */
                        yylval->integer = buffer_to_int(compiler, &buffer);
                        ws_buffer_uninit(&buffer);

                        /* Read a HexIntegerLiteral. */
                        return tINTEGER;
                    }
                    if (WS_IS_OCTAL_DIGIT(ch2)) {
                        /* OctalIntegerLiteral. */

                        ws_buffer_init(&buffer);
                        if (!ws_buffer_append_space(&buffer, &p, 2))
                            goto number_error_memory;

                        p[0] = '0';
                        p[1] = ch2;

                        while (ws_stream_getc(compiler->input, &ch)) {
                            if (WS_IS_OCTAL_DIGIT(ch)) {
                                if (!ws_buffer_append_space(&buffer, &p, 1))
                                    goto number_error_memory;
                                p[0] = ch;
                            } else {
                                ws_stream_ungetc(compiler->input, ch);
                                break;
                            }
                        }

                        /* Convert the buffer into an intger number. */
                        yylval->integer = buffer_to_int(compiler, &buffer);
                        ws_buffer_uninit(&buffer);

                        /* Read an OctalIntegerLiteral. */
                        return tINTEGER;
                    }
                    if (ch2 == '.' || ch2 == 'e' || ch2 == 'E') {
                        /* DecimalFloatLiteral. */
                        ws_buffer_init(&buffer);

                        if (ch2 == '.') {
                            if (!ws_buffer_append_space(&buffer, &p, 1))
                                goto number_error_memory;
                            p[0] = '.';

                            success = read_float_from_point(compiler, &buffer,
                                                            &yylval->vfloat);
                        } else {
                            ws_stream_ungetc(compiler->input, ch);

                            success = read_float_from_exp(compiler, &buffer,
                                                          &yylval->vfloat);
                        }
                        ws_buffer_uninit(&buffer);

                        if (!success)
                            return EOF;

                        return tFLOAT;
                    }

                    ws_stream_ungetc(compiler->input, ch2);
                }

                /* Integer literal 0. */
                yylval->integer = 0;
                return tINTEGER;
            }

            /* Garbage found from the input stream. */
            ws_src_error(compiler, 0,
                         "garbage found from the input stream: character=0x%x",
                         ch);
            return EOF;
            break;
        }
    }

    return EOF;
}
Example #21
0
static WsBool read_float_from_exp(WsCompiler *compiler, WsBuffer *buffer,
                                  WsFloat *result)
{
    WsUInt32 ch;
    unsigned char *p;
    int sign = '+';
    unsigned char buf[4];

    /* Do we have an exponent part. */
    if (!ws_stream_getc(compiler->input, &ch))
        goto done;
    if (ch != 'e' && ch != 'E') {
        /* No exponent part. */
        ws_stream_ungetc(compiler->input, ch);
        goto done;
    }

    /* Sign. */
    if (!ws_stream_getc(compiler->input, &ch)) {
        /* This is an error. */
        ws_src_error(compiler, 0, "truncated float literal");
        return WS_FALSE;
    }
    if (ch == '-')
        sign = '-';
    else if (ch == '+')
        sign = '+';
    else
        ws_stream_ungetc(compiler->input, ch);

    /* DecimalDigits. */
    if (!ws_stream_getc(compiler->input, &ch)) {
        ws_src_error(compiler, 0, "truncated float literal");
        return WS_FALSE;
    }
    if (!WS_IS_DECIMAL_DIGIT(ch)) {
        ws_src_error(compiler, 0, "no decimal digits in exponent part");
        return WS_FALSE;
    }

    /* Append exponent part read so far. */
    if (!ws_buffer_append_space(buffer, &p, 2)) {
        ws_error_memory(compiler);
        return WS_FALSE;
    }
    p[0] = 'e';
    p[1] = sign;

    /* Read decimal digits. */
    while (WS_IS_DECIMAL_DIGIT(ch)) {
        if (!ws_buffer_append_space(buffer, &p, 1)) {
            ws_error_memory(compiler);
            return WS_FALSE;
        }
        p[0] = (unsigned char) ch;

        if (!ws_stream_getc(compiler->input, &ch))
            /* EOF.  This is ok. */
            goto done;
    }
    /* Unget the extra character. */
    ws_stream_ungetc(compiler->input, ch);

    /* FALLTHROUGH */

done:

    if (!ws_buffer_append_space(buffer, &p, 1)) {
        ws_error_memory(compiler);
        return WS_FALSE;
    }
    p[0] = 0;

    /* Now the buffer contains a valid floating point number. */
    *result = (WsFloat) strtod((char *) ws_buffer_ptr(buffer), NULL);

    /* Check that the generated floating point number fits to
       `float32'. */
    if (*result == HUGE_VAL || *result == -HUGE_VAL
        || ws_ieee754_encode_single(*result, buf) != WS_IEEE754_OK)
        ws_src_error(compiler, 0, "floating point literal too large");

    return WS_TRUE;
}
Example #22
0
void
ws_asm_linearize(WsCompiler *compiler)
{
    WsAsmIns *ins;
    WsBool process_again = WS_TRUE;

    /* Calculate all offsets and select real assembler instructions for
       our internal pseudo instructions.  This is continued as long as
       the code changes. */
    while (process_again) {
        WsUInt32 offset = 1;

        process_again = WS_FALSE;

        for (ins = compiler->asm_head; ins; ins = ins->next) {
            ins->offset = offset;

            switch (ins->type) {
            case WS_ASM_JUMP_FW_S:
                ins->ws_offset = (ins->ws_label->offset
                                  - (offset + WS_OPSIZE(ins->type)));
                break;

            case WS_ASM_JUMP_FW:
                ins->ws_offset = (ins->ws_label->offset
                                  - (offset + WS_OPSIZE(ins->type)));

                if (ins->ws_offset <= 31) {
                    ins->type = WS_ASM_JUMP_FW_S;
                    process_again = WS_TRUE;
                }
                break;

            case WS_ASM_JUMP_FW_W:
                ins->ws_offset = (ins->ws_label->offset
                                  - (offset + WS_OPSIZE(ins->type)));

                if (ins->ws_offset <= 31) {
                    ins->type = WS_ASM_JUMP_FW_S;
                    process_again = WS_TRUE;
                } else if (ins->ws_offset <= 255) {
                    ins->type = WS_ASM_JUMP_FW;
                    process_again = WS_TRUE;
                }
                break;

            case WS_ASM_JUMP_BW_S:
                ins->ws_offset = offset - ins->ws_label->offset;
                break;

            case WS_ASM_JUMP_BW:
                ins->ws_offset = offset - ins->ws_label->offset;

                if (ins->ws_offset <= 31) {
                    ins->type = WS_ASM_JUMP_BW_S;
                    process_again = WS_TRUE;
                }
                break;

            case WS_ASM_JUMP_BW_W:
                ins->ws_offset = offset - ins->ws_label->offset;

                if (ins->ws_offset <= 31) {
                    ins->type = WS_ASM_JUMP_BW_S;
                    process_again = WS_TRUE;
                } else if (ins->ws_offset <= 255) {
                    ins->type = WS_ASM_JUMP_BW;
                    process_again = WS_TRUE;
                }
                break;

            case WS_ASM_TJUMP_FW_S:
                ins->ws_offset = (ins->ws_label->offset
                                  - (offset + WS_OPSIZE(ins->type)));
                break;

            case WS_ASM_TJUMP_FW:
                ins->ws_offset = (ins->ws_label->offset
                                  - (offset + WS_OPSIZE(ins->type)));

                if (ins->ws_offset <= 31) {
                    ins->type = WS_ASM_TJUMP_FW_S;
                    process_again = WS_TRUE;
                }
                break;

            case WS_ASM_TJUMP_FW_W:
                ins->ws_offset = (ins->ws_label->offset
                                  - (offset + WS_OPSIZE(ins->type)));

                if (ins->ws_offset <= 31) {
                    ins->type = WS_ASM_TJUMP_FW_S;
                    process_again = WS_TRUE;
                } else if (ins->ws_offset <= 255) {
                    ins->type = WS_ASM_TJUMP_FW;
                    process_again = WS_TRUE;
                }
                break;

            case WS_ASM_TJUMP_BW:
                 ins->ws_offset = offset - ins->ws_label->offset;
                 break;

            case WS_ASM_TJUMP_BW_W:
                ins->ws_offset = offset - ins->ws_label->offset;

                if (ins->ws_offset <= 255) {
                    ins->type = WS_ASM_TJUMP_BW;
                    process_again = WS_TRUE;
                }
                break;

                /*
                 * The pseudo instructions.
                 */

            case WS_ASM_P_LABEL:
                /* Nothing here. */
                break;

            case WS_ASM_P_JUMP:
                if (ins->ws_label->offset == 0) {
                    /* A forward jump.  Let's assume the widest form. */
                    ins->type = WS_ASM_JUMP_FW_W;
                } else {
                    ins->ws_offset = offset - ins->ws_label->offset;

                    /* Jump backwards. */
                    if (ins->ws_offset <= 31) {
                        ins->type = WS_ASM_JUMP_BW_S;
                    } else if (ins->ws_offset <= 255) {
                        ins->type = WS_ASM_JUMP_BW;
                    } else {
                        ins->type = WS_ASM_JUMP_BW_W;
                    }
                }
                break;

            case WS_ASM_P_TJUMP:
                if (ins->ws_label->offset == 0) {
                    /* A forward jump.  Let's assume the widest form. */
                    ins->type = WS_ASM_TJUMP_FW_W;
                    process_again = WS_TRUE;
                } else {
                    ins->ws_offset = offset - ins->ws_label->offset;

                    /* Jump backwards. */
                    if (ins->ws_offset <= 255) {
                        ins->type = WS_ASM_TJUMP_BW;
                    } else {
                        ins->type = WS_ASM_TJUMP_BW_W;
                    }
                }
                break;

            case WS_ASM_P_CALL:
                if (ins->ws_findex <= 7) {
                    /* The most compact form. */
                    ins->type = WS_ASM_CALL_S;
                } else {
                    /* The wider form. */
                    ins->type = WS_ASM_CALL;
                }
                break;

            case WS_ASM_P_CALL_LIB:
                if (ins->ws_findex <= 7 && ins->ws_lindex <= 255) {
                    /* The most compact form. */
                    ins->type = WS_ASM_CALL_LIB_S;
                } else if (ins->ws_findex <= 255 && ins->ws_lindex <= 255) {
                    /* The quite compact form. */
                    ins->type = WS_ASM_CALL_LIB;
                } else {
                    /* The most liberal form. */
                    ins->type = WS_ASM_CALL_LIB_W;
                }
                break;

            case WS_ASM_P_CALL_URL:
                if (ins->ws_findex <= 255 && ins->ws_lindex <= 255)
                    /* The compact form. */
                    ins->type = WS_ASM_CALL_URL;
                else
                    ins->type = WS_ASM_CALL_URL_W;
                break;

            case WS_ASM_P_LOAD_VAR:
                if (ins->ws_vindex <= 31)
                    /* The compact form. */
                    ins->type = WS_ASM_LOAD_VAR_S;
                else
                    ins->type = WS_ASM_LOAD_VAR;
                break;

            case WS_ASM_P_STORE_VAR:
                if (ins->ws_vindex <= 15)
                    ins->type = WS_ASM_STORE_VAR_S;
                else
                    ins->type = WS_ASM_STORE_VAR;
                break;

            case WS_ASM_P_INCR_VAR:
                if (ins->ws_vindex <= 7)
                    ins->type = WS_ASM_INCR_VAR_S;
                else
                    ins->type = WS_ASM_INCR_VAR;
                break;

            case WS_ASM_P_LOAD_CONST:
                if (ins->ws_cindex <= 15)
                    ins->type = WS_ASM_LOAD_CONST_S;
                else if (ins->ws_cindex <= 255)
                    ins->type = WS_ASM_LOAD_CONST;
                else
                    ins->type = WS_ASM_LOAD_CONST_W;
                break;
            }

            gw_assert(ins->type == WS_ASM_P_LABEL || ins->type < 0x100);

            if (ins->type != WS_ASM_P_LABEL) {
                gw_assert(operands[ins->type].name != NULL);
                offset += operands[ins->type].size;
            }
        }
    }

    /* Ok, ready to linearize the byte-code. */
    for (ins = compiler->asm_head; ins; ins = ins->next) {
        if (ins->type == WS_ASM_P_LABEL)
            continue;

        gw_assert(ins->type <= 0xff);

        switch (ins->type) {
        case WS_ASM_JUMP_FW_S:
        case WS_ASM_JUMP_BW_S:
        case WS_ASM_TJUMP_FW_S:
            if (!ws_encode_buffer(&compiler->byte_code,
                                  WS_ENC_BYTE,
                                  WS_ASM_GLUE(ins->type, ins->ws_offset),
                                  WS_ENC_END))
                goto error;
            break;

        case WS_ASM_JUMP_FW:
        case WS_ASM_JUMP_BW:
        case WS_ASM_TJUMP_FW:
        case WS_ASM_TJUMP_BW:
            if (!ws_encode_buffer(&compiler->byte_code,
                                  WS_ENC_BYTE, ins->type,
                                  WS_ENC_UINT8, (WsUInt8) ins->ws_offset,
                                  WS_ENC_END))
                goto error;
            break;

        case WS_ASM_JUMP_FW_W:
        case WS_ASM_JUMP_BW_W:
        case WS_ASM_TJUMP_FW_W:
        case WS_ASM_TJUMP_BW_W:
            if (!ws_encode_buffer(&compiler->byte_code,
                                  WS_ENC_BYTE, ins->type,
                                  WS_ENC_UINT16, (WsUInt16) ins->ws_offset,
                                  WS_ENC_END))
                goto error;
            break;

        case WS_ASM_CALL_S:
            if (!ws_encode_buffer(&compiler->byte_code,
                                  WS_ENC_BYTE,
                                  WS_ASM_GLUE(ins->type, ins->ws_findex),
                                  WS_ENC_END))
                goto error;
            break;

        case WS_ASM_CALL:
            if (!ws_encode_buffer(&compiler->byte_code,
                                  WS_ENC_BYTE, (WsByte) ins->type,
                                  WS_ENC_UINT8, (WsUInt8) ins->ws_findex,
                                  WS_ENC_END))
                goto error;
            break;

        case WS_ASM_CALL_LIB_S:
            if (!ws_encode_buffer(&compiler->byte_code,
                                  WS_ENC_BYTE,
                                  WS_ASM_GLUE(ins->type, ins->ws_findex),
                                  WS_ENC_UINT8, (WsUInt8) ins->ws_lindex,
                                  WS_ENC_END))
                goto error;
            break;

        case WS_ASM_CALL_LIB:
            if (!ws_encode_buffer(&compiler->byte_code,
                                  WS_ENC_BYTE, (WsByte) ins->type,
                                  WS_ENC_UINT8, (WsUInt8) ins->ws_findex,
                                  WS_ENC_UINT8, (WsUInt8) ins->ws_lindex,
                                  WS_ENC_END))
                goto error;
            break;

        case WS_ASM_CALL_LIB_W:
            if (!ws_encode_buffer(&compiler->byte_code,
                                  WS_ENC_BYTE, (WsByte) ins->type,
                                  WS_ENC_UINT8, (WsUInt8) ins->ws_findex,
                                  WS_ENC_UINT16, (WsUInt16) ins->ws_lindex,
                                  WS_ENC_END))
                goto error;
            break;

        case WS_ASM_CALL_URL:
            if (!ws_encode_buffer(&compiler->byte_code,
                                  WS_ENC_BYTE, (WsByte) ins->type,
                                  WS_ENC_UINT8, (WsUInt8) ins->ws_lindex,
                                  WS_ENC_UINT8, (WsUInt8) ins->ws_findex,
                                  WS_ENC_UINT8, (WsUInt8) ins->ws_args,
                                  WS_ENC_END))
                goto error;
            break;

        case WS_ASM_CALL_URL_W:
            if (!ws_encode_buffer(&compiler->byte_code,
                                  WS_ENC_BYTE, (WsByte) ins->type,
                                  WS_ENC_UINT16, (WsUInt16) ins->ws_lindex,
                                  WS_ENC_UINT16, (WsUInt16) ins->ws_findex,
                                  WS_ENC_UINT8, (WsUInt8) ins->ws_args,
                                  WS_ENC_END))
                goto error;
            break;

        case WS_ASM_LOAD_VAR_S:
        case WS_ASM_STORE_VAR_S:
            if (!ws_encode_buffer(&compiler->byte_code,
                                  WS_ENC_BYTE,
                                  WS_ASM_GLUE(ins->type, ins->ws_vindex),
                                  WS_ENC_END))
                goto error;
            break;

        case WS_ASM_LOAD_VAR:
        case WS_ASM_STORE_VAR:
            if (!ws_encode_buffer(&compiler->byte_code,
                                  WS_ENC_BYTE, (WsByte) ins->type,
                                  WS_ENC_UINT8, (WsUInt8) ins->ws_vindex,
                                  WS_ENC_END))
                goto error;
            break;

        case WS_ASM_INCR_VAR_S:
            if (!ws_encode_buffer(&compiler->byte_code,
                                  WS_ENC_BYTE,
                                  WS_ASM_GLUE(ins->type, ins->ws_vindex),
                                  WS_ENC_END))
                goto error;
            break;

        case WS_ASM_INCR_VAR:
        case WS_ASM_DECR_VAR:
            if (!ws_encode_buffer(&compiler->byte_code,
                                  WS_ENC_BYTE, (WsByte) ins->type,
                                  WS_ENC_UINT8, (WsUInt8) ins->ws_vindex,
                                  WS_ENC_END))
                goto error;
            break;

        case WS_ASM_LOAD_CONST_S:
            if (!ws_encode_buffer(&compiler->byte_code,
                                  WS_ENC_BYTE,
                                  WS_ASM_GLUE(ins->type, ins->ws_cindex),
                                  WS_ENC_END))
                goto error;
            break;

        case WS_ASM_LOAD_CONST:
            if (!ws_encode_buffer(&compiler->byte_code,
                                  WS_ENC_BYTE, (WsByte) ins->type,
                                  WS_ENC_UINT8, (WsUInt8) ins->ws_cindex,
                                  WS_ENC_END))
                goto error;
            break;

        case WS_ASM_LOAD_CONST_W:
            if (!ws_encode_buffer(&compiler->byte_code,
                                  WS_ENC_BYTE, (WsByte) ins->type,
                                  WS_ENC_UINT16, (WsUInt16) ins->ws_cindex,
                                  WS_ENC_END))
                goto error;
            break;

        case WS_ASM_ADD_ASG:
        case WS_ASM_SUB_ASG:
            if (!ws_encode_buffer(&compiler->byte_code,
                                  WS_ENC_BYTE, (WsByte) ins->type,
                                  WS_ENC_UINT8, (WsUInt8) ins->ws_vindex,
                                  WS_ENC_END))
                goto error;
            break;

        case WS_ASM_CONST_0:
        case WS_ASM_CONST_1:
        case WS_ASM_CONST_M1:
        case WS_ASM_CONST_ES:
        case WS_ASM_CONST_INVALID:
        case WS_ASM_CONST_TRUE:
        case WS_ASM_CONST_FALSE:
        case WS_ASM_INCR:
        case WS_ASM_DECR:
        case WS_ASM_UMINUS:
        case WS_ASM_ADD:
        case WS_ASM_SUB:
        case WS_ASM_MUL:
        case WS_ASM_DIV:
        case WS_ASM_IDIV:
        case WS_ASM_REM:
        case WS_ASM_B_AND:
        case WS_ASM_B_OR:
        case WS_ASM_B_XOR:
        case WS_ASM_B_NOT:
        case WS_ASM_B_LSHIFT:
        case WS_ASM_B_RSSHIFT:
        case WS_ASM_B_RSZSHIFT:
        case WS_ASM_EQ:
        case WS_ASM_LE:
        case WS_ASM_LT:
        case WS_ASM_GE:
        case WS_ASM_GT:
        case WS_ASM_NE:
        case WS_ASM_NOT:
        case WS_ASM_SCAND:
        case WS_ASM_SCOR:
        case WS_ASM_TOBOOL:
        case WS_ASM_POP:
        case WS_ASM_TYPEOF:
        case WS_ASM_ISVALID:
        case WS_ASM_RETURN:
        case WS_ASM_RETURN_ES:
        case WS_ASM_DEBUG:
            if (!ws_encode_buffer(&compiler->byte_code,
                                  WS_ENC_BYTE, (WsByte) ins->type,
                                  WS_ENC_END))
                goto error;
            break;

        default:
            ws_fatal("ws_asm_linearize(): unknown instruction 0x%02x",
                     ins->type);
            break;
        }
    }

    /*
     * Avoid generating 0-length functions, because not all clients
     * handle them correctly.
     */
    if (ws_buffer_len(&compiler->byte_code) == 0) {
	if (!ws_encode_buffer(&compiler->byte_code,
	   		      WS_ENC_BYTE, (WsByte) WS_ASM_RETURN_ES,
			      WS_ENC_END))
	    goto error;
    }

    return;

    /*
     * Error handling.
     */

error:

    ws_error_memory(compiler);
    return;
}
Example #23
0
void ws_expr_linearize(WsCompiler *compiler, WsExpression *expr)
{
    WsListItem *li;
    WsAsmIns *ins;

    switch (expr->type) {
    case WS_EXPR_COMMA:
        /* Linearize left. */
        ws_expr_linearize(compiler, expr->u.comma.left);

        /* Pop its result. */
        ws_asm_link(compiler, ws_asm_ins(compiler, expr->line, WS_ASM_POP));

        /* Linearize right */
        ws_expr_linearize(compiler, expr->u.comma.right);
        break;

    case WS_EXPR_ASSIGN:
        {
            WsNamespace *ns = ws_variable_lookup(compiler,
                                                 expr->u.assign.identifier);

            if (ns == NULL) {
                /* Unknown identifier. */
                ws_src_error(compiler, expr->line, "unknown variable `%s'",
                             expr->u.symbol);
                return;
            }

            if (expr->u.assign.op == '=') {
                /* Evaluate the expression. */
                ws_expr_linearize(compiler, expr->u.assign.expr);

                /* Store the value to the variable. */
                ws_asm_link(compiler,
                            ws_asm_variable(compiler, expr->line,
                                            WS_ASM_P_STORE_VAR, ns->vindex));
            } else if (expr->u.assign.op == tADDA) {
                /* Linearize the expression. */
                ws_expr_linearize(compiler, expr->u.assign.expr);

                /* Add it to the variable. */
                ws_asm_link(compiler,
                            ws_asm_variable(compiler, expr->line,
                                            WS_ASM_ADD_ASG, ns->vindex));
            } else if (expr->u.assign.op == tSUBA) {
                /* Linearize the expression. */
                ws_expr_linearize(compiler, expr->u.assign.expr);

                /* Substract it from the variable. */
                ws_asm_link(compiler,
                            ws_asm_variable(compiler, expr->line,
                                            WS_ASM_SUB_ASG, ns->vindex));
            } else {
                /* Load the old value from the variable. */
                ws_asm_link(compiler,
                            ws_asm_variable(compiler, expr->line,
                                            WS_ASM_P_LOAD_VAR, ns->vindex));

                /* Evaluate the expression. */
                ws_expr_linearize(compiler, expr->u.assign.expr);

                /* Perform the operand. */
                ins = NULL;
                switch (expr->u.assign.op) {
                case tMULA:
                    ins = ws_asm_ins(compiler, expr->line, WS_ASM_MUL);
                    break;

                case tDIVA:
                    ins = ws_asm_ins(compiler, expr->line, WS_ASM_DIV);
                    break;

                case tREMA:
                    ins = ws_asm_ins(compiler, expr->line, WS_ASM_REM);
                    break;

                case tADDA:
                    ins = ws_asm_ins(compiler, expr->line, WS_ASM_ADD);
                    break;

                case tSUBA:
                    ins = ws_asm_ins(compiler, expr->line, WS_ASM_SUB);
                    break;

                case tLSHIFTA:
                    ins = ws_asm_ins(compiler, expr->line, WS_ASM_B_LSHIFT);
                    break;

                case tRSSHIFTA:
                    ins = ws_asm_ins(compiler, expr->line, WS_ASM_B_RSSHIFT);
                    break;

                case tRSZSHIFTA:
                    ins = ws_asm_ins(compiler, expr->line, WS_ASM_B_RSZSHIFT);
                    break;

                case tANDA:
                    ins = ws_asm_ins(compiler, expr->line, WS_ASM_B_AND);
                    break;

                case tXORA:
                    ins = ws_asm_ins(compiler, expr->line, WS_ASM_B_XOR);
                    break;

                case tORA:
                    ins = ws_asm_ins(compiler, expr->line, WS_ASM_B_OR);
                    break;

                case tIDIVA:
                    ins = ws_asm_ins(compiler, expr->line, WS_ASM_IDIV);
                    break;

                default:
                    ws_fatal("ws_expr_linearize(): unknown assignment operand %x",
                             expr->u.assign.op);
                    break;
                }
                ws_asm_link(compiler, ins);

                /* Store the value to the variable. */
                ws_asm_link(compiler,
                            ws_asm_variable(compiler, expr->line,
                                            WS_ASM_P_STORE_VAR, ns->vindex));
            }
            /* The value of the assignment expression is the value
               assigned.  So, we must load the value from the variable.
               This would also be a good place for the `dup' operand but
               we lose since we don't have it. */
            ws_asm_link(compiler, ws_asm_variable(compiler, expr->line,
                                                  WS_ASM_P_LOAD_VAR, ns->vindex));
        }
        break;

    case WS_EXPR_CONDITIONAL:
        {
            WsAsmIns *l_else = ws_asm_label(compiler, expr->line);
            WsAsmIns *l_end = ws_asm_label(compiler, expr->line);

            /* Linearize condition. */
            ws_expr_linearize(compiler, expr->u.conditional.e_cond);

            /* If the result if false, jump to the else-branch. */
            ws_asm_link(compiler, ws_asm_branch(compiler, expr->line,
                                                WS_ASM_P_TJUMP, l_else));

            /* Linearize the then-expression and jump out. */
            ws_expr_linearize(compiler, expr->u.conditional.e_then);
            ws_asm_link(compiler, ws_asm_branch(compiler, expr->line,
                                                WS_ASM_P_JUMP, l_end));

            /* The else-branch. */
            ws_asm_link(compiler, l_else);
            ws_expr_linearize(compiler, expr->u.conditional.e_else);

            /* Insert the end label. */
            ws_asm_link(compiler, l_end);
        }
        break;

    case WS_EXPR_LOGICAL:
        {
            WsAsmIns *l_out = ws_asm_label(compiler, expr->line);

            /* Linearize the left-hand size expression. */
            ws_expr_linearize(compiler, expr->u.logical.left);

            /* Short-circuit check.  The type of the logical expression is
                      the short-circuit byte-code operand. */
            ws_asm_link(compiler, ws_asm_ins(compiler, expr->line,
                                             expr->u.logical.type));
            ws_asm_link(compiler, ws_asm_branch(compiler, expr->line,
                                                WS_ASM_P_TJUMP, l_out));

            /* Linearize the right-hand size expression. */
            ws_expr_linearize(compiler, expr->u.logical.right);

            /* The result of a logical expression should be boolean.
             * Control statements do automatic conversion, but typeof()
	     * does not. */
            ws_asm_link(compiler, ws_asm_ins(compiler, expr->line,
                                         WS_ASM_TOBOOL));

            /* Insert the end label. */
            ws_asm_link(compiler, l_out);
        }
        break;

    case WS_EXPR_BINARY:
        /* Linearize left and right. */
        ws_expr_linearize(compiler, expr->u.binary.left);
        ws_expr_linearize(compiler, expr->u.binary.right);

        /* The type of the binary expression is the byte-code opcode. */
        ws_asm_link(compiler, ws_asm_ins(compiler, expr->line,
                                         expr->u.binary.type));
        break;

    case WS_EXPR_UNARY:
        /* Linearize the expression. */
        ws_expr_linearize(compiler, expr->u.unary.expr);

        /* The type of the unary expression is the byte-code opcode. */
        ws_asm_link(compiler, ws_asm_ins(compiler, expr->line,
                                         expr->u.unary.type));
        break;

    case WS_EXPR_UNARY_VAR:
        {
            WsNamespace *ns = ws_variable_lookup(compiler,
                                                 expr->u.unary_var.variable);
            if (ns == NULL) {
                /* An unknown identifier. */
                ws_src_error(compiler, expr->line, "unknown variable `%s'",
                             expr->u.unary_var.variable);
                return;
            }

            /* First, do the operation. */
            if (expr->u.unary_var.addp)
                ws_asm_link(compiler,
                            ws_asm_variable(compiler, expr->line, WS_ASM_P_INCR_VAR,
                                            ns->vindex));
            else
                ws_asm_link(compiler,
                            ws_asm_variable(compiler, expr->line, WS_ASM_DECR_VAR,
                                            ns->vindex));

            /* Second, load the new value of the variable. */
            ws_asm_link(compiler, ws_asm_variable(compiler, expr->line,
                                                  WS_ASM_P_LOAD_VAR, ns->vindex));
        }
        break;

    case WS_EXPR_POSTFIX_VAR:
        {
            WsNamespace *ns = ws_variable_lookup(compiler,
                                                 expr->u.postfix_var.variable);
            if (ns == NULL) {
                /* An unknown identifier. */
                ws_src_error(compiler, expr->line, "unknown variable `%s'",
                             expr->u.postfix_var.variable);
                return;
            }

            /* First, load the old value of the variable. */
            ws_asm_link(compiler, ws_asm_variable(compiler, expr->line,
                                                  WS_ASM_P_LOAD_VAR, ns->vindex));

            /* Second, do the operation. */
            if (expr->u.unary_var.addp)
                ws_asm_link(compiler,
                            ws_asm_variable(compiler, expr->line, WS_ASM_P_INCR_VAR,
                                            ns->vindex));
            else
                ws_asm_link(compiler,
                            ws_asm_variable(compiler, expr->line, WS_ASM_DECR_VAR,
                                            ns->vindex));
        }
        break;

    case WS_EXPR_CALL:
        /* First, evaluate the arguments. */
        for (li = expr->u.call.arguments->head; li; li = li->next)
            ws_expr_linearize(compiler, li->data);

        /* Second, emit the call instruction. */
        switch (expr->u.call.type) {
        case ' ': 		/* LocalScriptFunctionCall */
            {
                WsFunctionHash *f = ws_function_hash(compiler, expr->u.call.name);

                if (f == NULL || !f->defined)
                {
                    ws_src_error(compiler, expr->line,
                                 "unknown local function `%s'",
                                 expr->u.call.name);
                    return;
                }

                /* Check that the function is called with correct amount
                          of arguments. */
                if (expr->u.call.arguments->num_items
                    != compiler->functions[f->findex].params->num_items)
                {
                    ws_src_error(compiler, expr->line,
                                 "invalid amount of arguments for `%s': "
                                 "expected %u, got %u",
                                 expr->u.call.name,
                                 compiler->functions[f->findex].params->num_items,
                                 expr->u.call.arguments->num_items);
                    return;
                }

                /* Emit assembler. */
                ws_asm_link(compiler, ws_asm_call(compiler, expr->line,
                                                  f->findex));
            }
            break;

        case '#': 		/* ExternalScriptFunctionCall */
            {
                WsPragmaUse *use = ws_hash_get(compiler->pragma_use_hash,
                                               expr->u.call.base);
                WsUInt16 findex;

                if (use == NULL)
                {
                    ws_src_error(compiler, expr->line,
                                 "unknown external compilation unit `%s'",
                                 expr->u.call.base);
                    return;
                }

                /* Insert the function name to the byte-code pool. */
                if (!ws_bc_add_const_utf8_string(
                        compiler->bc, &findex,
                        (unsigned char *) expr->u.call.name,
                        strlen(expr->u.call.name)))
                {
                    ws_error_memory(compiler);
                    return;
                }

                /* Emit assembler. */
                ws_asm_link(compiler,
                            ws_asm_call_url(compiler, expr->line,
                                            findex, use->urlindex,
                                            expr->u.call.arguments->num_items));
            }
            break;

        case '.': 		/* LibraryFunctionCall */
            {
                WsUInt16 lindex;
                WsUInt8 findex;
                WsUInt8 num_args;
                WsBool lindex_found;
                WsBool findex_found;

                if (!ws_stdlib_function(expr->u.call.base, expr->u.call.name,
                                        &lindex, &findex, &num_args,
                                        &lindex_found, &findex_found))
                {
                    if (!lindex_found)
                        ws_src_error(compiler, expr->line,
                                     "unknown system library `%s'",
                                     expr->u.call.base);
                    else
                        ws_src_error(compiler, expr->line,
                                     "unknown library function `%s.%s'",
                                     expr->u.call.base, expr->u.call.name);

                    return;
                }
                /* Check the argument count. */
                if (expr->u.call.arguments->num_items != num_args)
                {
                    ws_src_error(compiler, expr->line,
                                 "invalid amount of arguments for `%s.%s': "
                                 "expected %u, got %u",
                                 expr->u.call.base, expr->u.call.name,
                                 num_args, expr->u.call.arguments->num_items);
                    return;
                }

                /* Emit assembler. */
                ws_asm_link(compiler, ws_asm_call_lib(compiler, expr->line, findex,
                                                      lindex));
            }
            break;

        default:
            ws_fatal("ws_expr_linearize(): unknown call expression type %x",
                     expr->u.call.type);
            break;
        }
        break;

    case WS_EXPR_SYMBOL:
        {
            WsNamespace *ns = ws_variable_lookup(compiler, expr->u.symbol);

            if (ns == NULL) {
                /* An unknown identifier. */
                ws_src_error(compiler, expr->line, "unknown variable `%s'",
                             expr->u.symbol);
                return;
            }

            /* Create a load instruction for the variable. */
            ws_asm_link(compiler, ws_asm_variable(compiler, expr->line,
                                                  WS_ASM_P_LOAD_VAR, ns->vindex));
        }
        break;

    case WS_EXPR_CONST_INVALID:
        ws_asm_link(compiler, ws_asm_ins(compiler, expr->line,
                                         WS_ASM_CONST_INVALID));
        break;

    case WS_EXPR_CONST_TRUE:
        ws_asm_link(compiler, ws_asm_ins(compiler, expr->line,
                                         WS_ASM_CONST_TRUE));
        break;

    case WS_EXPR_CONST_FALSE:
        ws_asm_link(compiler, ws_asm_ins(compiler, expr->line,
                                         WS_ASM_CONST_FALSE));
        break;


    case WS_EXPR_CONST_INTEGER:
        if (expr->u.integer.ival == 0)
            ins = ws_asm_ins(compiler, expr->line, WS_ASM_CONST_0);
        else if (expr->u.integer.ival == 1 && expr->u.integer.sign == 1)
            ins = ws_asm_ins(compiler, expr->line, WS_ASM_CONST_1);
        else {
            WsUInt16 cindex;
	    WsInt32 ival;

            if (expr->u.integer.sign >= 0) {
		if (expr->u.integer.ival > (WsUInt32) WS_INT32_MAX)
		    ws_src_error(compiler, expr->line,
                                 "integer literal too large");
                ival = expr->u.integer.ival;
	    } else {
                if (expr->u.integer.ival > (WsUInt32) WS_INT32_MAX + 1)
		    ws_src_error(compiler, expr->line, "integer too small");
                ival = - (WsInt32) expr->u.integer.ival;
	    }

            if (!ws_bc_add_const_int(compiler->bc, &cindex, ival)) {
                ws_error_memory(compiler);
                return;
            }
            ins = ws_asm_load_const(compiler, expr->line, cindex);
        }

        ws_asm_link(compiler, ins);
        break;

    case WS_EXPR_CONST_FLOAT:
        {
            WsUInt16 cindex;

            if (!ws_bc_add_const_float(compiler->bc, &cindex, expr->u.fval)) {
                ws_error_memory(compiler);
                return;
            }

            ws_asm_link(compiler, ws_asm_load_const(compiler, expr->line, cindex));
        }
        break;

    case WS_EXPR_CONST_STRING:
        if (expr->u.string.len == 0)
            ins = ws_asm_ins(compiler, expr->line, WS_ASM_CONST_ES);
        else {
            WsUInt16 cindex;

            if (!ws_bc_add_const_utf8_string(compiler->bc, &cindex,
                                             expr->u.string.data,
                                             expr->u.string.len)) {
                ws_error_memory(compiler);
                return;
            }
            ins = ws_asm_load_const(compiler, expr->line, cindex);
        }

        ws_asm_link(compiler, ins);
        break;
    }
}
Example #24
0
void ws_stmt_linearize(WsCompiler *compiler, WsStatement *stmt)
{
    WsListItem *li;
    WsAsmIns *ins;

    switch (stmt->type) {
    case WS_STMT_BLOCK:
        for (li = stmt->u.block->head; li; li = li->next)
            ws_stmt_linearize(compiler, li->data);
        break;

    case WS_STMT_VARIABLE:
        linearize_variable_init(compiler, stmt->u.var, stmt->first_line);
        break;

    case WS_STMT_EMPTY:
        /* Nothing here. */
        break;

    case WS_STMT_EXPR:
        ws_expr_linearize(compiler, stmt->u.expr);

        /* Pop the expressions result from the stack.  Otherwise loops
           could eventually cause stack overflows. */
        ws_asm_link(compiler, ws_asm_ins(compiler, stmt->last_line, WS_ASM_POP));
        break;

    case WS_STMT_IF:
        {
            WsAsmIns *l_else = ws_asm_label(compiler,
                                            (stmt->u.s_if.s_else
                                             ? stmt->u.s_if.s_else->first_line
                                             : stmt->last_line));
            WsAsmIns *l_end = ws_asm_label(compiler, stmt->last_line);

            /* Linearize the expression. */
            ws_expr_linearize(compiler, stmt->u.s_if.expr);

            /* If the result is false, jump to the else-branch. */
            ws_asm_link(compiler, ws_asm_branch(compiler, stmt->first_line,
                                                WS_ASM_P_TJUMP, l_else));

            /* Else, execute the then-branch and jump to the end. */
            ws_stmt_linearize(compiler, stmt->u.s_if.s_then);
            ws_asm_link(compiler, ws_asm_branch(compiler, stmt->last_line,
                                                WS_ASM_P_JUMP, l_end));

            /* Then else-branch. */
            ws_asm_link(compiler, l_else);

            /* Linearize the else-branch if it is present. */
            if (stmt->u.s_if.s_else)
                ws_stmt_linearize(compiler, stmt->u.s_if.s_else);

            /* Insert the end label. */
            ws_asm_link(compiler, l_end);
        }
        break;

    case WS_STMT_FOR:
        {
            WsAsmIns *l_loop = ws_asm_label(compiler, stmt->first_line);
            WsAsmIns *l_cont = ws_asm_label(compiler, stmt->first_line);
            WsAsmIns *l_break = ws_asm_label(compiler, stmt->first_line);
            WsContBreak *cb;

            /* Store the labels to the compiler. */

            cb = ws_f_calloc(compiler->pool_stree, 1, sizeof(*cb));
            if (cb == NULL) {
                ws_error_memory(compiler);
                return;
            }

            cb->next = compiler->cont_break;
            compiler->cont_break = cb;

            cb->l_cont = l_cont;
            cb->l_break = l_break;

            /* Linearize the possible init code. */
            if (stmt->u.s_for.init)
                linearize_variable_init(compiler, stmt->u.s_for.init,
                                        stmt->first_line);
            else if (stmt->u.s_for.e1) {
                /* Linearize the init. */
                ws_expr_linearize(compiler, stmt->u.s_for.e1);

                /* Pop the result. */
                ws_asm_link(compiler, ws_asm_ins(compiler, stmt->first_line,
                                                 WS_ASM_POP));
            }

            /* Insert the loop label. */
            ws_asm_link(compiler, l_loop);

            /* Linearize the condition. */
            if (stmt->u.s_for.e2) {
                ws_expr_linearize(compiler, stmt->u.s_for.e2);

                /* If false, jump out. */
                ws_asm_link(compiler, ws_asm_branch(compiler, stmt->first_line,
                                                    WS_ASM_P_TJUMP, l_break));
            }

            /* Linearize the body statement. */
            ws_stmt_linearize(compiler, stmt->u.s_for.stmt);

            /* Link the continue label. */
            ws_asm_link(compiler, l_cont);

            /* Linearize the update expression. */
            if (stmt->u.s_for.e3) {
                ws_expr_linearize(compiler, stmt->u.s_for.e3);

                /* Pop the result. */
                ws_asm_link(compiler, ws_asm_ins(compiler, stmt->first_line,
                                                 WS_ASM_POP));
            }

            /* Jump to the loop label to check the condition. */
            ws_asm_link(compiler, ws_asm_branch(compiler, stmt->last_line,
                                                WS_ASM_P_JUMP, l_loop));

            /* Insert the break label. */
            ws_asm_link(compiler, l_break);

            /* Pop the cont-break block. */
            compiler->cont_break = compiler->cont_break->next;
        }
        break;

    case WS_STMT_WHILE:
        {
            WsAsmIns *l_cont = ws_asm_label(compiler, stmt->first_line);
            WsAsmIns *l_break = ws_asm_label(compiler,
                                             stmt->u.s_while.stmt->last_line);
            WsContBreak *cb;

            /* Store the labels to the compiler. */

            cb = ws_f_calloc(compiler->pool_stree, 1, sizeof(*cb));
            if (cb == NULL) {
                ws_error_memory(compiler);
                return;
            }

            cb->next = compiler->cont_break;
            compiler->cont_break = cb;

            cb->l_cont = l_cont;
            cb->l_break = l_break;

            /* Insert the continue label. */
            ws_asm_link(compiler, l_cont);

            /* Linearize the expression. */
            ws_expr_linearize(compiler, stmt->u.s_while.expr);

            /* If false, jump out. */
            ws_asm_link(compiler, ws_asm_branch(compiler, stmt->first_line,
                                                WS_ASM_P_TJUMP, l_break));

            /* Linearize the body statement. */
            ws_stmt_linearize(compiler, stmt->u.s_while.stmt);

            /* And jump to the continue label to check the expression. */
            ws_asm_link(compiler, ws_asm_branch(compiler, stmt->last_line,
                                                WS_ASM_P_JUMP, l_cont));

            /* Insert the break label. */
            ws_asm_link(compiler, l_break);

            /* Pop the cont-break block. */
            compiler->cont_break = compiler->cont_break->next;
        }
        break;

    case WS_STMT_CONTINUE:
        if (compiler->cont_break == NULL)
            ws_src_error(compiler, stmt->first_line,
                         "continue statement not within a loop");

        ws_asm_link(compiler, ws_asm_branch(compiler, stmt->first_line,
                                            WS_ASM_P_JUMP,
                                            compiler->cont_break->l_cont));
        break;

    case WS_STMT_BREAK:
        if (compiler->cont_break == NULL)
            ws_src_error(compiler, stmt->first_line,
                         "break statement not within a loop");

        ws_asm_link(compiler, ws_asm_branch(compiler, stmt->first_line,
                                            WS_ASM_P_JUMP,
                                            compiler->cont_break->l_break));
        break;

    case WS_STMT_RETURN:
        if (stmt->u.expr) {
            /* Linearize the return value and return it. */
            ws_expr_linearize(compiler, stmt->u.expr);
            ins = ws_asm_ins(compiler, stmt->first_line, WS_ASM_RETURN);
        } else
            /* Return an empty string. */
            ins = ws_asm_ins(compiler, stmt->first_line, WS_ASM_RETURN_ES);

        ws_asm_link(compiler, ins);
        break;
    }
}