-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #33 from jmanuel1/stubs
Stubs
- Loading branch information
Showing
45 changed files
with
4,286 additions
and
2,448 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import concat.astutils | ||
import concat.parser_combinators | ||
import io | ||
import textwrap | ||
from typing import Sequence, TextIO | ||
|
||
|
||
def get_line_at(file: TextIO, location: concat.astutils.Location) -> str: | ||
file.seek(0, io.SEEK_SET) | ||
lines = [*file] | ||
return lines[location[0] - 1] | ||
|
||
|
||
def create_parsing_failure_message( | ||
file: TextIO, | ||
stream: Sequence[concat.lex.Token], | ||
failure: concat.parser_combinators.FailureTree, | ||
) -> str: | ||
location = stream[failure.furthest_index].start | ||
line = get_line_at(file, location) | ||
message = f'Expected {failure.expected} at line {location[0]}, column {location[1] + 1}:\n{line.rstrip()}\n{" " * location[1] + "^"}' | ||
if failure.children: | ||
message += '\nbecause:' | ||
for f in failure.children: | ||
message += '\n' + textwrap.indent( | ||
create_parsing_failure_message(file, stream, f), ' ' | ||
) | ||
return message |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
# Kind Polymorphism | ||
|
||
* Will probably want kind variables in the future | ||
* Introduce a kind `Kind` at that point | ||
* And kind aliases, too | ||
|
||
Probably, the easiest migration is to take the individual variable syntax: | ||
|
||
``` | ||
`t | ||
``` | ||
|
||
And use it to mean item-kinded variables instead. | ||
|
||
## Prior art | ||
|
||
* [Adding kind-polymorphism to the Scala programming language](https://codesync.global/media/adding-kind-polymorphism-to-the-scala-programming-language/) | ||
* [`AnyKind`](https://www.scala-lang.org/api/current/scala/AnyKind.html) | ||
|
||
## Kinds | ||
|
||
* (?) Item: the kind of types of stack items | ||
* Just use Individual? | ||
* I use kinds for arity checking too, so I think that would make it harder | ||
* Needed to exclude Sequence from kind-polymorphic type parameters where a | ||
Sequence is invalid, e.g: | ||
* `def drop[t : Item](*s t -- *s)` (possible syntax) | ||
* Individual: the kind of zero-arity types of values | ||
* Generic: type constructors | ||
* they have arities | ||
* they always construct an individual type | ||
* I should change this | ||
* they can be the type of a value, e.g. polymorphic functions | ||
* Sequence: stack types | ||
|
||
### Subkinding | ||
|
||
``` | ||
Item | ||
/ \ | ||
Individual Generic | ||
Sequence | ||
``` | ||
|
||
## Syntax | ||
|
||
* `def drop[t : Item](*s t -- *s)` | ||
* First thing I thought of | ||
* Looks more natural to me | ||
* Similar to type parameter syntax for classes | ||
* `def drop(forall (t : Item). (*s t -- *s)):` | ||
* Uses existing forall syntax, but extended | ||
* Opens the door to allowing any type syntax as a type annotation |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
from typing import ( | ||
Callable, | ||
Iterable, | ||
Iterator, | ||
List, | ||
Optional, | ||
Sequence, | ||
Tuple, | ||
TypeVar, | ||
Union, | ||
overload, | ||
) | ||
from typing_extensions import Never | ||
|
||
_T_co = TypeVar('_T_co', covariant=True) | ||
_T = TypeVar('_T') | ||
|
||
|
||
class LinkedList(Sequence[_T_co]): | ||
def __init__( | ||
self, _val: Optional[Tuple[_T_co, 'LinkedList[_T_co]']] | ||
) -> None: | ||
self._val = _val | ||
self._length: Optional[int] = None | ||
|
||
@classmethod | ||
def from_iterable(cls, iterable: Iterable[_T_co]) -> 'LinkedList[_T_co]': | ||
if isinstance(iterable, cls): | ||
return iterable | ||
l: LinkedList[_T_co] = cls(None) | ||
head = l | ||
for el in iterable: | ||
next_node = cls(None) | ||
l._val = (el, next_node) | ||
l = next_node | ||
return head | ||
|
||
@overload | ||
def __getitem__(self, i: int) -> _T_co: | ||
pass | ||
|
||
@overload | ||
def __getitem__(self, i: slice) -> 'LinkedList[_T_co]': | ||
pass | ||
|
||
def __getitem__( | ||
self, i: Union[slice, int] | ||
) -> Union['LinkedList[_T_co]', _T_co]: | ||
if isinstance(i, slice): | ||
raise NotImplementedError | ||
for _ in range(i): | ||
if self._val is None: | ||
raise IndexError | ||
self = self._val[1] | ||
if self._val is None: | ||
raise IndexError | ||
return self._val[0] | ||
|
||
def __len__(self) -> int: | ||
if self._length is None: | ||
node = self | ||
length = 0 | ||
while node._val is not None: | ||
node = node._val[1] | ||
length += 1 | ||
self._length = length | ||
return self._length | ||
|
||
def __add__(self, other: 'LinkedList[_T_co]') -> 'LinkedList[_T_co]': | ||
if not isinstance(other, LinkedList): | ||
return NotImplemented | ||
for el in reversed(list(self)): | ||
other = LinkedList((el, other)) | ||
return other | ||
|
||
def filter(self, p: Callable[[_T_co], bool]) -> 'LinkedList[_T_co]': | ||
if self._val is None: | ||
return self | ||
# FIXME: Stack safety | ||
# TODO: Reuse as much of tail as possible | ||
if p(self._val[0]): | ||
tail = self._val[1].filter(p) | ||
return LinkedList((self._val[0], tail)) | ||
return self._val[1].filter(p) | ||
|
||
def _tails(self) -> 'List[LinkedList[_T_co]]': | ||
res: List[LinkedList[_T_co]] = [] | ||
while self._val is not None: | ||
res.append(self) | ||
self = self._val[1] | ||
return res | ||
|
||
def __iter__(self) -> Iterator[_T_co]: | ||
while self._val is not None: | ||
yield self._val[0] | ||
self = self._val[1] | ||
|
||
def __str__(self) -> str: | ||
return str(list(self)) | ||
|
||
def __repr__(self) -> str: | ||
return f'LinkedList.from_iterable({list(self)!r})' | ||
|
||
# "supertype defines the argument type as object" | ||
def __eq__(self, other: object) -> bool: | ||
if not isinstance(other, LinkedList): | ||
return NotImplemented | ||
if len(self) != len(other): | ||
return False | ||
for a, b in zip(self, other): | ||
if a != b: | ||
return False | ||
return True | ||
|
||
|
||
empty_list = LinkedList[Never](None) |
Oops, something went wrong.