nodes: 0, module; 1, function_definition; 2, function_name:application; 3, parameters; 4, block; 5, identifier:self; 6, identifier:func; 7, expression_statement; 8, expression_statement; 9, if_statement; 10, expression_statement; 11, while_statement; 12, expression_statement; 13, return_statement; 14, comment:"""Parse the function application subgrammar.
  
          Function application can, conceptually, be thought of as a mixfix
          operator, similar to the way array subscripting works. However, it is
          not clear at this point whether we want to allow it to work as such,
          because doing so would permit queries to, at runtime, select methods
          out of an arbitrary object and then call them.
  
          While there is a function whitelist and preventing this sort of thing
          in the syntax isn't a security feature, it still seems like the
          syntax should make it clear what the intended use of application is.
  
          If we later decide to extend DottySQL to allow function application
          over an arbitrary LHS expression then that syntax would be a strict
          superset of the current syntax and backwards compatible.
          """; 15, assignment; 16, call; 17, comment:# That was easy.; 18, block; 19, assignment; 20, call; 21, block; 22, call; 23, call; 24, identifier:start; 25, attribute; 26, attribute; 27, argument_list; 28, return_statement; 29, identifier:arguments; 30, list; 31, attribute; 32, argument_list; 33, expression_statement; 34, attribute; 35, argument_list; 36, attribute; 37, argument_list; 38, attribute; 39, identifier:start; 40, attribute; 41, identifier:accept; 42, attribute; 43, call; 44, call; 45, attribute; 46, identifier:accept; 47, attribute; 48, call; 49, attribute; 50, identifier:expect; 51, attribute; 52, identifier:ast; 53, identifier:Apply; 54, identifier:func; 55, list_splat; 56, keyword_argument; 57, keyword_argument; 58, keyword_argument; 59, attribute; 60, identifier:matched; 61, identifier:self; 62, identifier:tokens; 63, identifier:common_grammar; 64, identifier:rparen; 65, attribute; 66, argument_list; 67, attribute; 68, argument_list; 69, identifier:self; 70, identifier:tokens; 71, identifier:common_grammar; 72, identifier:comma; 73, attribute; 74, argument_list; 75, identifier:self; 76, identifier:tokens; 77, identifier:common_grammar; 78, identifier:rparen; 79, identifier:arguments; 80, identifier:start; 81, identifier:start; 82, identifier:end; 83, attribute; 84, identifier:source; 85, attribute; 86, identifier:self; 87, identifier:tokens; 88, identifier:ast; 89, identifier:Apply; 90, identifier:func; 91, keyword_argument; 92, keyword_argument; 93, keyword_argument; 94, identifier:self; 95, identifier:expression; 96, identifier:arguments; 97, identifier:append; 98, call; 99, attribute; 100, identifier:end; 101, identifier:self; 102, identifier:original; 103, identifier:start; 104, identifier:start; 105, identifier:end; 106, attribute; 107, identifier:source; 108, attribute; 109, attribute; 110, argument_list; 111, attribute; 112, identifier:matched; 113, attribute; 114, identifier:end; 115, identifier:self; 116, identifier:original; 117, identifier:self; 118, identifier:expression; 119, identifier:self; 120, identifier:tokens; 121, attribute; 122, identifier:matched; 123, identifier:self; 124, identifier:tokens
code: def application(self, func):
          """Parse the function application subgrammar.
  
          Function application can, conceptually, be thought of as a mixfix
          operator, similar to the way array subscripting works. However, it is
          not clear at this point whether we want to allow it to work as such,
          because doing so would permit queries to, at runtime, select methods
          out of an arbitrary object and then call them.
  
          While there is a function whitelist and preventing this sort of thing
          in the syntax isn't a security feature, it still seems like the
          syntax should make it clear what the intended use of application is.
  
          If we later decide to extend DottySQL to allow function application
          over an arbitrary LHS expression then that syntax would be a strict
          superset of the current syntax and backwards compatible.
          """
          start = self.tokens.matched.start
          if self.tokens.accept(common_grammar.rparen):
              # That was easy.
              return ast.Apply(func, start=start, end=self.tokens.matched.end,
                               source=self.original)
  
          arguments = [self.expression()]
          while self.tokens.accept(common_grammar.comma):
              arguments.append(self.expression())
  
          self.tokens.expect(common_grammar.rparen)
          return ast.Apply(func, *arguments, start=start,
                           end=self.tokens.matched.end, source=self.original)