Toggle navigation
Toggle navigation
This project
Loading...
Sign in
Franck Pommereau
/
snakes
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Builds
Commits
Authored by
Franck Pommereau
2013-10-23 10:30:29 +0200
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
b32249730371cf9af9ab340034a75cf643c3fef0
b3224973
1 parent
6cc97aa1
moved let to a plugin with extended capabilities
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
99 additions
and
37 deletions
snakes/nets.py
snakes/plugins/let.py
snakes/nets.py
View file @
b322497
...
...
@@ -1040,43 +1040,6 @@ class Expression (ArcAnnotation) :
def
__hash__
(
self
)
:
return
hash
(
self
.
_str
.
strip
())
def
let
(
**
args
)
:
"""A dirty trick to allow side effects in expressions
Assignement takes place when method `bind` of the expression is
called. Assigned variables are then stored in the `Substitution`
passed to `bind`. This is useful in some cases when you want to
repeat a computation in several output arcs: you do it once in the
guard and then use the bounded variable on the output arcs.
>>> n = PetriNet('n')
>>> n.globals['let'] = let
>>> t = Transition('t', Expression('x is not None and let(foo=42)'))
>>> n.add_transition(t)
>>> n.add_place(Place('p', [dot]))
>>> n.add_input('p', 't', Variable('x'))
>>> t.modes() == [Substitution(x=dot, foo=42)]
True
Note in the example above that `let` is not known by default, you
have to import it explicitly in the global environment of your
`PetriNet` (line 2). This is intended so it is clear that you
known what you do.
@param args: a list of `name=value` to assign
@return: `True` if assignment could be made, `False` otherwise
@rtype: `bool`
@warning: use with care, sides effects are nasty tricks, you may
get unexpected results while playing with `let`
"""
try
:
__binding__
=
inspect
.
stack
()[
1
][
0
]
.
f_locals
[
"__binding__"
]
for
name
,
value
in
args
.
items
()
:
__binding__
[
name
]
=
value
except
:
return
False
return
True
class
MultiArc
(
ArcAnnotation
)
:
"""A collection of other annotations, allowing to consume or produce
several tokens at once.
...
...
snakes/plugins/let.py
0 → 100644
View file @
b322497
"""A dirty trick to allow side effects in expressions
Assignement takes place when method `bind` of the expression is
called. Assigned variables are then stored in the `Substitution`
passed to `bind`. This is useful in some cases when you want to
repeat a computation in several output arcs: you do it once in the
guard and then use the bounded variable on the output arcs.
>>> import snakes.plugins
>>> snakes.plugins.load('let', 'snakes.nets', 'snk')
<module ...>
>>> from snk import *
>>> n = PetriNet('n')
>>> t = Transition('t', Expression('x is not None and let("egg, spam = iter(str(foo))", foo=42, __raise__=True)'))
>>> n.add_transition(t)
>>> n.add_place(Place('p', [dot]))
>>> n.add_input('p', 't', Variable('x'))
>>> t.modes() == [Substitution(x=dot, foo=42, egg='4', spam='2')]
True
@param args: a list of `name=value` to assign
@return: `True` if assignment could be made, `False` otherwise
@rtype: `bool`
@warning: use with care, sides effects are nasty tricks, you may
get unexpected results while playing with `let`
"""
import
inspect
import
snakes.plugins
from
snakes.lang.python.parser
import
ast
,
parse
from
snakes.lang
import
unparse
class
DropLet
(
ast
.
NodeTransformer
)
:
def
__init__
(
self
,
names
)
:
ast
.
NodeTransformer
.
__init__
(
self
)
self
.
names
=
set
(
names
)
self
.
calls
=
[]
def
visit_Call
(
self
,
node
)
:
func
=
node
.
func
if
func
.
__class__
.
__name__
==
"Name"
and
func
.
id
in
self
.
names
:
self
.
calls
.
append
((
func
.
id
,
node
.
args
and
node
.
args
[
0
]
.
s
or
None
,
[(
k
.
arg
,
unparse
(
k
.
value
))
for
k
in
node
.
keywords
]))
return
ast
.
Name
(
id
=
"True"
)
return
node
class
DropTrue
(
ast
.
NodeTransformer
)
:
def
visit_BoolOp
(
self
,
node
)
:
if
node
.
op
.
__class__
.
__name__
==
"And"
:
values
=
[
self
.
visit
(
v
)
for
v
in
node
.
values
if
v
.
__class__
.
__name__
!=
"Name"
or
v
.
id
!=
"True"
]
if
values
:
node
.
values
[:]
=
values
return
node
else
:
return
ast
.
Name
(
id
=
"True"
)
else
:
return
self
.
visit
(
node
)
def
unlet
(
expr
,
*
names
)
:
if
not
names
:
names
=
[
"let"
]
drop
=
DropLet
(
names
)
new
=
DropTrue
()
.
visit
(
drop
.
visit
(
parse
(
expr
)))
return
unparse
(
new
),
drop
.
calls
class
MakeLet
(
object
)
:
def
__init__
(
self
,
globals
)
:
self
.
globals
=
globals
def
match
(
self
,
match
,
binding
)
:
env
=
binding
.
dict
()
env
.
update
(
iter
(
self
.
globals
))
exec
(
""
,
env
)
old
=
set
(
env
)
exec
(
match
,
env
)
for
name
in
set
(
env
)
-
old
:
binding
[
name
]
=
env
[
name
]
def
__call__
(
self
,
__match__
=
None
,
__raise__
=
False
,
**
args
)
:
try
:
__binding__
=
inspect
.
stack
()[
1
][
0
]
.
f_locals
[
"__binding__"
]
for
name
,
value
in
args
.
items
()
:
__binding__
[
name
]
=
value
if
__match__
:
self
.
match
(
__match__
,
__binding__
)
except
:
if
__raise__
:
raise
return
False
return
True
@snakes.plugins.plugin
(
"snakes.nets"
)
def
extend
(
module
)
:
class
PetriNet
(
module
.
PetriNet
)
:
def
__init__
(
self
,
name
,
**
args
)
:
module
.
PetriNet
.
__init__
(
self
,
name
,
**
args
)
self
.
globals
[
"let"
]
=
MakeLet
(
self
.
globals
)
return
PetriNet
,
unlet
Please
register
or
login
to post a comment