odin-blend2d

Odin bindings to Blend2D
Log | Files | Refs | README | LICENSE

generator-cxx.js (5535B)


      1 // This file is part of AsmJit project <https://asmjit.com>
      2 //
      3 // See <asmjit/core.h> or LICENSE.md for license and copyright information
      4 // SPDX-License-Identifier: Zlib
      5 
      6 // C++ code generation helpers.
      7 const commons = require("./generator-commons.js");
      8 const FATAL = commons.FATAL;
      9 
     10 // Utilities to convert primitives to C++ code.
     11 class Utils {
     12   static toHexRaw(val, pad) {
     13     if (val < 0)
     14       val = 0xFFFFFFFF + val + 1;
     15 
     16     let s = val.toString(16);
     17     if (pad != null && s.length < pad)
     18       s = "0".repeat(pad - s.length) + s;
     19 
     20     return s.toUpperCase();
     21   }
     22 
     23   static toHex(val, pad) {
     24     return "0x" + Utils.toHexRaw(val, pad);
     25   }
     26 
     27   static capitalize(s) {
     28     s = String(s);
     29     return !s ? s : s[0].toUpperCase() + s.substr(1);
     30   }
     31 
     32   static camelCase(s) {
     33     if (s == null || s === "")
     34       return s;
     35 
     36     s = String(s);
     37     if (/^[A-Z]+$/.test(s))
     38       return s.toLowerCase();
     39     else
     40       return s[0].toLowerCase() + s.substr(1);
     41   }
     42 
     43   static normalizeSymbolName(s) {
     44     switch (s) {
     45       case "and":
     46       case "or":
     47       case "xor":
     48         return s + "_";
     49       default:
     50         return s;
     51     }
     52   }
     53 
     54   static indent(s, indentation) {
     55     if (typeof indentation === "number")
     56       indentation = " ".repeat(indentation);
     57 
     58     var lines = s.split(/\r?\n/g);
     59     if (indentation) {
     60       for (var i = 0; i < lines.length; i++) {
     61         var line = lines[i];
     62         if (line)
     63           lines[i] = indentation + line;
     64       }
     65     }
     66 
     67     return lines.join("\n");
     68   }
     69 }
     70 exports.Utils = Utils;
     71 
     72 // A node that represents a C++ construct.
     73 class Node {
     74   constructor(kind) {
     75     this.kind = kind;
     76   }
     77 };
     78 exports.Node = Node;
     79 
     80 // A single line of C++ code that declares a variable with optional initialization.
     81 class Var extends Node {
     82   constructor(type, name, init) {
     83     super("var");
     84 
     85     this.type = type;
     86     this.name = name;
     87     this.init = init || "";
     88   }
     89 
     90   toString() {
     91     let s = this.type + " " + this.name;
     92     if (this.init)
     93       s += " = " + this.init;
     94     return s + ";\n";
     95   }
     96 };
     97 exports.Var = Var;
     98 
     99 // A single line of C++ code, which should not contain any branch or a variable declaration.
    100 class Line extends Node {
    101   constructor(code) {
    102     super("line");
    103 
    104     this.code = code;
    105   }
    106 
    107   toString() {
    108     return String(this.code) + "\n";
    109   }
    110 };
    111 exports.Line = Line;
    112 
    113 // A block containing an array of `Node` items (may contain nested blocks, etc...).
    114 class Block extends Node {
    115   constructor(nodes) {
    116     super("block");
    117 
    118     this.nodes = nodes || [];
    119   }
    120 
    121   isEmpty() {
    122     return this.nodes.length === 0;
    123   }
    124 
    125   appendNode(node) {
    126     if (!(node instanceof Node))
    127       FATAL("Block.appendNode(): Node must be an instance of Node");
    128 
    129     this.nodes.push(node);
    130     return this;
    131   }
    132 
    133   prependNode(node) {
    134     if (!(node instanceof Node))
    135       FATAL("Block.prependNode(): Node must be an instance of Node");
    136 
    137     this.nodes.unshift(node);
    138     return this;
    139   }
    140 
    141   insertNode(index, node) {
    142     if (!(node instanceof Node))
    143       FATAL("Block.insertNode(): Node must be an instance of Node");
    144 
    145     if (index >= this.nodes.length)
    146       this.nodes.push(node);
    147     else
    148       this.nodes.splice(index, 0, node);
    149 
    150     return this;
    151   }
    152 
    153   addVarDecl(type, name, init) {
    154     let node = type;
    155 
    156     if (!(node instanceof Var))
    157       node = new Var(type, name, init);
    158 
    159     let i = 0;
    160     while (i < this.nodes.length) {
    161       const n = this.nodes[i];
    162       if (n.kind === "var" && n.name === node.name && n.init === node.init)
    163         return this;
    164 
    165       if (n.kind !== "var")
    166         break;
    167 
    168       i++;
    169     }
    170 
    171     this.insertNode(i, node);
    172     return this;
    173   }
    174 
    175   addLine(code) {
    176     if (typeof code !== "string")
    177       FATAL("Block.addLine(): Line must be string");
    178 
    179     this.nodes.push(new Line(code));
    180     return this;
    181   }
    182 
    183   prependEmptyLine() {
    184     if (!this.isEmpty())
    185       this.nodes.splice(0, 0, new Line(""));
    186     return this;
    187   }
    188 
    189   addEmptyLine() {
    190     if (!this.isEmpty())
    191       this.nodes.push(new Line(""));
    192     return this;
    193   }
    194 
    195   toString() {
    196     let s = "";
    197     for (let node of this.nodes)
    198       s += String(node);
    199     return s;
    200   }
    201 }
    202 exports.Block = Block;
    203 
    204 // A C++ 'condition' (if statement) and its 'body' if it's taken.
    205 class If extends Node {
    206   constructor(cond, body) {
    207     super("if");
    208 
    209     if (body == null)
    210       body = new Block();
    211 
    212     if (!(body instanceof Block))
    213       FATAL("If() - body must be a Block");
    214 
    215     this.cond = cond;
    216     this.body = body;
    217   }
    218 
    219   toString() {
    220     const cond = String(this.cond);
    221     const body = String(this.body);
    222 
    223     return `if (${cond}) {\n` + Utils.indent(body, 2) + `}\n`;
    224   }
    225 }
    226 exports.If = If;
    227 
    228 //! A C++ switch statement.
    229 class Case extends Node {
    230   constructor(cond, body) {
    231     super("case");
    232 
    233     this.cond = cond;
    234     this.body = body || new Block();
    235   }
    236 
    237   toString() {
    238     let s = "";
    239     for (let node of this.body.nodes)
    240       s += String(node)
    241 
    242     if (this.cond !== "default")
    243       return `case ${this.cond}: {\n` + Utils.indent(s, 2) + `}\n`;
    244     else
    245       return `default: {\n` + Utils.indent(s, 2) + `}\n`;
    246   }
    247 };
    248 exports.Case = Case;
    249 
    250 class Switch extends Node {
    251   constructor(expression, cases) {
    252     super("switch");
    253 
    254     this.expression = expression;
    255     this.cases = cases || [];
    256   }
    257 
    258   addCase(cond, body) {
    259     this.cases.push(new Case(cond, body));
    260     return this;
    261   }
    262 
    263   toString() {
    264     let s = "";
    265     for (let c of this.cases) {
    266       if (s)
    267         s += "\n";
    268       s += String(c);
    269     }
    270 
    271     return `switch (${this.expression}) {\n` + Utils.indent(s, 2) + `}\n`;
    272   }
    273 }
    274 exports.Switch = Switch;