Exemplo n.º 1
0
    def process(self, scope, preserve_types=False):
        lhs = to_value(self.lhs, scope)
        op = self.operator

        if op is not None:
            rhs = to_value(self.rhs, scope)

            if op.power:
                return lhs**rhs, None
            elif op.bitwise_not:
                return ~rhs, None
            elif op.multiply:
                return lhs * rhs, None
            elif op.divide:
                return lhs / rhs, None
            elif op.modulus:
                return lhs & rhs, None
            elif op.add:
                return lhs + rhs, None
            elif op.subtract:
                return lhs - rhs, None
            elif op.bitwise_and:
                return lhs & rhs, None
            elif op.bitwise_xor:
                return lhs ^ rhs, None
            elif op.bitwise_or:
                return lhs | rhs, None

            return None, None

        if preserve_types:
            return self.lhs, None
        else:
            return lhs, None
Exemplo n.º 2
0
    def resolve(self, scope, fallback=None):
        if self.skip:
            return fallback

        value = scope.get(self.as_key(scope), fallback)

        return to_value(value, scope)
Exemplo n.º 3
0
def execute_script(browser, script, scope=None, environment=None, preserve_state=False, scriptpath=None):
    # setup the environment
    if not environment:
        environment = Environment(scope, browser=browser)

    if not scope:
        scope = environment.scope

    if not scriptpath:
        scriptpath = os.path.abspath(os.getcwd())

    callbacks = set()

    # load and parse the script
    friendscript = parser.Friendscript(data=script, environment=environment)

    # tell the environment about the calling script
    environment.script = friendscript

    if browser:
        # setup event handlers for this execution
        for handler in friendscript.handlers:
            callback_id = browser.default.on(
                parser.to_value(handler.pattern, scope),
                _handle_event(friendscript, handler, scope)
            )

            logging.debug('Add event handler {}'.format(callback_id))
            callbacks.add(callback_id)

    # Script Execution starts NOW
    # ---------------------------------------------------------------------------------------------
    try:
        # recursively evaluate all blocks and nested blocks starting from the top level
        for block in friendscript.blocks:
            try:
                evaluate_block(friendscript, block, scope, scriptpath=scriptpath)
            except parser.exceptions.ScriptError:
                raise
            except Exception as e:
                logging.debug('Exception')
                raise
                raise parser.exceptions.ScriptError('{}'.format(e), model=block)

    finally:
        if not preserve_state:
            # unregister the event handlers we created for this run
            for callback_id in callbacks:
                logging.debug('Remove event handler {}'.format(callback_id))
                browser.default.remove_handler(callback_id)

    # ...and done.
    # ---------------------------------------------------------------------------------------------

    # return the final state after script execution
    return scope
Exemplo n.º 4
0
    def evaluate(self, environment, scope=None):
        if scope is None:
            scope = environment.scope

        # Inline Assignment and test condition
        # ------------------------------------------------------------------------------------------
        if self.assignment:
            self.assignment.assign(environment, scope, force=True)

            # recursively evaluate the condition portion of the statement
            return self.condition.evaluate(environment, scope)

        # Command Evaluation (with optional test condition)
        # ------------------------------------------------------------------------------------------
        elif self.command:
            # execute the command
            resultkey, result = environment.execute(self.command, scope)

            # whatever the result of the expression command was, put it in the calling scope
            scope.set(resultkey, result, force=True)

            # if the statement has a condition, then evaluate using it
            if self.condition:
                # recursively evaluate the condition portion of the statement
                return self.condition.evaluate(environment, scope)
            else:
                # no condition, so just do the same thing as a unary comparison
                return self.compare(result)

        # Comparison
        # ------------------------------------------------------------------------------------------
        else:
            result = self.compare(to_value(self.lhs, scope), self.operator,
                                  to_value(self.rhs, scope))

        if self.negate is True:
            return not result
        else:
            return result
