Codegen.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.Codegen = exports.CodegenStepExecJs = void 0;
  4. const _1 = require(".");
  5. class CodegenStepExecJs {
  6. constructor(js) {
  7. this.js = js;
  8. }
  9. }
  10. exports.CodegenStepExecJs = CodegenStepExecJs;
  11. class Codegen {
  12. constructor(opts) {
  13. this.steps = [];
  14. this.dependencies = [];
  15. this.dependencyNames = [];
  16. this.linked = {};
  17. this.constants = [];
  18. this.constantNames = [];
  19. this.options = {
  20. args: ['r0'],
  21. name: '',
  22. prologue: '',
  23. epilogue: '',
  24. processSteps: (steps) => steps.filter((step) => step instanceof CodegenStepExecJs),
  25. linkable: {},
  26. ...opts,
  27. };
  28. this.registerCounter = this.options.args.length;
  29. }
  30. js(js) {
  31. this.steps.push(new CodegenStepExecJs(js));
  32. }
  33. var(expression) {
  34. const r = this.getRegister();
  35. if (expression)
  36. this.js('var ' + r + ' = ' + expression + ';');
  37. else
  38. this.js('var ' + r + ';');
  39. return r;
  40. }
  41. if(condition, then, otherwise) {
  42. this.js('if (' + condition + ') {');
  43. then();
  44. if (otherwise) {
  45. this.js('} else {');
  46. otherwise();
  47. }
  48. this.js('}');
  49. }
  50. while(condition, block) {
  51. this.js('while (' + condition + ') {');
  52. block();
  53. this.js('}');
  54. }
  55. doWhile(block, condition) {
  56. this.js('do {');
  57. block();
  58. this.js('} while (' + condition + ');');
  59. }
  60. switch(expression, cases, def) {
  61. this.js('switch (' + expression + ') {');
  62. for (const [match, block, noBreak] of cases) {
  63. this.js('case ' + match + ': {');
  64. block();
  65. if (!noBreak)
  66. this.js('break;');
  67. this.js('}');
  68. }
  69. if (def) {
  70. this.js('default: {');
  71. def();
  72. this.js('}');
  73. }
  74. this.js('}');
  75. }
  76. return(expression) {
  77. this.js('return ' + expression + ';');
  78. }
  79. step(step) {
  80. this.steps.push(step);
  81. }
  82. getRegister() {
  83. return `r${this.registerCounter++}`;
  84. }
  85. r() {
  86. return this.getRegister();
  87. }
  88. linkDependency(dep, name = 'd' + this.dependencies.length) {
  89. this.dependencies.push(dep);
  90. this.dependencyNames.push(name);
  91. return name;
  92. }
  93. linkDependencies(deps) {
  94. return deps.map((dep) => this.linkDependency(dep));
  95. }
  96. link(name) {
  97. if (this.linked[name])
  98. return;
  99. this.linked[name] = 1;
  100. this.linkDependency(this.options.linkable[name], name);
  101. }
  102. addConstant(constant, name = 'c' + this.constants.length) {
  103. this.constants.push(constant);
  104. this.constantNames.push(name);
  105. return name;
  106. }
  107. addConstants(constants) {
  108. return constants.map((constant) => this.addConstant(constant));
  109. }
  110. generate(opts = {}) {
  111. const { name, args, prologue, epilogue } = { ...this.options, ...opts };
  112. const steps = this.options.processSteps(this.steps);
  113. const js = `(function(${this.dependencyNames.join(', ')}) {
  114. ${this.constants.map((constant, index) => `var ${this.constantNames[index]} = (${constant});`).join('\n')}
  115. return ${name ? `function ${name}` : 'function'}(${args.join(',')}){
  116. ${prologue}
  117. ${steps.map((step) => step.js).join('\n')}
  118. ${typeof epilogue === 'function' ? epilogue() : epilogue || ''}
  119. }})`;
  120. return {
  121. deps: this.dependencies,
  122. js: js,
  123. };
  124. }
  125. compile(opts) {
  126. const closure = this.generate(opts);
  127. return (0, _1.compileClosure)(closure);
  128. }
  129. }
  130. exports.Codegen = Codegen;
  131. //# sourceMappingURL=Codegen.js.map