add SCL python files

This commit is contained in:
jriegel 2014-01-05 19:35:07 +01:00
parent 3648912e24
commit e17090fadd
18 changed files with 127807 additions and 1 deletions

View File

@ -31,9 +31,39 @@ SET(Import_SRCS
PreCompiled.h
)
SET(SCL_Resources
SCL/__init__.py
SCL/AggregationDataTypes.py
SCL/BaseType.py
SCL/Builtin.py
SCL/ConstructedDataTypes.py
SCL/essa_par.py
SCL/Model.py
SCL/Part21.py
SCL/Rules.py
SCL/SCLBase.py
SCL/SimpleDataTypes.py
SCL/TypeChecker.py
SCL/Utils.py
automotive_design.py # AP214e3
ifc2x3.py # IFC
ifc4.py # IFC 4
)
SOURCE_GROUP("SCL" FILES ${SCL_Resources})
add_library(Import SHARED ${Import_SRCS})
target_link_libraries(Import ${Import_LIBS})
ADD_CUSTOM_TARGET(ImportPy ALL
SOURCES ${SCL_Resources}
)
fc_target_copy_resource(ImportPy
${CMAKE_SOURCE_DIR}/src/Mod/Import/App
${CMAKE_BINARY_DIR}/Mod/Import
${SCL_Resources})
if(MSVC)
set_target_properties(Import PROPERTIES SUFFIX ".pyd")
set_target_properties(Import PROPERTIES DEBUG_OUTPUT_NAME "Import_d")

View File

