Пример #1
0
def test_property_color_red():
    # color: red
    expression = Expression()
    expression.append(Ident("red"))
    property = Property(["color"], expression)
    assert property.expr == expression
    assert len(property.segments) == 1
    assert f"{property}" == "property(color, (red))"
Пример #2
0
    def invoke_builtin(self, fn, args):
        """
        :param fn:
        :param args:
        :return:
        """
        # map arguments to first node
        # providing a nicer js api for
        # built-in functions. Functions may specify that
        # they wish to accept full expressions
        # via raw_bifs
        if hasattr(fn, "__name__") and fn.__name__ in raw_bifs:
            ret = args.nodes
        else:
            ret = []
            # fit in the args to the functions
            sig = inspect.signature(fn)
            i = 0
            # remove the last parameter (the evaluator) first
            keys = [key for key in sig.parameters.keys()][:-1]
            for key in keys:
                param = sig.parameters.get(key)
                # handle the *args parameters
                if param.name == "args":
                    while i < len(args.nodes):
                        ret.append(utils.unwrap(args.nodes[i].first()))
                        i += 1
                # regular parameters
                elif param.name in args.map.keys():
                    # in the map
                    ret.append(args.map[param.name].first())
                else:
                    # then in the nodes
                    all_arguments = []
                    for nodes in args.nodes:
                        all_arguments.extend(unwrap(nodes))
                    if i < len(unwrap(all_arguments)):
                        ret.append(unwrap(all_arguments)[i].first())
                    i += 1
                    # else: assume remaining parameters are not required

        # invoke builtin function
        body = utils.coerce(
            fn(*ret, evaluator=self),
            False,
            lineno=self.parser.lineno,
            column=self.parser.column,
        )

        # Always wrapping allows js functions
        # to return several values with a single
        # Expression node
        expr = Expression()
        expr.append(body)
        body = expr

        return self.invoke(body)
Пример #3
0
def test_empty_expression():
    from stilus.nodes.null import null
    from stilus.nodes.boolean import false

    expression = Expression()
    assert len(expression) == 0
    assert expression.is_empty()
    assert expression.first() is null
    assert expression.to_boolean() is false
Пример #4
0
def test_unwrap_one_than_one():
    inner_expression = Expression()
    inner_expression.append(Unit(10))
    inner_expression.append(Unit(20))
    assert utils.unwrap(inner_expression) == inner_expression
    outer_expression = Expression()
    outer_expression.append(inner_expression)
    outer_expression.append(true)
    assert utils.unwrap(outer_expression) == outer_expression
Пример #5
0
def test_ternary():
    true_expression = Expression()
    false_expression = Expression()
    ternary = Ternary("+", true_expression, false_expression)
    assert ternary.node_name == "ternary"
    assert ternary.cond == "+"
    assert ternary.true_expr == true_expression
    assert ternary.false_expr == false_expression
    assert f"{ternary}" == f"(+,{true_expression},{false_expression})"
Пример #6
0
def test_binop():
    left = Expression()
    right = Expression()
    binop = BinOp("+", left, right)
    assert binop.node_name == "binop"
    assert binop.op == "+"
    assert binop.left == left
    assert binop.left == right
    assert f"{binop}" == f"{left} + {right}"
Пример #7
0
Файл: node.py Проект: jw/stilus
    def to_expression(self):
        """Return expression or wrap this node in an expression
        :return:
        """
        from stilus.nodes.expression import Expression

        if self.node_name == "expression":
            return self
        expression = Expression()
        expression.append(self)
        return expression
Пример #8
0
def split(delim, value, evaluator=None):
    assert_string(delim, "delimiter")
    assert_string(value, "val")
    words = value.string.split(delim.string)
    expr = Expression()
    for word in words:
        if isinstance(value, Ident):
            addition = Ident(word)
        else:
            addition = String(word)
        expr.append(Ident(addition))
    return expr
