Beispiel #1
0
def InitEvaluator():
    mem = cmd_exec.Mem('', [])

    val1 = Value.FromString('xxx')
    val2 = Value.FromString('yyy')
    pairs = [(ast.LeftVar('x'), val1), (ast.LeftVar('y'), val2)]
    mem.SetLocal(pairs, 0)

    exec_opts = cmd_exec.ExecOpts()
    # Don't need side effects for most things
    return word_eval.CompletionEvaluator(mem, exec_opts)
Beispiel #2
0
def InitEvaluator():
    mem = cmd_exec.Mem('', [])

    val1 = runtime.Str('xxx')
    val2 = runtime.Str('yyy')
    pairs = [(ast.LeftVar('x'), val1), (ast.LeftVar('y'), val2)]
    mem.SetLocals(pairs)

    exec_opts = cmd_exec.ExecOpts()
    # Don't need side effects for most things
    return word_eval.CompletionWordEvaluator(mem, exec_opts)
Beispiel #3
0
    def testShellFuncExecution(self):
        ex = cmd_exec_test.InitExecutor()
        func_node = ast.FuncDef()

        c1 = ast.CompoundWord()
        t1 = ast.token(Id.Lit_Chars, 'f1')
        c1.parts.append(ast.LiteralPart(t1))

        c2 = ast.CompoundWord()
        t2 = ast.token(Id.Lit_Chars, 'f2')
        c2.parts.append(ast.LiteralPart(t2))

        a = ast.ArrayLiteralPart()
        a.words = [c1, c2]
        w = ast.CompoundWord()
        w.parts.append(a)

        # Set global COMPREPLY=(f1 f2)
        pairs = [ast.assign_pair(ast.LeftVar('COMPREPLY'), w)]
        body_node = ast.Assignment(Id.Assign_None, pairs)

        func_node.body = body_node

        a = completion.ShellFuncAction(ex, func_node)
        matches = (list(a.Matches([], 0, 'f')))
        self.assertEqual(['f1 ', 'f2 '], matches)
Beispiel #4
0
    def Matches(self, words, index, prefix):
        # TODO:
        # - Set COMP_CWORD etc. in ex.mem -- in the global namespace I guess
        # - Then parse the reply here

        # This is like a stack code:
        # for word in words:
        #   self.ex.PushString(word)
        # self.ex.PushString('COMP_WORDS')
        # self.ex.MakeArray()

        # self.ex.PushString(str(index))
        # self.ex.PushString('COMP_CWORD')

        # TODO: Get the name instead!
        # self.ex.PushString(self.func_name)
        # self.ex.Call()  # call wit no arguments

        # self.ex.PushString('COMP_REPLY')

        # How does this one work?
        # reply = []
        # self.ex.GetArray(reply)

        self.ex.mem.SetGlobalArray(ast.LeftVar('COMP_WORDS'), words)
        self.ex.mem.SetGlobalString(ast.LeftVar('COMP_CWORD'), str(index))

        self.ex.RunFunc(self.func, [])  # call with no arguments

        # Should be COMP_REPLY to follow naming convention!  Lame.
        defined, val = self.ex.mem.GetGlobal('COMPREPLY')
        if not defined:
            print('COMP_REPLY not defined', file=sys.stderr)
            return

        is_array, reply = val.AsArray()
        if not is_array:
            print('ERROR: COMP_REPLY should be an array, got %s',
                  file=sys.stderr)
            return

        print('REPLY', reply)
        #reply = ['g1', 'g2', 'h1', 'i1']
        for name in sorted(reply):
            if name.startswith(prefix):
                yield name + ' '  # full word
Beispiel #5
0
  def SetLocal(self, name, val):
    """Set a single local.

    Used for:
    1) for loop iteration variables
    2) temporary environments like FOO=bar BAR=$FOO cmd, 
    3) read builtin
    """
    pairs = [(ast.LeftVar(name), val)]
    self.SetLocals(pairs)
Beispiel #6
0
 def _Read(self, argv):
     names = argv[1:]
     line = sys.stdin.readline()
     if not line:  # EOF
         return 1
     # TODO: split line and do that logic
     val = Value.FromString(line.strip())
     pairs = [(ast.LeftVar(names[0]), val)]
     self.mem.SetLocal(pairs, 0)  # read always uses local variables?
     return 0
Beispiel #7
0
Datei: tdop.py Projekt: 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))
Beispiel #8
0
  def _MakeAssignment(self, assign_kw, suffix_words):
    bindings = []
    for i, w in enumerate(suffix_words):
      if i == 0:
        continue  # skip over local, export, etc.

      left_spid = word.LeftMostSpanForWord(w)

      kv = word.LooksLikeAssignment(w)
      if kv:
        k, v = kv
        t = word.TildeDetect(v)
        if t:
          # t is an unevaluated word with TildeSubPart
          pair = (k, t, left_spid)
        else:
          pair = (k, v, left_spid)  # v is unevaluated word
      else:
        # In aboriginal in variables/sources: export_if_blank does export "$1".
        # We should allow that.
        ok, value, quoted = word.StaticEval(w)
        if not ok or quoted:
          self.AddErrorContext(
              'Variable names must be constant strings, got %s', w, word=w)
          return None
        pair = (value, None, left_spid)  # No value is equivalent to ''
      bindings.append(pair)

    pairs = []
    for lhs, rhs, spid in bindings:
      p = ast.assign_pair(ast.LeftVar(lhs), rhs)
      p.spids.append(spid)
      pairs.append(p)

    node = ast.Assignment(assign_kw, pairs)

    return node