@ -0,0 +1,602 @@
# Copyright (c) 2011, Thomas Paviot (tpaviot@gmail.com)
# All rights reserved.
# This file is part of the StepClassLibrary (SCL).
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# Neither the name of the <ORGANIZATION> nor the names of its contributors may
# be used to endorse or promote products derived from this software without
# specific prior written permission.
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from SimpleDataTypes import *
from TypeChecker import check_type
import BaseType
class BaseAggregate(object):
""" A class that define common properties to ARRAY, LIST, SET and BAG.
"""
def __init__( self , bound1 , bound2 , base_type ):
# check that bound1<bound2
if (bound1!=None and bound2!=None):
if bound1>bound2:
raise AssertionError("bound1 shall be less than or equal to bound2")
self._bound1 = bound1
self._bound2 = bound2
self._base_type = base_type
def __getitem__(self, index):
if index<self._bound1:
raise IndexError("ARRAY index out of bound (lower bound is %i, passed %i)"%(self._bound1,index))
elif(self._bound2!=None and index>self._bound2):
raise IndexError("ARRAY index out of bound (upper bound is %i, passed %i)"%(self._bound2,index))
else:
return list.__getitem__(self,index)
def __setitem__(self,index,value):
if index<self._bound1:
raise IndexError("ARRAY index out of bound (lower bound is %i, passed %i)"%(self._bound1,index))
elif (self._bound2!=None and index>self._bound2):
raise IndexError("ARRAY index out of bound (upper bound is %i, passed %i)"%(self._bound2,index))
elif not isinstance(value,self._base_type):
raise TypeError("%s type expected, passed %s."%(self._base_type, type(value)))
else:
# first find the length of the list, and extend it if ever
# the index is
list.__setitem__(self,index,value)
class ARRAY(BaseType.Type, BaseType.Aggregate):
"""
EXPRESS definition:
==================
An array data type has as its domain indexed, fixed-size collections of like elements. The lower
and upper bounds, which are integer-valued expressions, define the range of index values, and
thus the size of each array collection.
An array data type definition may optionally specify
that an array value cannot contain duplicate elements.
It may also specify that an array value
need not contain an element at every index position.
Given that m is the lower bound and n is the upper bound, there are exactly n-m+1 elements
in the array. These elements are indexed by subscripts from m to n, inclusive (see 12.6.1).
NOTE 1 { The bounds may be positive, negative or zero, but may not be indeterminate (?) (see
14.2).
Syntax:
165 array_type = ARRAY bound_spec OF [ OPTIONAL ] [ UNIQUE ] base_type .
176 bound_spec = '[' bound_1 ':' bound_2 ']' .
174 bound_1 = numeric_expression .
175 bound_2 = numeric_expression .
171 base_type = aggregation_types | simple_types | named_types .
Given that m is the lower bound and n is the upper bound, there are exactly n-m+1 elements
in the array. These elements are indexed by subscripts from m to n, inclusive (see 12.6.1).
NOTE 1 { The bounds may be positive, negative or zero, but may not be indeterminate (?) (see
14.2).
Rules and restrictions:
a) Both expressions in the bound speci cation, bound_1 and bound_2, shall evaluate to
integer values. Neither shall evaluate to the indeterminate (?) value.
b) bound_1 gives the lower bound of the array. This shall be the lowest index which is
valid for an array value of this data type.
c) bound_2 gives the upper bound of the array. This shall be the highest index which is
valid for an array value of this data type.
d) bound_1 shall be less than or equal to bound_2.
e) If the optional keyword is speci ed, an array value of this data type may have the
indeterminate (?) value at one or more index positions.
f) If the optional keyword is not speci ed, an array value of this data type shall not
contain an indeterminate (?) value at any index position.
g) If the unique keyword is speci ed, each element in an array value of this data type
shall be di erent from (i.e., not instance equal to) every other element in the same array
value.
NOTE 2 : Both optional and unique may be speci ed in the same array data type definition.
This does not preclude multiple indeterminate (?) values from occurring in a single array value.
This is because comparisons between indeterminate (?) values result in unknown so the uniqueness
constraint is not violated.
EXAMPLE 27 : This example shows how a multi-dimensioned array is declared.
sectors : ARRAY [ 1 : 10 ] OF -- first dimension
ARRAY [ 11 : 14 ] OF -- second dimension
UNIQUE something;
The first array has 10 elements of data type ARRAY[11:14] OF UNIQUE something. There is
a total of 40 elements of data type something in the attribute named sectors. Within each
ARRAY[11:14], no duplicates may occur; however, the same something instance may occur in two
different ARRAY[11:14] values within a single value for the attribute named sectors.
Python definition:
==================
@TODO
"""
def __init__( self , bound_1 , bound_2 , base_type , UNIQUE = False, OPTIONAL=False, scope = None):
BaseType.Type.__init__(self, base_type, scope)
if not type(bound_1)==int:
raise TypeError("ARRAY lower bound must be an integer")
if not type(bound_2)==int:
raise TypeError("ARRAY upper bound must be an integer")
if not (bound_1 <= bound_2):
raise AssertionError("ARRAY lower bound must be less than or equal to upper bound")
# set up class attributes
self._bound_1 = bound_1
self._bound_2 = bound_2
self._unique = UNIQUE
self._optional = OPTIONAL
# preallocate list elements
list_size = bound_2 - bound_1 + 1
self._container = list_size*[None]
def bound_1(self):
return self._bound_1
def bound_2(self):
return self._bound_2
def get_hiindex(self):
return INTEGER(self._bound_2)
def get_loindex(self):
return INTEGER(self._bound_1)
def get_hibound(self):
return INTEGER(self._bound_2)
def get_lobound(self):
return INTEGER(self._bound_1)
def get_size(self):
return INTEGER(self._bound_2 - self._bound_1 +1)
def get_value_unique(self):
''' Return True if all items are different in the container, UNKNOWN if some items are
indeterminate, or False otherwise'''
if None in self._container:
return Unknown
if self.get_size()-len(set(self._container))>0: #some items are repeated
return False
else:
return True
def __getitem__(self, index):
if index<self._bound_1:
raise IndexError("ARRAY index out of bound (lower bound is %i, passed %i)"%(self._bound_1,index))
elif(index>self._bound_2):
raise IndexError("ARRAY index out of bound (upper bound is %i, passed %i)"%(self._bound_2,index))
else:
value = self._container[index-self._bound_1]
if not self._optional and value==None:
raise AssertionError("Not OPTIONAL prevent the value with index %i from being None (default). Please set the value first."%index)
return value
def __setitem__(self, index, value):
if index<self._bound_1:
raise IndexError("ARRAY index out of bound (lower bound is %i, passed %i)"%(self._bound_1,index))
elif(index>self._bound_2):
raise IndexError("ARRAY index out of bound (upper bound is %i, passed %i)"%(self._bound_2,index))
else:
# first check the type of the value
check_type(value,self.get_type())
# then check if the value is already in the array
if self._unique:
if value in self._container:
raise AssertionError("UNIQUE keyword prevents inserting this instance.")
self._container[index-self._bound_1] = value
class LIST(BaseType.Type, BaseType.Aggregate):
"""
EXPRESS definition:
==================
A list data type has as its domain sequences of like elements. The optional lower and upper
bounds, which are integer-valued expressions, define the minimum and maximum number of
elements that can be held in the collection defined by a list data type.
A list data type
definition may optionally specify that a list value cannot contain duplicate elements.
Syntax:
237 list_type = LIST [ bound_spec ] OF [ UNIQUE ] base_type .
176 bound_spec = '[' bound_1 ':' bound_2 ']' .
174 bound_1 = numeric_expression .
175 bound_2 = numeric_expression .
171 base_type = aggregation_types | simple_types | named_types .
Rules and restrictions:
a) The bound_1 expression shall evaluate to an integer value greater than or equal to
zero. It gives the lower bound, which is the minimum number of elements that can be in a
list value of this data type. bound_1 shall not produce the indeterminate (?) value.
b) The bound_2 expression shall evaluate to an integer value greater than or equal to
bound_1, or an indeterminate (?) value. It gives the upper bound, which is the maximum
number of elements that can be in a list value of this data type.
If this value is indeterminate (?) the number of elements in a list value of this data type is
not bounded from above.
c) If the bound_spec is omitted, the limits are [0:?].
d) If the unique keyword is speci ed, each element in a list value of this data type shall
be di erent from (i.e., not instance equal to) every other element in the same list value.
EXAMPLE 28 { This example de nes a list of arrays. The list can contain zero to ten arrays. Each
array of ten integers shall be di erent from all other arrays in a particular list.
complex_list : LIST[0:10] OF UNIQUE ARRAY[1:10] OF INTEGER;
Python definition:
==================
@TODO
"""
def __init__( self , bound_1 , bound_2 , base_type , UNIQUE = False, scope = None):
BaseType.Type.__init__(self, base_type, scope)
if not type(bound_1)==int:
raise TypeError("LIST lower bound must be an integer")
# bound_2 can be set to None
self._unbounded = False
if bound_2 == None:
self._unbounded = True
elif not type(bound_2)==int:
raise TypeError("LIST upper bound must be an integer")
if not bound_1>=0:
raise AssertionError("LIST lower bound must be greater of equal to 0")
if (type(bound_2)==int and not (bound_1 <= bound_2)):
raise AssertionError("ARRAY lower bound must be less than or equal to upper bound")
# set up class attributes
self._bound_1 = bound_1
self._bound_2 = bound_2
self._unique = UNIQUE
# preallocate list elements if bounds are both integers
if not self._unbounded:
list_size = bound_2 - bound_1 + 1
self._container = list_size*[None]
# for unbounded list, this will come after
else:
self._container = [None]
def bound_1(self):
return self._bound_1
def bound_2(self):
return self._bound_2
def get_size(self):
number_of_indeterminates = self._container.count(None)
hiindex = len(self._container) - number_of_indeterminates
return INTEGER(hiindex)
def get_hiindex(self):
''' When V is a bag, list or set, the returned value is the actual number of elements in
the aggregate value.'''
number_of_indeterminates = self._container.count(None)
hiindex = len(self._container) - number_of_indeterminates
return INTEGER(hiindex)
def get_loindex(self):
return INTEGER(1)
def get_hibound(self):
hibound = self._bound_2
if type(hibound)==int:
return INTEGER(hibound)
else:
return hibound
def get_lobound(self):
lobound = self._bound_1
if type(lobound)==int:
return INTEGER(lobound)
else:
return lobound
def get_value_unique(self):
''' Return True if all items are different in the container, UNKNOWN if some items are
indeterminate, or False otherwise'''
if None in self._container:
return Unknown
if self.get_size()-len(set(self._container))>0: #some items are repeated
return False
else:
return True
def __getitem__(self, index):
# case bounded
if not self._unbounded:
if index<self._bound_1:
raise IndexError("ARRAY index out of bound (lower bound is %i, passed %i)"%(self._bound_1,index))
elif(index>self._bound_2):
raise IndexError("ARRAY index out of bound (upper bound is %i, passed %i)"%(self._bound_2,index))
else:
value = self._container[index-self._bound_1]
if value == None:
raise AssertionError("Value with index %i not defined. Please set the value first."%index)
return value
#case unbounded
else:
if index-self._bound_1>len(self._container):
raise AssertionError("Value with index %i not defined. Please set the value first."%index)
else:
value = self._container[index-self._bound_1]
if value == None:
raise AssertionError("Value with index %i not defined. Please set the value first."%index)
return value
def __setitem__(self, index, value):
# case bounded
if not self._unbounded:
if index<self._bound_1:
raise IndexError("ARRAY index out of bound (lower bound is %i, passed %i)"%(self._bound_1,index))
elif(index>self._bound_2):
raise IndexError("ARRAY index out of bound (upper bound is %i, passed %i)"%(self._bound_2,index))
else:
# first check the type of the value
check_type(value,self.get_type())
# then check if the value is already in the array
if self._unique:
if value in self._container:
raise AssertionError("UNIQUE keyword prevent inserting this instance.")
self._container[index-self._bound_1] = value
# case unbounded
else:
if index<self._bound_1:
raise IndexError("ARRAY index out of bound (lower bound is %i, passed %i)"%(self._bound_1,index))
# if the _container list is of good size, just do like the bounded case
if (index-self._bound_1<len(self._container)):
# first check the type of the value
check_type(value,self.get_type)
# then check if the value is already in the array
if self._unique:
if value in self._container:
raise AssertionError("UNIQUE keyword prevent inserting this instance.")
self._container[index-self._bound_1] = value
# in the other case, we have to extend the base _container list
else:
delta_size = (index-self._bound_1) - len(self._container) + 1
#create a list of None, and extend the list
list_extension = delta_size*[None]
self._container.extend(list_extension)
# first check the type of the value
check_type(value,self.get_type())
# then check if the value is already in the array
if self._unique:
if value in self._container:
raise AssertionError("UNIQUE keyword prevent inserting this instance.")
self._container[index-self._bound_1] = value
class BAG(BaseType.Type, BaseType.Aggregate):
"""
EXPRESS definition:
==================
A bag data type has as its domain unordered collections of like elements. The optional lower
and upper bounds, which are integer-valued expressions, define the minimum and maximum
number of elements that can be held in the collection de ned by a bag data type.
Syntax:
170 bag_type = BAG [ bound_spec ] OF base_type .
176 bound_spec = '[' bound_1 ':' bound_2 ']' .
174 bound_1 = numeric_expression .
175 bound_2 = numeric_expression .
171 base_type = aggregation_types | simple_types | named_types .
Rules and restrictions:
a) The bound_1 expression shall evaluate to an integer value greater than or equal to
zero. It gives the lower bound, which is the minimum number of elements that can be in a
bag value of this data type. bound_1 shall not produce the indeterminate (?) value.
b) The bound_2 expression shall evaluate to an integer value greater than or equal to
bound_1, or an indeterminate (?) value. It gives the upper bound, which is the maximum
number of elements that can be in a bag value of this data type.
If this value is indeterminate (?) the number of elements in a bag value of this data type is
not be bounded from above.
c) If the bound_spec is omitted, the limits are [0:?].
EXAMPLE 29 (This example defines an attribute as a bag of point (where point is a named data
type assumed to have been declared elsewhere).
a_bag_of_points : BAG OF point;
The value of the attribute named a_bag_of_points can contain zero or more points. The same
point instance may appear more than once in the value of a_bag_of_points.
If the value is required to contain at least one element, the specification can provide a lower bound,
as in:
a_bag_of_points : BAG [1:?] OF point;
The value of the attribute named a_bag_of_points now must contain at least one point.
Python definition:
==================
@TODO
"""
def __init__( self , bound_1 , bound_2 , base_type , scope = None):
BaseType.Type.__init__(self, base_type, scope)
if not type(bound_1)==int:
raise TypeError("LIST lower bound must be an integer")
# bound_2 can be set to None
self._unbounded = False
if bound_2 == None:
self._unbounded = True
elif not type(bound_2)==int:
raise TypeError("LIST upper bound must be an integer")
if not bound_1>=0:
raise AssertionError("LIST lower bound must be greater of equal to 0")
if (type(bound_2)==int and not (bound_1 <= bound_2)):
raise AssertionError("ARRAY lower bound must be less than or equal to upper bound")
# set up class attributes
self._bound_1 = bound_1
self._bound_2 = bound_2
self._container = []
def bound_1(self):
return self._bound_1
def bound_2(self):
return self._bound_2
def add(self,value):
'''
Adds a value to the bag
'''
if self._unbounded:
check_type(value,self.get_type())
self._container.append(value)
else:
# first ensure that the bag is not full
if len(self._container) == self._bound_2 - self._bound_1 + 1:
raise AssertionError('BAG is full. Impossible to add any more item')
else:
check_type(value,self.get_type())
self._container.append(value)
def get_size(self):
''' When V is a bag, list or set, the returned value is the actual number of elements in
the aggregate value.'''
return INTEGER(len(self._container))
def get_hiindex(self):
''' When V is a bag, list or set, the returned value is the actual number of elements in
the aggregate value.'''
return INTEGER(len(self._container))
def get_loindex(self):
return INTEGER(1)
def get_hibound(self):
hibound = self._bound_2
if type(hibound)==int:
return INTEGER(hibound)
else:
return hibound
def get_lobound(self):
lobound = self._bound_1
if type(lobound)==int:
return INTEGER(lobound)
else:
return lobound
def get_value_unique(self):
''' Return True if all items are different in the container, UNKNOWN if some items are
indeterminate, or False otherwise'''
if None in self._container:
return Unknown
if self.get_size()-len(set(self._container))>0: #some items are repeated
return False
else:
return True
class SET(BaseType.Type, BaseType.Aggregate):
"""
EXPRESS definition:
==================
A set data type has as its domain unordered collections of like elements. The set data type is
a specialization of the bag data type. The optional lower and upper bounds, which are integer-
valued expressions, de ne the minimum and maximum number of elements that can be held in
the collection de ned by a set data type. The collection de ned by set data type shall not
contain two or more elements which are instance equal.
Syntax:
285 set_type = SET [ bound_spec ] OF base_type .
176 bound_spec = '[' bound_1 ':' bound_2 ']' .
174 bound_1 = numeric_expression .
175 bound_2 = numeric_expression .
171 base_type = aggregation_types | simple_types | named_types .
Rules and restrictions:
a) The bound_1 expression shall evaluate to an integer value greater than or equal to
zero. It gives the lower bound, which is the minimum number of elements that can be in a
set value of this data type. bound_1 shall not produce the indeterminate (?) value.
b) The bound_2 expression shall evaluate to an integer value greater than or equal to
bound_1, or an indeterminate (?) value. It gives the upper bound, which is the maximum
number of elements that can be in a set value of this data type.
If this value is indeterminate (?) the number of elements in a set value of this data type is
not be bounded from above.
c) If the bound_spec is omitted, the limits are [0:?].
d) Each element in an occurrence of a set data type shall be di erent from (i.e., not
instance equal to) every other element in the same set value.
EXAMPLE 30 { This example de nes an attribute as a set of points (a named data type assumed
to have been declared elsewhere).
a_set_of_points : SET OF point;
The attribute named a_set_of_points can contain zero or more points. Each point instance (in
the set value) is required to be di erent from every other point in the set.
If the value is required to have no more than 15 points, the speci cation can provide an upper bound,
as in:
a_set_of_points : SET [0:15] OF point;
The value of the attribute named a_set_of_points now may contain no more than 15 points.
Python definition:
==================
The difference with the BAG class is that the base container for SET is a set object.
"""
def __init__( self , bound_1 , bound_2 , base_type , scope = None):
BaseType.Type.__init__(self, base_type, scope)
if not type(bound_1)==int:
raise TypeError("LIST lower bound must be an integer")
# bound_2 can be set to None
self._unbounded = False
if bound_2 == None:
self._unbounded = True
elif not type(bound_2)==int:
raise TypeError("LIST upper bound must be an integer")
if not bound_1>=0:
raise AssertionError("LIST lower bound must be greater of equal to 0")
if (type(bound_2)==int and not (bound_1 <= bound_2)):
raise AssertionError("ARRAY lower bound must be less than or equal to upper bound")
# set up class attributes
self._bound_1 = bound_1
self._bound_2 = bound_2
self._container = set()
def bound_1(self):
return self._bound_1
def bound_2(self):
return self._bound_2
def add(self,value):
'''
Adds a value to the bag
'''
if self._unbounded:
check_type(value,self.get_type())
self._container.add(value)
else:
# first ensure that the bag is not full
if len(self._container) == self._bound_2 - self._bound_1 + 1:
if not value in self._container:
raise AssertionError('SET is full. Impossible to add any more item')
else:
check_type(value,self.get_type())
self._container.add(value)
def get_size(self):
''' When V is a bag, list or set, the returned value is the actual number of elements in
the aggregate value.'''
return INTEGER(len(self._container))
def get_hiindex(self):
''' When V is a bag, list or set, the returned value is the actual number of elements in
the aggregate value.'''
return INTEGER(len(self._container))
def get_loindex(self):
return INTEGER(1)
def get_hibound(self):
hibound = self._bound_2
if type(hibound)==int:
return INTEGER(hibound)
else:
return hibound
def get_lobound(self):
lobound = self._bound_1
if type(lobound)==int:
return INTEGER(lobound)
else:
return lobound
def get_value_unique(self):
''' Return True if all items are different in the container, UNKNOWN if some items are
indeterminate, or False otherwise'''
if None in self._container:
return Unknown
else:
return True

