inner let vals
authorMichael Wallner <mike@php.net>
Thu, 1 Sep 2016 14:53:12 +0000 (16:53 +0200)
committerMichael Wallner <mike@php.net>
Tue, 18 Oct 2016 08:26:25 +0000 (10:26 +0200)
src/context_validate.c
src/marshal.c
src/marshal.h
src/parser_def.h
src/parser_proc.y
src/types.h
src/types/let_func.h
src/types/let_vals.h [new file with mode: 0644]

index 8add34d5ec53be4697a038b4e467e59c24517596..f7f517dfd37e86e40f944a66d1b9391313f6b3fb 100644 (file)
@@ -603,17 +603,27 @@ static inline int validate_decl(struct psi_data *data, void *dl, decl *decl) {
        }
        return 1;
 }
-static inline decl_arg *locate_decl_var_arg(decl_var *var, decl_args *args, decl_arg *func) {
+static inline decl_arg *locate_decl_arg(decl_args *args, const char *name) {
        size_t i;
 
        if (args) for (i = 0; i < args->count; ++i) {
                decl_arg *arg = args->args[i];
 
-               if (!strcmp(var->name, arg->var->name)) {
-                       ZEND_ASSERT(!var->arg || var->arg == arg);
-                       return var->arg = arg;
+               if (!strcmp(name, arg->var->name)) {
+                       return arg;
                }
        }
+
+       return NULL;
+}
+static inline decl_arg *locate_decl_var_arg(decl_var *var, decl_args *args, decl_arg *func) {
+       decl_arg *arg = locate_decl_arg(args, var->name);
+
+       if (arg) {
+               ZEND_ASSERT(!var->arg || var->arg == arg);
+               return var->arg = arg;
+       }
+
        if (func && !strcmp(var->name, func->var->name)) {
                return var->arg = func;
        }
@@ -936,16 +946,50 @@ static inline impl_arg *locate_impl_var_arg(impl_var *var, impl_args *args) {
        return NULL;
 }
 
-static inline int validate_let_func(struct psi_data *data, let_func *func, impl *impl) {
-       if (impl->func->args) {
-               if (!locate_impl_var_arg(func->var, impl->func->args)) {
-                       data->error(data, func->var->token, PSI_WARNING,
-                                       "Unknown variable '$%s' of `let` statement"
-                                       " for cast '%s' of implementation '%s'",
-                                       func->var->name, func->name, impl->func->name);
+static inline int validate_let_val(struct psi_data *data, let_val *val, decl_var *let_var, impl *impl);
+
+static inline const char *locate_let_val_varname(let_val *val) {
+       if (val) {
+               switch (val->kind) {
+               case PSI_LET_CALLBACK:
+                       return &val->data.callback->func->var->name[1];
+               case PSI_LET_FUNC:
+                       return &val->data.func->var->name[1];
+               default:
+                       break;
+               }
+       }
+       return NULL;
+}
+
+static inline int validate_let_func(struct psi_data *data, let_func *func, decl_var *let_var, impl *impl) {
+       if (func->outer) {
+               decl_type *var_typ = real_decl_type(let_var->arg->type);
+
+               switch (var_typ->type) {
+               case PSI_T_STRUCT:
+                       func->ref = locate_decl_arg(var_typ->real.strct->args, &func->var->name[1]);
+                       break;
+               case PSI_T_UNION:
+                       func->ref = locate_decl_arg(var_typ->real.unn->args, &func->var->name[1]);
+                       break;
+               default:
+                       data->error(data, let_var->token, PSI_WARNING,
+                                       "Inner let statement's values must refer to a structure type, got '%s' for '%s'",
+                                       real_decl_type(let_var->arg->type)->name, let_var->name);
                        return 0;
                }
        }
+       if (impl->func->args) {
+               locate_impl_var_arg(func->var, impl->func->args);
+       }
+       if (!func->var->arg && !func->ref) {
+               data->error(data, func->var->token, PSI_WARNING,
+                               "Unknown variable '$%s' of `let` statement"
+                               " for cast '%s' of implementation '%s'",
+                               func->var->name, func->name, impl->func->name);
+               return 0;
+       }
        switch (func->type) {
        case PSI_T_BOOLVAL:             func->handler = psi_let_boolval;        break;
        case PSI_T_INTVAL:              func->handler = psi_let_intval;         break;
@@ -956,8 +1000,46 @@ static inline int validate_let_func(struct psi_data *data, let_func *func, impl
        case PSI_T_ARRVAL:              func->handler = psi_let_arrval;         break;
        case PSI_T_OBJVAL:              func->handler = psi_let_objval;         break;
        case PSI_T_ZVAL:                func->handler = psi_let_zval;           break;
+       case PSI_T_VOID:                func->handler = psi_let_void;           break;
        EMPTY_SWITCH_DEFAULT_CASE();
        }
+
+       if (func->inner && func->ref) {
+               size_t i;
+               decl_type *var_typ = real_decl_type(let_var->arg->type);
+
+               switch (var_typ->type) {
+               case PSI_T_STRUCT:
+               case PSI_T_UNION:
+                       break;
+               default:
+                       data->error(data, let_var->token, PSI_WARNING,
+                                       "Inner let statement's values must refer to a structure type, got '%s' for '%s'",
+                                       real_decl_type(let_var->arg->type)->name, let_var->name);
+                       return 0;
+               }
+
+               for (i = 0; i < func->inner->count; ++i) {
+                       let_val *inner = func->inner->vals[i];
+                       let_val *outer = func->outer;
+                       const char *name = locate_let_val_varname(inner);
+                       decl_arg *sub_arg;
+
+                       if (name) {
+                               sub_arg = locate_decl_arg(var_typ->real.strct->args, name);
+                       }
+                       if (!name || !sub_arg) {
+                               data->error(data, let_var->token, PSI_WARNING,
+                                               "Unknown variable '%s' of '%s'",
+                                               name,
+                                               var_typ->real.strct->name);
+                               return 0;
+                       }
+                       if (!validate_let_val(data, inner, sub_arg->var, impl)) {
+                               return 0;
+                       }
+               }
+       }
        return 1;
 }
 
@@ -966,7 +1048,7 @@ static inline int validate_let_callback(struct psi_data *data, decl_var *cb_var,
        decl *cb_func;
        decl_type *cb_type = real_decl_type(cb_var->arg->type);
 
-       if (!validate_let_func(data, cb->func, impl)) {
+       if (!validate_let_func(data, cb->func, cb_var, impl)) {
                return 0;
        }
 
@@ -990,6 +1072,95 @@ static inline int validate_let_callback(struct psi_data *data, decl_var *cb_var,
        return 1;
 }
 
+static inline int validate_let_val(struct psi_data *data, let_val *val, decl_var *let_var, impl *impl) {
+
+       switch (val->kind) {
+       case PSI_LET_NULL:
+               break;
+       case PSI_LET_TMP:
+               if (!let_var) {
+                       data->error(data, NULL, PSI_WARNING,
+                                       "Ivalid let statement value of implementation '%s'",
+                                       impl->func->name);
+                       return 0;
+               }
+               /* e.g. let bar = &strval($bar); // decl_arg(char **bar) */
+               /* e.g. let foo = *bar;  */
+               let_var->pointer_level = val->data.var->pointer_level;
+               let_var->arg = init_decl_arg(
+                               init_decl_type(
+                                               real_decl_type(val->data.var->arg->type)->type,
+                                               real_decl_type(val->data.var->arg->type)->name),
+                               init_decl_var(
+                                               let_var->name,
+                                               let_var->pointer_level,
+                                               let_var->array_size));
+               break;
+       case PSI_LET_NUMEXP:
+               if (!validate_num_exp(data, val->data.num, impl->decl->args, impl->decl->func, NULL)) {
+                       return 0;
+               }
+               break;
+       case PSI_LET_CALLOC:
+               if (!validate_num_exp(data, val->data.alloc->nmemb, impl->decl->args, impl->decl->func, NULL)) {
+                       return 0;
+               }
+               if (!validate_num_exp(data, val->data.alloc->size, impl->decl->args, impl->decl->func, NULL)) {
+                       return 0;
+               }
+               break;
+       case PSI_LET_CALLBACK:
+               if (!let_var) {
+                       data->error(data, NULL, PSI_WARNING,
+                                       "Ivalid let statement value of implementation '%s'",
+                                       impl->func->name);
+                       return 0;
+               }
+               if (val->data.callback->func->inner) {
+                       size_t i;
+
+                       for (i = 0; i < val->data.callback->func->inner->count; ++i) {
+                               let_val *inner = val->data.callback->func->inner->vals[i];
+                               switch (inner->kind) {
+                               case PSI_LET_FUNC:
+                                       inner->data.func->outer = val;
+                                       break;
+                               case PSI_LET_CALLBACK:
+                                       inner->data.callback->func->outer = val;
+                                       break;
+                               }
+                       }
+               }
+               if (!validate_let_callback(data, let_var, val->data.callback, impl)) {
+                       return 0;
+               }
+               break;
+       case PSI_LET_FUNC:
+               if (val->data.func->inner) {
+                       size_t i;
+
+                       for (i = 0; i < val->data.func->inner->count; ++i) {
+                               let_val *inner = val->data.func->inner->vals[i];
+                               switch (inner->kind) {
+                               case PSI_LET_FUNC:
+                                       inner->data.func->outer = val;
+                                       break;
+                               case PSI_LET_CALLBACK:
+                                       inner->data.callback->func->outer = val;
+                                       break;
+                               }
+                       }
+               }
+
+               if (!validate_let_func(data, val->data.func, let_var, impl)) {
+                       return 0;
+               }
+               break;
+       }
+
+       return 1;
+}
+
 static inline int validate_impl_let_stmts(struct psi_data *data, impl *impl) {
        size_t i, j;
        /* we can have multiple let stmts */
@@ -1011,48 +1182,10 @@ static inline int validate_impl_let_stmts(struct psi_data *data, impl *impl) {
                        return 0;
                }
 
-               switch (let->val->kind) {
-               case PSI_LET_NULL:
-                       break;
-               case PSI_LET_TMP:
-                       /* e.g. let bar = &strval($bar); // decl_arg(char **bar) */
-                       /* e.g. let foo = *bar;  */
-                       let->var->pointer_level = let->val->data.var->pointer_level;
-                       let->var->arg = init_decl_arg(
-                                       init_decl_type(
-                                                       real_decl_type(let->val->data.var->arg->type)->type,
-                                                       real_decl_type(let->val->data.var->arg->type)->name),
-                                       init_decl_var(
-                                                       let->var->name,
-                                                       let->var->pointer_level,
-                                                       let->var->array_size));
-                       break;
-               case PSI_LET_NUMEXP:
-                       if (!validate_num_exp(data, let->val->data.num, impl->decl->args, impl->decl->func, NULL)) {
-                               return 0;
-                       }
-                       break;
-               case PSI_LET_CALLOC:
-                       if (!validate_num_exp(data, let->val->data.alloc->nmemb, impl->decl->args, impl->decl->func, NULL)) {
-                               return 0;
-                       }
-                       if (!validate_num_exp(data, let->val->data.alloc->size, impl->decl->args, impl->decl->func, NULL)) {
-                               return 0;
-                       }
-                       break;
-               case PSI_LET_CALLBACK:
-                       if (!validate_let_callback(data, let->var, let->val->data.callback, impl)) {
-                               return 0;
-                       }
-                       break;
-               case PSI_LET_FUNC:
-                       if (!validate_let_func(data, let->val->data.func, impl)) {
-                               return 0;
-                       }
-                       break;
+               if (!validate_let_val(data, let->val, let->var, impl)) {
+                       return 0;
                }
        }
-
        /* check that we have a let stmt for every decl arg */
        if (impl->decl->args) for (i = 0; i < impl->decl->args->count; ++i) {
                decl_arg *darg = impl->decl->args->args[i];
@@ -1277,7 +1410,7 @@ int psi_context_validate(struct psi_context *C, struct psi_parser *P)
        decl_structs *check_structs = P->structs;
        decl_unions *check_unions = P->unions;
        decl_enums *check_enums = P->enums;
-       unsigned silent = C->flags & PSI_PARSER_SILENT;
+       unsigned flags = C->flags;
 
        C->data = realloc(C->data, C->count * sizeof(*C->data));
        D = psi_data_exchange(&C->data[count], PSI_DATA(P));
@@ -1292,7 +1425,7 @@ int psi_context_validate(struct psi_context *C, struct psi_parser *P)
 #define CHECK_TOTAL (CHECK_COUNT(defs) + CHECK_COUNT(structs) + CHECK_COUNT(enums))
 #define CHECK_COUNT(of) (check_ ##of ? check_ ##of->count : 0)
 
-       if (!silent) {
+       if (!(flags & PSI_PARSER_SILENT)) {
                /* no warnings on first round */
                C->flags |= PSI_PARSER_SILENT;
        }
@@ -1338,11 +1471,12 @@ int psi_context_validate(struct psi_context *C, struct psi_parser *P)
                REVALIDATE(unions);
                REVALIDATE(enums);
 
-               if (check_round == 0 && !silent) {
-                       C->flags &= ~PSI_PARSER_SILENT;
+               if (check_round == 0 && !(flags & PSI_PARSER_SILENT)) {
+                       C->flags ^= PSI_PARSER_SILENT;
                }
        }
 
+       C->flags = flags;
 
        if (D->consts) {
                for (i = 0; i < D->consts->count; ++i) {
index ce5cc2441702c75a40bf6438bbbe85f90f0751d2..28553173862e69caebfb0f1d474fd77a777bd2a6 100644 (file)
@@ -13,6 +13,10 @@ void psi_to_void(zval *return_value, set_value *set, impl_val *ret_val)
        RETVAL_NULL();
 }
 
+impl_val *psi_let_void(impl_val *tmp, decl_type *type, impl_arg *iarg, void **to_free) {
+       return tmp;
+}
+
 void psi_to_zval(zval *return_value, set_value *set, impl_val *ret_val) {
        RETVAL_ZVAL(ret_val->ptr, 1, 0);
 }
index 47402e46cc06036b0b3377e464e1c7af19ac0525..a011c1bb115d794a393dd92fe74242b34c568515 100644 (file)
@@ -14,6 +14,7 @@ void psi_to_zval(zval *return_value, set_value *set, impl_val *ret_val);
 void *psi_array_to_struct(decl_struct *s, HashTable *arr);
 void psi_from_zval(impl_val *mem, decl_arg *spec, zval *zv, void **tmp);
 
+impl_val *psi_let_void(impl_val *tmp, decl_type *type, impl_arg *iarg, void **to_free);
 impl_val *psi_let_boolval(impl_val *tmp, decl_type *type, impl_arg *iarg, void **to_free);
 impl_val *psi_let_intval(impl_val *tmp, decl_type *type, impl_arg *iarg, void **to_free);
 impl_val *psi_let_floatval(impl_val *tmp, decl_type *type, impl_arg *iarg, void **to_free);
index f7d7d06560ba6c50d2828056aa0dbd5048997eb3..b4a4ff004655c7c9c35fe79f2649fba6ba82586c 100644 (file)
@@ -48,7 +48,7 @@ DEF(%extra_argument, {struct psi_parser *P})
 DEF(%syntax_error, {
        ++P->errors;
        if (TOKEN && TOKEN->type != PSI_T_EOF) {
-               psi_error(PSI_WARNING, TOKEN->file, TOKEN->line, "PSI syntax error: Unexpected token '%s'", TOKEN->text);
+               psi_error(PSI_WARNING, TOKEN->file, TOKEN->line, "PSI syntax error: Unexpected token '%s' at pos %u", TOKEN->text, TOKEN->col);
        } else {
                psi_error(PSI_WARNING, P->psi.file.fn, P->line, "PSI syntax error: Unexpected end of input");
        }
@@ -153,6 +153,8 @@ TOKEN_TYPE(callback_args, set_values *)
 TOKEN_DTOR(callback_args, free_set_values($$);)
 TOKEN_TYPE(let_val, let_val*)
 TOKEN_DTOR(let_val, free_let_val($$);)
+TOKEN_TYPE(let_vals, let_vals*)
+TOKEN_DTOR(let_vals, free_let_vals($$);)
 TOKEN_TYPE(set_stmt, set_stmt*)
 TOKEN_DTOR(set_stmt, free_set_stmt($$);)
 TOKEN_TYPE(set_value, set_value*)
@@ -1008,6 +1010,29 @@ PARSE_TYPED(let_func, func,
        free(T);
 }
 
+PARSE_TYPED(let_vals, vals,
+               TYPED(let_val, val)) {
+       vals = init_let_vals(val);
+}
+PARSE_TYPED(let_vals, vals,
+               TYPED(let_vals, vals_)
+               TOKEN(COMMA)
+               TYPED(let_val, val)) {
+       vals = add_let_val(vals_, val);
+}
+
+PARSE_TYPED(let_func, func,
+               NAMED(let_func_token, T)
+               TOKEN(LPAREN)
+               TYPED(impl_var, var)
+               TOKEN(COMMA)
+               TYPED(let_vals, vals)
+               TOKEN(RPAREN)) {
+       func = init_let_func(T->type, T->text, var);
+       func->inner = vals;
+       free(T);
+}
+
 LET(callback_arg_list, )
 PARSE_TYPED(callback_arg_list, args,
                TYPED(callback_args, args_)) {
@@ -1024,6 +1049,14 @@ PARSE_TYPED(callback_args, args,
                TYPED(set_value, val)) {
        args = add_set_value(args_, val);
 }
+PARSE_NAMED(callback_rval, rval,
+               NAMED(let_func_token, F)) {
+       rval = F;
+}
+PARSE_NAMED(callback_rval, rval,
+               NAMED(VOID, V)) {
+       rval = V;
+}
 
 PARSE_TYPED(let_val, val,
                TOKEN(NULL)) {
@@ -1041,12 +1074,12 @@ PARSE_TYPED(let_val, val,
        val = init_let_val(PSI_LET_CALLOC, alloc);
 }
 PARSE_TYPED(let_val, val,
-               TYPED(let_func, func)) {
-       val = init_let_val(PSI_LET_FUNC, func);
+               TYPED(let_func, func_)) {
+       val = init_let_val(PSI_LET_FUNC, func_);
 }
 PARSE_TYPED(let_val, val,
                TOKEN(CALLBACK)
-               NAMED(let_func_token, F)
+               NAMED(callback_rval, F)
                TOKEN(LPAREN)
                TYPED(impl_var, var)
                TOKEN(LPAREN)
index 0d0aa61ceb99a33824033d2b030a3400595b2348..b97d28f7b00e4dfc23cd29c4a80abed630a62dc0 100644 (file)
 
 #include "parser.h"
 }
-%include { void psi_error(int, const char *, int, const char *, ...); }
+%include {void psi_error(int, const char *, int, const char *, ...);}
+
+
+
 %name psi_parser_proc_
 %token_prefix PSI_T_
 %token_type {struct psi_token *}
 %token_destructor {free($$);}
 %default_destructor {(void)P;}
 %extra_argument {struct psi_parser *P}
-%syntax_error { ++P->errors; if (TOKEN && TOKEN->type != PSI_T_EOF) { psi_error(PSI_WARNING, TOKEN->file, TOKEN->line, "PSI syntax error: Unexpected token '%s'", TOKEN->text); } else { psi_error(PSI_WARNING, P->psi.file.fn, P->line, "PSI syntax error: Unexpected end of input"); } }
+
+
+%syntax_error { ++P->errors; if (TOKEN && TOKEN->type != PSI_T_EOF) { psi_error(PSI_WARNING, TOKEN->file, TOKEN->line, "PSI syntax error: Unexpected token '%s' at pos %u", TOKEN->text, TOKEN->col); } else { psi_error(PSI_WARNING, P->psi.file.fn, P->line, "PSI syntax error: Unexpected end of input"); }}
 %nonassoc NAME.
 %left PLUS MINUS.
 %left SLASH ASTERISK.
 %fallback NAME TEMP FREE SET LET RETURN CALLOC CALLBACK ZVAL LIB STRING.
+
 %token_class const_type_token BOOL INT FLOAT STRING.
 %token_class decl_type_token FLOAT DOUBLE INT8 UINT8 INT16 UINT16 INT32 UINT32 INT64 UINT64 NAME.
 %token_class impl_def_val_token NULL NUMBER TRUE FALSE QUOTED_STRING.
@@ -33,6 +39,7 @@
 %token_class let_func_token ZVAL OBJVAL ARRVAL PATHVAL STRLEN STRVAL FLOATVAL INTVAL BOOLVAL.
 %token_class set_func_token TO_OBJECT TO_ARRAY TO_STRING TO_INT TO_FLOAT TO_BOOL ZVAL VOID.
 %token_class impl_type_token VOID MIXED BOOL INT FLOAT STRING ARRAY OBJECT CALLABLE.
+
 %type decl_enum {decl_enum *}
 %destructor decl_enum {free_decl_enum($$);}
 %type decl_enum_items {decl_enum_items*}
 %destructor callback_args {free_set_values($$);}
 %type let_val {let_val*}
 %destructor let_val {free_let_val($$);}
+%type let_vals {let_vals*}
+%destructor let_vals {free_let_vals($$);}
 %type set_stmt {set_stmt*}
 %destructor set_stmt {free_set_stmt($$);}
 %type set_value {set_value*}
 %type reference {char}
 %type indirection {unsigned}
 %type pointers {unsigned}
+
 file ::= blocks.
 blocks ::= block.
 blocks ::= blocks block.
+
 block ::= EOF.
 block ::= EOS.
+
 block ::= LIB(token) QUOTED_STRING(libname) EOS. {
  if (P->psi.file.ln) {
   P->error(P, token, PSI_WARNING, "Extra 'lib %s' statement has no effect", libname->text);
@@ -156,9 +168,11 @@ block ::= LIB(token) QUOTED_STRING(libname) EOS. {
 block ::= decl(decl). {
  P->decls = add_decl(P->decls, decl);
 }
+
 block ::= impl(impl). {
  P->impls = add_impl(P->impls, impl);
 }
+
 block ::= decl_typedef(def). {
  P->defs = add_decl_typedef(P->defs, def);
  switch (def->type->type) {
@@ -179,116 +193,192 @@ block ::= decl_typedef(def). {
   break;
  }
 }
+
 block ::= constant(constant). {
  P->consts = add_constant(P->consts, constant);
 }
+
 block ::= decl_struct(strct). {
  P->structs = add_decl_struct(P->structs, strct);
 }
+
 block ::= decl_union(u). {
  P->unions = add_decl_union(P->unions, u);
 }
+
 block ::= decl_enum(e). {
  P->enums = add_decl_enum(P->enums, e);
 }
+
 optional_name(n) ::= . {
  n = NULL;
 }
+
 optional_name(n) ::= NAME(N). {
+
  n = N;
 }
+
 enum_name(n) ::= ENUM(E) optional_name(N). {
+
  if (N) {
   n = N;
   free(E);
  } else {
   char digest[17];
+
   psi_token_hash(E, digest);
   n = psi_token_translit(psi_token_append(E, 1, digest), " ", "@");
  }
 }
+
 decl_enum(e) ::= enum_name(N) LBRACE decl_enum_items(list) RBRACE. {
+
+
+
+
  e = init_decl_enum(N->text, list);
  e->token = N;
 }
+
 decl_enum_items(l) ::= decl_enum_item(i). {
+
  l = init_decl_enum_items(i);
 }
 decl_enum_items(l) ::= decl_enum_items(l_) COMMA decl_enum_item(i). {
+
+
+
  l = add_decl_enum_item(l_, i);
 }
+
 decl_enum_item(i) ::= NAME(N) EQUALS num_exp(num). {
+
+
+
  i = init_decl_enum_item(N->text, num);
  i->token = N;
 }
 decl_enum_item(i) ::= NAME(N). {
+
  i = init_decl_enum_item(N->text, NULL);
  i->token = N;
 }
+
 union_name(n) ::= UNION(U) optional_name(N). {
+
+
  if (N) {
   n = N;
   free(U);
  } else {
   char digest[17];
+
   psi_token_hash(U, digest);
   n = psi_token_translit(psi_token_append(U, 1, digest), " ", "@");
  }
 }
+
 struct_name(n) ::= STRUCT(S) optional_name(N). {
+
+
  if (N) {
   n = N;
   free(S);
  } else {
   char digest[17];
+
   psi_token_hash(S, digest);
   n = psi_token_translit(psi_token_append(S, 1, digest), " ", "@");
  }
 }
+
 decl_struct_args_block(args_) ::= LBRACE struct_args(args) RBRACE. {
+
+
+
  args_ = args;
 }
+
 decl_struct_args(args_) ::= decl_struct_args_block(args). {
+
  args_ = args;
 }
 decl_struct_args(args_) ::= EOS. {
+
  args_ = init_decl_args(NULL);
 }
+
 decl_struct(strct) ::= STRUCT NAME(N) align_and_size(as) decl_struct_args(args). {
+
+
+
+
  strct = init_decl_struct(N->text, args);
  strct->align = as.pos;
  strct->size = as.len;
  strct->token = N;
 }
+
 align_and_size(as) ::= . {
  as.pos = 0;
  as.len = 0;
 }
 align_and_size(as) ::= COLON COLON LPAREN NUMBER(A) COMMA NUMBER(S) RPAREN. {
+
+
+
+
+
+
+
  as.pos = atol(A->text);
  as.len = atol(S->text);
  free(A);
  free(S);
 }
+
 decl_union(u) ::= UNION NAME(N) align_and_size(as) decl_struct_args(args). {
+
+
+
+
  u = init_decl_union(N->text, args);
  u->align = as.pos;
  u->size = as.len;
  u->token = N;
 }
+
 const_type(type_) ::= const_type_token(T). {
+
  type_ = init_const_type(T->type, T->text);
  free(T);
 }
+
 constant(constant) ::= CONST const_type(type) NSNAME(T) EQUALS impl_def_val(val) EOS. {
+
+
+
+
+
+
  constant = init_constant(type, T->text, val);
  free(T);
 }
+
 decl_typedef(def) ::= TYPEDEF(T) decl_typedef_body(def_) EOS. {
+
+
+
  def = def_;
  def->token = T;
 }
+
 decl_typedef_body_ex(def) ::= struct_name(N) align_and_size(as) decl_struct_args_block(args) decl_var(var). {
+
+
+
+
  def = init_decl_arg(init_decl_type(PSI_T_STRUCT, N->text), var);
  def->type->token = psi_token_copy(N);
  def->type->real.strct = init_decl_struct(N->text, args);
@@ -297,6 +387,10 @@ decl_typedef_body_ex(def) ::= struct_name(N) align_and_size(as) decl_struct_args
  def->type->real.strct->size = as.len;
 }
 decl_typedef_body_ex(def) ::= union_name(N) align_and_size(as) decl_struct_args_block(args) decl_var(var). {
+
+
+
+
  def = init_decl_arg(init_decl_type(PSI_T_UNION, N->text), var);
  def->type->token = psi_token_copy(N);
  def->type->real.unn = init_decl_union(N->text, args);
@@ -305,32 +399,55 @@ decl_typedef_body_ex(def) ::= union_name(N) align_and_size(as) decl_struct_args_
  def->type->real.unn->size = as.len;
 }
 decl_typedef_body_ex(def) ::= decl_enum(e) NAME(ALIAS). {
+
+
  def = init_decl_arg(init_decl_type(PSI_T_ENUM, e->name), init_decl_var(ALIAS->text, 0, 0));
  def->var->token = ALIAS;
  def->type->token = psi_token_copy(e->token);
  def->type->real.enm = e;
 }
+
 decl_typedef_body(def) ::= decl_typedef_body_ex(def_). {
+
  def = def_;
 }
+
 decl_typedef_body_fn_args(args) ::= LPAREN decl_args(args_) RPAREN. {
+
+
+
  args = args_;
 }
 decl_typedef_body(def) ::= decl_func(func_) decl_typedef_body_fn_args(args). {
+
+
  def = init_decl_arg(init_decl_type(PSI_T_FUNCTION, func_->var->name), copy_decl_var(func_->var));
  def->type->token = psi_token_copy(func_->token);
  def->type->real.func = init_decl(init_decl_abi("default"), func_, args);
 }
 decl_typedef_body(def) ::= decl_arg(arg). {
+
  def = arg;
 }
+
 decl(decl) ::= decl_abi(abi) decl_func(func) LPAREN decl_args(args) RPAREN EOS. {
+
+
+
+
+
+
  decl = init_decl(abi, func, args);
 }
+
 decl_func(func) ::= decl_arg(arg). {
+
  func = arg;
 }
+
 decl_func(func) ::= VOID(T) NAME(N). {
+
+
  func = init_decl_arg(
   init_decl_type(T->type, T->text),
   init_decl_var(N->text, 0, 0)
@@ -340,6 +457,13 @@ decl_func(func) ::= VOID(T) NAME(N). {
  func->token = N;
 }
 decl_typedef_body(def) ::= VOID(T) indirection(decl_i) LPAREN indirection(type_i) NAME(N) RPAREN decl_typedef_body_fn_args(args). {
+
+
+
+
+
+
+
  decl_arg *func_ = init_decl_arg(
   init_decl_type(T->type, T->text),
   init_decl_var(N->text, decl_i, 0)
@@ -347,6 +471,7 @@ decl_typedef_body(def) ::= VOID(T) indirection(decl_i) LPAREN indirection(type_i
  func_->type->token = T;
  func_->var->token = N;
  func_->token = N;
+
  def = init_decl_arg(
   init_decl_type(PSI_T_FUNCTION, func_->var->name),
   copy_decl_var(func_->var)
@@ -363,6 +488,7 @@ decl_typedef_body(def) ::= CONST VOID(T) pointers(decl_i) LPAREN indirection(typ
  func_->type->token = T;
  func_->var->token = N;
  func_->token = N;
+
  def = init_decl_arg(
   init_decl_type(PSI_T_FUNCTION, func_->var->name),
   copy_decl_var(func_->var)
@@ -371,35 +497,61 @@ decl_typedef_body(def) ::= CONST VOID(T) pointers(decl_i) LPAREN indirection(typ
  def->type->token = psi_token_copy(func_->token);
  def->type->real.func = init_decl(init_decl_abi("default"), func_, args);
 }
+
 decl_abi(abi) ::= NAME(T). {
+
  abi = init_decl_abi(T->text);
  abi->token = T;
 }
+
 decl_var(var) ::= indirection(p) NAME(T). {
+
+
  var = init_decl_var(T->text, p, 0);
  var->token = T;
 }
 decl_var(var) ::= indirection(p) NAME(T) LBRACKET NUMBER(D) RBRACKET. {
+
+
+
+
+
  var = init_decl_var(T->text, p+1, atol(D->text));
  var->token = T;
  free(D);
 }
+
 decl_vars(vars) ::= decl_var(var). {
+
  vars = init_decl_vars(var);
 }
 decl_vars(vars) ::= decl_vars(vars_) COMMA decl_var(var). {
+
+
+
  vars = add_decl_var(vars_, var);
 }
+
 decl_arg(arg_) ::= const_decl_type(type) decl_var(var). {
+
+
  arg_ = init_decl_arg(type, var);
 }
 decl_typedef_body(def) ::= const_decl_type(type_) indirection(decl_i) LPAREN indirection(type_i) NAME(N) RPAREN decl_typedef_body_fn_args(args). {
+
+
+
+
+
+
+
  decl_arg *func_ = init_decl_arg(
   type_,
   init_decl_var(N->text, decl_i, 0)
  );
  func_->var->token = N;
  func_->token = N;
+
  def = init_decl_arg(
   init_decl_type(PSI_T_FUNCTION, func_->var->name),
   copy_decl_var(func_->var)
@@ -408,7 +560,12 @@ decl_typedef_body(def) ::= const_decl_type(type_) indirection(decl_i) LPAREN ind
  def->type->token = psi_token_copy(func_->token);
  def->type->real.func = init_decl(init_decl_abi("default"), func_, args);
 }
+
+
 decl_arg(arg_) ::= VOID(T) pointers(p) NAME(N). {
+
+
+
  arg_ = init_decl_arg(
   init_decl_type(T->type, T->text),
   init_decl_var(N->text, p, 0)
@@ -418,6 +575,10 @@ decl_arg(arg_) ::= VOID(T) pointers(p) NAME(N). {
  arg_->token = N;
 }
 decl_arg(arg_) ::= CONST VOID(T) pointers(p) NAME(N). {
+
+
+
+
  arg_ = init_decl_arg(
   init_decl_type(T->type, T->text),
   init_decl_var(N->text, p, 0)
@@ -426,25 +587,40 @@ decl_arg(arg_) ::= CONST VOID(T) pointers(p) NAME(N). {
  arg_->var->token = N;
  arg_->token = N;
 }
+
 decl_args ::= .
 decl_args ::= VOID.
 decl_args(args) ::= decl_arg(arg). {
+
  args = init_decl_args(arg);
 }
 decl_args(args) ::= decl_args(args_) COMMA decl_arg(arg). {
+
+
+
  args = add_decl_arg(args_, arg);
 }
 decl_args(args) ::= decl_args(args_) COMMA ELLIPSIS. {
+
+
+
  args = args_;
  args->varargs = 1;
 }
+
 struct_args(args) ::= struct_arg(arg). {
+
  args = init_decl_args(arg);
 }
 struct_args(args) ::= struct_args(args_) struct_arg(arg). {
+
+
  args = add_decl_arg(args_, arg);
 }
+
 struct_arg(arg_) ::= decl_typedef_body_ex(def) EOS. {
+
+
  arg_ = def;
  switch (def->type->type) {
  case PSI_T_STRUCT:
@@ -465,21 +641,37 @@ struct_arg(arg_) ::= decl_typedef_body_ex(def) EOS. {
  }
 }
 struct_arg(arg) ::= decl_arg(arg_) struct_layout(layout_) EOS. {
+
+
+
  arg_->layout = layout_;
  arg = arg_;
 }
+
 struct_layout(layout) ::= . {
  layout = NULL;
 }
 struct_layout(layout) ::= COLON COLON LPAREN NUMBER(POS) COMMA NUMBER(SIZ) RPAREN. {
+
+
+
+
+
+
+
  layout = init_decl_struct_layout(atol(POS->text), atol(SIZ->text));
  free(POS);
  free(SIZ);
 }
+
+
 decl_scalar_type(type_) ::= CHAR(C). {
+
  type_ = C;
 }
 decl_scalar_type(type_) ::= SHORT(S) decl_scalar_type_short(s). {
+
+
  if (s) {
   type_ = psi_token_cat(2, S, s);
   free(S);
@@ -491,13 +683,18 @@ decl_scalar_type(type_) ::= SHORT(S) decl_scalar_type_short(s). {
 decl_scalar_type_short(s) ::= . {
  s = NULL;
 }
+
 decl_scalar_type_short(s) ::= INT(I). {
+
  s = I;
 }
 decl_scalar_type(type_) ::= INT(I). {
+
  type_ = I;
 }
 decl_scalar_type(type_) ::= LONG(L) decl_scalar_type_long(l). {
+
+
  if (l) {
   type_ = psi_token_cat(2, L, l);
   free(L);
@@ -510,9 +707,12 @@ decl_scalar_type_long(l) ::= . {
  l = NULL;
 }
 decl_scalar_type_long(l) ::= DOUBLE(D). {
+
  l = D;
 }
 decl_scalar_type_long(l) ::= LONG(L) decl_scalar_type_long_long(ll). {
+
+
  if (ll) {
   l = psi_token_cat(2, L, ll);
   free(L);
@@ -525,9 +725,12 @@ decl_scalar_type_long_long(ll) ::= . {
  ll = NULL;
 }
 decl_scalar_type_long_long(ll) ::= INT(I). {
+
  ll = I;
 }
 decl_type(type_) ::= UNSIGNED(U) decl_scalar_type(N). {
+
+
  struct psi_token *T = psi_token_cat(2, U, N);
  type_ = init_decl_type(T->type, T->text);
  type_->token = T;
@@ -535,6 +738,8 @@ decl_type(type_) ::= UNSIGNED(U) decl_scalar_type(N). {
  free(N);
 }
 decl_type(type_) ::= SIGNED(S) decl_scalar_type(N). {
+
+
  struct psi_token *T = psi_token_cat(2, S, N);
  type_ = init_decl_type(T->type, T->text);
  type_->token = T;
@@ -542,175 +747,350 @@ decl_type(type_) ::= SIGNED(S) decl_scalar_type(N). {
  free(N);
 }
 decl_type(type_) ::= UNSIGNED(U). {
+
  type_ = init_decl_type(PSI_T_NAME, U->text);
  type_->token = U;
 }
 decl_type(type_) ::= SIGNED(S). {
+
  type_ = init_decl_type(PSI_T_NAME, S->text);
  type_->token = S;
 }
 decl_type(type_) ::= decl_scalar_type(N). {
+
  type_ = init_decl_type(N->type, N->text);
  type_->token = N;
 }
+
 decl_type(type_) ::= STRUCT(S) NAME(T). {
+
+
  type_ = init_decl_type(S->type, T->text);
  type_->token = T;
  free(S);
 }
 decl_type(type_) ::= UNION(U) NAME(T). {
+
+
  type_ = init_decl_type(U->type, T->text);
  type_->token = T;
  free(U);
 }
 decl_type(type_) ::= ENUM(E) NAME(T). {
+
+
  type_ = init_decl_type(E->type, T->text);
  type_->token = T;
  free(E);
 }
 decl_type(type_) ::= decl_type_token(T). {
+
  type_ = init_decl_type(T->type, T->text);
  type_->token = T;
 }
+
+
 const_decl_type(type) ::= decl_type(type_). {
+
  type = type_;
 }
 const_decl_type(type) ::= CONST decl_type(type_). {
+
+
  type = type_;
 }
+
 impl(impl) ::= impl_func(func) LBRACE impl_stmts(stmts) RBRACE. {
+
+
+
+
  impl = init_impl(func, stmts);
 }
+
 impl_func(func) ::= FUNCTION reference(r) NSNAME(NAME) impl_args(args) COLON impl_type(type). {
+
+
+
+
+
+
  func = init_impl_func(NAME->text, args, type, r);
  func->token = NAME;
 }
+
 impl_def_val(def) ::= impl_def_val_token(T). {
+
  def = init_impl_def_val(T->type, T->text);
  free(T);
 }
+
 impl_var(var) ::= reference(r) DOLLAR_NAME(T). {
+
+
  var = init_impl_var(T->text, r);
  var->token = T;
 }
+
 impl_arg(arg) ::= impl_type(type) impl_var(var). {
+
+
  arg = init_impl_arg(type, var, NULL);
 }
 impl_arg(arg) ::= impl_type(type) impl_var(var) EQUALS impl_def_val(def). {
+
+
+
+
  arg = init_impl_arg(type, var, def);
 }
+
 impl_args(args) ::= LPAREN RPAREN. {
+
+
  args = NULL;
 }
 impl_args(args) ::= LPAREN impl_arg_list(args_) RPAREN. {
+
+
+
  args = args_;
 }
 impl_args(args) ::= LPAREN impl_arg_list(args_) COMMA impl_vararg(va) RPAREN. {
+
+
+
+
+
  args = args_;
  args->vararg.name = va;
 }
+
 impl_vararg(va) ::= impl_type(type) reference(r) ELLIPSIS DOLLAR_NAME(T). {
+
+
+
+
  va = init_impl_arg(type, init_impl_var(T->text, r), NULL);
  free(T);
 }
+
 impl_arg_list(args) ::= impl_arg(arg). {
+
  args = init_impl_args(arg);
 }
 impl_arg_list(args) ::= impl_arg_list(args_) COMMA impl_arg(arg). {
+
+
+
  args = add_impl_arg(args_, arg);
 }
+
 impl_stmts(stmts) ::= impl_stmt(stmt). {
+
  stmts = init_impl_stmts(stmt);
 }
 impl_stmts(stmts) ::= impl_stmts(stmts_) impl_stmt(stmt). {
+
+
  stmts = add_impl_stmt(stmts_, stmt);
 }
+
 impl_stmt(stmt) ::= let_stmt(let). {
+
  stmt = init_impl_stmt(PSI_T_LET, let);
 }
 impl_stmt(stmt) ::= set_stmt(set). {
+
  stmt = init_impl_stmt(PSI_T_SET, set);
 }
 impl_stmt(stmt) ::= return_stmt(ret). {
+
  stmt = init_impl_stmt(PSI_T_RETURN, ret);
 }
 impl_stmt(stmt) ::= free_stmt(free). {
+
  stmt = init_impl_stmt(PSI_T_FREE, free);
 }
+
 num_exp(exp) ::= num_exp_token(tok). {
+
  exp = init_num_exp(tok->type, tok->text);
  exp->token = tok;
 }
 num_exp(exp) ::= decl_var(var). {
+
  exp = init_num_exp(PSI_T_NAME, var);
  exp->token = psi_token_copy(var->token);
 }
 num_exp(exp) ::= num_exp(exp_) num_exp_op_token(operator_) num_exp(operand_). {
+
+
+
  exp_->operator = operator_->type;
  exp_->operand = operand_;
  exp = exp_;
  free(operator_);
 }
+
 let_stmt(let) ::= LET decl_var(var) EOS. {
+
+
+
  let = init_let_stmt(var, init_let_val(PSI_LET_NULL, NULL));
 }
 let_stmt(let) ::= LET decl_var(var) EQUALS reference(r) let_val(val) EOS. {
+
+
+
+
+
+
  val->flags.one.is_reference = r ? 1 : 0;
  let = init_let_stmt(var, val);
 }
 let_stmt(let) ::= TEMP decl_var(var) EQUALS decl_var(val) EOS. {
+
+
+
+
+
  let = init_let_stmt(var, init_let_val(PSI_LET_TMP, val));
 }
+
 let_calloc(alloc) ::= num_exp(nmemb) COMMA num_exp(size). {
+
+
+
  alloc = init_let_calloc(nmemb, size);
 }
+
 let_func(func) ::= let_func_token(T) LPAREN impl_var(var) RPAREN. {
+
+
+
+
  func = init_let_func(T->type, T->text, var);
  free(T);
 }
+
+let_vals(vals) ::= let_val(val). {
+
+ vals = init_let_vals(val);
+}
+let_vals(vals) ::= let_vals(vals_) COMMA let_val(val). {
+
+
+
+ vals = add_let_val(vals_, val);
+}
+
+let_func(func) ::= let_func_token(T) LPAREN impl_var(var) COMMA let_vals(vals) RPAREN. {
+
+
+
+
+
+
+ func = init_let_func(T->type, T->text, var);
+ func->inner = vals;
+ free(T);
+}
+
 callback_arg_list ::= .
 callback_arg_list(args) ::= callback_args(args_). {
+
  args = args_;
 }
+
 callback_args(args) ::= set_value(val). {
+
  args = init_set_values(val);
 }
 callback_args(args) ::= callback_args(args_) COMMA set_value(val). {
+
+
+
  args = add_set_value(args_, val);
 }
+callback_rval(rval) ::= let_func_token(F). {
+
+ rval = F;
+}
+callback_rval(rval) ::= VOID(V). {
+
+ rval = V;
+}
+
 let_val(val) ::= NULL. {
+
  val = init_let_val(PSI_LET_NULL, NULL);
 }
 let_val(val) ::= num_exp(exp). {
+
  val = init_let_val(PSI_LET_NUMEXP, exp);
 }
 let_val(val) ::= CALLOC LPAREN let_calloc(alloc) RPAREN. {
+
+
+
+
  val = init_let_val(PSI_LET_CALLOC, alloc);
 }
-let_val(val) ::= let_func(func). {
- val = init_let_val(PSI_LET_FUNC, func);
+let_val(val) ::= let_func(func_). {
+
+ val = init_let_val(PSI_LET_FUNC, func_);
 }
-let_val(val) ::= CALLBACK let_func_token(F) LPAREN impl_var(var) LPAREN callback_arg_list(args_) RPAREN RPAREN. {
+let_val(val) ::= CALLBACK callback_rval(F) LPAREN impl_var(var) LPAREN callback_arg_list(args_) RPAREN RPAREN. {
  val = init_let_val(PSI_LET_CALLBACK, init_let_callback(
   init_let_func(F->type, F->text, var), args_));
  free(F);
 }
+
 set_stmt(set) ::= SET impl_var(var) EQUALS set_value(val) EOS. {
+
+
+
+
+
  set = init_set_stmt(var, val);
 }
+
 set_value(val) ::= set_func(func) LPAREN decl_var(var) RPAREN. {
+
+
+
+
  val = init_set_value(func, init_decl_vars(var));
 }
 set_value(val) ::= set_func(func) LPAREN decl_var(var) COMMA num_exp(num_) RPAREN. {
+
+
+
+
+
+
  val = init_set_value(func, init_decl_vars(var));
  val->num = num_;
 }
 set_value(val) ::= set_func(func_) LPAREN decl_var(var) COMMA ELLIPSIS(T) RPAREN. {
+
+
+
+
+
+
  free_set_func(func_);
  val = init_set_value(init_set_func(T->type, T->text), init_decl_vars(var));
  val->func->token = T;
 }
 set_value(val) ::= set_func(func_) LPAREN decl_var(var) COMMA set_vals(vals) RPAREN. {
+
+
+
+
+
+
  val = vals;
  val->func = func_;
  val->vars = init_decl_vars(var);
@@ -721,52 +1101,87 @@ set_value(val) ::= set_func(func_) LPAREN decl_var(var) COMMA num_exp(num_) COMM
  val->num = num_;
  val->vars = init_decl_vars(var);
 }
+
 set_vals(vals) ::= set_value(val). {
+
  vals = add_inner_set_value(init_set_value(NULL, NULL), val);
 }
 set_vals(vals) ::= set_vals(vals_) COMMA set_value(val). {
+
+
+
  vals = add_inner_set_value(vals_, val);
 }
+
 set_func(func) ::= set_func_token(T). {
+
  func = init_set_func(T->type, T->text);
  func->token = T;
 }
+
 return_stmt(ret) ::= RETURN(T) set_value(val) EOS. {
+
+
+
  ret = init_return_stmt(val);
  ret->token = T;
 }
+
 free_stmt(free) ::= FREE free_calls(calls) EOS. {
+
+
+
  free = init_free_stmt(calls);
 }
+
 free_calls(calls) ::= free_call(call). {
+
  calls = init_free_calls(call);
 }
 free_calls(calls) ::= free_calls(calls_) COMMA free_call(call). {
+
+
+
  calls = add_free_call(calls_, call);
 }
+
 free_call(call) ::= NAME(F) LPAREN decl_vars(vars) RPAREN. {
+
+
+
+
  call = init_free_call(F->text, vars);
  call->token = F;
 }
+
 impl_type(type_) ::= impl_type_token(T). {
+
  type_ = init_impl_type(T->type, T->text);
  free(T);
 }
+
 reference(r) ::= . {
  r = 0;
 }
 reference(r) ::= AMPERSAND. {
+
  r = 1;
 }
+
 indirection(i) ::= .{
  i = 0;
 }
 indirection(i) ::= pointers(p). {
+
  i = p;
 }
+
 pointers(p) ::= ASTERISK. {
+
  p = 1;
 }
 pointers(p) ::= pointers(p_) ASTERISK. {
+
+
  p = p_+1;
 }
index 1b91a0c33d8bdb5dda62bdebfd788ce9089f43d3..a4e5dadcaae1552221911338a70f975b9ba3b8b4 100644 (file)
@@ -43,6 +43,7 @@ typedef struct zend_fcall {
 #include "types/let_callback.h"
 #include "types/let_func.h"
 #include "types/let_val.h"
+#include "types/let_vals.h"
 #include "types/let_stmt.h"
 #include "types/set_func.h"
 #include "types/set_value.h"
index 526265b9cbf0c9ec44c8e91b59e7f864b1b1d627..850eb84251889b60553e6775066d448081bc56ab 100644 (file)
@@ -3,11 +3,18 @@
 
 typedef impl_val *(*let_func_handler)(impl_val *tmp, decl_type *type, impl_arg *iarg, void **to_free);
 
+struct let_val;
+struct let_vals;
+static inline void free_let_vals(struct let_vals *vals);
+
 typedef struct let_func {
        token_t type;
        char *name;
        impl_var *var;
        let_func_handler handler;
+       struct let_vals *inner;
+       struct let_val *outer;
+       decl_arg *ref;
 } let_func;
 
 static inline let_func *init_let_func(token_t type, const char *name, impl_var *var) {
@@ -21,6 +28,9 @@ static inline let_func *init_let_func(token_t type, const char *name, impl_var *
 static inline void free_let_func(let_func *func) {
        free_impl_var(func->var);
        free(func->name);
+       if (func->inner) {
+               free_let_vals(func->inner);
+       }
        free(func);
 }
 
diff --git a/src/types/let_vals.h b/src/types/let_vals.h
new file mode 100644 (file)
index 0000000..f46345c
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef _PSI_TYPES_LET_VALS_H
+#define _PSI_TYPES_LET_VALS_H
+
+struct let_val;
+
+typedef struct let_vals {
+       struct let_val **vals;
+       size_t count;
+} let_vals;
+
+static inline let_vals *init_let_vals(struct let_val *val) {
+       let_vals *vals = calloc(1, sizeof(*vals));
+       if (val) {
+               vals->count = 1;
+               vals->vals = calloc(1, sizeof(val));
+               vals->vals[0] = val;
+       }
+       return vals;
+}
+
+static inline let_vals *add_let_val(let_vals *vals, struct let_val *val) {
+       if (!vals) {
+               vals = calloc(1, sizeof(*vals));
+       }
+       vals->vals = realloc(vals->vals, ++vals->count * sizeof(val));
+       vals->vals[vals->count-1] = val;
+       return vals;
+}
+
+static inline void free_let_vals(let_vals *vals) {
+       if (vals->vals) {
+               size_t i;
+
+               for (i = 0; i < vals->count; ++i) {
+                       free_let_val(vals->vals[i]);
+               }
+               free(vals->vals);
+       }
+       free(vals);
+}
+
+#endif