monasca-analytics/monasca_analytics/banana/eval/ctx.py

120 lines
3.7 KiB
Python

#!/usr/bin/env python
# Copyright (c) 2016 Hewlett Packard Enterprise Development Company, L.P.
#
# 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.
import monasca_analytics.banana.grammar.ast as ast
import monasca_analytics.exception.banana as exception
class EvaluationContext(object):
"""Evalutation context for an AST evaluation"""
def __init__(self):
"""
Construct an evaluation context using the type table
as based for the variable needed to be created.
"""
self._variables = {}
self._components = {}
def set_variable(self, name, value):
"""Set the variable value."""
if isinstance(value, tuple) and len(value) == 2:
comp_type, config = value
comp_name = name.varname.inner_val()
self._components[comp_name] = comp_type(
comp_name,
config
)
self._variables[comp_name] = config
elif not set_property(self._variables, name, value):
raise exception.BananaEvalBug(
"set_variable can only be used with DotPath or Ident."
)
def get_components(self):
return self._components
def get_variable(self, name):
"""Returns the variable value."""
return self._variables[name]
def get_prop_of_variable(self, name, prop):
"""Returns the sub property of the given variable name."""
variable = self._variables[name]
for el in prop:
variable = variable[el]
return variable
def set_property(root_object, name, value):
"""
Set the property name of the root_object to value.
:type root_object: dict
:param root_object: The root object
:type name: ast.DotPath | ast.Ident | ast.StringLit
:param name: Name of
:param value:
:return: Returns true if succeeded.
"""
if isinstance(name, ast.Ident) or isinstance(name, ast.StringLit):
root_object[name.inner_val()] = value
return True
elif isinstance(name, ast.DotPath):
_create_as_many_object_as_needed(root_object, name, value)
return True
return False
def _create_as_many_object_as_needed(root_object, dot_path, value):
"""
Create as many object as needed to be able to access the
nested property.
:type root_object: dict
:param root_object: The root object
:type dot_path: ast.DotPath
:param dot_path: Dot Path to use.
:type value: object
:param value: Any value to set.
"""
name = dot_path.varname.inner_val()
if len(dot_path.properties) == 0:
root_object[name] = value
return
if name in root_object:
variable = root_object[name]
else:
variable = {}
current_var = variable
last_index = len(dot_path.properties) - 1
for index, subpath in enumerate(dot_path.properties):
subpath_name = subpath.inner_val()
if index != last_index:
if subpath_name in current_var:
current_var = current_var[subpath_name]
else:
new_object = {}
current_var[subpath_name] = new_object
current_var = new_object
else:
current_var[subpath_name] = value
root_object[name] = variable