function parseCaseNoBase(&$source, &$cases, &$default) { // The return type of the tests must be boolean $testRetType = lookupType('bool'); // We don't know the return type yet, it will be defined by the cases. $retType = null; $retSource = null; // Generate a name for the return value of the case. $value_name = generate_name("case_value"); $prep = []; $info = new ExpressionInfo($source, null, $value_name, true); grokit_logic_assert(count($cases) > 0, 'No cases found for case statement at ' . $source); // Handle cases foreach ($cases as $case) { $test = parseExpression(ast_get($case, NodeKey::TEST)); $expr = parseExpression(ast_get($case, NodeKey::EXPR)); $first = false; // Test if the return type of the test is compatible with boolean if (canConvert($test->type(), $testRetType)) { $test = convertExpression($test, $testRetType, $retSource); } else { // Incompatible types grokit_error('Case test expression has return type ' . $test->type() . ' which is incompatible with boolean ' . $test->source()); } // If the return type is not set, set it and continue. // Otherwise, make sure the expression's return type is compatible with // the already set return type. if ($retType === null) { $retType = $expr->type(); $retSource = $expr->source(); $first = true; $info->setType($retType); } else { if (canConvert($expr->type(), $retType)) { // The types are compatible or the same, so make them the same. $expr = convertExpression($expr, $retType, $retSource); } else { // Incompatible types grokit_error('Case return type ' . $expr->type() . ' of expression at ' . $expr->source() . ' incompatible with previous return type ' . $retType . ' defined by expression at ' . $retSource); } } // Absorb the metadata from the test and expression into our info $info->absorbMeta($test); $info->absorbMeta($expr); $myPrep = ''; if (!$first) { $myPrep .= 'else '; } $myPrep .= "if( {$test->value()} ) {$value_name} = {$expr->value()};"; $prep[] = $myPrep; } // Handle default if ($default !== null) { if (canConvert($default->type(), $retType)) { $default = convertExpression($default, $retType, $retSource); } else { // Incompatible types. grokit_error('Case return type ' . $default->type() . ' of default at ' . $default->source() . ' incompatible with previous return type ' . $retType . ' defined by expression at ' . $retSource); } $info->absorbMeta($default); $prep[] = "else {$value_name} = {$default->value()};"; } // Prepend the declaration of the return variable array_unshift($prep, "{$retType} {$value_name};"); // Add all of our stuff as preprocesses $info->addPreprocesses($prep); if ($info->is_const()) { $info->makeConstant(); } return $info; }
public function apply($obj, array $exprs, $source) { $this->checkFuzzy($this->args, $exprs, 'parameter'); $exprVals = array_map(function ($val) { return $val->value(); }, $exprs); $value = $obj->value() . '.' . $this->name . '(' . implode(', ', $exprVals) . ')'; $is_const = $this->deterministic && $obj->is_const(); foreach ($exprs as $expr) { $is_const = $is_const && $expr->is_const(); } $retType = lookupType($this->resultType); $info = new ExpressionInfo($source, $retType, $value, $is_const); $info->absorbMeta($obj); foreach ($exprs as $expr) { $info->absorbMeta($expr); } return $info; }