View File

@ -0,0 +1,69 @@
# Copyright (c) 2011, Thomas Paviot (tpaviot@gmail.com)
# All rights reserved.
# This file is part of the StepClassLibrary (SCL).
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# Neither the name of the <ORGANIZATION> nor the names of its contributors may
# be used to endorse or promote products derived from this software without
# specific prior written permission.
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
class Type(object):
'''
A type can be defined from its name and scope
Looking into the scope dict returns the python type class.
This is the base class for aggregated data types or constructed data types
'''
def __init__(self, typedef, scope):
self._scope = scope
self._typedef = typedef
def get_scope(self):
return self._scope
def get_type(self):
if type(self._typedef) == str:
if self._scope == None:
raise AssertionError('No scope defined for this type')
elif vars(self._scope).has_key(self._typedef):
return vars(self._scope)[self._typedef]
else:
raise TypeError("Type '%s' is not defined in given scope"%self._typedef)
else:
return self._typedef
class Aggregate:
'''
This is an abstract class. ARRAY, LIST, SET and BAG inherit from this class
'''
pass
if __name__ == "__main__":
import sys
scp = sys.modules[__name__]
class line:
pass
new_type = Type('lie',scp)
print new_type.get_type()

View File

@ -0,0 +1,716 @@
# Copyright (c) 2011-2012, Thomas Paviot (tpaviot@gmail.com)
# All rights reserved.
# This file is part of the StepClassLibrary (SCL).
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# Neither the name of the <ORGANIZATION> nor the names of its contributors may
# be used to endorse or promote products derived from this software without
# specific prior written permission.
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
__doc__ = "This module defines EXPRESS built in constants and functions"
import math
from SimpleDataTypes import *
from BaseType import Aggregate
from AggregationDataTypes import *
SCL_float_epsilon = 1e-7
# Builtin constants
# EXPRESS definition:
# ===================
#14.1 CONST_E is a REAL constant representing the mathematical value e, the base of the natural
#logarithm function (ln).
CONST_E = REAL(math.pi)
# EXPRESS definition:
# ===================
#14.2 Indeterminate
#The indeterminate symbol (?) stands for an ambiguous value. It is compatible with all data
#types.
#NOTE - The most common use of indeterminate (?) is as the upper bound speci cation of a bag,
#list or set. This usage represents the notion that the size of the aggregate value de ned by the
#aggregation data type is unbounded.
# python note: indeterminate value is mapped to None in aggregate bounds
# EXPRESS definition:
# ===================
#14.3 False
#false is a logical constant representing the logical notion of falsehood. It is compatible with
#the boolean and logical data types.
FALSE = False
# EXPRESS definition:
# ===================
#14.4 Pi
#PI is a REAL constant representing the mathematical value , the ratio of a circle's circumference
#to its diameter.
PI = REAL(math.pi)
# EXPRESS definition:
# ===================
#14.5 Self
#SELF refers to the current entity instance or type value. self may appear within an entity
#declaration, a type declaration or an entity constructor.
#NOTE - sSELF is not a constant, but behaves as one in every context in which it can appear.
# python note: SELF is not mapped to any constant, but is mapper to self
# EXPRESS definition:
# ===================
#14.6 True
#true is a logical constant representing the logical notion of truth. It is compatible with the
#boolean and logical data types.
TRUE = True
# EXPRESS definition:
# ===================
#14.7 Unknown
#unknown is a logical constant representing that there is insucient information available to
#be able to evaluate a logical condition. It is compatible with the logical data type, but not
#with the boolean data type.
# @TODO: define UNKNOWN in python
#
# Builtin Functions
#15 Built-in functions
#All functions (and mathematical operations in general) are assumed to evaluate to exact results.
#The prototype for each of the built-in functions is given to show the type of the formal parameters
#and the result.
#
# EXPRESS definition:
# ===================
#15.1 Abs - arithmetic function
#FUNCTION ABS ( V:NUMBER ) : NUMBER;
#The abs function returns the absolute value of a number.
#Parameters : V is a number.
#Result : The absolute value of V. The returned data type is identical to the data type of V.
#EXAMPLE 125 { ABS ( -10 ) --> 10
# Python definition:
# ==================
# ABS is mapped to python abs builtin function
def ABS(V):
if not isinstance(V,NUMBER):
raise TypeError("ABS function takes a NUMBER parameter")
return type(V)(abs(V))
# EXPRESS definition:
# ===================
#15.2 ACos - arithmetic function
#FUNCTION ACOS ( V:NUMBER ) : REAL;
#The acos function returns the angle given a cosine value.
#Parameters : V is a number which is the cosine of an angle.
#Result : The angle in radians (0  result  ) whose cosine is V.
#Conditions : -1.0=<V<=1.0
#EXAMPLE 126 { ACOS ( 0.3 ) --> 1.266103...
# Python definition:
# ==================
# ACOS is mapped to python math.acos builtin function
def ACOS(V):
if not isinstance(V,NUMBER):
raise TypeError("ACOS function takes a NUMBER parameter")
return REAL(math.acos(V))
# it's the same for ASIN and ATAN
def ASIN(V):
if not isinstance(V,NUMBER):
raise TypeError("ASIN function takes a NUMBER parameter")
return REAL(math.asin(V))
# EXPRESS definition:
# ===================
# 15.3 ATan - arithmetic function
#FUNCTION ATAN ( V1:NUMBER; V2:NUMBER ) : REAL;
#The atan function returns the angle given a tangent value of V , where V is given by the
#expression V = V1/V2.
#Parameters :
#a) V1 is a number.
#b) V2 is a number.
#Result : The angle in radians (-pi/2<=result<=pi/2) whose tangent is V. If V2 is zero, the result
#is pi/2 or -pi/2 depending on the sign of V1.
#Conditions : Both V1 and V2 shall not be zero.
#EXAMPLE 128 { ATAN ( -5.5, 3.0 ) --> -1.071449...
def ATAN(V1,V2):
if not isinstance(V1,NUMBER) and not isinstance(V2,NUMBER):
raise TypeError("ATAN function takes 2 NUMBER parameters")
if V2 == 0:
if V1>0:
return REAL(math.pi/2)
elif V1<0:
return REAL(-math.pi/2)
else:
raise ValueError("ATAN parameters can be both equal to zero")
else:
return REAL(math.atan(float(V1)/float(V2)))
# EXPRESS definition:
# ===================
#15.5 BLength - binary function
#FUNCTION BLENGTH ( V:BINARY ) : INTEGER;
#The blength function returns the number of bits in a binary.
#Parameters : V is a binary value.
#Result : The returned value is the actual number of bits in the binary value passed.
#EXAMPLE 129
#LOCAL
#n : NUMBER;
#x : BINARY := %01010010 ;
#END_LOCAL;
#...
#n := BLENGTH ( x ); -- n is assigned the value 8
def BLENGTH(V):
if not isinstance(V,BINARY):
raise TypeError("BLENGTH function takes one BINARY parameter")
return INTEGER(len(V))
# EXPRESS definition:
# ===================
#15.6 Cos - arithmetic function
#FUNCTION COS ( V:NUMBER ) : REAL;
#The cos function returns the cosine of an angle.
#Parameters : V is a number which is an angle in radians.
#Result : The cosine of V (-1.0<=result<=1.0).
#EXAMPLE 130 { COS ( 0.5 ) --> 8.77582...E-1
#
#15.21 Sin - arithmetic function
#FUNCTION SIN ( V:NUMBER ) : REAL;
#The sin function returns the sine of an angle.
#Parameters : V is a number representing an angle expressed in radians.
#Result : The sine of V (-1.0  result  1.0).
#EXAMPLE 144 { SIN ( PI ) --> 0.0
#
def COS(V):
if not isinstance(V,NUMBER):
raise TypeError("COS function takes a NUMBER parameter")
return REAL(math.cos(V))
def SIN(V):
if not isinstance(V,NUMBER):
raise TypeError("SIN function takes a NUMBER parameter")
return REAL(math.sin(V))
# EXPRESS definition:
# ===================
#15.7 Exists - general function
#FUNCTION EXISTS ( V:GENERIC ) : BOOLEAN;
#The exists function returns true if a value exists for the input parameter, or false if no value
#exists for it. The exists function is useful for checking if values have been given to optional
#attributes, or if variables have been initialized.
#Parameters : V is an expression which results in any type.
#Result : true or false depending on whether V has an actual or indeterminate (?) value.
#EXAMPLE 131 { IF EXISTS ( a ) THEN ...
def EXISTS(V):
if V==None:
return False
else:
return True
# EXPRESS definition:
# ===================
#15.8 Exp - arithmetic function
#FUNCTION EXP ( V:NUMBER ) : REAL;
#The exp function returns e (the base of the natural logarithm system) raised to the power V.
#Parameters : V is a number.
#Result : The value eV .
#EXAMPLE 132 { EXP ( 10 ) --> 2.202646...E+4
def EXP(V):
if not isinstance(V,NUMBER):
raise TypeError("EXP function takes a NUMBER parameter")
return REAL(math.exp(V))
# EXPRESS definition:
# ===================
#15.9 Format - general function
#FUNCTION FORMAT(N:NUMBER; F:STRING):STRING;
#The format returns a formatted string representation of a number.
#Parameters :
#a) N is a number (integer or real).
#b) F is a string containing formatting commands.
#Result : A string representation of N formatted according to F. Rounding is applied to the
#string representation if necessary.
#The formatting string contains special characters to indicate the appearance of the result. The
#formatting string can be written in three ways:
#a) The formatting string can give a symbolic description of the output representation.
#b) The formatting string can give a picture description of the output representation.
#c) When the formatting string is empty, a standard output representation is produced.
# Table 20:
#Number Format Display Comment
#10 +7I ' +10' Zero suppression
#10 +07I '+000010' Zeros not suppressed
#10 10.3E ' 1.000E+01'
#123.456789 8.2F ' 123.46'
#123.456789 8.2E '1.23E+02'
#123.456789 08.2E '0.12E+02' Preceding zero forced
#9.876E123 8.2E '9.88E+123' Exponent part is 3 characters
#and width ignored
#32.777 6I ' 33' Rounded
# Python definition
# =================
# python string formatting is obtained from the val function
# @TODO: implement a safe eval or provide another implementation
# that avoids unsafe eval python builtin function.
def FORMAT(N,F):
if not isinstance(N,NUMBER):
raise TypeError("FORMAT function takes a NUMBER parameter")
if not isinstance(F,STRING):
raise TypeError("FORMAT function takes a NUMBER parameter")
py_formatting = F.lower()
string_to_evaluate = "'%"
string_to_evaluate += "%s'"%py_formatting
string_to_evaluate += "%"
string_to_evaluate += "%s"%N
result = eval(string_to_evaluate).upper()
return STRING(result)
# EXPRESS definition:
# ===================
#15.10 HiBound - arithmetic function
#FUNCTION HIBOUND ( V:AGGREGATE OF GENERIC ) : INTEGER;
#The hibound function returns the declared upper index of an array or the declared upper
#bound of a bag, list or set.
#Parameters : V is an aggregate value.
#Result :
#a) When V is an array the returned value is the declared upper index.
#b) When V is a bag, list or set the returned value is the declared upper bound; if there
#are no bounds declared or the upper bound is declared to be indeterminate (?) indeterminate
#(?) is returned.
#EXAMPLE 133 { Usage of hibound function on nested aggregate values.
#LOCAL
#a : ARRAY[-3:19] OF SET[2:4] OF LIST[0:?] OF INTEGER;
#h1, h2, h3 : INTEGER;
#END_LOCAL;
#...
#a[-3][1][1] := 2; -- places a value in the list
#...
#h1 := HIBOUND(a); -- =19 (upper bound of array)
#h2 := HIBOUND(a[-3]); -- = 4 (upper bound of set)
#h3 := HIBOUND(a[-3][1]); -- = ? (upper bound of list (unbounded))
def HIBOUND(V):
if not isinstance(V,Aggregate):
raise TypeError("HIBOUND takes an aggregate of generic")
return V.get_hibound()
# EXPRESS definition:
# ===================
#15.11 HiIndex - arithmetic function
#FUNCTION HIINDEX ( V:AGGREGATE OF GENERIC ) : INTEGER;
#The hiindex function returns the upper index of an array or the number of elements in a bag,
#list or set
#Parameters : V is an aggregate value.
#Result :
#a) When V is an array, the returned value is the declared upper index.
#b) When V is a bag, list or set, the returned value is the actual number of elements in
#the aggregate value.
#EXAMPLE 134 { Usage of hiindex function on nested aggregate values.
#LOCAL
#a : ARRAY[-3:19] OF SET[2:4] OF LIST[0:?] OF INTEGER;
#h1, h2, h3 : INTEGER;
#END_LOCAL;
#a[-3][1][1] := 2; -- places a value in the list
#h1 := HIINDEX(a); -- = 19 (upper bound of array)
#h2 := HIINDEX(a[-3]); -- = 1 (size of set) -- this is invalid with respect
#-- to the bounds on the SET
#h3 := HIINDEX(a[-3][1]); -- = 1 (size of list)
def HIINDEX(V):
if not isinstance(V,Aggregate):
raise TypeError("HIINDEX takes an aggregate of generic")
return V.get_hiindex()
# EXPRESS definition:
# ===================
#15.12 Length - string function
#FUNCTION LENGTH ( V:STRING ) : INTEGER;
#The length function returns the number of characters in a string.
#Parameters : V is a string value.
#Result : The returned value is the number of characters in the string and shall be greater than
#or equal to zero.
#EXAMPLE 135 - Usage of the length function.
#LOCAL
#n : NUMBER;
#x1 : STRING := 'abc';
#x2 : STRING := "000025FF000101B5;
#END_LOCAL;
#...
#n := LENGTH ( x1 ); -- n is assigned the value 3
#n := LENGTH ( x2 ); -- n is assigned the value 2
def LENGTH(V):
if not isinstance(V,STRING):
raise TypeError("LENGTH take a STRING parameter")
return INTEGER(len(V))
# EXPRESS definition:
# ===================
#15.13 LoBound - arithmetic function
#FUNCTION LOBOUND ( V:AGGREGATE OF GENERIC ) : INTEGER;
#The lobound function returns the declared lower index of an array, or the declared lower
#bound of a bag, list or set.
#Parameters : V is an aggregate value.
#Result :
#a) When V is an array the returned value is the declared lower index.
#b) When V is a bag, list or set the returned value is the declared lower bound; if no
#lower bound is declared, zero (0) is returned.
#EXAMPLE 136 { Usage of lobound function on nested aggregate values.
#LOCAL
#a : ARRAY[-3:19] OF SET[2:4] OF LIST[0:?] OF INTEGER;
#h1, h2, h3 : INTEGER;
#END_LOCAL;
#...
#h1 := LOBOUND(a); -- =-3 (lower index of array)
#h2 := LOBOUND(a[-3]); -- = 2 (lower bound of set)
#h3 := LOBOUND(a[-3][1]); -- = 0 (lower bound of list)
def LOBOUND(V):
if not isinstance(V,Aggregate):
raise TypeError("HIBOUND takes an aggregate of generic")
return V.get_lobound()
# EXPRESS definition:
# ===================
#15.14 Log - arithmetic function
#FUNCTION LOG ( V:NUMBER ) : REAL;
#The log function returns the natural logarithm of a number.
#Parameters : V is a number.
#Result : A real number which is the natural logarithm of V.
#Conditions : V > 0:0
#EXAMPLE 137 { LOG ( 4.5 ) --> 1.504077...E0
#15.15 Log2 - arithmetic function
#FUNCTION LOG2 ( V:NUMBER ) : REAL;
#The log2 function returns the base two logarithm of a number.
#Parameters : V is a number.
#Result : A real number which is the base two logarithm of V.
#Conditions : V > 0:0
#EXAMPLE 138 { LOG2 ( 8 ) --> 3.00...E0
#15.16 Log10 - arithmetic function
#FUNCTION LOG10 ( V:NUMBER ) : REAL;
#The log10 function returns the base ten logarithm of a number.
#Parameters : V is a number.
#Result : A real number which is the base ten logarithm of V.
#Conditions : V > 0:0
#EXAMPLE 139 { LOG10 ( 10 ) --> 1.00...E0
def LOG(V):
if not isinstance(V,NUMBER):
raise TypeError("LOG function takes a NUMBER parameter")
return REAL(math.log(V))
def LOG2(V):
if not isinstance(V,NUMBER):
raise TypeError("LOG2 function takes a NUMBER parameter")
return REAL(math.log(V,2))
def LOG10(V):
if not isinstance(V,NUMBER):
raise TypeError("LOG10 function takes a NUMBER parameter")
return REAL(math.log10(V))
# EXPRESS definition:
# ===================
#15.17 LoIndex - arithmetic function
#FUNCTION LOINDEX ( V:AGGREGATE OF GENERIC ) : INTEGER;
#The loindex function returns the lower index of an aggregate value.
#Parameters : V is an aggregate value.
#Result :
#a) When V is an array the returned value is the declared lower index.
#b) When V is a bag, list or set, the returned value is 1 (one).
#EXAMPLE 140 { Usage of loindex function on nested aggregate values.
#LOCAL
#a : ARRAY[-3:19] OF SET[2:4] OF LIST[0:?] OF INTEGER;
#h1, h2, h3 : INTEGER;
#END_LOCAL;
#...
#h1 := LOINDEX(a); -- =-3 (lower bound of array)
#h2 := LOINDEX(a[-3]); -- = 1 (for set)
#h3 := LOINDEX(a[-3][1]); -- = 1 (for list)
def LOINDEX(V):
if not isinstance(V,Aggregate):
raise TypeError("LOINDEX takes an aggregate of generic")
return V.get_loindex()
# EXPRESS definition:
# ===================
#15.18 NVL - null value function
#FUNCTION NVL(V:GENERIC:GEN1; SUBSTITUTE:GENERIC:GEN1):GENERIC:GEN1;
#The nvl function returns either the input value or an alternate value in the case where the input
#has a indeterminate (?) value.
#Parameters :
#a) V is an expression which is of any type.
#b) SUBSTITUTE is an expression which shall not evaluate to indeterminate (?).
#Result : When V is not indeterminate (?) that value is returned. Otherwise, SUBSTITUTE is
#returned.
#EXAMPLE 141 { ENTITY unit_vector;
#x, y : REAL;
#z : OPTIONAL REAL;
#WHERE
#x**2 + y**2 + NVL(z, 0.0)**2 = 1.0;
#END_ENTITY;
#The nvl function is used to supply zero (0.0) as the value of Z when Z is indeterminate (?).
def NVL(V,SUBSTITUTE):
if V is not None:
return V
else:
return SUBSTITUTE
# EXPRESS definition:
# ===================
#15.19 Odd - arithmetic function
#FUNCTION ODD ( V:INTEGER ) : LOGICAL;
#The odd function returns true or false depending on whether a number is odd or even.
#Parameters : V is an integer number.
#Result : When V MOD 2 = 1 true is returned; otherwise false is returned.
#Conditions : Zero is not odd.
#EXAMPLE 142 { ODD ( 121 ) --> TRUE
def ODD(V):
if not isinstance(V,INTEGER):
raise TypeError("ODD takes an INTEGER")
if V%2 == 0:
return False
else:
return True
# EXPRESS definition:
# ===================
#15.20 RolesOf - general function
#FUNCTION ROLESOF ( V:GENERIC ) : SET OF STRING;
#The rolesof function returns a set of strings containing the fully quali ed names of the roles
#played by the speci ed entity instance. A fully quali ed name is de ned to be the name of the
#attribute quali ed by the name of the schema and entity in which this attribute is declared (i.e.
#'SCHEMA.ENTITY.ATTRIBUTE').
#Parameters : V is any instance of an entity data type.
#Result : A set of string values (in upper case) containing the fully quali ed names of the
#attributes of the entity instances which use the instance V.
#When a named data type is use'd or reference'd, the schema and the name in that schema,
#if renamed, are also returned. Since use statements may be chained, all the chained schema
#names and the name in each schema are returned.
#EXAMPLE 143 { This example shows that a point might be used as the centre of a circle. The
#rolesof function determines what roles an entity instance actually plays.
#SCHEMA that_schema;
#ENTITY point;
#x, y, z : REAL;
#END_ENTITY;
#ENTITY line;
#start,
#end : point;
#END_ENTITY;
#END_SCHEMA;
#SCHEMA this_schema;
#USE FROM that_schema (point,line);
#CONSTANT
#origin : point := point(0.0, 0.0, 0.0);
#END_CONSTANT;
#ENTITY circle;
#centre : point;
#axis : vector;
#radius : REAL;
#END_ENTITY;
#...
#LOCAL
#p : point := point(1.0, 0.0, 0.0);
#c : circle := circle(p, vector(1,1,1), 1.0);
#l : line := line(p, origin);
#END_LOCAL;
#...
#IF 'THIS_SCHEMA.CIRCLE.CENTRE' IN ROLESOF(p) THEN -- true
#...
#IF 'THIS_SCHEMA.LINE.START' IN ROLESOF(p) THEN -- true
#...
#IF 'THAT_SCHEMA.LINE.START' IN ROLESOF(p) THEN -- true
#...
#IF 'THIS_SCHEMA.LINE.END' IN ROLESOF(p) THEN -- false
#
# Python note:
# @TODO: implement the ROLESOF function
def ROLESOF(V):
raise NotImplemented("Function ROLESOF not implemented")
# EXPRESS definition:
# ===================
#15.22 SizeOf - aggregate function
#FUNCTION SIZEOF ( V:AGGREGATE OF GENERIC ) : INTEGER;
#The sizeof function returns the number of elements in an aggregate value.
#Parameters : V is an aggregate value.
#Result :
#a) When V is an array the returned value is its declared number of elements in the
#aggregation data type.
#b) When V is a bag, list or set, the returned value is the actual number of elements in
#the aggregate value.
#EXAMPLE 145 { LOCAL
#n : NUMBER;
#y : ARRAY[2:5] OF b;
#END_LOCAL;
#...
#n := SIZEOF (y); -- n is assigned the value 4
def SIZEOF(V):
if not isinstance(V,Aggregate):
raise TypeError("SIZEOF takes an aggregate of generic")
return V.get_size()
# EXPRESS definition:
# ===================
#15.23 Sqrt - arithmetic function
#FUNCTION SQRT ( V:NUMBER ) : REAL;
#The sqrt function returns the non-negative square root of a number.
#Parameters : V is any non-negative number.
#Result : The non-negative square root of V.
#Conditions : V  0:0
#EXAMPLE 146 - SQRT ( 121 ) --> 11.0
def SQRT(V):
if not isinstance(V,NUMBER):
raise TypeError("SQRT function takes a NUMBER parameter")
if V<0.0:
raise ValueError("SQRT takes a non-negative parameter")
return REAL(math.sqrt(V))
# EXPRESS definition:
# ===================
#15.24 Tan - arithmetic function
#FUNCTION TAN ( V:NUMBER ) : REAL;
#The tan function returns the tangent of of an angle.
#Parameters : V is a number representing an angle expressed in radians.
#Result : The tangent of the angle. If the angle is npi/2, where n is an odd integer, indeterminate
#(?) is returned.
#EXAMPLE 147 - TAN ( 0.0 ) --> 0.0
def TAN(V):
if not isinstance(V,NUMBER):
raise TypeError("TAN function takes a NUMBER parameter")
# check if angle is npi/2 where n is an odd integer
a = V/(PI/2)
if abs(a%2-1.) < SCL_float_epsilon :
return None
else:
return REAL(math.tan(V))
# EXPRESS definition:
# ===================
#15.25 TypeOf - general function
#FUNCTION TYPEOF ( V:GENERIC ) : SET OF STRING;
#The typeof function returns a set of strings that contains the names of all the data types
#of which the parameter is a member. Except for the simple data types (binary, boolean,
#integer, logical, number, real, and string) and the aggregation data types (array, bag,
#list, set) these names are quali ed by the name of the schema which contains the de nition of
#the type.
#NOTE 1 { The primary purpose of this function is to check whether a given value (variable, at-
#tribute value) can be used for a certain purpose, e.g. to ensure assignment compatibility between
#two values. It may also be used if di erent subtypes or specializations of a given type have to be
#treated di erently in some context.
#Parameters : V is a value of any type.
#Result : The contents of the returned set of string values are the names (in upper case) of all
#types the value V is a member of. Such names are quali ed by the name of the schema which
#contains the de nition of the type ('SCHEMA.TYPE') if it is neither a simple data type nor an
#aggregation data type. It may be derived by the following algorithm (which is given here for
#specification purposes rather than to prescribe any particular type of implementation)
def TYPEOF(V):
# Create the set to return
v_types = set()
# append the type of V to the set
try: #it's a class
to_add = V.__name__.upper()
except AttributeError: #it's an instance, first retrieve the type
to_add = type(V).__name__.upper()
if not to_add in ['FLOAT','INT','AGGREGATE']:
v_types.add(to_add)
# recursively adds the base class names
for base_type in type(V).__bases__:
#print base_type
if not base_type == object:
v_types = v_types.union(TYPEOF(base_type))
# finally, converts the v_types set to SET
return v_types
# EXPRESS definition:
# ===================
#15.26 UsedIn - general function
#FUNCTION USEDIN ( T:GENERIC; R:STRING) : BAG OF GENERIC;
#The usedin function returns each entity instance that uses a speci ed entity instance in a
#speci ed role.
def USEDIN(T,R):
raise NotImplemented("USEDIN function not yet implemented.")
# EXPRESS definition:
# ===================
#15.27 Value - arithmetic function
#FUNCTION VALUE ( V:STRING ) : NUMBER;
#The value function returns the numeric representation of a string.
#Parameters : V is a string containing either a real or integer literal.
#Result : A number corresponding to the string representation. If it is not possible to interpret
#the string as either a real or integer literal, indeterminate (?) is returned.
#EXAMPLE 151 { VALUE ( '1.234' ) --> 1.234 (REAL)
#VALUE ( '20' ) --> 20 (INTEGER)
#VALUE ( 'abc' ) --> ? null
def VALUE(V):
if not isinstance(V,STRING):
raise TypeError("VALULE function takes a NUMBER parameter")
# first try to instanciate an INTEGER from the string:
try:
return INTEGER(V)
except:
pass #not possible, try to cast to REAL
try:
return REAL(V)
except:
pass
# else return None
return None
# EXPRESS definition:
# ===================
#15.28 Value in - membership function
#FUNCTION VALUE_IN ( C:AGGREGATE OF GENERIC:GEN; V:GENERIC:GEN ) : LOGICAL;
#The value in function returns a logical value depending on whether or not a particular value
#is a member of an aggregation.
#Parameters :
#a) C is an aggregation of any type.
#b) V is an expression which is assignment compatible with the base type of C.
#Result :
#a) If either V or C is indeterminate (?), unknown is returned.
#b) If any element of C has a value equal to the value of V, true is returned.
#c) If any element of C is indeterminate (?), unknown is returned.
#d) Otherwise false is returned.
#EXAMPLE 152 { The following test ensures that there is at least one point which is positioned at
#the origin.
#LOCAL
#points : SET OF point;
#END_LOCAL;
#...
#IF VALUE_IN(points, point(0.0, 0.0, 0.0)) THEN ...
def VALUE_IN(C,V):
if not isinstance(C,Aggregate):
raise TypeError("VALUE_IN method takes an aggregate as first parameter")
raise NotImplemented("VALUE_IN function not et implemented")
# EXPRESS definition:
# ===================
#15.29 Value unique - uniqueness function
#FUNCTION VALUE UNIQUE ( V:AGGREGATE OF GENERIC) : LOGICAL;
#The value unique function returns a logical value depending on whether or not the elements
#of an aggregation are value unique.
#Parameters : V is an aggregation of any type.
#Result :
#a) If V is indeterminate (?), unknown is returned.
#b) If any any two elements of V are value equal, false is returned.
#c) If any element of V is indeterminate (?), unknown is returned.
#d) Otherwise true is returned.
#EXAMPLE 153 { The following test ensures tht each point is a set is at a di erent position, (by
#de nition they are distinct, i.e., instance unique).
#IF VALUE_UNIQUE(points) THEN ...
def VALUE_UNIQUE(V):
if not isinstance(V,Aggregate):
raise TypeError("VALUE_UNIQUE method takes an aggregate as first parameter")
return V.get_value_unique()

