class CommonTransformer(Transformer): @staticmethod def _unescape(input, escaped): return input.replace('\\%s' % escaped, escaped) @staticmethod def _hack(s, escaped): # We modify the internal value representation, directly accessed from value_string() s.value = CommonTransformer._unescape(s[1:-1], escaped) return s @v_args(inline=True) def uqstring(self, s): r = _wildcard_to_regex(s) if r[0] > 1: # We modify the internal value representation, directly accessed from value_string() s.value = r[1] op = "~" else: op = "<>*" return op, s string = v_args(inline=True)(lambda _, s: s) sqstring = v_args(inline=True)(lambda _, s: ("<>*", CommonTransformer._hack(s, "'"))) dqstring = v_args(inline=True)(lambda _, s: ("<>*", CommonTransformer._hack(s, '"'))) regstr = v_args(inline=True)(lambda _, s: ("~", CommonTransformer._hack(s, '/')))
class ParTransformer(lark.Transformer): start = list sysexpr = lark.v_args(inline=True)( lambda self, name, *params: ParCmd("system", name, params)) userexpr = lark.v_args(inline=True)( lambda self, name, *params: ParCmd("user", name[1:], params)) include = lark.v_args( inline=True)(lambda self, fname: ParCmd("system", "LUE", [fname])) string = lambda self, x: " ".join(x) number = lark.v_args(inline=True)(float)
class TreeToDict(Transformer): start = dict @v_args(inline=True) def section(self, header, *pairs): return (header[1:-1], dict(pairs)) @v_args(inline=True) def stripped(self, s=''): return str.strip(s) value = key = stripped header = v_args(inline=True)(str) keyval = tuple bare_key = v_args(inline=True)(lambda self, key: (key, None))
class CommonTransformer(Transformer): @staticmethod def _unescape(input, escaped): return input.replace('\\%s' % escaped, escaped) @v_args(inline=True) def dqstring(self, s): s.value = self._unescape(s.value[1:-1], '"') return s.value @v_args(inline=True) def sqstring(self, s): s.value = self._unescape(s.value[1:-1], "'") return s.value uqstring = v_args(inline=True)(text_type) path = string = operator = v_args(inline=True)(text_type)
class TreeToJson(Transformer): @v_args(inline=True) def string(self, s): return json_unescape(s) array = list pair = tuple object = dict number = v_args(inline=True)(float) null = lambda self, _: None true = lambda self, _: True false = lambda self, _: False
class TreeToJson(Transformer): @v_args(inline=True) def string(self, s): return s[1:-1].replace('\\"', '"') array = list pair = tuple object = dict number = v_args(inline=True)(float) null = lambda self, _: None true = lambda self, _: True false = lambda self, _: False
def get_sqstring_transformer(parser: JsomParser, warnings: bool = True) -> Callable[[Token], str]: @v_args(inline=True) def dqstring_no_warn(token: Token) -> str: return literal_eval(token.replace(r'\/', '/')) @v_args(inline=True) def sqstring_warn(token: Token) -> str: warn( SingleQuotedString(line=token.line, column=token.column, near=token, file=parser.file)) return literal_eval(token.replace(r'\/', '/')) return sqstring_warn if warnings else v_args(inline=True)(literal_eval)
class TreeToJson(Transformer): @v_args(inline=True) def string(self, s): return s[1:-1].replace('\\"', '"') array = list pair = tuple object = dict number = v_args(inline=True)(float) def null(self, _): return None def true(self, _): return True def false(self, _): return False
class TreeToJson(Transformer): @v_args(inline=True) def string(self, s): return s[1:-1].replace('\\"', '"') def name(self, key): key = str(key[0]) return key array = list pair = tuple object = dict number = v_args(inline=True)(float) def null(self, _): return None def true(self, _): return True def false(self, _): return False def inf(self, _): return float("inf") def minf(self, _): return -float("inf") def nan(self, _): return float("nan")
class treeFunct(Transformer): @v_args(inline=True) def string(self, s): return s[1:-1].replace('\\"', '"') def no_quote_string(self, s): s = str(s[0]) return s array = list pair = tuple object = dict number = v_args(inline=True)(float) null = lambda self, _: None true = lambda self, _: True false = lambda self, _: False inf = lambda self, _: float("inf") minf = lambda self, _: -float("inf") nan = lambda self, _: float("nan")
class TreeToJson(Transformer): @v_args(inline=True) def string(self, s): return s[1:-1].replace('\\"', '"') def name(self, key): key = str(key[0]) return key array = list pair = tuple object = dict number = v_args(inline=True)(float) null = lambda self, _: None true = lambda self, _: True false = lambda self, _: False inf = lambda self, _: float("inf") minf = lambda self, _: -float("inf") nan = lambda self, _: float("nan")
class TreeToJson(Transformer): @v_args(inline=True) def string(self, s): return s[1:-1].replace('\\"', '"') def simple_id(self, s): return str(s[0].value) array = list pair = tuple object = dict number = v_args(inline=True)(float) null = lambda self, _: None true = lambda self, _: True false = lambda self, _: False positive_infinity = lambda self, _: float("inf") negative_infinity = lambda self, _: -float("inf") not_a_number = lambda self, _: float("nan")
class CriteriaTransformer(CommonTransformer): def __init__(self, compile=Criterion): self._compile = compile parenthesis = v_args(inline=True)(lambda self, criterion: criterion) or_ = v_args( inline=True)(lambda self, left, right: Criterion(left, "||", right)) and_ = v_args( inline=True)(lambda self, left, right: Criterion(left, "&&", right)) not_ = v_args( inline=True)(lambda self, right: Criterion(operator="!", right=right)) criterion = v_args(inline=True)( lambda self, left, op, right: self._compile(left, op, right)) not_null = v_args( inline=True)(lambda self, path: self._compile(path, "!=", None))
class SieveTransformer(Transformer): ESCAPED_CHARACTER = compile(br'\\(.)') start = v_args(inline=True)(SieveScript) @v_args(inline=True) def command_name(self, token: Token): return token tag = test_name = command_name @v_args(inline=True) def string(self, token: Token): token.value = self.ESCAPED_CHARACTER.sub(br'\1', token.value[1:-1]) return token @v_args(inline=True) def text(self, token: Token): text = token.value token.value = text.replace(b'\r\n..', b'\r\n.')[text.index(b'\r\n') + 2:-3] return token
class TreeToJson(Transformer): @v_args(inline=True) def string(self, s): return s def infinity(self, token): return float("inf") def ninfinity(self, token): return -float("inf") def nan(self, token): return float("nan") array = list pair = tuple object = dict number = v_args(inline=True)(float) null = lambda self, _: None true = lambda self, _: True false = lambda self, _: False
class TreeToJson(Transformer): @v_args(inline=True) def string(self, s): return s[1:-1].replace('\\"', '"') def infinity(self, tk): return float("inf") def minus_infinity(self, tk): return -float("inf") def nan(self, tk): return float("nan") array = list pair = tuple object = dict number = v_args(inline=True)(float) null = lambda self, _: None true = lambda self, _: True false = lambda self, _: False
class TransformToIR(Transformer): def __init__(self, module_dict, event_dict): super().__init__() self.module_dict = module_dict self.event_dict = event_dict self.cur_event_dict = {} self.errors = 0 def _add_without_duplicates(self, type_string, in_dict, new): if new.name in in_dict: existing = in_dict[new.name] new_meta = new.name.meta old_meta = existing.name.meta logger.error("%s:%d:%d: error: duplicate definition of %s '%s'", new_meta.filename, new_meta.line, new_meta.column, type_string, new.name) logger.info("%s:%d:%d: note: previous definition of %s '%s'", old_meta.filename, old_meta.line, old_meta.column, type_string, new.name) self.errors += 1 else: in_dict[new.name] = new def _general_event(self, event_class, children, meta): # Check for duplicated parameters params = {} for c in children: if isinstance(c, Param): self._add_without_duplicates('parameter', params, c) event = event_class(children) event.meta = meta self._add_without_duplicates('event', self.cur_event_dict, event) return event @v_args(meta=True) def module(self, children, meta): assert not self.cur_event_dict m = Module(children) m.meta = meta if m.name in self.module_dict: self.module_dict[m.name].merge(m) else: self.module_dict[m.name] = m return m @v_args(meta=True) def interface(self, children, meta): interface_name = next(c for c in children if isinstance(c, Symbol)) for name, event in self.cur_event_dict.items(): if not name.startswith(interface_name + "_"): meta = event.name.meta logger.error( "%s:%d:%d: error: incorrect name: " "'%s' should start with '%s_'", meta.filename, meta.line, meta.column, name, interface_name) self.errors += 1 self.event_dict[name] = event self.cur_event_dict = {} return self.module(children, meta) def include(self, children): return Include(''.join(str(c) for c in children)) @v_args(meta=True) def publish_event(self, children, meta): return self._general_event(Event, children, meta) @v_args(meta=True) def publish_handled_event(self, children, meta): return self._general_event(HandledEvent, children, meta) @v_args(meta=True) def publish_multi_event(self, children, meta): return self._general_event(MultiEvent, children, meta) @v_args(meta=True) def publish_setup_event(self, children, meta): return self._general_event(SetupEvent, children, meta) @v_args(meta=True) def publish_selector_event(self, children, meta): return self._general_event(SelectorEvent, children, meta) @v_args(meta=True) def symbol(self, children, meta): sym = Symbol(*children) sym.meta = meta return sym @v_args(meta=True) def event_param(self, children, meta): p = Param(children) p.meta = meta return p @v_args(meta=True) def selector_param(self, children, meta): p = SelectorParam(children) p.meta = meta return p @v_args(meta=True) def count_param(self, children, meta): p = CountParam(children) p.meta = meta return p @v_args(meta=True) def result(self, children, meta): r = Result(children) r.meta = meta return r @v_args(meta=True) def type_decl(self, children, meta): t = Type(' '.join(str(c) for c in children)) t.meta = meta return t @v_args(meta=True) def subscribe(self, children, meta): s = Subscription(children) s.meta = meta return s @v_args(meta=True) def selector(self, children, meta): s = Selectors(children) s.meta = meta return s subscribe_public = subscribe def optional(self, children): return Optional() def public(self, children): return Public() @v_args(meta=True) def handler(self, children, meta): h = Handler(*children) h.meta = meta return h handler_public = handler @v_args(meta=True) def unwinder(self, children, meta): u = Unwinder(*children) u.meta = meta return u unwinder_public = unwinder constant = v_args(inline=True)(Constant) def expected_args(self, children): args = collections.OrderedDict() for c in children: c.name = c self._add_without_duplicates('argument', args, c) return ExpectedArgs(args.values()) @v_args(meta=True) def priority(self, children, meta): if children[0] in ('first', 'max'): c = Priority(math.inf) elif children[0] in ('last', 'min'): c = Priority(-math.inf) elif children[0] == 'default': c = Priority(0) else: c = Priority(children[0]) c.meta = meta return c @v_args(meta=True) def constexpr(self, children, meta): c = ConstExpr(' '.join(children)) c.meta = meta return c @v_args(meta=True) def success(self, children, meta): c = Success(' '.join(children)) c.meta = meta return c
"Create meta with 'code' from transformer" res = f(*children) header_comments = getattr(meta, 'header_comments', None) if header_comments: return '\n'.join('//' + h.lstrip()[1:] for h in header_comments) + '\n' + res inline_comment = getattr(meta, 'inline_comment', None) if inline_comment: c = inline_comment.lstrip() assert c.startswith('#'), c res += " //" + c[1:] + '\n' return res as_args = v_args(inline=False) VAR_TRANSLATION = { 'print': 'console.log', 'self': 'this', 'append': 'push', 'Exception': 'Error', 'NameError': 'ReferenceError', } @v_args(wrapper=_args_wrapper) class ToJs(Transformer): NAME = number = str # string = str
class DataSetGeneratorTransformer(Transformer): from operator import add, sub, mul, truediv as div, neg @v_args(inline=True) def random_variables(self, names, values): assert len(names) == values.shape[ 1], f"Value dimension do not agree with variable dimension {names} have " \ f"{len(names)} whereas values {values.shape[-1]}" new_columns = dict(zip(names, values.T)) new_columns = {k: v.reshape((-1, 1)) for k, v in new_columns.items()} self.columns.update(new_columns) @v_args(inline=True) def create(self, distribution): result = distribution() if result.ndim == 1: result = result.reshape(-1, 1) return result def sizes(self, parts): ratio = self.sample_size / parts remainder = self.sample_size % parts return [int(ratio + 1)] * remainder + [int(ratio)] * (parts - remainder) def stack(self, items): shapes = np.array([item.shape[1] for item in items]) assert all(shapes[0] == shapes) sizes = self.sizes(len(items)) splitted = [i[:s] for i, s in zip(items, sizes)] return np.vstack(splitted) def stackall(self, items): total_dims = sum((item.shape[1] for item in items)) sizes = self.sizes(total_dims) flatten = np.concatenate(items, axis=1).T.tolist() splitted = [np.array(i[:s]) for i, s in zip(flatten, sizes)] return np.concatenate(splitted).reshape(-1, 1) @v_args(inline=True) def range(self, lower, upper): assert upper >= lower, f"Range lower is larger than upper limit {lower} > {upper}" return list(range(lower, upper + 1)) @v_args(inline=True) def multi(self, name, range): return [f"{name}{i}" for i in range] @v_args(inline=True) def single(self, name): return [name] distribution_fn_map = { "normal": np.random.normal, "pois": np.random.poisson, "uniform": np.random.uniform, "constant": lambda v, size: np.array([v] * size), "multivariate": multivariate, "range_dist": lambda start, size: np.arange(start, start + size), 'choice': lambda choices, size: np.random.choice(choices, size) } @v_args(inline=True) def distribution(self, args): name = args.data return lambda: self.distribution_fn_map[name](*args.children, self.sample_size) @v_args(inline=True) def multi_dist(self, distr_fn, rep): temp = [distr_fn() for _ in range(rep)] if temp[0].ndim == 1: return lambda: np.array(temp).T return lambda: np.concatenate(temp, axis=1) @v_args(inline=True) def tile(self, values, rep): return np.tile(values, rep) @v_args(inline=True) def scalar(self, value): return value @v_args(inline=True) def rv(self, variable): # also handle noise if all(v in self.columns.keys() for v in variable): return np.column_stack([self.columns[v] for v in variable]) else: raise ValueError(f'Identifier {variable} not defined') @v_args(inline=True) def combine(self, left, right): def left_or_right(l, r): return l if l != 'not_assigned' and r == 'not_assigned' else r left = left.reshape(-1, ) right = right.reshape(-1, ) result = np.array([left_or_right(l, r) for l, r in zip(left, right)]).reshape((-1, 1)) return result @v_args(inline=True) def bool_if(self, array, true_value): values = [true_value, "not_assigned"] def f(values, x): return values[0] if x else values[1] f = functools.partial(f, values) result = np.array(list(map(f, array))).reshape((-1, 1)) return result @v_args(inline=True) def bool_compound(self, array, default_value): array = array.reshape(-1, ) def f(x): return default_value if x == 'not_assigned' else x result = np.array(list(map(f, array))).reshape((-1, 1)) return result def bool_array(self, values): return values[0] @v_args(inline=True) def equal(self, left, right): return left == right @v_args(inline=True) def inverse(self, item): return np.logical_not(item) @v_args(inline=True) def not_equal(self, left, right): return left != right @v_args(inline=True) def larger_equal(self, left, right): return left >= right @v_args(inline=True) def larger(self, left, right): return left > right @v_args(inline=True) def smaller(self, left, right): return left < right @v_args(inline=True) def smaller_equal(self, left, right): return left <= right @v_args(inline=True) def bool_and(self, left, right): return np.logical_and(left, right) @v_args(inline=True) def bool_or(self, left, right): return np.logical_or(left, right) @v_args(inline=True) def power(self, item, power): return np.power(item, power) @v_args(inline=True) def log(self, item): return np.log(item) @v_args(inline=True) def sqrt(self, item): return np.sqrt(item) mul = v_args(inline=True)(mul) add = v_args(inline=True)(add) sub = v_args(inline=True)(sub) div = v_args(inline=True)(div) neg = v_args(inline=True)(neg) @v_args(inline=True) def addlist(self, name, low, high): return np.sum([self.columns[name + str(i)] for i in range(low, high + 1)], axis=0) @v_args(inline=True) def mullist(self, name, low, high): return np.prod([self.columns[name + str(i)] for i in range(low, high + 1)], axis=0) @v_args(inline=True) def samplenumber(self, sample_size): self.sample_size = sample_size self.columns = {} def output(self, items): columns = {a: self.columns[a] for a in items[0]} if items else self.columns flatten = {k: v.squeeze() for k, v in columns.items()} self.df = pd.DataFrame.from_dict(flatten) # pprint(self.df) @v_args(inline=True) def id(self, s): return s.value @v_args(inline=True) def string(self, s): return s.value[1:-1] @v_args(inline=True) def seed(self, seed): np.random.seed(seed) def id_array(self, items): return list(itertools.chain.from_iterable(items)) number = v_args(inline=True)(float) int = v_args(inline=True)(int) array = list string_array = list
ParseTreeTransformer = lark.v_args(inline=True)( type( "ParseTreeTransformer", (lark.Transformer, ), { **{ "__doc__": """Transformer from flat parse trees to character classes Parse trees handled by this transformer should only have the root node 'start' with children containing tokens, with a name that is the (lowercased) name of the corresponding character class and the character as value. For brackets name_open and name_closed are expected. Args: char_mapping: A function that takes a character as input and returns its representations as dict. Defaults to the character in all representations. """, "__init__": __parse_tree_transformer_init, "start": lambda self, *characters: characters, }, ## add basic characters **{ class_.__name__.lower(): lambda self, character, class_=class_: class_(**self._create_char(character)) for class_ in __get_all_subclasses(Char) if not issubclass( class_, Bracket) }, ## add whitspace **{ class_.__name__.lower(): lambda self, character, class_=class_: class_( self._create_char(character)["_trans"]) for class_ in [Whitespace] + __get_all_subclasses(Whitespace) }, ## add brackets - open and close **{ class_.__name__.lower() + "_open": lambda self, character, class_=class_: class_(**self._create_char(character), opening=True) for class_ in __get_all_subclasses(Bracket) }, **{ class_.__name__.lower() + "_close": lambda self, character, class_=class_: class_(**self._create_char(character), opening=False) for class_ in __get_all_subclasses(Bracket) }, }, ))
class SQLTransformer(Transformer): def start(self, statements): # flatten flat = [item for sublist in statements for item in sublist] return flat @v_args(inline=True) def custom_decorated_statement(self, decorators, statement): text = str(statement) availability = get_deco(decorators, "availability") if get_deco(decorators, "internal") or get_deco( decorators, "deprecated"): return "" if availability: text += f"\n*Since v{availability}*" text += "\n\n" return text def custom_decorators(self, lines): decorators = {} for line in lines: try: key, value = line.split(":") decorators[str(key).lower()] = value.strip() except: decorators[str(line).lower()] = True return decorators def custom_md_statement(self, children): return children # -- MARKDOWN -------------------------------------------------------------- @v_args(inline=True) def custom_markdown(self, line=""): return "" + line # -- CREATE TYPE ----------------------------------------------------------- def create_type_stmt(self, children): return "" # -- CREATE CAST ----------------------------------------------------------- @v_args(inline=True) def create_cast_stmt(self, source, target, *children): return f"### `{source}` :: `{target}`" # -- CREATE OPERATOR ------------------------------------------------------- @v_args(inline=True) def create_oper_stmt(self, name, options): return f"### Operator: `{options['LEFTARG']}` {name} `{options['RIGHTARG']}`" def create_oper_opts(self, opts): options = {} for [k, v] in opts: options[k] = v return options @v_args(inline=True) def create_oper_opt(self, option, value=None): return [str(option), value] # -- CREATE FUNCTION ------------------------------------------------------- @v_args(inline=True) def create_func_stmt(self, name: str, arguments, returntype, *opts): # skip internal functions if name.startswith("__"): return None # print("func") return Function(name, arguments, returntype) def argument_list(self, children): return children # -- CREATE COMMENT -------------------------------------------------------- @v_args(inline=True) def comment_on_stmt(self, child, text): child["type"] = "comment" child["text"] = text # print(child) return text # ... ON CAST @v_args(inline=True) def comment_on_cast(self, source, target): return {"on": "cast", "source": source, "target": target} # ... ON FUNCTION @v_args(inline=True) def comment_on_function(self, name, arguments): return {"on": "function", "name": name, "arguments": arguments} # ... ON OPERATOR @v_args(inline=True) def comment_on_operator(self, name, left, right): return {"on": "operator", "name": name, "left": left, "right": right} # -- SIMPLE RULES ---------------------------------------------------------- true = lambda self, _: "`true`" false = lambda self, _: "`false`" number = v_args(inline=True)(int) @v_args(inline=True) def string(self, s): return s[1:-1].replace('\\"', '"') def fun_name(self, children): return children[1] @v_args(inline=True) def argument(self, name, argtype, default=None): out = "" if name: out += name + " " out += "`{}`".format(argtype) if default: out = "[{} = {}]".format(out, default) return out # -- TERMINALS ------------------------------------------------------------- def SIGNED_NUMBER(self, children): return int(children) def CNAME(self, cname): return str(cname) def OPERATOR(self, name): return str(name)
class TreeToDSL(Transformer): array = list number = v_args(inline=True)(float) true = lambda self, _: True false = lambda self, _: False
"mul", "div", "rem", "eqeq", "neq", "lt", "lte", "gt", "gte", ]: def fn(self, items, meta, op=op): assert len(items) == 2 return E.Apply(sp(self.filename, meta), "_" + op, items) setattr(_ExprTransformer, op, lark.v_args(meta=True)(classmethod(fn))) # pyre-fixme class _TypeTransformer(lark.Transformer): # pylint: disable=no-self-use,unused-argument def __init__(self, file: str) -> None: self.filename = file def int_type(self, items, meta): optional = False if items and items[0].value == "?": optional = True return T.Int(optional) def float_type(self, items, meta):
class BaseTreeTransformer(_LarkTransformer): """ Abstract implementation of the Tree transformer class """ lookup: Callable[[RowType, str], Any] add: Callable[[RowType, Any, Any], Any] subtract: Callable[[RowType, Any, Any], Any] multiply: Callable[[RowType, Any, Any], Any] divide: Callable[[RowType, Any, Any], Any] eq: Callable[[RowType, Any, Any], Any] not_eq: Callable[[RowType, Any, Any], Any] is_in: Callable[[RowType, Any, Any], Any] not_in: Callable[[RowType, Any, Any], Any] gt: Callable[[RowType, Any, Any], Any] gte: Callable[[RowType, Any, Any], Any] lt: Callable[[RowType, Any, Any], Any] lte: Callable[[RowType, Any, Any], Any] logical_not: Callable[[RowType, Any, Any], Any] logical_or: Callable[[RowType, Any, Any], Any] logical_and: Callable[[RowType, Any, Any], Any] any: Callable[[RowType, List[Any]], GroupWrapper] all: Callable[[RowType, List[Any]], GroupWrapper] str_join: Callable[..., Any] str_replace: Callable[[RowType, Any, Pattern, Any], Any] str_match: Callable[[RowType, Any, Pattern, Any], Any] str_search: Callable[[RowType, Any, Pattern, Any], Any] array = v_args(inline=False)(list) string_escape_re = re.compile(r"`([`'])") def string(self, value=""): """ Parses a string from the transformer language and performs any necessary escaping. `value` has a default value to account for the empty string case. :param value: The value to parse :return: The parsed value """ # process any escape characters return self.string_escape_re.sub(r"\1", value) def regex(self, value=""): """ Generates a regex from teh provided string :param value: The pattern :return: The regex object """ return re.compile(self.string(value)) def iregex(self, value=""): """ Generates a case insensitive regex from teh provided string :param value: The pattern :return: The regex object """ return re.compile(self.string(value), flags=re.IGNORECASE) def boolean(self, value): """ Pareses a boolean from the transformer language. :param value: The value to parse :return: True if the value is "True", False otherwise """ return value == "True" def null(self, value): """ Pareses a null from the transformer language. :param value: The value to parse (ignored as its always Null) :return: None """ return None def number(self, value): """ Parses a number from the transformer language. First tries to parse an integer but on failure parses as a float. :param value: The value to parse :return: The parsed value """ try: return int(value) except ValueError: return float(value)
def _args_wrapper_meta(f, data, children, meta): ref = make_text_reference(*f.__self__.code_ref, meta, children) res = f(ref, *children) if isinstance(res, (Str, ast.Ast)): res.set_text_ref(ref) return res def _args_wrapper_list(f, data, children, meta): res = f(children) return _wrap_result(res, f, meta, children) with_meta = v_args(wrapper=_args_wrapper_meta) no_inline = v_args(wrapper=_args_wrapper_list) def token_value(self, t): return Str(str(t)) @v_args(wrapper=_args_wrapper) class TreeToAst(Transformer): def __init__(self, code_ref): self.code_ref = code_ref name = token_value def string(self, s):
yield '\n' for section in self.sections: yield from section._print_rst() yield '\n' def print_text(self, indent=0): return ''.join(self._print_text(indent)) def print_html(self): return ''.join(self._print_html()) def print_rst(self): return ''.join(self._print_rst()) _inline = v_args(inline=True) class DocTransformer(Transformer): def as_list(self, items): return items # attrs = as_list section_items = as_list sections = as_list text = Text header = Text start = _inline(DocString) @_inline
"div", "rem", "eqeq", "neq", "lt", "lte", "gt", "gte", ]: def fn(self, items, meta, op=op): assert len(items) == 2 return Expr.Apply(self._sp(meta), "_" + op, items) setattr(_ExprTransformer, op, lark.v_args(meta=True)(classmethod(fn))) # pyre-fixme class _TypeTransformer(_SourcePositionTransformerMixin, lark.Transformer): # pylint: disable=no-self-use,unused-argument def optional(self, items, meta): return set(["optional"]) def nonempty(self, items, meta): return set(["nonempty"]) def optional_nonempty(self, items, meta): return set(["optional", "nonempty"]) def type(self, items, meta):
""" pass class AsList(object): """Abstract class Subclasses will be instanciated with the parse results as a single list, instead of as arguments. """ def camel_to_snake(name): return re.sub(r'(?<!^)(?=[A-Z])', '_', name).lower() def _call(func, _data, children, _meta): return func(*children) inline = v_args(wrapper=_call) def create_transformer(ast_module, transformer=None): """Collects `Ast` subclasses from the given module, and creates a Lark transformer that builds the AST. For each class, we create a corresponding rule in the transformer, with a matching name. CamelCase names will be converted into snake_case. Example: "CodeBlock" -> "code_block". Classes starting with an underscore (`_`) will be skipped. Parameters: ast_module - A Python module containing all the subclasses of `ast_utils.Ast` transformer (Optional[Transformer]) - An initial transformer. Its attributes may be overwritten. """ t = transformer or Transformer()
class QuilTransformer(Transformer): # type: ignore def quil(self, instructions): return instructions indented_instrs = list @v_args(inline=True) def def_gate_matrix(self, name, variables, matrix): return DefGate(name, matrix=matrix, parameters=variables) @v_args(inline=True) def def_gate_as_permutation(self, name, matrix): return DefPermutationGate(name, permutation=matrix) @v_args(inline=True) def def_pauli_gate(self, name, variables, qubits, terms): pg = DefGateByPaulis(name, parameters=variables, arguments=qubits, body=terms) return pg pauli_terms = list @v_args(inline=True) def pauli_term(self, name, expression, qubits): from pyquil.paulis import PauliTerm return PauliTerm.from_list(list(zip(name, qubits)), expression) @v_args(inline=True) def def_circuit(self, name, variables, qubits, instrs): qubits = qubits if qubits else [] space = " " if qubits else "" if variables: raw_defcircuit = "DEFCIRCUIT {}({}){}{}:".format( name, ", ".join(map(str, variables)), space, " ".join(map(str, qubits)) ) else: raw_defcircuit = "DEFCIRCUIT {}{}{}:".format(name, space, " ".join(map(str, qubits))) raw_defcircuit += "\n ".join([""] + [str(instr) for instr in instrs]) return RawInstr(raw_defcircuit) @v_args(inline=True) def def_circuit_without_qubits(self, name, variables, instrs): return self.def_circuit_qubits(name, variables, [], instrs) @v_args(inline=True) def def_frame(self, frame, *specs): names = { "DIRECTION": "direction", "HARDWARE-OBJECT": "hardware_object", "INITIAL-FREQUENCY": "initial_frequency", "SAMPLE-RATE": "sample_rate", "CENTER-FREQUENCY": "center_frequency", } options = {} for (spec_name, spec_value) in specs: name = names.get(spec_name, None) if name: options[name] = json.loads(str(spec_value)) else: raise ValueError( f"Unexpectected attribute {spec_name} in definition of frame {frame}. " f"{frame}, {specs}" ) f = DefFrame(frame, **options) return f frame_spec = list frame_attr = v_args(inline=True)(str) @v_args(inline=True) def def_waveform(self, name, params, matrix): return DefWaveform(name, params, matrix[0]) @v_args(inline=True) def def_calibration(self, name, params, qubits, instructions): for p in params: mrefs = _contained_mrefs(p) if mrefs: raise ValueError(f"Unexpected memory references {mrefs} in DEFCAL {name}. Did you forget a '%'?") dc = DefCalibration(name, params, qubits, instructions) return dc @v_args(inline=True) def def_measure_calibration(self, qubit, name, instructions): mref = FormalArgument(name) if name else None dmc = DefMeasureCalibration(qubit, mref, instructions) return dmc @v_args(inline=True) def gate(self, modifiers, name, params, qubits): # TODO Don't like this. modifiers = modifiers or [] params = params or [] # Some gate modifiers increase the arity of the base gate. The # new qubit arguments prefix the old ones. modifier_qubits = [] for m in modifiers: if m in ["CONTROLLED", "FORKED"]: modifier_qubits.append(qubits[len(modifier_qubits)]) base_qubits = qubits[len(modifier_qubits) :] forked_offset = len(params) >> modifiers.count("FORKED") base_params = params[:forked_offset] if name in QUANTUM_GATES: if base_params: gate = QUANTUM_GATES[name](*base_params, *base_qubits) else: gate = QUANTUM_GATES[name](*base_qubits) else: gate = Gate(name, base_params, base_qubits) for modifier in modifiers[::-1]: if modifier == "CONTROLLED": gate.controlled(modifier_qubits.pop()) elif modifier == "DAGGER": gate.dagger() elif modifier == "FORKED": gate.forked(modifier_qubits.pop(), params[forked_offset : (2 * forked_offset)]) forked_offset *= 2 else: raise ValueError(f"Unsupported gate modifier {modifier}.") return gate @v_args(inline=True) def gate_no_qubits(self, name): return RawInstr(name) modifiers = list modifier = v_args(inline=True)(str) @v_args(inline=True) def frame(self, qubits, name): f = Frame(qubits, name) return f @v_args(inline=True) def pulse(self, nonblocking, frame, waveform): p = Pulse(frame, waveform, nonblocking=bool(nonblocking)) return p @v_args(inline=True) def fence_some(self, qubits): f = Fence(list(qubits)) return f fence_all = v_args(inline=True)(FenceAll) @v_args(inline=True) def declare(self, name, memory_type, memory_size, *sharing): shared, *offsets = sharing d = Declare( str(name), memory_type=str(memory_type), memory_size=int(memory_size) if memory_size else 1, shared_region=str(shared) if shared else None, offsets=offsets if shared else None, ) return d @v_args(inline=True) def capture(self, nonblocking, frame, waveform, addr): c = Capture(frame, waveform, addr, nonblocking=nonblocking) return c @v_args(inline=True) def raw_capture(self, nonblocking, frame, expression, addr): c = RawCapture(frame, expression, addr, nonblocking=nonblocking) return c @v_args(inline=True) def addr(self, name): return MemoryReference(str(name)) @v_args(inline=True) def addr_subscript(self, name, subscript): return MemoryReference(str(name), int(subscript)) @v_args(inline=True) def offset_descriptor(self, offset, name): return (int(offset), str(name)) @v_args(inline=True) def delay_qubits(self, qubits, delay_amount=None): # TODO(notmgsk): This is a very nasty hack. I can't quite get # the Lark grammar to recognize the last token (i.e. 1) in # `DELAY 0 1` as the delay amount. I think it's because it # matches 1 as a qubit rather than an expression (in the # grammar). Then again I would expect look-ahead to see that # it matches expression too, so it should give that # preference. How do we encode that priority? if delay_amount is None: delay_amount = int(qubits[-1].index) qubits = qubits[:-1] d = DELAY(*[*qubits, delay_amount]) return d @v_args(inline=True) def delay_frames(self, qubit, *frames_and_delay_amount): *frame_names, delay_amount = frames_and_delay_amount frames = [Frame([qubit], name) for name in frame_names] d = DELAY(*[*frames, delay_amount]) return d @v_args(inline=True) def shift_phase(self, frame, expression): return SHIFT_PHASE(frame, expression) @v_args(inline=True) def set_phase(self, frame, expression): return SET_PHASE(frame, expression) @v_args(inline=True) def set_scale(self, frame, expression): return SET_SCALE(frame, expression) @v_args(inline=True) def set_frequency(self, frame, expression): return SET_FREQUENCY(frame, expression) @v_args(inline=True) def shift_frequency(self, frame, expression): return SHIFT_FREQUENCY(frame, expression) @v_args(inline=True) def swap_phase(self, framea, frameb): return SWAP_PHASE(framea, frameb) @v_args(inline=True) def pragma(self, name, *pragma_names_and_string): args = list(map(str, pragma_names_and_string)) p = Pragma(str(name), args=args) return p @v_args(inline=True) def pragma_freeform_string(self, name, *pragma_names_and_string): if len(pragma_names_and_string) == 1: freeform_string = pragma_names_and_string[0] args = () else: *args_identifiers, freeform_string = pragma_names_and_string args = list(map(str, args_identifiers)) # Strip the quotes from start/end of string which are matched # by the Lark grammar freeform_string = freeform_string[1:-1] p = Pragma(str(name), args=args, freeform_string=freeform_string) return p @v_args(inline=True) def measure(self, qubit, address): return MEASURE(qubit, address) @v_args(inline=True) def halt(self): return HALT @v_args(inline=True) def nop(self): return NOP @v_args(inline=True) def include(self, string): return RawInstr(f"INCLUDE {string}") @v_args(inline=True) def def_label(self, label): return JumpTarget(label) @v_args(inline=True) def jump(self, label): return Jump(label) @v_args(inline=True) def jump_when(self, label, address): return JumpWhen(label, address) @v_args(inline=True) def jump_unless(self, label, address): return JumpUnless(label, address) label = v_args(inline=True)(Label) @v_args(inline=True) def reset(self, qubit): if qubit: return ResetQubit(qubit) else: return Reset() @v_args(inline=True) def wait(self): return Wait() @v_args(inline=True) def store(self, left, subscript, right): return ClassicalStore(left, subscript, right) @v_args(inline=True) def load(self, left, right, subscript): return ClassicalLoad(left, right, subscript) @v_args(inline=True) def convert(self, left, right): return ClassicalConvert(left, right) @v_args(inline=True) def exchange(self, left, right): return ClassicalExchange(left, right) @v_args(inline=True) def move(self, left, right): return ClassicalMove(left, right) @v_args(inline=True) def classical_unary(self, op, target): if op == "TRUE": return ClassicalMove(target, 1) elif op == "FALSE": return ClassicalMove(target, 0) elif op == "NEG": return ClassicalNeg(target) elif op == "NOT": return ClassicalNot(target) @v_args(inline=True) def logical_binary_op(self, op, left, right): if op == "AND": return ClassicalAnd(left, right) elif op == "OR": return ClassicalInclusiveOr(left, right) elif op == "IOR": return ClassicalInclusiveOr(left, right) elif op == "XOR": return ClassicalExclusiveOr(left, right) @v_args(inline=True) def arithmetic_binary_op(self, op, left, right): if op == "ADD": return ClassicalAdd(left, right) elif op == "SUB": return ClassicalSub(left, right) elif op == "MUL": return ClassicalMul(left, right) elif op == "DIV": return ClassicalDiv(left, right) @v_args(inline=True) def classical_comparison(self, op, target, left, right): if op == "EQ": return ClassicalEqual(target, left, right) elif op == "GT": return ClassicalGreaterThan(target, left, right) elif op == "GE": return ClassicalGreaterEqual(target, left, right) elif op == "LT": return ClassicalLessThan(target, left, right) elif op == "LE": return ClassicalLessEqual(target, left, right) @v_args(inline=True) def waveform(self, name, *params): param_dict = {k: v for (k, v) in params} if param_dict: return _wf_from_dict(name, param_dict) else: return WaveformReference(name) @v_args(inline=True) def waveform_name(self, prefix, suffix=None): return f"{prefix}/{suffix}" if suffix else prefix def matrix(self, rows): return list(rows) def matrix_row(self, expressions): return list(expressions) def params(self, params): return list(params) @v_args(inline=True) def named_param(self, name, val): return (str(name), val) def qubit_designators(self, qubits): return list(qubits) qubit = v_args(inline=True)(Qubit) qubits = list qubit_variable = v_args(inline=True)(FormalArgument) qubit_variables = list @v_args(inline=True) def variable(self, var): variable = Parameter(str(var)) return variable def variables(self, variables): return list(variables) @v_args(inline=True) def i(self): return 1j @v_args(inline=True) def imag(self, number): return number * 1j @v_args(inline=True) def pi(self): return np.pi int_n = v_args(inline=True)(int) float_n = v_args(inline=True)(float) name = v_args(inline=True)(str) string = v_args(inline=True)(str) @v_args(inline=True) def signed_number(self, sign, number): if sign and sign == "-": return -number else: return number @v_args(inline=True) def apply_fun(self, fun, arg): if fun == "SIN": return quil_sin(arg) if isinstance(arg, Expression) else np.sin(arg) if fun == "COS": return quil_cos(arg) if isinstance(arg, Expression) else np.cos(arg) if fun == "SQRT": return quil_sqrt(arg) if isinstance(arg, Expression) else np.sqrt(arg) if fun == "EXP": return quil_exp(arg) if isinstance(arg, Expression) else np.exp(arg) if fun == "CIS": return quil_cis(arg) if isinstance(arg, Expression) else np.cos(arg) + 1j * np.sin(arg) add = v_args(inline=True)(operator.add) sub = v_args(inline=True)(operator.sub) mul = v_args(inline=True)(operator.mul) div = v_args(inline=True)(operator.truediv) pow = v_args(inline=True)(operator.pow) neg = v_args(inline=True)(operator.neg) pos = v_args(inline=True)(operator.pos) function = v_args(inline=True)(str) keyword = v_args(inline=True)(str)
class ETreeTransformer(Transformer): """ Transform a lark parsing tree into an ElementTree """ _strtype = v_args(inline=True)(str) value_list = list attribute = tuple element_children = list text = _strtype key = _strtype value = _strtype tag = _strtype def __init__(self, root_name=DEFAULT_ROOT_NAME, single_root_node=False, id_mapper=None): """ - root_name: tag of the root xml element that is added implicitly. Defaults to 'root' - single_root_node: if True, do not add a root xml element. In this case, the conf must have a single root - id_mapper: a user function to set the value_list after the tag. e.g. Resource "testlab" "loadbalancer1" { ... } testlab and loadbalancer1 could be attributes of 'Resource' element or sub-element or whatever you want (see make_id_mapper_elt and make_id_mapper_attr for examples). """ self.root_name = root_name self.single_root_node = single_root_node self.id_mapper = id_mapper # pylint: disable=no-self-use @v_args(inline=True) def triple_quoted_string(self, arg): "remove quote and replace escapes" res = arg[3:-3] return res.encode("utf-8") # pylint: disable=no-self-use @v_args(inline=True) def quoted_string(self, arg): "remove quote and replace escapes" res = arg[1:-1] replace_list = [ ("\\\"", "\""), ("\\\\", "\\"), ("\\/", "/"), ("\\b", "\b"), ("\\n", "\n"), ("\\r", "\r"), ("\\t", "\t") ] for replace_tuple in replace_list: res = res.replace(*replace_tuple) return res.encode("utf-8") @v_args(inline=True) def start(self, children=None): "match start of the grammar" if self.single_root_node: if len(children) != 1: raise Exception( "Error: the document does not contain a single "\ "top level element") return children[0] if not self.root_name: return children elt = etree.Element(self.root_name) _append_list(elt, children) return elt @v_args(inline=True) def element(self, tag, value_list=None, text=None, children=None): "create ElementTree node" elt = etree.Element(tag) if text: elt.text = text.decode("utf-8") if value_list and children is None: elt_lst = [] if text: elt_lst.append(elt) for value in value_list: xelt = etree.Element(tag) xelt.text = value.decode("utf-8") elt_lst.append(xelt) return elt_lst _append_list(elt, children) if value_list and children is not None and self.id_mapper: self.id_mapper(elt, value_list) return elt