private ArgumentNode[] maybeEatModuleArgs() {
		List<ArgumentNode> args = null;
		if (tokens.peek(TokenKind.DOUBLE_MINUS) && tokens.isNextAdjacent()) {
			tokens.raiseException(tokens.peek().startpos, JobDSLMessage.EXPECTED_WHITESPACE_AFTER_NAME_BEFORE_ARGUMENT);
		}
		while (tokens.peek(TokenKind.DOUBLE_MINUS)) {
			Token dashDash = tokens.next(); // skip the '--'
			if (tokens.peek(TokenKind.IDENTIFIER) && !tokens.isNextAdjacent()) {
				tokens.raiseException(tokens.peek().startpos, JobDSLMessage.NO_WHITESPACE_BEFORE_ARG_NAME);
			}
			Token argName = tokens.next();
			if (!argName.isKind(TokenKind.IDENTIFIER)) {
				tokens.raiseException(argName.startpos, JobDSLMessage.NOT_EXPECTED_TOKEN,
						argName.data != null ? argName.data
								: new String(argName.getKind().tokenChars));
			}
			if (tokens.peek(TokenKind.EQUALS) && !tokens.isNextAdjacent()) {
				tokens.raiseException(tokens.peek().startpos, JobDSLMessage.NO_WHITESPACE_BEFORE_ARG_EQUALS);
			}
			tokens.eat(TokenKind.EQUALS);
			if (tokens.peek(TokenKind.IDENTIFIER) && !tokens.isNextAdjacent()) {
				tokens.raiseException(tokens.peek().startpos, JobDSLMessage.NO_WHITESPACE_BEFORE_ARG_VALUE);
			}
			// Process argument value:
			Token t = tokens.peek();
			String argValue = eatArgValue();
			tokens.checkpoint();
			if (args == null) {
				args = new ArrayList<ArgumentNode>();
			}
			args.add(new ArgumentNode(argName.data, argValue, dashDash.startpos, t.endpos));
		}
		return args == null ? null : args.toArray(new ArgumentNode[args.size()]);
	}
Parse a job flow definition into an abstract syntax tree (AST).

@param jobSpecification the textual job specification
@return the AST for the parsed job
@throws JobSpecificationException if any problems occur during parsing
spring-xd-dirt/src/main/java/org/springframework/xd/dirt/job/dsl/JobParser.java