2014-03-13 16:24:46 +04:00
|
|
|
# Copyright (c) 2014 Mirantis, Inc.
|
|
|
|
#
|
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
|
|
# not use this file except in compliance with the License. You may obtain
|
|
|
|
# a copy of the License at
|
|
|
|
#
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
#
|
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
|
|
# License for the specific language governing permissions and limitations
|
|
|
|
# under the License.
|
|
|
|
|
2015-07-21 16:56:43 +03:00
|
|
|
import itertools
|
2014-03-13 16:24:46 +04:00
|
|
|
|
2016-01-14 00:39:43 -08:00
|
|
|
import six
|
2015-07-21 16:56:43 +03:00
|
|
|
from yaql.language import specs
|
|
|
|
from yaql.language import utils
|
|
|
|
from yaql.language import yaqltypes
|
2014-03-13 16:24:46 +04:00
|
|
|
|
2015-09-20 21:57:45 +03:00
|
|
|
from murano.dsl import constants
|
2016-01-25 02:52:15 +03:00
|
|
|
from murano.dsl import dsl
|
2015-07-21 16:56:43 +03:00
|
|
|
from murano.dsl import dsl_types
|
|
|
|
from murano.dsl import exceptions
|
2016-01-25 02:52:15 +03:00
|
|
|
from murano.dsl import yaql_functions
|
2015-07-21 16:56:43 +03:00
|
|
|
from murano.dsl import yaql_integration
|
2014-03-13 16:24:46 +04:00
|
|
|
|
|
|
|
|
|
|
|
class LhsExpression(object):
|
|
|
|
class Property(object):
|
|
|
|
def __init__(self, getter, setter):
|
|
|
|
self._getter = getter
|
|
|
|
self._setter = setter
|
|
|
|
|
|
|
|
def get(self):
|
|
|
|
return self._getter()
|
|
|
|
|
|
|
|
def set(self, value):
|
|
|
|
self._setter(value)
|
|
|
|
|
|
|
|
def __init__(self, expression):
|
2015-09-20 21:57:45 +03:00
|
|
|
self._expression = expression
|
2014-03-13 16:24:46 +04:00
|
|
|
|
2015-07-21 16:56:43 +03:00
|
|
|
def _create_context(self, root_context):
|
2015-09-20 21:57:45 +03:00
|
|
|
@specs.parameter('name', yaqltypes.StringConstant())
|
|
|
|
def get_context_data(name):
|
2014-03-13 16:24:46 +04:00
|
|
|
|
|
|
|
def set_data(value):
|
2015-09-20 21:57:45 +03:00
|
|
|
if not name or name == '$' or name == '$this':
|
|
|
|
raise ValueError('Cannot assign to {0}'.format(name))
|
|
|
|
ctx = root_context
|
|
|
|
while constants.CTX_VARIABLE_SCOPE not in ctx:
|
|
|
|
ctx = ctx.parent
|
|
|
|
ctx[name] = value
|
2014-03-13 16:24:46 +04:00
|
|
|
|
|
|
|
return LhsExpression.Property(
|
2015-09-20 21:57:45 +03:00
|
|
|
lambda: root_context[name], set_data)
|
2015-07-21 16:56:43 +03:00
|
|
|
|
|
|
|
@specs.parameter('this', LhsExpression.Property)
|
|
|
|
@specs.parameter('key', yaqltypes.Keyword())
|
|
|
|
def attribution(this, key):
|
|
|
|
def setter(src_property, value):
|
|
|
|
src = src_property.get()
|
|
|
|
if isinstance(src, utils.MappingType):
|
|
|
|
src_property.set(
|
|
|
|
utils.FrozenDict(
|
|
|
|
itertools.chain(
|
2016-01-14 00:39:43 -08:00
|
|
|
six.iteritems(src),
|
2015-07-21 16:56:43 +03:00
|
|
|
((key, value),))))
|
|
|
|
elif isinstance(src, dsl_types.MuranoObject):
|
|
|
|
src.set_property(key, value, root_context)
|
2016-01-25 02:52:15 +03:00
|
|
|
elif isinstance(src, (
|
|
|
|
dsl_types.MuranoTypeReference,
|
2016-02-26 00:13:58 +03:00
|
|
|
dsl_types.MuranoType)):
|
|
|
|
if isinstance(src, dsl_types.MuranoTypeReference):
|
|
|
|
mc = src.type
|
2016-01-25 02:52:15 +03:00
|
|
|
else:
|
|
|
|
mc = src
|
|
|
|
mc.set_property(key, value, root_context)
|
2015-07-21 16:56:43 +03:00
|
|
|
else:
|
|
|
|
raise ValueError(
|
|
|
|
'attribution may only be applied to '
|
|
|
|
'objects and dictionaries')
|
|
|
|
|
|
|
|
def getter(src):
|
|
|
|
if isinstance(src, utils.MappingType):
|
|
|
|
return src.get(key, {})
|
|
|
|
elif isinstance(src, dsl_types.MuranoObject):
|
|
|
|
self._current_obj = src
|
|
|
|
self._current_obj_name = key
|
|
|
|
try:
|
|
|
|
return src.get_property(key, root_context)
|
|
|
|
except exceptions.UninitializedPropertyAccessError:
|
|
|
|
return {}
|
|
|
|
|
|
|
|
else:
|
|
|
|
raise ValueError(
|
|
|
|
'attribution may only be applied to '
|
|
|
|
'objects and dictionaries')
|
2014-03-13 16:24:46 +04:00
|
|
|
|
|
|
|
return LhsExpression.Property(
|
2015-07-21 16:56:43 +03:00
|
|
|
lambda: getter(this.get()),
|
|
|
|
lambda value: setter(this, value))
|
2014-03-13 16:24:46 +04:00
|
|
|
|
2015-07-21 16:56:43 +03:00
|
|
|
@specs.parameter('this', LhsExpression.Property)
|
|
|
|
@specs.parameter('index', yaqltypes.Lambda(with_context=True))
|
2014-03-13 16:24:46 +04:00
|
|
|
def indexation(this, index):
|
2015-07-21 16:56:43 +03:00
|
|
|
index = index(root_context)
|
|
|
|
|
|
|
|
def getter(src):
|
|
|
|
if utils.is_sequence(src):
|
|
|
|
return src[index]
|
|
|
|
else:
|
|
|
|
raise ValueError('indexation may only be applied to lists')
|
|
|
|
|
|
|
|
def setter(src_property, value):
|
|
|
|
src = src_property.get()
|
|
|
|
if utils.is_sequence(src):
|
|
|
|
src_property.set(src[:index] + (value,) + src[index + 1:])
|
2015-11-14 21:54:37 +03:00
|
|
|
elif isinstance(src, utils.MappingType):
|
|
|
|
attribution(src_property, index).set(value)
|
2015-07-21 16:56:43 +03:00
|
|
|
|
2015-10-29 20:02:36 +05:30
|
|
|
if isinstance(index, int):
|
2015-07-21 16:56:43 +03:00
|
|
|
return LhsExpression.Property(
|
|
|
|
lambda: getter(this.get()),
|
|
|
|
lambda value: setter(this, value))
|
|
|
|
else:
|
|
|
|
return attribution(this, index)
|
2014-03-13 16:24:46 +04:00
|
|
|
|
2016-01-25 02:52:15 +03:00
|
|
|
def _wrap_type_reference(tr):
|
|
|
|
return LhsExpression.Property(lambda: tr, self._invalid_target)
|
|
|
|
|
|
|
|
@specs.parameter('prefix', yaqltypes.Keyword())
|
|
|
|
@specs.parameter('name', yaqltypes.Keyword())
|
|
|
|
@specs.name('#operator_:')
|
|
|
|
def ns_resolve(prefix, name):
|
|
|
|
return _wrap_type_reference(
|
|
|
|
yaql_functions.ns_resolve(context, prefix, name))
|
|
|
|
|
|
|
|
@specs.parameter('name', yaqltypes.Keyword())
|
|
|
|
@specs.name('#unary_operator_:')
|
|
|
|
def ns_resolve_unary(context, name):
|
|
|
|
return _wrap_type_reference(
|
|
|
|
yaql_functions.ns_resolve_unary(context, name))
|
|
|
|
|
|
|
|
@specs.parameter('object_', dsl_types.MuranoObject)
|
|
|
|
def type_(object_):
|
|
|
|
return _wrap_type_reference(yaql_functions.type_(object_))
|
|
|
|
|
|
|
|
@specs.name('type')
|
2016-02-23 18:48:31 +03:00
|
|
|
@specs.parameter('cls', dsl.MuranoTypeParameter())
|
2016-01-25 02:52:15 +03:00
|
|
|
def type_from_name(cls):
|
|
|
|
return _wrap_type_reference(cls)
|
|
|
|
|
2015-07-21 16:56:43 +03:00
|
|
|
context = yaql_integration.create_empty_context()
|
2014-03-13 16:24:46 +04:00
|
|
|
context.register_function(get_context_data, '#get_context_data')
|
|
|
|
context.register_function(attribution, '#operator_.')
|
2015-07-21 16:56:43 +03:00
|
|
|
context.register_function(indexation, '#indexer')
|
2016-01-25 02:52:15 +03:00
|
|
|
context.register_function(ns_resolve)
|
|
|
|
context.register_function(ns_resolve_unary)
|
|
|
|
context.register_function(type_)
|
|
|
|
context.register_function(type_from_name)
|
2014-03-13 16:24:46 +04:00
|
|
|
return context
|
|
|
|
|
2016-01-25 02:52:15 +03:00
|
|
|
def _invalid_target(self, *args, **kwargs):
|
|
|
|
raise exceptions.InvalidLhsTargetError(self._expression)
|
|
|
|
|
2015-07-21 16:56:43 +03:00
|
|
|
def __call__(self, value, context):
|
|
|
|
new_context = self._create_context(context)
|
|
|
|
new_context[''] = context['$']
|
2016-03-02 21:22:14 +03:00
|
|
|
for name in (constants.CTX_NAMES_SCOPE,):
|
|
|
|
new_context[name] = context[name]
|
2014-03-13 16:24:46 +04:00
|
|
|
self._current_obj = None
|
|
|
|
self._current_obj_name = None
|
2015-07-21 16:56:43 +03:00
|
|
|
property = self._expression(context=new_context)
|
2016-01-25 02:52:15 +03:00
|
|
|
if not isinstance(property, LhsExpression.Property):
|
|
|
|
self._invalid_target()
|
2014-03-13 16:24:46 +04:00
|
|
|
property.set(value)
|