예제 #1
0
    def visit_Subscript(self, node):
        from ast import Expr, Call, Name, Load, Lambda, arguments, arg

        m = match("E[ _expr | _x in _set]", node)
        if m:
            x_s = m["_x"].id  # name of dummy vaqriable
            expr = m["_expr"]
            sset = m["_set"]
            res = Call(
                func=Name(id="Ex", ctx=Load()),
                args=[
                    Lambda(
                        args=arguments(
                            args=[arg(arg=x_s, annotation=None)],
                            vararg=None,
                            kwonlyargs=[],
                            kw_defaults=[],
                            kwarg=None,
                            defaults=[],
                        ),
                        body=expr,
                    ),
                    sset,
                ],
                keywords=[],
                starargs=None,
                kwargs=None,
            )
            return res
        m = match("Sum[ _expr | _x in _set]", node)
        if m:
            x_s = m["_x"].id  # name of dummy vaqriable
            expr = m["_expr"]
            sset = m["_set"]
            res = Call(
                func=Name(id="Sum", ctx=Load()),
                args=[
                    Lambda(
                        args=arguments(
                            args=[arg(arg=x_s, annotation=None)],
                            vararg=None,
                            kwonlyargs=[],
                            kw_defaults=[],
                            kwarg=None,
                            defaults=[],
                        ),
                        body=expr,
                    ),
                    sset,
                ],
                keywords=[],
                starargs=None,
                kwargs=None,
            )
            return res

        return node
예제 #2
0
def _make_coverage_dummy_expr(macronode):
    """Force expression `macronode` to be reported as covered by coverage tools.

    This facilitates "deleting" expression nodes by `return None` from a macro.
    Since an expression slot in the AST cannot be empty, we inject a dummy node
    that evaluates to `None`.

    `macronode` is the macro invocation node to copy source location info from.
    """
    # TODO: inject the macro name for human-readability
    # We inject a lambda and an immediate call to it, because a constant `None`,
    # if it appears alone in an `ast.Expr`, is optimized away by CPython.
    # We must set location info manually, because we run after `expand`.
    non = copy_location(Constant(value=None), macronode)
    lam = copy_location(
        Lambda(args=arguments(posonlyargs=[],
                              args=[],
                              vararg=None,
                              kwonlyargs=[],
                              kw_defaults=[],
                              kwarg=None,
                              defaults=[]),
               body=non), macronode)
    call = copy_location(Call(func=lam, args=[], keywords=[]), macronode)
    return Done(call)
예제 #3
0
    def visit_BoolOp(self, node: BoolOp) -> Union[UnaryOp, Call]:
        self.generic_visit(node)

        if isinstance(node.op, And):
            runtime = '__lazybooland__'
        elif isinstance(node.op, Or):
            runtime = '__lazyboolor__'
        else:
            return node

        lhs, rhs = node.values
        delegate = Call(
            func=Name(id=runtime, ctx=Load()),
            args=[
                lhs,
                # Make the rhs a deferred computation by wrapping with a lambda
                Lambda(args=arguments(args=[],
                                      kwonlyargs=[],
                                      kw_defaults=[],
                                      defaults=[]),
                       body=rhs)
            ],
            keywords=[])

        copy_location(delegate, node)
        fix_missing_locations(delegate)
        return delegate
예제 #4
0
def rewrite_with_to_binds(body, monad):
    new_body = []
    # Construct a transformer for this specific monad's mreturn
    rdb = RewriteDoBody(monad)
    # This is the body of the lambda we're about to construct
    last_part = body[-1].value
    # Rewrite mreturn
    rdb.visit(last_part)
    # Iterate in reverse, making each line the into a lambda whose body is the
    # rest of the lines (which are each lambdas), and whose names are the
    # bind assignments.
    for b in reversed(body[:-1]):
        rdb.visit(b)
        if isinstance(b, Assign):
            name = b.targets[0].id
            value = b.value
        else:
            # If there was no assignment to the bind, just use a random name, eek
            name = '__DO_NOT_NAME_A_VARIABLE_THIS_STRING__'
            value = b.value
        # last part = value.bind(lambda name: last_part)
        last_part = Call(func=Attribute(value=value, attr='bind', ctx=Load()),
                         args=[
                             Lambda(args=arguments(args=[
                                 Name(id=name, ctx=Param()),
                             ],
                                                   vararg=None,
                                                   kwarg=None,
                                                   defaults=[]),
                                    body=last_part),
                         ],
                         keywords=[],
                         starargs=None,
                         kwargs=None)
    return last_part