View File

@ -0,0 +1,139 @@
# Copyright (c) 2011, Thomas Paviot (tpaviot@gmail.com)
# All rights reserved.
# This file is part of the StepClassLibrary (SCL).
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# Neither the name of the <ORGANIZATION> nor the names of its contributors may
# be used to endorse or promote products derived from this software without
# specific prior written permission.
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import sys
import BaseType
class EnumerationId(object):
"""
EXPRESS definition:
===================
An enumeration data type has as its domain an ordered set of names. The names represent
values of the enumeration data type. These names are designated by enumeration_ids and are
referred to as enumeration items.
"""
pass
class ENUMERATION(object):
"""
EXPRESS definition:
===================
An ENUMERATION data type has as its domain an ordered set of names. The names represent
values of the enumeration data type.
Python implementation:
======================
An enumeration is initialized from strings defining the types.
For instance, some EXPRESS definition:
TYPE ahead_or_behind = ENUMERATION OF
(ahead,
behind);
END_TYPE; -- ahead_or_behind
is implemented in python with the line:
>>> ahead_of_behind = ENUMERATION('ahead','behind', the_current_scope)
>>> ahead_or_behind.ahead
>>> ahead_of_behind.behind
And, if and only if ahead and/or behind are not in scope (e.g. they are not entity names,
and/or many enums define the same enumeration identifier):
>>> ahead
>>> behind
"""
def __init__(self,*kargs,**args):
# first defining the scope
if args.has_key('scope'):
self._scope = args['scope']
else:
self._scope = None
# store passed enum identifiers
self._enum_id_names = list(kargs)
self._enum_ids = []
# we create enums id from names, and create attributes
# for instance, from the identifier name 'ahead',
# we create an attribute ahead with which is a new
# instance of EnumerationId
for enum_id_name in self._enum_id_names:
setattr(self,enum_id_name,EnumerationId())
# we store this new attributes to the enum_ids list, which
# will be accessed by the type checker with the get_enum_ids method
self._enum_ids.append(self.__getattribute__(enum_id_name))
#
# Then we check if the enums names can be added to the current scope:
# if the name is already in the scope, then another enums id or select
# has the same name -> we do nothing, enums will be called
# with ahead_of_behind.ahead or ahead_or_behind.behind.
# otherwise, they can be called as only ahead or behind
# Note: since ENUMERATIONS are defined *before* entities, if an entity
# has the same name as an enum id, it will replace it in the current scope.
#
for enum_id_name in self._enum_id_names:
if not vars(self._scope).has_key(enum_id_name):
vars(self._scope)[enum_id_name] = self.__getattribute__(enum_id_name)
def get_enum_ids(self):
return self._enum_ids
class SELECT(object):
""" A select data type has as its domain the union of the domains of the named data types in
its select list. The select data type is a generalization of each of the named data types in its
select list.
"""
def __init__(self,*kargs,**args):
# first defining the scope
if args.has_key('scope'):
self._scope = args['scope']
else:
self._scope = None
# create the types from the list of arguments
self._base_types = []
for types in list(kargs):
new_type = BaseType.Type(types,self._scope)
self._base_types.append(new_type)
def get_allowed_types(self):
_auth_types = []
for types in self._base_types:
_auth_types.append(types.get_type())
return _auth_types
def get_allowed_basic_types(self):
''' if a select contains some subselect, goes down through the different
sublayers untill there is no more '''
b = []
_auth_types = self.get_allowed_types()
for _auth_type in _auth_types:
if isinstance(_auth_type,SELECT) or isinstance(_auth_type,ENUMERATION):
h = _auth_type.get_allowed_types()
b.extend(h)
else:
b = _auth_types
return b

