libidav/davqlexec.c

Fri, 29 May 2015 14:16:45 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Fri, 29 May 2015 14:16:45 +0200
changeset 123
806c4dccf2ae
parent 104
6fb4d24d9df9
child 124
41939c8f3f9c
permissions
-rw-r--r--

added where clause compiler prototype

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 2015 Olaf Wintermann. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   1. Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *
 *   2. Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <ucx/utils.h>

#include "davqlexec.h"

DavQLResult* dav_statement_exec(DavSession *sn, DavQLStatement *st, ...) {
    va_list ap;
    va_start(ap, st);
    DavQLResult *result = dav_statement_execv(sn, st, ap);
    va_end(ap);
    return result;
}

DavQLResult* dav_statement_execv(DavSession *sn, DavQLStatement *st, va_list ap) {
    DavQLResult *result = dav_session_malloc(sn, sizeof(DavQLResult));
    result->result = NULL;
    result->status = 1;
    
    // make sure the statement was successfully parsed
    if(st->type == DAVQL_ERROR) {
        return result;
    }
    
    // get path string
    davqlerror_t error;
    UcxBuffer *path = dav_path_string(st->path, ap, &error);
    
    if(st->type == DAVQL_GET) {
        dav_exec_get(sn, st, path->space, ap);
    } else {
        // TODO
    }
    
    return result;
}

UcxBuffer* dav_path_string(sstr_t pathfmt, va_list ap, davqlerror_t *error) {
    UcxBuffer *path = ucx_buffer_new(NULL, 128, UCX_BUFFER_AUTOEXTEND);
    
    int placeholder = 0;
    for(int i=0;i<pathfmt.length;i++) {
        char c = pathfmt.ptr[i];
        if(placeholder) {
            if(c == '%') {
                // no placeholder, %% transposes to %
                ucx_buffer_putc(path, c);
            } else {
                // detect placeholder type and insert arg
                int err = 0;
                switch(c) {
                    case 's': {
                        char *arg = va_arg(ap, char*);
                        ucx_buffer_puts(path, arg);
                        break;
                    }
                    case 'd': {
                        int arg = va_arg(ap, int);
                        ucx_bprintf(path, "%d", arg);
                        break;
                    }
                    case 'u': {
                        unsigned int arg = va_arg(ap, unsigned int);
                        ucx_bprintf(path, "%u", arg);
                        break;
                    }
                    case 't': {
                        // time arguments doesn't make any sense in a path
                        *error = DAVQL_UNSUPPORTED_FORMATCHAR;
                        err = 1;
                        break;
                    }
                    default: {
                        *error = DAVQL_UNKNOWN_FORMATCHAR;
                        err = 1;
                    }
                }
                if(err) {
                    ucx_buffer_free(path);
                    return NULL;
                }
            }
            placeholder = 0;
        } else {
            if(c == '%') {
                placeholder = 1;
            } else {
                ucx_buffer_putc(path, c);
            }
        }
    }
    ucx_buffer_putc(path, '\0');
    *error = DAVQL_OK;
    return path;
}

void dav_exec_get(DavSession *sn, DavQLStatement *st, char* path, va_list ap) {
    // execute a davql get statement
    
    // TODO: get property list
    
    UcxBuffer *bcode = dav_compile_lexpr(st->where);
    printf("bcode: %.*s\n", bcode->size, bcode->space);
}

static int count_func_args(DavQLExpression *expr) {
    int count = 0;
    DavQLExpression *arg = expr->right;
    while(arg) {
        count++;
        if(arg->op == DAVQL_ARGLIST) {
            arg = arg->right;
        } else {
            break;
        }
    }
    return count;
}

