Guest User

Untitled

a guest
Jul 28th, 2019
196
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==UserScript==
  2. // @name        forth-highlighter.js
  3. // @namespace   fforum.winglion.ru
  4. // @description highlights forth code
  5. // @include     http://fforum.winglion.ru/*
  6. // @require     https://code.jquery.com/jquery-3.4.1.slim.min.js
  7. // @version     1
  8. // @grant       none
  9. // ==/UserScript==
  10.  
  11. (function($) {
  12.     'use strict';
  13.     function highlight (text) {
  14.         if (!text) return "";
  15.         const all_source = text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;'); // внимание!!! в исходнике заэскейплены спецсимволы HTML
  16.         let rest_all_source = all_source;
  17.         let source;
  18.         let rest_source = '';
  19.         let latest;
  20.         let state = false;
  21.         let dstack = [];
  22.         let output = [];
  23.         let currenttags;  // стиль, который наследует слово
  24.         let current = []; // сюда компилируется слово
  25.         function compile(word) {
  26.             if (word in words) {
  27.                 const t = words[word][words[word].length - 1].tags;
  28.                 if (t && !currenttags) currenttags = t;
  29.                 current.push('this["' + word.replace(/['"\\]/g, '\\$&') + '"][' + String(words[word].length - 1) + ']();');
  30.             }
  31.         }
  32.         function notfound (word) {
  33.             if (word.match(/^(0x)?[0-9a-f]+$/i)) return number;
  34.             return ['', ''];
  35.         }
  36.         const words = {
  37.             parse: [function() {
  38.                 let c = dstack[dstack.length - 1];
  39.                 c = c === ' ' ? '\\s' : c.replace(/[^\w\s]/g, '\\$&');
  40.                 const regex = new RegExp('^[^' + c + ']*', 'g');
  41.                 const match = regex.exec(rest_source);
  42.                 dstack.push(match[0]);
  43.                 output.push(rest_source.slice(0, regex.lastIndex + 1));
  44.                 rest_source = rest_source.slice(regex.lastIndex + 1, rest_source.length);
  45.             }],
  46.             word: [function() {
  47.                 let c = dstack[dstack.length - 1];
  48.                 c = c == ' ' ? '\\s' : s.replace(/[^\w\s]/g, '\\$&');
  49.                 const regex = new RegExp('^[' + c + ']*', 'g');
  50.                 const match = regex.exec(rest_source);
  51.                 rest_source = rest_source.slice(regex.lastIndex, rest_source.length);
  52.                 output.push(match[0]);
  53.                 words.parse[0]();
  54.             }],
  55.             name: [function() {
  56.                 dstack.push(' ');
  57.                 words.word[0]();
  58.             }],
  59.             interpret: [function() {
  60.                 do {
  61.                     words.name[0]();
  62.                     const word = dstack.pop().toLowerCase();
  63.                     let xt = words[word] || false;
  64.                     xt = xt && xt[xt.length - 1];
  65.                     const tags = xt.tags || (!(word in words) && notfound(word));
  66.                     const t = output.pop();
  67.                     output.push(tags[0]);
  68.                     output.push(t);
  69.                     if (xt) {
  70.                         if (xt.immediate || !state) {
  71.                             xt();
  72.                         } else {
  73.                             compile(word);
  74.                         }
  75.                     }
  76.                     output.push(tags[1]);
  77.                 } while (rest_source);
  78.             }],
  79.             refill: [function() {
  80.                 output.push(rest_source);
  81.                 source = rest_source = '';
  82.                 if (!rest_all_source) {
  83.                     return;
  84.                 }
  85.                 const line = /^[^\n]*\n?/g;
  86.                 const match = line.exec(rest_all_source);
  87.                 source = rest_source = match[0];
  88.                 rest_all_source = rest_all_source.slice(line.lastIndex, rest_all_source.length);
  89.             }],
  90.             ':': [function() {
  91.                 words.name[0]();
  92.                 latest = dstack.pop().toLowerCase();
  93.                 current = [];
  94.                 state = true;
  95.             }],
  96.             ';': [function() {
  97.                 if (!words[latest]) words[latest] = [];
  98.                 words[latest].push(new Function(current.join('')).bind(words));
  99.                 state = false;
  100.                 words[latest][words[latest].length - 1].tags = currenttags;
  101.                 currenttags = undefined;
  102.                 current = [];
  103.             }],
  104.             '[': [function() {
  105.                 state = false;
  106.             }],
  107.             ']': [function() {
  108.                 state = true;
  109.             }],
  110.             bl: [function() {
  111.                 dstack.push(' ')
  112.             }],
  113.             immediate: [function() {
  114.                 words[latest][words[latest].length - 1].immediate = true;
  115.             }],
  116.             '(': [function() {
  117.                 dstack.push(')');
  118.                 words.parse[0]();
  119.             }],
  120.             '\\': [function() {
  121.                 words.refill[0]();
  122.             }],
  123.             'if': [function(){}],
  124.             'else': [function(){}],
  125.             then: [function(){}],
  126.             begin: [function(){}],
  127.             'while': [function(){}],
  128.             repeat: [function(){}],
  129.             until: [function(){}],
  130.             again: [function(){}],
  131.             'do': [function(){}],
  132.             loop: [function(){}],
  133.             '?do': [function(){}],
  134.             create: [function() {
  135.                 words.name[0]();
  136.                 latest = dstack.pop();
  137.                 if (!words[latest]) words[latest] = [];
  138.                 words[latest].push(function(){});
  139.             }],
  140.             'does&gt;': [function(){}],
  141.             postpone: [function() {
  142.                 words.name[0]();
  143.                 compile(dstack.pop().toLowerCase());
  144.             }],
  145.             'char': [function() {
  146.                 words.name[0]();
  147.                 dstack.push(dstack.pop()[0]);
  148.             }],
  149.             '[char]': [function() {
  150.                 words.name[0]();
  151.                 current.push('this.push[0]("' + dstack.pop()[0].replace(/[\\"]/g, "\\$&") + '");');
  152.             }],
  153.             push: [function(x) {
  154.                 dstack.push(x);
  155.             }],
  156.         };
  157.         words[';'][0].immediate = true;
  158.         words['('][0].immediate = true;
  159.         words['\\'][0].immediate = true;
  160.         words['['][0].immediate = true;
  161.         words['does&gt;'][0].immediate = true;
  162.         words['if'][0].immediate = true;
  163.         words['else'][0].immediate = true;
  164.         words['then'][0].immediate = true;
  165.         words.begin[0].immediate = true;
  166.         words['while'][0].immediate = true;
  167.         words.repeat[0].immediate = true;
  168.         words.until[0].immediate = true;
  169.         words.again[0].immediate = true;
  170.         words['do'][0].immediate = true;
  171.         words.loop[0].immediate = true;
  172.         words['?do'][0].immediate = true;
  173.         words.postpone[0].immediate = true;
  174.         words['[char]'][0].immediate = true;
  175.         // в св-ве tags хранится пара тегов: начало и конец
  176.         const literal = ['<span style="color: green;">', '</span>'];
  177.         const define = ['<span style="color: darkorange;">', '</span>'];
  178.         const comment = ['<span style="color: gray;">', '</span>'];
  179.         const control = ['<span style="color: blue;">', '</span>'];
  180.         const number = ['<span style="color: red;">', '</span>'];
  181.         words.parse[0].tags = literal;
  182.         words.word[0].tags = literal;
  183.         words.name[0].tags = literal;
  184.         words[':'][0].tags = define;
  185.         words[';'][0].tags = define;
  186.         words.create[0].tags = define;
  187.         words['does&gt;'][0].tags = define;
  188.         words['('][0].tags = comment;
  189.         words['\\'][0].tags = comment;
  190.         words['['][0].tags = ['<i>', ''];
  191.         words[']'][0].tags = ['', '</i>'];
  192.         words['if'][0].tags = control;
  193.         words['else'][0].tags = control;
  194.         words['then'][0].tags = control;
  195.         words.begin[0].tags = control;
  196.         words['while'][0].tags = control;
  197.         words.repeat[0].tags = control;
  198.         words.until[0].tags = control;
  199.         words.again[0].tags = control;
  200.         words['do'][0].tags = control;
  201.         words.loop[0].tags = control;
  202.         words['?do'][0].tags = control;
  203.         words.postpone[0].tags = literal;
  204.         words['[char]'][0].tags = literal;
  205.         function e(s) {
  206.             source = rest_source = s;
  207.             words.interpret[0]();
  208.             output = [];
  209.             dstack = [];
  210.         }
  211.         e(": ' name ; : ['] ' ; immediate");
  212.         e(': "  [char] " parse ; immediate');
  213.         words['."'] = words['c"'] = words['s"'] = words['"'];
  214.         e(': .(  [char] ) parse ; immediate');
  215.         e(': constant create ; : variable create ; : value create ; : vect create ; : ->vect create ; : defer create ; : vocabulary create ;');
  216.         e(': case postpone if ; immediate : of postpone if ; immediate : endof postpone if ; immediate : endcase postpone if ; immediate : exit postpone if ; immediate');
  217.         e(': code  : ;');
  218.         e(': end-code  postpone ; ; immediate');
  219.         function run () {
  220.             do {
  221.                 words.refill[0]();
  222.                 words.interpret[0]();
  223.             } while (rest_all_source);
  224.         }
  225.         try {
  226.             run();
  227.         } catch (e) {
  228.             console.log(e);
  229.         }
  230.         return output.join('').replace(/\n/g, '<br>');
  231.     }
  232.  
  233.     $('.codecontent').each(function(){
  234.         const code = $(this)[0];
  235.         code.setAttribute('style', 'color: black; font-size: 12pt; font-style: bold;');
  236.         const src = code.innerText;
  237.         try {
  238.             code.innerHTML = highlight(src);
  239.         } catch (e) {
  240.             console.log(e);
  241.         }
  242.         try {
  243.             $(code).append('<div><button>оригинал</button></div>');
  244.             const t = $(code).children('div');
  245.             t.children('button').bind('click', () => t.children('div').css('display', 'block'))
  246.             t.append('<div></div>');
  247.             t.children('div').css('display', 'none')[0].innerText = src;
  248.         } catch (e) {
  249.             console.log(e);
  250.         }
  251.     });
  252. })($);
Add Comment
Please, Sign In to add comment