def execute(self, sensor_graph, scope_stack): """Execute this statement on the sensor_graph given the current scope tree. This adds a single config variable assignment to the current sensor graph Args: sensor_graph (SensorGraph): The sensor graph that we are building or modifying scope_stack (list(Scope)): A stack of nested scopes that may influence how this statement allocates clocks or other stream resources. """ parent = scope_stack[-1] try: slot = parent.resolve_identifier('current_slot', SlotIdentifier) except UnresolvedIdentifierError: raise SensorGraphSemanticError("set config statement used outside of config block") if self.explicit_type is None or not isinstance(self.identifier, int): raise SensorGraphSemanticError("Config variable type definitions are not yet supported") if isinstance(self.value, (bytes, bytearray)) and not self.explicit_type == 'binary': raise SensorGraphSemanticError("You must pass the binary variable type when using encoded binary data") if not isinstance(self.value, (bytes, bytearray)) and self.explicit_type == 'binary': raise SensorGraphSemanticError("You must pass an encoded binary value with binary type config variables") sensor_graph.add_config(slot, self.identifier, self.explicit_type, self.value)
def trigger_chain(self): """Return a NodeInput tuple for creating a node. Returns: (StreamIdentifier, InputTrigger) """ raise SensorGraphSemanticError( "There is no trigger chain in this scope since no triggering criteria have been set", scope=self.name)
def __init__(self, parsed, location=None): realtime = 'realtime' in parsed broadcast = 'broadcast' in parsed encrypted = 'security' in parsed and parsed['security'] == 'encrypted' signed = 'security' in parsed and parsed['security'] == 'signed' self.auto = 'manual' not in parsed self.with_other = None if 'with_other' in parsed: self.with_other = parsed['with_other'] self.auto = False dest = SlotIdentifier.FromString('controller') if 'explicit_tile' in parsed: dest = parsed['explicit_tile'] selector = parsed['selector'] # Make sure all of the combination are valid if realtime and (encrypted or signed): raise SensorGraphSemanticError( "Realtime streamers cannot be either signed or encrypted") if broadcast and (encrypted or signed): raise SensorGraphSemanticError( "Broadcast streamers cannot be either signed or encrypted") super(StreamerStatement, self).__init__([], location) self.report_type = 'broadcast' if broadcast else 'telegram' self.dest = dest self.selector = selector if realtime or broadcast: self.report_format = u'individual' elif signed: self.report_format = u'signedlist_userkey' elif encrypted: raise SensorGraphSemanticError( "Encrypted streamers are not yet supported") else: self.report_format = u'hashedlist'
def execute(self, sensor_graph, scope_stack): """Execute this statement on the sensor_graph given the current scope tree. This adds a single node to the sensor graph with subtract as the function so that the current scope's trigger stream has the subtract_stream's value subtracted from it. Args: sensor_graph (SensorGraph): The sensor graph that we are building or modifying scope_stack (list(Scope)): A stack of nested scopes that may influence how this statement allocates clocks or other stream resources. """ if self.subtract_stream.stream_type != DataStream.ConstantType: raise SensorGraphSemanticError( "You can only subtract a constant value currently", stream=self.subtract_stream) parent = scope_stack[-1] alloc = parent.allocator trigger_stream, trigger_cond = parent.trigger_chain() sensor_graph.add_node(u"({} always && {} {}) => {} using {}".format( self.subtract_stream, trigger_stream, trigger_cond, self.stream, 'subtract_afromb')) value = self.default if value is None: value = 0 if self.default is not None and self.subtract_stream in sensor_graph.constant_database: raise SensorGraphSemanticError( "Attempted to set the same constant stream twice", stream=self.subtract_stream, new_value=self.default) elif self.default is None and self.subtract_stream in sensor_graph.constant_database: return sensor_graph.add_constant(self.subtract_stream, value)
def clock(self, interval, basis): """Return a NodeInput tuple for triggering an event every interval. Args: interval (int): The interval (in seconds) at which this input should trigger. basis (str): The basis to use for calculating the interval. This can either be system, tick_1 or tick_2. System means that the clock will use either the fast or regular builtin tick. Passing tick_1 or tick_2 will cause the clock to be generated based on the selected tick. """ raise SensorGraphSemanticError( "There is not default clock defined in this scope", scope=self.name)
def execute(self, sensor_graph, scope_stack): """Execute this statement on the sensor_graph given the current scope tree. This function will likely modify the sensor_graph and will possibly also add to or remove from the scope_tree. If there are children nodes they will be called after execute_before and before execute_after, allowing block statements to sandwich their children in setup and teardown functions. Args: sensor_graph (SensorGraph): The sensor graph that we are building or modifying scope_stack (list(Scope)): A stack of nested scopes that may influence how this statement allocates clocks or other stream resources. """ if not isinstance(scope_stack[-1], RootScope): raise SensorGraphSemanticError( "You may only declare metadata at global scope in a sensorgraph.", identifier=self.identifier, value=self.value) sensor_graph.add_metadata(self.identifier, self.value)
def parse_statement(self, statement, orig_contents): """Parse a statement, possibly called recursively. Args: statement (int, ParseResult): The pyparsing parse result that contains one statement prepended with the match location orig_contents (str): The original contents of the file that we're parsing in case we need to convert an index into a line, column pair. Returns: SensorGraphStatement: The parsed statement. """ children = [] is_block = False name = statement.getName() # Recursively parse all children statements in a block # before parsing the block itself. # If this is a non-block statement, parse it using the statement # parser to figure out what specific statement it is before # processing it further. # This two step process produces better syntax error messsages if name == 'block': children_statements = statement[1] for child in children_statements: parsed = self.parse_statement(child, orig_contents=orig_contents) children.append(parsed) locn = statement[0]['location'] statement = statement[0][1] name = statement.getName() is_block = True else: stmt_language = get_statement() locn = statement['location'] statement = statement['match'] statement_string = str(u"".join(statement.asList())) # Try to parse this generic statement into an actual statement. # Do this here in a separate step so we have good error messages when there # is a problem parsing a step. try: statement = stmt_language.parseString(statement_string)[0] except (pyparsing.ParseException, pyparsing.ParseSyntaxException) as exc: raise SensorGraphSyntaxError( "Error parsing statement in sensor graph file", message=exc.msg, line=pyparsing.line(locn, orig_contents).strip(), line_number=pyparsing.lineno(locn, orig_contents), column=pyparsing.col(locn, orig_contents)) except SensorGraphSemanticError as exc: # Reraise semantic errors with line information raise SensorGraphSemanticError( exc.msg, line=pyparsing.line(locn, orig_contents).strip(), line_number=pyparsing.lineno(locn, orig_contents), **exc.params) name = statement.getName() if name not in statement_map: raise ArgumentError("Unknown statement in sensor graph file", parsed_statement=statement, name=name) # Save off our location information so we can give good error and warning information line = pyparsing.line(locn, orig_contents).strip() line_number = pyparsing.lineno(locn, orig_contents) column = pyparsing.col(locn, orig_contents) location_info = LocationInfo(line, line_number, column) if is_block: return statement_map[name](statement, children=children, location=location_info) return statement_map[name](statement, location_info)