Exemplo n.º 5
0
    def as_key(self, scope):
        parts = tuple()

        for part in self.parts:
            if len(part.key):
                parts = parts + (part.key.decode('UTF-8'), )

            if part.index is not None:
                index = to_value(part.index, scope)

                if index is not None:
                    parts = parts + (index, )

        return parts
Exemplo n.º 6
0
    def interpolate(self, value, scope=None, deindent_heredocs=True, **kwargs):
        if scope is None:
            scope = self._scope

        scope = Scope(kwargs, parent=scope)
        scopevars = scope.as_dict()

        if isinstance(value, parser.lang.Expression):
            value, _ = value.process(scope, preserve_types=True)

        # if this is an exact-match string, then interpolate is a no-op
        if isinstance(value, parser.types.StringLiteral):
            if isinstance(value, str):
                value = value.decode('UTF-8')

            return value

        # for heredocs, we're going to return the literal as-is, but we trim off the indentation
        # whitespace of the calling command, that way heredocs can be written to match the indentation
        # level of the surrounding script, but when evaluated they are indented to the "intended" level
        if isinstance(value, parser.types.Heredoc):
            if deindent_heredocs:
                return value.deindent(self.col - 1)
            else:
                return value

        actual = parser.to_value(value, scope)

        if isinstance(actual, str):
            actual = actual.decode('UTF-8')

        # lists get recursed into
        if isinstance(actual, list):
            # recurse into lists
            return [self.interpolate(v, **scopevars) for v in actual]

        # dicts also get recursed into
        elif isinstance(actual, dict):
            # recurse into dicts
            return dict([(k, self.interpolate(v, **scopevars))
                         for k, v in actual.items()])

        # strings (as returned from to_value) get interpolated
        elif isinstance(actual, basestring):
            # do the interpolation
            return actual.format(**self.prepare_output_values(scopevars))

        # everything else passes through
        else:
            return actual
Exemplo n.º 7
0
    def execute_loop(self, environment, scope=None):
        if scope is None:
            scope = environment.scope

        i = 0

        if self.iterable:
            loop = self.iterable

            if isinstance(loop.iterator, variables.Variable):
                iter_value = to_value(loop.iterator, scope)
            else:
                _, iter_value = environment.execute(loop.iterator, scope=scope)

            try:
                if isinstance(iter_value, dict):
                    iter_value = iter_value.items()

                if not iter_value:
                    return

                for item in iter(iter_value):
                    if len(loop.variables) > 1 and isinstance(item, tuple):
                        # unpack iter items into the variables we were given
                        for var_i, var in enumerate(
                                loop.variables[0:len(item)]):
                            if not var.skip:
                                if var_i < len(item):
                                    scope.set(var.as_key(scope),
                                              item[var_i],
                                              force=True)

                        # null out any remaining variables
                        if len(loop.variables) > len(item):
                            for var in loop.variables[len(item):]:
                                scope.set(var.as_key(scope), None, force=True)

                    else:
                        scope.set(loop.variables[0].as_key(scope),
                                  item,
                                  force=True)

                    scope.set('index', i, force=True)

                    for result in self.iterate_blocks(i, environment, scope):
                        yield result

                    i += 1

            except TypeError:
                raise TypeError("Cannot loop on result of {}".format(
                    loop.iterator))

        elif self.bounded:
            loop = self.bounded
            environment.execute(loop.initial, scope=scope)

            while loop.termination.evaluate(environment, scope=scope):
                scope.set('index', i, force=True)

                for result in self.iterate_blocks(i, environment, scope):
                    yield result

                environment.execute(loop.next, scope=scope)
                i += 1

        elif self.truthy:
            loop = self.truthy

            while loop.termination.evaluate(environment, scope=scope):
                scope.set('index', i, force=True)

                for result in self.iterate_blocks(i, environment, scope):
                    yield result

                i += 1

        elif self.fixedlen:
            loop = self.fixedlen
            count = int(to_value(loop.count, scope))

            for _ in range(count):
                scope.set('index', i, force=True)

                for result in self.iterate_blocks(i, environment, scope):
                    yield result

                i += 1

        else:
            while True:
                scope.set('index', i, force=True)

                for result in self.iterate_blocks(i, environment, scope):
                    yield result

                i += 1
