예제 #1
0
파일: evaluator.py 프로젝트: jw/stilus
    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
예제 #2
0
파일: test_utils.py 프로젝트: jw/stilus
def test_unwrap():
    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)
    assert utils.unwrap(outer_expression) == inner_expression
예제 #3
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))"
예제 #4
0
파일: evaluator.py 프로젝트: jw/stilus
    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)
예제 #5
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
예제 #6
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
예제 #7
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")
예제 #8
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
예제 #9
0
파일: stilus_split.py 프로젝트: jw/stilus
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
예제 #10
0
파일: evaluator.py 프로젝트: jw/stilus
 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 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)
예제 #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
파일: test_utils.py 프로젝트: jw/stilus
def test_unwrap_double():
    first_expression = Expression()
    first_expression.append(Unit(10))
    first_expression.append(Unit(20))
    inner_expression = Expression()
    inner_expression.append(first_expression)
    outer_expression = Expression()
    outer_expression.append(inner_expression)
    last_expression = Expression()
    last_expression.append(outer_expression)
    assert utils.unwrap(last_expression) == first_expression
예제 #14
0
파일: test_utils.py 프로젝트: jw/stilus
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
예제 #15
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"
예제 #16
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
예제 #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 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)
예제 #19
0
파일: selectors.py 프로젝트: jw/stilus
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
파일: evaluator.py 프로젝트: jw/stilus
    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)