Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • kit/virtmat-tools/vre-language
1 result
Show changes
Commits on Source (11)
Showing
with 395 additions and 137 deletions
...@@ -61,6 +61,7 @@ def variable_type(self): ...@@ -61,6 +61,7 @@ def variable_type(self):
def expression_type(self): def expression_type(self):
"""evaluate expression type""" """evaluate expression type"""
# a possible problem to distiguish (int, float) from tuple or table type
if not hasattr(self, '__type'): if not hasattr(self, '__type'):
if all(op.type_ == float for op in self.operands): if all(op.type_ == float for op in self.operands):
self.__type = float self.__type = float
...@@ -79,6 +80,7 @@ def expression_type(self): ...@@ -79,6 +80,7 @@ def expression_type(self):
def term_type(self): def term_type(self):
"""evaluate term type""" """evaluate term type"""
# a possible problem to distiguish (int, float) from tuple or table type
if not hasattr(self, '__type'): if not hasattr(self, '__type'):
otypes = [o.type_ for o in self.operands] otypes = [o.type_ for o in self.operands]
if all(t == int for t in otypes) and all(o != '/' for o in self.operators): if all(t == int for t in otypes) and all(o != '/' for o in self.operators):
...@@ -142,6 +144,7 @@ def if_expression_type(self): ...@@ -142,6 +144,7 @@ def if_expression_type(self):
def comparison_type(self): def comparison_type(self):
"""evaluate comparison type""" """evaluate comparison type"""
# a possible problem to distiguish (int, float) from tuple or table type
num_type = (int, float, (int, float)) num_type = (int, float, (int, float))
numbers = self.left.type_ in num_type and self.right.type_ in num_type numbers = self.left.type_ in num_type and self.right.type_ in num_type
booleans = self.left.type_ == bool and self.right.type_ == bool booleans = self.left.type_ == bool and self.right.type_ == bool
...@@ -157,7 +160,6 @@ def comparison_type(self): ...@@ -157,7 +160,6 @@ def comparison_type(self):
def var_reference_type(self): def var_reference_type(self):
"""evaluate the type of a referenced variable""" """evaluate the type of a referenced variable"""
if not hasattr(self, '__type'): if not hasattr(self, '__type'):
# to do: inference in case: if self.ref.type_ == None
self.__type = self.ref.type_ self.__type = self.ref.type_
return self.__type return self.__type
...@@ -248,41 +250,62 @@ def var_tuple_type(self): ...@@ -248,41 +250,62 @@ def var_tuple_type(self):
def series_type(self): def series_type(self):
"""evaluate / check the type of a series""" """evaluate / check the type of a series"""
if not hasattr(self, '__type'): if not hasattr(self, '__type'):
types = set(element.type_ for element in self.elements) if not self.need_input:
types.discard(None) types = set(element.type_ for element in self.elements)
try: types.discard(None)
assert len(types) == 1 try:
except AssertionError as err: assert len(types) == 1
msg = f'series elements must have one type but {len(types)} types ' except AssertionError as err:
msg += f'were found:\nloc: {repr(get_location(self))}' msg = f'series elements must have one type but {len(types)}'
raise TypeError(msg) from err msg += f' types were found:\nloc: {repr(get_location(self))}'
raise TypeError(msg) from err
else:
self.__type = (next(iter(types)), len(self.elements))
else: else:
self.__type = (next(iter(types)), len(self.elements)) self.__type = None
return self.__type return self.__type
def table_type(self): def table_type(self):
"""evaluate / check the types in a table object""" """evaluate / check the types in a table object"""
if not hasattr(self, '__type'): if not hasattr(self, '__type'):
ctype = get_metamodel(self)['Series'] if not self.need_input:
assert all(textx_isinstance(c, ctype) for c in self.columns) meta = get_metamodel(self)
types = [c.type_ for c in self.columns] ctype = meta['Series']
sizes = set(map(lambda x: x[1], types)) if self.columns_tuple:
try: msg = ('a table column must be series or a reference:\n'
assert len(sizes) == 1 f'loc: {repr(get_location(self))}')
except AssertionError as err: for par in self.columns_tuple.params:
msg = f'table columns must have one size but {len(sizes)} sizes ' if textx_isinstance(par, meta['Series']):
msg += f'were found:\nloc: {repr(get_location(self))}' self.columns.append(par)
raise ValueError(msg) from err elif textx_isinstance(par, meta['VarReference']):
try:
assert textx_isinstance(par.ref.parameter, ctype)
except AssertionError as err:
raise TypeError(msg) from err
self.columns.append(par.ref.parameter)
else:
raise TypeError(msg)
assert all(textx_isinstance(c, ctype) for c in self.columns)
types = [c.type_ for c in self.columns]
sizes = set(map(lambda x: x[1], types))
try:
assert len(sizes) == 1
except AssertionError as err:
msg = f'table columns must have one size but {len(sizes)} sizes '
msg += f'were found:\nloc: {repr(get_location(self))}'
raise ValueError(msg) from err
else:
self.__type = (tuple(map(lambda x: x[0], types)), next(iter(sizes)))
names = [c.name for c in self.columns]
try:
assert len(set(names)) == len(names)
except AssertionError as err:
msg = ('repeating column names were found in table:\n'
f'loc: {repr(get_location(self))}')
raise ValueError(msg) from err
else: else:
self.__type = (tuple(map(lambda x: x[0], types)), next(iter(sizes))) self.__type = None
names = [c.name for c in self.columns]
try:
assert len(set(names)) == len(names)
except AssertionError as err:
msg = ('repeating column names were found in table:\n'
f'loc: {repr(get_location(self))}')
raise ValueError(msg) from err
return self.__type return self.__type
...@@ -358,6 +381,9 @@ def add_type_properties(metamodel): ...@@ -358,6 +381,9 @@ def add_type_properties(metamodel):
metamodel['Term'].type_ = property(term_type) metamodel['Term'].type_ = property(term_type)
metamodel['Expression'].type_ = property(expression_type) metamodel['Expression'].type_ = property(expression_type)
metamodel['Operand'].type_ = property(operand_type) metamodel['Operand'].type_ = property(operand_type)
# a possible problem to distiguish (int, float) from tuple or table type
metamodel['Number'].type_ = (int, float)
metamodel['Bool'].type_ = bool
metamodel['String'].type_ = str metamodel['String'].type_ = str
metamodel['Null'].type_ = type(None) metamodel['Null'].type_ = type(None)
metamodel['BooleanOperand'].type_ = property(operand_type) metamodel['BooleanOperand'].type_ = property(operand_type)
......
true
""" first case: ordering of statements """
sqr(x) = x*x
one_minus_sqr(y) = sqr(y)
a = one_minus_sqr(2)
print(a) # 4
b = one_minus_sqr2(2)
one_minus_sqr2(y) = sqr(y)
print(b) # 4
""" second case: use of dummies with the same names """
# this works in either ordering:
f1(x) = (f2(4) + x)
f2(y) = 2*y
print(f1(2)) # 10
# but this does not:
# f1(x) = (f2(4) + x)
# f2(x) = 2*x
"""
Traceback (most recent call last):
File "../scripts/run_model.py", line 19, in <module>
program = meta.model_from_file(model_file)
File "/home/ubuntu/python3-venv/lib/python3.8/site-packages/textx/metamodel.py", line 634, in model_from_file
return self.internal_model_from_file(
File "/home/ubuntu/python3-venv/lib/python3.8/site-packages/textx/metamodel.py", line 688, in internal_model_from_file
p(model, self)
File "/home/ubuntu/vre-language/constraints/functions.py", line 61, in check_functions_processor
check_function_definition(func, metamodel)
File "/home/ubuntu/vre-language/constraints/functions.py", line 29, in check_function_definition
assert not any(d in args_uniq_names for d in call_dummies)
AssertionError
"""
# without a function call in the function definition, it works:
fx1(x) = 1 + x
fx2(x) = 2*x
print(fx1(2)) # 3
""" other cases """
g3(z) = 4*z
g2(y) = 3*g3(y)
g1(x) = 2*g2(x)
print(g1(1)) # 24
h3(z) = h2(3*z)
h2(y) = 3*y+h1(y)
h1(x) = x
print(h3(1)) # 12
g(y) = y
f(x) = g(3*x)
print(f(1), f(2), f(3)) # 3 6 9
a = String from file 'string_in.yaml'
a to file 'string_out.yaml'
e = Bool from file 'bool_in.yaml'
e to file 'bool_out.yaml'
f = Number from file 'number_in.yaml'
f to file 'number_out.yaml'
b = Number from url 'https://git.scc.kit.edu/th7356/wfgenes/-/raw/master/intro_examples/foreach_sample/inputs/constant_y.yaml'
c = Series from file 'series_in.yaml'
c to file 'series_out.yaml'
d = Table from file 'table_in.yaml'
d to file 'table_out.yaml'
3.14
data:
- 1.0
- 2.0
- 3.0
name: temperature
domain specific languages help a lot!
pressure:
- 100.0
- 200.0
- 300.0
temperature:
- 1.0
- 2.0
- 3.0
s1 = (booleans: true, false)
s2 = (floats: 1.2, -3.5)
t1 = Table with columns=(s1, s2)
t2 = Table with columns=((booleans: true, false), (floats: 1.2, -3.5))
t3 = Table with columns=(s2, (booleans: true, false))
print(t1)
print(t2)
print(t3)
# a = 3; b = 4; t4 = Table with columns=(a, s1) # TypeError
Keyword:
/(String|Series|Number|Bool|Table|null|true|false|not|and|or|if|else|print|use|from|all|any|select|where)\W/
;
TrueID:
!Keyword ID
;
Dummy:
name = TrueID &/,|\)/
;
FQN: ID ('.' ID)*;
/* object imports */
import identifiers
ObjectImports:
('use' namespace = TrueID '.' names = ObjectImport) |
('use' names += ObjectImport[','] ('from' namespace += TrueID['.'])?)
;
ObjectImport:
name = TrueID (namespace += /\w$/)?
// requires object processor to obtain 'namespace' from its parent
;
/* built-in types */
TrueBOOL:
!/[0-9]/ BOOL
;
Null:
str_repr = 'null'
;
PlainType:
Number | Bool | String
;
Number:
( 'Number' need_input ?= 'from'
( 'url' url = STRING | 'file' filename = STRING )
) | ( __value = NUMBER )
;
Bool:
( 'Bool' need_input ?= 'from'
( 'url' url = STRING | 'file' filename = STRING )
) | ( __value = TrueBOOL )
;
String:
( 'String' need_input ?= 'from'
( 'url' url = STRING | 'file' filename = STRING )
) | ( __value = STRING )
;
/* Model for virtmat modeling language */ /* Model for virtmat modeling language */
import imports
import identifiers
import types
Program: Program:
statements *= Statement[/^|;/] statements *= Statement[/^|;/]
; ;
Statement: Statement:
ObjectImports | VarTuple | FunctionDefinition | IfStatement | ObjectImports | VarTuple | FunctionDefinition | IfStatement | ObjectTo |
Variable | Print Variable | Print
; ;
...@@ -22,11 +27,20 @@ Tuple: ...@@ -22,11 +27,20 @@ Tuple:
; ;
Series: Series:
'(' name = TrueID ':' elements += Parameter[','] ')' ( 'Series' need_input ?= 'from'
( 'url' url = STRING | 'file' filename = STRING )
) | ( '(' name = TrueID ':' elements += Parameter[','] ')' )
; ;
Table: Table:
'(' columns += Series[','] ')' ( 'Table' need_input ?= 'from'
( 'url' url = STRING | 'file' filename = STRING )
) | ( 'Table' with_attr ?= 'with' 'columns' '=' columns_tuple = Tuple
) | ( '(' columns += Series[','] ')' )
;
Object:
Table | Series | Tuple
; ;
Property: Property:
...@@ -68,10 +82,6 @@ Variable: ...@@ -68,10 +82,6 @@ Variable:
name = TrueID &/,|\)|=/ ('=' parameter = Parameter)? name = TrueID &/,|\)|=/ ('=' parameter = Parameter)?
; ;
Dummy:
name = TrueID &/,|\)/
;
VarReference: VarReference:
!Keyword !Keyword
ref = [GeneralVariable|FQN|^args, statements, ~statements.names, ref = [GeneralVariable|FQN|^args, statements, ~statements.names,
...@@ -120,14 +130,6 @@ Operand: ...@@ -120,14 +130,6 @@ Operand:
('(' op_expr = Expression ')') ('(' op_expr = Expression ')')
; ;
Keyword:
/(null|true|false|not|and|or|if|else|print|use|from|all|any|select|where)\W/
;
TrueID:
!Keyword ID
;
/* boolean expressions */ /* boolean expressions */
Or: Or:
...@@ -153,18 +155,6 @@ BooleanOperand: ...@@ -153,18 +155,6 @@ BooleanOperand:
( '(' op_expr = BooleanExpression ')' ) ( '(' op_expr = BooleanExpression ')' )
; ;
TrueBOOL:
!/[0-9]/ BOOL
;
Null:
str_repr = 'null'
;
String:
value = STRING
;
// print function // print function
Print: Print:
...@@ -172,15 +162,15 @@ Print: ...@@ -172,15 +162,15 @@ Print:
; ;
Parameter: Parameter:
Null | IfFunction | FunctionCall | IfExpression | Comparison | Null | IfFunction | FunctionCall | IfExpression | Comparison | Property |
Property | VarReferenceTerm | Expression | BooleanExpression | String | Table | VarReferenceTerm | Expression | BooleanExpression | Object | PlainType
Tuple | Series
; ;
/* if expressions and if function */ /* if expressions and if function */
IfExpressionParameter: IfExpressionParameter:
Null | IfFunction | VarReference | Expression | BooleanExpression | String Null | IfFunction | VarReference | Expression | BooleanExpression | Object |
PlainType
; ;
IfStatement: IfStatement:
...@@ -208,7 +198,7 @@ IfFunction: ...@@ -208,7 +198,7 @@ IfFunction:
/* comparison operators */ /* comparison operators */
GeneralExpression: GeneralExpression:
Null | FunctionCall | VarReferenceTerm | Expression | Or | String Null | FunctionCall | VarReferenceTerm | Expression | Or | Object | PlainType
; ;
Comparison: Comparison:
...@@ -250,18 +240,12 @@ FunctionCall: ...@@ -250,18 +240,12 @@ FunctionCall:
// requires model processor to obtain a copy of expr from FunctionDefinition // requires model processor to obtain a copy of expr from FunctionDefinition
; ;
ObjectImports: /* built-in i/o operations */
('use' namespace = TrueID '.' names = ObjectImport) |
('use' names += ObjectImport[','] ('from' namespace += TrueID['.'])?)
;
ObjectImport: ObjectTo:
name = TrueID (namespace += /\w$/)? ref = [Variable] 'to' ( 'url' url = STRING | 'file' filename = STRING )
// requires object processor to obtain 'namespace' from its parent
; ;
FQN: ID('.'ID)*;
/* single-line and multi-line comments */ /* single-line and multi-line comments */
Comment: Comment:
......
import os, sys import os, sys
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from . import ioops
from instant_executor import add_value_properties from instant_executor import add_value_properties
...@@ -7,6 +7,7 @@ from textx import textx_isinstance ...@@ -7,6 +7,7 @@ from textx import textx_isinstance
from textx import get_metamodel from textx import get_metamodel
from textx import get_children_of_type, get_parent_of_type from textx import get_children_of_type, get_parent_of_type
from constraints import get_object_import from constraints import get_object_import
import ioops
def is_active_branch(obj): def is_active_branch(obj):
...@@ -25,8 +26,12 @@ def is_active_branch(obj): ...@@ -25,8 +26,12 @@ def is_active_branch(obj):
def program_value(self): def program_value(self):
""" """
Evaluate variables regardless of the order of definition and returns only Evaluate variables regardless of the order of definition and returns only
printed values in a single string printed values in a single string. The output objects are evaluated in order
of definition. The output objects are currently processed in this order:
(ObjectTo, Print)
""" """
for obj in get_children_of_type('ObjectTo', self):
_ = obj.value
vals = [p.value for p in get_children_of_type('Print', self) if p.value] vals = [p.value for p in get_children_of_type('Print', self) if p.value]
return '\n'.join(vals) return '\n'.join(vals)
...@@ -222,15 +227,21 @@ def tuple_value(self): ...@@ -222,15 +227,21 @@ def tuple_value(self):
def series_value(self): def series_value(self):
"""Evaluate a series object""" """Evaluate a series object"""
if not hasattr(self, '__value'): if not hasattr(self, '__value'):
elements = (e.value for e in self.elements) if self.need_input:
self.__value = pandas.Series(name=self.name, data=elements) self.load()
else:
elements = (e.value for e in self.elements)
self.__value = pandas.Series(name=self.name, data=elements)
return self.__value return self.__value
def table_value(self): def table_value(self):
"""Evaluate a table object""" """Evaluate a table object"""
if not hasattr(self, '__value'): if not hasattr(self, '__value'):
self.__value = pandas.concat((c.value for c in self.columns), axis=1) if self.need_input:
self.load()
else:
self.__value = pandas.concat((c.value for c in self.columns), axis=1)
return self.__value return self.__value
...@@ -262,6 +273,34 @@ def object_property_value(self): ...@@ -262,6 +273,34 @@ def object_property_value(self):
return self.__value return self.__value
def plain_type_value(self):
"""Evaluate an object of plain type"""
if self.__value is None:
if self.need_input:
self.load()
return self.__value
def object_to_value(self):
"""Store an object to file or url"""
if not hasattr(self, '__value'):
obj_val = self.ref.parameter.value
if isinstance(obj_val, pandas.Series):
val = dict(data=obj_val.to_list(), name=obj_val.name)
elif isinstance(obj_val, pandas.DataFrame):
val = obj_val.to_dict(orient='list')
else:
val = obj_val
try:
ioops.store_value(val, self.url, self.filename)
except OSError:
self.__value = False
raise
else:
self.__value = True
return self.__value
def add_value_properties(metamodel): def add_value_properties(metamodel):
"""Add object class properties using monkey style patching""" """Add object class properties using monkey style patching"""
metamodel['Program'].value = property(program_value) metamodel['Program'].value = property(program_value)
...@@ -276,6 +315,7 @@ def add_value_properties(metamodel): ...@@ -276,6 +315,7 @@ def add_value_properties(metamodel):
metamodel['Or'].value = property(or_value) metamodel['Or'].value = property(or_value)
metamodel['Not'].value = property(not_value) metamodel['Not'].value = property(not_value)
metamodel['Print'].value = property(print_value) metamodel['Print'].value = property(print_value)
metamodel['ObjectTo'].value = property(object_to_value)
metamodel['IfStatement'].value = property(if_statement_value) metamodel['IfStatement'].value = property(if_statement_value)
metamodel['IfExpression'].value = property(if_expression_value) metamodel['IfExpression'].value = property(if_expression_value)
metamodel['IfFunction'].value = property(if_expression_value) metamodel['IfFunction'].value = property(if_expression_value)
...@@ -293,3 +333,6 @@ def add_value_properties(metamodel): ...@@ -293,3 +333,6 @@ def add_value_properties(metamodel):
metamodel['SeriesProperty'].value = property(object_property_value) metamodel['SeriesProperty'].value = property(object_property_value)
metamodel['ObjectProperty'].value = property(object_property_value) metamodel['ObjectProperty'].value = property(object_property_value)
metamodel['Null'].value = None metamodel['Null'].value = None
metamodel['String'].value = property(plain_type_value)
metamodel['Number'].value = property(plain_type_value)
metamodel['Bool'].value = property(plain_type_value)
""" i/o operations """
from urllib.request import urlopen
# from urllib import request, parse
import yaml
def load_value(url=None, filename=None):
"""load data from file or from URL using the GET method"""
assert url or filename
if filename:
with open(filename, 'r') as inp:
val = yaml.safe_load(inp)
elif url:
with urlopen(url) as inp:
val = yaml.safe_load(inp)
return val
def store_value(val, url=None, filename=None):
"""store data to a new file or to an URL using the POST method"""
assert url or filename
if filename:
with open(filename, 'x') as out:
yaml.safe_dump(val, out)
elif url:
raise NotImplementedError
# data = parse.urlencode(val).encode()
# req = request.Request(url, data=data)
# resp = request.urlopen(req)
...@@ -10,6 +10,8 @@ def __deepcopy__(self, memo): ...@@ -10,6 +10,8 @@ def __deepcopy__(self, memo):
if key == 'parent': if key == 'parent':
# must stay a reference # must stay a reference
result.parent = self.parent result.parent = self.parent
elif key == 'func':
result.func = self.func
else: else:
# must be copied # must be copied
setattr(result, key, deepcopy(val, memo)) setattr(result, key, deepcopy(val, memo))
...@@ -21,7 +23,6 @@ def add_deepcopy(metamodel): ...@@ -21,7 +23,6 @@ def add_deepcopy(metamodel):
"""Add deepcopy method to metamodel classes using monkey style patching""" """Add deepcopy method to metamodel classes using monkey style patching"""
metamodel['IfExpression'].__deepcopy__ = __deepcopy__ metamodel['IfExpression'].__deepcopy__ = __deepcopy__
metamodel['IfFunction'].__deepcopy__ = __deepcopy__ metamodel['IfFunction'].__deepcopy__ = __deepcopy__
metamodel['FunctionDefinition'].__deepcopy__ = __deepcopy__
metamodel['FunctionCall'].__deepcopy__ = __deepcopy__ metamodel['FunctionCall'].__deepcopy__ = __deepcopy__
metamodel['Variable'].__deepcopy__ = __deepcopy__ metamodel['Variable'].__deepcopy__ = __deepcopy__
metamodel['Dummy'].__deepcopy__ = __deepcopy__ metamodel['Dummy'].__deepcopy__ = __deepcopy__
......
# pylint: disable=protected-access # pylint: disable=protected-access
"""properties and attributes of FunctionCall class""" """properties and attributes of FunctionCall class"""
from copy import deepcopy from copy import deepcopy
from textx import get_children_of_type, get_children from textx import get_children_of_type, get_children, get_parent_of_type
from textx import get_metamodel from textx import get_metamodel
from textx import textx_isinstance from textx import textx_isinstance
...@@ -9,60 +9,19 @@ comparisons = ['Equal', 'LessThan', 'GreaterThan', 'LessThanOrEqual', ...@@ -9,60 +9,19 @@ comparisons = ['Equal', 'LessThan', 'GreaterThan', 'LessThanOrEqual',
'GreaterThanOrEqual'] 'GreaterThanOrEqual']
def substitute_vref(vref, param, metamodel):
"""substitute variable reference with a parameter"""
if (textx_isinstance(vref.parent, metamodel['Operand']) or
textx_isinstance(vref.parent, metamodel['BooleanOperand'])):
if textx_isinstance(param, metamodel['VarReference']):
vref.parent.op_id = param
vref.parent.op_func = None
vref.parent.op_expr = None
elif textx_isinstance(param, metamodel['FunctionCall']):
vref.parent.op_func = param
vref.parent.op_expr = None
vref.parent.op_id = None
else:
vref.parent.op_expr = param
vref.parent.op_func = None
vref.parent.op_id = None
elif any(textx_isinstance(vref.parent, metamodel[c]) for c in comparisons):
if vref is vref.parent.left:
vref.parent.left = param
else:
vref.parent.right = param
elif textx_isinstance(vref.parent, metamodel['FunctionCall']):
if vref.parent.__expr is vref:
vref.parent.__expr = param
else:
assert param.parent is not vref.parent
vref.ref = param
elif textx_isinstance(vref.parent, metamodel['IfFunction']):
if vref is vref.parent.expr:
vref.parent.expr = param
elif vref is vref.parent.true_:
vref.parent.true_ = param
else:
vref.parent.false_ = param
elif textx_isinstance(vref.parent, metamodel['Tuple']):
vref.ref = param
else:
raise RuntimeError
def complete_expr(self): def complete_expr(self):
"""substitute all references to dummy variables with call parameters""" """substitute all references to dummy variables with call parameters"""
if not (hasattr(self, '_expr_complete') and self._expr_complete): meta = get_metamodel(self)
for call in get_children_of_type('FunctionCall', self.__expr): vrefs = get_children_of_type('VarReference', self.__expr)
call.complete_expr() for vref in filter(lambda x: textx_isinstance(x.ref, meta['Dummy']), vrefs):
meta = get_metamodel(self) if hasattr(vref.ref, 'name'):
vrefs = get_children_of_type('VarReference', self.__expr) for par, arg in zip(self.params, self.func.args):
dummy = meta['Dummy'] if vref.ref.name == arg.name:
for vref in filter(lambda x: textx_isinstance(x.ref, dummy), vrefs): if textx_isinstance(par, meta['VarReference']):
rname = vref.ref.name vref.ref = par.ref
pargs = zip(self.params, self.func.args) else:
args = next((vref, p, meta) for p, a in pargs if rname == a.name) vref.ref = par
substitute_vref(*args) break
self._expr_complete = True
return self.__expr return self.__expr
...@@ -74,13 +33,16 @@ def add_function_call_properties(metamodel): ...@@ -74,13 +33,16 @@ def add_function_call_properties(metamodel):
def function_call_processor(model, metamodel): def function_call_processor(model, metamodel):
"""copy expression tree from the function definition object""" """copy expression tree from the function definition object"""
for call in get_children_of_type('FunctionCall', model): if not get_parent_of_type('FunctionDefinition', model):
if textx_isinstance(call.func, metamodel['FunctionDefinition']): for call in get_children_of_type('FunctionCall', model):
call.__expr = deepcopy(call.func.expr) if not call.__expr:
new_objs = get_children(lambda x: True, call.__expr) if textx_isinstance(call.func, metamodel['FunctionDefinition']):
for new_obj in new_objs: call.__expr = deepcopy(call.func.expr)
if new_obj is not call.__expr: new_objs = get_children(lambda x: True, call.__expr)
new_obj.parent = new_obj.parent.last_copy for new_obj in new_objs:
call.__expr.parent = call if new_obj is not call.__expr:
else: new_obj.parent = new_obj.parent.last_copy
call.__expr = None call.__expr.parent = call
function_call_processor(call.expr, metamodel)
else:
call.__expr = None
# pylint: disable=protected-access
"""define loader methods"""
import pandas
from textx import get_metamodel
from interpreter import ioops
def load_plain_type(self):
"""load plain type object from a file or URL"""
assert self.need_input
self.__value = ioops.load_value(self.url, self.filename)
assert isinstance(self.__value, self.type_)
self.need_input = False
def load_series(self):
"""load a series object from a file or URL"""
assert self.need_input
val = ioops.load_value(self.url, self.filename)
assert isinstance(val, dict)
self.name = val['name']
self.elements = val['data']
self.need_input = False
self.__value = pandas.Series(**val)
self.__type = (type(self.__value[0].item()), len(self.elements))
def load_table(self):
"""load a table object from a file or URL"""
assert self.need_input
val = ioops.load_value(self.url, self.filename)
assert isinstance(val, dict)
self.__value = pandas.DataFrame.from_dict(val, orient='columns')
series = list(self.__value.to_dict(orient='series').values())
types = tuple(type(s[0].item()) for s in series)
self.__type = (types, len(self.__value))
self.columns = []
for ser, typ in zip(series, types):
ser_obj = get_metamodel(self)['Series']()
setattr(ser_obj, 'elements', ser.to_list())
setattr(ser_obj, 'name', ser.name)
setattr(ser_obj, 'parent', self)
setattr(ser_obj, 'need_input', False)
setattr(ser_obj, 'url', None)
setattr(ser_obj, 'filename', None)
# setattr(ser_obj, 'value', ser)
# setattr(ser_obj, 'type_', typ)
self.columns.append(ser_obj)
self.need_input = False
def add_object_loaders(metamodel):
"""add loader methods to metamodel classes"""
metamodel['String'].load = load_plain_type
metamodel['Number'].load = load_plain_type
metamodel['Bool'].load = load_plain_type
metamodel['Series'].load = load_series
metamodel['Table'].load = load_table
"""object and model processors""" """object and model processors"""
from function import function_call_processor
def object_import_processor(obj): def object_import_processor(obj):
...@@ -10,3 +11,4 @@ def add_processors(metamodel): ...@@ -10,3 +11,4 @@ def add_processors(metamodel):
"""register the processors on the metamodel instance""" """register the processors on the metamodel instance"""
obj_processors = {'ObjectImport': object_import_processor} obj_processors = {'ObjectImport': object_import_processor}
metamodel.register_obj_processors(obj_processors) metamodel.register_obj_processors(obj_processors)
metamodel.register_model_processor(function_call_processor)