code: function parseElements(start, end, tokens) {
  	const length = end - start;
  	let error;
  
  	if (length === 0) {
  		return [];
  	} else {
  		for (
  			let elementEnd = start + 1;
  			elementEnd <= end;
  			elementEnd++
  		) {
  			const element = parseElement(start, elementEnd, tokens);
  
  			if (element instanceof ParseError) {
  				// Store the latest error in parsing an element. This will be the
  				// error with the largest possible match if all of the input tokens
  				// fail to match.
  				error = element;
  			} else {
  				const elements = parseElements(elementEnd, end, tokens);
  
  				if (!(elements instanceof ParseError)) {
  					// Combine the first element with the rest of the elements.
  					let elementsAll = [element];
  
  					for (let i = 0; i < elements.length; i++) {
  						elementsAll.push(elements[i]);
  					}
  
  					return elementsAll;
  				}
  			}
  		}
  
  		return new ParseError(
  			parseErrorMessage("Parser expected valid elements but encountered an error."),
  			start,
  			end,
  			error
  		);
  	}
  }
docs: Given a start index, end index, and a list of tokens, return a tree after
  matching against the following grammar:
  
  Elements -> Empty | Element Elements
  
  The parsing algorithm is explained in more detail in the `parse` function.
  
  @param {number} start
  @param {number} end
  @param {Object[]} tokens
  @returns {Object} Abstract syntax tree or ParseError