Пример #9
0
def test_unwrap_preserve():
    inner_expression = Expression()
    inner_expression.append(Unit(10))
    inner_expression.append(Unit(20))
    assert utils.unwrap(inner_expression) == inner_expression
    outer_expression = Expression()
    outer_expression.preserve = True
    outer_expression.append(inner_expression)
    assert utils.unwrap(outer_expression) == outer_expression
Пример #10
0
 def setup(self):
     self.populate_global_scope()
     for file in reversed(self.imports):
         expr = Expression()
         expr.append(
             String(file,
                    lineno=self.parser.lineno,
                    column=self.parser.column))
         self.root.nodes.insert(
             0,
             Import(expr,
                    lineno=self.parser.lineno,
                    column=self.parser.column),
         )
Пример #11
0
def test_from_expression():
    expression = Expression()
    expression.append(Unit(10, "mm"))
    expression.append(true)
    expression.lineno = 42
    expression.column = 13
    expression.is_list = True
    arguments = Arguments.from_expression(expression)
    assert arguments.nodes == expression.nodes
    assert arguments.lineno == expression.lineno
    assert arguments.column == expression.column
    assert arguments.is_list == expression.is_list
Пример #12
0
def range_function(start, stop, step=None, evaluator=None):
    assert_type(start, "unit", "start")
    assert_type(stop, "unit", "stop")
    if step:
        assert_type(step, "unit", "step")
        if step.value == 0:
            raise StilusError('ArgumentError: "step" argument '
                              "must not be zero")
    else:
        step = Unit(1)
    lst = Expression()
    i = start.value
    while i <= stop.value:
        lst.append(Unit(i, start.type))
        i += step.value
    return lst
Пример #13
0
def test_binop():
    expression = Expression()
    unaryop = UnaryOp("+", expression)
    assert unaryop.node_name == "unaryop"
    assert unaryop.op == "+"
    assert unaryop.expr == expression
    assert f"{unaryop}" == f"(+,{expression})"
Пример #14
0
def test_block_properties():
    block = Block(
        Comment("comment", False, False),
        Block(String("hello"), String("There!")),
    )
    block.append(Property(["foo", "bar"], Expression()))
    assert block.has_properties() is True
    assert block.has_media() is False
Пример #15
0
def test_property():
    expression = Expression()
    block = Block("parent", Node)
    each = Each("foo", "fizz", expression, block)
    assert each.node_name == "each"
    assert each.value == "foo"
    assert each.key == "fizz"
    assert each.expr == expression
    assert each.block == block
Пример #16
0
def test_feature():
    foo = Ident("foo")
    bar = Ident("bar")
    feature = Feature([foo, bar])
    assert feature.node_name == "feature"
    assert feature.segments == [foo, bar]
    assert feature.expr is None
    expression = Expression()
    feature.expr = expression
    assert feature.expr == expression
Пример #17
0
def test_property_expression():
    from stilus.nodes.boolean import true
    from stilus.nodes.boolean import false
    from stilus.nodes.null import null

    expression = Expression()
    expression.append(true)
    expression.append(false)
    expression.append(null)
    property = Property(["foo", "bar"], expression)
    assert property.node_name == "property"
    assert len(property.segments) == 2
    assert property.expr is expression
    assert f"{property}" == "property(foobar, (true false null))"
    expression.is_list = True
    assert f"{property}" == "property(foobar, (true, false, null))"
Пример #18
0
    def property_expression(self, prop, name):
        expr = Expression(lineno=self.parser.lineno, column=self.parser.column)
        value = prop.expr.clone(None)

        # name
        expr.append(
            String(prop.name,
                   lineno=self.parser.lineno,
                   column=self.parser.column))

        # replace cyclic call with __CALL__
        def replace(node):
            if (node.node_name == "call" and hasattr(node, "function_name")
                    and name == node.function_name):
                return Literal(
                    "__CALL__",
                    lineno=self.parser.lineno,
                    column=self.parser.column,
                )
            if hasattr(node, "nodes") and node.nodes:
                node.nodes = [replace(n) for n in node.nodes]
            return node

        replace(value)
        expr.append(value)
        return expr
