diff options
Diffstat (limited to '3rdparty/asmjit/tools/generator-cxx.js')
-rw-r--r-- | 3rdparty/asmjit/tools/generator-cxx.js | 270 |
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; |