summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/asmjit/tools/generator-cxx.js
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/asmjit/tools/generator-cxx.js')
-rw-r--r--3rdparty/asmjit/tools/generator-cxx.js270
1 files changed, 270 insertions, 0 deletions
diff --git a/3rdparty/asmjit/tools/generator-cxx.js b/3rdparty/asmjit/tools/generator-cxx.js
new file mode 100644
index 00000000000..b1b1d946cae
--- /dev/null
+++ b/3rdparty/asmjit/tools/generator-cxx.js
@@ -0,0 +1,270 @@
+// This file is part of AsmJit project <https://asmjit.com>
+//
+// See asmjit.h or LICENSE.md for license and copyright information
+// SPDX-License-Identifier: Zlib
+
+// C++ code generation helpers.
+const commons = require("./generator-commons.js");
+const FATAL = commons.FATAL;
+
+// Utilities to convert primitives to C++ code.
+class Utils {
+ static toHex(val, pad) {
+ if (val < 0)
+ val = 0xFFFFFFFF + val + 1;
+
+ let s = val.toString(16);
+ if (pad != null && s.length < pad)
+ s = "0".repeat(pad - s.length) + s;
+
+ return "0x" + s.toUpperCase();
+ }
+
+ static capitalize(s) {
+ s = String(s);
+ return !s ? s : s[0].toUpperCase() + s.substr(1);
+ }
+
+ static camelCase(s) {
+ if (s == null || s === "")
+ return s;
+
+ s = String(s);
+ if (/^[A-Z]+$/.test(s))
+ return s.toLowerCase();
+ else
+ return s[0].toLowerCase() + s.substr(1);
+ }
+
+ static normalizeSymbolName(s) {
+ switch (s) {
+ case "and":
+ case "or":
+ case "xor":
+ return s + "_";
+ default:
+ return s;
+ }
+ }
+
+ static indent(s, indentation) {
+ if (typeof indentation === "number")
+ indentation = " ".repeat(indentation);
+
+ var lines = s.split(/\r?\n/g);
+ if (indentation) {
+ for (var i = 0; i < lines.length; i++) {
+ var line = lines[i];
+ if (line)
+ lines[i] = indentation + line;
+ }
+ }
+
+ return lines.join("\n");
+ }
+}
+exports.Utils = Utils;
+
+// A node that represents a C++ construct.
+class Node {
+ constructor(kind) {
+ this.kind = kind;
+ }
+};
+exports.Node = Node;
+
+// A single line of C++ code that declares a variable with optional initialization.
+class Var extends Node {
+ constructor(type, name, init) {
+ super("var");
+
+ this.type = type;
+ this.name = name;
+ this.init = init || "";
+ }
+
+ toString() {
+ let s = this.type + " " + this.name;
+ if (this.init)
+ s += " = " + this.init;
+ return s + ";\n";
+ }
+};
+exports.Var = Var;
+
+// A single line of C++ code, which should not contain any branch or a variable declaration.
+class Line extends Node {
+ constructor(code) {
+ super("line");
+
+ this.code = code;
+ }
+
+ toString() {
+ return String(this.code) + "\n";
+ }
+};
+exports.Line = Line;
+
+// A block containing an array of `Node` items (may contain nested blocks, etc...).
+class Block extends Node {
+ constructor(nodes) {
+ super("block");
+
+ this.nodes = nodes || [];
+ }
+
+ isEmpty() {
+ return this.nodes.length === 0;
+ }
+
+ appendNode(node) {
+ if (!(node instanceof Node))
+ FATAL("Block.appendNode(): Node must be an instance of Node");
+
+ this.nodes.push(node);
+ return this;
+ }
+
+ prependNode(node) {
+ if (!(node instanceof Node))
+ FATAL("Block.prependNode(): Node must be an instance of Node");
+
+ this.nodes.unshift(node);
+ return this;
+ }
+
+ insertNode(index, node) {
+ if (!(node instanceof Node))
+ FATAL("Block.insertNode(): Node must be an instance of Node");
+
+ if (index >= this.nodes.length)
+ this.nodes.push(node);
+ else
+ this.nodes.splice(index, 0, node);
+
+ return this;
+ }
+
+ addVarDecl(type, name, init) {
+ let node = type;
+
+ if (!(node instanceof Var))
+ node = new Var(type, name, init);
+
+ let i = 0;
+ while (i < this.nodes.length) {
+ const n = this.nodes[i];
+ if (n.kind === "var" && n.name === node.name && n.init === node.init)
+ return this;
+
+ if (n.kind !== "var")
+ break;
+
+ i++;
+ }
+
+ this.insertNode(i, node);
+ return this;
+ }
+
+ addLine(code) {
+ if (typeof code !== "string")
+ FATAL("Block.addLine(): Line must be string");
+
+ this.nodes.push(new Line(code));
+ return this;
+ }
+
+ prependEmptyLine() {
+ if (!this.isEmpty())
+ this.nodes.splice(0, 0, new Line(""));
+ return this;
+ }
+
+ addEmptyLine() {
+ if (!this.isEmpty())
+ this.nodes.push(new Line(""));
+ return this;
+ }
+
+ toString() {
+ let s = "";
+ for (let node of this.nodes)
+ s += String(node);
+ return s;
+ }
+}
+exports.Block = Block;
+
+// A C++ 'condition' (if statement) and its 'body' if it's taken.
+class If extends Node {
+ constructor(cond, body) {
+ super("if");
+
+ if (body == null)
+ body = new Block();
+
+ if (!(body instanceof Block))
+ FATAL("If() - body must be a Block");
+
+ this.cond = cond;
+ this.body = body;
+ }
+
+ toString() {
+ const cond = String(this.cond);
+ const body = String(this.body);
+
+ return `if (${cond}) {\n` + Utils.indent(body, 2) + `}\n`;
+ }
+}
+exports.If = If;
+
+//! A C++ switch statement.
+class Case extends Node {
+ constructor(cond, body) {
+ super("case");
+
+ this.cond = cond;
+ this.body = body || new Block();
+ }
+
+ toString() {
+ let s = "";
+ for (let node of this.body.nodes)
+ s += String(node)
+
+ if (this.cond !== "default")
+ return `case ${this.cond}: {\n` + Utils.indent(s, 2) + `}\n`;
+ else
+ return `default: {\n` + Utils.indent(s, 2) + `}\n`;
+ }
+};
+exports.Case = Case;
+
+class Switch extends Node {
+ constructor(expression, cases) {
+ super("switch");
+
+ this.expression = expression;
+ this.cases = cases || [];
+ }
+
+ addCase(cond, body) {
+ this.cases.push(new Case(cond, body));
+ return this;
+ }
+
+ toString() {
+ let s = "";
+ for (let c of this.cases) {
+ if (s)
+ s += "\n";
+ s += String(c);
+ }
+
+ return `switch (${this.expression}) {\n` + Utils.indent(s, 2) + `}\n`;
+ }
+}
+exports.Switch = Switch;