/** * Returns an integer describing the compatibility of the function * with the given types. * * @returns -1 if incompatible * 0 if perfectly compatible * otherwise the number of implicit conversions required to make compatible */ public function compatibility(array $types, $exact = false) { if (count($types) != count($this->args)) { return -1; } $types = array_map("strtoupper", $types); $rating = 0; foreach ($this->args as $name => $expected) { $given = $types[$name]; if ($expected != $given) { if ($exact) { return -1; } if (canConvert($given, $expected)) { $rating += 1; } else { return -1; } } } return $rating; }
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; }
function parseSelectionWP($ast, $name, $header) { // Push LibraryManager so we can undo this waypoint's definitions. ob_start(); LibraryManager::Push(); $res = new GenerationInfo(); /*************** PROCESS AST ***************/ $attMap = parseAttributeMap(ast_get($ast, NodeKey::ATT_MAP), $res); $qFilters = ast_get($ast, NodeKey::FILTERS); $qSynth = ast_get($ast, NodeKey::SYNTH); $queries = []; foreach ($qFilters as $query => $qInfo) { $filterAST = ast_get($qInfo, NodeKey::ARGS); $gfAST = ast_get($qInfo, NodeKey::TYPE); if ($gfAST !== null) { $filter = parseNamedExpressionList($filterAST); } else { $filter = parseExpressionList($filterAST); } $gf = null; if ($gfAST !== null) { $gf = parseGF($gfAST); $gf = $gf->apply($filter); } if (ast_has($qInfo, NodeKey::CARGS)) { $cargs = parseLiteralList(ast_get($qInfo, NodeKey::CARGS)); } else { $cargs = []; } $sargs = ast_has($qInfo, NodeKey::SARGS) ? parseStateList(ast_get($qInfo, NodeKey::SARGS), $query) : []; $synths = array(); $synthAST = ast_get($ast, NodeKey::SYNTH); if (ast_has($synthAST, $query)) { $curSynths = ast_get($synthAST, $query); foreach ($curSynths as $curSynthAST) { $expr = parseExpression(ast_get($curSynthAST, NodeKey::EXPR)); $att = parseAttribute(ast_get($curSynthAST, NodeKey::ATT)); if ($att->type() == null) { AttributeManager::setAttributeType($att->name(), $expr->type()); $att = AttributeManager::lookupAttribute($att->name()); } else { if (canConvert($expr, $att->type())) { $expr = convertExpression($expr, $att->type()); } else { grokit_error('Unable to convert expression for synthesized attribute ' . $att->name() . ' from type ' . $expr->type() . ' to type ' . $att->type() . ' ' . $expr->source()); } } $synths[$att->name()] = $expr; } } $info = ['filters' => $filter, 'synths' => $synths, 'gf' => $gf, 'cargs' => $cargs, 'states' => $sargs]; $queries[$query] = $info; $res->addJob($query, $name); $res->absorbInfoList($filter); $res->absorbInfoList($synths); $res->absorbInfoList($cargs); $res->absorbStateList($sargs); if ($gf !== null) { $res->absorbInfo($gf); } } /*************** END PROCESS AST ***************/ // Get this waypoint's headers $myHeaders = $header . PHP_EOL . ob_get_clean(); // Only one file at the moment $filename = $name . '.cc'; $res->addFile($filename, $name); _startFile($filename); SelectionGenerate($name, $queries, $attMap); _endFile($filename, $myHeaders); // Pop LibraryManager again to get rid of this waypoint's declarations LibraryManager::Pop(); return $res; }
protected function CheckFuzzy(array &$expected, array &$exprs, $type) { //fwrite(STDERR, "CheckFuzzy: " . print_r($exprs,true) . PHP_EOL); $nGiven = \count($exprs); $nExpected = \count($expected); grokit_assert($nExpected == $nGiven, 'Unable to apply ' . $this . ' to given ' . $type . 's: Expected ' . $nExpected . ' ' . $type . 's, received ' . $nGiven); if ($nGiven == 0) { return; } $expectKeys = array_keys($expected); reset($expected); reset($exprs); foreach (range(0, $nExpected - 1) as $i) { $cExpected = current($expected); $cGiven = current($exprs); $cGivenType = is_datatype($cGiven) ? $cGiven : $cGiven->type(); grokit_assert(canConvert($cGivenType, $cExpected), 'Unable to apply ' . $this . ' to given ' . $type . 's: ' . '' . $type . ' at position ' . $i . ' of type ' . $cGiven->type() . ' not compatible with ' . 'expected type ' . $cExpected); if (is_expression($cGiven)) { $exprs[key($exprs)] = convertExpression($cGiven, $cExpected); } next($expected); next($exprs); } }