static int add_cmd(UcxBuffer *bcode, DavQLExpression *expr) {
    if(!expr) {
        return 0;
    }
    
    int numcmd = 1;
    sstr_t src = expr->srctext;
    switch(expr->type) {
        case DAVQL_NUMBER: {
            ucx_bprintf(bcode, "number(%.*s) ", src.length, src.ptr);
            break;
        }
        case DAVQL_STRING: {
            // TODO: check format specifier
            ucx_bprintf(bcode, "string(%.*s) ", src.length, src.ptr);
            break;
        }
        case DAVQL_TIMESTAMP: {
            ucx_bprintf(bcode, "timestamp(%.*s) ", src.length, src.ptr);
            break;
        }
        case DAVQL_IDENTIFIER: {
            // TODO: check identifier type
            ucx_bprintf(bcode, "identifier(%.*s) ", src.length, src.ptr);
            break;
        }
        case DAVQL_UNARY: {
            numcmd += add_cmd(bcode, expr->left);
            switch(expr->op) {
                case DAVQL_ADD: {
                    ucx_bprintf(bcode, "unop_add ");
                    break;
                }
                case DAVQL_SUB: {
                    ucx_bprintf(bcode, "unop_sub ");
                    break;
                }
                case DAVQL_NEG: {
                    ucx_bprintf(bcode, "unop_neg ");
                    break;
                }
            }
            break;
        }
        case DAVQL_BINARY: {
            numcmd += add_cmd(bcode, expr->left);
            numcmd += add_cmd(bcode, expr->right);
            switch(expr->op) {
                case DAVQL_ADD: {
                    ucx_bprintf(bcode, "binop_add ");
                    break;
                }
                case DAVQL_SUB: {
                    ucx_bprintf(bcode, "binop_sub ");
                    break;
                }
                case DAVQL_MUL: {
                    ucx_bprintf(bcode, "binop_sub ");
                    break;
                }
                case DAVQL_DIV: {
                    ucx_bprintf(bcode, "binop_sub ");
                    break;
                }
                case DAVQL_AND: {
                    ucx_bprintf(bcode, "binop_sub ");
                    break;
                }
                case DAVQL_OR: {
                    ucx_bprintf(bcode, "binop_sub ");
                    break;
                }
                case DAVQL_XOR: {
                    ucx_bprintf(bcode, "binop_sub ");
                    break;
                }
            }
            break;
        }
        case DAVQL_LOGICAL: {
            if(expr->left && expr->right && expr->op != DAVQL_LOR) {
                numcmd += add_cmd(bcode, expr->left);
                numcmd += add_cmd(bcode, expr->right);
            }
            
            switch(expr->op) {
                case DAVQL_NOOP: {
                    break;
                }
                case DAVQL_NOT: {
                    numcmd += add_cmd(bcode, expr->left);
                    ucx_bprintf(bcode, "op_not ");
                    break;
                }
                case DAVQL_LAND: {
                    ucx_bprintf(bcode, "op_land ");
                    break;
                }
                case DAVQL_LOR: {
                    int nleft = add_cmd(bcode, expr->left);
                    ucx_bprintf(bcode, "op_lor_left(    ) ");
                    char *bcode_pos = bcode->space + bcode->size - 6;
                    int nright = add_cmd(bcode, expr->right);
                    char buf[5];
                    ssize_t n = snprintf(buf, 4, "%d", nright);
                    memcpy(bcode_pos, buf, n);
                    ucx_bprintf(bcode, "op_lor ");
                    numcmd += nleft + nright;
                    break;
                }
                case DAVQL_LXOR: {
                    ucx_bprintf(bcode, "op_lxor ");
                    break;
                }
                case DAVQL_EQ: {
                    ucx_bprintf(bcode, "op_eq ");
                    break;
                }
                case DAVQL_NEQ: {
                    ucx_bprintf(bcode, "op_neq ");
                    break;
                }
                case DAVQL_LT: {
                   ucx_bprintf(bcode, "op_lt ");
                    break;
                }
                case DAVQL_GT: {
                    ucx_bprintf(bcode, "op_gt ");
                    break;
                }
                case DAVQL_LE: {
                    ucx_bprintf(bcode, "op_le ");
                    break;
                }
                case DAVQL_GE: {
                    ucx_bprintf(bcode, "op_ge ");
                    break;
                }
                case DAVQL_LIKE: {
                    ucx_bprintf(bcode, "op_like ");
                    break;
                }
                case DAVQL_UNLIKE: {
                    ucx_bprintf(bcode, "op_unlike ");
                    break;
                }
            }
            break;
        }
        case DAVQL_FUNCCALL: {
            switch(expr->op) {
                case DAVQL_CALL: {
                    int nright = add_cmd(bcode, expr->right);
                    // TODO: count args
                    DavQLExpression *funcid = expr->left;
                    if(!funcid && funcid->type != DAVQL_IDENTIFIER) {
                        // fail
                        return -1;
                    }
                    
                    ucx_bprintf(bcode, "funcname(%.*s) numargs(%d) call ", funcid->srctext.length, funcid->srctext.ptr, count_func_args(expr));
                    numcmd = 3;
                    numcmd += nright;
                    break;
                }
                case DAVQL_ARGLIST: {
                    numcmd = 0;
                    numcmd += add_cmd(bcode, expr->left);
                    numcmd += add_cmd(bcode, expr->right);
                    break;
                }
            }
            break;
        }
    }
    return numcmd;
}

UcxBuffer* dav_compile_lexpr(DavQLExpression *lexpr) {
    UcxBuffer *bcode = ucx_buffer_new(NULL, 512, UCX_BUFFER_AUTOEXTEND);
    if(!bcode) {
        return NULL;
    }
    
    int numcmd = add_cmd(bcode, lexpr);
    
    return bcode;
}

mercurial