Пример #19
0
def selectors(evaluator=None):
    stack = evaluator.selector_stack()
    expr = Expression(is_list=True)
    if stack:
        for i, group in enumerate(stack):
            if len(group) > 1:
                selector_values = []
                for selector in group:
                    nested = SelectorParser(selector.value).parse()["nested"]
                    if nested and i != 0:
                        selector_values.append(f"& {selector.value}")
                    else:
                        selector_values.append(f"{selector.value}")
                expr.append(String(",".join(selector_values)))
            else:
                selector = group[0].value
                nested = SelectorParser(selector).parse()["nested"]
                if nested and i != 0:
                    expr.append(String(f"& {selector}"))
                else:
                    expr.append(String(f"{selector}"))
    else:
        expr.append(String("&"))
    return expr
Пример #20
0
def test_expression_append():
    from stilus.nodes.null import null
    from stilus.nodes.boolean import true
    from stilus.nodes.boolean import false

    expression = Expression()
    expression.append(null)
    expression.append(true)
    expression.append(false)
    assert len(expression) == 3
Пример #21
0
def test_coerce():
    first = String("hello")
    other = String("there")
    assert first.coerce(other) == other
    expression = Expression()
    expression.append(String("one"))
    expression.append(String("two"))
    expression.append(String("three"))
    assert first.coerce(expression) == String("one two three")
    assert first.coerce(null) == String("null")
    assert first.coerce(Ident("foobar")) == String("foobar")
Пример #22
0
    def operate(self, op, right, value=None):
        value = right.first()
        if op == "-":
            if value.node_name == "unit":
                from stilus.nodes.expression import Expression

                expression = Expression()
                value = value.clone()
                value.value = -value.value
                expression.append(self)
                expression.append(value)
                return expression
        elif op == "+":
            return Ident(self.string + self.coerce(value).string)
        return super().operate(op, right)
Пример #23
0
def image_size(img: str, ignore_errors=False, evaluator=None):
    assert_type(img, "string", "img")
    p = Path(img.string)
    path = lookup(p, evaluator.paths)
    if p.suffix == ".svg":
        return _x_and_y_from_svg(path)
    if path:
        with Image.open(path) as image:
            x, y = image.size
            expression = Expression()
            expression.nodes = [Unit(x, "px"), Unit(y, "px")]
            return expression
    elif ignore_errors:
        expression = Expression()
        expression.nodes = [Unit(0), Unit(0)]
        return expression
    else:
        raise StilusError("Could not find image.")
Пример #24
0
def test_expression_operate_in():
    # empty expression
    expression = Expression()
    other_expression = Expression()
    other_expression.append(Ident("foo"))
    other_expression.append(Ident("bar"))
    assert expression.operate("in", other_expression) == Boolean(False)
    with pytest.raises(StilusError):
        other_expression.operate("in", expression) == Boolean(True)

    # same expression
    expression = Expression()
    expression.append(Ident("foo"))
    expression.append(Ident("bar"))
    assert expression.operate("in", expression) == Boolean(False)

    # other expression
    expression = Expression()
    expression.append(Ident("foo"))
    expression.append(Ident("bar"))
    other_expression = Expression()
    other_expression.append(Ident("bar"))
    assert other_expression.operate("in", expression) == Boolean(True)
Пример #25
0
def test_expression_creation():
    expression = Expression()
    assert not expression.is_list
    assert not expression.preserve
    assert expression.node_name == "expression"
Пример #26
0
def test_expression_make_is_list_and_preserve():
    expression = Expression()
    expression.is_list = True
    expression.preserve = True
    assert expression.is_list
    assert expression.preserve