View File

@ -0,0 +1,55 @@
# Copyright (c) 2011-2012, Thomas Paviot (tpaviot@gmail.com)
# All rights reserved.
# This file is part of the StepClassLibrary (SCL).
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# Neither the name of the <ORGANIZATION> nor the names of its contributors may
# be used to endorse or promote products derived from this software without
# specific prior written permission.
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
class Model(objet):
""" The container for entity instances
"""
def __init_(self):
print "Model initialized"
self._instances = []
def add_instance(self, entity_instance):
self._instances.append(entity_instance)
def remove_instance(self, entity_instance):
self._instances.remove(entity_instance)
def get_instances(self):
return self._instances
def export_to_p21file(self, filename):
raise AssertionError("Not implemented")
def export_to_p28file(self, filename):
raise AssertionError("Not implemented")

View File

@ -0,0 +1,209 @@
# Copyright (c) 2011, Thomas Paviot (tpaviot@gmail.com)
# All rights reserved.
# This file is part of the StepClassLibrary (SCL).
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# Neither the name of the <ORGANIZATION> nor the names of its contributors may
# be used to endorse or promote products derived from this software without
# specific prior written permission.
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import re
import Utils
import time
INSTANCE_DEFINITION_RE = re.compile("#(\d+)[^\S\n]?=[^\S\n]?(.*?)\((.*)\)[^\S\n]?;[\\r]?$")
def map_string_to_num(stri):
""" Take a string, check wether it is an integer, a float or not
"""
if ('.' in stri) or ('E' in stri): #it's definitely a float
return REAL(stri)
else:
return INTEGER(stri)
class Model:
"""
A model contains a list of instances
"""
def __init__(self,name):
self._name = name
# a dict of instances
# each time an instance is added to the model, count is incremented
self._instances = {}
self._number_of_instances = 0
def add_instance(self, instance):
'''
Adds an instance to the model
'''
self._number_of_instances += 1
self._instances[self._number_of_instances-1] = instance
def print_instances(self):
'''
Dump instances to stdout
'''
for idx in range(self._number_of_instances):
"=========="
print "Instance #%i"%(idx+1)
print self._instances[idx]
class Part21EntityInstance:
"""
A class to represent a Part21 instance as defined in one Part21 file
A Part21EntityInstance is defined by the following arguments:
entity_name: a string
entity_attributes: a list of strings to represent an attribute.
For instance, the following expression:
#4 = PRODUCT_DEFINITION_SHAPE('$','$',#5);
will result in :
entity : <class 'config_control_design.product_definition_shape'>
entity_instance_attributes: ['$','$','#5']
"""
def __init__(self,entity_name,attributes):
self._entity
self._attributes_definition = attributes
print self._entity_name
print self._attributes_definition
class Part21Parser:
"""
Loads all instances definition of a Part21 file into memory.
Two dicts are created:
self._instance_definition : stores attibutes, key is the instance integer id
self._number_of_ancestors : stores the number of ancestors of entity id. This enables
to define the order of instances creation.
"""
def __init__(self, filename):
self._filename = filename
# the schema
self._schema_name = ""
# the dict self._instances contain instance definition
self._instances_definition = {}
# this dict contains lists of 0 ancestors, 1 ancestor, etc.
# initializes this dict
self._number_of_ancestors = {}
for i in range(2000):
self._number_of_ancestors[i]=[]
self.parse_file()
# reduce number_of_ancestors dict
for item in self._number_of_ancestors.keys():
if len(self._number_of_ancestors[item])==0:
del self._number_of_ancestors[item]
def get_schema_name(self):
return self._schema_name
print schema_name
def get_number_of_instances(self):
return len(self._instances_definition.keys())
def parse_file(self):
init_time = time.time()
print "Parsing file %s..."%self._filename,
fp = open(self._filename)
while True:
line = fp.readline()
if not line:
break
# there may be a multline definition. In this case, we read lines untill we found
# a ;
#while (not line.endswith(";\r\n")): #its a multiline
# line = line.replace("\r\n","") + fp.readline()
# parse line
match_instance_definition = INSTANCE_DEFINITION_RE.search(line) # id,name,attrs
if match_instance_definition:
instance_id, entity_name, entity_attrs = match_instance_definition.groups()
instance_int_id = int(instance_id)
# find number of ancestors
number_of_ancestors = entity_attrs.count('#')
# fill number of ancestors dict
self._number_of_ancestors[number_of_ancestors].append(instance_int_id)
# parse attributes string
entity_attrs_list, str_len = Utils.process_nested_parent_str(entity_attrs)
# then finally append this instance to the disct instance
self._instances_definition[instance_int_id] = (entity_name,entity_attrs_list)
else: #does not match with entity instance definition, parse the header
if line.startswith('FILE_SCHEMA'):
#identify the schema name
self._schema_name = line.split("'")[1].split("'")[0].split(" ")[0].lower()
fp.close()
print 'done in %fs.'%(time.time()-init_time)
print 'schema: - %s entities %i'%(self._schema_name,len(self._instances_definition.keys()))
class EntityInstancesFactory(object):
'''
This class creates entity instances from the str definition
For instance, the definition:
20: ('CARTESIAN_POINT', ["''", '(5.,125.,20.)'])
will result in:
p = ARRAY(1,3,REAL)
p.[1] = REAL(5)
p.[2] = REAL(125)
p.[3] = REAL(20)
new_instance = cartesian_point(STRING(''),p)
'''
def __init__(self, schema_name, instance_definition):
# First try to import the schema module
pass
class Part21Population(object):
def __init__(self, part21_loader):
""" Take a part21_loader a tries to create entities
"""
self._part21_loader = part21_loader
self._aggregate_scope = []
self._aggr_scope = False
self.create_entity_instances()
def create_entity_instances(self):
""" Starts entity instances creation
"""
for number_of_ancestor in self._part21_loader._number_of_ancestors.keys():
for entity_definition_id in self._part21_loader._number_of_ancestors[number_of_ancestor]:
self.create_entity_instance(entity_definition_id)
def create_entity_instance(self, instance_id):
instance_definition = self._part21_loader._instances_definition[instance_id]
print "Instance definition to process",instance_definition
# first find class name
class_name = instance_definition[0].lower()
print "Class name:%s"%class_name
object_ = globals()[class_name]
# then attributes
#print object_.__doc__
instance_attributes = instance_definition[1]
print "instance_attributes:",instance_attributes
a = object_(*instance_attributes)
if __name__ == "__main__":
import time
import sys
from config_control_design import *
p21loader = Part21Parser("gasket1.p21")
print "Creating instances"
p21population = Part21Population(p21loader)

