+
+ switch (exp->op) {
+ case PSI_T_NUMBER:
+ return psi_number_validate(data, exp->data.n, impl, cb_decl, current_let, current_set, current_enum);
+
+ case PSI_T_CAST:
+ return psi_num_exp_validate(data, exp->data.c.num, impl, cb_decl, current_let, current_set, current_enum)
+ && psi_decl_type_validate(data, exp->data.c.typ, 0, NULL);
+ break;
+
+ case PSI_T_NOT:
+ case PSI_T_TILDE:
+ case PSI_T_LPAREN:
+ return psi_num_exp_validate(data, exp->data.u, impl, cb_decl, current_let, current_set, current_enum);
+ break;
+
+ case PSI_T_OR:
+ case PSI_T_AND:
+
+ case PSI_T_CMP_EQ:
+ case PSI_T_CMP_NE:
+ case PSI_T_CMP_LE:
+ case PSI_T_CMP_GE:
+ case PSI_T_RCHEVR:
+ case PSI_T_LCHEVR:
+
+ case PSI_T_PIPE:
+ case PSI_T_CARET:
+ case PSI_T_AMPERSAND:
+ case PSI_T_LSHIFT:
+ case PSI_T_RSHIFT:
+ case PSI_T_PLUS:
+ case PSI_T_MINUS:
+ case PSI_T_ASTERISK:
+ case PSI_T_SLASH:
+ case PSI_T_MODULO:
+ return psi_num_exp_validate(data, exp->data.b.lhs, impl, cb_decl, current_let, current_set, current_enum)
+ && psi_num_exp_validate(data, exp->data.b.rhs, impl, cb_decl, current_let, current_set, current_enum);
+
+ case PSI_T_IIF:
+ return psi_num_exp_validate(data, exp->data.t.cond, impl, cb_decl, current_let, current_set, current_enum)
+ && psi_num_exp_validate(data, exp->data.t.truthy, impl, cb_decl, current_let, current_set, current_enum)
+ && psi_num_exp_validate(data, exp->data.t.falsy, impl, cb_decl, current_let, current_set, current_enum);
+
+ default:
+ assert(0);
+ }
+
+ return false;
+}
+
+static inline void psi_impl_val_dump(token_t t, impl_val *res,
+ struct psi_call_frame *frame)
+{
+ switch (t) {
+ case PSI_T_INT8:
+ case PSI_T_UINT8:
+ if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIi8, res->i8);
+ break;
+ case PSI_T_INT16:
+ case PSI_T_UINT16:
+ if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIi16, res->i16);
+ break;
+ case PSI_T_INT32:
+ case PSI_T_UINT32:
+ if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIi32, res->i32);
+ break;
+ case PSI_T_INT64:
+ case PSI_T_UINT64:
+ if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIi64, res->i64);
+ break;
+ case PSI_T_FLOAT:
+ if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIfval, res->fval);
+ break;
+ case PSI_T_DOUBLE:
+ if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIdval, res->dval);
+ break;
+ default:
+ assert(0);
+ }
+}
+
+static inline void psi_num_exp_verify_result(token_t t, impl_val *res, struct psi_call_frame *frame)
+{
+ if (frame) PSI_DEBUG_PRINT(frame->context, "%s", " = ");
+ psi_impl_val_dump(t, res, frame);
+ if (frame) PSI_DEBUG_PRINT(frame->context, "%s", "\n");
+}
+
+static void psi_num_exp_reduce(struct psi_num_exp *exp, struct psi_plist **output_ptr,
+ struct psi_plist **input_ptr, struct psi_call_frame *frame, HashTable *defs)
+{
+ struct psi_plist *output = *output_ptr, *input = *input_ptr;
+ struct element {
+ token_t type;
+ union {
+ impl_val value;
+ psi_calc calc;
+ struct psi_decl_type *cast;
+ } data;
+ } entry;
+
+ switch (exp->op) {
+ case PSI_T_NUMBER:
+ entry.type = psi_number_eval(exp->data.n, &entry.data.value, frame, defs);
+ output = psi_plist_add(output, &entry);
+ break;
+
+ case PSI_T_LPAREN:
+ entry.type = exp->op;
+ input = psi_plist_add(input, &entry);
+ psi_num_exp_reduce(exp->data.u, &output, &input, frame, defs);
+ while (psi_plist_pop(input, &entry)) {
+ if (entry.type == PSI_T_LPAREN) {
+ break;
+ }
+ if (frame) PSI_DEBUG_PRINT(frame->context, " %s", psi_num_exp_op_tok(entry.type));
+ output = psi_plist_add(output, &entry);
+ }
+ break;
+
+ case PSI_T_CAST:
+ while (psi_plist_top(input, &entry)) {
+ /* bail out if exp->op >= entry.type */
+ if (psi_calc_oper(exp->op, entry.type) != 1) {
+ break;