Exemplo n.º 8
0
def evaluate_block(scriptmgr, block, scope, scriptpath=None):
    environment = scriptmgr.environment
    # line, column = scriptmgr.get_item_position(block)
    # print('{} = line {}, column: {}'.format(block.__class__, line, column))

    # Assignment
    # ---------------------------------------------------------------------------------------------
    if isinstance(block, parser.variables.Assignment):
        block.assign(environment, scope)

    # Directives
    # ---------------------------------------------------------------------------------------------
    elif isinstance(block, parser.lang.Directive):
        if block.is_unset:
            for var in block.variables:
                scope.unset(var.as_key(scope))
        elif block.is_include:
            if scriptpath is None:
                raise parser.exceptions.ScriptError('Cannot include; no scriptpath set')

            fileset = environment.interpolate(block.fileglob)

            if not fileset.startswith('/'):
                fileset = os.path.join(scriptpath, fileset)

            # expand the globs, becomes a list here
            fileset = glob.glob(fileset)

            for include in fileset:
                if include.endswith('.fs'):
                    logging.debug('Including script {}'.format(include))

                    with open(include, 'r+b') as subscript:
                        execute_script(
                            environment.browser,
                            subscript.read(),
                            environment.scope,
                            environment,
                            scriptpath=os.path.dirname(include)
                        )

    # Expressions
    # ---------------------------------------------------------------------------------------------
    elif isinstance(block, parser.lang.Expression):
        result, put_result_in = block.process(environment, scope)

        if put_result_in:
            scope.set(put_result_in.as_key(scope), result)

    # Commands
    # ---------------------------------------------------------------------------------------------
    elif isinstance(block, parser.commands.CommandSequence):
        # for each command in the pipeline...
        for command in block.commands:
            key, value = environment.execute(command, scope)

            if not isinstance(value, IgnoreResults):
                value = parser.to_value(value, scope)

                if key is not None:
                    scope.set(key, value)

            # perform delay if we have one
            if environment.has_execution_option('demo.post_command_delay'):
                delay = environment.get_execution_option('demo.post_command_delay')
                time.sleep(delay / 1e3)

    # If / Else If / Else
    # ---------------------------------------------------------------------------------------------
    elif isinstance(block, parser.conditions.IfElseBlock):
        subscope = Scope(parent=scope)

        for subblock in block.get_blocks(environment, scope=subscope):
            evaluate_block(scriptmgr, subblock, subscope)

    # Loops
    # ---------------------------------------------------------------------------------------------
    elif isinstance(block, parser.loops.LoopBlock):
        loopscope = Scope(parent=scope)

        for i, _, subblock, scope in block.execute_loop(environment, scope=loopscope):
            try:
                evaluate_block(scriptmgr, subblock, scope=scope)

            except parser.loops.FlowControlMultiLevel as e:
                if e.levels > 1:
                    e.levels -= 1
                    raise
                elif isinstance(e, parser.loops.FlowControlBreak):
                    break
                elif isinstance(e, parser.loops.FlowControlContinue):
                    continue

    # Flow Control
    # ---------------------------------------------------------------------------------------------
    elif isinstance(block, parser.loops.FlowControlWord):
        if block.is_break:
            raise parser.loops.FlowControlBreak('break', levels=block.levels)

        elif block.is_continue:
            raise parser.loops.FlowControlContinue('continue', levels=block.levels)

        else:
            raise parser.exceptions.ScriptError('Unrecognized statement')
Exemplo n.º 9
0
    def resolve(self, scope):
        if self.variable:
            return self.variable.resolve(scope)

        return to_value(self.value, scope)