예제 #5
0
 def visit_ClassDef(self, node):
     """Process property defaults for Scenic classes."""
     if node.name in self.constructors:  # Scenic class definition
         newBody = []
         for child in node.body:
             child = self.visit(child)
             if isinstance(child, AnnAssign):  # default value for property
                 origValue = child.annotation
                 target = child.target
                 # extract any attributes for this property
                 metaAttrs = []
                 if isinstance(target, Subscript):
                     sl = target.slice
                     if not isinstance(sl, Index):
                         self.parseError(sl, 'malformed attributes for property default')
                     sl = sl.value
                     if isinstance(sl, Name):
                         metaAttrs.append(sl.id)
                     elif isinstance(sl, Tuple):
                         for elt in sl.elts:
                             if not isinstance(elt, Name):
                                 self.parseError(elt,
                                                 'malformed attributes for property default')
                             metaAttrs.append(elt.id)
                     else:
                         self.parseError(sl, 'malformed attributes for property default')
                     newTarget = Name(target.value.id, Store())
                     copy_location(newTarget, target)
                     target = newTarget
                 # find dependencies of the default value
                 properties = AttributeFinder.find('self', origValue)
                 # create default value object
                 args = [
                     Set([Str(prop) for prop in properties]),
                     Set([Str(attr) for attr in metaAttrs]),
                     Lambda(self.self_args, origValue)
                 ]
                 value = Call(Name(createDefault, Load()), args, [])
                 copy_location(value, origValue)
                 newChild = AnnAssign(
                     target=target, annotation=value,
                     value=None, simple=True)
                 child = copy_location(newChild, child)
             newBody.append(child)
         node.body = newBody
         return node
     else:  # ordinary Python class
         # it's impossible at the moment to define a Python class in a Scenic file,
         # but we'll leave this check here for future-proofing
         for base in node.bases:
             name = None
             if isinstance(base, Call):
                 name = base.func.id
             elif isinstance(base, Name):
                 name = base.id
             if name is not None and name in self.constructors:
                 self.parseError(node,
                                 f'Python class {node.name} derives from PRS class {name}')
         return self.generic_visit(node)
예제 #6
0
	def visit_ClassDef(self, node):
		"""Process property defaults for Scenic classes."""
		if node.name in self.constructors:		# constructor definition
			newBody = []
			for child in node.body:
				child = self.visit(child)
				if isinstance(child, AnnAssign):	# default value for property
					origValue = child.annotation
					target = child.target
					# extract any attributes for this property
					metaAttrs = []
					if isinstance(target, Subscript):
						sl = target.slice
						if not isinstance(sl, Index):
							self.parseError(sl, 'malformed attributes for property default')
						sl = sl.value
						if isinstance(sl, Name):
							metaAttrs.append(sl.id)
						elif isinstance(sl, Tuple):
							for elt in sl.elts:
								if not isinstance(elt, Name):
									self.parseError(elt,
									    'malformed attributes for property default')
								metaAttrs.append(elt.id)
						else:
							self.parseError(sl, 'malformed attributes for property default')
						newTarget = Name(target.value.id, Store())
						copy_location(newTarget, target)
						target = newTarget
					# find dependencies of the default value
					properties = AttributeFinder.find('self', origValue)
					# create default value object
					args = [
						Set([Str(prop) for prop in properties]),
						Set([Str(attr) for attr in metaAttrs]),
						Lambda(selfArg, origValue)
					]
					value = Call(Name(createDefault, Load()), args, [])
					copy_location(value, origValue)
					newChild = AnnAssign(
						target=target, annotation=value,
						value=None, simple=True)
					child = copy_location(newChild, child)
				newBody.append(child)
			node.body = newBody
			return node
		else:		# ordinary Python class
			# catch some mistakes where 'class' was used instead of 'constructor'
			for base in node.bases:
				name = None
				if isinstance(base, Call):
					name = base.func.id
				elif isinstance(base, Name):
					name = base.id
				if name is not None and name in self.constructors:
					self.parseError(node, f'must use "{constructorStatement}" to subclass objects')
			return self.generic_visit(node)
