#!/usr/bin/env python3 ''' KLL Context Definitions * Generic (auto-detected) * Configuration * BaseMap * DefaultMap * PartialMap ''' # Copyright (C) 2016 by Jacob Alexander # # This file is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This file is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this file. If not, see . ### Imports ### import copy import os import common.organization as organization ### Decorators ### ## Print Decorator Variables ERROR = '\033[5;1;31mERROR\033[0m:' WARNING = '\033[5;1;33mWARNING\033[0m:' ### Classes ### class Context: ''' Base KLL Context Class ''' def __init__( self ): ''' Context initialization ''' # Each context may have one or more included kll files # And each of these files will have at least 1 Context self.kll_files = [] # File data assigned to each context # This info is populated during the PreprocessorStage self.lines = [] self.data = "" self.parent = None # Tokenized data sets self.classification_token_data = [] self.expressions = [] # Organized Expression Datastructure self.organization = organization.Organization() def __repr__( self ): # Build list of all the info return "(kll_files={0}, lines={1}, data='''{2}''')".format( self.kll_files, self.lines, self.data, ) def initial_context( self, lines, data, parent ): ''' Used in the PreprocessorStage to update the initial line and kll file data @param lines: Data split per line @param data: Entire context in a single string @param parent: Parent node, always a KLLFile ''' self.lines = lines self.data = data self.parent = parent def query( self, kll_expression, kll_type ): ''' Query Returns a dictionary of the specified property. Most queries should use this. See organization.py:Organization for property_type details. @param kll_expression: String name of expression type @param kll_type: String name of the expression sub-type @return: context_name: (dictionary) ''' return self.organization.data_mapping[ kll_expression ][ kll_type ] class GenericContext( Context ): ''' Generic KLL Context Class ''' class ConfigurationContext( Context ): ''' Configuration KLL Context Class ''' class BaseMapContext( Context ): ''' Base Map KLL Context Class ''' class DefaultMapContext( Context ): ''' Default Map KLL Context Class ''' class PartialMapContext( Context ): ''' Partial Map KLL Context Class ''' def __init__( self, layer ): ''' Partial Map Layer Context Initialization @param: Layer associated with Partial Map ''' super().__init__() self.layer = layer class MergeContext( Context ): ''' Container class for a merged Context Has references to the original contexts merged in ''' def __init__( self, base_context ): ''' Initialize the MergeContext with the base context Another MergeContext can be used as the base_context @param base_context: Context used to seed the MergeContext ''' super().__init__() # List of context, in the order of merging, starting from the base self.contexts = [ base_context ] # Copy the base context Organization into the MergeContext self.organization = copy.copy( base_context.organization ) # Set the layer if the base is a PartialMapContext if base_context.__class__.__name__ == 'PartialMapContext': self.layer = base_context.layer def merge( self, merge_in, debug ): ''' Merge in context Another MergeContext can be merged into a MergeContext @param merge_in: Context to merge in to this one @param debug: Enable debug out ''' # Append to context list self.contexts.append( merge_in ) # Merge context self.organization.merge( merge_in.organization, debug ) # Set the layer if the base is a PartialMapContext if merge_in.__class__.__name__ == 'PartialMapContext': self.layer = merge_in.layer def reduction( self ): ''' Simplifies datastructure NOTE: This will remove data, therefore, context is lost ''' self.organization.reduction() def paths( self ): ''' Returns list of file paths used to generate this context ''' file_paths = [] for kll_context in self.contexts: # If context is a MergeContext then we have to recursively search if kll_context.__class__.__name__ is 'MergeContext': file_paths.extend( kll_context.paths() ) else: file_paths.append( kll_context.parent.path ) return file_paths def files( self ): ''' Short form list of file paths used to generate this context ''' file_paths = [] for file_path in self.paths(): file_paths.append( os.path.basename( file_path ) ) return file_paths def __repr__( self ): return "(kll_files={0}, organization={1})".format( self.files(), self.organization, ) def query_contexts( self, kll_expression, kll_type ): ''' Context Query Returns a list of tuples (dictionary, kll_context) doing a deep search to the context leaf nodes. This results in pre-merge data and is useful for querying information about files used during compilation. See organization.py:Organization for property_type details. @param kll_expression: String name of expression type @param kll_type: String name of the expression sub-type @return: context_name: (dictionary, kll_context) ''' # Build list of leaf contexts leaf_contexts = [] for kll_context in self.contexts: # Recursively search if necessary if kll_context.__class__.__name__ == 'MergeContext': leaf_contexts.extend( kll_context.query_contexts( kll_expression, kll_type ) ) else: leaf_contexts.append( ( kll_context.query( kll_expression, kll_type ), kll_context ) ) return leaf_contexts