docs: function(hljs) {
    var PERL_KEYWORDS = 'getpwent getservent quotemeta msgrcv scalar kill dbmclose undef lc ' +
      'ma syswrite tr send umask sysopen shmwrite vec qx utime local oct semctl localtime ' +
      'readpipe do return format read sprintf dbmopen pop getpgrp not getpwnam rewinddir qq' +
      'fileno qw endprotoent wait sethostent bless s|0 opendir continue each sleep endgrent ' +
      'shutdown dump chomp connect getsockname die socketpair close flock exists index shmget' +
      'sub for endpwent redo lstat msgctl setpgrp abs exit select print ref gethostbyaddr ' +
      'unshift fcntl syscall goto getnetbyaddr join gmtime symlink semget splice x|0 ' +
      'getpeername recv log setsockopt cos last reverse gethostbyname getgrnam study formline ' +
      'endhostent times chop length gethostent getnetent pack getprotoent getservbyname rand ' +
      'mkdir pos chmod y|0 substr endnetent printf next open msgsnd readdir use unlink ' +
      'getsockopt getpriority rindex wantarray hex system getservbyport endservent int chr ' +
      'untie rmdir prototype tell listen fork shmread ucfirst setprotoent else sysseek link ' +
      'getgrgid shmctl waitpid unpack getnetbyname reset chdir grep split require caller ' +
      'lcfirst until warn while values shift telldir getpwuid my getprotobynumber delete and ' +
      'sort uc defined srand accept package seekdir getprotobyname semop our rename seek if q|0 ' +
      'chroot sysread setpwent no crypt getc chown sqrt write setnetent setpriority foreach ' +
      'tie sin msgget map stat getlogin unless elsif truncate exec keys glob tied closedir' +
      'ioctl socket readlink eval xor readline binmode setservent eof ord bind alarm pipe ' +
      'atan2 getgrent exp time push setgrent gt lt or ne m|0 break given say state when';
    var SUBST = {
      className: 'subst',
      begin: '[$@]\\{', end: '\\}',
      keywords: PERL_KEYWORDS
    };
    var METHOD = {
      begin: '->{', end: '}'
      // contains defined later
    };
    var VAR = {
      className: 'variable',
      variants: [
        {begin: /\$\d/},
        {begin: /[\$\%\@](\^\w\b|#\w+(\:\:\w+)*|{\w+}|\w+(\:\:\w*)*)/},
        {begin: /[\$\%\@][^\s\w{]/, relevance: 0}
      ]
    };
    var COMMENT = {
      className: 'comment',
      begin: '^(__END__|__DATA__)', end: '\\n$',
      relevance: 5
    };
    var STRING_CONTAINS = [hljs.BACKSLASH_ESCAPE, SUBST, VAR];
    var PERL_DEFAULT_CONTAINS = [
      VAR,
      hljs.HASH_COMMENT_MODE,
      COMMENT,
      {
        className: 'comment',
        begin: '^\\=\\w', end: '\\=cut', endsWithParent: true
      },
      METHOD,
      {
        className: 'string',
        contains: STRING_CONTAINS,
        variants: [
          {
            begin: 'q[qwxr]?\\s*\\(', end: '\\)',
            relevance: 5
          },
          {
            begin: 'q[qwxr]?\\s*\\[', end: '\\]',
            relevance: 5
          },
          {
            begin: 'q[qwxr]?\\s*\\{', end: '\\}',
            relevance: 5
          },
          {
            begin: 'q[qwxr]?\\s*\\|', end: '\\|',
            relevance: 5
          },
          {
            begin: 'q[qwxr]?\\s*\\<', end: '\\>',
            relevance: 5
          },
          {
            begin: 'qw\\s+q', end: 'q',
            relevance: 5
          },
          {
            begin: '\'', end: '\'',
            contains: [hljs.BACKSLASH_ESCAPE]
          },
          {
            begin: '"', end: '"'
          },
          {
            begin: '`', end: '`',
            contains: [hljs.BACKSLASH_ESCAPE]
          },
          {
            begin: '{\\w+}',
            contains: [],
            relevance: 0
          },
          {
            begin: '\-?\\w+\\s*\\=\\>',
            contains: [],
            relevance: 0
          }
        ]
      },
      {
        className: 'number',
        begin: '(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b',
        relevance: 0
      },
      { // regexp container
        begin: '(\\/\\/|' + hljs.RE_STARTERS_RE + '|\\b(split|return|print|reverse|grep)\\b)\\s*',
        keywords: 'split return print reverse grep',
        relevance: 0,
        contains: [
          hljs.HASH_COMMENT_MODE,
          COMMENT,
          {
            className: 'regexp',
            begin: '(s|tr|y)/(\\\\.|[^/])*/(\\\\.|[^/])*/[a-z]*',
            relevance: 10
          },
          {
            className: 'regexp',
            begin: '(m|qr)?/', end: '/[a-z]*',
            contains: [hljs.BACKSLASH_ESCAPE],
            relevance: 0 // allows empty "//" which is a common comment delimiter in other languages
          }
        ]
      },
      {
        className: 'sub',
        beginKeywords: 'sub', end: '(\\s*\\(.*?\\))?[;{]',
        relevance: 5
      },
      {
        className: 'operator',
        begin: '-\\w\\b',
        relevance: 0
      }
    ];
    SUBST.contains = PERL_DEFAULT_CONTAINS;
    METHOD.contains = PERL_DEFAULT_CONTAINS;
  
    return {
      aliases: ['pl'],
      keywords: PERL_KEYWORDS,
      contains: PERL_DEFAULT_CONTAINS
    };
  }