static/js/hiril.js 3.0 KiB raw
1
(function (hiril) {
2
//
3
// hiril - Radiance IL Syntax Highlighter
4
//
5
// Copyright (c) 2020-2025 Alexis Sellier
6
//
7
const selector = hiril || '.language-ril';
8
const keywords = ['fn', 'data', 'extern', 'mut', 'align'];
9
const instrs = [
10
    'reserve', 'load', 'sload', 'store', 'blit', 'copy',
11
    'add', 'sub', 'mul', 'sdiv', 'udiv', 'srem', 'urem', 'neg',
12
    'eq', 'ne', 'slt', 'sge', 'ult', 'uge',
13
    'and', 'or', 'xor', 'shl', 'sshr', 'ushr', 'not',
14
    'zext', 'sext', 'call', 'ret', 'jmp',
15
    'switch', 'unreachable', 'ecall', 'ebreak'
16
];
17
const branchOps = ['br.eq', 'br.ne', 'br.slt', 'br.ult'];
18
const dataItems = ['str', 'sym', 'undef'];
19
const types = ['w8', 'w16', 'w32', 'w64'];
20
21
// Syntax definition.
22
//
23
// The key becomes the class name of the span around the matched block of code.
24
const syntax = [
25
    ['comment', /(\/\/[^\n]*)/g],
26
    ['string' , /("[^"]*")/g],
27
    ['reg'    , /(%[0-9]+)/g],
28
    ['label'  , /(@[A-Za-z_][A-Za-z#0-9_]*)/g],
29
    ['symbol' , /(\$[A-Za-z_][A-Za-z0-9_]*)/g],
30
    ['number' , /\b(-?[0-9]+|0x[a-fA-F0-9]+)\b/g],
31
    ['delim'  , /([{}();:,])/g],
32
    ['keyword', new RegExp('\\b(' + keywords.join('|') + ')\\b', 'g')],
33
    ['instr'  , new RegExp('\\b(' + branchOps.join('|').replace(/\./g, '\\.') + ')\\b', 'g')],
34
    ['instr'  , new RegExp('\\b(' + instrs.join('|') + ')\\b', 'g')],
35
    ['type'   , new RegExp('\\b(' + dataItems.join('|') + ')\\b', 'g')],
36
    ['type'   , new RegExp('\\b(' + types.join('|') + ')\\b', 'g')],
37
];
38
39
const table = {};
40
41
// Encode ASCII characters to Braille to avoid conflicts between patterns.
42
const encode = (str) => {
43
    const encoded = [...str].map(c =>
44
        c.charCodeAt(0) <= 127 ? String.fromCharCode(c.charCodeAt(0) + 0x2800) : c
45
    ).join('');
46
    table[encoded] = str;
47
48
    return encoded;
49
};
50
51
// Decode Braille back to ASCII.
52
const decode = (str) =>
53
    table[str] || [...str].map(c => {
54
        const code = c.charCodeAt(0) - 0x2800;
55
        return code >= 0 && code <= 127 ? String.fromCharCode(code) : c;
56
    }).join('');
57
58
// Escape HTML special characters.
59
const escape = (str) =>
60
    str.replace(/</g, '&lt;').replace(/>/g, '&gt;');
61
62
// Highlight all matching elements.
63
for (const node of document.querySelectorAll(selector)) {
64
    for (const child of node.childNodes) {
65
        if (child.nodeType !== Node.TEXT_NODE) continue;
66
        if (/^\$\s/.test(child.nodeValue.trim())) continue; // Skip shell snippets.
67
68
        for (const [cls, re] of syntax) {
69
            child.nodeValue = child.nodeValue.replace(re, (_, m) =>
70
                '\u00ab' + encode(cls) + '\u00b7' +
71
                           encode(m)   +
72
                '\u00b7' + encode(cls) + '\u00bb'
73
            );
74
        }
75
    }
76
    node.innerHTML = node.innerHTML.replace(
77
        /\u00ab(.+?)\u00b7(.+?)\u00b7\1\u00bb/g,
78
        (_, name, value) => {
79
            value = value.replace(/\u00ab[^\u00b7]+\u00b7|\u00b7[^\u00bb]+\u00bb/g, '');
80
            return '<span class="' + decode(name) + '">'   +
81
                                     escape(decode(value)) +
82
                   '</span>';
83
        }
84
    );
85
}
86
87
})(window.hiril);