View File

@ -0,0 +1,39 @@
# Copyright (c) 2011-2012, Thomas Paviot (tpaviot@gmail.com)
# All rights reserved.
# This file is part of the StepClassLibrary (SCL).
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# Neither the name of the <ORGANIZATION> nor the names of its contributors may
# be used to endorse or promote products derived from this software without
# specific prior written permission.
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
__doc__ = "This module defines EXPRESS rules"
class Rule(object):
'''
This class describes a RULE
@TODO: to be implemented
'''
pass

View File

@ -0,0 +1,44 @@
# Copyright (c) 2011, Thomas Paviot (tpaviot@gmail.com)
# All rights reserved.
# This file is part of the StepClassLibrary (SCL).
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# Neither the name of the <ORGANIZATION> nor the names of its contributors may
# be used to endorse or promote products derived from this software without
# specific prior written permission.
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
class BaseEntityClass(object):
""" A class that allows advanced __repr__ features for entity instances
"""
def __repr__(self):
""" Displays attribute with their values
"""
doc_string = "# %s class description:\n%s\n# Instance attributes:\n"%(self.__class__,self.__doc__)
# write each argument with its value
properties = dir(self)
for elem in properties:
if not elem.startswith("_"):
doc_string += "\t%s:%s\n"%(elem,self.__getattribute__(elem))
return doc_string

