*/ function _regexp_match( string $pattern, string $subject ) { $matches = []; $pattern_ = sprintf('/%s/', $pattern); $result = preg_match($pattern_, $subject, $matches); if ($result === 0) { return null; } else { return array_slice($matches, 1); } } /** * @param list<§x> $list * @param function<§x,§y> $function * @return list<§y> */ function _list_map( array $list, \Closure $function ) : array { $list_ = []; for ($index = 0; $index < count($list); $index += 1) { $value = $list[$index]; $value_ = $function($value, $index); array_push($list_, $value_); } return $list_; } /** * @param map $map * @param function<§x,§y> $function * @return map */ function _map_map( array $map, \Closure $function ) : array { $map_ = []; foreach ($map as $key => $value) { $key_ = $key; $value_ = $function($value, $key); $map_[$key_] = $value_; } return $map_; } /** * @param record>>,named:map>>> $spec_raw * @param list $args_raw * @return map * @author Christian Fraß */ function parse( array $spec_raw, array $args_raw, array $settings_given = [] ) : array { $settings_default = [ 'supress_warnings' => false, ]; $settings = array_merge( $settings_default, $settings_given ); // spec refinement { $spec = [ 'positioned_mandatory' => _list_map( $spec_raw['positioned_mandatory'], function ($entry_raw, $index) { return [ 'target' => ( array_key_exists('target', $entry_raw) ? $entry_raw['target'] : sprintf('_arg_%d', $index) ), 'processing' => ( array_key_exists('processing', $entry_raw) ? $entry_raw['processing'] : (function ($value_raw) {return $value_raw;}) ), ]; } ), 'positioned_optional' => _list_map( $spec_raw['positioned_optional'], function ($entry_raw, $index) use (&$spec_raw) { return [ 'target' => ( array_key_exists('target', $entry_raw) ? $entry_raw['target'] : sprintf('_arg_%d', $index + count($spec_raw['positioned_mandatory'])) ), 'processing' => ( array_key_exists('processing', $entry_raw) ? $entry_raw['processing'] : (function ($value_raw) {return $value_raw;}) ), 'default' => ( array_key_exists('default', $entry_raw) ? $entry_raw['default'] : null ), ]; } ), 'named' => _map_map( $spec_raw['named'], function ($entry_raw, $key) { return [ 'target' => ( array_key_exists('target', $entry_raw) ? $entry_raw['target'] : $key ), 'processing' => ( array_key_exists('processing', $entry_raw) ? $entry_raw['processing'] : (function ($value_raw) {return $value_raw;}) ), 'default' => ( array_key_exists('default', $entry_raw) ? $entry_raw['default'] : null ), ]; } ), ]; } $args = []; // default values { foreach ($spec['positioned_optional'] as $entry) { $args[$entry['target']] = $entry['default']; } foreach ($spec['named'] as $entry) { $args[$entry['target']] = $entry['default']; } } // parsing { $position = 0; foreach ($args_raw as $arg_raw) { $result = _regexp_match('--([^=]+)=([^=]+)', $arg_raw); if ($result === null) { if ($position < count($spec['positioned_mandatory'])) { $entry = $spec['positioned_mandatory'][$position]; $value_raw = $entry['processing']($arg_raw); $value = $value_raw; $args[$entry['target']] = $value; } else if ($position < count($spec['positioned_mandatory']) + count($spec['positioned_optional'])) { $entry = $spec['positioned_optional'][$position - count($spec['positioned_optional'])]; $value_raw = $entry['processing']($arg_raw); $value = $value_raw; $args[$entry['target']] = $value; } else { if (! $settings['supress_warnings']) { \alveolata\log\warning( 'unrecognized positional argument', [ 'position' => $position, 'value' => $arg_raw, ] ); } } $position += 1; } else { $name = $result[0]; $value_raw = $result[1]; if (array_key_exists($name, $spec['named'])) { $entry = $spec['named'][$name]; $value = $entry['processing']($value_raw); $args[$entry['target']] = $value; } else { if (! $settings['supress_warnings']) { \alveolata\log\warning( 'unrecognized named argument', [ 'name' => $name, 'value' => $value_raw, ] ); } } } } $left = array_slice($spec['positioned_mandatory'], $position); if (count($left) > 0) { throw (new \Exception(sprintf('%d missing mandatory positioned arguments', count($left)))); } } return $args; }