Пример #27
0
def test_expression_hash():
    expression = Expression()
    assert expression.hash() == ""
    expression = Expression()
    expression.append(Ident("foo"))
    assert expression.hash() == "foo"
    other_expression = Expression()
    other_expression.append(Ident("foo"))
    other_expression.append(Ident("bar"))
    assert other_expression.hash() == "foo::bar"
    from stilus.nodes.null import null
    from stilus.nodes.boolean import true
    from stilus.nodes.boolean import false

    expression = Expression()
    expression.append(null)
    expression.append(true)
    expression.append(false)
    # in stylus null::true::false is returned; stilus returns the Python types
    assert expression.hash() == "None::True::False"
Пример #28
0
def test_expression_string_first_boolean():
    from stilus.nodes.boolean import true
    from stilus.nodes.boolean import false
    from stilus.nodes.null import null

    expression = Expression()
    expression.append(true)
    expression.append(false)
    expression.append(null)
    assert str(expression) == "(true false null)"
    expression.is_list = True
    assert str(expression) == "(true, false, null)"
    assert expression.first() is true
    assert expression.to_boolean().value is True
Пример #29
0
def test_expression_creation_with_is_list_and_preserve():
    expression = Expression(is_list=True, preserve=True)
    assert expression.is_list
    assert expression.preserve
Пример #30
0
    def invoke_function(self, fn, args, content):
        block = Block(
            fn.block.parent,
            None,
            lineno=self.parser.lineno,
            column=self.parser.column,
        )

        # clone the function body to prevent mutation of subsequent calls
        body = fn.block.clone(block)

        mixin_block = self.stack.current_frame().block

        # new block scope
        self.stack.append(Frame(block))
        scope = self.get_current_scope()

        # normalize arguments
        if args.node_name != "arguments":
            expr = Expression()
            expr.append(args)
            args = Arguments.from_expression(expr)

        # arguments
        scope.add(Ident("arguments", args))

        # mixin scope introspection
        bn = mixin_block.node_name
        if self.result:
            scope.add(Ident("mixin", false))
        else:
            scope.add(
                Ident(
                    "mixin",
                    String(
                        bn,
                        lineno=self.parser.lineno,
                        column=self.parser.column,
                    ),
                ))

        # current property
        if self.property:
            prop = self.property_expression(self.property, fn.function_name)
            scope.add(
                Ident(
                    "current-property",
                    prop,
                    lineno=self.parser.lineno,
                    column=self.parser.column,
                ))
        else:
            scope.add(
                Ident(
                    "current-property",
                    null,
                    lineno=self.parser.lineno,
                    column=self.parser.column,
                ))

        # current call stack
        expr = Expression(lineno=self.parser.lineno, column=self.parser.column)
        for call in reversed(self.calling[:-1]):
            expr.append(
                Literal(call,
                        lineno=self.parser.lineno,
                        column=self.parser.column))
        scope.add(
            Ident(
                "called-from",
                expr,
                lineno=self.parser.lineno,
                column=self.parser.column,
            ))

        # inject arguments as locals
        # todo: rewrite this!
        i = 0
        for index, node in enumerate(fn.params.nodes):
            # rest param support
            if node.rest:
                node.value = Expression(lineno=self.parser.lineno,
                                        column=self.parser.column)
                for n in args.nodes[i:]:
                    node.value.append(n)
                node.value.preserve = True
                node.value.is_list = args.is_list
            else:
                # argument default support

                # in dict?
                arg = args.map.get(node.name)
                # next node?
                if not arg:
                    if hasattr(args, "nodes") and i < len(args.nodes):
                        arg = args.nodes[i]
                    i += 1

                node = node.clone()
                if arg is not None:
                    if hasattr(arg, "is_empty") and arg.is_empty():
                        args.nodes[i - 1] = self.visit(node)
                    else:
                        node.value = arg
                else:
                    args.append(node.value)

                # required argument not satisfied
                if not node.value:
                    raise TypeError(f'argument "{node}" required for {fn}')

            scope.add(node)

        # mixin block
        if content:
            scope.add(Ident("block", content, True))

        # invoke
        return self.invoke(body, True, fn.filename)