def ParseOil(spec, arg_r): # type: (arg_def._OilFlags, Reader) -> Tuple[_Attributes, int] out = _Attributes(spec.defaults) while not arg_r.AtEnd(): arg = arg_r.Peek() if arg == '--': out.saw_double_dash = True arg_r.Next() break if arg == '-': # a valid argument break # TODO: Use FLAG_RE above if arg.startswith('-'): m = libc.regex_match(_FLAG_ERE, arg) if m is None: e_usage('Invalid flag syntax: %r' % arg) _, flag, val = m # group 0 is ignored; the whole match # TODO: we don't need arity 1 or 0? Booleans are like --verbose=1, # --verbose (equivalent to turning it on) or --verbose=0. name = flag.replace('-', '_') if name in spec.arity1: # e.g. read -t1.0 action = spec.arity1[name] if val.startswith('='): suffix = val[1:] # could be empty, but remove = if any else: suffix = None action.OnMatch(None, suffix, arg_r, out) else: e_usage('Unrecognized flag %r' % arg) arg_r.Next() # next arg else: # a regular arg break return out, arg_r.i
def testRegexParse(self): self.assertEqual(True, libc.regex_parse(r'.*\.py')) # Syntax errors self.assertRaises(RuntimeError, libc.regex_parse, r'*') self.assertRaises(RuntimeError, libc.regex_parse, '\\') self.assertRaises(RuntimeError, libc.regex_parse, '{') cases = [ ('([a-z]+)([0-9]+)', 'foo123', ['foo123', 'foo', '123']), (r'.*\.py', 'foo.py', ['foo.py']), (r'.*\.py', 'abcd', None), # The match is unanchored (r'bc', 'abcd', ['bc']), # The match is unanchored (r'.c', 'abcd', ['bc']) ] for pat, s, expected in cases: #print('CASE %s' % pat) actual = libc.regex_match(pat, s) self.assertEqual(expected, actual)
def _EvalMatch(self, left, right, set_match_result): """ Args: set_match_result: Whether to assign """ # TODO: Rename EggEx? if isinstance(right, str): pass elif isinstance(right, objects.Regex): right = right.AsPosixEre() else: raise RuntimeError("RHS of ~ should be string or Regex (got %s)" % right.__class__.__name__) # TODO: We need an API that can populate _start() and _end() too matches = libc.regex_match(right, left) if matches: if set_match_result: self.mem.SetMatches(matches) return True else: if set_match_result: self.mem.ClearMatches() return False
def Eval(self, node): # type: (bool_expr_t) -> bool UP_node = node with tagswitch(node) as case: if case(bool_expr_e.WordTest): node = cast(bool_expr__WordTest, UP_node) s = self._EvalCompoundWord(node.w) return bool(s) elif case(bool_expr_e.LogicalNot): node = cast(bool_expr__LogicalNot, UP_node) b = self.Eval(node.child) return not b elif case(bool_expr_e.LogicalAnd): node = cast(bool_expr__LogicalAnd, UP_node) # Short-circuit evaluation if self.Eval(node.left): return self.Eval(node.right) else: return False elif case(bool_expr_e.LogicalOr): node = cast(bool_expr__LogicalOr, UP_node) if self.Eval(node.left): return True else: return self.Eval(node.right) elif case(bool_expr_e.Unary): node = cast(bool_expr__Unary, UP_node) op_id = node.op_id s = self._EvalCompoundWord(node.child) # Now dispatch on arg type arg_type = consts.BoolArgType( op_id) # could be static in the LST? if arg_type == bool_arg_type_e.Path: return bool_stat.DoUnaryOp(op_id, s) if arg_type == bool_arg_type_e.Str: if op_id == Id.BoolUnary_z: return not bool(s) if op_id == Id.BoolUnary_n: return bool(s) raise AssertionError(op_id) # should never happen if arg_type == bool_arg_type_e.Other: if op_id == Id.BoolUnary_t: try: fd = int(s) except ValueError: # TODO: Need location information of [ e_die('Invalid file descriptor %r', s, word=node.child) return bool_stat.isatty(fd, s, node.child) # See whether 'set -o' options have been set if op_id == Id.BoolUnary_o: index = match.MatchOption(s) if index == 0: return False else: return self.exec_opts.opt_array[index] e_die("%s isn't implemented", ui.PrettyId(op_id)) # implicit location raise AssertionError(arg_type) # should never happen elif case(bool_expr_e.Binary): node = cast(bool_expr__Binary, UP_node) op_id = node.op_id # Whether to glob escape with switch(op_id) as case2: if case2(Id.BoolBinary_GlobEqual, Id.BoolBinary_GlobDEqual, Id.BoolBinary_GlobNEqual): quote_kind = quote_e.FnMatch elif case2(Id.BoolBinary_EqualTilde): quote_kind = quote_e.ERE else: quote_kind = quote_e.Default s1 = self._EvalCompoundWord(node.left) s2 = self._EvalCompoundWord(node.right, quote_kind=quote_kind) # Now dispatch on arg type arg_type = consts.BoolArgType(op_id) if arg_type == bool_arg_type_e.Path: return bool_stat.DoBinaryOp(op_id, s1, s2) if arg_type == bool_arg_type_e.Int: # NOTE: We assume they are constants like [[ 3 -eq 3 ]]. # Bash also allows [[ 1+2 -eq 3 ]]. i1 = self._StringToIntegerOrError(s1, blame_word=node.left) i2 = self._StringToIntegerOrError(s2, blame_word=node.right) if op_id == Id.BoolBinary_eq: return i1 == i2 if op_id == Id.BoolBinary_ne: return i1 != i2 if op_id == Id.BoolBinary_gt: return i1 > i2 if op_id == Id.BoolBinary_ge: return i1 >= i2 if op_id == Id.BoolBinary_lt: return i1 < i2 if op_id == Id.BoolBinary_le: return i1 <= i2 raise AssertionError(op_id) # should never happen if arg_type == bool_arg_type_e.Str: if op_id in (Id.BoolBinary_GlobEqual, Id.BoolBinary_GlobDEqual): #log('Matching %s against pattern %s', s1, s2) return libc.fnmatch(s2, s1) if op_id == Id.BoolBinary_GlobNEqual: return not libc.fnmatch(s2, s1) if op_id in (Id.BoolBinary_Equal, Id.BoolBinary_DEqual): return s1 == s2 if op_id == Id.BoolBinary_NEqual: return s1 != s2 if op_id == Id.BoolBinary_EqualTilde: # TODO: This should go to --debug-file #log('Matching %r against regex %r', s1, s2) try: matches = libc.regex_match(s2, s1) except RuntimeError: # Status 2 indicates a regex parse error. This is fatal in OSH but # not in bash, which treats [[ like a command with an exit code. e_die("Invalid regex %r", s2, word=node.right, status=2) if matches is None: return False self._SetRegexMatches(matches) return True if op_id == Id.Op_Less: return s1 < s2 if op_id == Id.Op_Great: return s1 > s2 raise AssertionError(op_id) # should never happen raise AssertionError(node.tag_())
def testPatSubRegexesLibc(self): r = libc.regex_parse('^(.*)git.*(.*)') print(r) # It matches. But we need to get the positions out! print(libc.regex_match('^(.*)git.*(.*)', '~/git/oil'))
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))
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_ARG_TYPES[op_id] # could be static in the LST? if arg_type == bool_arg_type_e.Path: # Only use lstat if we're testing for a symlink. if op_id in (Id.BoolUnary_h, Id.BoolUnary_L): try: mode = posix.lstat(s).st_mode except OSError: return False return stat.S_ISLNK(mode) try: mode = posix.stat(s).st_mode except OSError: # TODO: Signal extra debug information? #log("Error from stat(%r): %s" % (s, e)) return False if op_id in (Id.BoolUnary_e, Id.BoolUnary_a): # -a is alias for -e return True if op_id == Id.BoolUnary_f: return stat.S_ISREG(mode) if op_id == Id.BoolUnary_d: return stat.S_ISDIR(mode) if op_id == Id.BoolUnary_x: return posix.access(s, posix.X_OK) if op_id == Id.BoolUnary_r: return posix.access(s, posix.R_OK) if op_id == Id.BoolUnary_w: return posix.access(s, posix.W_OK) raise NotImplementedError(op_id) if arg_type == bool_arg_type_e.Str: if op_id == Id.BoolUnary_z: return not bool(s) if op_id == Id.BoolUnary_n: return bool(s) raise NotImplementedError(op_id) if arg_type == bool_arg_type_e.Other: if op_id == Id.BoolUnary_t: try: fd = int(s) except ValueError: # TODO: Need location information of [ e_die('Invalid file descriptor %r', s) return posix.isatty(fd) raise NotImplementedError(op_id) raise NotImplementedError(arg_type) if node.tag == bool_expr_e.BoolBinary: op_id = node.op_id s1 = self._EvalCompoundWord(node.left) # Whether to glob escape do_fnmatch = op_id in (Id.BoolBinary_GlobEqual, Id.BoolBinary_GlobDEqual, Id.BoolBinary_GlobNEqual) do_ere = (op_id == Id.BoolBinary_EqualTilde) s2 = self._EvalCompoundWord(node.right, do_fnmatch=do_fnmatch, do_ere=do_ere) # Now dispatch on arg type arg_type = BOOL_ARG_TYPES[op_id] if arg_type == bool_arg_type_e.Path: st1 = posix.stat(s1) st2 = posix.stat(s2) # TODO: test newer than (mtime) if op_id == Id.BoolBinary_nt: return st1[stat.ST_MTIME] > st2[stat.ST_MTIME] if op_id == Id.BoolBinary_ot: return st1[stat.ST_MTIME] < st2[stat.ST_MTIME] raise NotImplementedError(op_id) if arg_type == bool_arg_type_e.Int: # NOTE: We assume they are constants like [[ 3 -eq 3 ]]. # Bash also allows [[ 1+2 -eq 3 ]]. i1 = self._StringToIntegerOrError(s1, blame_word=node.left) i2 = self._StringToIntegerOrError(s2, blame_word=node.right) if op_id == Id.BoolBinary_eq: return i1 == i2 if op_id == Id.BoolBinary_ne: return i1 != i2 if op_id == Id.BoolBinary_gt: return i1 > i2 if op_id == Id.BoolBinary_ge: return i1 >= i2 if op_id == Id.BoolBinary_lt: return i1 < i2 if op_id == Id.BoolBinary_le: return i1 <= i2 raise NotImplementedError(op_id) if arg_type == bool_arg_type_e.Str: if op_id in (Id.BoolBinary_GlobEqual, Id.BoolBinary_GlobDEqual): #log('Matching %s against pattern %s', s1, s2) # TODO: Respect extended glob? * and ! and ? are quoted improperly. # But @ and + are OK. return libc.fnmatch(s2, s1) if op_id == Id.BoolBinary_GlobNEqual: return not libc.fnmatch(s2, s1) if op_id in (Id.BoolBinary_Equal, Id.BoolBinary_DEqual): return s1 == s2 if op_id == Id.BoolBinary_NEqual: return s1 != s2 if op_id == Id.BoolBinary_EqualTilde: #log('Matching %r against regex %r', s1, s2) try: matches = libc.regex_match(s2, s1) except RuntimeError: # 2 means a parse error. Note this is a fatal error in OSH but not # in bash. e_die("Invalid regex %r", s2, word=node.right, status=2) if matches is None: return False self._SetRegexMatches(matches) return True if op_id == Id.Redir_Less: # pun return s1 < s2 if op_id == Id.Redir_Great: # pun return s1 > s2 raise NotImplementedError(op_id) raise AssertionError(node.tag)
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.Unary: op_id = node.op_id s = self._EvalCompoundWord(node.child) # Now dispatch on arg type arg_type = BOOL_ARG_TYPES[op_id.enum_id] # could be static in the LST? if arg_type == bool_arg_type_e.Path: # Only use lstat if we're testing for a symlink. if op_id in (Id.BoolUnary_h, Id.BoolUnary_L): try: mode = posix.lstat(s).st_mode except OSError: # TODO: simple_test_builtin should this as status=2. #e_die("lstat() error: %s", e, word=node.child) return False return stat.S_ISLNK(mode) try: st = posix.stat(s) except OSError as e: # TODO: simple_test_builtin should this as status=2. # Problem: we really need errno, because test -f / is bad argument, # while test -f /nonexistent is a good argument but failed. Gah. # ENOENT vs. ENAMETOOLONG. #e_die("stat() error: %s", e, word=node.child) return False mode = st.st_mode if op_id in (Id.BoolUnary_e, Id.BoolUnary_a): # -a is alias for -e return True if op_id == Id.BoolUnary_f: return stat.S_ISREG(mode) if op_id == Id.BoolUnary_d: return stat.S_ISDIR(mode) if op_id == Id.BoolUnary_b: return stat.S_ISBLK(mode) if op_id == Id.BoolUnary_c: return stat.S_ISCHR(mode) if op_id == Id.BoolUnary_p: return stat.S_ISFIFO(mode) if op_id == Id.BoolUnary_S: return stat.S_ISSOCK(mode) if op_id == Id.BoolUnary_x: return posix.access(s, posix.X_OK) if op_id == Id.BoolUnary_r: return posix.access(s, posix.R_OK) if op_id == Id.BoolUnary_w: return posix.access(s, posix.W_OK) if op_id == Id.BoolUnary_s: return st.st_size != 0 if op_id == Id.BoolUnary_O: return st.st_uid == posix.geteuid() if op_id == Id.BoolUnary_G: return st.st_gid == posix.getegid() e_die("%s isn't implemented", op_id) # implicit location if arg_type == bool_arg_type_e.Str: if op_id == Id.BoolUnary_z: return not bool(s) if op_id == Id.BoolUnary_n: return bool(s) raise AssertionError(op_id) # should never happen if arg_type == bool_arg_type_e.Other: if op_id == Id.BoolUnary_t: try: fd = int(s) except ValueError: # TODO: Need location information of [ e_die('Invalid file descriptor %r', s, word=node.child) try: return posix.isatty(fd) # fd is user input, and causes this exception in the binding. except OverflowError: e_die('File descriptor %r is too big', s, word=node.child) # See whether 'set -o' options have been set if op_id == Id.BoolUnary_o: b = getattr(self.exec_opts, s, None) return False if b is None else b e_die("%s isn't implemented", op_id) # implicit location raise AssertionError(arg_type) # should never happen if node.tag == bool_expr_e.Binary: op_id = node.op_id s1 = self._EvalCompoundWord(node.left) # Whether to glob escape do_fnmatch = op_id in (Id.BoolBinary_GlobEqual, Id.BoolBinary_GlobDEqual, Id.BoolBinary_GlobNEqual) do_ere = (op_id == Id.BoolBinary_EqualTilde) s2 = self._EvalCompoundWord(node.right, do_fnmatch=do_fnmatch, do_ere=do_ere) # Now dispatch on arg type arg_type = BOOL_ARG_TYPES[op_id.enum_id] if arg_type == bool_arg_type_e.Path: try: st1 = posix.stat(s1) except OSError: st1 = None try: st2 = posix.stat(s2) except OSError: st2 = None if op_id in (Id.BoolBinary_nt, Id.BoolBinary_ot): # pretend it's a very old file m1 = 0 if st1 is None else st1.st_mtime m2 = 0 if st2 is None else st2.st_mtime if op_id == Id.BoolBinary_nt: return m1 > m2 else: return m1 < m2 if op_id == Id.BoolBinary_ef: if st1 is None: return False if st2 is None: return False return st1.st_dev == st2.st_dev and st1.st_ino == st2.st_ino raise AssertionError(op_id) if arg_type == bool_arg_type_e.Int: # NOTE: We assume they are constants like [[ 3 -eq 3 ]]. # Bash also allows [[ 1+2 -eq 3 ]]. i1 = self._StringToIntegerOrError(s1, blame_word=node.left) i2 = self._StringToIntegerOrError(s2, blame_word=node.right) if op_id == Id.BoolBinary_eq: return i1 == i2 if op_id == Id.BoolBinary_ne: return i1 != i2 if op_id == Id.BoolBinary_gt: return i1 > i2 if op_id == Id.BoolBinary_ge: return i1 >= i2 if op_id == Id.BoolBinary_lt: return i1 < i2 if op_id == Id.BoolBinary_le: return i1 <= i2 raise AssertionError(op_id) # should never happen if arg_type == bool_arg_type_e.Str: if op_id in (Id.BoolBinary_GlobEqual, Id.BoolBinary_GlobDEqual): #log('Matching %s against pattern %s', s1, s2) return libc.fnmatch(s2, s1) if op_id == Id.BoolBinary_GlobNEqual: return not libc.fnmatch(s2, s1) if op_id in (Id.BoolBinary_Equal, Id.BoolBinary_DEqual): return s1 == s2 if op_id == Id.BoolBinary_NEqual: return s1 != s2 if op_id == Id.BoolBinary_EqualTilde: # TODO: This should go to --debug-file #log('Matching %r against regex %r', s1, s2) try: matches = libc.regex_match(s2, s1) except RuntimeError: # Status 2 indicates a regex parse error. This is fatal in OSH but # not in bash, which treats [[ like a command with an exit code. e_die("Invalid regex %r", s2, word=node.right, status=2) if matches is None: return False self._SetRegexMatches(matches) return True if op_id == Id.Op_Less: return s1 < s2 if op_id == Id.Op_Great: return s1 > s2 raise AssertionError(op_id) # should never happen raise AssertionError(node.tag)
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_ARG_TYPES[op_id] # could be static in the LST? if arg_type == bool_arg_type_e.Path: # Only use lstat if we're testing for a symlink. if op_id in (Id.BoolUnary_h, Id.BoolUnary_L): try: mode = os.lstat(s).st_mode except OSError: return False return stat.S_ISLNK(mode) try: mode = os.stat(s).st_mode except OSError: # TODO: Signal extra debug information? #self._AddErrorContext("Error from stat(%r): %s" % (s, e)) return False if op_id in (Id.BoolUnary_e, Id.BoolUnary_a): # -a is alias for -e return True if op_id == Id.BoolUnary_f: return stat.S_ISREG(mode) if op_id == Id.BoolUnary_d: return stat.S_ISDIR(mode) if op_id == Id.BoolUnary_x: return os.access(s, os.X_OK) if op_id == Id.BoolUnary_r: return os.access(s, os.R_OK) if op_id == Id.BoolUnary_w: return os.access(s, os.W_OK) raise NotImplementedError(op_id) if arg_type == bool_arg_type_e.Str: if op_id == Id.BoolUnary_z: return not bool(s) if op_id == Id.BoolUnary_n: return bool(s) raise NotImplementedError(op_id) if arg_type == bool_arg_type_e.Other: if op_id == Id.BoolUnary_t: try: fd = int(s) except ValueError: # TODO: Need location information of [ e_die('Invalid file descriptor %r', s) return os.isatty(fd) raise NotImplementedError(op_id) raise NotImplementedError(arg_type) 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_GlobEqual, Id.BoolBinary_GlobDEqual, Id.BoolBinary_GlobNEqual) s2 = self._EvalCompoundWord(node.right, do_fnmatch=do_fnmatch) # Now dispatch on arg type arg_type = BOOL_ARG_TYPES[op_id] if arg_type == bool_arg_type_e.Path: st1 = os.stat(s1) st2 = os.stat(s2) # TODO: test newer than (mtime) if op_id == Id.BoolBinary_nt: return st1[stat.ST_MTIME] > st2[stat.ST_MTIME] if op_id == Id.BoolBinary_ot: return st1[stat.ST_MTIME] < st2[stat.ST_MTIME] raise NotImplementedError(op_id) if arg_type == bool_arg_type_e.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 if op_id == Id.BoolBinary_gt: return i1 > i2 if op_id == Id.BoolBinary_ge: return i1 >= i2 if op_id == Id.BoolBinary_lt: return i1 < i2 if op_id == Id.BoolBinary_le: return i1 <= i2 raise NotImplementedError(op_id) if arg_type == bool_arg_type_e.Str: # TODO: # - Compare arrays. (Although bash coerces them to string first) if op_id in (Id.BoolBinary_GlobEqual, Id.BoolBinary_GlobDEqual): #log('Comparing %s and %s', s2, s1) return libc.fnmatch(s2, s1) if op_id == Id.BoolBinary_GlobNEqual: return not libc.fnmatch(s2, s1) if op_id in (Id.BoolBinary_Equal, Id.BoolBinary_DEqual): return s1 == s2 if op_id == Id.BoolBinary_NEqual: return s1 != s2 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) raise AssertionError(node.tag)