Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
O
OUTDATED Verse-library
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
AutonomyCourse_ECEIllinois
OUTDATED Verse-library
Commits
0f9cfed7
Commit
0f9cfed7
authored
3 years ago
by
crides
Browse files
Options
Downloads
Patches
Plain Diff
parse: fix if handling
parent
6b99b0d6
No related branches found
No related tags found
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
parse.py
+145
-44
145 additions, 44 deletions
parse.py
with
145 additions
and
44 deletions
parse.py
+
145
−
44
View file @
0f9cfed7
...
@@ -3,8 +3,30 @@ from typing import List, Dict, Union, Optional, TypeAlias, Any
...
@@ -3,8 +3,30 @@ from typing import List, Dict, Union, Optional, TypeAlias, Any
from
dataclasses
import
dataclass
from
dataclasses
import
dataclass
from
enum
import
Enum
,
auto
from
enum
import
Enum
,
auto
class
Argument
():
def
dbg
(
msg
,
*
rest
):
pass
print
(
f
"
\x1b
[31m
{
msg
}
\x1b
[m
"
,
end
=
""
)
for
i
,
a
in
enumerate
(
rest
[:
5
]):
print
(
f
"
\x1b
[3
{
i
+
2
}
m
{
a
}
\x1b
[m
"
,
end
=
""
)
if
rest
[
5
:]:
print
(
""
,
rest
[
5
:])
else
:
print
()
ScopeValue
:
TypeAlias
=
Union
[
ast
.
AST
,
"
CondVal
"
,
"
Lambda
"
,
Dict
[
str
,
"
ScopeValue
"
]]
# TODO
@dataclass
class
CondValElem
:
cond
:
List
[
ScopeValue
]
val
:
ScopeValue
def
__eq__
(
self
,
o
)
->
bool
:
if
o
==
None
or
len
(
self
.
cond
)
!=
len
(
o
.
cond
):
return
False
return
all
(
ir_eq
(
sc
,
oc
)
for
sc
,
oc
in
zip
(
self
.
cond
,
o
.
cond
))
and
ir_eq
(
self
.
val
,
o
.
val
)
@dataclass
class
CondVal
:
elems
:
List
[
CondValElem
]
class
ReductionType
(
Enum
):
class
ReductionType
(
Enum
):
Any
=
auto
()
Any
=
auto
()
...
@@ -30,14 +52,10 @@ class Reduction:
...
@@ -30,14 +52,10 @@ class Reduction:
it
:
str
it
:
str
value
:
ast
.
AST
value
:
ast
.
AST
class
If
:
def
__eq__
(
self
,
o
)
->
bool
:
test
:
ast
.
expr
if
o
==
None
:
true
:
ast
.
expr
return
False
false
:
Optional
[
ast
.
expr
]
return
self
.
op
==
o
.
op
and
self
.
it
==
o
.
it
and
ir_eq
(
self
.
expr
,
o
.
expr
)
and
ir_eq
(
self
.
value
,
o
.
value
)
def
__init__
(
self
,
test
,
true
,
false
=
None
):
self
.
test
=
test
self
.
true
=
true
self
.
false
=
false
@dataclass
@dataclass
class
Lambda
:
class
Lambda
:
...
@@ -54,35 +72,46 @@ class Lambda:
...
@@ -54,35 +72,46 @@ class Lambda:
for
a
in
args
:
for
a
in
args
:
scope
.
set
(
a
,
ast
.
arg
(
a
))
scope
.
set
(
a
,
ast
.
arg
(
a
))
ret
=
None
ret
=
None
for
node
in
tree
.
body
:
if
isinstance
(
tree
,
ast
.
FunctionDef
):
ret
=
proc
(
node
,
scope
)
for
node
in
tree
.
body
:
ret
=
proc
(
node
,
scope
)
else
:
ret
=
proc
(
tree
.
body
,
scope
)
scope
.
pop
()
scope
.
pop
()
return
Lambda
(
args
,
ret
)
return
Lambda
(
args
,
ret
)
def
apply
(
self
,
args
:
List
[
ast
.
expr
])
->
ast
.
expr
:
def
apply
(
self
,
args
:
List
[
ast
.
expr
])
->
ast
.
expr
:
ret
=
copy
.
deepcopy
(
self
.
body
)
ret
=
copy
.
deepcopy
(
self
.
body
)
args
=
{
k
:
v
for
k
,
v
in
zip
(
self
.
args
,
args
)}
return
ArgSubstituter
({
k
:
v
for
k
,
v
in
zip
(
self
.
args
,
args
)}).
visit
(
ret
)
return
ArgSubstituter
(
args
).
visit
(
ret
)
ast_dump
=
lambda
node
,
dump
=
False
:
ast
.
dump
(
node
,
indent
=
2
)
if
dump
else
ast
.
unparse
(
node
)
ast_dump
=
lambda
node
,
dump
=
False
:
ast
.
dump
(
node
,
indent
=
2
)
if
dump
else
ast
.
unparse
(
node
)
def
ir_dump
(
node
,
dump
=
False
):
def
ir_dump
(
node
,
dump
=
False
):
if
node
==
None
:
return
"
None
"
if
isinstance
(
node
,
Lambda
):
if
isinstance
(
node
,
Lambda
):
return
f
"
<Lambda args:
{
node
.
args
}
body:
{
ir_dump
(
node
.
body
,
dump
)
}
>
"
return
f
"
<Lambda args:
{
node
.
args
}
body:
{
ir_dump
(
node
.
body
,
dump
)
}
>
"
if
isinstance
(
node
,
CondVal
):
return
f
"
<CondVal
{
''
.
join
(
f
'
[
{
ir_dump
(
e
.
val
,
dump
)
}
if
{
ir_dump
(
e
.
cond
,
dump
)
}
]
'
for e in node.elems)
}
>
"
if
isinstance
(
node
,
ast
.
If
):
if
isinstance
(
node
,
ast
.
If
):
return
f
"
<{{
{
ast_dump
(
node
,
dump
)
}
}}>
"
return
f
"
<{{
{
ast_dump
(
node
,
dump
)
}
}}>
"
if
isinstance
(
node
,
Reduction
):
if
isinstance
(
node
,
Reduction
):
return
f
"
<Reduction
{
node
.
op
}
(
{
ast_dump
(
node
.
expr
,
dump
)
}
for
{
node
.
it
}
in
{
ast_dump
(
node
.
value
,
dump
)
}
>
"
return
f
"
<Reduction
{
node
.
op
}
{
ast_dump
(
node
.
expr
,
dump
)
}
for
{
node
.
it
}
in
{
ast_dump
(
node
.
value
,
dump
)
}
>
"
# if isinstance(node, If):
# if node.false == None:
# return f"<If test: {node.test} true: {ir_dump(node.true)}>"
# return f"<If test: {node.test} true: {ir_dump(node.true)} false: {ir_dump(node.false)}>"
elif
isinstance
(
node
,
dict
):
elif
isinstance
(
node
,
dict
):
return
"
<Object
"
+
"
"
.
join
(
f
"
{
k
}
:
{
ir_dump
(
v
,
dump
)
}
"
for
k
,
v
in
node
.
items
())
+
"
>
"
return
"
<Object
"
+
"
"
.
join
(
f
"
{
k
}
:
{
ir_dump
(
v
,
dump
)
}
"
for
k
,
v
in
node
.
items
())
+
"
>
"
elif
isinstance
(
node
,
list
):
return
f
"
[
{
'
,
'
.
join
(
ir_dump
(
n
,
dump
)
for
n
in
node
)
}
]
"
else
:
else
:
return
ast_dump
(
node
,
dump
)
return
ast_dump
(
node
,
dump
)
ScopeValue
:
TypeAlias
=
Union
[
ast
.
AST
,
If
,
Lambda
,
Dict
[
str
,
"
ScopeValue
"
]]
# TODO
def
ir_eq
(
a
:
Optional
[
ScopeValue
],
b
:
Optional
[
ScopeValue
])
->
bool
:
return
ir_dump
(
a
)
==
ir_dump
(
b
)
def
sv_eq
(
a
:
Optional
[
ScopeValue
],
b
:
Optional
[
ScopeValue
])
->
bool
:
if
isinstance
(
a
,
ast
.
AST
)
and
isinstance
(
b
,
ast
.
AST
):
return
ir_eq
(
a
,
b
)
return
a
==
b
class
Scope
:
class
Scope
:
scopes
:
List
[
Dict
[
str
,
ScopeValue
]]
scopes
:
List
[
Dict
[
str
,
ScopeValue
]]
def
__init__
(
self
):
def
__init__
(
self
):
...
@@ -115,7 +144,7 @@ class Scope:
...
@@ -115,7 +144,7 @@ class Scope:
class
ArgSubstituter
(
ast
.
NodeTransformer
):
class
ArgSubstituter
(
ast
.
NodeTransformer
):
args
:
Dict
[
str
,
ast
.
expr
]
args
:
Dict
[
str
,
ast
.
expr
]
def
__init__
(
self
,
args
):
def
__init__
(
self
,
args
:
Dict
[
str
,
ast
.
expr
]
):
super
().
__init__
()
super
().
__init__
()
self
.
args
=
args
self
.
args
=
args
...
@@ -125,25 +154,93 @@ class ArgSubstituter(ast.NodeTransformer):
...
@@ -125,25 +154,93 @@ class ArgSubstituter(ast.NodeTransformer):
self
.
generic_visit
(
node
)
self
.
generic_visit
(
node
)
return
node
# XXX needed?
return
node
# XXX needed?
def
merge_if
(
test
,
true
,
false
,
scope
:
Dict
[
str
,
ScopeValue
]):
def
merge_if
(
test
:
ast
.
expr
,
trues
:
Scope
,
falses
:
Scope
,
scope
:
Scope
):
# `true`, `false` and `scope` should have the same level
for
true
,
false
in
zip
(
trues
.
scopes
,
falses
.
scopes
):
merge_if_single
(
test
,
true
,
false
,
scope
)
def
merge_if_single
(
test
,
true
:
Dict
[
str
,
ScopeValue
],
false
:
Dict
[
str
,
ScopeValue
],
scope
:
Union
[
Scope
,
Dict
[
str
,
ScopeValue
]]):
dbg
(
"
merge if single
"
,
ir_dump
(
test
),
true
.
keys
(),
false
.
keys
())
def
lookup
(
s
,
k
):
if
isinstance
(
s
,
Scope
):
return
s
.
lookup
(
k
)
return
s
.
get
(
k
)
def
assign
(
s
,
k
,
v
):
if
isinstance
(
s
,
Scope
):
s
.
set
(
k
,
v
)
else
:
s
[
k
]
=
v
for
var
in
set
(
true
.
keys
()).
union
(
set
(
false
.
keys
())):
for
var
in
set
(
true
.
keys
()).
union
(
set
(
false
.
keys
())):
if
true
.
get
(
var
)
!=
None
and
false
.
get
(
var
)
!=
None
:
var_true
,
var_false
=
true
.
get
(
var
),
false
.
get
(
var
)
assert
isinstance
(
true
.
get
(
var
),
dict
)
==
isinstance
(
false
.
get
(
var
),
dict
)
if
sv_eq
(
var_true
,
var_false
):
if
isinstance
(
true
.
get
(
var
),
dict
):
continue
if
not
isinstance
(
scope
.
get
(
var
),
dict
):
if
var_true
!=
None
and
var_false
!=
None
:
if
var
in
scope
:
assert
isinstance
(
var_true
,
dict
)
==
isinstance
(
var_false
,
dict
)
print
(
"
???
"
,
var
,
scope
[
var
])
dbg
(
"
merge
"
,
var
,
ir_dump
(
test
),
ir_dump
(
var_true
),
ir_dump
(
var_false
))
scope
[
var
]
=
{}
if
isinstance
(
var_true
,
dict
):
merge_if
(
test
,
true
.
get
(
var
,
{}),
false
.
get
(
var
,
{}),
scope
[
var
])
if
not
isinstance
(
lookup
(
scope
,
var
),
dict
):
if
lookup
(
scope
,
var
)
!=
None
:
dbg
(
"
???
"
,
var
,
lookup
(
scope
,
var
))
dbg
(
"
if.merge.obj.init
"
)
assign
(
scope
,
var
,
{})
var_true_emp
,
var_false_emp
,
var_scope
=
true
.
get
(
var
,
{}),
false
.
get
(
var
,
{}),
lookup
(
scope
,
var
)
assert
isinstance
(
var_true_emp
,
dict
)
and
isinstance
(
var_false_emp
,
dict
)
and
isinstance
(
var_scope
,
dict
)
merge_if_single
(
test
,
var_true_emp
,
var_false_emp
,
var_scope
)
else
:
else
:
if
true
.
get
(
var
)
==
None
:
if_val
=
merge_if_val
(
test
,
var_true
,
var_false
,
lookup
(
scope
,
var
))
scope
[
var
]
=
ast
.
If
(
ast
.
UnaryOp
(
ast
.
Not
(),
test
),
[
false
.
get
(
var
)],
[])
print
(
ir_dump
(
if_val
))
elif
false
.
get
(
var
)
==
None
:
assign
(
scope
,
var
,
if_val
)
scope
[
var
]
=
ast
.
If
(
test
,
[
true
.
get
(
var
)],
[])
else
:
def
merge_if_val
(
test
,
true
:
Optional
[
ScopeValue
],
false
:
Optional
[
ScopeValue
],
orig
:
Optional
[
ScopeValue
])
->
CondVal
:
scope
[
var
]
=
ast
.
If
(
test
,
[
true
.
get
(
var
)],
[
false
.
get
(
var
)])
dbg
(
"
merge val
"
,
ir_dump
(
test
),
ir_dump
(
true
),
ir_dump
(
false
),
ir_dump
(
orig
),
false
==
orig
)
def
merge_cond
(
test
,
val
):
if
isinstance
(
val
,
CondVal
):
for
elem
in
val
.
elems
:
elem
.
cond
.
append
(
test
)
return
val
else
:
return
CondVal
([
CondValElem
([
test
],
val
)])
def
as_cv
(
a
):
if
a
==
None
:
return
None
if
not
isinstance
(
a
,
CondVal
):
return
CondVal
([
CondValElem
([],
a
)])
return
a
true
,
false
,
orig
=
as_cv
(
true
),
as_cv
(
false
),
as_cv
(
orig
)
dbg
(
"
merge convert
"
,
ir_dump
(
true
),
ir_dump
(
false
),
ir_dump
(
orig
))
if
orig
!=
None
:
for
orig_cve
in
orig
.
elems
:
if
true
!=
None
and
orig_cve
in
true
.
elems
:
true
.
elems
.
remove
(
orig_cve
)
if
false
!=
None
and
orig_cve
in
false
.
elems
:
false
.
elems
.
remove
(
orig_cve
)
dbg
(
"
merge diff
"
,
ir_dump
(
true
),
ir_dump
(
false
),
ir_dump
(
orig
))
if
true
!=
None
and
len
(
true
.
elems
)
==
0
:
true
=
None
if
false
!=
None
and
len
(
false
.
elems
)
==
0
:
false
=
None
if
true
==
None
and
false
==
None
:
raise
Exception
(
"
no need for merge?
"
)
elif
true
==
None
:
ret
=
merge_cond
(
ast
.
UnaryOp
(
ast
.
Not
(),
test
),
false
)
elif
false
==
None
:
ret
=
merge_cond
(
test
,
true
)
elif
sv_eq
(
false
,
orig
):
if
isinstance
(
orig
,
CondVal
):
ret
=
CondVal
(
merge_cond
(
test
,
true
).
elems
+
orig
.
elems
)
else
:
assert
orig
!=
None
ret
=
CondVal
(
merge_cond
(
test
,
true
).
elems
+
[
CondValElem
([],
orig
)])
else
:
merge_true
,
merge_false
=
merge_cond
(
test
,
true
),
merge_cond
(
ast
.
UnaryOp
(
ast
.
Not
(),
test
),
false
)
ret
=
CondVal
(
merge_true
.
elems
+
merge_false
.
elems
)
if
orig
!=
None
:
return
CondVal
(
ret
.
elems
+
orig
.
elems
)
return
ret
def
proc_assign
(
target
:
ast
.
AST
,
val
,
scope
:
Scope
):
def
proc_assign
(
target
:
ast
.
AST
,
val
,
scope
:
Scope
):
dbg
(
"
proc_assign
"
,
ast
.
unparse
(
target
),
val
)
if
isinstance
(
target
,
ast
.
Name
):
if
isinstance
(
target
,
ast
.
Name
):
if
isinstance
(
val
,
ast
.
AST
):
if
isinstance
(
val
,
ast
.
AST
):
scope
.
set
(
target
.
id
,
proc
(
val
,
scope
))
scope
.
set
(
target
.
id
,
proc
(
val
,
scope
))
...
@@ -151,6 +248,7 @@ def proc_assign(target: ast.AST, val, scope: Scope):
...
@@ -151,6 +248,7 @@ def proc_assign(target: ast.AST, val, scope: Scope):
scope
.
set
(
target
.
id
,
val
)
scope
.
set
(
target
.
id
,
val
)
elif
isinstance
(
target
,
ast
.
Attribute
):
elif
isinstance
(
target
,
ast
.
Attribute
):
if
proc
(
target
.
value
,
scope
)
==
None
:
if
proc
(
target
.
value
,
scope
)
==
None
:
dbg
(
"
proc.assign.obj.init
"
)
proc_assign
(
target
.
value
,
{},
scope
)
proc_assign
(
target
.
value
,
{},
scope
)
obj
=
proc
(
target
.
value
,
scope
)
obj
=
proc
(
target
.
value
,
scope
)
obj
[
target
.
attr
]
=
val
obj
[
target
.
attr
]
=
val
...
@@ -169,16 +267,21 @@ def proc(node: ast.AST, scope: Scope) -> Any:
...
@@ -169,16 +267,21 @@ def proc(node: ast.AST, scope: Scope) -> Any:
elif
isinstance
(
node
,
ast
.
If
):
elif
isinstance
(
node
,
ast
.
If
):
test
=
proc
(
node
.
test
,
scope
)
test
=
proc
(
node
.
test
,
scope
)
true_scope
=
copy
.
deepcopy
(
scope
)
true_scope
=
copy
.
deepcopy
(
scope
)
true_scope
.
push
()
for
true
in
node
.
body
:
for
true
in
node
.
body
:
dbg
(
"
true
"
,
true
)
proc
(
true
,
true_scope
)
proc
(
true
,
true_scope
)
false_scope
=
copy
.
deepcopy
(
scope
)
false_scope
=
copy
.
deepcopy
(
scope
)
false_scope
.
push
()
for
false
in
node
.
orelse
:
for
false
in
node
.
orelse
:
proc
(
false
,
false_scope
)
proc
(
false
,
false_scope
)
merge_if
(
test
,
true_scope
.
scopes
[
0
]
,
false_scope
.
scopes
[
0
],
scope
.
scopes
[
0
]
)
merge_if
(
test
,
true_scope
,
false_scope
,
scope
)
# Definition/Assignment
# Definition/Assignment
elif
isinstance
(
node
,
ast
.
Import
)
or
isinstance
(
node
,
ast
.
ImportFrom
):
for
alias
in
node
.
names
:
if
alias
.
asname
==
None
:
scope
.
set
(
alias
.
name
,
ast
.
arg
(
alias
.
name
))
else
:
scope
.
set
(
alias
.
asname
,
ast
.
arg
(
alias
.
asname
))
elif
isinstance
(
node
,
ast
.
Assign
):
elif
isinstance
(
node
,
ast
.
Assign
):
if
len
(
node
.
targets
)
==
1
:
if
len
(
node
.
targets
)
==
1
:
proc_assign
(
node
.
targets
[
0
],
node
.
value
,
scope
)
proc_assign
(
node
.
targets
[
0
],
node
.
value
,
scope
)
...
@@ -196,7 +299,7 @@ def proc(node: ast.AST, scope: Scope) -> Any:
...
@@ -196,7 +299,7 @@ def proc(node: ast.AST, scope: Scope) -> Any:
elif
isinstance
(
node
,
ast
.
Lambda
):
elif
isinstance
(
node
,
ast
.
Lambda
):
return
Lambda
.
from_ast
(
node
,
scope
)
return
Lambda
.
from_ast
(
node
,
scope
)
elif
isinstance
(
node
,
ast
.
ClassDef
):
elif
isinstance
(
node
,
ast
.
ClassDef
):
pass
scope
.
set
(
node
.
name
,
ast
.
arg
(
node
.
name
))
# Expressions
# Expressions
elif
isinstance
(
node
,
ast
.
UnaryOp
):
elif
isinstance
(
node
,
ast
.
UnaryOp
):
...
@@ -243,8 +346,6 @@ def proc(node: ast.AST, scope: Scope) -> Any:
...
@@ -243,8 +346,6 @@ def proc(node: ast.AST, scope: Scope) -> Any:
scope
.
pop
()
scope
.
pop
()
expr
=
cond_trans
(
expr
,
ast
.
BoolOp
(
ast
.
And
(),
ifs
))
expr
=
cond_trans
(
expr
,
ast
.
BoolOp
(
ast
.
And
(),
ifs
))
return
Reduction
(
op
,
expr
,
target
.
id
,
proc
(
iter
,
scope
))
return
Reduction
(
op
,
expr
,
target
.
id
,
proc
(
iter
,
scope
))
print
(
ast
.
dump
(
node
))
print
(
proc
(
node
.
func
.
value
,
scope
))
elif
isinstance
(
node
,
ast
.
Return
):
elif
isinstance
(
node
,
ast
.
Return
):
return
proc
(
node
.
value
,
scope
)
if
node
.
value
!=
None
else
None
return
proc
(
node
.
value
,
scope
)
if
node
.
value
!=
None
else
None
elif
isinstance
(
node
,
ast
.
IfExp
):
elif
isinstance
(
node
,
ast
.
IfExp
):
...
@@ -266,8 +367,8 @@ def parse(fn: str):
...
@@ -266,8 +367,8 @@ def parse(fn: str):
root
=
ast
.
parse
(
cont
,
fn
)
root
=
ast
.
parse
(
cont
,
fn
)
scope
=
Scope
()
scope
=
Scope
()
proc
(
root
,
scope
)
proc
(
root
,
scope
)
scope
.
dump
(
True
)
scope
.
dump
()
print
(
ir_dump
(
scope
.
lookup
(
"
controller
"
).
body
[
"
mode
"
].
test
))
#
print(ir_dump(scope.lookup("controller").body["mode"].test))
if
__name__
==
"
__main__
"
:
if
__name__
==
"
__main__
"
:
import
sys
import
sys
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment