docs: function scanTemplate() {
          var cooked = '', ch, start, rawOffset, terminated, head, tail, restore, unescaped;
  
          terminated = false;
          tail = false;
          start = index;
          head = (source[index] === '`');
          rawOffset = 2;
  
          ++index;
  
          while (index < length) {
              ch = source[index++];
              if (ch === '`') {
                  rawOffset = 1;
                  tail = true;
                  terminated = true;
                  break;
              } else if (ch === '$') {
                  if (source[index] === '{') {
                      state.curlyStack.push('${');
                      ++index;
                      terminated = true;
                      break;
                  }
                  cooked += ch;
              } else if (ch === '\\') {
                  ch = source[index++];
                  if (!isLineTerminator(ch.charCodeAt(0))) {
                      switch (ch) {
                      case 'n':
                          cooked += '\n';
                          break;
                      case 'r':
                          cooked += '\r';
                          break;
                      case 't':
                          cooked += '\t';
                          break;
                      case 'u':
                      case 'x':
                          if (source[index] === '{') {
                              ++index;
                              cooked += scanUnicodeCodePointEscape();
                          } else {
                              restore = index;
                              unescaped = scanHexEscape(ch);
                              if (unescaped) {
                                  cooked += unescaped;
                              } else {
                                  index = restore;
                                  cooked += ch;
                              }
                          }
                          break;
                      case 'b':
                          cooked += '\b';
                          break;
                      case 'f':
                          cooked += '\f';
                          break;
                      case 'v':
                          cooked += '\v';
                          break;
  
                      default:
                          if (ch === '0') {
                              if (isDecimalDigit(source.charCodeAt(index))) {
                                  // Illegal: \01 \02 and so on
                                  throwError(Messages.TemplateOctalLiteral);
                              }
                              cooked += '\0';
                          } else if (isOctalDigit(ch)) {
                              // Illegal: \1 \2
                              throwError(Messages.TemplateOctalLiteral);
                          } else {
                              cooked += ch;
                          }
                          break;
                      }
                  } else {
                      ++lineNumber;
                      if (ch === '\r' && source[index] === '\n') {
                          ++index;
                      }
                      lineStart = index;
                  }
              } else if (isLineTerminator(ch.charCodeAt(0))) {
                  ++lineNumber;
                  if (ch === '\r' && source[index] === '\n') {
                      ++index;
                  }
                  lineStart = index;
                  cooked += '\n';
              } else {
                  cooked += ch;
              }
          }
  
          if (!terminated) {
              throwUnexpectedToken();
          }
  
          if (!head) {
              state.curlyStack.pop();
          }
  
          return {
              type: Token.Template,
              value: {
                  cooked: cooked,
                  raw: source.slice(start + 1, index - rawOffset)
              },
              head: head,
              tail: tail,
              lineNumber: lineNumber,
              lineStart: lineStart,
              start: start,
              end: index
          };
      }