Esempio n. 1
0
    def testTokens(self):
        print(Id.Op_Newline)
        print(ast.token(Id.Op_Newline, '\n'))

        print(IdName(Id.Op_Newline))

        print(Kind.Eof)
        print(Kind.Left)
        print('--')
        for name in dir(Kind):
            if name[0].isupper():
                print(name, getattr(Kind, name))

        # Make sure we're not exporting too much
        print(dir(id_kind))

        # 206 out of 256 tokens now
        print(len(id_kind._ID_NAMES))

        t = ast.token(Id.Arith_Plus, '+')
        self.assertEqual(Kind.Arith, LookupKind(t.id))
        t = ast.token(Id.Arith_CaretEqual, '^=')
        self.assertEqual(Kind.Arith, LookupKind(t.id))
        t = ast.token(Id.Arith_RBrace, '}')
        self.assertEqual(Kind.Arith, LookupKind(t.id))

        t = ast.token(Id.BoolBinary_DEqual, '==')
        self.assertEqual(Kind.BoolBinary, LookupKind(t.id))
Esempio n. 2
0
  def _Read(self, lex_mode):
    if self.line_lexer.AtEnd():
      line_id, line = self.line_reader.GetLine()

      if line is None:  # no more lines
        t = ast.token(Id.Eof_Real, '', -1)
        # No line number.  I guess we are showing the last line of the file.
        # TODO: Could keep track of previous position for this case?
        return t

      self.line_lexer.Reset(line, line_id)

    t = self.line_lexer.Read(lex_mode)

    # e.g. translate ) or ` into EOF
    if self.translation_stack:
      old_id, new_id = self.translation_stack[-1]  # top
      if t.id == old_id:
        new_s = IdName(new_id)
        #print('==> TRANSLATING %s ==> %s' % (t, new_s))
        self.translation_stack.pop()
        #print(self.translation_stack)
        t.id = new_id

    return t
Esempio n. 3
0
File: tdop.py Progetto: silky/oil
    def Eat(self, token_type):
        """ Eat()? """
        if not self.AtToken(token_type):
            t = IdName(token_type)
            raise TdopParseError('TDOP expected %s, got %s' %
                                 (t, self.cur_word))

        self.Next()
Esempio n. 4
0
  def PushHint(self, old_id, new_id):
    """
    Use cases:
    Id.Op_RParen -> Id.Right_Subshell -- disambiguate
    Id.Op_RParen -> Id.Eof_RParen

    Problems for $() nesting.

    - posix:
      - case foo) and case (foo)
      - func() {}
      - subshell ( )
    - bash extensions:
      - precedence in [[,   e.g.  [[ (1 == 2) && (2 == 3) ]]
      - arrays: a=(1 2 3), a+=(4 5)
    """
    old_s = IdName(old_id)
    new_s = IdName(new_id)
    #print('* Lexer.PushHint %s => %s' % (old_s, new_s))
    self.translation_stack.append((old_id, new_id))
Esempio n. 5
0
File: tdop.py Progetto: silky/oil
def LeftAssign(p, w, left, rbp):
    """ Normal binary operator like 1+2 or 2*3, etc. """
    # x += 1, or a[i] += 1

    if not IsLValue(left):
        raise TdopParseError("Can't assign to %r (%s)" %
                             (left, IdName(left.id)))

    # HACK: NullConstant makes this of type RightVar?  Change that to something
    # generic?
    if left.tag == arith_expr_e.RightVar:
        lhs = ast.LeftVar(left.name)
    elif left.tag == arith_expr_e.ArithBinary:
        assert left.op_id == Id.Arith_LBracket
        # change a[i] to LeftIndex(a, i)
        lhs = ast.LeftIndex(left.left, left.right)
    else:
        raise AssertionError

    return ast.ArithAssign(word.ArithId(w), lhs, p.ParseUntil(rbp))
