def base_convert(num, base, width=None, evaluator=None): if isinstance(num, Expression): num = unwrap(num).nodes[0] if isinstance(base, Expression): base = unwrap(base).nodes[0] if width and isinstance(width, Expression): width = unwrap(width).nodes[0] assert_type(num, "unit") assert_type(base, "unit") if width: assert_type(width, "unit") if width: width = width.value else: width = 2 num = int(num.value) base = int(base.value) result = _convert(num, base) while len(result) < width: result = "0" + result return Literal(result)
def p(*args, evaluator=None): for arg in args: expr = unwrap(arg) if not expr: return None e = str(expr) if e.startswith("("): e = e[1:] if e.endswith(")"): e = e[:-1] print(f"inspect: {e}") return null
def lookup(self, name): """ Lookup `name`, with support for JavaScript functions, and BIFs. :param name: :return: """ if self.ignore_colors and name in colors: return val = self.stack.lookup(name) if val is not None: # fixme: implement __len__() return utils.unwrap(val) else: return self.lookup_function(name)
def add_property(name, expr, evaluator=None): assert_type(name, "expression", "name") name = unwrap(name).first() assert_string(name, "name") assert_type(expr, "expression", "expr") prop = Property([name], expr) block = evaluator.closest_block() head = block.nodes[0:block.index] tail = block.nodes[block.index:len(block.nodes)] block.index += 1 block.mixin = True # this is a dirty hack head.append(prop) head.extend(tail) block.nodes = head return prop
def s(fmt, *args, evaluator=None): options = evaluator.options if evaluator else {} fmt = unwrap(fmt).nodes[0] assert_string(fmt, "string") result = fmt.string results = [] for arg in args: from stilus.visitor.evaluator import Evaluator if not isinstance(arg, Evaluator): results.append(Compiler(arg, options).compile()) for r in results: result = result.replace("%s", r, 1) # add nulls for missed %s elements c = Compiler(null, options).compile() result = result.replace("%s", c) return Literal(result)
def opposite_position(positions, evaluator=None): expr = [] nodes = utils.unwrap(positions) for i, node in enumerate(nodes): utils.assert_string(node, f"position {i}") if node.string == "top": expr.append(Literal("bottom")) elif node.string == "bottom": expr.append(Literal("top")) elif node.string == "left": expr.append(Literal("right")) elif node.string == "right": expr.append(Literal("left")) elif node.string == "center": expr.append(Literal("center")) else: raise StilusError(f"invalid position {i}") return expr
def visit_each(self, each): self.result += 1 expr = utils.unwrap(self.visit(each.expr)) length = len(expr.nodes) val = Ident(each.value) key = Ident("__index__") if each.key: key = Ident(each.key) scope = self.get_current_scope() block = self.get_current_block() vals = [] self.result -= 1 each.block.scope = False def visit_body(key, value): scope.add(value) scope.add(key) body = self.visit(each.block.clone()) vals.extend(body.nodes) # for prop in obj if length == 1 and "objectnode" == expr.nodes[0].node_name: obj = expr.nodes[0] for prop in obj.values: val.value = String(prop, lineno=self.parser.lineno, column=self.parser.column) key.value = obj.get(prop) # checkme: works? visit_body(key, val) else: for i, n in enumerate(expr.nodes): val.value = n key.value = Unit(i) visit_body(key, val) self.mixin(vals, block) if vals and len(vals) > 0: return vals[len(vals) - 1] else: return null
def slice(values, start, end=None, evaluator=None): start = int(start.nodes[0].value) if end and len(end.nodes) > 0: end = int(end.nodes[0].value) values = utils.unwrap(values).nodes if len(values) > 1: if end: return utils.coerce(values[start:end], raw=True) else: return utils.coerce(values[start:], raw=True) if end: result = values[0].string[start:end] else: result = values[0].string[start:] if isinstance(values[0], Ident): return Ident(result) else: return String(result)
def selector(*args, evaluator=None): stack = evaluator.selector_stack() if len(args) == 1: expr = unwrap(args[0]) length = len(expr.nodes) # selector .a if length == 1: assert_string(expr.first(), "selector") value = expr.first().string parsed = SelectorParser(value).parse()["value"] if parsed == value: return value stack.append(parse(value)) elif length > 1: # selector-list = '.a', '.b', '.c' # selector(selector-list) if expr.is_list: push_to_stack(expr.nodes, stack) # selector('.a' '.b' '.c') else: joined = " ".join([node.string for node in expr.nodes]) stack.append(parse(joined)) # selector('.a', '.b', '.c') elif len(args) > 1: push_to_stack(args, stack) if stack: return ",".join(compile_selectors(stack)) else: return "&"
def visit_property(self, prop): name = self.interpolate(prop) fn = self.lookup(name) call = fn and "function" == fn.first().node_name literal = name in self.calling _prop = self.property prop_lit = True if hasattr(prop, "literal") and prop.literal else False if call and not literal and not prop_lit: # function of the same node_name clone = prop.expr.clone(None, None) args = Arguments.from_expression(utils.unwrap(clone)) prop.name = name self.property = prop self.result += 1 self.property.expr = self.visit(prop.expr) self.result -= 1 ret = self.visit( Call( name, args, lineno=self.parser.lineno, column=self.parser.column, )) self.property = _prop return ret else: # regular property self.result += 1 prop.name = name prop.literal = True self.property = prop prop.expr = self.visit(prop.expr) self.property = _prop self.result -= 1 return prop
def list_separator(list, evaluator=None): list = unwrap(list) return String("," if list.is_list else " ")
def unshift(expr, *args, evaluator=None): expr = unwrap(expr) for arg in args: a = unwrap(arg) expr.nodes.insert(0, a) return len(expr.nodes)
def test_unwrap_no_expression(): assert utils.unwrap(true) == true assert utils.unwrap(Unit(50, "mm")) == Unit(50, "mm")
def operate( # noqa: C901 self, op: str, right: Type["Node"], value=None ) -> "Node": """Operate on ``right`` with the given ``op``.""" from .boolean import Boolean if op == "is a": if "string" == right.first().node_name: return Boolean(self.node_name == right.value) else: raise Exception( f'"is a" expects a string, ' f"got {right.toString}" ) elif op == "==": from stilus import utils if utils.is_number(self) and utils.is_number(right): return Boolean(utils.get_value(self) == utils.get_value(right)) return Boolean(self.hash() == right.hash()) elif op == "!=": return Boolean(self.hash() != right.hash()) elif op == ">=": return Boolean(self.hash() >= right.hash()) elif op == "<=": return Boolean(self.hash() <= right.hash()) elif op == ">": if self.one_is_unit(right): return Boolean(float(self.hash()) > float(right.hash())) return Boolean(self.hash() > right.hash()) elif op == "<": return Boolean(self.hash() < right.hash()) elif op == "||": return self if self.to_boolean().value is True else right elif op == "in": from stilus import utils values = utils.unwrap(right).nodes if not values: raise StilusError( '"in" given invalid right-hand operand, ' "expecting an expression" ) # 'prop' in object if len(values) == 1 and values[0].node_name == "objectnode": return Boolean(values[0].has(self.hash())) for value in values: if str(value.hash()) == str(self.hash()): return Boolean(True) return Boolean(False) elif op == "&&": a = self.to_boolean() b = right.to_boolean() if a.value is True and b.value is True: return right elif a.value is False: return self return right elif op == "[]": raise StilusError(f"cannot perform {self}[{right}]") else: raise StilusError(f"cannot perform {self} {op} {right}")
def push(expr, *args, evaluator=None): expr = unwrap(expr) if evaluator: for arg in args: expr.nodes.append(unwrap(arg).clone()) return len(expr.nodes)
def shift(expr, *args, evaluator=None): expr = unwrap(expr) if len(expr.nodes) > 0: return expr.nodes.pop(0) else: return null