46 lines
1.6 KiB
JavaScript
46 lines
1.6 KiB
JavaScript
// @flow
|
|
import defineFunction from "../defineFunction";
|
|
import ParseError from "../ParseError";
|
|
import {assertNodeType} from "../parseNode";
|
|
|
|
// \@char is an internal function that takes a grouped decimal argument like
|
|
// {123} and converts into symbol with code 123. It is used by the *macro*
|
|
// \char defined in macros.js.
|
|
defineFunction({
|
|
type: "textord",
|
|
names: ["\\@char"],
|
|
props: {
|
|
numArgs: 1,
|
|
allowedInText: true,
|
|
},
|
|
handler({parser}, args) {
|
|
const arg = assertNodeType(args[0], "ordgroup");
|
|
const group = arg.body;
|
|
let number = "";
|
|
for (let i = 0; i < group.length; i++) {
|
|
const node = assertNodeType(group[i], "textord");
|
|
number += node.text;
|
|
}
|
|
let code = parseInt(number);
|
|
let text;
|
|
if (isNaN(code)) {
|
|
throw new ParseError(`\\@char has non-numeric argument ${number}`);
|
|
// If we drop IE support, the following code could be replaced with
|
|
// text = String.fromCodePoint(code)
|
|
} else if (code < 0 || code >= 0x10ffff) {
|
|
throw new ParseError(`\\@char with invalid code point ${number}`);
|
|
} else if (code <= 0xffff) {
|
|
text = String.fromCharCode(code);
|
|
} else { // Astral code point; split into surrogate halves
|
|
code -= 0x10000;
|
|
text = String.fromCharCode((code >> 10) + 0xd800,
|
|
(code & 0x3ff) + 0xdc00);
|
|
}
|
|
return {
|
|
type: "textord",
|
|
mode: parser.mode,
|
|
text: text,
|
|
};
|
|
},
|
|
});
|