From e3513733c2b0970901f564f898176858901e4f1b Mon Sep 17 00:00:00 2001 From: mikesamuel Date: Sat, 5 Jul 2008 03:59:51 +0000 Subject: [PATCH] implemented language specific formatters, fixed python docstrings, and slashes inside regular expression charsets. --- CHANGES.html | 4 + README.html | 15 +- src/prettify.js | 270 +++++++++++-------- tests/prettify_test.html | 556 ++++++++++++++++++++++++++++++++++++++- 4 files changed, 732 insertions(+), 113 deletions(-) diff --git a/CHANGES.html b/CHANGES.html index f584ee0b..a7efeaeb 100644 --- a/CHANGES.html +++ b/CHANGES.html @@ -37,6 +37,10 @@

29 March 2007

>patch
  • Added a distribution that has comments and whitespace removed to reduce download size from 45.5kB to 12.8kB. +
  • Added language specific formatters that are triggered by the presence + of a lang-<language-file-extension>
  • +
  • Fixed bug: python handling of '''string''' +
  • Fixed bug: / in regex [charsets] should not end regex diff --git a/README.html b/README.html index 2d9ee055..dfb4a496 100644 --- a/README.html +++ b/README.html @@ -71,8 +71,17 @@

    Which languages does it work for?

    CAML-like languages.

    How do I specify which language my code is in?

    -

    There's no way to tell it which language because would complicate the - interface. If it doesn't guess the language properly, that's a bug.

    +

    You don't need to specify the language since prettyprint() + will guess. You can specify a language by specifying the language extension + along with the prettyprint class like so:

    + + <pre class="prettyprint lang-html">
    +   The lang-* class specifies the language file extensions.
    +   Supported file extensions include
    +     "c", "cc", "cpp", "cs", "cyc", "java", "bsh", "csh", "sh",
    +     "cv", "py", "perl", "pl", "pm", "rb", "js",
    +     "html", "html", "xhtml", "xml", "xsl".
    + </pre>

    It doesn't work on <obfuscated code sample>?

    Yes. Prettifying obfuscated code is like putting lipstick on a pig @@ -93,7 +102,7 @@

    What's changed?

    diff --git a/src/prettify.js b/src/prettify.js index d5c77b3e..81de4dd8 100644 --- a/src/prettify.js +++ b/src/prettify.js @@ -140,7 +140,7 @@ function pr_isIE6() { "BEGIN END "; var SH_KEYWORDS = "break case continue do done elif else esac eval fi for " + "function if in local set then until while "; - var ALL_KEYWORD_SET = wordSet( + var ALL_KEYWORDS = ( CPP_KEYWORDS + CSHARP_KEYWORDS + JSCRIPT_KEYWORDS + PERL_KEYWORDS + PYTHON_KEYWORDS + RUBY_KEYWORDS + SH_KEYWORDS); @@ -270,6 +270,7 @@ function pr_isIE6() { var pr_aposEnt = /'/g; var pr_quotEnt = /"/g; var pr_ampEnt = /&/g; + var pr_nbspEnt = / /g; /** unescapes html to plain text. */ function htmlToText(html) { var pos = html.indexOf('&'); @@ -298,7 +299,8 @@ function pr_isIE6() { .replace(pr_gtEnt, '>') .replace(pr_aposEnt, "'") .replace(pr_quotEnt, '"') - .replace(pr_ampEnt, '&'); + .replace(pr_ampEnt, '&') + .replace(pr_nbspEnt, ' '); } /** is the given node's innerHTML normally unescaped? */ @@ -333,7 +335,7 @@ function pr_isIE6() { break; } } - + var PR_innerHtmlWorks = null; function getInnerHtml(node) { // inner html is hopelessly broken in Safari 2.0.4 when the content is @@ -497,7 +499,7 @@ function pr_isIE6() { * function that takes source code and returns a list of decorations. */ function createSimpleLexer(shortcutStylePatterns, - fallthroughStylePatterns) { + fallthroughStylePatterns) { var shortcuts = {}; (function () { var allPatterns = shortcutStylePatterns.concat(fallthroughStylePatterns); @@ -562,76 +564,6 @@ function pr_isIE6() { }; } - var PR_C_STYLE_STRING_AND_COMMENT_LEXER = createSimpleLexer([ - [PR_STRING, /^\'(?:[^\\\']|\\[\s\S])*(?:\'|$)/, null, "'"], - [PR_STRING, /^\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)/, null, '"'], - [PR_STRING, /^\`(?:[^\\\`]|\\[\s\S])*(?:\`|$)/, null, '`'] - ], [ - [PR_PLAIN, /^(?:[^\'\"\`\/\#]+)/, null, ' \r\n'], - [PR_COMMENT, /^#[^\r\n]*/, null, '#'], - [PR_COMMENT, /^\/\/[^\r\n]*/, null], - [PR_STRING, /^\/(?:[^\\\*\/]|\\[\s\S])+(?:\/|$)/, - REGEXP_PRECEDER_PATTERN], - [PR_COMMENT, /^\/\*[\s\S]*?(?:\*\/|$)/, null] - ]); - /** splits the given string into comment, string, and "other" tokens. - * @param {string} sourceCode as plain text - * @return {Array.} a decoration list. - * @private - */ - function splitStringAndCommentTokens(sourceCode) { - return PR_C_STYLE_STRING_AND_COMMENT_LEXER(sourceCode); - } - - var PR_C_STYLE_LITERAL_IDENTIFIER_PUNC_RECOGNIZER = createSimpleLexer([], [ - [PR_PLAIN, /^\s+/, null, ' \r\n'], - // TODO(mikesamuel): recognize non-latin letters and numerals in idents - [PR_PLAIN, /^[a-z_$@][a-z_$@0-9]*/i, null], - // A hex number - [PR_LITERAL, /^0x[a-f0-9]+[a-z]/i, null], - // An octal or decimal number, possibly in scientific notation - [PR_LITERAL, /^(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d+)(?:e[+\-]?\d+)?[a-z]*/i, - null, '123456789'], - [PR_PUNCTUATION, /^[^\s\w\.$@]+/, null] - // Fallback will handle decimal points not adjacent to a digit - ]); - - /** splits plain text tokens into more specific tokens, and then tries to - * recognize keywords, and types. - * @private - */ - function splitNonStringNonCommentTokens(source, decorations) { - for (var i = 0; i < decorations.length; i += 2) { - var style = decorations[i + 1]; - if (style === PR_PLAIN) { - var start, end, chunk, subDecs; - start = decorations[i]; - end = i + 2 < decorations.length ? decorations[i + 2] : source.length; - chunk = source.substring(start, end); - subDecs = PR_C_STYLE_LITERAL_IDENTIFIER_PUNC_RECOGNIZER(chunk, start); - for (var j = 0, m = subDecs.length; j < m; j += 2) { - var subStyle = subDecs[j + 1]; - if (subStyle === PR_PLAIN) { - var subStart = subDecs[j]; - var subEnd = j + 2 < m ? subDecs[j + 2] : chunk.length; - var token = source.substring(subStart, subEnd); - if (token === '.') { - subDecs[j + 1] = PR_PUNCTUATION; - } else if (token in ALL_KEYWORD_SET) { - subDecs[j + 1] = PR_KEYWORD; - } else if (/^@?[A-Z][A-Z$]*[a-z][A-Za-z$]*$/.test(token)) { - // classify types and annotations using Java's style conventions - subDecs[j + 1] = token.charAt(0) === '@' ? PR_LITERAL : PR_TYPE; - } - } - } - spliceArrayInto(subDecs, decorations, i, 2); - i += subDecs.length - 2; - } - } - return decorations; - } - var PR_MARKUP_LEXER = createSimpleLexer([], [ [PR_PLAIN, /^[^<]+/, null], [PR_DECLARATION, /^]*(?:>|$)/, null], @@ -704,7 +636,7 @@ function pr_isIE6() { return decorations; } - /** returns a list of decorations, where even entries + /** returns a function that produces a list of decorations from source text. * * This code treats ", ', and ` as string delimiters, and \ as a string * escape. It does not recognize perl's qq() style strings. @@ -715,30 +647,130 @@ function pr_isIE6() { * * It recognizes C, C++, and shell style comments. * - * @param {string} sourceCode as plain text - * @return {Array.} a decoration list + * @param {Object} options a set of optional parameters. + * @return {function (sourceCode : string) : Array.} a + * decorator that takes sourceCode as plain text and that returns a + * decoration list */ - function decorateSource(sourceCode) { - // Split into strings, comments, and other. - // We do this because strings and comments are easily recognizable and can - // contain stuff that looks like other tokens, so we want to mark those - // early so we don't recurse into them. - var decorations = splitStringAndCommentTokens(sourceCode); + function sourceDecorator(options) { + var shortcutStylePatterns = [], fallthroughStylePatterns = []; + if (options.tripleQuotedStrings) { + shortcutStylePatterns.push( + [PR_STRING, /^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/, + null, '\'"']); + } else if (options.multiLineStrings) { + shortcutStylePatterns.push( + [PR_STRING, /^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/, + null, '\'"`']); + } else { + shortcutStylePatterns.push( + [PR_STRING, + /^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/, + null, '"\'']); + } + fallthroughStylePatterns.push( + [PR_PLAIN, /^(?:[^\'\"\`\/\#]+)/, null, ' \r\n']); + if (options.hashComments) { + shortcutStylePatterns.push([PR_COMMENT, /^#[^\r\n]*/, null, '#']); + } + if (options.cStyleComments) { + fallthroughStylePatterns.push([PR_COMMENT, /^\/\/[^\r\n]*/, null]); + } + if (options.regexLiterals) { + fallthroughStylePatterns.push( + [PR_STRING, + /^\/(?:[^\\\*\/\[]|\\[\s\S]|\[(?:[^\]\\]|\\.)*(?:\]|$))+(?:\/|$)/, + REGEXP_PRECEDER_PATTERN]); + } + if (options.cStyleComments) { + fallthroughStylePatterns.push( + [PR_COMMENT, /^\/\*[\s\S]*?(?:\*\/|$)/, null]); + } - // Split non comment|string tokens on whitespace and word boundaries - decorations = splitNonStringNonCommentTokens(sourceCode, decorations); + var keywords = wordSet(options.keywords); + + options = null; + + /** splits the given string into comment, string, and "other" tokens. + * @param {string} sourceCode as plain text + * @return {Array.} a decoration list. + * @private + */ + var splitStringAndCommentTokens = createSimpleLexer( + shortcutStylePatterns, fallthroughStylePatterns); + + var styleLiteralIdentifierPuncRecognizer = createSimpleLexer([], [ + [PR_PLAIN, /^\s+/, null, ' \r\n'], + // TODO(mikesamuel): recognize non-latin letters and numerals in idents + [PR_PLAIN, /^[a-z_$@][a-z_$@0-9]*/i, null], + // A hex number + [PR_LITERAL, /^0x[a-f0-9]+[a-z]/i, null], + // An octal or decimal number, possibly in scientific notation + [PR_LITERAL, + /^(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d+)(?:e[+\-]?\d+)?[a-z]*/i, + null, '123456789'], + [PR_PUNCTUATION, /^[^\s\w\.$@]+/, null] + // Fallback will handle decimal points not adjacent to a digit + ]); - return decorations; - } + /** splits plain text tokens into more specific tokens, and then tries to + * recognize keywords, and types. + * @private + */ + function splitNonStringNonCommentTokens(source, decorations) { + for (var i = 0; i < decorations.length; i += 2) { + var style = decorations[i + 1]; + if (style === PR_PLAIN) { + var start, end, chunk, subDecs; + start = decorations[i]; + end = i + 2 < decorations.length ? decorations[i + 2] : source.length; + chunk = source.substring(start, end); + subDecs = styleLiteralIdentifierPuncRecognizer(chunk, start); + for (var j = 0, m = subDecs.length; j < m; j += 2) { + var subStyle = subDecs[j + 1]; + if (subStyle === PR_PLAIN) { + var subStart = subDecs[j]; + var subEnd = j + 2 < m ? subDecs[j + 2] : chunk.length; + var token = source.substring(subStart, subEnd); + if (token === '.') { + subDecs[j + 1] = PR_PUNCTUATION; + } else if (token in keywords) { + subDecs[j + 1] = PR_KEYWORD; + } else if (/^@?[A-Z][A-Z$]*[a-z][A-Za-z$]*$/.test(token)) { + // classify types and annotations using Java's style conventions + subDecs[j + 1] = token.charAt(0) === '@' ? PR_LITERAL : PR_TYPE; + } + } + } + spliceArrayInto(subDecs, decorations, i, 2); + i += subDecs.length - 2; + } + } + return decorations; + } - function cSourceDecorator(keywords, opt_options) { - return decorateSource; // TODO: implement me - } + return function (sourceCode) { + // Split into strings, comments, and other. + // We do this because strings and comments are easily recognizable and can + // contain stuff that looks like other tokens, so we want to mark those + // early so we don't recurse into them. + var decorations = splitStringAndCommentTokens(sourceCode); + + // Split non comment|string tokens on whitespace and word boundaries + decorations = splitNonStringNonCommentTokens(sourceCode, decorations); - function shellSourceDecorator(keywords, opt_options) { - return decorateSource; // TODO: implement me + return decorations; + }; } + var decorateSource = sourceDecorator({ + keywords: ALL_KEYWORDS, + hashComments: true, + cStyleComments: true, + multiLineStrings: true, + regexLiterals: true + }); + /** identify regions of markup that are really source code, and recursivley * lex them. * @private @@ -958,22 +990,44 @@ function pr_isIE6() { } registerLangHandler(decorateSource, ['default-code']); registerLangHandler(decorateMarkup, - ['default-markup', 'html', 'htm', 'xhtml', 'xml']); - registerLangHandler(cSourceDecorator(CPP_KEYWORDS), - ['c', 'cc', 'cpp', 'cs', 'cxx', 'cyc']); - registerLangHandler(cSourceDecorator(JAVA_KEYWORDS), ['java']); - registerLangHandler(shellSourceDecorator(SH_KEYWORDS), ['csh', 'sh']); - registerLangHandler( - shellSourceDecorator(PYTHON_KEYWORDS), ['cv', 'py'], - { tripleQuotedStrings: true }); - registerLangHandler( - shellSourceDecorator(PERL_KEYWORDS, - { regexLiteral: true, multiLineStrings: true }), ['pl']); - registerLangHandler( - shellSourceDecorator(RUBY_KEYWORDS, - { regexLiteral: true, multiLineStrings: true }), ['rb']); - registerLangHandler( - cSourceDecorator(JSCRIPT_KEYWORDS, { regexLiteral: true }), ['js']); + ['default-markup', 'html', 'htm', 'xhtml', 'xml', 'xsl']); + registerLangHandler(sourceDecorator({ + keywords: CPP_KEYWORDS, + hashComments: true, + cStyleComments: true + }), ['c', 'cc', 'cpp', 'cs', 'cxx', 'cyc']); + registerLangHandler(sourceDecorator({ + keywords: JAVA_KEYWORDS, + cStyleComments: true + }), ['java']); + registerLangHandler(sourceDecorator({ + keywords: SH_KEYWORDS, + hashComments: true, + multiLineStrings: true + }), ['bsh', 'csh', 'sh']); + registerLangHandler(sourceDecorator({ + keywords: PYTHON_KEYWORDS, + hashComments: true, + multiLineStrings: true, + tripleQuotedStrings: true + }), ['cv', 'py']); + registerLangHandler(sourceDecorator({ + keywords: PERL_KEYWORDS, + hashComments: true, + multiLineStrings: true, + regexLiterals: true + }), ['perl', 'pl', 'pm']); + registerLangHandler(sourceDecorator({ + keywords: RUBY_KEYWORDS, + hashComments: true, + multiLineStrings: true, + regexLiterals: true + }), ['rb']); + registerLangHandler(sourceDecorator({ + keywords: JSCRIPT_KEYWORDS, + cStyleComments: true, + regexLiterals: true + }), ['js']); function prettyPrintOne(sourceCodeHtml, opt_langExtension) { try { diff --git a/tests/prettify_test.html b/tests/prettify_test.html index bf5958b4..eaafb331 100644 --- a/tests/prettify_test.html +++ b/tests/prettify_test.html @@ -41,6 +41,26 @@

    Bash

    fib | head -10 | tail -1 +

    Bash w/ language specified

    +
    #!/bin/bash
    +
    +# Fibonacci numbers
    +# Writes an infinite series to stdout, one entry per line
    +function fib() {
    +  local a=1
    +  local b=1
    +  while true ; do
    +    echo $a
    +    local tmp=$a
    +    a=$(( $a + $b ))
    +    b=$tmp
    +  done
    +}
    +
    +# output the 10th element of the series and halt
    +fib | head -10 | tail -1
    +
    +

    C

    @@ -64,6 +84,28 @@ 

    C

    }
    +

    C w/ language specified

    + +
    +#include <stdio.h>
    +
    +/* the nth fibonacci number. */
    +unsigned int fib(unsigned int n) {
    +  unsigned int a = 1, b = 1;
    +  unsigned int tmp;
    +  while (--n >= 0) {
    +    tmp = a;
    +    a += b;
    +    b = tmp;
    +  }
    +  return a;
    +}
    +
    +void main() {
    +  printf("%u", fib(10));
    +}
    +
    +

    C++

     #include <iostream>
    @@ -77,7 +119,33 @@ 

    C++

    template <class T> T fib(unsigned int n, const T& fib0) { T a(fib0), b(fib0); - while (--n >= 0) { + for (; n; --n) { + T tmp(a); + a += b; + b = tmp; + } + return a; +} + +int main(int argc, char **argv) { + cout << fib(10, 1U); +} +
    + +

    C++ w/ language specified

    +
    +#include <iostream>
    +
    +using namespace std;
    +
    +//! fibonacci numbers with gratuitous use of templates.
    +//! \param n an index into the fibonacci series
    +//! \param fib0 element 0 of the series
    +//! \return the nth element of the fibonacci series
    +template <class T>
    +T fib(int n, const T& fib0) {
    +  T a(fib0), b(fib0);
    +  while (--n >= 0) {
         T tmp(a);
         a += b;
         b = tmp;
    @@ -103,6 +171,7 @@ 

    Java

    /** the next and previous members of the series. */ private int a = 1, b = 1; + @Override public Iterator<Integer> iterator() { return new Iterator<Integer>() { /** the series is infinite. */ @@ -137,6 +206,57 @@

    Java

    }
    +

    Java w/ language specified

    +
    +package foo;
    +
    +import java.util.Iterator;
    +
    +/**
    + * the fibonacci series implemented as an Iterable.
    + */
    +public final class Fibonacci implements Iterable<Integer> {
    +  /** the next and previous members of the series. */
    +  private int a = 1, b = 1;
    +
    +  @Override
    +  public Iterator<Integer> iterator() {
    +    return new Iterator<Integer>() {
    +      /** the series is infinite. */
    +      public boolean hasNext() { return true; }
    +      public Integer next() {
    +        int tmp = a;
    +        a += b;
    +        b = tmp;
    +        return a;
    +      }
    +      public void remove() { throw new UnsupportedOperationException(); }
    +    };
    +  }
    +
    +  /**
    +   * the n<sup>th</sup> element of the given series.
    +   * @throws NoSuchElementException if there are less than n elements in the
    +   *   given Iterable's {@link Iterable#iterator iterator}.
    +   */
    +  public static <T>
    +  T nth(int n, Iterable<T> iterable) {
    +    Iterator<? extends T> in = iterable.iterator();
    +    while (--n > 0) {
    +      in.next();
    +    }
    +    return in.next();
    +  }
    +
    +  public static void main(String[] args) {
    +    System.out.print(nth(10, new Fibonacci()));
    +  }
    +}
    +
    +# not a java comment
    +# not keywords: static_cast and namespace
    +
    +

    Javascript

     /**
    @@ -166,6 +286,7 @@ 

    Issue 12 - Javascript Regular Expressions

    "foo /bar/".test(/"baz"/); // test string and regexp boundaries var division = /\b\d+\/\d+/g; // test char sets and escaping of specials var allSpecials = /([^\(\)\[\]\{\}\-\?\+\*\.\^\$\/]+)\\/; +var slashInCharset = /[^/]/g, notCloseSq = /[^\]]/; // test that slash used in numeric context treated as an operator 1 / 2; @@ -197,6 +318,52 @@

    Issue 12 - Javascript Regular Expressions

    // & not used as prefix operator in javascript but this should still work &/foo/; + +extends = /extends/; +
    + +

    Issue 12 - Javascript Regular Expressions w/ language specified

    +
    +/foo/;  // a slash starting a line treated as a regexp beginning
    +"foo".match(/fo+$/);
    +// this line comment not treated as a regular expressions
    +"foo /bar/".test(/"baz"/);  // test string and regexp boundaries
    +var division = /\b\d+\/\d+/g;  // test char sets and escaping of specials
    +var allSpecials = /([^\(\)\[\]\{\}\-\?\+\*\.\^\$\/]+)\\/;
    +var slashInCharset = /[^/]/g, notCloseSq = /[^\]]/;
    +
    +// test that slash used in numeric context treated as an operator
    +1 / 2;
    +1. / x;
    +x / y;
    +(x) / y;
    +1 /* foo */ / 2;
    +1 /* foo *// 2;
    +1/2;
    +1./x;
    +x/y;
    +(x)/y;
    +
    +// test split over two lines.  line comment should not fool it
    +1//
    +/2;
    +
    +x++/y;
    +x--/y;
    +x[y] / z;
    +f() / n;
    +
    +// test that slash after non postfix operator is start of regexp
    +log('matches = ' + /foo/.test(foo));
    +
    +// test keyword preceders
    +return /a regexp/;
    +division = notreturn / not_a_regexp / 2;  // keyword suffix does not match
    +
    +// & not used as prefix operator in javascript but this should still work
    +&/foo/;
    +
    +extends = /extends/;
     

    Perl

    @@ -246,6 +413,36 @@

    Python

    print nth(fib(), 10) +

    Python w/ language specified

    +
    +#!/usr/bin/python2.4
    +
    +def fib():
    +  '''
    +  a generator that produces the fibonacci series's elements
    +  '''
    +
    +  a = 1
    +  b = 1
    +  while True:
    +    a, b = a + b, a
    +    yield a
    +
    +def nth(series, n):
    +  '''
    +  returns the nth element of a series,
    +  consuming the earlier elements of the series
    +  '''
    +
    +  for x in series:
    +    n -= 1
    +    if n <= 0: return x
    +
    +print nth(fib(), 10)
    +
    +/* not a comment and not keywords: null char true */
    +
    +

    XML

     <!DOCTYPE series PUBLIC "fibonacci numbers">
    @@ -300,6 +497,40 @@ 

    HTML

    </html>
    +

    HTML w/ language specified

    +
    +Fibonacci Numbers
    +
    +<noscript>
    +  <dl>
    +    <dt>Fibonacci numbers</dt>
    +    <dd>1</dd>
    +    <dd>1</dd>
    +    <dd>2</dd>
    +    <dd>3</dd>
    +    <dd>5</dd>
    +    <dd>8</dd>
    +    &hellip;
    +  </dl>
    +</noscript>
    +
    +<script type="text/javascript"><!--
    +function fib(n) {
    +  var a = 1, b = 1;
    +  var tmp;
    +  while (--n >= 0) {
    +    tmp = a;
    +    a += b;
    +    b = tmp;
    +  }
    +  return a;
    +}
    +
    +document.writeln(fib(10));
    +// -->
    +</script>
    +
    +

    HTML using XMP

    Bug 21 - code doesn't copy and paste well in IE</h1> '`END`COM# output the 10th element of the series and halt`END`PLN<br>' + 'fib `END`PUN|`END`PLN head `END`PUN-`END`LIT10`END`PLN `END`PUN|`END' + '`PLN tail `END`PUN-`END`LIT1`END'), + bash_lang: ( + '`COM#!/bin/bash`END`PLN<br>' + + '<br>' + + '`END`COM# Fibonacci numbers`END`PLN<br>' + + '`END`COM# Writes an infinite series to stdout, one entry per line`END' + + '`PLN<br>' + + '`END`KWDfunction`END`PLN fib`END`PUN()`END`PLN `END`PUN{`END`PLN<br>' + + '&nbsp; `END`KWDlocal`END`PLN a`END`PUN=`END`LIT1`END`PLN<br>' + + '&nbsp; `END`KWDlocal`END`PLN b`END`PUN=`END`LIT1`END`PLN<br>' + + '&nbsp; `END`KWDwhile`END`PLN true `END`PUN;`END' + + '`PLN `END`KWDdo`END`PLN<br>' + + '&nbsp; &nbsp; echo $a<br>' + + '&nbsp; &nbsp; `END`KWDlocal`END`PLN tmp`END`PUN=`END`PLN$a<br>' + + '&nbsp; &nbsp; a`END`PUN=`END`PLN$`END`PUN((`END`PLN $a `END`PUN+`END' + + '`PLN $b `END`PUN))`END`PLN<br>' + + '&nbsp; &nbsp; b`END`PUN=`END`PLN$tmp<br>' + + '&nbsp; `END`KWDdone`END`PLN<br>' + + '`END`PUN}`END`PLN<br>' + + '<br>' + + '`END`COM# output the 10th element of the series and halt`END`PLN<br>' + + 'fib `END`PUN|`END`PLN head `END`PUN-`END`LIT10`END`PLN `END`PUN|`END' + + '`PLN tail `END`PUN-`END`LIT1`END'), C: ( '`COM#include &lt;stdio.h&gt;`END`PLN<br>' + '<br>' + @@ -532,6 +785,31 @@ <h1>Bug 21 - code doesn't copy and paste well in IE</h1> '&nbsp; printf`END`PUN(`END`STR"%u"`END`PUN,`END`PLN fib`END`PUN(`END' + '`LIT10`END`PUN));`END`PLN<br>' + '`END`PUN}`END'), + C_lang: ( + '`COM#include &lt;stdio.h&gt;`END`PLN<br>' + + '<br>' + + '`END`COM/* the n`END<sup>`COMth`END<\/sup>`COM fibonacci number. *\/`END`PLN<br>' + + '`END`KWDunsigned`END`PLN `END`KWDint`END`PLN fib`END`PUN(`END' + + '`KWDunsigned`END`PLN `END`KWDint`END`PLN n`END`PUN)`END`PLN `END' + + '`PUN{`END`PLN<br>' + + '&nbsp; `END`KWDunsigned`END`PLN `END`KWDint`END`PLN a `END`PUN=`END' + + '`PLN `END`LIT1`END`PUN,`END`PLN b `END`PUN=`END`PLN `END`LIT1`END' + + '`PUN;`END`PLN<br>' + + '&nbsp; `END`KWDunsigned`END`PLN `END`KWDint`END`PLN tmp`END`PUN;`END' + + '`PLN<br>' + + '&nbsp; `END`KWDwhile`END`PLN `END`PUN(--`END`PLNn `END`PUN&gt;=`END' + + '`PLN `END`LIT0`END`PUN)`END`PLN `END`PUN{`END`PLN<br>' + + '&nbsp; &nbsp; tmp `END`PUN=`END`PLN a`END`PUN;`END`PLN<br>' + + '&nbsp; &nbsp; a `END`PUN+=`END`PLN b`END`PUN;`END`PLN<br>' + + '&nbsp; &nbsp; b `END`PUN=`END`PLN tmp`END`PUN;`END`PLN<br>' + + '&nbsp; `END`PUN}`END`PLN<br>' + + '&nbsp; `END`KWDreturn`END`PLN a`END`PUN;`END`PLN<br>' + + '`END`PUN}`END`PLN<br>' + + '<br>' + + '`END`KWDvoid`END`PLN main`END`PUN()`END`PLN `END`PUN{`END`PLN<br>' + + '&nbsp; printf`END`PUN(`END`STR"%u"`END`PUN,`END`PLN fib`END`PUN(`END' + + '`LIT10`END`PUN));`END`PLN<br>' + + '`END`PUN}`END'), Cpp: ( '`COM#include &lt;iostream&gt;`END`PLN<br>' + '<br>' + @@ -551,6 +829,41 @@ <h1>Bug 21 - code doesn't copy and paste well in IE</h1> '`END`PUN)`END`PLN `END`PUN{`END`PLN<br>' + '&nbsp; T a`END`PUN(`END`PLNfib0`END`PUN),`END`PLN b`END`PUN(`END' + '`PLNfib0`END`PUN);`END`PLN<br>' + + '&nbsp; `END`KWDfor`END`PLN `END`PUN(;`END`PLN n`END`PUN;`END' + + '`PLN `END`PUN--`END`PLNn`END`PUN)`END`PLN `END`PUN{`END`PLN<br>' + + '&nbsp; &nbsp; T tmp`END`PUN(`END`PLNa`END`PUN);`END`PLN<br>' + + '&nbsp; &nbsp; a `END`PUN+=`END`PLN b`END`PUN;`END`PLN<br>' + + '&nbsp; &nbsp; b `END`PUN=`END`PLN tmp`END`PUN;`END`PLN<br>' + + '&nbsp; `END`PUN}`END`PLN<br>' + + '&nbsp; `END`KWDreturn`END`PLN a`END`PUN;`END`PLN<br>' + + '`END`PUN}`END`PLN<br>' + + '<br>' + + '`END`KWDint`END`PLN main`END`PUN(`END`KWDint`END`PLN argc`END' + + '`PUN,`END`PLN `END`KWDchar`END`PLN `END`PUN**`END`PLNargv`END' + + '`PUN)`END`PLN `END`PUN{`END`PLN<br>' + + '&nbsp; cout `END`PUN&lt;&lt;`END`PLN fib`END`PUN(`END`LIT10`END' + + '`PUN,`END`PLN `END`LIT1U`END`PUN);`END`PLN<br>' + + '`END`PUN}`END'), + + Cpp_lang: ( + '`COM#include &lt;iostream&gt;`END`PLN<br>' + + '<br>' + + '`END`KWDusing`END`PLN `END`KWDnamespace`END`PLN std`END`PUN;`END' + + '`PLN<br>' + + '<br>' + + '`END`COM//! fibonacci numbers with gratuitous use of templates.`END' + + '`PLN<br>' + + '`END`COM//! \\param n an index into the fibonacci series`END`PLN<br>' + + '`END`COM//! \\param fib0 element 0 of the series`END`PLN<br>' + + '`END`COM//! \\return the nth element of the fibonacci series`END' + + '`PLN<br>' + + '`END`KWDtemplate`END`PLN `END`PUN&lt;`END`KWDclass`END`PLN T`END' + + '`PUN&gt;`END`PLN<br>' + + 'T fib`END`PUN(`END`KWDint`END`PLN n`END' + + '`PUN,`END`PLN `END`KWDconst`END`PLN T`END`PUN&amp;`END`PLN fib0' + + '`END`PUN)`END`PLN `END`PUN{`END`PLN<br>' + + '&nbsp; T a`END`PUN(`END`PLNfib0`END`PUN),`END`PLN b`END`PUN(`END' + + '`PLNfib0`END`PUN);`END`PLN<br>' + '&nbsp; `END`KWDwhile`END`PLN `END`PUN(--`END`PLNn `END`PUN&gt;=`END' + '`PLN `END`LIT0`END`PUN)`END`PLN `END`PUN{`END`PLN<br>' + '&nbsp; &nbsp; T tmp`END`PUN(`END`PLNa`END`PUN);`END`PLN<br>' + @@ -587,6 +900,7 @@ <h1>Bug 21 - code doesn't copy and paste well in IE</h1> '`PLN `END`LIT1`END`PUN,`END`PLN b `END`PUN=`END`PLN `END`LIT1`END' + '`PUN;`END`PLN<br>' + '<br>' + + '&nbsp; `END`LIT@Override`END`PLN<br>' + '&nbsp; `END`KWDpublic`END`PLN `END`TYPIterator`END`PUN&lt;`END' + '`TYPInteger`END`PUN&gt;`END`PLN iterator`END`PUN()`END`PLN `END' + '`PUN{`END`PLN<br>' + @@ -651,6 +965,95 @@ <h1>Bug 21 - code doesn't copy and paste well in IE</h1> '`PLN<br>' + '&nbsp; `END`PUN}`END`PLN<br>' + '`END`PUN}`END'), + java_lang: ( + '`KWDpackage`END`PLN foo`END`PUN;`END`PLN<br>' + + '<br>' + + '`END`KWDimport`END`PLN java`END`PUN.`END`PLNutil`END`PUN.`END' + + '`TYPIterator`END`PUN;`END`PLN<br>' + + '<br>' + + '`END`COM/**<br>' + + '&nbsp;* the fibonacci series implemented as an Iterable.<br>' + + '&nbsp;*\/`END`PLN<br>' + + '`END`KWDpublic`END`PLN `END`KWDfinal`END`PLN `END`KWDclass`END' + + '`PLN `END`TYPFibonacci`END`PLN `END`KWDimplements`END`PLN `END' + + '`TYPIterable`END`PUN&lt;`END`TYPInteger`END`PUN&gt;`END`PLN `END`' + + 'PUN{`END`PLN<br>' + + '&nbsp; `END' + + '`COM/** the next and previous members of the series. *\/`END' + + '`PLN<br>' + + '&nbsp; `END`KWDprivate`END`PLN `END`KWDint`END`PLN a `END`PUN=`END' + + '`PLN `END`LIT1`END`PUN,`END`PLN b `END`PUN=`END`PLN `END`LIT1`END' + + '`PUN;`END`PLN<br>' + + '<br>' + + '&nbsp; `END`LIT@Override`END`PLN<br>' + + '&nbsp; `END`KWDpublic`END`PLN `END`TYPIterator`END`PUN&lt;`END' + + '`TYPInteger`END`PUN&gt;`END`PLN iterator`END`PUN()`END`PLN `END' + + '`PUN{`END`PLN<br>' + + '&nbsp; &nbsp; `END`KWDreturn`END`PLN `END`KWDnew`END`PLN `END' + + '`TYPIterator`END`PUN&lt;`END`TYPInteger`END`PUN&gt;()`END`PLN `END' + + '`PUN{`END`PLN<br>' + + '&nbsp; &nbsp; &nbsp; `END`COM/** the series is infinite. *\/`END' + + '`PLN<br>' + + '&nbsp; &nbsp; &nbsp; `END`KWDpublic`END`PLN `END`KWDboolean`END' + + '`PLN hasNext`END`PUN()`END`PLN `END`PUN{`END`PLN `END' + + '`KWDreturn`END`PLN `END`KWDtrue`END`PUN;`END`PLN `END`PUN}`END' + + '`PLN<br>' + + '&nbsp; &nbsp; &nbsp; `END`KWDpublic`END`PLN `END`TYPInteger`END' + + '`PLN next`END`PUN()`END`PLN `END`PUN{`END`PLN<br>' + + '&nbsp; &nbsp; &nbsp; &nbsp; `END`KWDint`END`PLN tmp `END`PUN=`END' + + '`PLN a`END`PUN;`END`PLN<br>' + + '&nbsp; &nbsp; &nbsp; &nbsp; a `END`PUN+=`END`PLN b`END`PUN;`END' + + '`PLN<br>' + + '&nbsp; &nbsp; &nbsp; &nbsp; b `END`PUN=`END`PLN tmp`END`PUN;`END' + + '`PLN<br>' + + '&nbsp; &nbsp; &nbsp; &nbsp; `END`KWDreturn`END`PLN a`END`PUN;`END' + + '`PLN<br>' + + '&nbsp; &nbsp; &nbsp; `END`PUN}`END`PLN<br>' + + '&nbsp; &nbsp; &nbsp; `END`KWDpublic`END`PLN `END`KWDvoid`END' + + '`PLN remove`END`PUN()`END`PLN `END`PUN{`END`PLN `END`KWDthrow`END' + + '`PLN `END`KWDnew`END`PLN `END' + + '`TYPUnsupportedOperationException`END`PUN();`END`PLN `END' + + '`PUN}`END`PLN<br>' + + '&nbsp; &nbsp; `END`PUN};`END`PLN<br>' + + '&nbsp; `END`PUN}`END`PLN<br>' + + '<br>' + + '&nbsp; `END`COM/**<br>' + + '&nbsp; &nbsp;* the n&lt;sup&gt;th&lt;/sup&gt; element of the given ' + + 'series.<br>' + + '&nbsp; &nbsp;* @throws NoSuchElementException if there are less than ' + + 'n elements in the<br>' + + '&nbsp; &nbsp;* &nbsp; given Iterable\'s {@link Iterable#iterator ' + + 'iterator}.<br>' + + '&nbsp; &nbsp;*\/`END`PLN<br>' + + '&nbsp; `END`KWDpublic`END`PLN `END`KWDstatic`END`PLN `END' + + '`PUN&lt;`END`PLNT`END`PUN&gt;`END`PLN<br>' + + '&nbsp; T nth`END`PUN(`END`KWDint`END`PLN n`END`PUN,`END`PLN `END' + + '`TYPIterable`END`PUN&lt;`END`PLNT`END`PUN&gt;`END' + + '`PLN iterable`END`PUN)`END`PLN `END`PUN{`END`PLN<br>' + + '&nbsp; &nbsp; `END`TYPIterator`END`PUN&lt;?`END`PLN `END' + + '`KWDextends`END`PLN T`END`PUN&gt;`END`PLN in `END`PUN=`END' + + '`PLN iterable`END`PUN.`END`PLNiterator`END`PUN();`END`PLN<br>' + + '&nbsp; &nbsp; `END`KWDwhile`END`PLN `END`PUN(--`END`PLNn `END' + + '`PUN&gt;`END`PLN `END`LIT0`END`PUN)`END`PLN `END`PUN{`END`PLN<br>' + + '&nbsp; &nbsp; &nbsp; in`END`PUN.`END`PLNnext`END`PUN();`END`PLN<br>' + + '&nbsp; &nbsp; `END`PUN}`END`PLN<br>' + + '&nbsp; &nbsp; `END`KWDreturn`END`PLN in`END`PUN.`END`PLNnext`END' + + '`PUN();`END`PLN<br>' + + '&nbsp; `END`PUN}`END`PLN<br>' + + '<br>' + + '&nbsp; `END`KWDpublic`END`PLN `END`KWDstatic`END`PLN `END`KWDvoid`END' + + '`PLN main`END`PUN(`END`TYPString`END`PUN[]`END`PLN args`END' + + '`PUN)`END`PLN `END`PUN{`END`PLN<br>' + + '&nbsp; &nbsp; `END`TYPSystem`END`PUN.`END`PLNout`END`PUN.`END' + + '`PLNprint`END`PUN(`END`PLNnth`END`PUN(`END`LIT10`END`PUN,`END' + + '`PLN `END`KWDnew`END`PLN `END`TYPFibonacci`END`PUN()));`END' + + '`PLN<br>' + + '&nbsp; `END`PUN}`END`PLN<br>' + + '`END`PUN}`END`PLN<br>' + + '<br>' + + '`END`PUN#`END`PLN not a java comment<br>' + + '`END`PUN#`END`PLN not keywords`END`PUN:`END' + + '`PLN static_cast and namespace`END'), javascript: ( '`COM/**<br>' + '&nbsp;* nth element in the fibonacci series.<br>' + @@ -728,6 +1131,42 @@ <h1>Bug 21 - code doesn't copy and paste well in IE</h1> '<br>' + '`END`KWDprint`END`PLN nth`END`PUN(`END`PLNfib`END`PUN(),`END`PLN `END' + '`LIT10`END`PUN)`END'), + python_lang: ( + '`COM#!/usr/bin/python2.4`END`PLN<br>' + + '<br>' + + '`END`KWDdef`END`PLN fib`END`PUN():`END`PLN<br>' + + '&nbsp; `END`STR\'\'\'<br>' + + '&nbsp; a generator that produces the fibonacci series\'s elements' + + '<br>' + + '&nbsp; \'\'\'`END`PLN<br>' + + '<br>' + + '&nbsp; a `END`PUN=`END`PLN `END`LIT1`END`PLN<br>' + + '&nbsp; b `END`PUN=`END`PLN `END`LIT1`END`PLN<br>' + + '&nbsp; `END`KWDwhile`END`PLN `END`KWDTrue`END`PUN:`END`PLN<br>' + + '&nbsp; &nbsp; a`END`PUN,`END`PLN b `END`PUN=`END`PLN a `END`PUN+`END' + + '`PLN b`END`PUN,`END`PLN a<br>' + + '&nbsp; &nbsp; `END`KWDyield`END`PLN a<br>' + + '<br>' + + '`END`KWDdef`END`PLN nth`END`PUN(`END`PLNseries`END`PUN,`END`PLN n`END' + + '`PUN):`END`PLN<br>' + + '&nbsp; `END`STR\'\'\'<br>' + + '&nbsp; returns the nth element of a series,<br>' + + '&nbsp; consuming the earlier elements of the series<br>' + + '&nbsp; \'\'\'`END`PLN<br>' + + '<br>' + + '&nbsp; `END`KWDfor`END`PLN x `END`KWDin`END`PLN series`END`PUN:`END' + + '`PLN<br>' + + '&nbsp; &nbsp; n `END`PUN-=`END`PLN `END`LIT1`END' + + '`PLN<br>' + + '&nbsp; &nbsp; `END`KWDif`END`PLN n `END`PUN&lt;=`END`PLN `END' + + '`LIT0`END`PUN:`END`PLN `END`KWDreturn`END`PLN x<br>' + + '<br>' + + '`END`KWDprint`END`PLN nth`END`PUN(`END`PLNfib`END`PUN(),`END`PLN `END' + + '`LIT10`END`PUN)`END`PLN<br>' + + '<br>' + + '`END`PUN/*`END`PLN `END`KWDnot`END`PLN a comment `END`KWDand`END' + + '`PLN `END`KWDnot`END`PLN keywords`END`PUN:`END' + + '`PLN null char true `END`PUN*/`END'), xml: ( '`DEC&lt;!DOCTYPE series PUBLIC "fibonacci numbers"&gt;`END`PLN<br>' + '<br>' + @@ -810,6 +1249,49 @@ <h1>Bug 21 - code doesn't copy and paste well in IE</h1> '&nbsp; &nbsp; `END`PUN&lt;/`END`TAGscript`END`PUN&gt;`END`PLN<br>' + '&nbsp; `END`PUN&lt;/`END`TAGbody`END`PUN&gt;`END`PLN<br>' + '`END`PUN&lt;/`END`TAGhtml`END`PUN&gt;`END'), + html_lang: ( + '`PLNFibonacci Numbers<br>' + + '<br>' + + '`END`PUN&lt;`END`TAGnoscript`END`PUN&gt;`END`PLN<br>' + + '&nbsp; `END`PUN&lt;`END`TAGdl`END`PUN&gt;`END`PLN<br>' + + '&nbsp; &nbsp; `END`PUN&lt;`END`TAGdt`END`PUN&gt;`END' + + '`PLNFibonacci numbers`END`PUN&lt;/`END`TAGdt`END`PUN&gt;`END`PLN<br>' + + '&nbsp; &nbsp; `END`PUN&lt;`END`TAGdd`END`PUN&gt;`END`PLN1`END' + + '`PUN&lt;/`END`TAGdd`END`PUN&gt;`END`PLN<br>' + + '&nbsp; &nbsp; `END`PUN&lt;`END`TAGdd`END`PUN&gt;`END`PLN1`END' + + '`PUN&lt;/`END`TAGdd`END`PUN&gt;`END`PLN<br>' + + '&nbsp; &nbsp; `END`PUN&lt;`END`TAGdd`END`PUN&gt;`END`PLN2`END' + + '`PUN&lt;/`END`TAGdd`END`PUN&gt;`END`PLN<br>' + + '&nbsp; &nbsp; `END`PUN&lt;`END`TAGdd`END`PUN&gt;`END`PLN3`END' + + '`PUN&lt;/`END`TAGdd`END`PUN&gt;`END`PLN<br>' + + '&nbsp; &nbsp; `END`PUN&lt;`END`TAGdd`END`PUN&gt;`END`PLN5`END' + + '`PUN&lt;/`END`TAGdd`END`PUN&gt;`END`PLN<br>' + + '&nbsp; &nbsp; `END`PUN&lt;`END`TAGdd`END`PUN&gt;`END`PLN8`END' + + '`PUN&lt;/`END`TAGdd`END`PUN&gt;`END`PLN<br>' + + '&nbsp; &nbsp; &amp;hellip;<br>' + + '&nbsp; `END`PUN&lt;/`END`TAGdl`END`PUN&gt;`END`PLN<br>' + + '`END`PUN&lt;/`END`TAGnoscript`END`PUN&gt;`END`PLN<br>' + + '<br>' + + '`END`PUN&lt;`END`TAGscript`END`PLN `END`ATNtype`END`PUN=`END' + + '`ATV"text/javascript"`END`PUN&gt;&lt;!--`END`PLN<br>' + + '`END`KWDfunction`END`PLN fib`END`PUN(`END`PLNn`END`PUN)`END`PLN `END' + + '`PUN{`END`PLN<br>' + + '&nbsp; `END`KWDvar`END`PLN a `END`PUN=`END`PLN `END`LIT1`END`PUN,`END' + + '`PLN b `END`PUN=`END`PLN `END`LIT1`END`PUN;`END`PLN<br>' + + '&nbsp; `END`KWDvar`END`PLN tmp`END`PUN;`END`PLN<br>' + + '&nbsp; `END`KWDwhile`END`PLN `END`PUN(--`END`PLNn `END`PUN&gt;=`END' + + '`PLN `END`LIT0`END`PUN)`END`PLN `END`PUN{`END`PLN<br>' + + '&nbsp; &nbsp; tmp `END`PUN=`END`PLN a`END`PUN;`END`PLN<br>' + + '&nbsp; &nbsp; a `END`PUN+=`END`PLN b`END`PUN;`END`PLN<br>' + + '&nbsp; &nbsp; b `END`PUN=`END`PLN tmp`END`PUN;`END`PLN<br>' + + '&nbsp; `END`PUN}`END`PLN<br>' + + '&nbsp; `END`KWDreturn`END`PLN a`END`PUN;`END`PLN<br>' + + '`END`PUN}`END`PLN<br>' + + '<br>' + + 'document`END`PUN.`END`PLNwriteln`END`PUN(`END`PLNfib`END`PUN(`END' + + '`LIT10`END`PUN));`END`PLN<br>' + + '`END`COM// --&gt;`END`PLN<br>' + + '`END`PUN&lt;/`END`TAGscript`END`PUN&gt;`END'), htmlXmp: ( '`PUN&lt;`END`TAGhtml`END`PUN&gt;`END`PLN<br>' + '&nbsp; `END`PUN&lt;`END`TAGhead`END`PUN&gt;`END`PLN<br>' + @@ -1014,6 +1496,74 @@ <h1>Bug 21 - code doesn't copy and paste well in IE</h1> '`END`KWDvar`END`PLN allSpecials `END`PUN=`END`PLN `END' + '`STR/([^\\(\\)\\[\\]\\{\\}\\-\\?\\+\\*\\.\\^\\$\\/]+)\\\\/`END' + '`PUN;`END`PLN<br>' + + '`END`KWDvar`END`PLN slashInCharset `END`PUN=`END`PLN `END' + + '`STR/[^/]/`END`PLNg`END`PUN,`END`PLN notCloseSq `END`PUN=`END' + + '`PLN `END`STR/[^\\]]/`END`PUN;`END`PLN<br>' + + '<br>' + + '`END`COM// test that slash used in numeric context treated as an ' + + 'operator`END`PLN<br>' + + '`END`LIT1`END`PLN `END`PUN/`END`PLN `END`LIT2`END`PUN;`END`PLN<br>' + + '`END`LIT1.`END`PLN `END`PUN/`END`PLN x`END`PUN;`END`PLN<br>' + + 'x `END`PUN/`END`PLN y`END`PUN;`END`PLN<br>' + + '`END`PUN(`END`PLNx`END`PUN)`END`PLN `END`PUN/`END`PLN y`END`PUN;`END' + + '`PLN<br>' + + '`END`LIT1`END`PLN `END`COM/* foo *\/`END`PLN `END`PUN/`END`PLN `END' + + '`LIT2`END`PUN;`END`PLN<br>' + + '`END`LIT1`END`PLN `END`COM/* foo *\/`END`PUN/`END`PLN `END`LIT2`END' + + '`PUN;`END`PLN<br>' + + '`END`LIT1`END`PUN/`END`LIT2`END`PUN;`END`PLN<br>' + + '`END`LIT1.`END`PUN/`END`PLNx`END`PUN;`END`PLN<br>' + + 'x`END`PUN/`END`PLNy`END`PUN;`END`PLN<br>' + + '`END`PUN(`END`PLNx`END`PUN)/`END`PLNy`END`PUN;`END`PLN<br>' + + '<br>' + + '`END`COM// test split over two lines. &nbsp;line comment should not ' + + 'fool it`END`PLN<br>' + + '`END`LIT1`END`COM//`END`PLN<br>' + + '`END`PUN/`END`LIT2`END`PUN;`END`PLN<br>' + + '<br>' + + 'x`END`PUN++/`END`PLNy`END`PUN;`END`PLN<br>' + + 'x`END`PUN--/`END`PLNy`END`PUN;`END`PLN<br>' + + 'x`END`PUN[`END`PLNy`END`PUN]`END`PLN `END`PUN/`END`PLN z`END`PUN;`END' + + '`PLN<br>' + + 'f`END`PUN()`END`PLN `END`PUN/`END`PLN n`END`PUN;`END`PLN<br>' + + '<br>' + + '`END`COM// test that slash after non postfix operator is start of ' + + 'regexp`END`PLN<br>' + + 'log`END`PUN(`END`STR\'matches = \'`END`PLN `END`PUN+`END`PLN `END' + + '`STR/foo/`END`PUN.`END`PLNtest`END`PUN(`END`PLNfoo`END`PUN));`END' + + '`PLN<br>' + + '<br>' + + '`END`COM// test keyword preceders`END`PLN<br>' + + '`END`KWDreturn`END`PLN `END`STR/a regexp/`END`PUN;`END`PLN<br>' + + 'division `END`PUN=`END`PLN notreturn `END`PUN/`END`PLN not_a_regexp ' + + '`END`PUN/`END`PLN `END`LIT2`END`PUN;`END`PLN &nbsp;`END`COM// ' + + 'keyword suffix does not match`END`PLN<br>' + + '<br>' + + '`END`COM// &amp; not used as prefix operator in javascript but this ' + + 'should still work`END`PLN<br>' + + '`END`PUN&amp;`END`STR/foo/`END`PUN;`END`PLN<br>' + + '<br>' + + '`END`KWDextends`END`PLN `END`PUN=`END`PLN `END`STR/extends/`END' + + '`PUN;`END'), + issue12_lang: ( + '`STR/foo/`END`PUN;`END`PLN &nbsp;`END`COM// a slash starting a line ' + + 'treated as a regexp beginning`END`PLN<br>' + + '`END`STR"foo"`END`PUN.`END`PLNmatch`END`PUN(`END`STR/fo+$/`END' + + '`PUN);`END`PLN<br>' + + '`END`COM// this line comment not treated as a regular expressions`END' + + '`PLN<br>' + + '`END`STR"foo /bar/"`END`PUN.`END`PLNtest`END`PUN(`END`STR/"baz"/`END' + + '`PUN);`END`PLN &nbsp;`END`COM// test string and regexp boundaries' + + '`END`PLN<br>' + + '`END`KWDvar`END`PLN division `END`PUN=`END`PLN `END' + + '`STR/\\b\\d+\\/\\d+/`END`PLNg`END`PUN;`END`PLN &nbsp;`END' + + '`COM// test char sets and escaping of specials`END`PLN<br>' + + '`END`KWDvar`END`PLN allSpecials `END`PUN=`END`PLN `END' + + '`STR/([^\\(\\)\\[\\]\\{\\}\\-\\?\\+\\*\\.\\^\\$\\/]+)\\\\/`END' + + '`PUN;`END`PLN<br>' + + '`END`KWDvar`END`PLN slashInCharset `END`PUN=`END`PLN `END' + + '`STR/[^/]/`END`PLNg`END`PUN,`END`PLN notCloseSq `END`PUN=`END' + + '`PLN `END`STR/[^\\]]/`END`PUN;`END`PLN<br>' + '<br>' + '`END`COM// test that slash used in numeric context treated as an ' + 'operator`END`PLN<br>' + @@ -1056,7 +1606,9 @@ <h1>Bug 21 - code doesn't copy and paste well in IE</h1> '<br>' + '`END`COM// &amp; not used as prefix operator in javascript but this ' + 'should still work`END`PLN<br>' + - '`END`PUN&amp;`END`STR/foo/`END`PUN;`END'), + '`END`PUN&amp;`END`STR/foo/`END`PUN;`END`PLN<br>' + + '<br>' + + 'extends `END`PUN=`END`PLN `END`STR/extends/`END`PUN;`END'), issue14a: ( '`COM//comment`END`PLN<br>' + '`END`KWDint`END`PLN main`END`PUN(`END`KWDint`END`PLN argc`END`PUN,`END' +