예제 #7
0
    def visit_Subscript(self, node):
        from ast import Expr, Call, Name, Load, Lambda, arguments, arg
        m = match('E[ _expr | _x in _set]', node)
        if m:
            x_s = m['_x'].id  # name of dummy vaqriable
            expr = m['_expr']
            sset = m['_set']
            res = Call(func=Name(id='Ex', ctx=Load()),
                       args=[
                           Lambda(args=arguments(
                               args=[arg(arg=x_s, annotation=None)],
                               vararg=None,
                               kwonlyargs=[],
                               kw_defaults=[],
                               kwarg=None,
                               defaults=[]),
                                  body=expr), sset
                       ],
                       keywords=[],
                       starargs=None,
                       kwargs=None)
            return res
        m = match('Sum[ _expr | _x in _set]', node)
        if m:
            x_s = m['_x'].id  # name of dummy vaqriable
            expr = m['_expr']
            sset = m['_set']
            res = Call(func=Name(id='Sum', ctx=Load()),
                       args=[
                           Lambda(args=arguments(
                               args=[arg(arg=x_s, annotation=None)],
                               vararg=None,
                               kwonlyargs=[],
                               kw_defaults=[],
                               kwarg=None,
                               defaults=[]),
                                  body=expr), sset
                       ],
                       keywords=[],
                       starargs=None,
                       kwargs=None)
            return res

        return node
예제 #8
0
 def visit_Call(self, node):
     """Wrap require statements with lambdas and unpack any argument packages."""
     func = node.func
     if isinstance(
             func,
             Name) and func.id == requireStatement:  # Require statement
         # Soft reqs have 2 arguments, including the probability, which is given as the
         # first argument by the token translator; so we allow an extra argument here and
         # validate it later on (in case the user wrongly gives 2 arguments to require).
         if not (1 <= len(node.args) <= 2):
             raise self.parseError(node,
                                   'require takes exactly one argument')
         if len(node.keywords) != 0:
             raise self.parseError(node,
                                   'require takes no keyword arguments')
         cond = node.args[-1]
         if isinstance(cond, Starred):
             raise self.parseError(
                 node, 'argument unpacking cannot be used with require')
         req = self.visit(cond)
         line = self.lineMap[node.lineno]
         reqID = Num(len(self.requirements))  # save ID number
         self.requirements.append(
             req)  # save condition for later inspection when pruning
         closure = Lambda(noArgs, req)  # enclose requirement in a lambda
         lineNum = Num(line)  # save line number for error messages
         copy_location(closure, req)
         copy_location(lineNum, req)
         newArgs = [reqID, closure, lineNum]
         if len(node.args) == 2:  # get probability for soft requirements
             prob = node.args[0]
             if not isinstance(prob, Num):
                 raise self.parseError(
                     node, 'malformed requirement '
                     '(should be a single expression)')
             newArgs.append(prob)
         return copy_location(Call(func, newArgs, []), node)
     else:  # Ordinary function call
         newArgs = []
         # Translate arguments, unpacking any argument packages
         for arg in node.args:
             if isinstance(arg, BinOp) and isinstance(arg.op, packageNode):
                 newArgs.extend(self.unpack(arg, 2, node))
             else:
                 newArgs.append(self.visit(arg))
         newKeywords = [self.visit(kwarg) for kwarg in node.keywords]
         return copy_location(Call(func, newArgs, newKeywords), node)
예제 #9
0
def _visit_lam(self: 'ASTTagger', node: ast.Lambda):
    args = node.args
    new = self.symtable.enter_new()
    arguments = args.args + args.kwonlyargs
    if args.vararg:
        arguments.append(args.vararg)
    if args.kwarg:
        arguments.append(args.kwarg)
    for arg in arguments:
        # lambda might be able to annotated in the future?
        annotation = arg.annotation
        if annotation:
            self.visit(annotation)
        new.entered.add(arg.arg)

    new_tagger = ASTTagger(new)
    node.body = new_tagger.visit(node.body)
    return Tag(node, new)
예제 #10
0
파일: transformer.py 프로젝트: Lattay/worm
def make_lambda(expr):
    """
    Take an expression and return a thunk node evaluating to that expression
    """
    return copy_loc(
        expr,
        Lambda(
            args=arguments(
                posonlyargs=[],
                args=[],
                varargs=[],
                kwonlyargs=[],
                kw_defaults=[],
                defaults=[],
            ),
            body=expr,
        ),
    )
예제 #11
0
파일: astlib.py 프로젝트: dhilst/lampy
 def inner(e):
     return Lambda(args=arguments(args=[arg(a) for a in args]), body=e)
예제 #12
0
파일: letast.py 프로젝트: dhilst/lampy
def create_let_lamb(call, body):
    return Lambda(
        args=arguments(args=[arg(arg=a.id) for a in call.args], ),
        body=body,
    )