Sat, 30 May 2015 13:49:17 +0200
expression compiler generates byte code
dav/main.c | file | annotate | diff | comparison | revisions | |
libidav/davqlexec.c | file | annotate | diff | comparison | revisions | |
libidav/davqlexec.h | file | annotate | diff | comparison | revisions | |
libidav/utils.c | file | annotate | diff | comparison | revisions | |
libidav/webdav.h | file | annotate | diff | comparison | revisions |
--- a/dav/main.c Fri May 29 14:16:45 2015 +0200 +++ b/dav/main.c Sat May 30 13:49:17 2015 +0200 @@ -55,10 +55,10 @@ #include <libidav/davqlexec.h> void test() { DavQLStatement *stmt = dav_parse_statement(S( - "get * from / where (better or func(x, y, 1+1)) and -a = 2")); + "get * from / where name unlike '%d.%s'")); DavSession *sn = dav_session_new(ctx, "http://test/"); - dav_statement_exec(sn, stmt); + dav_statement_exec(sn, stmt, 123, "txt"); dav_debug_statement(stmt); dav_free_statement(stmt); }
--- a/libidav/davqlexec.c Fri May 29 14:16:45 2015 +0200 +++ b/libidav/davqlexec.c Sat May 30 13:49:17 2015 +0200 @@ -31,8 +31,8 @@ #include <string.h> #include <ucx/utils.h> - #include "davqlexec.h" +#include "utils.h" DavQLResult* dav_statement_exec(DavSession *sn, DavQLStatement *st, ...) { va_list ap; @@ -54,10 +54,10 @@ // get path string davqlerror_t error; - UcxBuffer *path = dav_path_string(st->path, ap, &error); + sstr_t path = dav_format_string(sn->mp->allocator, st->path, ap, &error); if(st->type == DAVQL_GET) { - dav_exec_get(sn, st, path->space, ap); + dav_exec_get(sn, st, path.ptr, ap); } else { // TODO } @@ -65,38 +65,37 @@ 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); +sstr_t dav_format_string(UcxAllocator *a, sstr_t fstr, va_list ap, davqlerror_t *error) { + UcxBuffer *buf = ucx_buffer_new(NULL, 128, UCX_BUFFER_AUTOEXTEND); int placeholder = 0; - for(int i=0;i<pathfmt.length;i++) { - char c = pathfmt.ptr[i]; + for(int i=0;i<fstr.length;i++) { + char c = fstr.ptr[i]; if(placeholder) { if(c == '%') { // no placeholder, %% transposes to % - ucx_buffer_putc(path, c); + ucx_buffer_putc(buf, 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); + ucx_buffer_puts(buf, arg); break; } case 'd': { int arg = va_arg(ap, int); - ucx_bprintf(path, "%d", arg); + ucx_bprintf(buf, "%d", arg); break; } case 'u': { unsigned int arg = va_arg(ap, unsigned int); - ucx_bprintf(path, "%u", arg); + ucx_bprintf(buf, "%u", arg); break; } case 't': { - // time arguments doesn't make any sense in a path - *error = DAVQL_UNSUPPORTED_FORMATCHAR; + // time arguments not supported for strings err = 1; break; } @@ -106,8 +105,11 @@ } } if(err) { - ucx_buffer_free(path); - return NULL; + ucx_buffer_free(buf); + sstr_t n; + n.ptr = NULL; + n.length = 0; + return n; } } placeholder = 0; @@ -115,22 +117,24 @@ if(c == '%') { placeholder = 1; } else { - ucx_buffer_putc(path, c); + ucx_buffer_putc(buf, c); } } } - ucx_buffer_putc(path, '\0'); *error = DAVQL_OK; - return path; + + return sstrdup_a(a, sstrn(buf->space, buf->size)); } void dav_exec_get(DavSession *sn, DavQLStatement *st, char* path, va_list ap) { // execute a davql get statement + UcxMempool *mp = ucx_mempool_new(128); // TODO: get property list - UcxBuffer *bcode = dav_compile_lexpr(st->where); - printf("bcode: %.*s\n", bcode->size, bcode->space); + UcxBuffer *bcode = dav_compile_expr(mp->allocator, st->where, ap); + + print_bytecode(bcode); } static int count_func_args(DavQLExpression *expr) { @@ -147,150 +151,207 @@ return count; } -static int add_cmd(UcxBuffer *bcode, DavQLExpression *expr) { +static int add_cmd(UcxAllocator *a, UcxBuffer *bcode, DavQLExpression *expr, va_list ap) { if(!expr) { return 0; } + + int numcmd = 1; + DavQLCmd cmd; + memset(&cmd, sizeof(DavQLCmd), 0); + davqlerror_t error; - int numcmd = 1; sstr_t src = expr->srctext; switch(expr->type) { - case DAVQL_NUMBER: { - ucx_bprintf(bcode, "number(%.*s) ", src.length, src.ptr); + case DAVQL_NUMBER: { + cmd.type = DAVQL_CMD_INT; + if(src.ptr[0] == '%') { + cmd.data.integer = va_arg(ap, int); + } else if(util_strtoint(src.ptr, &cmd.data.integer)) { + ucx_buffer_write(&cmd, sizeof(cmd), 1, bcode); + } else { + // error + return -1; + } + break; } case DAVQL_STRING: { - // TODO: check format specifier - ucx_bprintf(bcode, "string(%.*s) ", src.length, src.ptr); + cmd.type = DAVQL_CMD_STRING; + cmd.data.string = dav_format_string(a, src, ap, &error); + ucx_buffer_write(&cmd, sizeof(cmd), 1, bcode); break; } case DAVQL_TIMESTAMP: { - ucx_bprintf(bcode, "timestamp(%.*s) ", src.length, src.ptr); + if(src.ptr[0] == '%') { + cmd.data.timestamp = va_arg(ap, time_t); + ucx_buffer_write(&cmd, sizeof(cmd), 1, bcode); + } else { + // error + return -1; + } break; } case DAVQL_IDENTIFIER: { - // TODO: check identifier type - ucx_bprintf(bcode, "identifier(%.*s) ", src.length, src.ptr); + sstr_t propertyname = sstrchr(src, ':'); + cmd.type = DAVQL_CMD_RES_IDENTIFIER; + if(propertyname.length > 0) { + cmd.type = DAVQL_CMD_PROP_IDENTIFIER; + + // TODO + } else if(!sstrcmp(src, S("name"))) { + cmd.data.resprop = DAVQL_RES_NAME; + } else if(!sstrcmp(src, S("path"))) { + cmd.data.resprop = DAVQL_RES_PATH; + } else if(!sstrcmp(src, S("href"))) { + cmd.data.resprop = DAVQL_RES_HREF; + } else if(!sstrcmp(src, S("contentlength"))) { + cmd.data.resprop = DAVQL_RES_CONTENTLENGTH; + } else if(!sstrcmp(src, S("contenttype"))) { + cmd.data.resprop = DAVQL_RES_CONTENTTYPE; + } else if(!sstrcmp(src, S("creationdate"))) { + cmd.data.resprop = DAVQL_RES_CREATIONDATE; + } else if(!sstrcmp(src, S("lastmodified"))) { + cmd.data.resprop = DAVQL_RES_LASTMODIFIED; + } else if(!sstrcmp(src, S("iscollection"))) { + cmd.data.resprop = DAVQL_RES_ISCOLLECTION; + } + ucx_buffer_write(&cmd, sizeof(cmd), 1, bcode); break; } case DAVQL_UNARY: { - numcmd += add_cmd(bcode, expr->left); + numcmd += add_cmd(a, bcode, expr->left, ap); switch(expr->op) { case DAVQL_ADD: { - ucx_bprintf(bcode, "unop_add "); + cmd.type = DAVQL_CMD_OP_UNARY_ADD; break; } case DAVQL_SUB: { - ucx_bprintf(bcode, "unop_sub "); + cmd.type = DAVQL_CMD_OP_UNARY_SUB; break; } case DAVQL_NEG: { - ucx_bprintf(bcode, "unop_neg "); + cmd.type = DAVQL_CMD_OP_UNARY_NEG; break; } } + ucx_buffer_write(&cmd, sizeof(cmd), 1, bcode); break; } case DAVQL_BINARY: { - numcmd += add_cmd(bcode, expr->left); - numcmd += add_cmd(bcode, expr->right); + numcmd += add_cmd(a, bcode, expr->left, ap); + numcmd += add_cmd(a, bcode, expr->right, ap); switch(expr->op) { case DAVQL_ADD: { - ucx_bprintf(bcode, "binop_add "); + cmd.type = DAVQL_CMD_OP_BINARY_ADD; break; } case DAVQL_SUB: { - ucx_bprintf(bcode, "binop_sub "); + cmd.type = DAVQL_CMD_OP_BINARY_SUB; break; } case DAVQL_MUL: { - ucx_bprintf(bcode, "binop_sub "); + cmd.type = DAVQL_CMD_OP_BINARY_MUL; break; } case DAVQL_DIV: { - ucx_bprintf(bcode, "binop_sub "); + cmd.type = DAVQL_CMD_OP_BINARY_DIV; break; } case DAVQL_AND: { - ucx_bprintf(bcode, "binop_sub "); + cmd.type = DAVQL_CMD_OP_BINARY_AND; break; } case DAVQL_OR: { - ucx_bprintf(bcode, "binop_sub "); + cmd.type = DAVQL_CMD_OP_BINARY_OR; break; } case DAVQL_XOR: { - ucx_bprintf(bcode, "binop_sub "); + cmd.type = DAVQL_CMD_OP_BINARY_XOR; break; } } + ucx_buffer_write(&cmd, sizeof(cmd), 1, bcode); 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); + numcmd += add_cmd(a, bcode, expr->left, ap); + numcmd += add_cmd(a, bcode, expr->right, ap); } switch(expr->op) { - case DAVQL_NOOP: { - break; - } case DAVQL_NOT: { - numcmd += add_cmd(bcode, expr->left); - ucx_bprintf(bcode, "op_not "); + numcmd += add_cmd(a, bcode, expr->left, ap); + cmd.type = DAVQL_CMD_OP_LOGICAL_NOT; + ucx_buffer_write(&cmd, sizeof(cmd), 1, bcode); break; } case DAVQL_LAND: { - ucx_bprintf(bcode, "op_land "); + cmd.type = DAVQL_CMD_OP_LOGICAL_NOT; + ucx_buffer_write(&cmd, sizeof(cmd), 1, bcode); 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 "); + int nleft = add_cmd(a, bcode, expr->left, ap); + + cmd.type = DAVQL_CMD_OP_LOGICAL_OR_L; + DavQLCmd *or_l = (DavQLCmd*)(bcode->space + bcode->pos); + ucx_buffer_write(&cmd, sizeof(cmd), 1, bcode); + + int nright = add_cmd(a, bcode, expr->right, ap); + or_l->data.integer = nright + 1; + + cmd.type = DAVQL_CMD_OP_LOGICAL_OR; + cmd.data.integer = 0; + ucx_buffer_write(&cmd, sizeof(cmd), 1, bcode); + numcmd += nleft + nright; break; } case DAVQL_LXOR: { - ucx_bprintf(bcode, "op_lxor "); + cmd.type = DAVQL_CMD_OP_LOGICAL_XOR; + ucx_buffer_write(&cmd, sizeof(cmd), 1, bcode); break; } case DAVQL_EQ: { - ucx_bprintf(bcode, "op_eq "); + cmd.type = DAVQL_CMD_OP_EQ; + ucx_buffer_write(&cmd, sizeof(cmd), 1, bcode); break; } case DAVQL_NEQ: { - ucx_bprintf(bcode, "op_neq "); + cmd.type = DAVQL_CMD_OP_NEQ; + ucx_buffer_write(&cmd, sizeof(cmd), 1, bcode); break; } case DAVQL_LT: { - ucx_bprintf(bcode, "op_lt "); + cmd.type = DAVQL_CMD_OP_LT; + ucx_buffer_write(&cmd, sizeof(cmd), 1, bcode); break; } case DAVQL_GT: { - ucx_bprintf(bcode, "op_gt "); + cmd.type = DAVQL_CMD_OP_GT; + ucx_buffer_write(&cmd, sizeof(cmd), 1, bcode); break; } case DAVQL_LE: { - ucx_bprintf(bcode, "op_le "); + cmd.type = DAVQL_CMD_OP_LE; + ucx_buffer_write(&cmd, sizeof(cmd), 1, bcode); break; } case DAVQL_GE: { - ucx_bprintf(bcode, "op_ge "); + cmd.type = DAVQL_CMD_OP_GE; + ucx_buffer_write(&cmd, sizeof(cmd), 1, bcode); break; } case DAVQL_LIKE: { - ucx_bprintf(bcode, "op_like "); + cmd.type = DAVQL_CMD_OP_LIKE; + ucx_buffer_write(&cmd, sizeof(cmd), 1, bcode); break; } case DAVQL_UNLIKE: { - ucx_bprintf(bcode, "op_unlike "); + cmd.type = DAVQL_CMD_OP_UNLIKE; + ucx_buffer_write(&cmd, sizeof(cmd), 1, bcode); break; } } @@ -299,7 +360,7 @@ case DAVQL_FUNCCALL: { switch(expr->op) { case DAVQL_CALL: { - int nright = add_cmd(bcode, expr->right); + int nright = add_cmd(a, bcode, expr->right, ap); // TODO: count args DavQLExpression *funcid = expr->left; if(!funcid && funcid->type != DAVQL_IDENTIFIER) { @@ -307,15 +368,24 @@ return -1; } - ucx_bprintf(bcode, "funcname(%.*s) numargs(%d) call ", funcid->srctext.length, funcid->srctext.ptr, count_func_args(expr)); - numcmd = 3; + // numargs + cmd.type = DAVQL_CMD_INT; + cmd.data.integer = count_func_args(expr); + ucx_buffer_write(&cmd, sizeof(cmd), 1, bcode); + + // TODO: resolve function name + cmd.type = DAVQL_CMD_CALL; + cmd.data.func = NULL; + ucx_buffer_write(&cmd, sizeof(cmd), 1, bcode); + + numcmd = 2; numcmd += nright; break; } case DAVQL_ARGLIST: { numcmd = 0; - numcmd += add_cmd(bcode, expr->left); - numcmd += add_cmd(bcode, expr->right); + numcmd += add_cmd(a, bcode, expr->left, ap); + numcmd += add_cmd(a, bcode, expr->right, ap); break; } } @@ -325,13 +395,145 @@ return numcmd; } -UcxBuffer* dav_compile_lexpr(DavQLExpression *lexpr) { +UcxBuffer* dav_compile_expr(UcxAllocator *a, DavQLExpression *lexpr, va_list ap) { UcxBuffer *bcode = ucx_buffer_new(NULL, 512, UCX_BUFFER_AUTOEXTEND); if(!bcode) { return NULL; } - int numcmd = add_cmd(bcode, lexpr); + if(add_cmd(a, bcode, lexpr, ap) <= 0) { + ucx_buffer_free(bcode); + return NULL; + } return bcode; } + + +void print_bytecode(UcxBuffer *bcode) { + bcode->pos = 0; + DavQLCmd cmd; + while(ucx_buffer_read(&cmd, sizeof(DavQLCmd), 1, bcode) == 1) { + switch(cmd.type) { + case DAVQL_CMD_INT: { + printf("int %ll\n", cmd.data.integer); + break; + } + case DAVQL_CMD_STRING: { + printf("string \"%.*s\"\n", cmd.data.string.length, cmd.data.string.ptr); + break; + } + case DAVQL_CMD_TIMESTAMP: { + printf("timestamp %d\n", cmd.data.timestamp); + break; + } + case DAVQL_CMD_RES_IDENTIFIER: { + char *rid[8] = {"name", "path", "href", "contentlength", "contenttype", "creationdate", "lastmodified", "iscollection"}; + printf("resprop %s\n", rid[cmd.data.resprop]); + break; + } + case DAVQL_CMD_PROP_IDENTIFIER: { + printf("property %s:%s\n", cmd.data.property.ns, cmd.data.property.name); + break; + } + case DAVQL_CMD_OP_UNARY_ADD: { + printf("uadd\n"); + break; + } + case DAVQL_CMD_OP_UNARY_SUB: { + printf("usub\n"); + break; + } + case DAVQL_CMD_OP_UNARY_NEG: { + printf("uneg\n"); + break; + } + case DAVQL_CMD_OP_BINARY_ADD: { + printf("add\n"); + break; + } + case DAVQL_CMD_OP_BINARY_SUB: { + printf("sub\n"); + break; + } + case DAVQL_CMD_OP_BINARY_MUL: { + printf("mul\n"); + break; + } + case DAVQL_CMD_OP_BINARY_DIV: { + printf("div\n"); + break; + } + case DAVQL_CMD_OP_BINARY_AND: { + printf("and\n"); + break; + } + case DAVQL_CMD_OP_BINARY_OR: { + printf("or\n"); + break; + } + case DAVQL_CMD_OP_BINARY_XOR: { + printf("xor\n"); + break; + } + case DAVQL_CMD_OP_LOGICAL_NOT: { + printf("not\n"); + break; + } + case DAVQL_CMD_OP_LOGICAL_AND: { + printf("land\n"); + break; + } + case DAVQL_CMD_OP_LOGICAL_OR_L: { + printf("or_l %d\n", cmd.data.integer); + break; + } + case DAVQL_CMD_OP_LOGICAL_OR: { + printf("or\n"); + break; + } + case DAVQL_CMD_OP_LOGICAL_XOR: { + printf("lxor\n"); + break; + } + case DAVQL_CMD_OP_EQ: { + printf("eq\n"); + break; + } + case DAVQL_CMD_OP_NEQ: { + printf("neq\n"); + break; + } + case DAVQL_CMD_OP_LT: { + printf("lt\n"); + break; + } + case DAVQL_CMD_OP_GT: { + printf("gt\n"); + break; + } + case DAVQL_CMD_OP_LE: { + printf("le\n"); + break; + } + case DAVQL_CMD_OP_GE: { + printf("ge\n"); + break; + } + case DAVQL_CMD_OP_LIKE: { + printf("like\n"); + break; + } + case DAVQL_CMD_OP_UNLIKE: { + printf("unlike\n"); + break; + } + case DAVQL_CMD_CALL: { + printf("call %x\n", cmd.data.func); + break; + } + } + } + printf("\n"); +} +
--- a/libidav/davqlexec.h Fri May 29 14:16:45 2015 +0200 +++ b/libidav/davqlexec.h Sat May 30 13:49:17 2015 +0200 @@ -38,7 +38,10 @@ extern "C" { #endif -typedef struct DavQLResult DavQLResult; +typedef struct DavQLCmd DavQLCmd; +typedef struct DavQLStackObj DavQLStackObj; + +typedef void*(*davql_func)(); // TODO: interface? typedef enum { DAVQL_OK = 0, @@ -46,22 +49,82 @@ DAVQL_UNKNOWN_FORMATCHAR } davqlerror_t; -struct DavQLResult { - DavResource *result; - int status; +typedef enum { + DAVQL_CMD_INT = 0, + DAVQL_CMD_STRING, + DAVQL_CMD_TIMESTAMP, + DAVQL_CMD_RES_IDENTIFIER, + DAVQL_CMD_PROP_IDENTIFIER, + DAVQL_CMD_OP_UNARY_ADD, + DAVQL_CMD_OP_UNARY_SUB, + DAVQL_CMD_OP_UNARY_NEG, + DAVQL_CMD_OP_BINARY_ADD, + DAVQL_CMD_OP_BINARY_SUB, + DAVQL_CMD_OP_BINARY_MUL, + DAVQL_CMD_OP_BINARY_DIV, + DAVQL_CMD_OP_BINARY_AND, + DAVQL_CMD_OP_BINARY_OR, + DAVQL_CMD_OP_BINARY_XOR, + DAVQL_CMD_OP_LOGICAL_NOT, + DAVQL_CMD_OP_LOGICAL_AND, + DAVQL_CMD_OP_LOGICAL_OR_L, + DAVQL_CMD_OP_LOGICAL_OR, + DAVQL_CMD_OP_LOGICAL_XOR, + DAVQL_CMD_OP_EQ, + DAVQL_CMD_OP_NEQ, + DAVQL_CMD_OP_LT, + DAVQL_CMD_OP_GT, + DAVQL_CMD_OP_LE, + DAVQL_CMD_OP_GE, + DAVQL_CMD_OP_LIKE, + DAVQL_CMD_OP_UNLIKE, + DAVQL_CMD_CALL +} davqlcmdtype_t; + +typedef enum { + DAVQL_RES_NAME = 0, + DAVQL_RES_PATH, + DAVQL_RES_HREF, + DAVQL_RES_CONTENTLENGTH, + DAVQL_RES_CONTENTTYPE, + DAVQL_RES_CREATIONDATE, + DAVQL_RES_LASTMODIFIED, + DAVQL_RES_ISCOLLECTION +} davqlresprop_t; + +struct DavQLCmd { + davqlcmdtype_t type; + union DavQLCmdData { + int64_t integer; + sstr_t string; + time_t timestamp; + davqlresprop_t resprop; + DavPropName property; + davql_func func; + } data; +}; + +struct DavQLStackObj { + int32_t type; // 0: int, 1: string + uint32_t length; + union DavQLStackData { + int64_t integer; + char *string; + } data; }; DavQLResult* dav_statement_exec(DavSession *sn, DavQLStatement *st, ...); DavQLResult* dav_statement_execv(DavSession *sn, DavQLStatement *st, va_list ap); UcxBuffer* dav_path_string(sstr_t src, va_list ap, davqlerror_t *error); +sstr_t dav_format_string(UcxAllocator *a, sstr_t fstr, va_list ap, davqlerror_t *error); void dav_exec_get(DavSession *sn, DavQLStatement *st, char* path, va_list ap); -UcxBuffer* dav_compile_lexpr(DavQLExpression *lexpr); +UcxBuffer* dav_compile_expr(UcxAllocator *a, DavQLExpression *lexpr, va_list ap); - +void print_bytecode(UcxBuffer *bcode); #ifdef __cplusplus }
--- a/libidav/utils.c Fri May 29 14:16:45 2015 +0200 +++ b/libidav/utils.c Sat May 30 13:49:17 2015 +0200 @@ -30,6 +30,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <errno.h> #include <ucx/string.h> #include <ucx/buffer.h> #include <ucx/utils.h> @@ -75,8 +76,9 @@ int util_strtoint(char *str, int64_t *value) { char *end; + errno = 0; int64_t val = strtoll(str, &end, 0); - if(strlen(end) == 0) { + if(errno == 0) { *value = val; return 1; } else {
--- a/libidav/webdav.h Fri May 29 14:16:45 2015 +0200 +++ b/libidav/webdav.h Sat May 30 13:49:17 2015 +0200 @@ -45,7 +45,7 @@ typedef struct DavProxy DavProxy; typedef struct DavSession DavSession; typedef struct DavResource DavResource; -typedef struct DavRequest DavRequest; +typedef struct DavQLResult DavQLResult; typedef struct DavNamespace DavNamespace; typedef struct DavProperty DavProperty; typedef struct DavPropName DavPropName; @@ -145,6 +145,11 @@ char *name; }; +struct DavQLResult { + DavResource *result; + int status; +}; + #define DAV_KEY_AES128 0 #define DAV_KEY_AES256 1 #define DAV_KEY_PASSWORD 2