Source code for IoTPy.tools.parser

from pyparsing import *
from .db import get_template
from .parameter import get_external, make_internal, Parameter

# Literals
lineEnd = Suppress(Literal(";"))

leftBracket = Suppress(Literal("["))
rightBracket = Suppress(Literal("]"))

leftBrace = Suppress(Literal("{"))
rightBrace = Suppress(Literal("}"))

leftParan = Suppress(Literal("("))
rightParan = Suppress(Literal(")"))

equals = Suppress(Literal("="))
arrow = Suppress(Literal("->"))

# Common

# Template name
name = Word(alphanums + "_").setResultsName("name")

# Field name
field = Word(alphas + "_")

# Optional field
optional_field = Combine(field + Literal("*"))

# Typed field
typed_field = Group((field ^ optional_field) + Suppress(Literal(":")) +
                    Word(alphas))

# Declaration

# List of fields
inputs = Group(leftParan +
               Optional(delimitedList(field ^ optional_field ^ typed_field)) +
               rightParan).setResultsName("inputs")

# List of outputs
outputs = Group(delimitedList(field ^ typed_field)).setResultsName("outputs")

# Statement

# Output
# Either a field or a list of fields enclosed in []
# If only one field is provided, return as a list
param = field | Group(leftBracket + delimitedList(field) + rightBracket)

# Keyword value
val = Word(alphanums + "._") | Combine(
    Literal("\"") + Word(alphanums + "._") + Literal("\""))

val1 = val | leftBracket + Group(delimitedList(val)) + rightBracket

# Field keyword
fieldKeyword = Group(field + equals + val1)

inputsLine = Group(leftParan + Optional(delimitedList(fieldKeyword)) +
                   rightParan).setResultsName("inputs")

# Inputs

# Outputs
outputsLine = Group(delimitedList(param)).setResultsName("outputs")

# Parser

first = name + inputs + arrow + outputs
line = Optional(outputsLine + equals) + name + inputsLine + lineEnd
lines = ZeroOrMore(Group(line)).setResultsName("lines")

template = first + leftBrace + lines + rightBrace
templates = OneOrMore(Group(template))


[docs]def parse_string(x): """ Parses a string using the parser Parameters ---------- x : str String that describes template Returns ------- pyparsing.ParseResults """ return templates.parseString(x)
[docs]def get_templates(x): """ Parses a string containing templates to dict Parameters ---------- x : str String that describes templates Returns ------- list List containing dict for templates """ templates = parse_string(x) y = [] for template in templates: y.append(parse_template(template)) return y
[docs]def parse_template(template): """ Creates a dict for a template Parameters ---------- template : pyparsing.ParseResults Template parsed using parser Returns ------- dict Dict for template """ args_dict = {} # Get name of template args_dict["name"] = template["name"] # Parse inputs args_dict["inputs"] = [] args_dict["optional"] = [] if "inputs" in template: for field in template["inputs"]: # Typed field try: field_name, field_type = field.asList() # Optional if field_name[-1] == "*": args_dict["optional"].append([field_name[0:-1]]) args_dict["inputs"].append([field_type, field_name[0:-1]]) else: args_dict["inputs"].append([field_type, field_name]) except BaseException: # Optional if field[-1] == "*": args_dict["optional"].append(field[0:-1]) args_dict["inputs"].append(field[0:-1]) else: args_dict["inputs"].append(field) # Parse outputs args_dict["outputs"] = [] output_names = [] if "outputs" in template: for field in template["outputs"]: # Typed field try: field_name, field_type = field.asList() args_dict["outputs"].append([field_type, field_name]) output_names.append(field_name) except BaseException: # No return val if field == "None": continue args_dict["outputs"].append(field) output_names.append(field) # Subparts if "lines" in template: args_dict["assembly"] = "assemble" args_dict["components"] = [] args_dict["externals"] = [] args_dict["internals"] = [] outputs = {} # Dict of subpart ids template_count = {} for line in template["lines"]: name = line["name"] if name in template_count: template_count[name] += 1 else: template_count[name] = 0 # Create name for subpart using id name_subpart = name + str(template_count[name]) args_dict["components"].append([name_subpart, name]) # Read template from db y = get_template(name) # Parse outputs of line if "outputs" in line: # Outputs from line line_outputs = line["outputs"].asList() # Outputs of template template_outputs = y["outputs"] # Iterate over each list of outputs for i in range(0, len(line_outputs)): # Iterate over each output output = template_outputs[i] # output = type, name if isinstance(output, list): output = output[1] # Single output if not isinstance(line_outputs[i], list): # External if line_outputs[i] in output_names: args_dict["externals"].append( [line_outputs[i], name_subpart, output]) # Temporary var else: outputs[line_outputs[i]] = [name_subpart, output] # List of outputs else: for j in range(0, len(line_outputs[i])): # External connection if line_outputs[i][j] in output_names: args_dict["externals"].append([ line_outputs[i][j], name_subpart, output, j ]) # Temporary var else: outputs[line_outputs[i][j]] = [ name_subpart, output, j ] # Dict of temp variable count output_counts = {} # Dict of subpart ids template_count = {} for line in template["lines"]: name = line["name"] if name in template_count: template_count[name] += 1 else: template_count[name] = 0 # Create name for subpart wth id name_subpart = name + str(template_count[name]) y = get_template(name) # Parse inputs of line if "inputs" in line: # Inputs from line inputs = line["inputs"].asList() # Iterate over each list of inputs for key, value in inputs: # Single input if not isinstance(value, list): # Temporary var if value in outputs: if value in output_counts: output_counts[value] += 1 else: output_counts[value] = 1 source = get_external(outputs[value]) des = Parameter(name_subpart, key, None) args_dict["internals"].append( make_internal(source, des)) # External connection else: args_dict["externals"].append( [value, name_subpart, key]) # List of inputs else: # Iterate over each stream for j in range(0, len(value)): # Temporary var if value[j] in outputs: if value[j] in output_counts: output_counts[value[j]] += 1 else: output_counts[value[j]] = 1 source = get_external(outputs[value[j]]) des = Parameter(name_subpart, key, j) args_dict["internals"].append( make_internal(source, des)) # External connection else: args_dict["externals"].append( [value[j], name_subpart, key, j]) for value in outputs: if value not in output_counts: args_dict["externals"].append(["None"] + outputs[value]) # No lines else: args_dict["assembly"] = template["name"] return args_dict