Esempio n. 6
0
    def Eval(self, node):
        #print('!!', node.tag)

        if node.tag == bool_expr_e.WordTest:
            s = self._EvalCompoundWord(node.w)
            return bool(s)

        if node.tag == bool_expr_e.LogicalNot:
            b = self.Eval(node.child)
            return not b

        if node.tag == bool_expr_e.LogicalAnd:
            # Short-circuit evaluation
            if self.Eval(node.left):
                return self.Eval(node.right)
            else:
                return False

        if node.tag == bool_expr_e.LogicalOr:
            if self.Eval(node.left):
                return True
            else:
                return self.Eval(node.right)

        if node.tag == bool_expr_e.BoolUnary:
            op_id = node.op_id
            s = self._EvalCompoundWord(node.child)

            # Now dispatch on arg type
            arg_type = BOOL_OPS[op_id]
            if arg_type == OperandType.Path:
                try:
                    mode = os.stat(s).st_mode
                except OSError as e:  # Python 3: FileNotFoundError
                    # TODO: Signal extra debug information?
                    #self._AddErrorContext("Error from stat(%r): %s" % (s, e))
                    return False

                if op_id == Id.BoolUnary_f:
                    return stat.S_ISREG(mode)

            if arg_type == OperandType.Str:
                if op_id == Id.BoolUnary_z:
                    return not bool(s)
                if op_id == Id.BoolUnary_n:
                    return bool(s)

                raise NotImplementedError(op_id)

            raise NotImplementedError(arg_type)

        #if node.id == Id.Node_BinaryExpr:
        if node.tag == bool_expr_e.BoolBinary:
            op_id = node.op_id

            s1 = self._EvalCompoundWord(node.left)
            # Whehter to glob escape
            do_fnmatch = op_id in (Id.BoolBinary_Equal, Id.BoolBinary_DEqual,
                                   Id.BoolBinary_NEqual)
            s2 = self._EvalCompoundWord(node.right, do_fnmatch=do_fnmatch)

            # Now dispatch on arg type
            arg_type = BOOL_OPS[op_id]

            if arg_type == OperandType.Path:
                st1 = os.stat(s1)
                st2 = os.stat(s2)

                if op_id == Id.BoolBinary_nt:
                    return True  # TODO: test newer than (mtime)

            if arg_type == OperandType.Int:
                # NOTE: We assume they are constants like [[ 3 -eq 3 ]].
                # Bash also allows [[ 1+2 -eq 3 ]].
                i1 = self._StringToIntegerOrError(s1)
                i2 = self._StringToIntegerOrError(s2)

                if op_id == Id.BoolBinary_eq:
                    return i1 == i2
                if op_id == Id.BoolBinary_ne:
                    return i1 != i2

                raise NotImplementedError(op_id)

            if arg_type == OperandType.Str:
                # TODO:
                # - Compare arrays.  (Although bash coerces them to string first)

                if op_id in (Id.BoolBinary_Equal, Id.BoolBinary_DEqual):
                    #log('Comparing %s and %s', s2, s1)
                    return libc.fnmatch(s2, s1)

                if op_id == Id.BoolBinary_NEqual:
                    return not libc.fnmatch(s2, s1)

                if op_id == Id.BoolBinary_EqualTilde:
                    # NOTE: regex matching can't fail if compilation succeeds.
                    match = libc.regex_match(s2, s1)
                    # TODO: BASH_REMATCH or REGEX_MATCH
                    if match == 1:
                        self._SetRegexMatches('TODO')
                        is_match = True
                    elif match == 0:
                        is_match = False
                    elif match == -1:
                        raise AssertionError(
                            "Invalid regex %r: should have been caught at compile time"
                            % s2)
                    else:
                        raise AssertionError

                    return is_match

                if op_id == Id.Redir_Less:  # pun
                    return s1 < s2

                if op_id == Id.Redir_Great:  # pun
                    return s1 > s2

                raise NotImplementedError(op_id)

        # We could have govered all node IDs
        raise AssertionError(IdName(node.id))
