Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
T
typon-compiler
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
typon
typon-compiler
Commits
85b27174
Commit
85b27174
authored
Aug 18, 2023
by
Tom Niget
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add preliminary support for list comprehensions
parent
00f0474f
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
272 additions
and
3 deletions
+272
-3
rt/include/python/builtins.hpp
rt/include/python/builtins.hpp
+24
-0
rt/include/python/builtins/list.hpp
rt/include/python/builtins/list.hpp
+1
-0
trans/stdlib/__init__.py
trans/stdlib/__init__.py
+2
-0
trans/tests/a_a_a_a_a_a_errtest.py
trans/tests/a_a_a_a_a_a_errtest.py
+10
-0
trans/tests/a_a_a_a_calcbasic.py
trans/tests/a_a_a_a_calcbasic.py
+167
-0
trans/transpiler/phases/emit_cpp/expr.py
trans/transpiler/phases/emit_cpp/expr.py
+34
-0
trans/transpiler/phases/typing/common.py
trans/transpiler/phases/typing/common.py
+15
-0
trans/transpiler/phases/typing/expr.py
trans/transpiler/phases/typing/expr.py
+18
-2
trans/transpiler/phases/typing/types.py
trans/transpiler/phases/typing/types.py
+1
-1
No files found.
rt/include/python/builtins.hpp
View file @
85b27174
...
...
@@ -294,4 +294,28 @@ template <class T> auto begin(std::shared_ptr<T> &obj) { return dotp(obj, begin)
template
<
class
T
>
auto
end
(
std
::
shared_ptr
<
T
>
&
obj
)
{
return
dotp
(
obj
,
end
)();
}
}
template
<
typename
T
>
struct
AlwaysTrue
{
// (1)
constexpr
bool
operator
()(
const
T
&
)
const
{
return
true
;
}
};
template
<
typename
Seq
>
struct
ValueTypeEx
{
using
type
=
decltype
(
*
std
::
begin
(
std
::
declval
<
Seq
&>
()));
};
// (2)
template
<
typename
Map
,
typename
Seq
,
typename
Filt
=
AlwaysTrue
<
typename
ValueTypeEx
<
Seq
>
::
type
>>
auto
mapFilter
(
Map
map
,
Seq
seq
,
Filt
filt
=
Filt
())
{
//typedef typename Seq::value_type value_type;
using
value_type
=
typename
ValueTypeEx
<
Seq
>::
type
;
using
return_type
=
decltype
(
map
(
std
::
declval
<
value_type
>
()));
std
::
vector
<
return_type
>
result
{};
for
(
auto
i
:
seq
|
std
::
views
::
filter
(
filt
)
|
std
::
views
::
transform
(
map
))
result
.
push_back
(
i
);
return
typon
::
PyList
(
std
::
move
(
result
));
}
#endif // TYPON_BUILTINS_HPP
rt/include/python/builtins/list.hpp
View file @
85b27174
...
...
@@ -15,6 +15,7 @@ namespace typon {
template
<
typename
T
>
class
PyList
{
public:
using
value_type
=
T
;
PyList
(
std
::
shared_ptr
<
std
::
vector
<
T
>>
&&
v
)
:
_v
(
std
::
move
(
v
))
{}
PyList
(
std
::
vector
<
T
>
&&
v
)
:
_v
(
std
::
move
(
std
::
make_shared
<
std
::
vector
<
T
>>
(
std
::
move
(
v
))))
{}
...
...
trans/stdlib/__init__.py
View file @
85b27174
...
...
@@ -17,6 +17,7 @@ class int:
def
__init__
(
self
,
x
:
str
)
->
None
:
...
def
__lt__
(
self
,
other
:
Self
)
->
bool
:
...
def
__gt__
(
self
,
other
:
Self
)
->
bool
:
...
def
__mod__
(
self
,
other
:
Self
)
->
Self
:
...
assert
int
.
__add__
...
...
@@ -71,6 +72,7 @@ class list(Generic[U]):
def
__len__
(
self
)
->
int
:
...
def
append
(
self
,
value
:
U
)
->
None
:
...
def
__contains__
(
self
,
item
:
U
)
->
bool
:
...
def
__init__
(
self
,
it
:
Iterator
[
U
])
->
None
:
...
assert
[
1
,
2
].
__iter__
()
assert
list
[
int
].
__iter__
...
...
trans/tests/a_a_errtest.py
→
trans/tests/a_a_
a_a_a_a_
errtest.py
View file @
85b27174
import
sys
import
math
def
g
àé
():
return
1
,
2
,
3
if
__name__
==
"__main__"
:
if
True
:
a
,
b
,
c
=
g
àé
()
# abc
\ No newline at end of file
a
=
[
n
for
n
in
range
(
10
)]
b
=
[
x
for
x
in
a
if
x
%
2
==
0
]
c
=
[
y
*
y
for
y
in
b
]
print
(
a
,
b
,
c
)
\ No newline at end of file
trans/tests/a_a_a_a_calcbasic.py
0 → 100644
View file @
85b27174
from
dataclasses
import
dataclass
from
typing
import
Any
,
Callable
from
enum
import
Enum
from
itertools
import
groupby
import
operator
import
string
@
dataclass
class
BinOperator
:
symbol
:
str
priority
:
int
perform
:
Callable
[[
float
,
float
],
float
]
OPERATORS
=
[
BinOperator
(
"+"
,
0
,
operator
.
add
),
BinOperator
(
"-"
,
0
,
operator
.
sub
),
BinOperator
(
"*"
,
1
,
operator
.
mul
),
BinOperator
(
"/"
,
1
,
operator
.
truediv
)
]
ops_by_priority
=
[
list
(
it
)
for
_
,
it
in
groupby
(
OPERATORS
,
lambda
op
:
op
.
priority
)]
MAX_PRIORITY
=
len
(
ops_by_priority
)
ops_syms
=
[
op
.
symbol
for
op
in
OPERATORS
]
class
TokenType
(
Enum
):
NUMBER
=
1
PARENTHESIS
=
2
OPERATION
=
3
@
dataclass
class
Token
:
type
:
TokenType
val
:
Any
def
tokenize
(
inp
:
str
):
tokens
=
[]
index
=
0
def
skip_spaces
():
nonlocal
index
while
inp
[
index
].
isspace
():
index
+=
1
def
has
():
return
index
<
len
(
inp
)
def
peek
():
return
inp
[
index
]
def
read
():
nonlocal
index
index
+=
1
return
inp
[
index
-
1
]
def
read_number
():
res
=
""
while
True
:
res
+=
read
()
if
not
has
()
or
peek
()
not
in
"0123456789."
:
break
return
Token
(
TokenType
.
NUMBER
,
float
(
res
)
if
"."
in
res
else
int
(
res
))
while
has
():
skip_spaces
()
next
=
peek
()
if
next
in
ops_syms
:
tok
=
Token
(
TokenType
.
OPERATION
,
read
())
elif
next
in
"()"
:
tok
=
Token
(
TokenType
.
PARENTHESIS
,
read
())
elif
next
in
"0123456789."
:
tok
=
read_number
()
else
:
raise
Exception
(
f"invalid character '
{
next
}
'"
,
index
)
tokens
.
append
(
tok
)
return
tokens
def
parse
(
tokens
):
index
=
0
def
has
():
return
index
<
len
(
tokens
)
def
current
():
if
not
has
():
raise
Exception
(
"expected token, got EOL"
)
return
tokens
[
index
]
def
match
(
type
:
TokenType
,
val
:
Any
=
None
):
return
has
()
and
tokens
[
index
].
type
==
type
and
(
val
is
None
or
tokens
[
index
].
val
==
val
)
def
accept
(
type
:
TokenType
,
val
:
Any
=
None
):
nonlocal
index
if
match
(
type
,
val
):
index
+=
1
return
True
return
False
def
expect
(
type
:
TokenType
,
val
:
Any
=
None
):
nonlocal
index
if
match
(
type
,
val
):
index
+=
1
return
tokens
[
index
-
1
]
if
not
has
():
raise
Exception
(
f"expected
{
type
}
, got EOL"
)
else
:
raise
Exception
(
f"expected
{
type
}
, got
{
current
().
type
}
"
)
def
parse_bin
(
priority
=
0
):
if
priority
>=
MAX_PRIORITY
:
return
parse_term
()
left
=
parse_bin
(
priority
+
1
)
ops
=
ops_by_priority
[
priority
]
while
has
()
and
current
().
type
==
TokenType
.
OPERATION
:
for
op
in
ops
:
if
accept
(
TokenType
.
OPERATION
,
op
.
symbol
):
right
=
parse_bin
(
priority
+
1
)
left
=
op
.
perform
(
left
,
right
)
break
else
:
break
return
left
def
parse_term
():
token
=
current
()
if
token
.
type
==
TokenType
.
NUMBER
:
return
expect
(
TokenType
.
NUMBER
).
val
elif
accept
(
TokenType
.
PARENTHESIS
,
"("
):
val
=
parse_expr
()
expect
(
TokenType
.
PARENTHESIS
,
")"
)
return
val
else
:
raise
Exception
(
f"expected term, got
{
token
.
type
}
"
)
def
parse_expr
():
return
parse_bin
()
return
parse_expr
()
if
__name__
==
"__main__"
:
while
True
:
inp
=
input
(
"> "
)
try
:
tok
=
tokenize
(
inp
)
res
=
parse
(
tok
)
print
(
res
)
except
Exception
as
e
:
print
(
e
)
print
()
trans/transpiler/phases/emit_cpp/expr.py
View file @
85b27174
...
...
@@ -110,6 +110,9 @@ class ExpressionVisitor(NodeVisitor):
# yield from self.visit_binary_operation(op, left, right, make_lnd(left, right))
def
visit_BoolOp
(
self
,
node
:
ast
.
BoolOp
)
->
Iterable
[
str
]:
if
len
(
node
.
values
)
==
1
:
yield
from
self
.
visit
(
node
.
values
[
0
])
return
cpp_op
=
{
ast
.
And
:
"&&"
,
ast
.
Or
:
"||"
...
...
@@ -297,3 +300,34 @@ class ExpressionVisitor(NodeVisitor):
# raise NotImplementedError(node)
yield
"co_yield"
yield
from
self
.
prec
(
"co_yield"
).
visit
(
node
.
value
)
def
visit_ListComp
(
self
,
node
:
ast
.
ListComp
)
->
Iterable
[
str
]:
if
len
(
node
.
generators
)
!=
1
:
raise
NotImplementedError
(
"Multiple generators not handled yet"
)
gen
:
ast
.
comprehension
=
node
.
generators
[
0
]
yield
"mapFilter([]("
yield
from
self
.
visit
(
node
.
input_item_type
)
yield
from
self
.
visit
(
gen
.
target
)
yield
") { return "
yield
from
self
.
visit
(
node
.
elt
)
yield
"; }, "
yield
from
self
.
visit
(
gen
.
iter
)
if
gen
.
ifs
:
yield
", "
yield
"[]("
yield
from
self
.
visit
(
node
.
input_item_type
)
yield
from
self
.
visit
(
gen
.
target
)
yield
") { return "
yield
from
self
.
visit
(
gen
.
ifs_node
)
yield
"; }"
yield
")"
# iter_type = get_iter(self.visit(gen.iter))
# next_type = get_next(iter_type)
# virt_scope = self.scope.child(ScopeKind.FUNCTION_INNER)
# from transpiler import ScoperBlockVisitor
# visitor = ScoperBlockVisitor(virt_scope)
# visitor.visit_assign_target(gen.target, next_type)
# res_item_type = visitor.expr().visit(node.elt)
# for if_ in gen.ifs:
# visitor.expr().visit(if_)
# return PyList(res_item_type)
\ No newline at end of file
trans/transpiler/phases/typing/common.py
View file @
85b27174
...
...
@@ -63,3 +63,18 @@ class ScoperVisitor(NodeVisitorSeq):
if
not
node
.
inner_scope
.
has_return
:
rtype
.
unify
(
TY_NONE
)
# todo: properly indicate missing return
def
get_iter
(
seq_type
):
try
:
iter_type
=
seq_type
.
methods
[
"__iter__"
].
return_type
except
:
from
transpiler.phases.typing.exceptions
import
NotIterableError
raise
NotIterableError
(
seq_type
)
return
iter_type
def
get_next
(
iter_type
):
try
:
next_type
=
iter_type
.
methods
[
"__next__"
].
return_type
except
:
from
transpiler.phases.typing.exceptions
import
NotIteratorError
raise
NotIteratorError
(
iter_type
)
return
next_type
\ No newline at end of file
trans/transpiler/phases/typing/expr.py
View file @
85b27174
...
...
@@ -4,7 +4,7 @@ import inspect
from
typing
import
List
from
transpiler.phases.typing
import
ScopeKind
,
VarDecl
,
VarKind
from
transpiler.phases.typing.common
import
ScoperVisitor
from
transpiler.phases.typing.common
import
ScoperVisitor
,
get_iter
,
get_next
from
transpiler.phases.typing.types
import
BaseType
,
TupleType
,
TY_STR
,
TY_BOOL
,
TY_INT
,
\
TY_COMPLEX
,
TY_NONE
,
FunctionType
,
PyList
,
TypeVariable
,
PySet
,
TypeType
,
PyDict
,
Promise
,
PromiseKind
,
UserType
,
\
TY_SLICE
...
...
@@ -248,4 +248,20 @@ class ScoperExprVisitor(ScoperVisitor):
return
self
.
visit_function_call
(
self
.
visit_getattr
(
TypeType
(
args
[
0
]),
f"__
{
name
}
__"
),
args
)
\ No newline at end of file
)
def
visit_ListComp
(
self
,
node
:
ast
.
ListComp
)
->
BaseType
:
if
len
(
node
.
generators
)
!=
1
:
raise
NotImplementedError
(
"Multiple generators not handled yet"
)
gen
:
ast
.
comprehension
=
node
.
generators
[
0
]
iter_type
=
get_iter
(
self
.
visit
(
gen
.
iter
))
node
.
input_item_type
=
get_next
(
iter_type
)
virt_scope
=
self
.
scope
.
child
(
ScopeKind
.
FUNCTION_INNER
)
from
transpiler
import
ScoperBlockVisitor
visitor
=
ScoperBlockVisitor
(
virt_scope
)
visitor
.
visit_assign_target
(
gen
.
target
,
node
.
input_item_type
)
node
.
item_type
=
visitor
.
expr
().
visit
(
node
.
elt
)
for
if_
in
gen
.
ifs
:
visitor
.
expr
().
visit
(
if_
)
gen
.
ifs_node
=
ast
.
BoolOp
(
ast
.
And
(),
gen
.
ifs
,
**
linenodata
(
node
))
return
PyList
(
node
.
item_type
)
\ No newline at end of file
trans/transpiler/phases/typing/types.py
View file @
85b27174
...
...
@@ -218,7 +218,7 @@ class TypeOperator(BaseType, ABC):
if
other
.
is_protocol
and
not
self
.
is_protocol
:
return
other
.
unify_internal
(
self
)
if
self
.
is_protocol
and
not
other
.
is_protocol
:
return
other
.
matches_protocol
(
self
)
return
other
.
matches_protocol
(
self
)
# TODO: doesn't print the correct type in the error message
if
len
(
self
.
args
)
<
len
(
other
.
args
):
return
other
.
unify_internal
(
self
)
assert
self
.
is_protocol
==
other
.
is_protocol
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment