Browse Source

More porting

master
J. King 2 years ago
parent
commit
77707690cc
  1. 112
      lib/Docopt.php

112
lib/Docopt.php

@ -18,15 +18,20 @@ class Docopt {
protected static function levenshtein_norm(string $source, string $target): float {
// NOTE: We split the strings into arrays of UTF-8 characters to match Python's behaviour (for UTF-8 input)
// TODO: How is argv encoded in Windows and macOS? Does the Windows Command Prompt differ from Powershell?
$source = preg_split('/(?<!^)(?!$)/suD', $source);
$target = preg_split('/(?<!^)(?!$)/suD', $target);
$s = @preg_split('//Su', $source, -1, \PREG_SPLIT_NO_EMPTY);
$t = @preg_split('//Su', $target, -1, \PREG_SPLIT_NO_EMPTY);
// If the input was not UTF-8, we can just treat it as bytes rather than failing, since Python cannot fail here
if ($s === false || $t === false) {
$s = @preg_split('//S', $source, -1, \PREG_SPLIT_NO_EMPTY);
$t = @preg_split('//S', $target, -1, \PREG_SPLIT_NO_EMPTY);
}
# # Compute Levenshtein distance using helper function. The max is always
# # just the length of the longer string, so this is used to normalize result
# # before returning it
# distance = levenshtein(source, target)
# return float(distance) / max(len(source), len(target))
$distance = static::levenshtein($source, $target);
return (float) ($distance / max(sizeof($source), sizeof($target)));
$distance = static::levenshtein($s, $t);
return (float) ($distance / max(sizeof($s), sizeof($t)));
}
# def levenshtein(source: str, target: str) -> int:
@ -100,6 +105,45 @@ class Docopt {
# return matrix[len(source)][len(target)]
return $matrix[sizeof($source)][sizeof($target)];
}
# def transform(pattern: "BranchPattern") -> "Either":
# """Expand pattern into an (almost) equivalent one, but with single Either.
#
# Example: ((-a | -b) (-c | -d)) => (-a -c | -a -d | -b -c | -b -d)
# Quirks: [-a] => (-a), (-a...) => (-a -a)
#
# """
protected static function transform(BranchPattern $pattern): Either {
# result = []
# groups = [[pattern]]
$result = [];
$groups = [[$pattern]];
# while groups:
while ($groups) {
# children = groups.pop(0)
$children = array_shift($groups);
# parents = [Required, NotRequired, OptionsShortcut, Either, OneOrMore]
$parents = [Required::class, NotRequired::class, OptionsShortcut::class, Either::class, OneOrMore::class];
# if any(t in map(type, children) for t in parents):
$anyParentTypeInChildren = array_reduce($children, function($out, $c) use ($parents) {
return $out ?: in_array(get_class($c), $parents);
}, false);
if ($anyParentTypeInChildren) {
# child = [c for c in children if type(c) in parents][0]
# children.remove(child)
# if type(child) is Either:
# for c in child.children:
# groups.append([c] + children)
# elif type(child) is OneOrMore:
# groups.append(child.children * 2 + children)
# else:
# groups.append(child.children + children)
}
# else:
# result.append(children)
}
# return Either(*[Required(*e) for e in result])
}
}
# class DocoptLanguageError(Exception):
@ -135,46 +179,32 @@ class DocoptExit extends \Exception {
}
# class Pattern:
# def __init__(self, name: Optional[str], value: Optional[Union[List[str], str, int]] = None) -> None:
# self._name, self.value = name, value
# @property
# def name(self) -> Optional[str]:
# return self._name
# def __eq__(self, other: Any) -> bool:
# return repr(self) == repr(other)
# def __hash__(self) -> int:
# return hash(repr(self))
class Pattern {
public $name = null; // DEVIATION: This is a read-only property in Python. As this class is not part of the public API, this was deemed unnecessary complication
public $value = null;
# def __init__(self, name: Optional[str], value: Optional[Union[List[str], str, int]] = None) -> None:
public function __construct(?string $name, $value = null) {
# self._name, self.value = name, value
$this->name = $name;
$this->value = $value;
}
# def transform(pattern: "BranchPattern") -> "Either":
# """Expand pattern into an (almost) equivalent one, but with single Either.
# @property
# def name(self) -> Optional[str]:
# return self._name
// DEVIATION: Not implemented; see property definition above
# Example: ((-a | -b) (-c | -d)) => (-a -c | -a -d | -b -c | -b -d)
# Quirks: [-a] => (-a), (-a...) => (-a -a)
# """
# result = []
# groups = [[pattern]]
# while groups:
# children = groups.pop(0)
# parents = [Required, NotRequired, OptionsShortcut, Either, OneOrMore]
# if any(t in map(type, children) for t in parents):
# child = [c for c in children if type(c) in parents][0]
# children.remove(child)
# if type(child) is Either:
# for c in child.children:
# groups.append([c] + children)
# elif type(child) is OneOrMore:
# groups.append(child.children * 2 + children)
# else:
# groups.append(child.children + children)
# else:
# result.append(children)
# return Either(*[Required(*e) for e in result])
# def __eq__(self, other: Any) -> bool:
# return repr(self) == repr(other)
// DEVIATION: Operators cannot be overloaded in PHP, thus this is not implemented
// TODO: Do we need to implement an explicit means oof comparison?
# def __hash__(self) -> int:
# return hash(repr(self))
// DEVIATION: Not implemented as it is only used internally for object comparison
// See https://docs.python.org/3/reference/datamodel.html?highlight=__hash__#object.__hash__
}
# TSingleMatch = Tuple[Union[int, None], Union["LeafPattern", None]]

Loading…
Cancel
Save