Esempio n. 7
0
    def _Eval(self, node):
        #print('!!', node.tag)

        if node.tag == bool_expr_e.WordTest:
            s = self._EvalCompoundWord(node.w)
            return bool(s)

        if node.tag == bool_expr_e.LogicalNot:
            b = self._Eval(node.child)
            return not b

        if node.tag == bool_expr_e.LogicalAnd:
            # Short-circuit evaluation
            if self._Eval(node.left):
                return self._Eval(node.right)
            else:
                return False

        if node.tag == bool_expr_e.LogicalOr:
            if self._Eval(node.left):
                return True
            else:
                return self._Eval(node.right)

        if node.tag == bool_expr_e.BoolUnary:
            op_id = node.op_id
            s = self._EvalCompoundWord(node.child)

            # Now dispatch on arg type
            arg_type = BOOL_OPS[op_id]
            if arg_type == OperandType.Path:
                try:
                    mode = os.stat(s).st_mode
                except FileNotFoundError as e:
                    # TODO: Signal extra debug information?
                    #self._AddErrorContext("Error from stat(%r): %s" % (s, e))
                    return False

                if op_id == Id.BoolUnary_f:
                    return stat.S_ISREG(mode)

            if arg_type == OperandType.Str:
                if op_id == Id.BoolUnary_z:
                    return not bool(s)
                if op_id == Id.BoolUnary_n:
                    return bool(s)

                raise NotImplementedError(op_id)

            raise NotImplementedError(arg_type)

        #if node.id == Id.Node_BinaryExpr:
        if node.tag == bool_expr_e.BoolBinary:
            op_id = node.op_id

            s1 = self._EvalCompoundWord(node.left)
            # Whehter to glob escape
            do_glob = op_id in (Id.BoolBinary_Equal, Id.BoolBinary_DEqual,
                                Id.BoolBinary_NEqual)
            s2 = self._EvalCompoundWord(node.right, do_glob=do_glob)

            # Now dispatch on arg type
            arg_type = BOOL_OPS[op_id]

            if arg_type == OperandType.Path:
                st1 = os.stat(s1)
                st2 = os.stat(s2)

                if op_id == Id.BoolBinary_nt:
                    return True  # TODO: test newer than (mtime)

            if arg_type == OperandType.Int:
                try:
                    i1 = int(s1)
                    i2 = int(s2)
                except ValueError as e:
                    # NOTE: Bash turns these into zero, but we won't by default.  Could
                    # provide a compat option.
                    # Also I think this should turn into exit code 3:
                    # - 0 true / 1 false / 3 runtime error
                    # - 2 is for PARSE error.
                    raise ExprEvalError("Invalid integer: %s" % e)

                if op_id == Id.BoolBinary_eq:
                    return i1 == i2
                if op_id == Id.BoolBinary_ne:
                    return i1 != i2

                raise NotImplementedError(op_id)

            if arg_type == OperandType.Str:
                # TODO:
                # - Compare arrays.  (Although bash coerces them to string first)

                if op_id in (Id.BoolBinary_Equal, Id.BoolBinary_DEqual):
                    #return True, _ValuesAreEqual(val1, val2)
                    return libc.fnmatch(s2, s1)

                if op_id == Id.BoolBinary_NEqual:
                    #return True, not _ValuesAreEqual(val1, val2)
                    return not libc.fnmatch(s2, s1)

                if op_id == Id.BoolBinary_EqualTilde:
                    # NOTE: regex matching can't fail if compilation succeeds.
                    match = libc.regex_match(s2, s1)
                    # TODO: BASH_REMATCH or REGEX_MATCH
                    if match == 1:
                        self._SetRegexMatches('TODO')
                        is_match = True
                    elif match == 0:
                        is_match = False
                    elif match == -1:
                        raise AssertionError(
                            "Invalid regex %r: should have been caught at compile time"
                            % s2)
                    else:
                        raise AssertionError

                    return is_match

                if op_id == Id.Redir_Less:  # pun
                    return s1 < s2

                if op_id == Id.Redir_Great:  # pun
                    return s1 > s2

                raise NotImplementedError(op_id)

        # We could have govered all node IDs
        raise AssertionError(IdName(node.id))