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
6454a3ad
Commit
6454a3ad
authored
Feb 06, 2024
by
Tom Niget
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Continue work on new generics, a lot of stuff works
parent
f8de89ac
Changes
22
Show whitespace changes
Inline
Side-by-side
Showing
22 changed files
with
445 additions
and
1997 deletions
+445
-1997
notes2.txt
notes2.txt
+9
-0
pyproject.toml
pyproject.toml
+1
-0
typon/trans/stdlib/__init__.py
typon/trans/stdlib/__init__.py
+2
-0
typon/trans/tests/user_generics.py
typon/trans/tests/user_generics.py
+20
-20
typon/trans/transpiler/__init__.py
typon/trans/transpiler/__init__.py
+4
-5
typon/trans/transpiler/phases/typing/__init__.py
typon/trans/transpiler/phases/typing/__init__.py
+19
-1
typon/trans/transpiler/phases/typing/annotations.py
typon/trans/transpiler/phases/typing/annotations.py
+15
-7
typon/trans/transpiler/phases/typing/exceptions.py
typon/trans/transpiler/phases/typing/exceptions.py
+4
-4
typon/trans/transpiler/phases/typing/expr.py
typon/trans/transpiler/phases/typing/expr.py
+61
-54
typon/trans/transpiler/phases/typing/scope.py
typon/trans/transpiler/phases/typing/scope.py
+2
-2
typon/trans/transpiler/phases/typing/stdlib.py
typon/trans/transpiler/phases/typing/stdlib.py
+85
-31
typon/trans/transpiler/phases/typing/types.py
typon/trans/transpiler/phases/typing/types.py
+223
-28
typon/trans/transpiler/phases/typing2/__init__.py
typon/trans/transpiler/phases/typing2/__init__.py
+0
-78
typon/trans/transpiler/phases/typing2/annotations.py
typon/trans/transpiler/phases/typing2/annotations.py
+0
-56
typon/trans/transpiler/phases/typing2/block.py
typon/trans/transpiler/phases/typing2/block.py
+0
-426
typon/trans/transpiler/phases/typing2/class_.py
typon/trans/transpiler/phases/typing2/class_.py
+0
-36
typon/trans/transpiler/phases/typing2/common.py
typon/trans/transpiler/phases/typing2/common.py
+0
-126
typon/trans/transpiler/phases/typing2/exceptions.py
typon/trans/transpiler/phases/typing2/exceptions.py
+0
-322
typon/trans/transpiler/phases/typing2/expr.py
typon/trans/transpiler/phases/typing2/expr.py
+0
-300
typon/trans/transpiler/phases/typing2/scope.py
typon/trans/transpiler/phases/typing2/scope.py
+0
-95
typon/trans/transpiler/phases/typing2/stdlib.py
typon/trans/transpiler/phases/typing2/stdlib.py
+0
-149
typon/trans/transpiler/phases/typing2/types.py
typon/trans/transpiler/phases/typing2/types.py
+0
-257
No files found.
notes2.txt
View file @
6454a3ad
...
@@ -55,3 +55,12 @@ x = Container(4) # ici on instancie Container avec un TypeVar donc on a `x: Cont
...
@@ -55,3 +55,12 @@ x = Container(4) # ici on instancie Container avec un TypeVar donc on a `x: Cont
# et on lit le corps de __init__ pour faire le reste de l'unification
# et on lit le corps de __init__ pour faire le reste de l'unification
# self.x est de type A, via l'assignation on unifie A=C=int
# self.x est de type A, via l'assignation on unifie A=C=int
# donc x: Container[int]
# donc x: Container[int]
---------------------------------------------------------------------------
fonction : type concret qui a un type caché qui correspond à ce qui sera générique en gros
pareil pour les classes
donc on peut passer des types génériques puisqu'ils sont wrappés par un type concret
pyproject.toml
View file @
6454a3ad
...
@@ -12,6 +12,7 @@ dependencies = [
...
@@ -12,6 +12,7 @@ dependencies = [
"pygments ~= 2.15.1"
,
"pygments ~= 2.15.1"
,
"colorful ~= 0.5.5"
,
"colorful ~= 0.5.5"
,
"pybind11 ~= 2.11.1"
,
"pybind11 ~= 2.11.1"
,
"python-dotenv ~= 1.0.1"
,
]
]
[project.optional-dependencies]
[project.optional-dependencies]
...
...
typon/trans/stdlib/__init__.py
View file @
6454a3ad
from
typing
import
Self
,
Generic
,
Protocol
,
Optional
from
typing
import
Self
,
Generic
,
Protocol
,
Optional
assert
5
class
object
:
class
object
:
def
__eq__
(
self
,
other
:
Self
)
->
bool
:
...
def
__eq__
(
self
,
other
:
Self
)
->
bool
:
...
def
__ne__
(
self
,
other
:
Self
)
->
bool
:
...
def
__ne__
(
self
,
other
:
Self
)
->
bool
:
...
...
...
typon/trans/tests/user_generics.py
View file @
6454a3ad
# coding: utf-8
# coding: utf-8
from
dataclasses
import
dataclass
#
from dataclasses import dataclass
#
#
#
@
dataclass
#
@dataclass
class
Thing
[
T
]:
#
class Thing[T]:
x
:
T
#
x: T
def
f
[
T
](
x
:
T
):
#
def f[T](x: T):
pass
#
pass
#
#
#
#
if
__name__
==
"__main__"
:
#
if __name__ == "__main__":
a
=
Thing
[
int
](
1
)
#
a = Thing[int](1)
b
=
Thing
[
str
](
"abc"
)
#
b = Thing[str]("abc")
print
(
a
)
#
print(a)
print
(
b
)
#
print(b)
typon/trans/transpiler/__init__.py
View file @
6454a3ad
...
@@ -15,12 +15,11 @@ from transpiler.phases.desugar_op import DesugarOp
...
@@ -15,12 +15,11 @@ from transpiler.phases.desugar_op import DesugarOp
colorama
.
init
()
colorama
.
init
()
from
transpiler.phases.emit_cpp.consts
import
MAPPINGS
from
transpiler.exceptions
import
CompileError
from
transpiler.exceptions
import
CompileError
from
transpiler.phases.desugar_with
import
DesugarWith
from
transpiler.phases.desugar_with
import
DesugarWith
from
transpiler.phases.emit_cpp.file
import
FileVisitor
#
from transpiler.phases.emit_cpp.file import FileVisitor
from
transpiler.phases.if_main
import
IfMainVisitor
from
transpiler.phases.if_main
import
IfMainVisitor
from
transpiler.phases.typing.block
import
ScoperBlockVisitor
#
from transpiler.phases.typing.block import ScoperBlockVisitor
from
transpiler.phases.typing.scope
import
Scope
from
transpiler.phases.typing.scope
import
Scope
from
transpiler.utils
import
highlight
from
transpiler.utils
import
highlight
...
@@ -179,12 +178,12 @@ else:
...
@@ -179,12 +178,12 @@ else:
def
transpile
(
source
,
name
:
str
,
path
=
None
):
def
transpile
(
source
,
name
:
str
,
path
=
None
):
__TB__
=
f"transpiling module
{
cf
.
white
(
name
)
}
"
__TB__
=
f"transpiling module
{
cf
.
white
(
name
)
}
"
res
=
ast
.
parse
(
source
,
type_comments
=
True
)
res
=
ast
.
parse
(
source
,
type_comments
=
True
)
exit
()
IfMainVisitor
().
visit
(
res
)
IfMainVisitor
().
visit
(
res
)
res
=
DesugarWith
().
visit
(
res
)
res
=
DesugarWith
().
visit
(
res
)
res
=
DesugarCompare
().
visit
(
res
)
res
=
DesugarCompare
().
visit
(
res
)
res
=
DesugarOp
().
visit
(
res
)
res
=
DesugarOp
().
visit
(
res
)
ScoperBlockVisitor
().
visit
(
res
)
#
ScoperBlockVisitor().visit(res)
# print(res.scope)
# print(res.scope)
...
...
typon/trans/transpiler/phases/typing/__init__.py
View file @
6454a3ad
...
@@ -4,7 +4,7 @@ from logging import debug
...
@@ -4,7 +4,7 @@ from logging import debug
from
transpiler.phases.typing.scope
import
VarKind
,
VarDecl
,
ScopeKind
,
Scope
from
transpiler.phases.typing.scope
import
VarKind
,
VarDecl
,
ScopeKind
,
Scope
from
transpiler.phases.typing.stdlib
import
PRELUDE
,
StdlibVisitor
from
transpiler.phases.typing.stdlib
import
PRELUDE
,
StdlibVisitor
from
transpiler.phases.typing.types
import
TY_TYPE
,
TY_INT
,
TY_STR
,
TY_BOOL
,
TY_COMPLEX
,
TY_NONE
,
ResolvedConcreteType
,
\
from
transpiler.phases.typing.types
import
TY_TYPE
,
TY_INT
,
TY_STR
,
TY_BOOL
,
TY_COMPLEX
,
TY_NONE
,
ResolvedConcreteType
,
\
MemberDef
MemberDef
,
TY_FLOAT
,
TY_BUILTIN_FEATURE
,
TY_TUPLE
,
TY_DICT
,
TY_SET
,
TY_LIST
,
TY_BYTES
,
TY_OBJECT
,
TY_CPP_TYPE
# PRELUDE.vars.update({
# PRELUDE.vars.update({
# "int": VarDecl(VarKind.LOCAL, TypeType(TY_INT)),
# "int": VarDecl(VarKind.LOCAL, TypeType(TY_INT)),
...
@@ -31,6 +31,24 @@ from transpiler.phases.typing.types import TY_TYPE, TY_INT, TY_STR, TY_BOOL, TY_
...
@@ -31,6 +31,24 @@ from transpiler.phases.typing.types import TY_TYPE, TY_INT, TY_STR, TY_BOOL, TY_
# "Optional": VarDecl(VarKind.LOCAL, TypeType(lambda x: UnionType(x, TY_NONE))),
# "Optional": VarDecl(VarKind.LOCAL, TypeType(lambda x: UnionType(x, TY_NONE))),
# })
# })
prelude_vars
=
{
"object"
:
TY_OBJECT
,
"bool"
:
TY_BOOL
,
"int"
:
TY_INT
,
"float"
:
TY_FLOAT
,
"str"
:
TY_STR
,
"bytes"
:
TY_BYTES
,
"complex"
:
TY_COMPLEX
,
"list"
:
TY_LIST
,
"set"
:
TY_SET
,
"dict"
:
TY_DICT
,
"tuple"
:
TY_TUPLE
,
"BuiltinFeature"
:
TY_BUILTIN_FEATURE
,
"CppType"
:
TY_CPP_TYPE
}
PRELUDE
.
vars
.
update
({
name
:
VarDecl
(
VarKind
.
LOCAL
,
ty
.
type_type
())
for
name
,
ty
in
prelude_vars
.
items
()})
typon_std
=
Path
(
__file__
).
parent
.
parent
.
parent
.
parent
/
"stdlib"
typon_std
=
Path
(
__file__
).
parent
.
parent
.
parent
.
parent
/
"stdlib"
def
make_module
(
name
:
str
,
scope
:
Scope
)
->
ResolvedConcreteType
:
def
make_module
(
name
:
str
,
scope
:
Scope
)
->
ResolvedConcreteType
:
...
...
typon/trans/transpiler/phases/typing/annotations.py
View file @
6454a3ad
...
@@ -4,7 +4,8 @@ from dataclasses import dataclass, field
...
@@ -4,7 +4,8 @@ from dataclasses import dataclass, field
from
typing
import
Optional
,
List
from
typing
import
Optional
,
List
from
transpiler.phases.typing.scope
import
Scope
from
transpiler.phases.typing.scope
import
Scope
from
transpiler.phases.typing.types
import
BaseType
,
TY_NONE
,
TypeVariable
,
TY_TYPE
,
ResolvedConcreteType
,
TypeListType
from
transpiler.phases.typing.types
import
BaseType
,
TY_NONE
,
TypeVariable
,
TY_TYPE
,
ResolvedConcreteType
,
TypeListType
,
\
TY_BUILTIN_FEATURE
,
make_builtin_feature
,
TY_CPP_TYPE
,
make_cpp_type
,
GenericType
,
TY_UNION
from
transpiler.phases.utils
import
NodeVisitorSeq
from
transpiler.phases.utils
import
NodeVisitorSeq
...
@@ -33,11 +34,18 @@ class TypeAnnotationVisitor(NodeVisitorSeq):
...
@@ -33,11 +34,18 @@ class TypeAnnotationVisitor(NodeVisitorSeq):
raise
NotImplementedError
raise
NotImplementedError
def
visit_Subscript
(
self
,
node
:
ast
.
Subscript
)
->
BaseType
:
def
visit_Subscript
(
self
,
node
:
ast
.
Subscript
)
->
BaseType
:
# ty_op = self.visit(node.value)
ty_op
=
self
.
visit
(
node
.
value
)
# args = list(node.slice.elts) if type(node.slice) == ast.Tuple else [node.slice]
args
=
list
(
node
.
slice
.
elts
)
if
type
(
node
.
slice
)
==
ast
.
Tuple
else
[
node
.
slice
]
# args = [self.visit(arg) for arg in args]
args
=
[
self
.
visit
(
arg
)
for
arg
in
args
]
if
ty_op
is
TY_BUILTIN_FEATURE
:
assert
len
(
args
)
==
1
return
make_builtin_feature
(
args
[
0
])
elif
ty_op
is
TY_CPP_TYPE
:
assert
len
(
args
)
==
1
return
make_cpp_type
(
args
[
0
])
# return ty_op(*args)
# return ty_op(*args)
raise
NotImplementedError
()
assert
isinstance
(
ty_op
,
GenericType
)
return
ty_op
.
instantiate
(
args
)
# return TypeOperator([self.visit(node.value)], self.visit(node.slice.value))
# return TypeOperator([self.visit(node.value)], self.visit(node.slice.value))
def
visit_List
(
self
,
node
:
ast
.
List
)
->
BaseType
:
def
visit_List
(
self
,
node
:
ast
.
List
)
->
BaseType
:
...
@@ -51,6 +59,6 @@ class TypeAnnotationVisitor(NodeVisitorSeq):
...
@@ -51,6 +59,6 @@ class TypeAnnotationVisitor(NodeVisitorSeq):
# return res.type_object
# return res.type_object
def
visit_BinOp
(
self
,
node
:
ast
.
BinOp
)
->
BaseType
:
def
visit_BinOp
(
self
,
node
:
ast
.
BinOp
)
->
BaseType
:
#
if isinstance(node.op, ast.BitOr):
if
isinstance
(
node
.
op
,
ast
.
BitOr
):
# return UnionType(self.visit(node.left), self.visit(node.right)
)
return
TY_UNION
.
instantiate
([
self
.
visit
(
node
.
left
),
self
.
visit
(
node
.
right
)]
)
raise
NotImplementedError
(
node
.
op
)
raise
NotImplementedError
(
node
.
op
)
typon/trans/transpiler/phases/typing/exceptions.py
View file @
6454a3ad
...
@@ -4,7 +4,7 @@ from dataclasses import dataclass
...
@@ -4,7 +4,7 @@ from dataclasses import dataclass
from
transpiler.utils
import
highlight
from
transpiler.utils
import
highlight
from
transpiler.exceptions
import
CompileError
from
transpiler.exceptions
import
CompileError
from
transpiler.phases.typing.types
import
TypeVariable
,
BaseType
,
TypeOperator
from
transpiler.phases.typing.types
import
TypeVariable
,
BaseType
@
dataclass
@
dataclass
...
@@ -85,8 +85,8 @@ class TypeMismatchError(CompileError):
...
@@ -85,8 +85,8 @@ class TypeMismatchError(CompileError):
@
dataclass
@
dataclass
class
ArgumentCountMismatchError
(
CompileError
):
class
ArgumentCountMismatchError
(
CompileError
):
func
:
TypeOperator
func
:
"TypeOperator"
arguments
:
TypeOperator
arguments
:
"TypeOperator"
def
__str__
(
self
)
->
str
:
def
__str__
(
self
)
->
str
:
fcount
=
str
(
len
(
self
.
func
.
args
))
fcount
=
str
(
len
(
self
.
func
.
args
))
...
@@ -309,7 +309,7 @@ class InconsistentMroError(CompileError):
...
@@ -309,7 +309,7 @@ class InconsistentMroError(CompileError):
bases
:
list
[
BaseType
]
bases
:
list
[
BaseType
]
def
__str__
(
self
)
->
str
:
def
__str__
(
self
)
->
str
:
return
f"Cannot create a c
nossi
tent method resolution order (MRO) for bases
{
'
\
n
'
.
join
(
map
(
highlight
,
self
.
bases
))
}
"
return
f"Cannot create a c
onsis
tent method resolution order (MRO) for bases
{
'
\
n
'
.
join
(
map
(
highlight
,
self
.
bases
))
}
"
def
detail
(
self
,
last_node
:
ast
.
AST
=
None
)
->
str
:
def
detail
(
self
,
last_node
:
ast
.
AST
=
None
)
->
str
:
return
f"""
return
f"""
...
...
typon/trans/transpiler/phases/typing/expr.py
View file @
6454a3ad
...
@@ -5,7 +5,9 @@ from typing import List
...
@@ -5,7 +5,9 @@ from typing import List
from
transpiler.phases.typing
import
ScopeKind
,
VarDecl
,
VarKind
from
transpiler.phases.typing
import
ScopeKind
,
VarDecl
,
VarKind
from
transpiler.phases.typing.common
import
ScoperVisitor
,
get_iter
,
get_next
,
is_builtin
from
transpiler.phases.typing.common
import
ScoperVisitor
,
get_iter
,
get_next
,
is_builtin
from
transpiler.phases.typing.types
import
BaseType
from
transpiler.phases.typing.types
import
BaseType
,
TY_STR
,
TY_BOOL
,
TY_INT
,
TY_COMPLEX
,
TY_FLOAT
,
TY_NONE
,
\
ClassTypeType
,
ResolvedConcreteType
,
GenericType
,
CallableInstanceType
,
TY_LIST
,
TY_SET
,
TY_DICT
,
RuntimeValue
,
\
TypeVariable
,
TY_LAMBDA
,
TypeListType
from
transpiler.utils
import
linenodata
from
transpiler.utils
import
linenodata
DUNDER
=
{
DUNDER
=
{
...
@@ -91,8 +93,8 @@ class ScoperExprVisitor(ScoperVisitor):
...
@@ -91,8 +93,8 @@ class ScoperExprVisitor(ScoperVisitor):
from
transpiler.phases.typing.exceptions
import
UnknownNameError
from
transpiler.phases.typing.exceptions
import
UnknownNameError
raise
UnknownNameError
(
node
.
id
)
raise
UnknownNameError
(
node
.
id
)
ty
=
obj
.
type
.
resolve
()
ty
=
obj
.
type
.
resolve
()
if
isinstance
(
ty
,
TypeType
)
and
isinstance
(
ty
.
type_object
,
TypeVariable
):
#
if isinstance(ty, TypeType) and isinstance(ty.type_object, TypeVariable):
raise
NameError
(
f"Use of type variable"
)
# todo: when does this happen exactly?
#
raise NameError(f"Use of type variable") # todo: when does this happen exactly?
if
getattr
(
ty
,
"is_python_func"
,
False
):
if
getattr
(
ty
,
"is_python_func"
,
False
):
ty
.
python_func_used
=
True
ty
.
python_func_used
=
True
return
ty
return
ty
...
@@ -104,46 +106,48 @@ class ScoperExprVisitor(ScoperVisitor):
...
@@ -104,46 +106,48 @@ class ScoperExprVisitor(ScoperVisitor):
def
visit_Call
(
self
,
node
:
ast
.
Call
)
->
BaseType
:
def
visit_Call
(
self
,
node
:
ast
.
Call
)
->
BaseType
:
ftype
=
self
.
visit
(
node
.
func
)
ftype
=
self
.
visit
(
node
.
func
)
if
is_builtin
(
ftype
,
"TypeVar"
):
return
TypeType
(
TypeVariable
(
*
[
ast
.
literal_eval
(
arg
)
for
arg
in
node
.
args
]))
if
ftype
.
typevars
:
ftype
=
ftype
.
gen_sub
(
None
,
{
v
.
name
:
TypeVariable
(
v
.
name
)
for
v
in
ftype
.
typevars
})
from
transpiler.exceptions
import
CompileError
from
transpiler.exceptions
import
CompileError
rtype
=
self
.
visit_function_call
(
ftype
,
[
self
.
visit
(
arg
)
for
arg
in
node
.
args
])
rtype
=
self
.
visit_function_call
(
ftype
,
[
self
.
visit
(
arg
)
for
arg
in
node
.
args
])
actual
=
rtype
actual
=
rtype
node
.
is_await
=
False
node
.
is_await
=
False
if
isinstance
(
actual
,
Promise
)
and
actual
.
kind
!=
PromiseKind
.
GENERATOR
:
#
if isinstance(actual, Promise) and actual.kind != PromiseKind.GENERATOR:
node
.
is_await
=
True
#
node.is_await = True
actual
=
actual
.
return_type
.
resolve
()
#
actual = actual.return_type.resolve()
#
if
self
.
scope
.
function
and
isinstance
(
actual
,
Promise
)
and
actual
.
kind
==
PromiseKind
.
FORKED
\
#
if self.scope.function and isinstance(actual, Promise) and actual.kind == PromiseKind.FORKED \
and
isinstance
(
fty
:
=
self
.
scope
.
function
.
obj_type
.
return_type
,
Promise
):
#
and isinstance(fty := self.scope.function.obj_type.return_type, Promise):
fty
.
kind
=
PromiseKind
.
JOIN
#
fty.kind = PromiseKind.JOIN
return
actual
return
actual
def
visit_function_call
(
self
,
ftype
:
BaseType
,
arguments
:
List
[
BaseType
]):
def
visit_function_call
(
self
,
ftype
:
ResolvedConcreteType
,
arguments
:
List
[
BaseType
]):
if
isinstance
(
ftype
,
TypeType
):
# and isinstance(ftype.type_object, UserType):
if
isinstance
(
ftype
,
GenericType
):
init
:
FunctionType
=
self
.
visit_getattr
(
ftype
,
"__init__"
).
remove_self
()
ftype
=
ftype
.
instantiate_default
()
init
.
return_type
=
ftype
.
type_object
assert
isinstance
(
ftype
,
CallableInstanceType
)
return
self
.
visit_function_call
(
init
,
arguments
)
for
a
,
b
in
zip
(
ftype
.
parameters
,
arguments
):
if
isinstance
(
ftype
,
FunctionType
):
a
.
try_assign
(
b
)
ret
=
ftype
.
return_type
return
ftype
.
return_type
elif
isinstance
(
ftype
,
TypeVariable
):
# if isinstance(ftype, TypeType):# and isinstance(ftype.type_object, UserType):
ret
=
TypeVariable
()
# init: FunctionType = self.visit_getattr(ftype, "__init__").remove_self()
else
:
# init.return_type = ftype.type_object
from
transpiler.phases.typing.exceptions
import
NotCallableError
# return self.visit_function_call(init, arguments)
raise
NotCallableError
(
ftype
)
# if isinstance(ftype, FunctionType):
#is_generic = any(isinstance(arg, TypeVariable) for arg in ftype.to_list())
# ret = ftype.return_type
equivalent
=
FunctionType
(
arguments
,
ret
)
# elif isinstance(ftype, TypeVariable):
equivalent
.
is_intermediary
=
True
# ret = TypeVariable()
ftype
.
unify
(
equivalent
)
# else:
return
equivalent
.
return_type
# from transpiler.phases.typing.exceptions import NotCallableError
# raise NotCallableError(ftype)
# #is_generic = any(isinstance(arg, TypeVariable) for arg in ftype.to_list())
# equivalent = FunctionType(arguments, ret)
# equivalent.is_intermediary = True
# ftype.unify(equivalent)
# return equivalent.return_type
def
visit_Lambda
(
self
,
node
:
ast
.
Lambda
)
->
BaseType
:
def
visit_Lambda
(
self
,
node
:
ast
.
Lambda
)
->
BaseType
:
argtypes
=
[
TypeVariable
()
for
_
in
node
.
args
.
args
]
argtypes
=
[
TypeVariable
()
for
_
in
node
.
args
.
args
]
rtype
=
TypeVariable
()
rtype
=
TypeVariable
()
ftype
=
FunctionType
(
argtypes
,
rtype
)
ftype
=
TY_LAMBDA
.
instantiate
([
TypeListType
(
argtypes
),
rtype
]
)
scope
=
self
.
scope
.
child
(
ScopeKind
.
FUNCTION
)
scope
=
self
.
scope
.
child
(
ScopeKind
.
FUNCTION
)
scope
.
obj_type
=
ftype
scope
.
obj_type
=
ftype
scope
.
function
=
scope
scope
.
function
=
scope
...
@@ -173,21 +177,27 @@ class ScoperExprVisitor(ScoperVisitor):
...
@@ -173,21 +177,27 @@ class ScoperExprVisitor(ScoperVisitor):
return
self
.
visit_getattr
(
ltype
,
node
.
attr
)
return
self
.
visit_getattr
(
ltype
,
node
.
attr
)
def
visit_getattr
(
self
,
ltype
:
BaseType
,
name
:
str
)
->
BaseType
:
def
visit_getattr
(
self
,
ltype
:
BaseType
,
name
:
str
)
->
BaseType
:
bound
=
True
bound
=
True
if
isinstance
(
ltype
,
TypeType
):
if
isinstance
(
ltype
,
Class
TypeType
):
# if mdecl := ltype.static_members.get(name):
# if mdecl := ltype.static_members.get(name):
# attr = mdecl.type
# attr = mdecl.type
# if getattr(attr, "is_python_func", False):
# if getattr(attr, "is_python_func", False):
# attr.python_func_used = True
# attr.python_func_used = True
# return attr
# return attr
ltype
=
ltype
.
type_object
ltype
=
ltype
.
inner_type
bound
=
False
bound
=
False
if
isinstance
(
ltype
,
abc
.
ABCMeta
):
ctor
=
ltype
.
__init__
if
isinstance
(
ltype
,
GenericType
):
args
=
list
(
inspect
.
signature
(
ctor
).
parameters
.
values
())[
1
:]
ltype
=
ltype
.
instantiate_default
()
if
not
all
(
arg
.
annotation
==
BaseType
for
arg
in
args
):
raise
NotImplementedError
(
"I don't know how to handle this type"
)
assert
isinstance
(
ltype
,
ResolvedConcreteType
)
ltype
=
ltype
(
*
(
TypeVariable
()
for
_
in
args
))
# if isinstance(ltype, abc.ABCMeta):
# ctor = ltype.__init__
# args = list(inspect.signature(ctor).parameters.values())[1:]
# if not all(arg.annotation == BaseType for arg in args):
# raise NotImplementedError("I don't know how to handle this type")
# ltype = ltype(*(TypeVariable() for _ in args))
# if mdecl := ltype.members.get(name):
# if mdecl := ltype.members.get(name):
# attr = mdecl.type
# attr = mdecl.type
# if getattr(attr, "is_python_func", False):
# if getattr(attr, "is_python_func", False):
...
@@ -203,15 +213,14 @@ class ScoperExprVisitor(ScoperVisitor):
...
@@ -203,15 +213,14 @@ class ScoperExprVisitor(ScoperVisitor):
ty
=
field
.
type
.
resolve
()
ty
=
field
.
type
.
resolve
()
if
getattr
(
ty
,
"is_python_func"
,
False
):
if
getattr
(
ty
,
"is_python_func"
,
False
):
ty
.
python_func_used
=
True
ty
.
python_func_used
=
True
if
isinstance
(
ty
,
FunctionType
):
if
isinstance
(
ty
,
CallableInstanceType
):
ty
=
ty
.
gen_sub
(
ltype
,
{})
if
bound
and
field
.
in_class_def
and
type
(
field
.
val
)
!=
RuntimeValue
:
if
bound
and
field
.
in_class_def
and
type
(
field
.
val
)
!=
RuntimeValue
:
return
ty
.
remove_self
()
return
ty
.
remove_self
()
return
ty
return
ty
from
transpiler.phases.typing.exceptions
import
MissingAttributeError
from
transpiler.phases.typing.exceptions
import
MissingAttributeError
parents
=
ltype
.
iter_hierarchy_recursive
(
)
parents
=
iter
(
ltype
.
get_mro
()
)
next
(
parents
)
next
(
parents
)
for
p
in
parents
:
for
p
in
parents
:
try
:
try
:
...
@@ -224,7 +233,7 @@ class ScoperExprVisitor(ScoperVisitor):
...
@@ -224,7 +233,7 @@ class ScoperExprVisitor(ScoperVisitor):
def
visit_List
(
self
,
node
:
ast
.
List
)
->
BaseType
:
def
visit_List
(
self
,
node
:
ast
.
List
)
->
BaseType
:
if
not
node
.
elts
:
if
not
node
.
elts
:
return
PyList
(
TypeVariable
()
)
return
TY_LIST
.
instantiate_default
(
)
elems
=
[
self
.
visit
(
e
)
for
e
in
node
.
elts
]
elems
=
[
self
.
visit
(
e
)
for
e
in
node
.
elts
]
first
,
*
rest
=
elems
first
,
*
rest
=
elems
for
e
in
rest
:
for
e
in
rest
:
...
@@ -232,33 +241,31 @@ class ScoperExprVisitor(ScoperVisitor):
...
@@ -232,33 +241,31 @@ class ScoperExprVisitor(ScoperVisitor):
first
.
unify
(
e
)
first
.
unify
(
e
)
except
:
except
:
raise
NotImplementedError
(
f"List with different types not handled yet:
{
', '
.
join
(
map
(
str
,
elems
))
}
"
)
raise
NotImplementedError
(
f"List with different types not handled yet:
{
', '
.
join
(
map
(
str
,
elems
))
}
"
)
return
PyList
(
elems
[
0
])
return
TY_LIST
.
instantiate
([
elems
[
0
]
])
def
visit_Set
(
self
,
node
:
ast
.
Set
)
->
BaseType
:
def
visit_Set
(
self
,
node
:
ast
.
Set
)
->
BaseType
:
if
not
node
.
elts
:
if
not
node
.
elts
:
return
PySet
(
TypeVariable
()
)
return
TY_SET
.
instantiate_default
(
)
elems
=
[
self
.
visit
(
e
)
for
e
in
node
.
elts
]
elems
=
[
self
.
visit
(
e
)
for
e
in
node
.
elts
]
if
len
(
set
(
elems
))
!=
1
:
if
len
(
set
(
elems
))
!=
1
:
raise
NotImplementedError
(
"Set with different types not handled yet"
)
raise
NotImplementedError
(
"Set with different types not handled yet"
)
return
PySet
(
elems
[
0
])
return
TY_SET
.
instantiate
([
elems
[
0
]
])
def
visit_Dict
(
self
,
node
:
ast
.
Dict
)
->
BaseType
:
def
visit_Dict
(
self
,
node
:
ast
.
Dict
)
->
BaseType
:
if
not
node
.
keys
:
if
not
node
.
keys
:
return
PyDict
(
TypeVariable
(),
TypeVariable
()
)
return
TY_DICT
.
instantiate_default
(
)
keys
=
[
self
.
visit
(
e
)
for
e
in
node
.
keys
]
keys
=
[
self
.
visit
(
e
)
for
e
in
node
.
keys
]
values
=
[
self
.
visit
(
e
)
for
e
in
node
.
values
]
values
=
[
self
.
visit
(
e
)
for
e
in
node
.
values
]
if
len
(
set
(
keys
))
!=
1
or
len
(
set
(
values
))
!=
1
:
if
len
(
set
(
keys
))
!=
1
or
len
(
set
(
values
))
!=
1
:
raise
NotImplementedError
(
f"Dict with different types not handled yet in `
{
ast
.
unparse
(
node
)
}
`"
)
raise
NotImplementedError
(
f"Dict with different types not handled yet in `
{
ast
.
unparse
(
node
)
}
`"
)
return
PyDict
(
keys
[
0
],
values
[
0
])
return
TY_DICT
.
instantiate
([
keys
[
0
],
values
[
0
]
])
def
visit_Subscript
(
self
,
node
:
ast
.
Subscript
)
->
BaseType
:
def
visit_Subscript
(
self
,
node
:
ast
.
Subscript
)
->
BaseType
:
left
=
self
.
visit
(
node
.
value
)
left
=
self
.
visit
(
node
.
value
)
if
isinstance
(
left
,
ClassTypeType
):
return
self
.
anno
().
visit
(
node
)
args
=
node
.
slice
if
type
(
node
.
slice
)
==
tuple
else
[
node
.
slice
]
args
=
node
.
slice
if
type
(
node
.
slice
)
==
tuple
else
[
node
.
slice
]
args
=
[
self
.
visit
(
e
)
for
e
in
args
]
args
=
[
self
.
visit
(
e
)
for
e
in
args
]
if
isinstance
(
left
,
TypeType
)
and
isinstance
(
left
.
type_object
,
abc
.
ABCMeta
):
# generic
return
TypeType
(
left
.
type_object
(
*
[
arg
.
type_object
if
isinstance
(
arg
,
TypeType
)
else
arg
for
arg
in
args
]))
pass
return
self
.
make_dunder
([
left
,
*
args
],
"getitem"
)
return
self
.
make_dunder
([
left
,
*
args
],
"getitem"
)
def
visit_UnaryOp
(
self
,
node
:
ast
.
UnaryOp
)
->
BaseType
:
def
visit_UnaryOp
(
self
,
node
:
ast
.
UnaryOp
)
->
BaseType
:
...
@@ -277,7 +284,7 @@ class ScoperExprVisitor(ScoperVisitor):
...
@@ -277,7 +284,7 @@ class ScoperExprVisitor(ScoperVisitor):
def
make_dunder
(
self
,
args
:
List
[
BaseType
],
name
:
str
)
->
BaseType
:
def
make_dunder
(
self
,
args
:
List
[
BaseType
],
name
:
str
)
->
BaseType
:
return
self
.
visit_function_call
(
return
self
.
visit_function_call
(
self
.
visit_getattr
(
TypeType
(
args
[
0
])
,
f"__
{
name
}
__"
),
self
.
visit_getattr
(
args
[
0
]
,
f"__
{
name
}
__"
),
args
args
)
)
...
...
typon/trans/transpiler/phases/typing/scope.py
View file @
6454a3ad
import
ast
import
ast
from
dataclasses
import
field
,
dataclass
from
dataclasses
import
field
,
dataclass
from
enum
import
Enum
from
enum
import
Enum
from
typing
import
Optional
,
Dict
,
List
,
Any
from
typing
import
Optional
,
Dict
,
List
,
Any
,
Self
from
transpiler.phases.typing.types
import
BaseType
,
RuntimeValue
from
transpiler.phases.typing.types
import
BaseType
,
RuntimeValue
...
@@ -67,7 +67,7 @@ class Scope:
...
@@ -67,7 +67,7 @@ class Scope:
return
self
.
parent
.
is_in_loop
()
return
self
.
parent
.
is_in_loop
()
return
None
return
None
def
child
(
self
,
kind
:
ScopeKind
):
def
child
(
self
,
kind
:
ScopeKind
)
->
Self
:
res
=
Scope
(
self
,
kind
,
self
.
function
,
self
.
global_scope
)
res
=
Scope
(
self
,
kind
,
self
.
function
,
self
.
global_scope
)
if
kind
==
ScopeKind
.
GLOBAL
:
if
kind
==
ScopeKind
.
GLOBAL
:
res
.
global_scope
=
res
res
.
global_scope
=
res
...
...
typon/trans/transpiler/phases/typing/stdlib.py
View file @
6454a3ad
...
@@ -4,13 +4,15 @@ from abc import ABCMeta
...
@@ -4,13 +4,15 @@ from abc import ABCMeta
from
dataclasses
import
dataclass
,
field
from
dataclasses
import
dataclass
,
field
from
typing
import
Optional
,
List
,
Dict
,
Callable
from
typing
import
Optional
,
List
,
Dict
,
Callable
from
logging
import
debug
from
logging
import
debug
from
transpiler.utils
import
highlight
from
transpiler.phases.typing.annotations
import
TypeAnnotationVisitor
from
transpiler.phases.typing.annotations
import
TypeAnnotationVisitor
from
transpiler.phases.typing.common
import
PRELUDE
,
is_builtin
from
transpiler.phases.typing.common
import
PRELUDE
,
is_builtin
from
transpiler.phases.typing.expr
import
ScoperExprVisitor
from
transpiler.phases.typing.expr
import
ScoperExprVisitor
from
transpiler.phases.typing.scope
import
Scope
,
VarDecl
,
VarKind
,
ScopeKind
from
transpiler.phases.typing.scope
import
Scope
,
VarDecl
,
VarKind
,
ScopeKind
from
transpiler.phases.typing.types
import
BaseType
,
BuiltinGenericType
,
BuiltinType
,
create_builtin_generic_type
,
\
from
transpiler.phases.typing.types
import
BaseType
,
BuiltinGenericType
,
BuiltinType
,
create_builtin_generic_type
,
\
create_builtin_type
,
ConcreteType
,
GenericInstanceType
,
TypeListType
,
TypeTupleType
,
GenericParameter
,
\
create_builtin_type
,
ConcreteType
,
GenericInstanceType
,
TypeListType
,
TypeTupleType
,
GenericParameter
,
\
GenericParameterKind
,
TypeVariable
GenericParameterKind
,
TypeVariable
,
ResolvedConcreteType
,
MemberDef
,
ClassTypeType
,
CallableInstanceType
from
transpiler.phases.utils
import
NodeVisitorSeq
from
transpiler.phases.utils
import
NodeVisitorSeq
def
visit_generic_item
(
def
visit_generic_item
(
...
@@ -18,8 +20,9 @@ def visit_generic_item(
...
@@ -18,8 +20,9 @@ def visit_generic_item(
node
,
node
,
output_type
:
BuiltinGenericType
,
output_type
:
BuiltinGenericType
,
scope
:
Scope
,
scope
:
Scope
,
instance_type
=
None
):
instance_type
=
None
,
if
node
.
type_params
:
force_generic
=
False
):
if
force_generic
or
node
.
type_params
:
output_type
.
parameters
=
[]
output_type
.
parameters
=
[]
for
param
in
node
.
type_params
:
for
param
in
node
.
type_params
:
match
param
:
match
param
:
...
@@ -47,19 +50,21 @@ def visit_generic_item(
...
@@ -47,19 +50,21 @@ def visit_generic_item(
op_val
=
TypeVariable
()
op_val
=
TypeVariable
()
match
param
:
match
param
:
case
ast
.
TypeVar
(
name
,
bound
):
case
ast
.
TypeVar
(
name
,
bound
):
new_scope
.
declare_local
(
name
,
op_val
)
new_scope
.
declare_local
(
name
,
op_val
.
type_type
()
)
if
bound
is
not
None
:
if
bound
is
not
None
:
constraints
.
append
((
op_val
,
anno
.
visit
(
bound
)))
constraints
.
append
((
op_val
,
anno
.
visit
(
bound
)))
case
ast
.
ParamSpec
(
name
):
case
ast
.
ParamSpec
(
name
):
assert
isinstance
(
op_val
,
TypeListType
)
assert
isinstance
(
op_val
,
TypeListType
)
new_scope
.
declare_local
(
name
,
op_val
)
new_scope
.
declare_local
(
name
,
op_val
.
type_type
()
)
case
ast
.
TypeVarTuple
(
name
):
case
ast
.
TypeVarTuple
(
name
):
new_scope
.
declare_local
(
name
,
TypeTupleType
(
list
(
args_iter
)))
new_scope
.
declare_local
(
name
,
TypeTupleType
(
list
(
args_iter
)).
type_type
())
for
a
,
b
in
constraints
:
# for a, b in constraints:
raise
NotImplementedError
()
# raise NotImplementedError()
# todo
new_output_type
=
instance_type
()
new_output_type
=
instance_type
()
visit_nongeneric
(
new_scope
,
new_output_type
)
visit_nongeneric
(
new_scope
,
new_output_type
)
return
new_output_type
return
new_output_type
output_type
.
constraints_
=
[]
output_type
.
instantiate_
=
instantiate
output_type
.
instantiate_
=
instantiate
else
:
else
:
visit_nongeneric
(
scope
,
output_type
)
visit_nongeneric
(
scope
,
output_type
)
...
@@ -68,7 +73,7 @@ def visit_generic_item(
...
@@ -68,7 +73,7 @@ def visit_generic_item(
@
dataclass
@
dataclass
class
StdlibVisitor
(
NodeVisitorSeq
):
class
StdlibVisitor
(
NodeVisitorSeq
):
scope
:
Scope
=
field
(
default_factory
=
lambda
:
PRELUDE
)
scope
:
Scope
=
field
(
default_factory
=
lambda
:
PRELUDE
)
cur_class
:
Optional
[
Bas
eType
]
=
None
cur_class
:
Optional
[
ResolvedConcret
eType
]
=
None
typevars
:
Dict
[
str
,
BaseType
]
=
field
(
default_factory
=
dict
)
typevars
:
Dict
[
str
,
BaseType
]
=
field
(
default_factory
=
dict
)
def
expr
(
self
)
->
ScoperExprVisitor
:
def
expr
(
self
)
->
ScoperExprVisitor
:
...
@@ -84,8 +89,8 @@ class StdlibVisitor(NodeVisitorSeq):
...
@@ -84,8 +89,8 @@ class StdlibVisitor(NodeVisitorSeq):
def
visit_AnnAssign
(
self
,
node
:
ast
.
AnnAssign
):
def
visit_AnnAssign
(
self
,
node
:
ast
.
AnnAssign
):
ty
=
self
.
anno
().
visit
(
node
.
annotation
)
ty
=
self
.
anno
().
visit
(
node
.
annotation
)
if
self
.
cur_class
:
if
self
.
cur_class
:
assert
isinstance
(
self
.
cur_class
,
Typ
eType
)
assert
isinstance
(
self
.
cur_class
,
ResolvedConcret
eType
)
self
.
cur_class
.
type_object
.
fields
[
node
.
target
.
id
]
=
MemberDef
(
ty
.
gen_sub
(
self
.
cur_class
.
type_object
,
self
.
typevars
)
)
self
.
cur_class
.
fields
[
node
.
target
.
id
]
=
MemberDef
(
ty
)
self
.
scope
.
vars
[
node
.
target
.
id
]
=
VarDecl
(
VarKind
.
LOCAL
,
ty
)
self
.
scope
.
vars
[
node
.
target
.
id
]
=
VarDecl
(
VarKind
.
LOCAL
,
ty
)
def
visit_ImportFrom
(
self
,
node
:
ast
.
ImportFrom
):
def
visit_ImportFrom
(
self
,
node
:
ast
.
ImportFrom
):
...
@@ -96,14 +101,16 @@ class StdlibVisitor(NodeVisitorSeq):
...
@@ -96,14 +101,16 @@ class StdlibVisitor(NodeVisitorSeq):
def
visit_ClassDef
(
self
,
node
:
ast
.
ClassDef
):
def
visit_ClassDef
(
self
,
node
:
ast
.
ClassDef
):
if
existing
:
=
self
.
scope
.
get
(
node
.
name
):
if
existing
:
=
self
.
scope
.
get
(
node
.
name
):
NewType
=
existing
.
type
assert
isinstance
(
existing
.
type
,
ClassTypeType
)
NewType
=
existing
.
type
.
inner_type
else
:
else
:
base_class
=
create_builtin_generic_type
if
node
.
type_params
else
create_builtin_type
base_class
=
create_builtin_generic_type
if
node
.
type_params
else
create_builtin_type
NewType
=
base_class
(
node
.
name
)
NewType
=
base_class
(
node
.
name
)
self
.
scope
.
vars
[
node
.
name
]
=
VarDecl
(
VarKind
.
LOCAL
,
NewType
.
type_type
())
self
.
scope
.
vars
[
node
.
name
]
=
VarDecl
(
VarKind
.
LOCAL
,
NewType
.
type_type
())
def
visit_nongeneric
(
scope
,
output
:
ConcreteType
):
def
visit_nongeneric
(
scope
:
Scope
,
output
:
ConcreteType
):
cl_scope
=
scope
.
child
(
ScopeKind
.
CLASS
)
cl_scope
=
scope
.
child
(
ScopeKind
.
CLASS
)
cl_scope
.
declare_local
(
"Self"
,
output
.
type_type
())
visitor
=
StdlibVisitor
(
cl_scope
,
output
)
visitor
=
StdlibVisitor
(
cl_scope
,
output
)
for
stmt
in
node
.
body
:
for
stmt
in
node
.
body
:
visitor
.
visit
(
stmt
)
visitor
.
visit
(
stmt
)
...
@@ -114,17 +121,74 @@ class StdlibVisitor(NodeVisitorSeq):
...
@@ -114,17 +121,74 @@ class StdlibVisitor(NodeVisitorSeq):
pass
pass
def
visit_FunctionDef
(
self
,
node
:
ast
.
FunctionDef
):
def
visit_FunctionDef
(
self
,
node
:
ast
.
FunctionDef
):
def
visit_nongeneric
(
scope
,
output
:
ConcreteType
):
def
visit_nongeneric
(
scope
,
output
:
CallableInstanceType
):
cl_scope
=
scope
.
child
(
ScopeKind
.
CLASS
)
scope
=
scope
.
child
(
ScopeKind
.
FUNCTION
)
visitor
=
StdlibVisitor
(
cl_scope
,
output
)
arg_visitor
=
TypeAnnotationVisitor
(
scope
)
for
stmt
in
node
.
body
:
output
.
parameters
=
[
arg_visitor
.
visit
(
arg
.
annotation
)
for
arg
in
node
.
args
.
args
]
visitor
.
visit
(
stmt
)
output
.
return_type
=
arg_visitor
.
visit
(
node
.
returns
)
@
dataclass
(
eq
=
False
,
init
=
False
)
class
InstanceType
(
CallableInstanceType
):
def
__init__
(
self
):
super
().
__init__
([],
None
)
def
__str__
(
self
):
return
f"
{
node
.
name
}
(
{
", "
.
join
(
map
(
str
,
self
.
parameters
))
}
) ->
{
self
.
return_type
}
"
'''
'''
class arguments(__ast.AST):
class arguments(__ast.AST):
""" arguments(arg* posonlyargs, arg* args, arg? vararg, arg* kwonlyargs, expr* kw_defaults, arg? kwarg, expr* defaults) """'''
""" arguments(arg* posonlyargs, arg* args, arg? vararg, arg* kwonlyargs, expr* kw_defaults, arg? kwarg, expr* defaults) """'''
visit_generic_item
(
visit_nongeneric
,
node
,
NewType
,
self
.
scope
)
args
=
node
.
args
assert
args
.
posonlyargs
==
[]
#assert args.vararg is None TODO
assert
args
.
kwonlyargs
==
[]
assert
args
.
kw_defaults
==
[]
assert
args
.
kwarg
is
None
#assert args.defaults == [] TODO
for
i
,
arg
in
enumerate
(
args
.
args
):
arg
:
ast
.
arg
""" arg(identifier arg, expr? annotation, string? type_comment) """
if
arg
.
annotation
is
None
:
if
i
==
0
and
self
.
cur_class
is
not
None
:
arg_name
=
"Self"
else
:
arg_name
=
f"AutoVar$
{
hash
(
arg
.
arg
)
}
"
node
.
type_params
.
append
(
ast
.
TypeVar
(
arg_name
,
None
))
# todo: bounds
arg
.
annotation
=
ast
.
Name
(
arg_name
,
ast
.
Load
())
else
:
if
isinstance
(
arg
.
annotation
,
ast
.
Name
)
and
(
arg
.
annotation
.
id
==
"Self"
or
any
(
k
.
name
==
arg
.
annotation
.
id
for
k
in
node
.
type_params
)
):
# annotation is type variable so we keep it
pass
else
:
arg_name
=
f"AutoBoundedVar$
{
hash
(
arg
.
arg
)
}
"
node
.
type_params
.
append
(
ast
.
TypeVar
(
arg_name
,
arg
.
annotation
))
arg
.
annotation
=
ast
.
Name
(
arg_name
,
ast
.
Load
())
# if self.cur_class is not None:
# node.type_params.append(ast.TypeVar("Self", None))
if
True
or
node
.
type_params
:
class
FuncType
(
BuiltinGenericType
):
def
name
(
self
):
return
f"FuncTypeGen$
{
node
.
name
}
"
else
:
class
FuncType
(
InstanceType
):
pass
base_class
=
FuncType
NewType
=
base_class
()
FuncType
.
__name__
=
NewType
.
name
()
self
.
scope
.
vars
[
node
.
name
]
=
VarDecl
(
VarKind
.
LOCAL
,
NewType
)
if
self
.
cur_class
is
not
None
:
self
.
cur_class
.
fields
[
node
.
name
]
=
MemberDef
(
NewType
,
node
)
visit_generic_item
(
visit_nongeneric
,
node
,
NewType
,
self
.
scope
,
InstanceType
,
True
)
# tc = node.type_comment # todo : lire les commetnaries de type pour les fonctions génériques sinon trouver autre chose
# tc = node.type_comment # todo : lire les commetnaries de type pour les fonctions génériques sinon trouver autre chose
...
@@ -155,18 +219,10 @@ class StdlibVisitor(NodeVisitorSeq):
...
@@ -155,18 +219,10 @@ class StdlibVisitor(NodeVisitorSeq):
else
:
else
:
raise
AssertionError
(
f"Assertion should fail, got
{
res
}
for
{
ast
.
unparse
(
oper
)
}
"
)
raise
AssertionError
(
f"Assertion should fail, got
{
res
}
for
{
ast
.
unparse
(
oper
)
}
"
)
else
:
else
:
debug
(
f"Type of
{
ast
.
unparse
(
node
.
test
)
}
:=
{
self
.
expr
().
visit
(
node
.
test
)
}
"
)
debug
(
f"Type of
{
highlight
(
ast
.
unparse
(
node
.
test
))
}
:=
{
highlight
(
self
.
expr
().
visit
(
node
.
test
))
}
"
)
def
visit_Call
(
self
,
node
:
ast
.
Call
)
->
BaseType
:
ty_op
=
self
.
visit
(
node
.
func
)
if
is_builtin
(
ty_op
,
"TypeVar"
):
return
TypeType
(
TypeVariable
(
*
[
ast
.
literal_eval
(
arg
)
for
arg
in
node
.
args
]))
if
isinstance
(
ty_op
,
TypeType
):
return
TypeType
(
ty_op
.
type_object
(
*
[
ast
.
literal_eval
(
arg
)
for
arg
in
node
.
args
]))
raise
NotImplementedError
(
ast
.
unparse
(
node
))
def
anno
(
self
)
->
"TypeAnnotationVisitor"
:
def
anno
(
self
)
->
"TypeAnnotationVisitor"
:
return
TypeAnnotationVisitor
(
self
.
scope
,
self
.
cur_class
)
return
TypeAnnotationVisitor
(
self
.
scope
)
def
visit_str
(
self
,
node
:
str
)
->
BaseType
:
def
visit_str
(
self
,
node
:
str
)
->
BaseType
:
if
existing
:
=
self
.
scope
.
get
(
node
):
if
existing
:
=
self
.
scope
.
get
(
node
):
...
@@ -175,6 +231,4 @@ class StdlibVisitor(NodeVisitorSeq):
...
@@ -175,6 +231,4 @@ class StdlibVisitor(NodeVisitorSeq):
raise
UnknownNameError
(
node
)
raise
UnknownNameError
(
node
)
def
visit_Name
(
self
,
node
:
ast
.
Name
)
->
BaseType
:
def
visit_Name
(
self
,
node
:
ast
.
Name
)
->
BaseType
:
if
node
.
id
==
"TypeVar"
:
return
BuiltinFeature
(
"TypeVar"
)
return
self
.
visit_str
(
node
.
id
)
return
self
.
visit_str
(
node
.
id
)
\ No newline at end of file
typon/trans/transpiler/phases/typing/types.py
View file @
6454a3ad
...
@@ -4,6 +4,8 @@ from abc import ABC, abstractmethod
...
@@ -4,6 +4,8 @@ from abc import ABC, abstractmethod
from
dataclasses
import
dataclass
,
field
from
dataclasses
import
dataclass
,
field
from
typing
import
Dict
,
Optional
,
Callable
from
typing
import
Dict
,
Optional
,
Callable
from
transpiler.utils
import
highlight
def
get_default_parents
():
def
get_default_parents
():
if
obj
:
=
globals
().
get
(
"TY_OBJECT"
):
if
obj
:
=
globals
().
get
(
"TY_OBJECT"
):
...
@@ -21,6 +23,15 @@ class MemberDef:
...
@@ -21,6 +23,15 @@ class MemberDef:
val
:
typing
.
Any
=
RuntimeValue
()
val
:
typing
.
Any
=
RuntimeValue
()
in_class_def
:
bool
=
True
in_class_def
:
bool
=
True
@
dataclass
class
UnifyMode
:
search_hierarchy
:
bool
=
True
match_protocol
:
bool
=
True
UnifyMode
.
NORMAL
=
UnifyMode
()
UnifyMode
.
EXACT
=
UnifyMode
(
False
,
False
)
@
dataclass
(
eq
=
False
)
@
dataclass
(
eq
=
False
)
class
BaseType
(
ABC
):
class
BaseType
(
ABC
):
...
@@ -30,6 +41,39 @@ class BaseType(ABC):
...
@@ -30,6 +41,39 @@ class BaseType(ABC):
def
type_type
(
self
)
->
"ClassTypeType"
:
def
type_type
(
self
)
->
"ClassTypeType"
:
return
TY_TYPE
.
instantiate
([
self
])
return
TY_TYPE
.
instantiate
([
self
])
@
abstractmethod
def
name
(
self
)
->
str
:
...
def
__str__
(
self
):
return
self
.
name
()
@
abstractmethod
def
unify_internal
(
self
,
other
:
"BaseType"
,
mode
:
UnifyMode
):
pass
def
unify
(
self
,
other
:
"BaseType"
,
mode
=
UnifyMode
.
NORMAL
):
a
,
b
=
self
.
resolve
(),
other
.
resolve
()
__TB__
=
f"unifying
{
highlight
(
a
)
}
and
{
highlight
(
b
)
}
"
if
isinstance
(
b
,
TypeVariable
):
return
b
.
unify_internal
(
a
,
mode
)
a
,
b
=
b
,
a
a
.
unify_internal
(
b
,
mode
)
@
abstractmethod
def
contains_internal
(
self
,
other
:
"BaseType"
)
->
bool
:
pass
def
contains
(
self
,
other
:
"BaseType"
)
->
bool
:
needle
,
haystack
=
other
.
resolve
(),
self
.
resolve
()
return
(
needle
is
haystack
)
or
haystack
.
contains_internal
(
needle
)
def
try_assign
(
self
,
other
:
"BaseType"
)
->
bool
:
try
:
self
.
unify
(
other
)
return
True
except
:
return
False
cur_var
=
0
cur_var
=
0
...
@@ -52,7 +96,7 @@ class ConcreteType(BaseType):
...
@@ -52,7 +96,7 @@ class ConcreteType(BaseType):
@
dataclass
(
eq
=
False
)
@
dataclass
(
eq
=
False
)
class
TypeVariable
(
ConcreteType
):
class
TypeVariable
(
ConcreteType
):
name
:
str
=
field
(
default_factory
=
lambda
:
next_var_id
())
var_
name
:
str
=
field
(
default_factory
=
lambda
:
next_var_id
())
resolved
:
Optional
[
ConcreteType
]
=
None
resolved
:
Optional
[
ConcreteType
]
=
None
def
resolve
(
self
)
->
ConcreteType
:
def
resolve
(
self
)
->
ConcreteType
:
...
@@ -60,19 +104,30 @@ class TypeVariable(ConcreteType):
...
@@ -60,19 +104,30 @@ class TypeVariable(ConcreteType):
return
self
return
self
return
self
.
resolved
.
resolve
()
return
self
.
resolved
.
resolve
()
def
__str__
(
self
):
def
name
(
self
):
if
self
.
resolved
is
None
:
if
self
.
resolved
is
None
:
# return f"TypeVar[\"{self.name}\"]"
# return f"TypeVar[\"{self.name}\"]"
return
f"_
{
self
.
name
}
"
return
f"_
{
self
.
var_
name
}
"
return
str
(
self
.
resolved
)
return
str
(
self
.
resolved
)
def
__eq__
(
self
,
other
):
def
__eq__
(
self
,
other
):
if
not
isinstance
(
other
,
BaseType
):
if
not
isinstance
(
other
,
BaseType
):
return
False
return
False
if
self
.
resolved
is
None
:
if
self
.
resolved
is
None
:
return
self
==
other
return
self
is
other
return
self
.
resolved
==
other
.
resolve
()
return
self
.
resolved
==
other
.
resolve
()
def
unify_internal
(
self
,
other
:
BaseType
,
mode
:
UnifyMode
):
if
self
is
not
other
:
if
other
.
contains
(
self
):
from
transpiler.phases.typing.exceptions
import
RecursiveTypeUnificationError
raise
RecursiveTypeUnificationError
(
self
,
other
)
self
.
resolved
=
other
def
contains_internal
(
self
,
other
:
BaseType
)
->
bool
:
return
self
.
resolve
()
is
other
.
resolve
()
@
dataclass
(
eq
=
False
)
@
dataclass
(
eq
=
False
)
class
ResolvedConcreteType
(
ConcreteType
):
class
ResolvedConcreteType
(
ConcreteType
):
...
@@ -94,18 +149,22 @@ class ResolvedConcreteType(ConcreteType):
...
@@ -94,18 +149,22 @@ class ResolvedConcreteType(ConcreteType):
https://www.python.org/download/releases/2.3/mro/
https://www.python.org/download/releases/2.3/mro/
"""
"""
def
remove_head_if
(
lst
,
head
):
if
lst
[
0
]
==
head
:
return
lst
[
1
:]
return
lst
def
merge
(
*
lists
):
def
merge
(
*
lists
):
while
True
:
lists
=
[
l
for
l
in
lists
if
len
(
l
)
>
0
]
lists
=
[
l
for
l
in
lists
if
len
(
l
)
>
0
]
if
len
(
lists
)
==
0
:
return
[]
for
i
,
l
in
enumerate
(
lists
):
for
i
,
l
in
enumerate
(
lists
):
first
=
l
[
0
]
head
=
l
[
0
]
for
j
,
l2
in
enumerate
(
lists
):
if
not
any
(
head
in
x
[
1
:]
for
j
,
x
in
enumerate
(
lists
)
if
i
!=
j
):
if
j
==
i
:
return
[
head
]
+
merge
(
*
[
remove_head_if
(
x
,
head
)
for
x
in
lists
])
continue
if
first
in
l2
:
break
else
:
else
:
return
[
first
]
+
merge
(
*
[
x
[
1
:]
for
x
in
lists
if
x
[
0
]
!=
first
])
# couldn't find good head
# unable to find a next element
from
transpiler.phases.typing.exceptions
import
InconsistentMroError
from
transpiler.phases.typing.exceptions
import
InconsistentMroError
raise
InconsistentMroError
(
self
.
parents
)
raise
InconsistentMroError
(
self
.
parents
)
...
@@ -114,10 +173,34 @@ class ResolvedConcreteType(ConcreteType):
...
@@ -114,10 +173,34 @@ class ResolvedConcreteType(ConcreteType):
def
inherits
(
self
,
parent
:
BaseType
):
def
inherits
(
self
,
parent
:
BaseType
):
return
self
==
parent
or
any
(
p
.
inherits
(
parent
)
for
p
in
self
.
parents
)
return
self
==
parent
or
any
(
p
.
inherits
(
parent
)
for
p
in
self
.
parents
)
def
can_receive
(
self
,
value
:
BaseType
):
return
self
==
value
class
UniqueTypeMixin
:
def
unify_internal
(
self
,
other
:
"BaseType"
,
mode
:
UnifyMode
):
from
transpiler.phases.typing.exceptions
import
TypeMismatchError
,
TypeMismatchKind
if
other
!=
self
:
raise
TypeMismatchError
(
self
,
other
,
TypeMismatchKind
.
DIFFERENT_TYPE
)
def
contains_internal
(
self
,
other
:
"BaseType"
)
->
bool
:
return
self
==
other
@
dataclass
(
eq
=
False
)
@
dataclass
(
eq
=
False
)
class
BuiltinType
(
ResolvedConcreteType
):
class
BuiltinType
(
UniqueTypeMixin
,
ResolvedConcreteType
):
pass
pass
@
dataclass
class
SpecialConstantType
[
T
](
ConcreteType
):
value
:
T
def
name
(
self
):
return
str
(
self
.
value
)
def
__eq__
(
self
,
other
):
if
isinstance
(
other
,
SpecialConstantType
):
return
self
.
value
==
other
.
value
return
False
@
dataclass
(
eq
=
False
,
init
=
False
)
@
dataclass
(
eq
=
False
,
init
=
False
)
class
GenericInstanceType
(
ResolvedConcreteType
):
class
GenericInstanceType
(
ResolvedConcreteType
):
...
@@ -140,8 +223,23 @@ class GenericInstanceType(ResolvedConcreteType):
...
@@ -140,8 +223,23 @@ class GenericInstanceType(ResolvedConcreteType):
return
self
.
generic_parent
==
other
.
generic_parent
and
self
.
generic_args
==
other
.
generic_args
return
self
.
generic_parent
==
other
.
generic_parent
and
self
.
generic_args
==
other
.
generic_args
return
False
return
False
def
__str__
(
self
):
def
name
(
self
):
return
f"
{
self
.
generic_parent
}
[
{
', '
.
join
(
map
(
str
,
self
.
generic_args
))
}
]"
return
f"
{
self
.
generic_parent
.
name
()
}
[
{
', '
.
join
(
map
(
str
,
self
.
generic_args
))
}
]"
def
unify_internal
(
self
,
other
:
"BaseType"
,
mode
:
UnifyMode
):
from
transpiler.phases.typing.exceptions
import
TypeMismatchError
,
TypeMismatchKind
if
not
isinstance
(
other
,
GenericInstanceType
):
raise
TypeMismatchError
(
self
,
other
,
TypeMismatchKind
.
DIFFERENT_TYPE
)
if
self
.
generic_parent
!=
other
.
generic_parent
:
raise
TypeMismatchError
(
self
,
other
,
TypeMismatchKind
.
DIFFERENT_TYPE
)
if
len
(
self
.
generic_args
)
!=
len
(
other
.
generic_args
):
raise
TypeMismatchError
(
self
,
other
,
TypeMismatchKind
.
DIFFERENT_TYPE
)
for
a
,
b
in
zip
(
self
.
generic_args
,
other
.
generic_args
):
a
.
unify
(
b
,
mode
)
def
contains_internal
(
self
,
other
:
"BaseType"
)
->
bool
:
# is this correct?
return
self
==
other
or
any
(
a
.
contains
(
other
)
for
a
in
self
.
generic_args
)
class
GenericParameterKind
(
enum
.
Enum
):
class
GenericParameterKind
(
enum
.
Enum
):
NORMAL
=
enum
.
auto
()
NORMAL
=
enum
.
auto
()
...
@@ -176,13 +274,24 @@ class GenericType(BaseType):
...
@@ -176,13 +274,24 @@ class GenericType(BaseType):
res
.
generic_parent
=
self
res
.
generic_parent
=
self
return
res
return
res
def
instantiate_default
(
self
)
->
GenericInstanceType
:
return
self
.
instantiate
([
TypeVariable
()
for
_
in
self
.
parameters
])
def
__str__
(
self
):
try
:
return
str
(
self
.
instantiate_default
())
except
:
return
super
().
__str__
()
@
dataclass
(
eq
=
False
,
init
=
False
)
@
dataclass
(
eq
=
False
,
init
=
False
)
class
BuiltinGenericType
(
GenericType
):
class
BuiltinGenericType
(
UniqueTypeMixin
,
GenericType
):
constraints_
:
Callable
[[
list
[
ConcreteType
]],
list
[
GenericConstraint
]]
constraints_
:
Callable
[[
list
[
ConcreteType
]],
list
[
GenericConstraint
]]
instantiate_
:
Callable
[[
list
[
ConcreteType
]],
GenericInstanceType
]
instantiate_
:
Callable
[[
list
[
ConcreteType
]],
GenericInstanceType
]
def
constraints
(
self
,
args
:
list
[
ConcreteType
])
->
list
[
GenericConstraint
]:
def
constraints
(
self
,
args
:
list
[
ConcreteType
])
->
list
[
GenericConstraint
]:
if
not
hasattr
(
self
,
"constraints_"
):
raise
ValueError
(
"missing constraints_"
)
return
self
.
constraints_
(
args
)
return
self
.
constraints_
(
args
)
def
_instantiate
(
self
,
args
:
list
[
ConcreteType
])
->
GenericInstanceType
:
def
_instantiate
(
self
,
args
:
list
[
ConcreteType
])
->
GenericInstanceType
:
...
@@ -191,7 +300,7 @@ class BuiltinGenericType(GenericType):
...
@@ -191,7 +300,7 @@ class BuiltinGenericType(GenericType):
def
create_builtin_type
(
name
:
str
):
def
create_builtin_type
(
name
:
str
):
class
CreatedType
(
BuiltinType
):
class
CreatedType
(
BuiltinType
):
def
__str__
(
self
):
def
name
(
self
):
return
name
return
name
CreatedType
.
__name__
=
f"BuiltinType$
{
name
}
"
CreatedType
.
__name__
=
f"BuiltinType$
{
name
}
"
res
=
CreatedType
()
res
=
CreatedType
()
...
@@ -216,18 +325,24 @@ def unimpl(*args, **kwargs):
...
@@ -216,18 +325,24 @@ def unimpl(*args, **kwargs):
def
create_builtin_generic_type
(
name
:
str
):
def
create_builtin_generic_type
(
name
:
str
):
class
CreatedType
(
BuiltinGenericType
):
class
CreatedType
(
BuiltinGenericType
):
def
__str__
(
self
):
def
name
(
self
):
return
name
return
name
CreatedType
.
__name__
=
f"BuiltinGenericType$
{
name
}
"
CreatedType
.
__name__
=
f"BuiltinGenericType$
{
name
}
"
res
=
CreatedType
()
res
=
CreatedType
()
return
res
return
res
@
dataclass
(
eq
=
False
)
class
TupleInstanceType
(
GenericInstanceType
):
fields
:
list
[
ConcreteType
]
TY_LIST
=
create_builtin_generic_type
(
"list"
)
TY_LIST
=
create_builtin_generic_type
(
"list"
)
TY_SET
=
create_builtin_generic_type
(
"set"
)
TY_SET
=
create_builtin_generic_type
(
"set"
)
TY_DICT
=
create_builtin_generic_type
(
"dict"
)
TY_DICT
=
create_builtin_generic_type
(
"dict"
)
TY_TUPLE
=
create_builtin_generic_type
(
"tuple"
)
TY_TUPLE
=
create_builtin_generic_type
(
"tuple"
)
TY_TUPLE
.
instantiate_
=
lambda
args
:
TupleInstanceType
(
args
)
@
dataclass
(
unsafe_hash
=
False
)
@
dataclass
(
unsafe_hash
=
False
)
class
TypeTupleType
(
ConcreteType
):
class
TypeTupleType
(
ConcreteType
):
"""
"""
...
@@ -239,9 +354,18 @@ class TypeTupleType(ConcreteType):
...
@@ -239,9 +354,18 @@ class TypeTupleType(ConcreteType):
"""
"""
contents
:
list
[
ConcreteType
]
contents
:
list
[
ConcreteType
]
def
__str__
(
self
):
def
name
(
self
):
return
f"*[
{
', '
.
join
(
map
(
str
,
self
.
contents
))
}
]"
return
f"*[
{
', '
.
join
(
map
(
str
,
self
.
contents
))
}
]"
def
unify_internal
(
self
,
other
:
"BaseType"
,
mode
:
UnifyMode
):
from
transpiler.phases.typing.exceptions
import
TypeMismatchError
,
TypeMismatchKind
if
type
(
other
)
!=
TypeTupleType
:
raise
TypeMismatchError
(
self
,
other
,
TypeMismatchKind
.
DIFFERENT_TYPE
)
if
len
(
self
.
contents
)
!=
len
(
other
.
contents
):
raise
TypeMismatchError
(
self
,
other
,
TypeMismatchKind
.
DIFFERENT_TYPE
)
for
a
,
b
in
zip
(
self
.
contents
,
other
.
contents
):
a
.
unify
(
b
,
mode
)
@
dataclass
(
unsafe_hash
=
False
)
@
dataclass
(
unsafe_hash
=
False
)
class
TypeListType
(
ConcreteType
):
class
TypeListType
(
ConcreteType
):
"""
"""
...
@@ -251,17 +375,47 @@ class TypeListType(ConcreteType):
...
@@ -251,17 +375,47 @@ class TypeListType(ConcreteType):
"""
"""
contents
:
list
[
ConcreteType
]
contents
:
list
[
ConcreteType
]
def
__str__
(
self
):
def
name
(
self
):
return
f"[
{
', '
.
join
(
map
(
str
,
self
.
contents
))
}
]"
return
f"[
{
', '
.
join
(
map
(
str
,
self
.
contents
))
}
]"
def
unify_internal
(
self
,
other
:
"BaseType"
,
mode
:
UnifyMode
):
from
transpiler.phases.typing.exceptions
import
TypeMismatchError
,
TypeMismatchKind
if
type
(
other
)
!=
TypeListType
:
raise
TypeMismatchError
(
self
,
other
,
TypeMismatchKind
.
DIFFERENT_TYPE
)
if
len
(
self
.
contents
)
!=
len
(
other
.
contents
):
raise
TypeMismatchError
(
self
,
other
,
TypeMismatchKind
.
DIFFERENT_TYPE
)
for
a
,
b
in
zip
(
self
.
contents
,
other
.
contents
):
a
.
unify
(
b
,
mode
)
def
contains_internal
(
self
,
other
:
"BaseType"
)
->
bool
:
return
self
==
other
or
any
(
a
.
contains
(
other
)
for
a
in
self
.
contents
)
@
dataclass
(
eq
=
False
)
class
UnionInstanceType
(
GenericInstanceType
):
types
:
list
[
ConcreteType
]
class
UnionType
(
UniqueTypeMixin
,
GenericType
):
def
name
(
self
):
return
"Union"
def
_instantiate
(
self
,
args
:
list
[
ConcreteType
])
->
GenericInstanceType
:
return
UnionInstanceType
(
args
)
TY_UNION
=
UnionType
()
@
dataclass
(
eq
=
False
)
@
dataclass
(
eq
=
False
)
class
CallableInstanceType
(
GenericInstanceType
):
class
CallableInstanceType
(
GenericInstanceType
):
parameters
:
list
[
ConcreteType
]
parameters
:
list
[
ConcreteType
]
return_type
:
ConcreteType
return_type
:
ConcreteType
def
remove_self
(
self
):
return
self
.
generic_parent
.
instantiate
([
TypeListType
(
self
.
parameters
[
1
:]),
self
.
return_type
])
class
CallableType
(
GenericType
):
def
__str__
(
self
):
class
CallableType
(
UniqueTypeMixin
,
GenericType
):
def
name
(
self
):
return
"Callable"
return
"Callable"
def
_instantiate
(
self
,
args
:
list
[
ConcreteType
])
->
CallableInstanceType
:
def
_instantiate
(
self
,
args
:
list
[
ConcreteType
])
->
CallableInstanceType
:
...
@@ -271,6 +425,47 @@ class CallableType(GenericType):
...
@@ -271,6 +425,47 @@ class CallableType(GenericType):
case
_
:
case
_
:
raise
ValueError
raise
ValueError
@
dataclass
(
eq
=
False
,
init
=
False
)
class
LambdaInstanceType
(
CallableInstanceType
):
def
__str__
(
self
):
return
f"<lambda>(
{
", "
.
join
(
map
(
str
,
self
.
parameters
))
}
) ->
{
self
.
return_type
}
"
class
LambdaType
(
CallableType
):
def
name
(
self
):
return
"<lambda>"
def
_instantiate
(
self
,
args
:
list
[
ConcreteType
])
->
CallableInstanceType
:
match
args
:
case
[
TypeListType
([
*
args
]),
ret
]:
return
CallableInstanceType
(
args
,
ret
)
case
_
:
raise
ValueError
TY_LAMBDA
=
LambdaType
()
def
make_builtin_feature
(
name
:
str
):
class
CreatedType
(
BuiltinType
):
def
name
(
self
):
return
name
def
feature
(
self
):
return
name
CreatedType
.
__name__
=
f"BuiltinFeatureType$
{
name
}
"
return
CreatedType
()
def
make_cpp_type
(
name
:
str
):
class
CreatedType
(
BuiltinType
):
def
name
(
self
):
return
name
CreatedType
.
__name__
=
f"CppTypeType$
{
name
}
"
return
CreatedType
()
TY_BUILTIN_FEATURE
=
create_builtin_generic_type
(
"BuiltinFeature"
)
TY_CPP_TYPE
=
create_builtin_type
(
"CppType"
)
TY_CALLABLE
=
CallableType
()
TY_CALLABLE
=
CallableType
()
...
@@ -278,8 +473,8 @@ TY_CALLABLE = CallableType()
...
@@ -278,8 +473,8 @@ TY_CALLABLE = CallableType()
class
ClassTypeType
(
GenericInstanceType
):
class
ClassTypeType
(
GenericInstanceType
):
inner_type
:
BaseType
inner_type
:
BaseType
class
ClassType
(
GenericType
):
class
ClassType
(
UniqueTypeMixin
,
GenericType
):
def
__str__
(
self
):
def
name
(
self
):
return
"Type"
return
"Type"
def
_instantiate
(
self
,
args
:
list
[
ConcreteType
])
->
ClassTypeType
:
def
_instantiate
(
self
,
args
:
list
[
ConcreteType
])
->
ClassTypeType
:
...
...
typon/trans/transpiler/phases/typing2/__init__.py
deleted
100644 → 0
View file @
f8de89ac
import
ast
from
pathlib
import
Path
from
logging
import
debug
from
transpiler.phases.typing.scope
import
VarKind
,
VarDecl
,
ScopeKind
,
Scope
from
transpiler.phases.typing.stdlib
import
PRELUDE
,
StdlibVisitor
from
transpiler.phases.typing.types
import
TY_TYPE
,
TY_INT
,
TY_STR
,
TY_BOOL
,
TY_COMPLEX
,
TY_NONE
,
FunctionType
,
\
TypeVariable
,
CppType
,
PyList
,
TypeType
,
Forked
,
Task
,
Future
,
PyIterator
,
TupleType
,
TypeOperator
,
BaseType
,
\
ModuleType
,
TY_BYTES
,
TY_FLOAT
,
PyDict
,
TY_SLICE
,
TY_OBJECT
,
BuiltinFeature
,
UnionType
,
MemberDef
PRELUDE
.
vars
.
update
({
# "int": VarDecl(VarKind.LOCAL, TY_TYPE, TY_INT),
# "str": VarDecl(VarKind.LOCAL, TY_TYPE, TY_STR),
# "bool": VarDecl(VarKind.LOCAL, TY_TYPE, TY_BOOL),
# "complex": VarDecl(VarKind.LOCAL, TY_TYPE, TY_COMPLEX),
# "None": VarDecl(VarKind.LOCAL, TY_NONE, None),
# "Callable": VarDecl(VarKind.LOCAL, TY_TYPE, FunctionType),
# "TypeVar": VarDecl(VarKind.LOCAL, TY_TYPE, TypeVariable),
# "CppType": VarDecl(VarKind.LOCAL, TY_TYPE, CppType),
# "list": VarDecl(VarKind.LOCAL, TY_TYPE, PyList),
"int"
:
VarDecl
(
VarKind
.
LOCAL
,
TypeType
(
TY_INT
)),
"float"
:
VarDecl
(
VarKind
.
LOCAL
,
TypeType
(
TY_FLOAT
)),
"str"
:
VarDecl
(
VarKind
.
LOCAL
,
TypeType
(
TY_STR
)),
"bytes"
:
VarDecl
(
VarKind
.
LOCAL
,
TypeType
(
TY_BYTES
)),
"bool"
:
VarDecl
(
VarKind
.
LOCAL
,
TypeType
(
TY_BOOL
)),
"complex"
:
VarDecl
(
VarKind
.
LOCAL
,
TypeType
(
TY_COMPLEX
)),
"None"
:
VarDecl
(
VarKind
.
LOCAL
,
TypeType
(
TY_NONE
)),
"Callable"
:
VarDecl
(
VarKind
.
LOCAL
,
TypeType
(
FunctionType
)),
#"TypeVar": VarDecl(VarKind.LOCAL, TypeType(TypeVariable)),
"CppType"
:
VarDecl
(
VarKind
.
LOCAL
,
TypeType
(
CppType
)),
"list"
:
VarDecl
(
VarKind
.
LOCAL
,
TypeType
(
PyList
)),
"dict"
:
VarDecl
(
VarKind
.
LOCAL
,
TypeType
(
PyDict
)),
"Forked"
:
VarDecl
(
VarKind
.
LOCAL
,
TypeType
(
Forked
)),
"Task"
:
VarDecl
(
VarKind
.
LOCAL
,
TypeType
(
Task
)),
"Future"
:
VarDecl
(
VarKind
.
LOCAL
,
TypeType
(
Future
)),
"Iterator"
:
VarDecl
(
VarKind
.
LOCAL
,
TypeType
(
PyIterator
)),
"tuple"
:
VarDecl
(
VarKind
.
LOCAL
,
TypeType
(
TupleType
)),
"slice"
:
VarDecl
(
VarKind
.
LOCAL
,
TypeType
(
TY_SLICE
)),
"object"
:
VarDecl
(
VarKind
.
LOCAL
,
TypeType
(
TY_OBJECT
)),
"BuiltinFeature"
:
VarDecl
(
VarKind
.
LOCAL
,
TypeType
(
BuiltinFeature
)),
"Any"
:
VarDecl
(
VarKind
.
LOCAL
,
TypeType
(
TY_OBJECT
)),
"Optional"
:
VarDecl
(
VarKind
.
LOCAL
,
TypeType
(
lambda
x
:
UnionType
(
x
,
TY_NONE
))),
})
typon_std
=
Path
(
__file__
).
parent
.
parent
.
parent
.
parent
/
"stdlib"
def
make_module
(
name
:
str
,
scope
:
Scope
)
->
BaseType
:
ty
=
ModuleType
([],
f"
{
name
}
"
)
for
n
,
v
in
scope
.
vars
.
items
():
ty
.
fields
[
n
]
=
MemberDef
(
v
.
type
,
v
.
val
,
False
)
return
ty
def
discover_module
(
path
:
Path
,
scope
):
for
child
in
sorted
(
path
.
iterdir
()):
if
child
.
is_dir
():
mod_scope
=
PRELUDE
.
child
(
ScopeKind
.
GLOBAL
)
discover_module
(
child
,
mod_scope
)
scope
.
vars
[
child
.
name
]
=
make_mod_decl
(
child
.
name
,
mod_scope
)
elif
child
.
name
==
"__init__.py"
:
StdlibVisitor
(
scope
).
visit
(
ast
.
parse
(
child
.
read_text
()))
debug
(
f"Visited
{
child
}
"
)
elif
child
.
suffix
==
".py"
:
mod_scope
=
PRELUDE
.
child
(
ScopeKind
.
GLOBAL
)
StdlibVisitor
(
mod_scope
).
visit
(
ast
.
parse
(
child
.
read_text
()))
if
child
.
stem
[
-
1
]
==
"_"
:
child
=
child
.
with_name
(
child
.
stem
[:
-
1
])
scope
.
vars
[
child
.
stem
]
=
make_mod_decl
(
child
.
name
,
mod_scope
)
debug
(
f"Visited
{
child
}
"
)
def
make_mod_decl
(
child
,
mod_scope
):
return
VarDecl
(
VarKind
.
MODULE
,
make_module
(
child
,
mod_scope
),
{
k
:
v
.
type
for
k
,
v
in
mod_scope
.
vars
.
items
()})
discover_module
(
typon_std
,
PRELUDE
)
debug
(
"Stdlib visited!"
)
#exit()
\ No newline at end of file
typon/trans/transpiler/phases/typing2/annotations.py
deleted
100644 → 0
View file @
f8de89ac
import
abc
import
ast
from
dataclasses
import
dataclass
,
field
from
typing
import
Optional
,
List
from
transpiler.phases.typing.scope
import
Scope
from
transpiler.phases.typing.types
import
BaseType
,
TY_NONE
,
TypeVariable
,
TY_TYPE
,
ResolvedConcreteType
,
TypeListType
from
transpiler.phases.utils
import
NodeVisitorSeq
@
dataclass
class
TypeAnnotationVisitor
(
NodeVisitorSeq
):
scope
:
Scope
def
visit_str
(
self
,
node
:
str
)
->
BaseType
:
if
existing
:
=
self
.
scope
.
get
(
node
):
ty
=
existing
.
type
assert
isinstance
(
ty
,
ResolvedConcreteType
)
assert
ty
.
inherits
(
TY_TYPE
)
return
ty
.
inner_type
from
transpiler.phases.typing.exceptions
import
UnknownNameError
raise
UnknownNameError
(
node
)
def
visit_Name
(
self
,
node
:
ast
.
Name
)
->
BaseType
:
return
self
.
visit_str
(
node
.
id
)
def
visit_Constant
(
self
,
node
:
ast
.
Constant
)
->
BaseType
:
if
node
.
value
is
None
:
return
TY_NONE
if
type
(
node
.
value
)
==
str
:
return
node
.
value
raise
NotImplementedError
def
visit_Subscript
(
self
,
node
:
ast
.
Subscript
)
->
BaseType
:
# ty_op = self.visit(node.value)
# args = list(node.slice.elts) if type(node.slice) == ast.Tuple else [node.slice]
# args = [self.visit(arg) for arg in args]
# return ty_op(*args)
raise
NotImplementedError
()
# return TypeOperator([self.visit(node.value)], self.visit(node.slice.value))
def
visit_List
(
self
,
node
:
ast
.
List
)
->
BaseType
:
return
TypeListType
([
self
.
visit
(
elt
)
for
elt
in
node
.
elts
])
def
visit_Attribute
(
self
,
node
:
ast
.
Attribute
)
->
BaseType
:
raise
NotImplementedError
()
# left = self.visit(node.value)
# res = left.fields[node.attr].type
# assert isinstance(res, TypeType)
# return res.type_object
def
visit_BinOp
(
self
,
node
:
ast
.
BinOp
)
->
BaseType
:
# if isinstance(node.op, ast.BitOr):
# return UnionType(self.visit(node.left), self.visit(node.right))
raise
NotImplementedError
(
node
.
op
)
typon/trans/transpiler/phases/typing2/block.py
deleted
100644 → 0
View file @
f8de89ac
import
ast
import
copy
import
dataclasses
import
importlib
from
dataclasses
import
dataclass
from
transpiler.exceptions
import
CompileError
from
transpiler.utils
import
highlight
,
linenodata
from
transpiler.phases.typing
import
make_mod_decl
from
transpiler.phases.typing.common
import
ScoperVisitor
,
get_iter
,
get_next
,
is_builtin
from
transpiler.phases.typing.expr
import
ScoperExprVisitor
,
DUNDER
from
transpiler.phases.typing.class_
import
ScoperClassVisitor
from
transpiler.phases.typing.scope
import
VarDecl
,
VarKind
,
ScopeKind
,
Scope
from
transpiler.phases.typing.types
import
BaseType
,
TypeVariable
,
FunctionType
,
\
Promise
,
TY_NONE
,
PromiseKind
,
TupleType
,
UserType
,
TypeType
,
ModuleType
,
BuiltinFeature
,
TY_INT
,
MemberDef
,
\
RuntimeValue
,
GenericUserType
,
MonomorphizedUserType
from
transpiler.phases.utils
import
PlainBlock
,
AnnotationName
@
dataclass
class
ScoperBlockVisitor
(
ScoperVisitor
):
stdlib
:
bool
=
False
def
visit_Pass
(
self
,
node
:
ast
.
Pass
):
pass
def
get_module
(
self
,
name
:
str
)
->
VarDecl
:
mod
=
self
.
scope
.
get
(
name
,
VarKind
.
MODULE
)
if
mod
is
None
:
# try lookup with importlib
py_mod
=
importlib
.
import_module
(
name
)
mod_scope
=
Scope
()
# copy all functions to mod_scope
for
fname
,
obj
in
py_mod
.
__dict__
.
items
():
if
callable
(
obj
):
# fty = FunctionType([], TypeVariable())
# fty.is_python_func = True
fty
=
TypeVariable
()
fty
.
is_python_func
=
True
mod_scope
.
vars
[
fname
]
=
VarDecl
(
VarKind
.
LOCAL
,
fty
)
mod
=
make_mod_decl
(
name
,
mod_scope
)
mod
.
type
.
is_python
=
True
self
.
scope
.
vars
[
name
]
=
mod
if
mod
is
None
:
from
transpiler.phases.typing.exceptions
import
UnknownNameError
raise
UnknownNameError
(
name
)
assert
isinstance
(
mod
,
VarDecl
),
mod
assert
isinstance
(
mod
.
type
,
ModuleType
),
mod
.
type
return
mod
def
visit_Import
(
self
,
node
:
ast
.
Import
):
for
alias
in
node
.
names
:
mod
=
self
.
get_module
(
alias
.
name
)
alias
.
module_obj
=
mod
.
type
self
.
scope
.
vars
[
alias
.
asname
or
alias
.
name
]
=
dataclasses
.
replace
(
mod
,
kind
=
VarKind
.
LOCAL
)
def
visit_ImportFrom
(
self
,
node
:
ast
.
ImportFrom
):
if
node
.
module
in
{
"typing2"
,
"__future__"
}:
return
module
=
self
.
get_module
(
node
.
module
)
node
.
module_obj
=
module
.
type
for
alias
in
node
.
names
:
thing
=
module
.
val
.
get
(
alias
.
name
)
if
not
thing
:
from
transpiler.phases.typing.exceptions
import
UnknownModuleMemberError
raise
UnknownModuleMemberError
(
node
.
module
,
alias
.
name
)
alias
.
item_obj
=
thing
self
.
scope
.
vars
[
alias
.
asname
or
alias
.
name
]
=
VarDecl
(
VarKind
.
LOCAL
,
thing
)
def
visit_Module
(
self
,
node
:
ast
.
Module
):
self
.
visit_block
(
node
.
body
)
def
get_type
(
self
,
node
:
ast
.
expr
)
->
BaseType
:
if
type
:
=
getattr
(
node
,
"type"
,
None
):
return
type
self
.
expr
().
visit
(
node
)
return
node
.
type
# ntype = TypeVariable()
# node.type = ntype
# return ntype
def
visit_Assign
(
self
,
node
:
ast
.
Assign
):
if
len
(
node
.
targets
)
!=
1
:
raise
NotImplementedError
(
node
)
target
=
node
.
targets
[
0
]
ty
=
self
.
get_type
(
node
.
value
)
decl
=
self
.
visit_assign_target
(
target
,
ty
)
if
not
hasattr
(
node
,
"is_declare"
):
node
.
is_declare
=
decl
def
visit_AnnAssign
(
self
,
node
:
ast
.
AnnAssign
):
if
node
.
simple
!=
1
:
raise
NotImplementedError
(
node
)
if
not
isinstance
(
node
.
target
,
ast
.
Name
):
raise
NotImplementedError
(
node
)
ty
=
self
.
visit_annotation
(
node
.
annotation
)
decl
=
self
.
visit_assign_target
(
node
.
target
,
ty
)
if
not
hasattr
(
node
,
"is_declare"
):
node
.
is_declare
=
decl
if
node
.
value
is
not
None
:
ty_val
=
self
.
get_type
(
node
.
value
)
__TB__
=
f"unifying annotation
{
highlight
(
node
.
annotation
)
}
with value
{
highlight
(
node
.
value
)
}
of type
{
highlight
(
ty_val
)
}
"
ty
.
unify
(
ty_val
)
def
visit_assign_target
(
self
,
target
,
decl_val
:
BaseType
)
->
bool
:
__TB__
=
f"analyzing assignment target
{
highlight
(
target
)
}
with value
{
highlight
(
decl_val
)
}
"
if
isinstance
(
target
,
ast
.
Name
):
if
target
.
id
==
"_"
:
return
False
target
.
type
=
decl_val
if
vdecl
:
=
self
.
scope
.
get
(
target
.
id
,
{
VarKind
.
LOCAL
,
VarKind
.
GLOBAL
,
VarKind
.
NONLOCAL
},
restrict_function
=
True
):
__TB__
=
f"unifying existing variable
{
highlight
(
target
.
id
)
}
of type
{
highlight
(
vdecl
.
type
)
}
with assigned value
{
highlight
(
decl_val
)
}
"
vdecl
.
type
.
unify
(
decl_val
)
return
False
else
:
self
.
scope
.
vars
[
target
.
id
]
=
VarDecl
(
VarKind
.
LOCAL
,
decl_val
)
if
self
.
scope
.
kind
==
ScopeKind
.
FUNCTION_INNER
:
self
.
root_decls
[
target
.
id
]
=
VarDecl
(
VarKind
.
OUTER_DECL
,
decl_val
)
return
False
return
True
elif
isinstance
(
target
,
ast
.
Tuple
):
if
not
isinstance
(
decl_val
,
TupleType
):
from
transpiler.phases.typing.exceptions
import
InvalidUnpackError
raise
InvalidUnpackError
(
decl_val
)
if
len
(
target
.
elts
)
!=
len
(
decl_val
.
args
):
from
transpiler.phases.typing.exceptions
import
InvalidUnpackCountError
raise
InvalidUnpackCountError
(
decl_val
,
len
(
target
.
elts
))
target
.
type
=
decl_val
decls
=
[
self
.
visit_assign_target
(
t
,
ty
)
for
t
,
ty
in
zip
(
target
.
elts
,
decl_val
.
args
)]
# eager evaluated
return
decls
elif
isinstance
(
target
,
ast
.
Attribute
):
attr_type
=
self
.
expr
().
visit
(
target
)
attr_type
.
unify
(
decl_val
)
return
False
elif
isinstance
(
target
,
ast
.
Subscript
):
expr
=
self
.
expr
()
left
=
expr
.
visit
(
target
.
value
)
args
=
target
.
slice
if
type
(
target
.
slice
)
==
tuple
else
[
target
.
slice
]
args
=
[
expr
.
visit
(
e
)
for
e
in
args
]
if
len
(
args
)
==
1
:
args
=
args
[
0
]
expr
.
make_dunder
([
left
,
args
,
decl_val
],
"setitem"
)
return
False
else
:
raise
NotImplementedError
(
ast
.
unparse
(
target
))
def
visit_FunctionDef
(
self
,
node
:
ast
.
FunctionDef
):
ftype
=
self
.
parse_function
(
node
)
ftype
.
return_type
=
Promise
(
ftype
.
return_type
,
PromiseKind
.
TASK
)
self
.
scope
.
vars
[
node
.
name
]
=
VarDecl
(
VarKind
.
LOCAL
,
ftype
)
def
process_class_ast
(
self
,
ctype
:
BaseType
,
node
:
ast
.
ClassDef
,
bases_after
:
list
[
ast
.
expr
]):
scope
=
self
.
scope
.
child
(
ScopeKind
.
CLASS
)
scope
.
obj_type
=
ctype
scope
.
class_
=
scope
node
.
inner_scope
=
scope
node
.
type
=
ctype
visitor
=
ScoperClassVisitor
(
scope
,
cur_class
=
TypeType
(
ctype
))
visitor
.
visit_block
(
node
.
body
)
for
base
in
bases_after
:
base
=
self
.
expr
().
visit
(
base
)
if
is_builtin
(
base
,
"Enum"
):
ctype
.
parents
.
append
(
TY_INT
)
for
k
,
m
in
ctype
.
fields
.
items
():
m
.
type
=
ctype
m
.
val
=
ast
.
literal_eval
(
m
.
val
)
assert
type
(
m
.
val
)
==
int
ctype
.
fields
[
"value"
]
=
MemberDef
(
TY_INT
)
lnd
=
linenodata
(
node
)
init_method
=
ast
.
FunctionDef
(
name
=
"__init__"
,
args
=
ast
.
arguments
(
args
=
[
ast
.
arg
(
arg
=
"self"
),
ast
.
arg
(
arg
=
"value"
)],
defaults
=
[],
kw_defaults
=
[],
kwarg
=
None
,
kwonlyargs
=
[],
posonlyargs
=
[],
),
body
=
[
ast
.
Assign
(
targets
=
[
ast
.
Attribute
(
value
=
ast
.
Name
(
id
=
"self"
),
attr
=
"value"
)],
value
=
ast
.
Name
(
id
=
"value"
),
**
lnd
)
],
decorator_list
=
[],
returns
=
None
,
type_comment
=
None
,
**
lnd
)
_
,
rtype
=
visitor
.
visit_FunctionDef
(
init_method
)
visitor
.
visit_function_definition
(
init_method
,
rtype
)
node
.
body
.
append
(
init_method
)
ctype
.
is_enum
=
True
else
:
raise
NotImplementedError
(
base
)
for
deco
in
node
.
decorator_list
:
deco
=
self
.
expr
().
visit
(
deco
)
if
is_builtin
(
deco
,
"dataclass"
):
# init_type = FunctionType([cttype, *cttype.members.values()], TypeVariable())
# cttype.methods["__init__"] = init_type
lnd
=
linenodata
(
node
)
init_method
=
ast
.
FunctionDef
(
name
=
"__init__"
,
args
=
ast
.
arguments
(
args
=
[
ast
.
arg
(
arg
=
"self"
),
*
[
ast
.
arg
(
arg
=
n
)
for
n
in
ctype
.
get_members
()]],
defaults
=
[],
kw_defaults
=
[],
kwarg
=
None
,
kwonlyargs
=
[],
posonlyargs
=
[],
),
body
=
[
ast
.
Assign
(
targets
=
[
ast
.
Attribute
(
value
=
ast
.
Name
(
id
=
"self"
),
attr
=
n
)],
value
=
ast
.
Name
(
id
=
n
),
**
lnd
)
for
n
in
ctype
.
get_members
()
],
decorator_list
=
[],
returns
=
None
,
type_comment
=
None
,
**
lnd
)
_
,
rtype
=
visitor
.
visit_FunctionDef
(
init_method
)
visitor
.
visit_function_definition
(
init_method
,
rtype
)
node
.
body
.
append
(
init_method
)
else
:
raise
NotImplementedError
(
deco
)
return
ctype
def
visit_ClassDef
(
self
,
node
:
ast
.
ClassDef
):
copied
=
copy
.
deepcopy
(
node
)
class
NewUserType
(
UserType
):
def
__init__
(
self
):
super
().
__init__
(
node
.
name
)
#ctype = UserType(node.name)
typevars
=
[]
bases_after
=
[]
for
base
in
node
.
bases
:
if
isinstance
(
base
,
ast
.
Subscript
):
if
isinstance
(
base
.
slice
,
ast
.
Name
):
sliceval
=
[
base
.
slice
.
id
]
elif
isinstance
(
base
.
slice
,
ast
.
Tuple
):
sliceval
=
[
n
.
id
for
n
in
base
.
slice
.
elts
]
if
is_builtin
(
self
.
expr
().
visit
(
base
.
value
),
"Generic"
):
typevars
=
sliceval
else
:
bases_after
.
append
(
base
)
if
typevars
:
# generic
#ctype = GenericUserType(node.name, typevars, node)
var_scope
=
self
.
scope
.
child
(
ScopeKind
.
GLOBAL
)
var_visitor
=
ScoperBlockVisitor
(
var_scope
,
self
.
root_decls
)
node
.
gen_instances
=
{}
class
OurGenericType
(
GenericUserType
):
# def __init__(self, *args):
# super().__init__(node.name)
# for tv, arg in zip(typevars, args):
# var_scope.declare_local(tv, arg)
# var_visitor.process_class_ast(self, node, bases_after)
def
__new__
(
cls
,
*
args
,
**
kwargs
):
res
=
MonomorphizedUserType
(
node
.
name
+
"$$"
+
"__"
.
join
(
map
(
str
,
args
))
+
"$$"
)
for
tv
,
arg
in
zip
(
typevars
,
args
):
var_scope
.
declare_local
(
tv
,
arg
)
new_node
=
copy
.
deepcopy
(
copied
)
new_node
.
name
=
res
.
name
var_visitor
.
process_class_ast
(
res
,
new_node
,
bases_after
)
node
.
gen_instances
[
tuple
(
args
)]
=
new_node
return
res
ctype
=
OurGenericType
else
:
# not generic
ctype
=
self
.
process_class_ast
(
UserType
(
node
.
name
),
node
,
bases_after
)
cttype
=
TypeType
(
ctype
)
self
.
scope
.
vars
[
node
.
name
]
=
VarDecl
(
VarKind
.
LOCAL
,
cttype
)
def
visit_If
(
self
,
node
:
ast
.
If
):
scope
=
self
.
scope
.
child
(
ScopeKind
.
FUNCTION_INNER
)
node
.
inner_scope
=
scope
self
.
expr
().
visit
(
node
.
test
)
then_scope
=
scope
.
child
(
ScopeKind
.
FUNCTION_INNER
)
then_visitor
=
ScoperBlockVisitor
(
then_scope
,
self
.
root_decls
)
then_visitor
.
visit_block
(
node
.
body
)
if
node
.
orelse
:
else_scope
=
scope
.
child
(
ScopeKind
.
FUNCTION_INNER
)
else_visitor
=
ScoperBlockVisitor
(
else_scope
,
self
.
root_decls
)
else_visitor
.
visit_block
(
node
.
orelse
)
node
.
orelse_scope
=
else_scope
if
then_scope
.
diverges
and
else_scope
.
diverges
:
self
.
scope
.
diverges
=
True
def
visit_While
(
self
,
node
:
ast
.
While
):
scope
=
self
.
scope
.
child
(
ScopeKind
.
FUNCTION_INNER
)
scope
.
is_loop
=
node
node
.
inner_scope
=
scope
self
.
expr
().
visit
(
node
.
test
)
body_scope
=
scope
.
child
(
ScopeKind
.
FUNCTION_INNER
)
body_visitor
=
ScoperBlockVisitor
(
body_scope
,
self
.
root_decls
)
body_visitor
.
visit_block
(
node
.
body
)
if
node
.
orelse
:
orelse_scope
=
scope
.
child
(
ScopeKind
.
FUNCTION_INNER
)
orelse_visitor
=
ScoperBlockVisitor
(
orelse_scope
,
self
.
root_decls
)
orelse_visitor
.
visit_block
(
node
.
orelse
)
node
.
orelse_variable
=
f"orelse_
{
id
(
node
)
}
"
def
visit_PlainBlock
(
self
,
node
:
PlainBlock
):
scope
=
self
.
scope
.
child
(
ScopeKind
.
FUNCTION_INNER
)
node
.
inner_scope
=
scope
body_visitor
=
ScoperBlockVisitor
(
scope
,
self
.
root_decls
)
body_visitor
.
visit_block
(
node
.
body
)
def
visit_For
(
self
,
node
:
ast
.
For
):
scope
=
self
.
scope
.
child
(
ScopeKind
.
FUNCTION_INNER
)
scope
.
is_loop
=
node
node
.
inner_scope
=
scope
assert
isinstance
(
node
.
target
,
ast
.
Name
)
var_var
=
TypeVariable
()
scope
.
vars
[
node
.
target
.
id
]
=
VarDecl
(
VarKind
.
LOCAL
,
var_var
)
seq_type
=
self
.
expr
().
visit
(
node
.
iter
)
iter_type
=
get_iter
(
seq_type
)
next_type
=
get_next
(
iter_type
)
var_var
.
unify
(
next_type
)
body_scope
=
scope
.
child
(
ScopeKind
.
FUNCTION_INNER
)
body_visitor
=
ScoperBlockVisitor
(
body_scope
,
self
.
root_decls
)
body_visitor
.
visit_block
(
node
.
body
)
if
node
.
orelse
:
orelse_scope
=
scope
.
child
(
ScopeKind
.
FUNCTION_INNER
)
orelse_visitor
=
ScoperBlockVisitor
(
orelse_scope
,
self
.
root_decls
)
orelse_visitor
.
visit_block
(
node
.
orelse
)
node
.
orelse_variable
=
f"orelse_
{
id
(
node
)
}
"
def
visit_Expr
(
self
,
node
:
ast
.
Expr
):
self
.
expr
().
visit
(
node
.
value
)
def
visit_Return
(
self
,
node
:
ast
.
Return
):
fct
=
self
.
scope
.
function
if
fct
is
None
:
from
transpiler.phases.typing.exceptions
import
OutsideFunctionError
raise
OutsideFunctionError
()
ftype
=
fct
.
obj_type
assert
isinstance
(
ftype
,
FunctionType
)
vtype
=
self
.
expr
().
visit
(
node
.
value
)
if
node
.
value
else
TY_NONE
vtype
.
unify
(
ftype
.
return_type
.
return_type
if
isinstance
(
ftype
.
return_type
,
Promise
)
else
ftype
.
return_type
)
self
.
scope
.
diverges
=
True
#fct.has_return = True
def
visit_Global
(
self
,
node
:
ast
.
Global
):
for
name
in
node
.
names
:
self
.
scope
.
function
.
vars
[
name
]
=
VarDecl
(
VarKind
.
GLOBAL
,
None
)
if
name
not
in
self
.
scope
.
global_scope
.
vars
:
self
.
scope
.
global_scope
.
vars
[
name
]
=
VarDecl
(
VarKind
.
LOCAL
,
None
)
def
visit_Nonlocal
(
self
,
node
:
ast
.
Global
):
fct
=
self
.
scope
.
function
if
fct
is
None
:
from
transpiler.phases.typing.exceptions
import
OutsideFunctionError
raise
OutsideFunctionError
()
for
name
in
node
.
names
:
fct
.
vars
[
name
]
=
VarDecl
(
VarKind
.
NONLOCAL
,
None
)
if
name
not
in
fct
.
parent
.
vars
:
fct
.
parent
.
vars
[
name
]
=
VarDecl
(
VarKind
.
LOCAL
,
None
)
def
visit_AugAssign
(
self
,
node
:
ast
.
AugAssign
):
target
,
value
=
map
(
self
.
get_type
,
(
node
.
target
,
node
.
value
))
try
:
self
.
expr
().
make_dunder
([
target
,
value
],
"i"
+
DUNDER
[
type
(
node
.
op
)])
except
CompileError
as
e
:
self
.
visit_assign_target
(
node
.
target
,
self
.
expr
().
make_dunder
([
target
,
value
],
DUNDER
[
type
(
node
.
op
)]))
# equivalent = ast.Assign(
# targets=[node.target],
# value=ast.BinOp(left=node.target, op=node.op, right=node.value, **linenodata(node)),
# **linenodata(node))
# self.visit(equivalent)
def
visit
(
self
,
node
:
ast
.
AST
):
if
isinstance
(
node
,
ast
.
AST
):
__TB_SKIP__
=
True
super
().
visit
(
node
)
node
.
scope
=
self
.
scope
else
:
raise
NotImplementedError
(
node
)
def
visit_Break
(
self
,
_node
:
ast
.
Break
):
if
not
self
.
scope
.
is_in_loop
():
from
transpiler.phases.typing.exceptions
import
OutsideLoopError
raise
OutsideLoopError
()
def
visit_Continue
(
self
,
_node
:
ast
.
Continue
):
if
not
self
.
scope
.
is_in_loop
():
from
transpiler.phases.typing.exceptions
import
OutsideLoopError
raise
OutsideLoopError
()
def
visit_Try
(
self
,
node
:
ast
.
Try
):
scope
=
self
.
scope
.
child
(
ScopeKind
.
FUNCTION_INNER
)
node
.
inner_scope
=
scope
body_scope
=
scope
.
child
(
ScopeKind
.
FUNCTION_INNER
)
body_visitor
=
ScoperBlockVisitor
(
body_scope
,
self
.
root_decls
)
body_visitor
.
visit_block
(
node
.
body
)
# todo
for
handler
in
node
.
handlers
:
handler_scope
=
scope
.
child
(
ScopeKind
.
FUNCTION_INNER
)
handler_visitor
=
ScoperBlockVisitor
(
handler_scope
,
self
.
root_decls
)
handler_visitor
.
visit_block
(
handler
.
body
)
if
node
.
orelse
:
else_scope
=
scope
.
child
(
ScopeKind
.
FUNCTION_INNER
)
else_visitor
=
ScoperBlockVisitor
(
else_scope
,
self
.
root_decls
)
else_visitor
.
visit_block
(
node
.
orelse
)
if
node
.
finalbody
:
raise
NotImplementedError
(
node
.
finalbody
)
def
visit_Raise
(
self
,
node
:
ast
.
Raise
):
self
.
scope
.
diverges
=
True
if
node
.
exc
:
self
.
expr
().
visit
(
node
.
exc
)
if
node
.
cause
:
self
.
expr
().
visit
(
node
.
cause
)
\ No newline at end of file
typon/trans/transpiler/phases/typing2/class_.py
deleted
100644 → 0
View file @
f8de89ac
# coding: utf-8
import
ast
from
dataclasses
import
dataclass
,
field
from
transpiler.phases.typing
import
FunctionType
,
ScopeKind
,
VarDecl
,
VarKind
,
TY_NONE
from
transpiler.phases.typing.common
import
ScoperVisitor
from
transpiler.phases.typing.types
import
PromiseKind
,
Promise
,
BaseType
,
MemberDef
@
dataclass
class
ScoperClassVisitor
(
ScoperVisitor
):
fdecls
:
list
[(
ast
.
FunctionDef
,
BaseType
)]
=
field
(
default_factory
=
list
)
def
visit_AnnAssign
(
self
,
node
:
ast
.
AnnAssign
):
assert
node
.
value
is
None
,
"Class field should not have a value"
assert
node
.
simple
==
1
,
"Class field should be simple (identifier, not parenthesized)"
assert
isinstance
(
node
.
target
,
ast
.
Name
)
self
.
scope
.
obj_type
.
fields
[
node
.
target
.
id
]
=
MemberDef
(
self
.
visit_annotation
(
node
.
annotation
))
def
visit_Assign
(
self
,
node
:
ast
.
Assign
):
assert
len
(
node
.
targets
)
==
1
,
"Can't use destructuring in class static member"
assert
isinstance
(
node
.
targets
[
0
],
ast
.
Name
)
node
.
is_declare
=
True
valtype
=
self
.
expr
().
visit
(
node
.
value
)
node
.
targets
[
0
].
type
=
valtype
self
.
scope
.
obj_type
.
fields
[
node
.
targets
[
0
].
id
]
=
MemberDef
(
valtype
,
node
.
value
)
def
visit_FunctionDef
(
self
,
node
:
ast
.
FunctionDef
):
ftype
=
self
.
parse_function
(
node
)
ftype
.
parameters
[
0
].
unify
(
self
.
scope
.
obj_type
)
inner
=
ftype
.
return_type
if
node
.
name
!=
"__init__"
:
ftype
.
return_type
=
Promise
(
ftype
.
return_type
,
PromiseKind
.
TASK
)
ftype
.
is_method
=
True
self
.
scope
.
obj_type
.
fields
[
node
.
name
]
=
MemberDef
(
ftype
,
node
)
return
(
node
,
inner
)
typon/trans/transpiler/phases/typing2/common.py
deleted
100644 → 0
View file @
f8de89ac
import
ast
from
dataclasses
import
dataclass
,
field
from
typing
import
Dict
,
Optional
from
transpiler.utils
import
highlight
from
transpiler.phases.typing.annotations
import
TypeAnnotationVisitor
from
transpiler.phases.typing.scope
import
Scope
,
ScopeKind
,
VarDecl
,
VarKind
from
transpiler.phases.typing.types
import
BaseType
,
TypeVariable
,
TY_NONE
,
TypeType
,
BuiltinFeature
,
FunctionType
,
\
Promise
,
PromiseKind
from
transpiler.phases.utils
import
NodeVisitorSeq
,
AnnotationName
PRELUDE
=
Scope
.
make_global
()
@
dataclass
class
ScoperVisitor
(
NodeVisitorSeq
):
scope
:
Scope
=
field
(
default_factory
=
lambda
:
PRELUDE
.
child
(
ScopeKind
.
GLOBAL
))
root_decls
:
Dict
[
str
,
VarDecl
]
=
field
(
default_factory
=
dict
)
cur_class
:
Optional
[
TypeType
]
=
None
def
expr
(
self
)
->
"ScoperExprVisitor"
:
from
transpiler.phases.typing.expr
import
ScoperExprVisitor
return
ScoperExprVisitor
(
self
.
scope
,
self
.
root_decls
)
def
anno
(
self
)
->
"TypeAnnotationVisitor"
:
return
TypeAnnotationVisitor
(
self
.
scope
,
self
.
cur_class
)
def
visit_annotation
(
self
,
expr
:
Optional
[
ast
.
expr
])
->
BaseType
:
res
=
self
.
anno
().
visit
(
expr
)
if
expr
else
TypeVariable
()
assert
not
isinstance
(
res
,
TypeType
)
return
res
def
annotate_arg
(
self
,
arg
:
ast
.
arg
)
->
BaseType
:
if
arg
.
annotation
is
None
or
isinstance
(
arg
.
annotation
,
AnnotationName
):
res
=
TypeVariable
()
arg
.
annotation
=
AnnotationName
(
res
)
return
res
else
:
return
self
.
visit_annotation
(
arg
.
annotation
)
def
parse_function
(
self
,
node
:
ast
.
FunctionDef
):
argtypes
=
[
self
.
annotate_arg
(
arg
)
for
arg
in
node
.
args
.
args
]
rtype
=
self
.
visit_annotation
(
node
.
returns
)
ftype
=
FunctionType
(
argtypes
,
rtype
)
scope
=
self
.
scope
.
child
(
ScopeKind
.
FUNCTION
)
scope
.
obj_type
=
ftype
scope
.
function
=
scope
node
.
inner_scope
=
scope
node
.
type
=
ftype
ftype
.
optional_at
=
len
(
node
.
args
.
args
)
-
len
(
node
.
args
.
defaults
)
for
ty
,
default
in
zip
(
argtypes
[
ftype
.
optional_at
:],
node
.
args
.
defaults
):
self
.
expr
().
visit
(
default
).
unify
(
ty
)
for
arg
,
ty
in
zip
(
node
.
args
.
args
,
argtypes
):
scope
.
vars
[
arg
.
arg
]
=
VarDecl
(
VarKind
.
LOCAL
,
ty
)
self
.
fdecls
.
append
((
node
,
rtype
))
return
ftype
def
visit_block
(
self
,
block
:
list
[
ast
.
AST
]):
if
not
block
:
return
__TB__
=
f"running type analysis on block starting with
{
highlight
(
block
[
0
])
}
"
self
.
fdecls
=
[]
for
b
in
block
:
self
.
visit
(
b
)
if
self
.
fdecls
:
old_list
=
self
.
fdecls
exc
=
None
while
True
:
new_list
=
[]
for
node
,
rtype
in
old_list
:
from
transpiler.exceptions
import
CompileError
try
:
self
.
visit_function_definition
(
node
,
rtype
)
except
CompileError
as
e
:
new_list
.
append
((
node
,
rtype
))
if
not
exc
or
getattr
(
node
,
"is_main"
,
False
):
exc
=
e
if
len
(
new_list
)
==
len
(
old_list
):
raise
exc
if
not
new_list
:
break
old_list
=
new_list
exc
=
None
def
visit_function_definition
(
self
,
node
,
rtype
):
__TB__
=
f"running type analysis on the body of
{
highlight
(
node
)
}
"
__TB_NODE__
=
node
from
transpiler.phases.typing.block
import
ScoperBlockVisitor
for
b
in
node
.
body
:
decls
=
{}
visitor
=
ScoperBlockVisitor
(
node
.
inner_scope
,
decls
)
visitor
.
fdecls
=
[]
visitor
.
visit
(
b
)
if
len
(
visitor
.
fdecls
)
>
1
:
raise
NotImplementedError
(
"?"
)
elif
len
(
visitor
.
fdecls
)
==
1
:
fnode
,
frtype
=
visitor
.
fdecls
[
0
]
self
.
visit_function_definition
(
fnode
,
frtype
)
#del node.inner_scope.vars[fnode.name]
visitor
.
visit_assign_target
(
ast
.
Name
(
fnode
.
name
),
fnode
.
type
)
b
.
decls
=
decls
if
not
node
.
inner_scope
.
diverges
and
not
(
isinstance
(
node
.
type
.
return_type
,
Promise
)
and
node
.
type
.
return_type
.
kind
==
PromiseKind
.
GENERATOR
):
from
transpiler.phases.typing.exceptions
import
TypeMismatchError
try
:
rtype
.
unify
(
TY_NONE
)
except
TypeMismatchError
as
e
:
from
transpiler.phases.typing.exceptions
import
MissingReturnError
raise
MissingReturnError
(
node
)
from
e
def
get_iter
(
seq_type
):
try
:
iter_type
=
seq_type
.
fields
[
"__iter__"
].
type
.
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
.
fields
[
"__next__"
].
type
.
return_type
except
:
from
transpiler.phases.typing.exceptions
import
NotIteratorError
raise
NotIteratorError
(
iter_type
)
return
next_type
def
is_builtin
(
x
,
feature
):
return
isinstance
(
x
,
BuiltinFeature
)
and
x
.
val
==
feature
\ No newline at end of file
typon/trans/transpiler/phases/typing2/exceptions.py
deleted
100644 → 0
View file @
f8de89ac
import
ast
import
enum
from
dataclasses
import
dataclass
from
transpiler.utils
import
highlight
from
transpiler.exceptions
import
CompileError
from
transpiler.phases.typing.types
import
TypeVariable
,
BaseType
,
TypeOperator
@
dataclass
class
UnresolvedTypeVariableError
(
CompileError
):
variable
:
TypeVariable
def
__str__
(
self
)
->
str
:
return
f"Unresolved type variable:
{
self
.
variable
}
"
def
detail
(
self
,
last_node
:
ast
.
AST
=
None
)
->
str
:
if
isinstance
(
last_node
,
(
ast
.
Import
,
ast
.
ImportFrom
)):
return
f"""
This indicates the compiler was unable to infer the type of a function in a module.
Currently, Typon cannot determine the type of Python functions imported from other modules, except
for the standard library.
As such, you need to give enough information to the compiler to infer the type of the function.
For example:
↓↓↓ this tells the compiler that
{
highlight
(
'math.factorial'
)
}
returns an
{
highlight
(
'int'
)
}
{
highlight
(
'res: int = math.factorial(5)'
)
}
"""
return
f"""
This generally indicates the compiler was unable to infer the type of a variable or expression.
A common fix is to add a type annotation to the variable or function.
For example:
↓↓↓ this tells the compiler that
{
highlight
(
'x'
)
}
is an
{
highlight
(
'int'
)
}
{
highlight
(
'def f(x: int):'
)
}
"""
@
dataclass
class
RecursiveTypeUnificationError
(
CompileError
):
needle
:
BaseType
haystack
:
BaseType
def
__str__
(
self
)
->
str
:
return
f"Recursive type unification:
{
highlight
(
self
.
needle
)
}
and
{
highlight
(
self
.
haystack
)
}
"
def
detail
(
self
,
last_node
:
ast
.
AST
=
None
)
->
str
:
return
f"""
This generally indicates a recursive type definition. Such types are not currently supported.
For example:
{
highlight
(
'T = tuple[T]'
)
}
In the current case,
{
highlight
(
self
.
haystack
)
}
contains type
{
highlight
(
self
.
needle
)
}
, but an attempt was made to
unify them.
"""
class
TypeMismatchKind
(
enum
.
Enum
):
NO_COMMON_PARENT
=
enum
.
auto
()
DIFFERENT_TYPE
=
enum
.
auto
()
@
dataclass
class
TypeMismatchError
(
CompileError
):
expected
:
BaseType
got
:
BaseType
reason
:
TypeMismatchKind
def
__str__
(
self
)
->
str
:
return
f"Type mismatch: expected
{
highlight
(
self
.
expected
)
}
, got
{
highlight
(
self
.
got
)
}
"
def
detail
(
self
,
last_node
:
ast
.
AST
=
None
)
->
str
:
return
f"""
This generally indicates a type error.
For example:
{
highlight
(
'def f(x: int): ...'
)
}
{
highlight
(
'f("hello")'
)
}
In the current case, the compiler expected an expression of type
{
highlight
(
self
.
expected
)
}
, but instead got
an expression of type
{
highlight
(
self
.
got
)
}
.
"""
@
dataclass
class
ArgumentCountMismatchError
(
CompileError
):
func
:
TypeOperator
arguments
:
TypeOperator
def
__str__
(
self
)
->
str
:
fcount
=
str
(
len
(
self
.
func
.
args
))
if
self
.
func
.
variadic
:
fcount
=
f"at least
{
fcount
}
"
return
f"Argument count mismatch: expected
{
fcount
}
, got
{
len
(
self
.
arguments
.
args
)
}
"
def
detail
(
self
,
last_node
:
ast
.
AST
=
None
)
->
str
:
return
f"""
This indicates missing or extraneous arguments in a function call or type instantiation.
The called or instantiated signature was
{
highlight
(
self
.
func
)
}
.
Other examples:
{
highlight
(
'def f(x: int): ...'
)
}
{
highlight
(
'f(1, 2)'
)
}
Here, the function
{
highlight
(
'f'
)
}
expects one argument, but was called with two.
{
highlight
(
'x: list[int, str]'
)
}
Here, the type
{
highlight
(
'list'
)
}
expects one argument, but was instantiated with two.
"""
@
dataclass
class
ProtocolMismatchError
(
CompileError
):
value
:
BaseType
protocol
:
BaseType
reason
:
Exception
|
str
def
__str__
(
self
)
->
str
:
return
f"Protocol mismatch:
{
str
(
self
.
value
)
}
does not implement
{
str
(
self
.
protocol
)
}
"
def
detail
(
self
,
last_node
:
ast
.
AST
=
None
)
->
str
:
return
f"""
This generally indicates a type error.
For example:
{
highlight
(
'def f(x: Iterable[int]): ...'
)
}
{
highlight
(
'f("hello")'
)
}
In the current case, the compiler expected an expression whose type implements
{
highlight
(
self
.
protocol
)
}
, but
instead got an expression of type
{
highlight
(
self
.
value
)
}
.
"""
@
dataclass
class
NotCallableError
(
CompileError
):
value
:
BaseType
def
__str__
(
self
)
->
str
:
return
f"Trying to call a non-function type:
{
highlight
(
self
.
value
)
}
"
def
detail
(
self
,
last_node
:
ast
.
AST
=
None
)
->
str
:
return
f"""
This indicates that an attempt was made to call an object that is not a function.
For example:
{
highlight
(
'x = 1'
)
}
{
highlight
(
'x()'
)
}
"""
@
dataclass
class
MissingAttributeError
(
CompileError
):
value
:
BaseType
attribute
:
str
def
__str__
(
self
)
->
str
:
return
f"Missing attribute:
{
highlight
(
self
.
value
)
}
has no attribute
{
highlight
(
self
.
attribute
)
}
"
def
detail
(
self
,
last_node
:
ast
.
AST
=
None
)
->
str
:
return
f"""
This indicates that an attempt was made to access an attribute that does not exist.
For example:
{
highlight
(
'x = 1'
)
}
{
highlight
(
'print(x.y)'
)
}
"""
@
dataclass
class
UnknownNameError
(
CompileError
):
name
:
str
def
__str__
(
self
)
->
str
:
return
f"Unknown name:
{
highlight
(
self
.
name
)
}
"
def
detail
(
self
,
last_node
:
ast
.
AST
=
None
)
->
str
:
return
f"""
This indicates that an attempt was made to access a name that does not exist.
For example:
{
highlight
(
'print(abcd)'
)
}
{
highlight
(
'import foobar'
)
}
"""
@
dataclass
class
UnknownModuleMemberError
(
CompileError
):
module
:
str
name
:
str
def
__str__
(
self
)
->
str
:
return
f"Unknown module member: Module
{
highlight
(
self
.
module
)
}
does not contain
{
highlight
(
self
.
name
)
}
"
def
detail
(
self
,
last_node
:
ast
.
AST
=
None
)
->
str
:
return
f"""
This indicates that an attempt was made to import
For example:
{
highlight
(
'from math import abcd'
)
}
"""
@
dataclass
class
InvalidUnpackCountError
(
CompileError
):
value
:
BaseType
count
:
int
def
__str__
(
self
)
->
str
:
return
f"Invalid unpack:
{
highlight
(
self
.
value
)
}
cannot be unpacked into
{
self
.
count
}
variables"
def
detail
(
self
,
last_node
:
ast
.
AST
=
None
)
->
str
:
return
f"""
This indicates that an attempt was made to unpack a value that cannot be unpacked into the given number of
variables.
For example:
{
highlight
(
'a, b, c = 1, 2'
)
}
"""
@
dataclass
class
InvalidUnpackError
(
CompileError
):
value
:
BaseType
def
__str__
(
self
)
->
str
:
return
f"Invalid unpack:
{
highlight
(
self
.
value
)
}
cannot be unpacked"
def
detail
(
self
,
last_node
:
ast
.
AST
=
None
)
->
str
:
return
f"""
This indicates that an attempt was made to unpack a value that cannot be unpacked.
For example:
{
highlight
(
'a, b, c = 1'
)
}
Moreover, currently typon only supports unpacking tuples.
"""
@
dataclass
class
NotIterableError
(
CompileError
):
value
:
BaseType
def
__str__
(
self
)
->
str
:
return
f"Not iterable:
{
highlight
(
self
.
value
)
}
is not iterable"
def
detail
(
self
,
last_node
:
ast
.
AST
=
None
)
->
str
:
return
f"""
This indicates that an attempt was made to iterate over a value that is not iterable.
For example:
{
highlight
(
'for x in 1: ...'
)
}
Iterable types must implement the Python
{
highlight
(
'Iterable'
)
}
protocol, which requires the presence of a
{
highlight
(
'__iter__'
)
}
method.
"""
@
dataclass
class
NotIteratorError
(
CompileError
):
value
:
BaseType
def
__str__
(
self
)
->
str
:
return
f"Not iterator:
{
highlight
(
self
.
value
)
}
is not an iterator"
def
detail
(
self
,
last_node
:
ast
.
AST
=
None
)
->
str
:
return
f"""
This indicates that an attempt was made to iterate over a value that is not an iterator.
For example:
{
highlight
(
'x = next(5)'
)
}
Iterator types must implement the Python
{
highlight
(
'Iterator'
)
}
protocol, which requires the presence of a
{
highlight
(
'__next__'
)
}
method.
"""
@
dataclass
class
OutsideFunctionError
(
CompileError
):
def
__str__
(
self
)
->
str
:
return
f"
{
highlight
(
'return'
)
}
and
{
highlight
(
'nonlocal'
)
}
cannot be used outside of a function"
def
detail
(
self
,
last_node
:
ast
.
AST
=
None
)
->
str
:
return
""
@
dataclass
class
OutsideLoopError
(
CompileError
):
def
__str__
(
self
)
->
str
:
return
f"
{
highlight
(
'break'
)
}
and
{
highlight
(
'continue'
)
}
can only be used inside a loop"
def
detail
(
self
,
last_node
:
ast
.
AST
=
None
)
->
str
:
return
""
@
dataclass
class
MissingReturnError
(
CompileError
):
node
:
ast
.
FunctionDef
def
__str__
(
self
)
->
str
:
return
f"Missing return: not all code paths in
{
highlight
(
self
.
node
)
}
return"
def
detail
(
self
,
last_node
:
ast
.
AST
=
None
)
->
str
:
return
f"""
This indicates that a function is missing a
{
highlight
(
'return'
)
}
statement in one or more of its code paths.
For example:
{
highlight
(
'def f(x: int):'
)
}
{
highlight
(
' if x > 0:'
)
}
{
highlight
(
' return 1'
)
}
{
highlight
(
' # if x <= 0, the function returns nothing'
)
}
"""
@
dataclass
class
InconsistentMroError
(
CompileError
):
bases
:
list
[
BaseType
]
def
__str__
(
self
)
->
str
:
return
f"Cannot create a cnossitent method resolution order (MRO) for bases
{
'
\
n
'
.
join
(
map
(
highlight
,
self
.
bases
))
}
"
def
detail
(
self
,
last_node
:
ast
.
AST
=
None
)
->
str
:
return
f"""
This indicates that a class has an inconsistent method resolution order (MRO).
For example:
{
highlight
(
'class A: pass'
)
}
{
highlight
(
'class B(A): pass'
)
}
{
highlight
(
'class C(B, A): pass'
)
}
"""
\ No newline at end of file
typon/trans/transpiler/phases/typing2/expr.py
deleted
100644 → 0
View file @
f8de89ac
import
abc
import
ast
import
inspect
from
typing
import
List
from
transpiler.phases.typing
import
ScopeKind
,
VarDecl
,
VarKind
from
transpiler.phases.typing.common
import
ScoperVisitor
,
get_iter
,
get_next
,
is_builtin
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
,
TY_FLOAT
,
RuntimeValue
,
BuiltinFeature
from
transpiler.utils
import
linenodata
DUNDER
=
{
ast
.
Eq
:
"eq"
,
ast
.
NotEq
:
"ne"
,
ast
.
Mult
:
"mul"
,
ast
.
Add
:
"add"
,
ast
.
Sub
:
"sub"
,
ast
.
Div
:
"truediv"
,
ast
.
FloorDiv
:
"floordiv"
,
ast
.
Mod
:
"mod"
,
ast
.
Lt
:
"lt"
,
ast
.
Gt
:
"gt"
,
ast
.
GtE
:
"ge"
,
ast
.
LtE
:
"le"
,
ast
.
LShift
:
"lshift"
,
ast
.
RShift
:
"rshift"
,
ast
.
BitXor
:
"xor"
,
ast
.
BitOr
:
"or"
,
ast
.
BitAnd
:
"and"
,
ast
.
USub
:
"neg"
,
ast
.
UAdd
:
"pos"
,
ast
.
Invert
:
"invert"
,
ast
.
In
:
"contains"
,
}
class
ScoperExprVisitor
(
ScoperVisitor
):
def
visit
(
self
,
node
)
->
BaseType
:
if
existing
:
=
getattr
(
node
,
"type"
,
None
):
return
existing
.
resolve
()
__TB_SKIP__
=
True
res
=
super
().
visit
(
node
)
if
not
res
:
__TB_SKIP__
=
False
raise
NotImplementedError
(
f"`
{
ast
.
unparse
(
node
)
}
`
{
type
(
node
)
}
"
)
res
=
res
.
resolve
()
if
True
or
not
hasattr
(
res
,
"from_node"
):
res
.
from_node
=
node
node
.
type
=
res
return
res
def
visit_Tuple
(
self
,
node
:
ast
.
Tuple
)
->
BaseType
:
return
TupleType
(
*
[
self
.
visit
(
e
)
for
e
in
node
.
elts
])
def
visit_Slice
(
self
,
node
:
ast
.
Slice
)
->
BaseType
:
for
n
in
(
"lower"
,
"upper"
,
"step"
):
if
arg
:
=
getattr
(
node
,
n
):
self
.
visit
(
arg
).
unify
(
TY_INT
)
return
TY_SLICE
def
visit_Yield
(
self
,
node
:
ast
.
Yield
)
->
BaseType
:
ytype
=
self
.
visit
(
node
.
value
)
ftype
=
self
.
scope
.
function
.
obj_type
.
return_type
assert
isinstance
(
ftype
,
Promise
)
assert
ftype
.
kind
==
PromiseKind
.
TASK
ftype
.
kind
=
PromiseKind
.
GENERATOR
ftype
.
return_type
.
unify
(
ytype
)
self
.
scope
.
function
.
has_yield
=
True
return
TY_NONE
def
visit_Constant
(
self
,
node
:
ast
.
Constant
)
->
BaseType
:
if
isinstance
(
node
.
value
,
str
):
return
TY_STR
elif
isinstance
(
node
.
value
,
bool
):
return
TY_BOOL
elif
isinstance
(
node
.
value
,
int
):
return
TY_INT
elif
isinstance
(
node
.
value
,
complex
):
return
TY_COMPLEX
elif
isinstance
(
node
.
value
,
float
):
return
TY_FLOAT
elif
node
.
value
is
None
:
return
TY_NONE
else
:
raise
NotImplementedError
(
node
,
type
(
node
))
def
visit_Name
(
self
,
node
:
ast
.
Name
)
->
BaseType
:
obj
=
self
.
scope
.
get
(
node
.
id
)
if
not
obj
:
from
transpiler.phases.typing.exceptions
import
UnknownNameError
raise
UnknownNameError
(
node
.
id
)
ty
=
obj
.
type
.
resolve
()
if
isinstance
(
ty
,
TypeType
)
and
isinstance
(
ty
.
type_object
,
TypeVariable
):
raise
NameError
(
f"Use of type variable"
)
# todo: when does this happen exactly?
if
getattr
(
ty
,
"is_python_func"
,
False
):
ty
.
python_func_used
=
True
return
ty
def
visit_BoolOp
(
self
,
node
:
ast
.
BoolOp
)
->
BaseType
:
for
value
in
node
.
values
:
self
.
visit
(
value
)
return
TY_BOOL
def
visit_Call
(
self
,
node
:
ast
.
Call
)
->
BaseType
:
ftype
=
self
.
visit
(
node
.
func
)
if
is_builtin
(
ftype
,
"TypeVar"
):
return
TypeType
(
TypeVariable
(
*
[
ast
.
literal_eval
(
arg
)
for
arg
in
node
.
args
]))
if
ftype
.
typevars
:
ftype
=
ftype
.
gen_sub
(
None
,
{
v
.
name
:
TypeVariable
(
v
.
name
)
for
v
in
ftype
.
typevars
})
from
transpiler.exceptions
import
CompileError
rtype
=
self
.
visit_function_call
(
ftype
,
[
self
.
visit
(
arg
)
for
arg
in
node
.
args
])
actual
=
rtype
node
.
is_await
=
False
if
isinstance
(
actual
,
Promise
)
and
actual
.
kind
!=
PromiseKind
.
GENERATOR
:
node
.
is_await
=
True
actual
=
actual
.
return_type
.
resolve
()
if
self
.
scope
.
function
and
isinstance
(
actual
,
Promise
)
and
actual
.
kind
==
PromiseKind
.
FORKED
\
and
isinstance
(
fty
:
=
self
.
scope
.
function
.
obj_type
.
return_type
,
Promise
):
fty
.
kind
=
PromiseKind
.
JOIN
return
actual
def
visit_function_call
(
self
,
ftype
:
BaseType
,
arguments
:
List
[
BaseType
]):
if
isinstance
(
ftype
,
TypeType
):
# and isinstance(ftype.type_object, UserType):
init
:
FunctionType
=
self
.
visit_getattr
(
ftype
,
"__init__"
).
remove_self
()
init
.
return_type
=
ftype
.
type_object
return
self
.
visit_function_call
(
init
,
arguments
)
if
isinstance
(
ftype
,
FunctionType
):
ret
=
ftype
.
return_type
elif
isinstance
(
ftype
,
TypeVariable
):
ret
=
TypeVariable
()
else
:
from
transpiler.phases.typing.exceptions
import
NotCallableError
raise
NotCallableError
(
ftype
)
#is_generic = any(isinstance(arg, TypeVariable) for arg in ftype.to_list())
equivalent
=
FunctionType
(
arguments
,
ret
)
equivalent
.
is_intermediary
=
True
ftype
.
unify
(
equivalent
)
return
equivalent
.
return_type
def
visit_Lambda
(
self
,
node
:
ast
.
Lambda
)
->
BaseType
:
argtypes
=
[
TypeVariable
()
for
_
in
node
.
args
.
args
]
rtype
=
TypeVariable
()
ftype
=
FunctionType
(
argtypes
,
rtype
)
scope
=
self
.
scope
.
child
(
ScopeKind
.
FUNCTION
)
scope
.
obj_type
=
ftype
scope
.
function
=
scope
node
.
inner_scope
=
scope
node
.
body
.
scope
=
scope
for
arg
,
ty
in
zip
(
node
.
args
.
args
,
argtypes
):
scope
.
vars
[
arg
.
arg
]
=
VarDecl
(
VarKind
.
LOCAL
,
ty
)
decls
=
{}
visitor
=
ScoperExprVisitor
(
scope
,
decls
)
rtype
.
unify
(
visitor
.
visit
(
node
.
body
))
node
.
body
.
decls
=
decls
return
ftype
# def visit_BinOp(self, node: ast.BinOp) -> BaseType:
# left, right = map(self.visit, (node.left, node.right))
# return self.make_dunder([left, right], DUNDER[type(node.op)])
# def visit_Compare(self, node: ast.Compare) -> BaseType:
# left, right = map(self.visit, (node.left, node.comparators[0]))
# op = node.ops[0]
# if type(op) == ast.In:
# left, right = right, left
# return self.make_dunder([left, right], DUNDER[type(op)])
def
visit_Attribute
(
self
,
node
:
ast
.
Attribute
)
->
BaseType
:
ltype
=
self
.
visit
(
node
.
value
)
return
self
.
visit_getattr
(
ltype
,
node
.
attr
)
def
visit_getattr
(
self
,
ltype
:
BaseType
,
name
:
str
)
->
BaseType
:
bound
=
True
if
isinstance
(
ltype
,
TypeType
):
# if mdecl := ltype.static_members.get(name):
# attr = mdecl.type
# if getattr(attr, "is_python_func", False):
# attr.python_func_used = True
# return attr
ltype
=
ltype
.
type_object
bound
=
False
if
isinstance
(
ltype
,
abc
.
ABCMeta
):
ctor
=
ltype
.
__init__
args
=
list
(
inspect
.
signature
(
ctor
).
parameters
.
values
())[
1
:]
if
not
all
(
arg
.
annotation
==
BaseType
for
arg
in
args
):
raise
NotImplementedError
(
"I don't know how to handle this type"
)
ltype
=
ltype
(
*
(
TypeVariable
()
for
_
in
args
))
# if mdecl := ltype.members.get(name):
# attr = mdecl.type
# if getattr(attr, "is_python_func", False):
# attr.python_func_used = True
# return attr
# if meth := ltype.methods.get(name):
# meth = meth.gen_sub(ltype, {})
# if bound:
# return meth.remove_self()
# else:
# return meth
if
field
:
=
ltype
.
fields
.
get
(
name
):
ty
=
field
.
type
.
resolve
()
if
getattr
(
ty
,
"is_python_func"
,
False
):
ty
.
python_func_used
=
True
if
isinstance
(
ty
,
FunctionType
):
ty
=
ty
.
gen_sub
(
ltype
,
{})
if
bound
and
field
.
in_class_def
and
type
(
field
.
val
)
!=
RuntimeValue
:
return
ty
.
remove_self
()
return
ty
from
transpiler.phases.typing.exceptions
import
MissingAttributeError
parents
=
ltype
.
iter_hierarchy_recursive
()
next
(
parents
)
for
p
in
parents
:
try
:
return
self
.
visit_getattr
(
p
,
name
)
except
MissingAttributeError
as
e
:
pass
# class MemberProtocol(TypeOperator):
# pass
raise
MissingAttributeError
(
ltype
,
name
)
def
visit_List
(
self
,
node
:
ast
.
List
)
->
BaseType
:
if
not
node
.
elts
:
return
PyList
(
TypeVariable
())
elems
=
[
self
.
visit
(
e
)
for
e
in
node
.
elts
]
first
,
*
rest
=
elems
for
e
in
rest
:
try
:
first
.
unify
(
e
)
except
:
raise
NotImplementedError
(
f"List with different types not handled yet:
{
', '
.
join
(
map
(
str
,
elems
))
}
"
)
return
PyList
(
elems
[
0
])
def
visit_Set
(
self
,
node
:
ast
.
Set
)
->
BaseType
:
if
not
node
.
elts
:
return
PySet
(
TypeVariable
())
elems
=
[
self
.
visit
(
e
)
for
e
in
node
.
elts
]
if
len
(
set
(
elems
))
!=
1
:
raise
NotImplementedError
(
"Set with different types not handled yet"
)
return
PySet
(
elems
[
0
])
def
visit_Dict
(
self
,
node
:
ast
.
Dict
)
->
BaseType
:
if
not
node
.
keys
:
return
PyDict
(
TypeVariable
(),
TypeVariable
())
keys
=
[
self
.
visit
(
e
)
for
e
in
node
.
keys
]
values
=
[
self
.
visit
(
e
)
for
e
in
node
.
values
]
if
len
(
set
(
keys
))
!=
1
or
len
(
set
(
values
))
!=
1
:
raise
NotImplementedError
(
f"Dict with different types not handled yet in `
{
ast
.
unparse
(
node
)
}
`"
)
return
PyDict
(
keys
[
0
],
values
[
0
])
def
visit_Subscript
(
self
,
node
:
ast
.
Subscript
)
->
BaseType
:
left
=
self
.
visit
(
node
.
value
)
args
=
node
.
slice
if
type
(
node
.
slice
)
==
tuple
else
[
node
.
slice
]
args
=
[
self
.
visit
(
e
)
for
e
in
args
]
if
isinstance
(
left
,
TypeType
)
and
isinstance
(
left
.
type_object
,
abc
.
ABCMeta
):
# generic
return
TypeType
(
left
.
type_object
(
*
[
arg
.
type_object
if
isinstance
(
arg
,
TypeType
)
else
arg
for
arg
in
args
]))
pass
return
self
.
make_dunder
([
left
,
*
args
],
"getitem"
)
def
visit_UnaryOp
(
self
,
node
:
ast
.
UnaryOp
)
->
BaseType
:
val
=
self
.
visit
(
node
.
operand
)
if
isinstance
(
node
.
op
,
ast
.
Not
):
return
TY_BOOL
return
self
.
make_dunder
([
val
],
DUNDER
[
type
(
node
.
op
)])
def
visit_IfExp
(
self
,
node
:
ast
.
IfExp
)
->
BaseType
:
self
.
visit
(
node
.
test
)
then
=
self
.
visit
(
node
.
body
)
else_
=
self
.
visit
(
node
.
orelse
)
if
then
!=
else_
:
raise
NotImplementedError
(
"IfExp with different types not handled yet"
)
return
then
def
make_dunder
(
self
,
args
:
List
[
BaseType
],
name
:
str
)
->
BaseType
:
return
self
.
visit_function_call
(
self
.
visit_getattr
(
TypeType
(
args
[
0
]),
f"__
{
name
}
__"
),
args
)
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
typon/trans/transpiler/phases/typing2/scope.py
deleted
100644 → 0
View file @
f8de89ac
import
ast
from
dataclasses
import
field
,
dataclass
from
enum
import
Enum
from
typing
import
Optional
,
Dict
,
List
,
Any
from
transpiler.phases.typing.types
import
BaseType
,
RuntimeValue
class
VarKind
(
Enum
):
"""Kind of variable."""
LOCAL
=
1
"""`xxx = ...`"""
GLOBAL
=
2
"""`global xxx"""
NONLOCAL
=
3
"""`nonlocal xxx`"""
SELF
=
4
OUTER_DECL
=
5
MODULE
=
6
class
VarType
:
pass
@
dataclass
class
VarDecl
:
kind
:
VarKind
type
:
BaseType
val
:
Any
=
RuntimeValue
()
class
ScopeKind
(
Enum
):
GLOBAL
=
1
"""Global (module) scope"""
FUNCTION
=
2
"""Function scope"""
FUNCTION_INNER
=
3
"""Block (if, for, ...) scope inside a function"""
CLASS
=
4
"""Class scope"""
@
dataclass
class
Scope
:
parent
:
Optional
[
"Scope"
]
=
None
kind
:
ScopeKind
=
ScopeKind
.
GLOBAL
function
:
Optional
[
"Scope"
]
=
None
global_scope
:
Optional
[
"Scope"
]
=
None
vars
:
Dict
[
str
,
VarDecl
]
=
field
(
default_factory
=
dict
)
children
:
List
[
"Scope"
]
=
field
(
default_factory
=
list
)
obj_type
:
Optional
[
BaseType
]
=
None
diverges
:
bool
=
False
class_
:
Optional
[
"Scope"
]
=
None
is_loop
:
Optional
[
ast
.
For
|
ast
.
While
]
=
None
@
staticmethod
def
make_global
():
res
=
Scope
()
res
.
global_scope
=
res
return
res
def
is_in_loop
(
self
)
->
Optional
[
ast
.
For
|
ast
.
While
]:
if
self
.
is_loop
:
return
self
.
is_loop
if
self
.
parent
is
not
None
and
self
.
kind
!=
ScopeKind
.
FUNCTION
:
return
self
.
parent
.
is_in_loop
()
return
None
def
child
(
self
,
kind
:
ScopeKind
):
res
=
Scope
(
self
,
kind
,
self
.
function
,
self
.
global_scope
)
if
kind
==
ScopeKind
.
GLOBAL
:
res
.
global_scope
=
res
self
.
children
.
append
(
res
)
return
res
def
declare_local
(
self
,
name
:
str
,
type
:
BaseType
):
"""Declares a local variable"""
self
.
vars
[
name
]
=
VarDecl
(
VarKind
.
LOCAL
,
type
)
def
get
(
self
,
name
:
str
,
kind
:
VarKind
|
set
[
VarKind
]
=
VarKind
.
LOCAL
,
restrict_function
:
bool
=
False
)
->
Optional
[
VarDecl
]:
"""
Gets the variable declaration of a variable in the current scope or any parent scope.
"""
if
type
(
kind
)
is
VarKind
:
kind
=
{
kind
}
if
(
res
:
=
self
.
vars
.
get
(
name
))
and
res
.
kind
in
kind
:
if
res
.
kind
==
VarKind
.
GLOBAL
:
return
self
.
global_scope
.
get
(
name
,
kind
)
elif
res
.
kind
==
VarKind
.
NONLOCAL
:
return
self
.
function
.
parent
.
get
(
name
,
VarKind
.
LOCAL
,
True
)
return
res
if
self
.
parent
is
not
None
and
not
(
self
.
kind
==
ScopeKind
.
FUNCTION
and
restrict_function
):
return
self
.
parent
.
get
(
name
,
kind
,
restrict_function
)
return
None
typon/trans/transpiler/phases/typing2/stdlib.py
deleted
100644 → 0
View file @
f8de89ac
import
ast
import
dataclasses
from
abc
import
ABCMeta
from
dataclasses
import
dataclass
,
field
from
typing
import
Optional
,
List
,
Dict
from
logging
import
debug
from
transpiler.phases.typing.annotations
import
TypeAnnotationVisitor
from
transpiler.phases.typing.common
import
PRELUDE
,
is_builtin
from
transpiler.phases.typing.expr
import
ScoperExprVisitor
from
transpiler.phases.typing.scope
import
Scope
,
VarDecl
,
VarKind
,
ScopeKind
from
transpiler.phases.typing.types
import
BaseType
,
TypeOperator
,
FunctionType
,
TY_VARARG
,
TypeType
,
TypeVariable
,
\
MemberDef
,
BuiltinFeature
from
transpiler.phases.utils
import
NodeVisitorSeq
@
dataclass
class
StdlibVisitor
(
NodeVisitorSeq
):
scope
:
Scope
=
field
(
default_factory
=
lambda
:
PRELUDE
)
cur_class
:
Optional
[
BaseType
]
=
None
typevars
:
Dict
[
str
,
BaseType
]
=
field
(
default_factory
=
dict
)
def
expr
(
self
)
->
ScoperExprVisitor
:
return
ScoperExprVisitor
(
self
.
scope
)
def
visit_Module
(
self
,
node
:
ast
.
Module
):
for
stmt
in
node
.
body
:
self
.
visit
(
stmt
)
def
visit_Assign
(
self
,
node
:
ast
.
Assign
):
self
.
scope
.
vars
[
node
.
targets
[
0
].
id
]
=
VarDecl
(
VarKind
.
LOCAL
,
self
.
visit
(
node
.
value
))
def
visit_AnnAssign
(
self
,
node
:
ast
.
AnnAssign
):
ty
=
self
.
anno
().
visit
(
node
.
annotation
)
if
self
.
cur_class
:
assert
isinstance
(
self
.
cur_class
,
TypeType
)
if
isinstance
(
self
.
cur_class
.
type_object
,
ABCMeta
):
raise
NotImplementedError
else
:
self
.
cur_class
.
type_object
.
fields
[
node
.
target
.
id
]
=
MemberDef
(
ty
.
gen_sub
(
self
.
cur_class
.
type_object
,
self
.
typevars
))
self
.
scope
.
vars
[
node
.
target
.
id
]
=
VarDecl
(
VarKind
.
LOCAL
,
ty
)
def
visit_ImportFrom
(
self
,
node
:
ast
.
ImportFrom
):
pass
def
visit_Import
(
self
,
node
:
ast
.
Import
):
pass
def
visit_ClassDef
(
self
,
node
:
ast
.
ClassDef
):
if
existing
:
=
self
.
scope
.
get
(
node
.
name
):
ty
=
existing
.
type
else
:
class
BuiltinClassType
(
TypeOperator
):
def
__init__
(
self
,
*
args
):
super
().
__init__
(
args
,
node
.
name
,
is_reference
=
True
)
ty
=
TypeType
(
BuiltinClassType
)
self
.
scope
.
vars
[
node
.
name
]
=
VarDecl
(
VarKind
.
LOCAL
,
ty
)
typevars
=
[]
for
b
in
node
.
bases
:
if
isinstance
(
b
,
ast
.
Subscript
):
if
isinstance
(
b
.
slice
,
ast
.
Name
):
sliceval
=
[
b
.
slice
.
id
]
elif
isinstance
(
b
.
slice
,
ast
.
Tuple
):
sliceval
=
[
n
.
id
for
n
in
b
.
slice
.
elts
]
if
isinstance
(
b
.
value
,
ast
.
Name
)
and
b
.
value
.
id
==
"Generic"
:
typevars
=
sliceval
elif
isinstance
(
b
.
value
,
ast
.
Name
)
and
b
.
value
.
id
==
"Protocol"
:
typevars
=
sliceval
ty
.
type_object
.
is_protocol_gen
=
True
else
:
idxs
=
[
typevars
.
index
(
v
)
for
v
in
sliceval
]
parent
=
self
.
visit
(
b
.
value
)
assert
isinstance
(
parent
,
TypeType
)
assert
isinstance
(
ty
.
type_object
,
ABCMeta
)
ty
.
type_object
.
gen_parents
.
append
(
lambda
selfvars
:
parent
.
type_object
(
*
[
selfvars
[
i
]
for
i
in
idxs
]))
else
:
if
isinstance
(
b
,
ast
.
Name
)
and
b
.
id
==
"Protocol"
:
ty
.
type_object
.
is_protocol_gen
=
True
else
:
parent
=
self
.
visit
(
b
)
assert
isinstance
(
parent
,
TypeType
)
if
isinstance
(
ty
.
type_object
,
ABCMeta
):
ty
.
type_object
.
gen_parents
.
append
(
parent
.
type_object
)
else
:
ty
.
type_object
.
parents
.
append
(
parent
.
type_object
)
if
not
typevars
and
not
existing
:
ty
.
type_object
=
ty
.
type_object
()
cl_scope
=
self
.
scope
.
child
(
ScopeKind
.
CLASS
)
visitor
=
StdlibVisitor
(
cl_scope
,
ty
)
for
var
in
typevars
:
visitor
.
typevars
[
var
]
=
TypeType
(
TypeVariable
(
var
))
for
stmt
in
node
.
body
:
visitor
.
visit
(
stmt
)
def
visit_Pass
(
self
,
node
:
ast
.
Pass
):
pass
def
visit_FunctionDef
(
self
,
node
:
ast
.
FunctionDef
):
tc
=
node
.
type_comment
# todo : lire les commetnaries de type pour les fonctions génériques sinon trouver autre chose
arg_visitor
=
TypeAnnotationVisitor
(
self
.
scope
.
child
(
ScopeKind
.
FUNCTION
),
self
.
cur_class
)
arg_types
=
[
arg_visitor
.
visit
(
arg
.
annotation
or
arg
.
arg
)
for
arg
in
node
.
args
.
args
]
ret_type
=
arg_visitor
.
visit
(
node
.
returns
)
ty
=
FunctionType
(
arg_types
,
ret_type
)
ty
.
typevars
=
arg_visitor
.
typevars
if
node
.
args
.
vararg
:
ty
.
variadic
=
True
ty
.
optional_at
=
1
+
len
(
node
.
args
.
args
)
-
len
(
node
.
args
.
defaults
)
if
self
.
cur_class
:
ty
.
is_method
=
True
assert
isinstance
(
self
.
cur_class
,
TypeType
)
if
isinstance
(
self
.
cur_class
.
type_object
,
ABCMeta
):
self
.
cur_class
.
type_object
.
gen_methods
[
node
.
name
]
=
lambda
t
:
ty
.
gen_sub
(
t
,
self
.
typevars
)
else
:
self
.
cur_class
.
type_object
.
fields
[
node
.
name
]
=
MemberDef
(
ty
.
gen_sub
(
self
.
cur_class
.
type_object
,
self
.
typevars
),
())
self
.
scope
.
vars
[
node
.
name
]
=
VarDecl
(
VarKind
.
LOCAL
,
ty
)
def
visit_Assert
(
self
,
node
:
ast
.
Assert
):
if
isinstance
(
node
.
test
,
ast
.
UnaryOp
)
and
isinstance
(
node
.
test
.
op
,
ast
.
Not
):
oper
=
node
.
test
.
operand
try
:
res
=
self
.
expr
().
visit
(
oper
)
except
:
debug
(
f"Type of
{
ast
.
unparse
(
oper
)
}
:= INVALID"
)
else
:
raise
AssertionError
(
f"Assertion should fail, got
{
res
}
for
{
ast
.
unparse
(
oper
)
}
"
)
else
:
debug
(
f"Type of
{
ast
.
unparse
(
node
.
test
)
}
:=
{
self
.
expr
().
visit
(
node
.
test
)
}
"
)
def
visit_Call
(
self
,
node
:
ast
.
Call
)
->
BaseType
:
ty_op
=
self
.
visit
(
node
.
func
)
if
is_builtin
(
ty_op
,
"TypeVar"
):
return
TypeType
(
TypeVariable
(
*
[
ast
.
literal_eval
(
arg
)
for
arg
in
node
.
args
]))
if
isinstance
(
ty_op
,
TypeType
):
return
TypeType
(
ty_op
.
type_object
(
*
[
ast
.
literal_eval
(
arg
)
for
arg
in
node
.
args
]))
raise
NotImplementedError
(
ast
.
unparse
(
node
))
def
anno
(
self
)
->
"TypeAnnotationVisitor"
:
return
TypeAnnotationVisitor
(
self
.
scope
,
self
.
cur_class
)
def
visit_str
(
self
,
node
:
str
)
->
BaseType
:
if
existing
:
=
self
.
scope
.
get
(
node
):
return
existing
.
type
from
transpiler.phases.typing.exceptions
import
UnknownNameError
raise
UnknownNameError
(
node
)
def
visit_Name
(
self
,
node
:
ast
.
Name
)
->
BaseType
:
if
node
.
id
==
"TypeVar"
:
return
BuiltinFeature
(
"TypeVar"
)
return
self
.
visit_str
(
node
.
id
)
\ No newline at end of file
typon/trans/transpiler/phases/typing2/types.py
deleted
100644 → 0
View file @
f8de89ac
import
typing
from
abc
import
ABC
,
abstractmethod
from
dataclasses
import
dataclass
,
field
from
typing
import
Dict
,
Optional
,
Callable
def
get_default_parents
():
if
obj
:
=
globals
().
get
(
"TY_OBJECT"
):
return
[
obj
]
return
[]
class
RuntimeValue
:
pass
@
dataclass
class
MemberDef
:
type
:
"BaseType"
val
:
typing
.
Any
=
RuntimeValue
()
in_class_def
:
bool
=
True
@
dataclass
(
eq
=
False
)
class
BaseType
(
ABC
):
def
resolve
(
self
)
->
"BaseType"
:
return
self
cur_var
=
0
def
next_var_id
():
global
cur_var
cur_var
+=
1
return
cur_var
@
dataclass
(
eq
=
False
)
class
ConcreteType
(
BaseType
):
"""
A concrete type is the type of a concrete value.
It has fields and a list of parent concrete types.
Examples: int, str, list[int]
"""
@
dataclass
(
eq
=
False
)
class
TypeVariable
(
ConcreteType
):
name
:
str
=
field
(
default_factory
=
lambda
:
next_var_id
())
resolved
:
Optional
[
ConcreteType
]
=
None
def
resolve
(
self
)
->
ConcreteType
:
if
self
.
resolved
is
None
:
return
self
return
self
.
resolved
.
resolve
()
def
__str__
(
self
):
if
self
.
resolved
is
None
:
# return f"TypeVar[\"{self.name}\"]"
return
f"_
{
self
.
name
}
"
return
str
(
self
.
resolved
)
def
__eq__
(
self
,
other
):
if
not
isinstance
(
other
,
BaseType
):
return
False
if
self
.
resolved
is
None
:
return
self
==
other
return
self
.
resolved
==
other
.
resolve
()
@
dataclass
(
eq
=
False
)
class
ResolvedConcreteType
(
ConcreteType
):
"""
A concrete type is the type of a concrete value.
It has fields and a list of parent concrete types.
Examples: int, str, list[int]
"""
fields
:
Dict
[
str
,
"MemberDef"
]
=
field
(
default_factory
=
dict
,
init
=
False
)
parents
:
list
[
"ResolvedConcreteType"
]
=
field
(
default_factory
=
lambda
:
[
TY_OBJECT
],
init
=
False
)
def
get_mro
(
self
):
"""
Performs linearization according to the MRO spec.
https://www.python.org/download/releases/2.3/mro/
"""
def
merge
(
*
lists
):
lists
=
[
l
for
l
in
lists
if
len
(
l
)
>
0
]
for
i
,
l
in
enumerate
(
lists
):
first
=
l
[
0
]
for
j
,
l2
in
enumerate
(
lists
):
if
j
==
i
:
continue
if
first
in
l2
:
break
else
:
return
[
first
]
+
merge
(
*
[
x
[
1
:]
for
x
in
lists
if
x
[
0
]
!=
first
])
# unable to find a next element
from
transpiler.phases.typing.exceptions
import
InconsistentMroError
raise
InconsistentMroError
(
self
.
parents
)
return
[
self
]
+
merge
(
*
[
p
.
get_mro
()
for
p
in
self
.
parents
],
self
.
parents
)
def
inherits
(
self
,
parent
:
BaseType
):
return
self
==
parent
or
any
(
p
.
inherits
(
parent
)
for
p
in
self
.
parents
)
@
dataclass
(
eq
=
False
,
init
=
False
)
class
GenericInstanceType
(
ResolvedConcreteType
):
"""
An instance of a generic type.
Examples: list[int], dict[str, object], Callable[[int, int], int]
"""
generic_parent
:
"GenericType"
generic_args
:
list
[
ConcreteType
]
def
__init__
(
self
):
super
().
__init__
()
def
inherits
(
self
,
parent
:
BaseType
):
return
self
.
generic_parent
==
parent
or
super
().
inherits
(
parent
)
def
__eq__
(
self
,
other
):
if
isinstance
(
other
,
GenericInstanceType
):
return
self
.
generic_parent
==
other
.
generic_parent
and
self
.
generic_args
==
other
.
generic_args
return
False
def
__str__
(
self
):
return
f"
{
self
.
generic_parent
}
[
{
', '
.
join
(
map
(
str
,
self
.
generic_args
))
}
]"
@
dataclass
class
GenericConstraint
:
left
:
ResolvedConcreteType
right
:
ResolvedConcreteType
@
dataclass
(
eq
=
False
,
init
=
False
)
class
GenericType
(
BaseType
):
parameters
:
list
[
str
]
def
constraints
(
self
,
args
:
list
[
ConcreteType
])
->
list
[
GenericConstraint
]:
return
[]
@
abstractmethod
def
_instantiate
(
self
,
args
:
list
[
ConcreteType
])
->
GenericInstanceType
:
raise
NotImplementedError
()
def
instantiate
(
self
,
args
:
list
[
ConcreteType
])
->
GenericInstanceType
:
res
=
self
.
_instantiate
(
args
)
res
.
generic_args
=
args
res
.
generic_parent
=
self
return
res
@
dataclass
(
eq
=
False
,
init
=
False
)
class
BuiltinGenericType
(
GenericType
):
constraints_
:
Callable
[[
list
[
ConcreteType
]],
list
[
GenericConstraint
]]
instantiate_
:
Callable
[[
list
[
ConcreteType
]],
GenericInstanceType
]
def
constraints
(
self
,
args
:
list
[
ConcreteType
])
->
list
[
GenericConstraint
]:
return
self
.
constraints_
(
args
)
def
_instantiate
(
self
,
args
:
list
[
ConcreteType
])
->
GenericInstanceType
:
return
self
.
instantiate_
(
args
)
def
create_builtin_type
(
name
:
str
):
class
CreatedType
(
BuiltinGenericType
):
def
__str__
(
self
):
return
name
res
=
CreatedType
()
return
res
TY_OBJECT
=
None
TY_OBJECT
=
create_builtin_type
(
"object"
)
TY_OBJECT
.
parents
=
[]
TY_BOOL
=
create_builtin_type
(
"bool"
)
TY_INT
=
create_builtin_type
(
"int"
)
TY_FLOAT
=
create_builtin_type
(
"float"
)
TY_STR
=
create_builtin_type
(
"str"
)
TY_BYTES
=
create_builtin_type
(
"bytes"
)
TY_COMPLEX
=
create_builtin_type
(
"complex"
)
TY_NONE
=
create_builtin_type
(
"NoneType"
)
def
unimpl
(
*
args
,
**
kwargs
):
raise
NotImplementedError
()
def
create_builtin_generic_type
(
name
:
str
):
class
CreatedType
(
BuiltinGenericType
):
def
__str__
(
self
):
return
name
res
=
CreatedType
()
return
res
TY_LIST
=
create_builtin_generic_type
(
"list"
)
TY_SET
=
create_builtin_generic_type
(
"set"
)
TY_DICT
=
create_builtin_generic_type
(
"dict"
)
TY_TUPLE
=
create_builtin_generic_type
(
"tuple"
)
@
dataclass
(
unsafe_hash
=
False
)
class
TypeListType
(
ConcreteType
):
"""
Special type used to represent a list of types.
Used in function types: Callable[[int, int], int]
"""
contents
:
list
[
ConcreteType
]
def
__str__
(
self
):
return
f"[
{
', '
.
join
(
map
(
str
,
self
.
contents
))
}
]"
@
dataclass
(
eq
=
False
)
class
CallableInstanceType
(
GenericInstanceType
):
parameters
:
list
[
ConcreteType
]
return_type
:
ConcreteType
class
CallableType
(
GenericType
):
def
__str__
(
self
):
return
"Callable"
def
_instantiate
(
self
,
args
:
list
[
ConcreteType
])
->
GenericInstanceType
:
match
args
:
case
[
TypeListType
([
*
args
]),
ret
]:
return
CallableInstanceType
(
args
,
ret
)
case
_
:
raise
ValueError
TY_CALLABLE
=
CallableType
()
@
dataclass
(
eq
=
False
)
class
ClassTypeType
(
GenericInstanceType
):
inner_type
:
BaseType
class
ClassType
(
GenericType
):
def
__str__
(
self
):
return
"Type"
def
_instantiate
(
self
,
args
:
list
[
ConcreteType
])
->
GenericInstanceType
:
return
ClassTypeType
(
*
args
)
TY_TYPE
=
ClassType
()
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