static int iter_correl(strm_stream* strm, strm_value data) { struct correl_data* d = strm->data; strm_value *v; double dx, dy; if (!strm_array_p(data) || strm_ary_len(data) != 2) { strm_raise(strm, "invalid data"); return STRM_NG; } v = strm_ary_ptr(data); if (!strm_number_p(v[0]) || !strm_number_p(v[1])) { strm_raise(strm, "correl() requires [num, num]"); return STRM_NG; } d->n++; dx = strm_value_flt(v[0]) - d->sx; d->sx += dx / d->n; dy = strm_value_flt(v[1]) - d->sy; d->sy += dy / d->n; d->sxx += (d->n-1) * dx * dx / d->n; d->syy += (d->n-1) * dy * dy / d->n; d->sxy += (d->n-1) * dx * dy / d->n; return STRM_OK; }
static int iter_rbk(strm_stream* strm, strm_value data) { struct rbk_data *d = strm->data; strm_value k, v; khiter_t i; int r; if (!strm_array_p(data) || strm_ary_len(data) != 2) { strm_raise(strm, "reduce_by_key element must be a key-value pair"); return STRM_NG; } k = strm_ary_ptr(data)[0]; v = strm_ary_ptr(data)[1]; i = kh_put(rbk, d->tbl, k, &r); if (r < 0) { /* r<0 operation failed */ return STRM_NG; } if (r != 0) { /* key does not exist */ kh_value(d->tbl, i) = v; } else { strm_value args[3]; args[0] = k; args[1] = kh_value(d->tbl, i); args[2] = v; if (strm_funcall(strm, d->func, 3, args, &v) == STRM_NG) { return STRM_NG; } kh_value(d->tbl, i) = v; } return STRM_OK; }
static int exec_seq(strm_stream* strm, int argc, strm_value* args, strm_value* ret) { strm_int start=1, end=-1, inc=1; struct seq_data* d; switch (argc) { case 0: break; case 1: end = strm_value_int(args[0]); break; case 2: start = strm_value_int(args[0]); end = strm_value_int(args[1]); break; case 3: start = strm_value_int(args[0]); inc = strm_value_int(args[1]); end = strm_value_int(args[2]); break; default: strm_raise(strm, "wrong number of arguments"); return STRM_NG; } d = malloc(sizeof(struct seq_data)); d->n = start; d->inc = inc; d->end = end; *ret = strm_stream_value(strm_stream_new(strm_producer, gen_seq, NULL, (void*)d)); return STRM_OK; }
static int lambda_call(strm_stream* strm, strm_value func, int argc, strm_value* argv, strm_value* ret) { strm_lambda lambda = strm_value_lambda(func); node_lambda* nlbd = lambda->body; node_args* args = (node_args*)nlbd->args; strm_state c = {0}; int i, n; node_error* exc; c.prev = lambda->state; if ((args == NULL && argc != 0) || (args->len != argc)) { if (strm) { strm_raise(strm, "wrong number of arguments"); strm->exc->fname = nlbd->fname; strm->exc->lineno = nlbd->lineno; } return STRM_NG; } for (i=0; i<argc; i++) { n = strm_var_set(&c, node_to_sym(args->data[i]), argv[i]); if (n) return n; } n = exec_expr(strm, &c, nlbd->compstmt, ret); if (n == STRM_NG && strm) { exc = strm->exc; if (exc && exc->type == NODE_ERROR_RETURN) { *ret = exc->arg; } } return n; }
static int exec_call(strm_stream* strm, strm_state* state, strm_string name, int argc, strm_value* argv, strm_value* ret) { int n = STRM_NG; strm_value m; if (argc > 0) { strm_state* ns = strm_value_ns(argv[0]); if (ns) { n = strm_var_get(ns, name, &m); } else if (argc == 1 && strm_array_p(argv[0])) { m = strm_str_value(name); n = ary_get(strm, argv[0], 1, &m, ret); if (n == STRM_OK) return STRM_OK; } } if (n == STRM_NG) { n = strm_var_get(state, name, &m); } if (n == STRM_OK) { return strm_funcall(strm, m, argc, argv, ret); } strm_raise(strm, "function not found"); return STRM_NG; }
int strm_funcall(strm_stream* strm, strm_value func, int argc, strm_value* argv, strm_value* ret) { switch (strm_value_tag(func)) { case STRM_TAG_CFUNC: return (strm_value_cfunc(func))(strm, argc, argv, ret); case STRM_TAG_ARRAY: return ary_get(strm, func, argc, argv, ret); case STRM_TAG_PTR: if (!strm_lambda_p(func)) { strm_raise(strm, "not a function"); return STRM_NG; } else { return lambda_call(strm, func, argc, argv, ret); } default: strm_raise(strm, "not a function"); break; } return STRM_NG; }
static strm_value convert_number(strm_stream* strm, strm_value data, strm_value func) { strm_value val; if (strm_funcall(strm, func, 1, &data, &val) == STRM_NG) { return STRM_NG; } if (!strm_number_p(val)) { strm_raise(strm, "number required"); return STRM_NG; } return val; }
static int exec_drop(strm_stream* strm, int argc, strm_value* args, strm_value* ret) { struct take_data* d; strm_int n; strm_get_args(strm, argc, args, "i", &n); if (n < 0) { strm_raise(strm, "negative iteration"); return STRM_NG; } d = malloc(sizeof(*d)); if (!d) return STRM_NG; d->n = n; *ret = strm_stream_value(strm_stream_new(strm_filter, iter_drop, NULL, (void*)d)); return STRM_OK; }
static int exec_cycle(strm_stream* strm, int argc, strm_value* args, strm_value* ret) { strm_array a; strm_int n = -1; struct cycle_data *d; strm_get_args(strm, argc, args, "A|i", &a, &n); if (argc == 2 && n <= 0) { strm_raise(strm, "invalid count number"); return STRM_NG; } d = malloc(sizeof(*d)); d->ary = a; d->count = n; *ret = strm_stream_value(strm_stream_new(strm_producer, gen_cycle, fin_cycle, (void*)d)); return STRM_OK; }
static int exec_repeat(strm_stream* strm, int argc, strm_value* args, strm_value* ret) { strm_value v; strm_int n = -1; struct repeat_data *d; strm_get_args(strm, argc, args, "v|i", &v, &n); if (argc == 2 && n <= 0) { strm_raise(strm, "invalid count number"); return STRM_NG; } d = malloc(sizeof(*d)); d->v = v; d->count = n; *ret = strm_stream_value(strm_stream_new(strm_producer, gen_repeat, fin_repeat, (void*)d)); return STRM_OK; }
static int iter_bar(strm_stream* strm, strm_value data) { struct bar_data* d = strm->data; double f, max = 1.0; if (interrupt) { interrupt = FALSE; strm_unsignal(SIGINT, sigupdate); move_cursor(d->row-1, 1); show_cursor(); exit(1); } if (!strm_number_p(data)) { strm_raise(strm, "invalid data"); return STRM_NG; } if (winch) { winch = FALSE; free(d->data); if (init_bar(d) == STRM_NG) { strm_stream_close(strm); return STRM_NG; } } f = strm_value_float(data); if (f < 0) f = 0; d->data[d->offset++] = f; max = 1.0; for (int i=0; i<d->dlen; i++) { f = d->data[i]; if (f > max) max = f; } d->max = max; if (d->offset == d->dlen) { d->offset = 0; } show_graph(d); return STRM_OK; }
static int iter_flatmap(strm_stream* strm, strm_value data) { struct map_data* d = strm->data; strm_value val; strm_int i, len; strm_value* e; if (strm_funcall(strm, d->func, 1, &data, &val) == STRM_NG) { return STRM_NG; } if (!strm_array_p(val)) { strm_raise(strm, "no array given for flatmap"); return STRM_NG; } len = strm_ary_len(val); e = strm_ary_ptr(val); for (i=0; i<len; i++){ strm_emit(strm, e[i], NULL); } return STRM_OK; }
int strm_funcall(strm_state* state, strm_value func, int argc, strm_value* argv, strm_value* ret) { switch (strm_value_tag(func)) { case STRM_TAG_CFUNC: return (strm_value_cfunc(func))(state, argc, argv, ret); case STRM_TAG_ARRAY: return ary_get(state, func, argc, argv, ret); case STRM_TAG_PTR: if (!strm_lambda_p(func)) { strm_raise(state, "not a function"); return STRM_NG; } else { strm_lambda lambda = strm_value_lambda(func); node_lambda* nlbd = lambda->body; node_args* args = (node_args*)nlbd->args; strm_state c = {0}; int i, n; c.prev = lambda->state; if ((args == NULL && argc != 0) && (args->len != argc)) return STRM_NG; for (i=0; i<argc; i++) { n = strm_var_set(&c, node_to_sym(args->data[i]), argv[i]); if (n) return n; } n = exec_expr(&c, nlbd->compstmt, ret); if (c.exc && c.exc->type == NODE_ERROR_RETURN) { *ret = c.exc->arg; return STRM_OK; } return n; } default: break; } return STRM_NG; }
static int ary_get(strm_stream* strm, strm_value ary, int argc, strm_value* argv, strm_value* ret) { struct strm_array* a; strm_value idx; if (argc != 1) { strm_raise(strm, "wrong number of arguments"); return STRM_NG; } a = strm_ary_struct(ary); idx = argv[0]; if (strm_num_p(idx)) { strm_int i = strm_value_int(idx); if (i>=a->len) return STRM_NG; *ret = a->ptr[i]; return STRM_OK; } if (strm_string_p(idx)) { if (a->headers) { strm_int i, len = a->len; for (i=0; i<len; i++) { if (strm_str_eq(strm_value_str(idx), strm_value_str(strm_ary_ptr(a->headers)[i]))) { *ret = a->ptr[i]; return STRM_OK; } } } } return STRM_NG; }
static int exec_bar(strm_stream* strm, int argc, strm_value* args, strm_value* ret) { strm_value lhs, rhs; assert(argc == 2); /* int x int */ if (strm_int_p(args[0]) && strm_int_p(args[1])) { *ret = strm_int_value(strm_value_int(args[0])|strm_value_int(args[1])); return STRM_OK; } lhs = args[0]; /* lhs: io */ if (strm_io_p(lhs)) { lhs = strm_stream_value(strm_io_stream(lhs, STRM_IO_READ)); } /* lhs: lambda */ else if (strm_lambda_p(lhs)) { strm_lambda lmbd = strm_value_lambda(lhs); lhs = strm_stream_value(strm_stream_new(strm_filter, blk_exec, NULL, (void*)lmbd)); } /* lhs: array */ else if (strm_array_p(lhs)) { struct array_data *arrd = malloc(sizeof(struct array_data)); arrd->arr = strm_value_ary(lhs); arrd->n = 0; lhs = strm_stream_value(strm_stream_new(strm_producer, arr_exec, NULL, (void*)arrd)); } /* lhs: should be stream */ rhs = args[1]; /* rhs: io */ if (strm_io_p(rhs)) { rhs = strm_stream_value(strm_io_stream(rhs, STRM_IO_WRITE)); } /* rhs: lambda */ else if (strm_lambda_p(rhs)) { strm_lambda lmbd = strm_value_lambda(rhs); rhs = strm_stream_value(strm_stream_new(strm_filter, blk_exec, NULL, (void*)lmbd)); } /* rhs: cfunc */ else if (strm_cfunc_p(rhs)) { strm_cfunc func = strm_value_cfunc(rhs); rhs = strm_stream_value(strm_stream_new(strm_filter, cfunc_exec, NULL, func)); } /* stream x stream */ if (strm_stream_p(lhs) && strm_stream_p(rhs)) { strm_stream* lstrm = strm_value_stream(lhs); strm_stream* rstrm = strm_value_stream(rhs); if (lstrm == NULL || rstrm == NULL || lstrm->mode == strm_consumer || rstrm->mode == strm_producer) { strm_raise(strm, "stream error"); return STRM_NG; } strm_stream_connect(strm_value_stream(lhs), strm_value_stream(rhs)); *ret = rhs; return STRM_OK; } strm_raise(strm, "type error"); return STRM_NG; }
static int str_split(strm_stream* strm, int argc, strm_value* args, strm_value* ret) { strm_string str; strm_string sep; const char* s; strm_int slen; const char* t; const char* p; const char* pend; char c; strm_int n = 0; strm_array ary; strm_value* sps; strm_int i; switch (argc) { case 1: str = args[0]; sep = strm_str_lit(" "); break; case 2: str = args[0]; if (!strm_string_p(args[1])) { strm_raise(strm, "need string separator"); return STRM_NG; } sep = strm_value_str(args[1]); break; default: strm_raise(strm, "wrong number of arguments"); return STRM_NG; } /* count number of split strings */ s = strm_str_ptr(sep); slen = strm_str_len(sep); c = s[0]; t = p = strm_str_ptr(str); pend = p + strm_str_len(str) - slen; n = 0; while (p<pend) { if (*p == c) { if (memcmp(p, s, slen) == 0) { if (!(slen == 1 && c == ' ' && (p-t) == 0)) { n++; } t = p + slen; } } p++; } n++; /* actual split */ ary = strm_ary_new(NULL, n); sps = strm_ary_ptr(ary); s = strm_str_ptr(sep); slen = strm_str_len(sep); c = s[0]; t = p = strm_str_ptr(str); pend = p + strm_str_len(str) - slen; i = 0; while (p<pend) { if (*p == c) { if (memcmp(p, s, slen) == 0) { if (!(slen == 1 && c == ' ' && (p-t) == 0)) { sps[i++] = strm_str_new(t, p-t); } t = p + slen; } } p++; } pend = strm_str_ptr(str) + strm_str_len(str); sps[i++] = strm_str_new(t, pend-t); *ret = strm_ary_value(ary); return STRM_OK; }
static int csv_accept(strm_stream* strm, strm_value data) { strm_array ary; strm_string line = strm_value_str(data); strm_value *bp; const char *fbeg; const char *ptr; const char *pend; int fieldcnt; int in_quote = 0, all_str = 1; int i = 0; enum csv_type ftype; enum csv_type* types; struct csv_data *cd = strm->data; if (cd->prev) { strm_int len = strm_str_len(cd->prev)+strm_str_len(line)+1; char* tmp = malloc(len); memcpy(tmp, strm_str_ptr(cd->prev), strm_str_len(cd->prev)); *(tmp+strm_str_len(cd->prev)) = '\n'; memcpy(tmp+strm_str_len(cd->prev)+1, strm_str_ptr(line), strm_str_len(line)); line = strm_str_new(tmp, len); free(tmp); cd->prev = strm_str_null; } fieldcnt = count_fields(line); if (fieldcnt == -1) { cd->prev = line; return STRM_NG; } if (cd->n > 0 && fieldcnt != cd->n) return STRM_NG; ptr = strm_str_ptr(line); pend = ptr + strm_str_len(line); ary = strm_ary_new(NULL, fieldcnt); if (!ary) return STRM_NG; bp = (strm_value*)strm_ary_ptr(ary); types = cd->types; ftype = types ? types[0] : TYPE_UNSPC; for (fbeg=ptr; ptr<pend; ptr++) { if (in_quote) { if (*ptr == '\"') { if (ptr[1] == '\"') { ptr++; ftype = TYPE_ESC; continue; } in_quote = 0; } continue; } switch(*ptr) { case '\"': in_quote = 1; if (ptr == fbeg) { ftype = TYPE_STR; fbeg = ptr+1; } else { ftype = TYPE_ESC; } continue; case ',': *bp = csv_value(fbeg, ptr-fbeg, ftype); if (!strm_string_p(*bp)) all_str = 0; bp++; fbeg = ptr+1; i++; ftype = types ? types[i] : TYPE_UNSPC; break; default: continue; } } /* trim newline at the end */ if (ptr[-1] == '\n') { ptr--; } /* trim carriage return at the end */ if (ptr[-1] == '\r') { ptr--; } *bp = csv_value(fbeg, ptr-fbeg, ftype); if (!strm_string_p(*bp)) all_str = 0; /* check headers */ if (!cd->headers && !cd->types) { if (all_str) { cd->headers = ary; ary = strm_ary_null; } cd->n = fieldcnt; } if (ary) { /* set headers if any */ if (cd->headers) strm_ary_headers(ary) = cd->headers; if (!cd->types) { /* first data line (after optinal header line) */ if (cd->headers) { if (all_str) { /* data line is all string; emit header line */ strm_emit(strm, strm_ary_value(cd->headers), NULL); cd->headers = strm_ary_null; } else { /* intern header strings */ strm_array h = cd->headers; strm_value *p = strm_ary_ptr(h); int i; for (i=0; i<strm_ary_len(h); i++) { strm_string str = strm_value_str(p[i]); p[i] = strm_str_value(strm_str_intern_str(str)); } } } /* initialize types (determined by first data line) */ cd->types = malloc(sizeof(enum csv_type)*fieldcnt); if (!cd->types) return STRM_NG; for (i=0; i<fieldcnt; i++) { cd->types[i] = csv_type(strm_ary_ptr(ary)[i]); } } else { /* type check */ for (i=0; i<fieldcnt; i++) { if (cd->types[i] != csv_type(strm_ary_ptr(ary)[i])) { /* type mismatch (error); skip this line */ strm_raise(strm, "csv type mismatch"); return STRM_NG; } } } strm_emit(strm, strm_str_value(ary), NULL); } return STRM_OK; }
static int exec_expr(strm_stream* strm, strm_state* state, node* np, strm_value* val) { int n; if (np == NULL) { return STRM_NG; } switch (np->type) { /* case NODE_ARGS: break; */ case NODE_NS: { node_ns* ns = (node_ns*)np; strm_state* s = strm_ns_find(state, node_to_sym(ns->name)); if (!s) { strm_raise(strm, "failed to create namespace"); return STRM_NG; } return exec_expr(strm, s, ns->body, val); } case NODE_IMPORT: { node_import *ns = (node_import*)np; strm_state* s = strm_ns_get(node_to_sym(ns->name)); if (!s) { strm_raise(strm, "no such namespace"); return STRM_NG; } n = strm_env_copy(state, s); if (n) { strm_raise(strm, "failed to import"); return n; } return STRM_OK; } break; case NODE_SKIP: strm_set_exc(strm, NODE_ERROR_SKIP, strm_nil_value()); return STRM_OK; case NODE_EMIT: { int i, n; node_array* v0; v0 = (node_array*)((node_emit*)np)->emit; if (!v0) { strm_emit(strm, strm_nil_value(), NULL); } else { for (i = 0; i < v0->len; i++) { n = exec_expr(strm, state, v0->data[i], val); if (n) return n; strm_emit(strm, *val, NULL); } } return STRM_OK; } break; case NODE_LET: { node_let *nlet = (node_let*)np; n = exec_expr(strm, state, nlet->rhs, val); if (n) { strm_raise(strm, "failed to assign"); return n; } return strm_var_set(state, node_to_sym(nlet->lhs), *val); } case NODE_ARRAY: { node_array* v0 = (node_array*)np; strm_array arr = strm_ary_new(NULL, v0->len); strm_value *ptr = (strm_value*)strm_ary_ptr(arr); int i=0; for (i = 0; i < v0->len; i++, ptr++) { n = exec_expr(strm, state, v0->data[i], ptr); if (n) return n; } if (v0->headers) { strm_ary_headers(arr) = ary_headers(v0->headers, v0->len); } if (v0->ns) { strm_ary_ns(arr) = strm_ns_get(node_to_sym(v0->ns)); } else { strm_ary_ns(arr) = strm_str_null; } *val = strm_ary_value(arr); return STRM_OK; } case NODE_IDENT: { node_ident* ni = (node_ident*)np; n = strm_var_get(state, node_to_sym(ni->name), val); if (n) { strm_raise(strm, "failed to reference variable"); } return n; } case NODE_IF: { strm_value v; node_if* nif = (node_if*)np; n = exec_expr(strm, state, nif->cond, &v); if (n) return n; if (strm_bool_p(v) && strm_value_bool(v)) { return exec_expr(strm, state, nif->then, val); } else if (nif->opt_else != NULL) { return exec_expr(strm, state, nif->opt_else, val); } else { *val = strm_nil_value(); return STRM_OK; } } break; case NODE_OP: { node_op* nop = (node_op*)np; strm_value args[2]; int i=0; if (nop->lhs) { n = exec_expr(strm, state, nop->lhs, &args[i++]); if (n) return n; } if (nop->rhs) { n = exec_expr(strm, state, nop->rhs, &args[i++]); if (n) return n; } return exec_call(strm, state, node_to_sym(nop->op), i, args, val); } break; case NODE_LAMBDA: { strm_lambda lambda = malloc(sizeof(struct strm_lambda)); if (!lambda) return STRM_NG; lambda->type = STRM_PTR_LAMBDA; lambda->body = (node_lambda*)np; lambda->state = state; *val = strm_ptr_value(lambda); return STRM_OK; } break; case NODE_CALL: { /* TODO: wip code of ident */ node_call* ncall = (node_call*)np; int i; node_nodes* v0 = (node_nodes*)ncall->args; strm_value *args = malloc(sizeof(strm_value)*v0->len); for (i = 0; i < v0->len; i++) { n = exec_expr(strm, state, v0->data[i], &args[i]); if (n) return n; } return exec_call(strm, state, node_to_sym(ncall->ident), i, args, val); } break; case NODE_RETURN: { node_return* nreturn = (node_return*)np; node_nodes* args = (node_nodes*)nreturn->rv; strm_value arg; if (!args) { arg = strm_nil_value(); } else { switch (args->len) { case 0: arg = strm_nil_value(); break; case 1: n = exec_expr(strm, state, args->data[0], &arg); if (n) return n; break; default: { strm_array ary = strm_ary_new(NULL, args->len); strm_int i; for (i=0; i<args->len; i++) { n = exec_expr(strm, state, args->data[i], (strm_value*)&strm_ary_ptr(ary)[i]); if (n) return n; } } break; } } strm_set_exc(strm, NODE_ERROR_RETURN, arg); return STRM_OK; } break; case NODE_NODES: { int i; node_nodes* v = (node_nodes*)np; for (i = 0; i < v->len; i++) { n = exec_expr(strm, state, v->data[i], val); if (n) { if (strm) { node_error* exc = strm->exc; if (exc != NULL) { node* n = v->data[i]; exc->fname = n->fname; exc->lineno = n->lineno; } } return n; } } } return STRM_OK; case NODE_INT: *val = strm_int_value(((node_int*)np)->value); return STRM_OK; case NODE_FLOAT: *val = strm_int_value(((node_float*)np)->value); return STRM_OK; case NODE_BOOL: *val = strm_bool_value(((node_bool*)np)->value); return STRM_OK; case NODE_NIL: *val = strm_nil_value(); return STRM_OK; case NODE_STR: *val = strm_str_value(node_to_str(((node_str*)np)->value)); return STRM_OK; default: break; } return STRM_NG; }
static int exec_bar(strm_state* state, int argc, strm_value* args, strm_value* ret) { strm_value lhs, rhs; assert(argc == 2); /* int x int */ if (strm_int_p(args[0]) && strm_int_p(args[1])) { *ret = strm_int_value(strm_value_int(args[0])|strm_value_int(args[1])); return STRM_OK; } lhs = args[0]; /* lhs: io */ if (strm_io_p(lhs)) { strm_io io = strm_value_io(lhs); lhs = strm_task_value(strm_io_open(io, STRM_IO_READ)); } /* lhs: lambda */ else if (strm_lambda_p(lhs)) { strm_lambda lmbd = strm_value_lambda(lhs); lhs = strm_task_value(strm_task_new(strm_task_filt, blk_exec, NULL, (void*)lmbd)); } /* lhs: array */ else if (strm_array_p(lhs)) { struct array_data *arrd = malloc(sizeof(struct array_data)); arrd->arr = strm_value_ary(lhs); arrd->n = 0; lhs = strm_task_value(strm_task_new(strm_task_prod, arr_exec, NULL, (void*)arrd)); } /* lhs: should be task */ rhs = args[1]; /* rhs: io */ if (strm_io_p(rhs)) { strm_io io = strm_value_io(rhs); rhs = strm_task_value(strm_io_open(io, STRM_IO_WRITE)); } /* rhs: lambda */ else if (strm_lambda_p(rhs)) { strm_lambda lmbd = strm_value_lambda(rhs); rhs = strm_task_value(strm_task_new(strm_task_filt, blk_exec, NULL, (void*)lmbd)); } /* rhs: cfunc */ else if (strm_cfunc_p(rhs)) { strm_cfunc func = strm_value_cfunc(rhs); rhs = strm_task_value(strm_task_new(strm_task_filt, cfunc_exec, NULL, func)); } /* task x task */ if (strm_task_p(lhs) && strm_task_p(rhs)) { if (strm_value_task(lhs) == NULL || strm_value_task(rhs) == NULL) { strm_raise(state, "task error"); return STRM_NG; } strm_task_connect(strm_value_task(lhs), strm_value_task(rhs)); *ret = rhs; return STRM_OK; } strm_raise(state, "type error"); return STRM_NG; }