Beispiel #9
0
 def SetGlobalString(self, name, s):
   """Helper for completion, $PWD, etc."""
   assert isinstance(s, str)
   val = runtime.Str(s)
   pairs = [(ast.LeftVar(name), val)]
   self.SetGlobals(pairs)
Beispiel #10
0
 def SetGlobalArray(self, name, a):
   """Helper for completion."""
   assert isinstance(a, list)
   val = runtime.StrArray(a)
   pairs = [(ast.LeftVar(name), val)]
   self.SetGlobals(pairs)
Beispiel #11
0
  def ParseSimpleCommand(self):
    """
    Fixed transcription of the POSIX grammar (TODO: port to grammar/Shell.g)

    io_file        : '<'       filename
                   | LESSAND   filename
                     ...

    io_here        : DLESS     here_end
                   | DLESSDASH here_end

    redirect       : IO_NUMBER (io_redirect | io_here)

    prefix_part    : ASSIGNMENT_WORD | redirect
    cmd_part       : WORD | redirect

    assign_kw      : Declare | Export | Local | Readonly

    # Without any words it is parsed as a command, not an assigment
    assign_listing : assign_kw

    # Now we have something to do (might be changing assignment flags too)
    # NOTE: any prefixes should be a warning, but they are allowed in shell.
    assignment     : prefix_part* assign_kw (WORD | ASSIGNMENT_WORD)+

    # an external command, a function call, or a builtin -- a "word_command"
    word_command   : prefix_part* cmd_part+

    simple_command : assign_listing
                   | assignment
                   | proc_command

    Simple imperative algorithm:

    1) Read a list of words and redirects.  Append them to separate lists.
    2) Look for the first non-assignment word.  If it's declare, etc., then
    keep parsing words AND assign words.  Otherwise, just parse words.
    3) If there are no non-assignment words, then it's a global assignment.

    { redirects, global assignments } OR
    { redirects, prefix_bindings, words } OR
    { redirects, ERROR_prefix_bindings, keyword, assignments, words }

    THEN CHECK that prefix bindings don't have any array literal parts!
    global assignment and keyword assignments can have the of course.
    well actually EXPORT shouldn't have them either -- WARNING

    3 cases we want to warn: prefix_bindings for assignment, and array literal
    in prefix bindings, or export

    A command can be an assignment word, word, or redirect on its own.

        ls
        >out.txt

        >out.txt FOO=bar   # this touches the file, and hten

    Or any sequence:
        ls foo bar
        <in.txt ls foo bar >out.txt
        <in.txt ls >out.txt foo bar

    Or add one or more environment bindings:
        VAR=val env
        >out.txt VAR=val env

    here_end vs filename is a matter of whether we test that it's quoted.  e.g.
    <<EOF vs <<'EOF'.
    """
    result = self._ScanSimpleCommand()
    if not result: return None
    redirects, words = result

    if not words:  # e.g.  >out.txt  # redirect without words
      node = ast.SimpleCommand()
      node.redirects = redirects
      return node

    prefix_bindings, suffix_words = self._SplitSimpleCommandPrefix(words)

    if not suffix_words:  # ONE=1 TWO=2  (with no other words)
      # TODO: Have a strict mode to prevent this?
      if redirects:  # >out.txt g=foo
        print('WARNING: Got redirects in assignment: %s', redirects)

      pairs = []
      for lhs, rhs, spid in prefix_bindings:
        p = ast.assign_pair(ast.LeftVar(lhs), rhs)
        p.spids.append(spid)
        pairs.append(p)

      node = ast.Assignment(Id.Assign_None, pairs)
      left_spid = word.LeftMostSpanForWord(words[0])
      node.spids.append(left_spid)  # no keyword spid to skip past
      return node

    assign_kw, keyword_spid = word.AssignmentBuiltinId(suffix_words[0])

    if assign_kw == Id.Undefined_Tok:
      node = self._MakeSimpleCommand(prefix_bindings, suffix_words, redirects)
      return node

    if redirects:
      # TODO: Make it a warning, or do it in the second stage?
      print(
          'WARNING: Got redirects in assignment: %s' % redirects, file=sys.stderr)

    if prefix_bindings:  # FOO=bar local spam=eggs not allowed
      # Use the location of the first value.  TODO: Use the whole word before
      # splitting.
      _, v0, _ = prefix_bindings[0]
      self.AddErrorContext(
          'Invalid prefix bindings in assignment: %s', prefix_bindings,
          word=v0)
      return None

    node = self._MakeAssignment(assign_kw, suffix_words)
    if not node: return None
    node.spids.append(keyword_spid)
    return node
Beispiel #12
0
 def SetLocal(self, name, val):
   """Set a single local.""" 
   pairs = [(ast.LeftVar(name), val)]
   self.SetLocals(pairs)