##
## Filename : SysExpr.py
## Author(s) : Michel Le Borgne
## Created : 11-12/2008
## Revision :
## Source :
##
## Copyright 2008 - 2009 - 2020 IRISA/IRSET
##
## This library is free software; you can redistribute it and/or modify it
## under the terms of the GNU General Public License as published
## by the Free Software Foundation; either version 2.1 of the License, or
## any later version.
##
## This library is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF
## MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. The software and
## documentation provided here under is on an "as is" basis, and IRISA has
## no obligations to provide maintenance, support, updates, enhancements
## or modifications.
## In no event shall IRISA be liable to any party for direct, indirect,
## special, incidental or consequential damages, including lost profits,
## arising out of the use of this software and its documentation, even if
## IRISA have been advised of the possibility of such damage. See
## the GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this library; if not, write to the Free Software Foundation,
## Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
##
## The original code contained here was initially developed by:
##
## Michel Le Borgne.
## IRISA/IRISA
## Symbiose team
## IRISA Campus de Beaulieu
## 35042 RENNES Cedex, FRANCE
##
##
## Contributor(s): Geoffroy Andrieux
##
"""
Standard representation of biosignal expressions as trees.
In addition to standard logical operator, we introduce the default
and when operators.
"""
[docs]class SigExpression(object):
"""
Generic abstract class
"""
def __init__(self):
pass
def __str__(self):
pass
def __repr__(self):
"""Fallback when repr function is not available"""
return str(self)
[docs] def get_signals(self):
"""
Gives the set of idents used in the expression
"""
return set()
[docs] def get_ultimate_signals(self, mcsystem):
"""
Gives the set of signals used in the expression
"""
return set()
[docs] def is_clock(self, symb_table, method=None):
"""
Check if an expression always give a clock
"""
return False
[docs] def is_ident(self):
"""
As it says
"""
return False
[docs] def is_bot(self):
"""
As it says
"""
return False
[docs] def is_const(self):
"""
As it says
"""
return False
[docs] def is_const_false(self):
"""
As it says
"""
return False
[docs] def accept(self, visitor):
"""
Method for all kind of visitors - raise exception if not implemented
"""
raise NotImplementedError(self.__class__.__name__ + ": Not implemented")
def __eq__(self, model):
"""
test if the expression tree is equal to model tree (for TESTS)
"""
raise NotImplementedError(self.__class__.__name__ + ": Not implemented")
def __ne__(self, model):
"""
test if the expression tree is not equal to model tree (for TESTS)
"""
raise NotImplementedError(self.__class__.__name__ + ": Not implemented")
[docs]class SigIdentExpr(SigExpression):
"""
Ident expressions are represented by their name. So we need a symbol
table for type checking
"""
def __init__(self, name):
"""
@param name: the identifier
"""
self.name = name
def __repr__(self):
return "<SigIdentExpr %s>" % self.name
def __str__(self):
return self.name
[docs] def is_ident(self):
return True
[docs] def get_signals(self):
return set([self.name])
[docs] def get_ultimate_signals(self, mcsystem):
try:
scg = mcsystem.symbol_table[self.name]
except: # undefined component considered as ultimate
return set([self.name])
if scg.is_state():
return set([self.name])
elif scg.is_signal():
sce = scg.expression
if not sce: # undefined signal
return set([self.name])
else:
return sce.get_ultimate_signals(mcsystem)
else: # ???
return set([self.name])
[docs] def is_clock(self, symb_table, method=None):
try:
scg = symb_table[self.name]
if not method:
return scg.is_clock()
else:
return method(scg)
except KeyError:
return False
[docs] def accept(self, visitor):
return visitor.visit_sig_ident(self)
def __eq__(self, item):
return isinstance(item, SigIdentExpr) and self.name == item.name
def __ne__(self, item):
return not self == item
def __hash__(self):
return hash(self.name)
[docs]class SigConstExpr(SigExpression):
"""
Constant signals: True, False
"""
def __init__(self, val):
"""
@param val: boll - the value
"""
self.value = val # boolean
def __repr__(self):
return "<SigConstExpr %s>" % self.value
def __str__(self):
return str(self.value)
[docs] def get_signals(self):
return set()
[docs] def is_clock(self, symb_table, method=None):
"""
Tick and true are considered as similar
"""
return self.value
[docs] def is_const(self):
return True
[docs] def is_const_false(self):
return not self.value
[docs] def accept(self, visitor):
return visitor.visit_sig_const(self)
def __eq__(self, item):
return isinstance(item, SigConstExpr) and self.value == item.value
def __ne__(self, item):
return not self == item
def __hash__(self):
return hash(self.value)
[docs]class SigBotExpr(SigExpression):
"""
Usefull signal for initialisations - should not appear in normal signal expressions
"""
def __init__(self):
pass
def __str__(self):
return "%b"
[docs] def get_signals(self):
return set()
[docs] def is_bot(self):
return True
[docs] def accept(self, visitor):
return visitor.visit_sig_bot(self)
def __eq__(self, item):
return isinstance(item, SigBotExpr)
def __ne__(self, item):
return not self == item
[docs]class SigBinExpr(SigExpression):
"""
Binary expression - abstract class
"""
def __init__(self, exp1, exp2):
"""
@param exp1,exp2: SigExpression - the two operands
"""
self.left_h = exp1
self.right_h = exp2
def __str__(self):
pass
[docs] def get_signals(self):
sig1 = self.left_h.get_signals()
sig2 = self.right_h.get_signals()
sig1.update(sig2) # union of sets
return sig1
[docs] def get_ultimate_signals(self, mcsys):
sig1 = self.left_h.get_ultimate_signals(mcsys)
sig2 = self.right_h.get_ultimate_signals(mcsys)
return sig1 | sig2 # union of sets
[docs]class SigDefaultExpr(SigBinExpr):
"""
Implements the default operator
"""
def __str__(self):
if self.left_h.is_bot():
return str(self.right_h)
elif self.right_h.is_bot():
return str(self.left_h)
else:
return "(" + str(self.left_h) + " default " + str(self.right_h) + ")"
[docs] def is_clock(self, symb_table, method=None):
cond = self.left_h.is_clock(symb_table, method)
cond = cond and self.right_h.is_clock(symb_table, method)
return cond
[docs] def accept(self, visitor):
return visitor.visit_sig_default(self)
def __eq__(self, item):
return (
isinstance(item, SigDefaultExpr)
and self.left_h == item.left_h
and self.right_h == item.right_h
)
def __ne__(self, item):
return not self == item
def __hash__(self):
return hash(self.left_h) ^ hash(self.right_h)
[docs]class SigWhenExpr(SigBinExpr):
"""
Implements when expression
"""
def __str__(self):
return "(" + str(self.left_h) + " when " + str(self.right_h) + ")"
[docs] def is_clock(self, symb_table, method=None):
return self.left_h.is_clock(symb_table, method)
[docs] def accept(self, visitor):
return visitor.visit_sig_when(self)
def __eq__(self, item):
return (
isinstance(item, SigWhenExpr)
and self.left_h == item.left_h
and self.right_h == item.right_h
)
def __ne__(self, item):
return not self == item
def __hash__(self):
return hash(self.left_h) ^ hash(self.right_h)
[docs]class SigEqualExpr(SigBinExpr):
"""
Implement the equality test: sig1 == sig2 when both present
"""
def __str__(self):
return "(" + str(self.left_h) + " == " + str(self.right_h) + ")"
[docs] def is_clock(self, symb_table, method=None):
cond = self.left_h.is_clock(symb_table, method)
cond = cond and self.right_h.is_clock(symb_table, method)
return cond
[docs] def accept(self, visitor):
return visitor.visit_sig_equal(self)
def __eq__(self, item):
return (
isinstance(item, SigEqualExpr)
and self.left_h == item.left_h
and self.right_h == item.right_h
)
def __ne__(self, item):
return not self == item
def __hash__(self):
return hash(self.left_h) ^ hash(self.right_h)
[docs]class SigDiffExpr(SigBinExpr):
"""
Implement the different test: sig1 != sig2 when both present
"""
def __str__(self):
return "(" + str(self.left_h) + " != " + str(self.right_h) + ")"
[docs] def is_clock(self, symb_table, method=None):
return False
[docs] def accept(self, visitor):
return visitor.visit_sig_diff(self)
def __eq__(self, item):
return (
isinstance(item, SigDiffExpr)
and self.left_h == item.left_h
and self.right_h == item.right_h
)
def __ne__(self, item):
return not self == item
def __hash__(self):
return hash(self.left_h) ^ hash(self.right_h)
[docs]class SigNotExpr(SigExpression):
"""
Boolean not on a signal
"""
def __init__(self, exp):
self.operand = exp
def __repr__(self):
return "<SigNotExpr (not %s)>" % repr(self.operand)
def __str__(self):
return "( not " + str(self.operand) + ")"
[docs] def get_signals(self):
return self.operand.get_signals()
[docs] def get_ultimate_signals(self, mcsys):
return self.operand.get_ultimate_signals(mcsys)
[docs] def is_clock(self, symb_table, method=None):
return False
[docs] def accept(self, visitor):
return visitor.visit_sig_not(self)
def __eq__(self, item):
return (
isinstance(item, SigNotExpr)
and self.operand == item.operand
)
def __ne__(self, item):
return not self == item
def __hash__(self):
return hash(self.operand)
[docs]class SigEventExpr(SigExpression):
"""
Event operand creates a clock
"""
def __init__(self, exp):
self.operand = exp
def __str__(self):
return "event(" + str(self.operand) + ")"
[docs] def get_signals(self):
return self.operand.get_signals()
[docs] def get_ultimate_signals(self, mcsys):
return self.operand.get_ultimate_signals(mcsys)
[docs] def is_clock(self, symb_table, method=None):
return True
[docs] def accept(self, visitor):
return visitor.visit_sig_event(self)
def __eq__(self, item):
return (
isinstance(item, SigEventExpr)
and self.operand == item.operand
)
def __ne__(self, item):
return not self == item
def __hash__(self):
return hash(self.operand)
[docs]class SigSyncBinExpr(SigBinExpr):
"""
Generic class for boolean operation on signals
A boolean operator emits a signal when both operand are present
"""
def __init__(self, operator, exp1, exp2):
self.left_h = exp1
self.right_h = exp2
self.operator = operator
def __repr__(self):
return "<SigSyncBinExpr (%s %s %s)>" % (
repr(self.left_h),
self.operator,
repr(self.right_h),
)
def __str__(self):
lhs = str(self.left_h)
rhs = str(self.right_h)
return "(" + lhs + " " + self.operator + " " + rhs + ")"
[docs] def is_clock(self, symb_table, method=None):
"""
Clocks are assimilated to boolean signals with true value
And and or give true in this case, so its a clock!!
"""
cond = self.left_h.is_clock(symb_table, method)
cond = cond and self.right_h.is_clock(symb_table, method)
return cond
[docs] def accept(self, visitor):
return visitor.visit_sig_sync(self)
def __eq__(self, item):
return (
isinstance(item, SigSyncBinExpr)
and self.left_h == item.left_h
and self.right_h == item.right_h
and self.operator == item.operator
)
def __ne__(self, item):
return not self == item
def __hash__(self):
return hash(self.left_h) ^ hash(self.right_h) ^ hash(self.operator)
# class SigPolyBinExpr(SigBinExpr):
# def __init__(self, op, exp1, exp2):
# self.left_h = exp1
# self.right_h = exp2
# self.operator = op
#
# def __str__(self):
# lhs = str(self.left_h)
# rhs = str(self.right_h)
# return '('+ lhs +' '+self.operator+' '+rhs+')'
#
# def is_clock(self, ts, method=None):
# """
# Clocks are assimilated to boolean signals with true value
# In general a polynomial expression doesn't deliver a clock
# """
# return False
#
# def accept(self, visitor):
# return visitor.visitSigPolyBinExpr(self)
#
# def test_equal(self, model):
# if not isinstance(model, SigPolyBinExpr):
# return False
# else:
# cond = self.operator==model.operator
# cond = cond and (self.left_h.test_equal(model.left_h)
# cond = cond and (self.right_h.test_equal()))
# return cond
#
# class SigPolyPowExpr(SigExpression):
# def __init__(self, exp, pow):
# self.operand = exp
# self.power = pow%3
#
# def __str__(self):
# op=str(self.operand)
# return '('+ op +'^'+"%d"%(self.power)+')'
#
# def get_signals(self):
# return self.operand.get_signals()
#
# def get_ultimate_signals(self, mcsys):
# return self.operand.get_ultimate_signals(mcsys)
#
# def is_clock(self, ts, method=None):
# if self.power == 2:
# return True
# else:
# return False
#
# def test_equal(self, model):
# if not isinstance(model, SigPolyPowExpr):
# return False
# else:
# cond = self.power==model.power
# cond = cond and (self.operand.test_equal(model.operand))
# return cond
#
# def accept(self, visitor):
# return visitor.visitSigPowExpr(self)
[docs]class SigConstraintExpr(SigExpression):
"""
Implements constraints on events
"""
SYNCHRO = "synchro"
EXCLU = "exclus"
INCL = "included"
def __init__(self, name, explist=[]):
self.constraint_name = name
self.arg = explist
[docs] def add_arg(self, arg):
"""
Constraints are n-ary operators - this method add an operand
"""
self.arg.append(arg)
def __str__(self):
str_out = self.constraint_name + "("
if len(self.arg) > 0:
str_out = str_out + str(self.arg[0])
for arg in self.arg[1:]:
str_out = str_out + ", " + str(arg)
str_out = str_out + ")"
return str_out
[docs] def accept(self, visitor):
return visitor.visit_sig_constraint(self)