View File

@ -0,0 +1,216 @@
# Copyright (c) 2011, Thomas Paviot (tpaviot@gmail.com)
# All rights reserved.
# This file is part of the StepClassLibrary (SCL).
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# Neither the name of the <ORGANIZATION> nor the names of its contributors may
# be used to endorse or promote products derived from this software without
# specific prior written permission.
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""
Docstrings are courtesy of ISO 10303-11:1994(E)
"""
class NUMBER:
"""
EXPRESS definition:
===================
The number data type has as its domain all numeric values in the language. The number data
type shall be used when a more speci c numeric representation is not important.
Syntax:
248 number_type = NUMBER .
EXAMPLE 15 - Since we may not know the context of size we do not know how to correctly
represent it, e.g. the size of the crowd at a football game would be an integer, whereas the area
of the pitch would be a real.
size : NUMBER ;
Python definition:
==================
class NUMBER is an abstract class, aimed at being specialized.
"""
pass
class REAL(float,NUMBER):
"""
EXPRESS definition:
===================
The real data type has as its domain all rational, irrational and scientfic real numbers. It is
a specialization of the number data type.
Syntax:
265 real_type = REAL [ '(' precision_spec ')' ] .
255 precision_spec = numeric_expression .
Rational and irrational numbers have infnite resolution and are exact. Scientific numbers rep-
resent quantities which are known only to a specified precision. The precision_spec is stated
in terms of significant digits.
A real number literal is represented by a mantissa and optional exponent. The number of digits
making up the mantissa when all leading zeros have been removed is the number of significant
digits. The known precision of a value is the number of leading digits that are necessary to the
application.
Rules and restrictions:
a) The precision_spec gives the minimum number of digits of resolution that are re-
quired. This expression shall evaluate to a positive integer value.
b) When no resolution specification is given the precision of the real number is uncon-
strained.
Note 9.2.6:
integer and real are both specializations of number;
Python definition:
==================
REAL both inherits from float and NUMBER
"""
pass
class INTEGER(int,NUMBER):
"""
EXPRESS definition:
===================
The integer data type has as its domain all integer numbers. It is a specialization of the real
data type.
Syntax:
227 integer_type = INTEGER .
EXAMPLE 16 - This example uses an integer data type to represent an attribute named nodes.
The domain of this attribute is all integers, with no further constraint.
ENTITY foo;
nodes : INTEGER;
END_ENTITY;
Note 9.2.6: integer and real are both specializations of number;
Python definition:
==================
INTEGER both inherits from int and NUMBER
@TODO: note 9.2.6 tells that integer is a specialization of real
"""
pass
class STRING(str):
"""
The string data type has as its domain sequences of characters. The characters which are
permitted to form part of a string value are de ned in ISO 10646.
Syntax:
293 string_type = STRING [ width_spec ] .
318 width_spec = '(' width ')' [ FIXED ] .
317 width = numeric_expression .
A string data type may be de ned as either xed or varying width (number of characters). If
it is not specfically defined as fixed width (by using the fixed reserved word in the dfinition)
the string has varying width.
The domain of a xed width string data type is the set of all character sequences of exactly
the width speci ed in the type de nition.
The domain of a varying width string data type is the set of all character sequences of width
less than or equal to the maximum width speci ed in the type de nition.
If no width is speci ed, the domain is the set of all character sequences, with no constraint on
the width of these sequences.
Substrings and individual characters may be addressed using subscripts as described in 12.5.
The case (upper or lower) of letters within a string is signi cant.
Python mapping: INTEGER is mapped the 'str' type. An additional width_spec parameter can be passed
to handle the FIXED length constraint
"""
pass
class LOGICAL:
"""
The logical data type has as its domain the three literals true, false and unknown.
Syntax:
243 logical_type = LOGICAL .
The following ordering holds for the values of the logical data type: false < unknown <
true. The logical data type is compatible with the boolean data type, except that the value
unknown cannot be assigned to a boolean variable.
"""
pass
Unknown = LOGICAL()
#
#The boolean data type has as its domain the two literals true and false. The boolean data
#type is a specialization of the logical data type.
#
#Python mapping: BOOLEAN is mapped to 'bool' type
#
# The bool data type can't however be subclassed in Python (see
# See http://mail.python.org/pipermail/python-dev/2002-March/020822.html)
# so it is just set to bool
BOOLEAN = bool
class BINARY(str):
"""
The binary data type has as its domain sequences of bits, each bit being represented by 0 or 1.
Syntax:
172 binary_type = BINARY [ width_spec ] .
318 width_spec = '(' width ')' [ FIXED ] .
317 width = numeric_expression .
A binary data type may be defined as either fixed or varying width (number of bits). If it is
not specifically defined as fixed width (by using the fixed reserved word in the definition) the
binary data type has varying width.
The domain of a fixed width binary data type is the set of all bit sequences of exactly the width
speci ed in the type definition.
The domain of a varying width binary data type is the set of all bit sequences of width less
than or equal to the maximum width speci ed in the type de nition. If no width is specified,
the domain is the set of all bit sequences, with no constraint on the width of these sequences.
Subbinaries and individual bits may be addressed using subscripts as described in 12.3.
Python mapping: BINARY is mapped to the 'str' type. A check is performed to validate it is a binary
string representing a number.
"""
def __new__(self, value, width=-1, fixed=False):
return str.__new__(self, value)
def __init__(self, value, width=-1, fixed=False):
""" By default, lenght is set to None"""
self._specified_width = width
self._fixed = fixed
# Check implicit width
if (width!=-1) and not fixed:
raise ValueError("The 'width' parameter is passed but 'fixed' is still false. Please explicitely set 'fixed' to True to avoid implicit declaration")
# First check the string length if 'fixed' is set to True
if fixed:
if len(value) != width:
raise ValueError("The BINARY width %i is not consistent with the 'width' declaration(%i)"%(len(value),width))
# Check that the value passed is actually a binary
try:
int(value,2)
except ValueError:
raise ValueError("%s is not a binary"%value)
if __name__=="__main__":
print "Creating REAL from float value"
a = REAL(1.5)
print a*2
print "Creating REAL from string value"
a = REAL("1.2")
print a*3
print "Creating INTEGER from int value"
b = INTEGER(2)
c = INTEGER(3)
print b+c
print "Creating INTEGER from string value"
e = INTEGER("5")
f = INTEGER("8")
print e*f

View File

@ -0,0 +1,101 @@
# Copyright (c) 2011, Thomas Paviot (tpaviot@gmail.com)
# All rights reserved.
# This file is part of the StepClassLibrary (SCL).
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# Neither the name of the <ORGANIZATION> nor the names of its contributors may
# be used to endorse or promote products derived from this software without
# specific prior written permission.
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from ConstructedDataTypes import ENUMERATION, SELECT
import BaseType
RAISE_EXCEPTION_IF_TYPE_DOES_NOT_MATCH = True
DEBUG = False
def cast_python_object_to_aggregate(obj, aggregate):
""" This function casts a python object to an aggregate type. For instance:
[1.,2.,3.]-> ARRAY(1,3,REAL)"""
aggregate_lower_bound = aggregate.bound_1()
aggregate_upper_bound = aggregate.bound_2()
if type(obj)==list:
for idx in range(aggregate_lower_bound,aggregate_upper_bound+1):
aggregate[idx] = obj[idx-aggregate_lower_bound]
return aggregate
def check_type(instance, expected_type):
""" This function checks wether an object is an instance of a given class
returns False or True
"""
type_match = False #by default, will be set to True if any match
if DEBUG:
print "==="
print "Instance passed: ",instance
print "Expected type: ", expected_type
# in the case of an enumeration, we have to check if the instance is in the list
if (isinstance(expected_type,ENUMERATION)):
allowed_ids = expected_type.get_enum_ids()
if instance in allowed_ids:
type_match = True
else:
raise TypeError('Enumeration ids must be %s ( passed %s)'%(allowed_ids,type(instance)))
elif (isinstance(expected_type,SELECT)):
# we check if the instance is of the type of any of the types that are in the SELECT
allowed_types = expected_type.get_allowed_basic_types()
for allowed_type in allowed_types:
if isinstance(instance,allowed_type):
type_match = True
if not type_match:
if RAISE_EXCEPTION_IF_TYPE_DOES_NOT_MATCH:
raise TypeError('Argument type must be %s (you passed %s)'%(allowed_types,type(instance)))
else:
print "WARNING: expected '%s' but passed a '%s', casting from python value to EXPRESS type"%(allowed_types, type(instance))
return False
elif (isinstance(expected_type, BaseType.Aggregate)):
# first check that they are instance of the same class
if not (type(instance) == type(expected_type)):
raise TypeError('Expected %s but passed %s'%(type(expected_type),type(instance)))
# then check that the base type is the same
elif not (instance.get_type() == expected_type.get_type()):
#print instance.get_type()
#print expected_type.get_type()
raise TypeError('Expected %s:%s base type but passed %s:%s base type'%(type(expected_type),expected_type.get_type(),type(instance), instance.get_type()))
# check optional and unique attributes
#elif not (instance._unique == expected_type._unique):
# raise TypeError('Aggregate expects UNIQUE:%s property but passed UNIQUE:%s'%(expected_type._unique, instance._unique))
#elif not (instance._optional == expected_type._optional):
# raise TypeError('Aggregate expects OPTIONAL:%s property but passed OPTIONAL:%s'%(expected_type._optional, instance._optional))
# @TODO: check aggregate bounds
else:
type_match = True
else: # simple data types
type_match = isinstance(instance,expected_type)
if not type_match:
if RAISE_EXCEPTION_IF_TYPE_DOES_NOT_MATCH:
raise TypeError('Argument type must be %s (you passed %s)'%(expected_type,type(instance)))
else:
print "WARNING: expected '%s' but passed a '%s', casting from python value to EXPRESS type"%(expected_type, type(instance))
return False
return True

View File

@ -0,0 +1,70 @@
# Copyright (c) 2011, Thomas Paviot (tpaviot@gmail.com)
# All rights reserved.
# This file is part of the StepClassLibrary (SCL).
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# Neither the name of the <ORGANIZATION> nor the names of its contributors may
# be used to endorse or promote products derived from this software without
# specific prior written permission.
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
''' This module provide string utils'''
def process_nested_parent_str(attr_str,idx=0):
'''
The first letter should be a parenthesis
input string: "(1,4,(5,6),7)"
output: ['1','4',['5','6'],'7']
'''
params = []
current_param = ''
k = 0
while (k<len(attr_str)):
ch = attr_str[k]
k += 1
if ch==',':
params.append(current_param)
current_param = ''
elif ch=='(':
nv = attr_str[k:]
current_param, progress = process_nested_parent_str(nv)
params.append(current_param)
current_param = ''
k += progress+1
elif ch==')':
params.append(current_param)
return params,k
else:
current_param += ch
params.append(current_param)
return params,k
if __name__=="__main__":
print process_nested_parent_str2("'A'")[0]
print process_nested_parent_str2("30.0,0.0,5.0")[0]
print process_nested_parent_str2("1,2,(3,4,5),6,7,8")[0]
print process_nested_parent_str2("(#9149,#9166),#9142,.T.")[0]

View File

@ -0,0 +1 @@
__all__ = ['SCLBase','SimpleDataTypes','AggregationDataTypes','TypeChecker','ConstructedDataTypes','Expr','Part21']

View File

@ -0,0 +1,74 @@
def process_nested_parent_str(attr_str):
'''
The first letter should be a parenthesis
input string: "(1,4,(5,6),7)"
output: tuple (1,4,(4,6),7)
'''
params = []
agg_scope_level = 0
current_param = ''
for i,ch in enumerate(attr_str):
if ch==',':
params.append(current_param)
current_param = ''
elif ch=='(':
agg_scope_level +=1
elif ch==')':
agg_scope_level = 0
elif agg_scope_level == 0:
current_param += ch
return params
def process_nested_parent_str2(attr_str,idx=0):
'''
The first letter should be a parenthesis
input string: "(1,4,(5,6),7)"
output: ['1','4',['5','6'],'7']
'''
#print 'Entering function with string %s'%(attr_str)
params = []
current_param = ''
k = 0
while (k<len(attr_str)):
#print 'k in this function:%i'%k
ch = attr_str[k]
k += 1
if ch==',':
#print "Add param:",current_param
params.append(current_param)
current_param = ''
elif ch=='(':
nv = attr_str[k:]
#print "Up one level parenthesis:%s"%(nv)
current_param, progress = process_nested_parent_str2(nv)
#print "Adding the list returned from nested",current_param
params.append(current_param)
current_param = ''
k += progress+1
elif ch==')':
#print "Down one level parenthesis: %i caracters parsed"%k
params.append(current_param)
#print "Current params:",params#k -= acc-2
return params,k
else:
current_param += ch
#print "Ch:",ch
#print "k:",k
#raw_input("")
#idx += 1
params.append(current_param)
return params,k
#print process_nested_parent_str2('1,2,3,4,5,6')
#idx=0
#print process_nested_parent_str2("'A','B','C'")
print process_nested_parent_str2("'A'")[0]
print process_nested_parent_str2("30.0,0.0,5.0")[0]
print process_nested_parent_str2("(Thomas)")[0]
print process_nested_parent_str2("Thomas, Paviot, ouais")[0]
print process_nested_parent_str2("1,2,(3,4,5),6,7,8")[0]
print process_nested_parent_str2("(#9149,#9166),#9142,.T.")[0]

File diff suppressed because it is too large Load Diff

37012
src/Mod/Import/App/ifc2x3.py Normal file

File diff suppressed because it is too large Load Diff

43883
src/Mod/Import/App/ifc4.py Normal file

File diff suppressed because it is too large Load Diff

View File

@ -25,8 +25,12 @@ ADD_CUSTOM_TARGET(Material ALL
SOURCES ${all_files}
)
fc_copy_sources(Material "${CMAKE_BINARY_DIR}/Mod/Material" ${all_files})
#fc_copy_sources(Material "${CMAKE_BINARY_DIR}/Mod/Material" ${Material_SRCS})
fc_target_copy_resource(Material
${CMAKE_SOURCE_DIR}/src/Mod/Material
${CMAKE_BINARY_DIR}/Mod/Material
${Material_SRCS})
fc_target_copy_resource(Material
${CMAKE_SOURCE_DIR}/src/Mod/Material