refactor compile
This commit is contained in:
parent
214c10e547
commit
59cc5d73c3
868
lib/tput.js
868
lib/tput.js
|
@ -253,445 +253,455 @@ Tput.prototype.parseExtended = function(data) {
|
||||||
return info;
|
return info;
|
||||||
};
|
};
|
||||||
|
|
||||||
Tput.prototype.invoke = function(key, prefix, params, suffix) {
|
Tput.prototype.compile = function(key) {
|
||||||
var self = this;
|
var self = this
|
||||||
if (!this.info.all) {
|
, info = this.info;
|
||||||
this.info.all = {};
|
|
||||||
Object.keys(info.bools).forEach(function(key) {
|
|
||||||
self.info.all[key] = info.bools;
|
|
||||||
});
|
|
||||||
Object.keys(info.numbers).forEach(function(key) {
|
|
||||||
self.info.all[key] = info.numbers;
|
|
||||||
});
|
|
||||||
Object.keys(info.strings).forEach(function(key) {
|
|
||||||
self.info.all[key] = info.strings;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
var val = this.info.all[key];
|
this.methods = {};
|
||||||
if (val == null) return;
|
this.info.all = {};
|
||||||
|
|
||||||
|
Object.keys(info.bools).forEach(function(key) {
|
||||||
|
info.all[key] = info.bools;
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.keys(info.numbers).forEach(function(key) {
|
||||||
|
info.all[key] = info.numbers;
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.keys(info.strings).forEach(function(key) {
|
||||||
|
info.all[key] = info.strings;
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.keys(info.all).forEach(function(key) {
|
||||||
|
self.methods[key] = self._compile(info.all[key]);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Tput.prototype._compile = function(val) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
switch (typeof val) {
|
switch (typeof val) {
|
||||||
case 'boolean':
|
case 'boolean':
|
||||||
val = val ? 'true' : 'false';
|
return function() {
|
||||||
break;
|
return val ? 'true' : 'false';
|
||||||
|
};
|
||||||
case 'number':
|
case 'number':
|
||||||
//val = val === -1 ? '' : val + '';
|
return function() {
|
||||||
val = val + '';
|
return val === -1 ? null : val;
|
||||||
break;
|
};
|
||||||
case 'string':
|
case 'string':
|
||||||
// e.g.
|
|
||||||
// set_attributes: '%?%p9%t\u001b(0%e\u001b(B%;\u001b[0%?%p6%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m',
|
|
||||||
// cursor_address: '\u001b[%i%p1%d;%p2%dH',
|
|
||||||
// column_address: '\u001b[%i%p1%dG',
|
|
||||||
// change_scroll_region: '\u001b[%i%p1%d;%p2%dr',
|
|
||||||
// CSI Ps ; Ps r
|
|
||||||
// CSI ? Pm r
|
|
||||||
|
|
||||||
var code = 'var dyn = {}, stat = {}, stack = [], out = []; out.push("';
|
|
||||||
|
|
||||||
// man terminfo, around line 940
|
|
||||||
|
|
||||||
while (val) {
|
|
||||||
// '\e' -> ^[
|
|
||||||
if (cap = /^\\e/gi.exec(val)) {
|
|
||||||
val = val.substring(cap[0].length);
|
|
||||||
code += '\x1b';
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// '^A' -> ^A
|
|
||||||
if (cap = /^\^(.)/gi.exec(val)) { // case-insensitive?
|
|
||||||
val = val.substring(cap[0].length);
|
|
||||||
ch = cap[1];
|
|
||||||
switch (ch) {
|
|
||||||
case '@':
|
|
||||||
code += '\x00';
|
|
||||||
break;
|
|
||||||
case 'A':
|
|
||||||
code += '\x01';
|
|
||||||
break;
|
|
||||||
case 'B':
|
|
||||||
code += '\x02';
|
|
||||||
break;
|
|
||||||
case 'C':
|
|
||||||
code += '\x03';
|
|
||||||
break;
|
|
||||||
case 'D':
|
|
||||||
code += '\x04';
|
|
||||||
break;
|
|
||||||
case 'E':
|
|
||||||
code += '\x05';
|
|
||||||
break;
|
|
||||||
case 'F':
|
|
||||||
code += '\x06';
|
|
||||||
break;
|
|
||||||
case 'G':
|
|
||||||
code += '\x07';
|
|
||||||
break;
|
|
||||||
case 'H':
|
|
||||||
code += '\x08';
|
|
||||||
break;
|
|
||||||
case 'I':
|
|
||||||
code += '\x09'; // \t
|
|
||||||
break;
|
|
||||||
case 'J':
|
|
||||||
code += '\x0a'; // \n
|
|
||||||
break;
|
|
||||||
case 'K':
|
|
||||||
code += '\x0b';
|
|
||||||
break;
|
|
||||||
case 'L':
|
|
||||||
code += '\x0c';
|
|
||||||
break;
|
|
||||||
case 'M':
|
|
||||||
code += '\x0d';
|
|
||||||
break;
|
|
||||||
case 'N':
|
|
||||||
code += '\x0e';
|
|
||||||
break;
|
|
||||||
case 'O':
|
|
||||||
code += '\x0f';
|
|
||||||
break;
|
|
||||||
case 'P':
|
|
||||||
code += '\x10';
|
|
||||||
break;
|
|
||||||
case 'Q':
|
|
||||||
code += '\x11';
|
|
||||||
break;
|
|
||||||
case 'R':
|
|
||||||
code += '\x12';
|
|
||||||
break;
|
|
||||||
case 'S':
|
|
||||||
code += '\x13';
|
|
||||||
break;
|
|
||||||
case 'T':
|
|
||||||
code += '\x14';
|
|
||||||
break;
|
|
||||||
case 'U':
|
|
||||||
code += '\x15';
|
|
||||||
break;
|
|
||||||
case 'V':
|
|
||||||
code += '\x16';
|
|
||||||
break;
|
|
||||||
case 'W':
|
|
||||||
code += '\x17';
|
|
||||||
break;
|
|
||||||
case 'X':
|
|
||||||
code += '\x18';
|
|
||||||
break;
|
|
||||||
case 'Y':
|
|
||||||
code += '\x19';
|
|
||||||
break;
|
|
||||||
case 'Z':
|
|
||||||
code += '\x1a';
|
|
||||||
break;
|
|
||||||
case '\\':
|
|
||||||
code += '\x1c';
|
|
||||||
break;
|
|
||||||
case '^':
|
|
||||||
code += '\x1e';
|
|
||||||
break;
|
|
||||||
case '_':
|
|
||||||
code += '\x1f';
|
|
||||||
break;
|
|
||||||
case '[':
|
|
||||||
code += '\x1b';
|
|
||||||
break;
|
|
||||||
case ']':
|
|
||||||
code += '\x1d';
|
|
||||||
break;
|
|
||||||
case '?':
|
|
||||||
code += '\x7f';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// '\n' -> \n
|
|
||||||
// '\r' -> \r
|
|
||||||
// '\0' -> \200 (special case)
|
|
||||||
if (cap = /^\\([nlrtbfs\^\\,:0])/g.exec(val)) {
|
|
||||||
val = val.substring(cap[0].length);
|
|
||||||
ch = cap[1];
|
|
||||||
switch (ch) {
|
|
||||||
case 'n':
|
|
||||||
return '\n';
|
|
||||||
case 'l':
|
|
||||||
return '\l';
|
|
||||||
case 'r':
|
|
||||||
return '\r';
|
|
||||||
case 't':
|
|
||||||
return '\t';
|
|
||||||
case 'b':
|
|
||||||
return '\b';
|
|
||||||
case 'f':
|
|
||||||
return '\f';
|
|
||||||
case 's':
|
|
||||||
return '\s';
|
|
||||||
case '\\':
|
|
||||||
return '\\';
|
|
||||||
case ',':
|
|
||||||
return ',';
|
|
||||||
case ';':
|
|
||||||
return ';';
|
|
||||||
case '0':
|
|
||||||
//return '\0';
|
|
||||||
return '\200';
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3 octal digits -> character
|
|
||||||
if (cap = /^\\(\d\d\d)/g.exec(val)) {
|
|
||||||
val = val.substring(cap[0].length);
|
|
||||||
ch = cap[1];
|
|
||||||
code += String.fromCharCode(parseInt(ch, 8));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// $<5> -> padding
|
|
||||||
if (cap = /^\$<(\d+)>(\*|\/)/g.exec(val)) {
|
|
||||||
val = val.substring(cap[0].length);
|
|
||||||
ch = cap[1];
|
|
||||||
code += Array(+ch + 1).join(' '); // "padding" characters?
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// man terminfo, around page 1034
|
|
||||||
// %% outputs `%'
|
|
||||||
if (cap = /^%%/g.exec(val)) {
|
|
||||||
val = val.substring(cap[0].length);
|
|
||||||
code += '%';
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// %[[:]flags][width[.precision]][doxXs]
|
|
||||||
// as in printf, flags are [-+#] and space. Use a `:' to allow the
|
|
||||||
// next character to be a `-' flag, avoiding interpreting "%-" as an
|
|
||||||
// operator.
|
|
||||||
if (cap = /^%(?:(:)?([\-+# ]+)?)(?:(\d+)(\.\d+)?)?([doxXs])?/g.exec(val)) {
|
|
||||||
val = val.substring(cap[0].length);
|
|
||||||
code += 'TODO';
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// %c print pop() like %c in printf
|
|
||||||
if (cap = /^%c/g.exec(val)) {
|
|
||||||
val = val.substring(cap[0].length);
|
|
||||||
code += 'stack.pop()'; // TODO: FORMAT
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// %d print pop() like %d in printf
|
|
||||||
// NOT SURE ABOUT %d being print!
|
|
||||||
if (cap = /^%d/g.exec(val)) {
|
|
||||||
val = val.substring(cap[0].length);
|
|
||||||
code += 'stack.pop()'; // TODO: FORMAT
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// %s print pop() like %s in printf
|
|
||||||
if (cap = /^%s/g.exec(val)) {
|
|
||||||
val = val.substring(cap[0].length);
|
|
||||||
code += 'stack.pop()'; // TODO: FORMAT
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// %p[1-9]
|
|
||||||
// push i'th parameter
|
|
||||||
if (cap = /^%p([1-9])/g.exec(val)) {
|
|
||||||
val = val.substring(cap[0].length);
|
|
||||||
code += 'params[i]';
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// %P[a-z]
|
|
||||||
// set dynamic variable [a-z] to pop()
|
|
||||||
if (cap = /^%P([a-z])/g.exec(val)) {
|
|
||||||
val = val.substring(cap[0].length);
|
|
||||||
v = cap[1];
|
|
||||||
code += 'dyn.' + v + ' = stack.pop()';
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// %g[a-z]
|
|
||||||
// get dynamic variable [a-z] and push it
|
|
||||||
if (cap = /^%g([a-z])/g.exec(val)) {
|
|
||||||
val = val.substring(cap[0].length);
|
|
||||||
v = cap[1];
|
|
||||||
code += '(stack.push(dyn.' + v + '), dyn.' + v + ')';
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// %P[A-Z]
|
|
||||||
// set static variable [a-z] to pop()
|
|
||||||
if (cap = /^%P([A-Z])/g.exec(val)) {
|
|
||||||
val = val.substring(cap[0].length);
|
|
||||||
v = cap[1];
|
|
||||||
code += 'stat.' + v + ' = stack.pop()';
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// %g[A-Z]
|
|
||||||
// get static variable [a-z] and push it
|
|
||||||
|
|
||||||
// The terms "static" and "dynamic" are misleading. Historically,
|
|
||||||
// these are simply two different sets of variables, whose values are
|
|
||||||
// not reset between calls to tparm. However, that fact is not
|
|
||||||
// documented in other implementations. Relying on it will adversely
|
|
||||||
// impact portability to other implementations.
|
|
||||||
|
|
||||||
if (cap = /^%g([A-Z])/g.exec(val)) {
|
|
||||||
val = val.substring(cap[0].length);
|
|
||||||
v = cap[1];
|
|
||||||
code += 'stack.push(stat.' + v + ')';
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// %'c' char constant c
|
|
||||||
if (cap = /^%'(\w)'/g.exec(val)) {
|
|
||||||
val = val.substring(cap[0].length);
|
|
||||||
ch = cap[1];
|
|
||||||
code += '"' + ch + '"';
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// %{nn}
|
|
||||||
// integer constant nn
|
|
||||||
if (cap = /^%\{(\d+)\}/g.exec(val)) {
|
|
||||||
val = val.substring(cap[0].length);
|
|
||||||
ch = cap[1];
|
|
||||||
code += '(' + ch + ')';
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// %l push strlen(pop)
|
|
||||||
if (cap = /^%l/g.exec(val)) {
|
|
||||||
val = val.substring(cap[0].length);
|
|
||||||
code += 'stack.push(stack.pop().length)';
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// %+ %- %* %/ %m
|
|
||||||
// arithmetic (%m is mod): push(pop() op pop())
|
|
||||||
// %& %| %^
|
|
||||||
// bit operations (AND, OR and exclusive-OR): push(pop() op pop())
|
|
||||||
// %= %> %<
|
|
||||||
// logical operations: push(pop() op pop())
|
|
||||||
if (cap = /^%([+\-*\/m&|\^=><])/g.exec(val)) {
|
|
||||||
val = val.substring(cap[0].length);
|
|
||||||
op = cap[1];
|
|
||||||
if (op === '=') op = '===';
|
|
||||||
else if (op === 'm') op = '%';
|
|
||||||
code += 'stack.push(stack.pop() ' + op + ' stack.pop())';
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// %A, %O
|
|
||||||
// logical AND and OR operations (for conditionals)
|
|
||||||
if (cap = /^%([AO])/g.exec(val)) {
|
|
||||||
val = val.substring(cap[0].length);
|
|
||||||
op = cap[1];
|
|
||||||
code += op === ' A ' ? ' && ' : ' || ';
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// %! %~
|
|
||||||
// unary operations (logical and bit complement): push(op pop())
|
|
||||||
if (cap = /^%([!~])/g.exec(val)) {
|
|
||||||
val = val.substring(cap[0].length);
|
|
||||||
op = cap[1];
|
|
||||||
code += 'stack.push(' + op + 'stack.pop())';
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// %i add 1 to first two parameters (for ANSI terminals)
|
|
||||||
if (cap = /^%i/g.exec(val)) {
|
|
||||||
val = val.substring(cap[0].length);
|
|
||||||
code += '(params[0]++, params[1]++)';
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// %? expr %t thenpart %e elsepart %;
|
|
||||||
// This forms an if-then-else. The %e elsepart is optional. Usually
|
|
||||||
// the %? expr part pushes a value onto the stack, and %t pops it from
|
|
||||||
// the stack, testing if it is nonzero (true). If it is zero (false),
|
|
||||||
// control passes to the %e (else) part.
|
|
||||||
|
|
||||||
// It is possible to form else-if's a la Algol 68:
|
|
||||||
// %? c1 %t b1 %e c2 %t b2 %e c3 %t b3 %e c4 %t b4 %e %;
|
|
||||||
|
|
||||||
// where ci are conditions, bi are bodies.
|
|
||||||
|
|
||||||
// Use the -f option of tic or infocmp to see the structure of
|
|
||||||
// if-then-else's. Some strings, e.g., sgr can be very complicated when
|
|
||||||
// written on one line. The -f option splits the string into lines with
|
|
||||||
// the parts indented.
|
|
||||||
if (cap = /^%\?/g.exec(val)) {
|
|
||||||
val = val.substring(cap[0].length);
|
|
||||||
code += '"); if (';
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cap = /^%t/g.exec(val)) {
|
|
||||||
val = val.substring(cap[0].length);
|
|
||||||
code += ') { out.push("';
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cap = /^%e/g.exec(val)) {
|
|
||||||
val = val.substring(cap[0].length);
|
|
||||||
code += '"); } else { out.push("';
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cap = /^%;/g.exec(val)) {
|
|
||||||
val = val.substring(cap[0].length);
|
|
||||||
code += '"); } out.push("';
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Binary operations are in postfix form with the operands in the usual
|
|
||||||
// order. That is, to get x-5 one would use "%gx%{5}%-". %P and %g vari‐
|
|
||||||
// ables are persistent across escape-string evaluations.
|
|
||||||
|
|
||||||
// Consider the HP2645, which, to get to row 3 and column 12, needs to be
|
|
||||||
// sent \E&a12c03Y padded for 6 milliseconds. Note that the order of the
|
|
||||||
// rows and columns is inverted here, and that the row and column are
|
|
||||||
// printed as two digits. Thus its cup capability is
|
|
||||||
// “cup=6\E&%p2%2dc%p1%2dY”.
|
|
||||||
|
|
||||||
// The Microterm ACT-IV needs the current row and column sent
|
|
||||||
// preceded by a ^T, with the row and column simply encoded in
|
|
||||||
// binary, “cup=^T%p1%c%p2%c”. Terminals which use “%c” need to be able
|
|
||||||
// to backspace the cursor (cub1), and to move the cursor up one line
|
|
||||||
// on the screen (cuu1). This is necessary because it is not always safe
|
|
||||||
// to transmit \n ^D and \r, as the system may change or discard them.
|
|
||||||
// (The library routines dealing with terminfo set tty modes so that tabs
|
|
||||||
// are never expanded, so \t is safe to send. This turns out to be
|
|
||||||
// essential for the Ann Arbor 4080.)
|
|
||||||
|
|
||||||
// A final example is the LSI ADM-3a, which uses row and column offset
|
|
||||||
// by a blank character, thus “cup=\E=%p1%' '%+%c%p2%' '%+%c”. After
|
|
||||||
// sending `\E=', this pushes the first parameter, pushes the ASCII value
|
|
||||||
// for a space (32), adds them (pushing the sum on the stack in place of
|
|
||||||
// the two previous values) and outputs that value as a character.
|
|
||||||
// Then the same is done for the second parameter. More complex
|
|
||||||
// arithmetic is possible using the stack.
|
|
||||||
|
|
||||||
code += val[0];
|
|
||||||
val = val.substring(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
code += '"); return out.join("");';
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
return function() {};
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(val);
|
// e.g.
|
||||||
|
// set_attributes: '%?%p9%t\u001b(0%e\u001b(B%;\u001b[0%?%p6%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m',
|
||||||
|
// cursor_address: '\u001b[%i%p1%d;%p2%dH',
|
||||||
|
// column_address: '\u001b[%i%p1%dG',
|
||||||
|
// change_scroll_region: '\u001b[%i%p1%d;%p2%dr',
|
||||||
|
// CSI Ps ; Ps r
|
||||||
|
// CSI ? Pm r
|
||||||
|
|
||||||
return val;
|
var code = 'var dyn = {}, stat = {}, stack = [], out = []; out.push("';
|
||||||
|
|
||||||
|
// man terminfo, around line 940
|
||||||
|
|
||||||
|
while (val) {
|
||||||
|
// '\e' -> ^[
|
||||||
|
if (cap = /^\\e/gi.exec(val)) {
|
||||||
|
val = val.substring(cap[0].length);
|
||||||
|
code += '\x1b';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// '^A' -> ^A
|
||||||
|
if (cap = /^\^(.)/gi.exec(val)) { // case-insensitive?
|
||||||
|
val = val.substring(cap[0].length);
|
||||||
|
ch = cap[1];
|
||||||
|
switch (ch) {
|
||||||
|
case '@':
|
||||||
|
code += '\x00';
|
||||||
|
break;
|
||||||
|
case 'A':
|
||||||
|
code += '\x01';
|
||||||
|
break;
|
||||||
|
case 'B':
|
||||||
|
code += '\x02';
|
||||||
|
break;
|
||||||
|
case 'C':
|
||||||
|
code += '\x03';
|
||||||
|
break;
|
||||||
|
case 'D':
|
||||||
|
code += '\x04';
|
||||||
|
break;
|
||||||
|
case 'E':
|
||||||
|
code += '\x05';
|
||||||
|
break;
|
||||||
|
case 'F':
|
||||||
|
code += '\x06';
|
||||||
|
break;
|
||||||
|
case 'G':
|
||||||
|
code += '\x07';
|
||||||
|
break;
|
||||||
|
case 'H':
|
||||||
|
code += '\x08';
|
||||||
|
break;
|
||||||
|
case 'I':
|
||||||
|
code += '\x09'; // \t
|
||||||
|
break;
|
||||||
|
case 'J':
|
||||||
|
code += '\x0a'; // \n
|
||||||
|
break;
|
||||||
|
case 'K':
|
||||||
|
code += '\x0b';
|
||||||
|
break;
|
||||||
|
case 'L':
|
||||||
|
code += '\x0c';
|
||||||
|
break;
|
||||||
|
case 'M':
|
||||||
|
code += '\x0d';
|
||||||
|
break;
|
||||||
|
case 'N':
|
||||||
|
code += '\x0e';
|
||||||
|
break;
|
||||||
|
case 'O':
|
||||||
|
code += '\x0f';
|
||||||
|
break;
|
||||||
|
case 'P':
|
||||||
|
code += '\x10';
|
||||||
|
break;
|
||||||
|
case 'Q':
|
||||||
|
code += '\x11';
|
||||||
|
break;
|
||||||
|
case 'R':
|
||||||
|
code += '\x12';
|
||||||
|
break;
|
||||||
|
case 'S':
|
||||||
|
code += '\x13';
|
||||||
|
break;
|
||||||
|
case 'T':
|
||||||
|
code += '\x14';
|
||||||
|
break;
|
||||||
|
case 'U':
|
||||||
|
code += '\x15';
|
||||||
|
break;
|
||||||
|
case 'V':
|
||||||
|
code += '\x16';
|
||||||
|
break;
|
||||||
|
case 'W':
|
||||||
|
code += '\x17';
|
||||||
|
break;
|
||||||
|
case 'X':
|
||||||
|
code += '\x18';
|
||||||
|
break;
|
||||||
|
case 'Y':
|
||||||
|
code += '\x19';
|
||||||
|
break;
|
||||||
|
case 'Z':
|
||||||
|
code += '\x1a';
|
||||||
|
break;
|
||||||
|
case '\\':
|
||||||
|
code += '\x1c';
|
||||||
|
break;
|
||||||
|
case '^':
|
||||||
|
code += '\x1e';
|
||||||
|
break;
|
||||||
|
case '_':
|
||||||
|
code += '\x1f';
|
||||||
|
break;
|
||||||
|
case '[':
|
||||||
|
code += '\x1b';
|
||||||
|
break;
|
||||||
|
case ']':
|
||||||
|
code += '\x1d';
|
||||||
|
break;
|
||||||
|
case '?':
|
||||||
|
code += '\x7f';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// '\n' -> \n
|
||||||
|
// '\r' -> \r
|
||||||
|
// '\0' -> \200 (special case)
|
||||||
|
if (cap = /^\\([nlrtbfs\^\\,:0])/g.exec(val)) {
|
||||||
|
val = val.substring(cap[0].length);
|
||||||
|
ch = cap[1];
|
||||||
|
switch (ch) {
|
||||||
|
case 'n':
|
||||||
|
return '\n';
|
||||||
|
case 'l':
|
||||||
|
return '\l';
|
||||||
|
case 'r':
|
||||||
|
return '\r';
|
||||||
|
case 't':
|
||||||
|
return '\t';
|
||||||
|
case 'b':
|
||||||
|
return '\b';
|
||||||
|
case 'f':
|
||||||
|
return '\f';
|
||||||
|
case 's':
|
||||||
|
return '\s';
|
||||||
|
case '\\':
|
||||||
|
return '\\';
|
||||||
|
case ',':
|
||||||
|
return ',';
|
||||||
|
case ';':
|
||||||
|
return ';';
|
||||||
|
case '0':
|
||||||
|
//return '\0';
|
||||||
|
return '\200';
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3 octal digits -> character
|
||||||
|
if (cap = /^\\(\d\d\d)/g.exec(val)) {
|
||||||
|
val = val.substring(cap[0].length);
|
||||||
|
ch = cap[1];
|
||||||
|
code += String.fromCharCode(parseInt(ch, 8));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// $<5> -> padding
|
||||||
|
if (cap = /^\$<(\d+)>(\*|\/)/g.exec(val)) {
|
||||||
|
val = val.substring(cap[0].length);
|
||||||
|
ch = cap[1];
|
||||||
|
code += Array(+ch + 1).join(' '); // "padding" characters?
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// man terminfo, around page 1034
|
||||||
|
// %% outputs `%'
|
||||||
|
if (cap = /^%%/g.exec(val)) {
|
||||||
|
val = val.substring(cap[0].length);
|
||||||
|
code += '%';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// %[[:]flags][width[.precision]][doxXs]
|
||||||
|
// as in printf, flags are [-+#] and space. Use a `:' to allow the
|
||||||
|
// next character to be a `-' flag, avoiding interpreting "%-" as an
|
||||||
|
// operator.
|
||||||
|
if (cap = /^%(?:(:)?([\-+# ]+)?)(?:(\d+)(\.\d+)?)?([doxXs])?/g.exec(val)) {
|
||||||
|
val = val.substring(cap[0].length);
|
||||||
|
code += 'TODO';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// %c print pop() like %c in printf
|
||||||
|
if (cap = /^%c/g.exec(val)) {
|
||||||
|
val = val.substring(cap[0].length);
|
||||||
|
code += 'stack.pop()'; // TODO: FORMAT
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// %d print pop() like %d in printf
|
||||||
|
// NOT SURE ABOUT %d being print!
|
||||||
|
if (cap = /^%d/g.exec(val)) {
|
||||||
|
val = val.substring(cap[0].length);
|
||||||
|
code += 'stack.pop()'; // TODO: FORMAT
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// %s print pop() like %s in printf
|
||||||
|
if (cap = /^%s/g.exec(val)) {
|
||||||
|
val = val.substring(cap[0].length);
|
||||||
|
code += 'stack.pop()'; // TODO: FORMAT
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// %p[1-9]
|
||||||
|
// push i'th parameter
|
||||||
|
if (cap = /^%p([1-9])/g.exec(val)) {
|
||||||
|
val = val.substring(cap[0].length);
|
||||||
|
code += 'params[i]';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// %P[a-z]
|
||||||
|
// set dynamic variable [a-z] to pop()
|
||||||
|
if (cap = /^%P([a-z])/g.exec(val)) {
|
||||||
|
val = val.substring(cap[0].length);
|
||||||
|
v = cap[1];
|
||||||
|
code += 'dyn.' + v + ' = stack.pop()';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// %g[a-z]
|
||||||
|
// get dynamic variable [a-z] and push it
|
||||||
|
if (cap = /^%g([a-z])/g.exec(val)) {
|
||||||
|
val = val.substring(cap[0].length);
|
||||||
|
v = cap[1];
|
||||||
|
code += '(stack.push(dyn.' + v + '), dyn.' + v + ')';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// %P[A-Z]
|
||||||
|
// set static variable [a-z] to pop()
|
||||||
|
if (cap = /^%P([A-Z])/g.exec(val)) {
|
||||||
|
val = val.substring(cap[0].length);
|
||||||
|
v = cap[1];
|
||||||
|
code += 'stat.' + v + ' = stack.pop()';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// %g[A-Z]
|
||||||
|
// get static variable [a-z] and push it
|
||||||
|
|
||||||
|
// The terms "static" and "dynamic" are misleading. Historically,
|
||||||
|
// these are simply two different sets of variables, whose values are
|
||||||
|
// not reset between calls to tparm. However, that fact is not
|
||||||
|
// documented in other implementations. Relying on it will adversely
|
||||||
|
// impact portability to other implementations.
|
||||||
|
|
||||||
|
if (cap = /^%g([A-Z])/g.exec(val)) {
|
||||||
|
val = val.substring(cap[0].length);
|
||||||
|
v = cap[1];
|
||||||
|
code += 'stack.push(stat.' + v + ')';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// %'c' char constant c
|
||||||
|
if (cap = /^%'(\w)'/g.exec(val)) {
|
||||||
|
val = val.substring(cap[0].length);
|
||||||
|
ch = cap[1];
|
||||||
|
code += '"' + ch + '"';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// %{nn}
|
||||||
|
// integer constant nn
|
||||||
|
if (cap = /^%\{(\d+)\}/g.exec(val)) {
|
||||||
|
val = val.substring(cap[0].length);
|
||||||
|
ch = cap[1];
|
||||||
|
code += '(' + ch + ')';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// %l push strlen(pop)
|
||||||
|
if (cap = /^%l/g.exec(val)) {
|
||||||
|
val = val.substring(cap[0].length);
|
||||||
|
code += 'stack.push(stack.pop().length)';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// %+ %- %* %/ %m
|
||||||
|
// arithmetic (%m is mod): push(pop() op pop())
|
||||||
|
// %& %| %^
|
||||||
|
// bit operations (AND, OR and exclusive-OR): push(pop() op pop())
|
||||||
|
// %= %> %<
|
||||||
|
// logical operations: push(pop() op pop())
|
||||||
|
if (cap = /^%([+\-*\/m&|\^=><])/g.exec(val)) {
|
||||||
|
val = val.substring(cap[0].length);
|
||||||
|
op = cap[1];
|
||||||
|
if (op === '=') op = '===';
|
||||||
|
else if (op === 'm') op = '%';
|
||||||
|
code += 'stack.push(stack.pop() ' + op + ' stack.pop())';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// %A, %O
|
||||||
|
// logical AND and OR operations (for conditionals)
|
||||||
|
if (cap = /^%([AO])/g.exec(val)) {
|
||||||
|
val = val.substring(cap[0].length);
|
||||||
|
op = cap[1];
|
||||||
|
code += op === ' A ' ? ' && ' : ' || ';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// %! %~
|
||||||
|
// unary operations (logical and bit complement): push(op pop())
|
||||||
|
if (cap = /^%([!~])/g.exec(val)) {
|
||||||
|
val = val.substring(cap[0].length);
|
||||||
|
op = cap[1];
|
||||||
|
code += 'stack.push(' + op + 'stack.pop())';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// %i add 1 to first two parameters (for ANSI terminals)
|
||||||
|
if (cap = /^%i/g.exec(val)) {
|
||||||
|
val = val.substring(cap[0].length);
|
||||||
|
code += '(params[0]++, params[1]++)';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// %? expr %t thenpart %e elsepart %;
|
||||||
|
// This forms an if-then-else. The %e elsepart is optional. Usually
|
||||||
|
// the %? expr part pushes a value onto the stack, and %t pops it from
|
||||||
|
// the stack, testing if it is nonzero (true). If it is zero (false),
|
||||||
|
// control passes to the %e (else) part.
|
||||||
|
|
||||||
|
// It is possible to form else-if's a la Algol 68:
|
||||||
|
// %? c1 %t b1 %e c2 %t b2 %e c3 %t b3 %e c4 %t b4 %e %;
|
||||||
|
|
||||||
|
// where ci are conditions, bi are bodies.
|
||||||
|
|
||||||
|
// Use the -f option of tic or infocmp to see the structure of
|
||||||
|
// if-then-else's. Some strings, e.g., sgr can be very complicated when
|
||||||
|
// written on one line. The -f option splits the string into lines with
|
||||||
|
// the parts indented.
|
||||||
|
if (cap = /^%\?/g.exec(val)) {
|
||||||
|
val = val.substring(cap[0].length);
|
||||||
|
code += '"); if (';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cap = /^%t/g.exec(val)) {
|
||||||
|
val = val.substring(cap[0].length);
|
||||||
|
code += ') { out.push("';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cap = /^%e/g.exec(val)) {
|
||||||
|
val = val.substring(cap[0].length);
|
||||||
|
code += '"); } else { out.push("';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cap = /^%;/g.exec(val)) {
|
||||||
|
val = val.substring(cap[0].length);
|
||||||
|
code += '"); } out.push("';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Binary operations are in postfix form with the operands in the usual
|
||||||
|
// order. That is, to get x-5 one would use "%gx%{5}%-". %P and %g vari‐
|
||||||
|
// ables are persistent across escape-string evaluations.
|
||||||
|
|
||||||
|
// Consider the HP2645, which, to get to row 3 and column 12, needs to be
|
||||||
|
// sent \E&a12c03Y padded for 6 milliseconds. Note that the order of the
|
||||||
|
// rows and columns is inverted here, and that the row and column are
|
||||||
|
// printed as two digits. Thus its cup capability is
|
||||||
|
// “cup=6\E&%p2%2dc%p1%2dY”.
|
||||||
|
|
||||||
|
// The Microterm ACT-IV needs the current row and column sent
|
||||||
|
// preceded by a ^T, with the row and column simply encoded in
|
||||||
|
// binary, “cup=^T%p1%c%p2%c”. Terminals which use “%c” need to be able
|
||||||
|
// to backspace the cursor (cub1), and to move the cursor up one line
|
||||||
|
// on the screen (cuu1). This is necessary because it is not always safe
|
||||||
|
// to transmit \n ^D and \r, as the system may change or discard them.
|
||||||
|
// (The library routines dealing with terminfo set tty modes so that tabs
|
||||||
|
// are never expanded, so \t is safe to send. This turns out to be
|
||||||
|
// essential for the Ann Arbor 4080.)
|
||||||
|
|
||||||
|
// A final example is the LSI ADM-3a, which uses row and column offset
|
||||||
|
// by a blank character, thus “cup=\E=%p1%' '%+%c%p2%' '%+%c”. After
|
||||||
|
// sending `\E=', this pushes the first parameter, pushes the ASCII value
|
||||||
|
// for a space (32), adds them (pushing the sum on the stack in place of
|
||||||
|
// the two previous values) and outputs that value as a character.
|
||||||
|
// Then the same is done for the second parameter. More complex
|
||||||
|
// arithmetic is possible using the stack.
|
||||||
|
|
||||||
|
code += val[0];
|
||||||
|
val = val.substring(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
code += '"); return out.join("");';
|
||||||
|
|
||||||
|
return new Function('params', code);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Return alias if one exists.
|
// Return alias if one exists.
|
||||||
|
|
Loading…
Reference in New Issue