Advertisement
Guest User

Untitled

a guest
Oct 7th, 2015
96
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.81 KB | None | 0 0
  1. const enum Op {
  2. IF,
  3. MUL, DIV, MOD, ADD, MIN,
  4. EQ, NE, GT, LT, GE, LE, IN,
  5. AND, OR,
  6. IMM,
  7. UNARY_MIN, NOT,
  8. MAKE_EMPTY_LIST,
  9. MAKE_SINGLETON_LIST,
  10. LIST_APPEND,
  11. LIST_ADD_TAIL,
  12. RET,
  13. RET0,
  14. JUMP,
  15. CALL_BI,
  16. CALL_VERB,
  17. FORK,
  18. FORK_WITH_ID,
  19. SUSPEND,
  20. EXTENDED,
  21. POP,
  22. tinyIntStart,
  23. lastOpCode = 255
  24. }
  25.  
  26. const tinyIntLow = -10;
  27. const tinyIntHi = Op.lastOpCode - Op.tinyIntStart + tinyIntLow;
  28.  
  29. function isTinyIntOpCode(op: Op): boolean {
  30. return op >= Op.tinyIntStart;
  31. }
  32.  
  33. function opCodeToTinyInt(op: Op): number {
  34. return op - Op.tinyIntStart + tinyIntLow;
  35. }
  36.  
  37. function tinyIntToOpCode(i: number): Op {
  38. return Op.tinyIntStart + i - tinyIntLow;
  39. }
  40.  
  41. function inTinyIntRange(i: number): boolean {
  42. return i >= tinyIntLow && i <= tinyIntHi;
  43. }
  44.  
  45. interface Program {
  46. main: Buffer;
  47. forks: Buffer[];
  48. literals: any[];
  49. }
  50.  
  51. class Frame {
  52. program: Program;
  53. caller: Frame;
  54. vp: number;
  55.  
  56. stack = [];
  57. ip = 0;
  58. env = {};
  59.  
  60. constructor(program: Program, caller: Frame = null, vp = -1) {
  61. this.program = program;
  62. this.caller = caller;
  63. this.vp = vp;
  64. }
  65. }
  66.  
  67. class DelayedFrame {
  68. frame: Frame;
  69. delay: number;
  70.  
  71. constructor(frame: Frame, delay: number) {
  72. this.frame = frame;
  73. this.delay = delay;
  74. }
  75. }
  76.  
  77. function toInt(bytes: Buffer): number {
  78. var n = 0;
  79. var len = bytes.length;
  80. for (var i = 0; i < len; i++) {
  81. var shift = (len - i - 1) * 8;
  82. n += bytes[i] * (1 << shift);
  83. }
  84.  
  85. return n;
  86. }
  87.  
  88. class VM {
  89. private objects: (id: number) => any;
  90.  
  91. constructor(objects: (id: number) => any) {
  92. this.objects = objects;
  93. }
  94.  
  95. run(f: Frame): [any, DelayedFrame[]] {
  96. let top = f;
  97. while (top) {
  98. let [r, cont, delayed] = this.exec(top);
  99. if (cont) {
  100. top = cont;
  101. top.stack.push(r);
  102. }
  103. else {
  104. return [r, delayed];
  105. }
  106. }
  107. }
  108.  
  109. exec(f: Frame): [any, Frame, DelayedFrame[]] {
  110. var y, x, z, r, s, d, t;
  111. let forks = [];
  112. let code = f.vp == -1 ? f.program.main : f.program.forks[f.vp];
  113. while(f.ip < code.length) {
  114. let op = code[f.ip];
  115. switch(op) {
  116. case Op.ADD:
  117. y = f.stack.pop();
  118. x = f.stack.pop();
  119. r = x + y;
  120. f.stack.push(r);
  121. break;
  122. case Op.MIN:
  123. y = f.stack.pop();
  124. x = f.stack.pop();
  125. r = x - y;
  126. f.stack.push(r);
  127. break;
  128. case Op.MUL:
  129. y = f.stack.pop();
  130. x = f.stack.pop();
  131. r = x * y;
  132. f.stack.push(r);
  133. break;
  134. case Op.DIV:
  135. y = f.stack.pop();
  136. x = f.stack.pop();
  137. r = x / y;
  138. f.stack.push(r);
  139. break;
  140. case Op.MOD:
  141. y = f.stack.pop();
  142. x = f.stack.pop();
  143. r = x % y;
  144. f.stack.push(r);
  145. break;
  146. case Op.IN:
  147. y = f.stack.pop();
  148. x = f.stack.pop();
  149. r = y.includes(x);
  150. f.stack.push(r);
  151. break;
  152. case Op.IF:
  153. x = f.stack.pop(); // cond
  154. break;
  155. case Op.IMM:
  156. s = code[f.ip];
  157. r = f.program.literals[s];
  158. f.stack.push(r);
  159. break;
  160. case Op.CALL_BI:
  161. y = f.stack.pop(); // args
  162. x = f.stack.pop(); // fname
  163. // We can't call verbs from inside builtin functions so
  164. // we can just execute this inline, push the result to
  165. // the current stack and continue.
  166. r = this[x](y);
  167. f.stack.push(r);
  168. break;
  169. case Op.CALL_VERB:
  170. z = f.stack.pop(); // args
  171. y = f.stack.pop(); // vname
  172. x = f.stack.pop(); // objid
  173. let id = +(x.substring(1));
  174. let obj = this.objects(id);
  175. let prog = obj[y];
  176. let cont = new Frame(prog, f);
  177. return [0, cont, forks];
  178. case Op.FORK:
  179. y = f.stack.pop(); // delay
  180. x = f.stack.pop(); // index
  181. t = new Frame(f.program, null, x);
  182. d = new DelayedFrame(t, y);
  183. forks.push(d);
  184. break;
  185. case Op.SUSPEND:
  186. // We'll continue on this frame after `delay` seconds
  187. // but because we are returning here we'll have to
  188. // manually progress the instruction pointer to point
  189. // at the first instruction following `suspend`.
  190. f.ip += 1;
  191. x = f.stack.pop(); // delay
  192. d = new DelayedFrame(f, x);
  193. return [0, null, forks.concat(d)];
  194. case Op.RET:
  195. r = f.stack.pop();
  196. return [r, null, forks];
  197. case Op.RET0:
  198. return [0, null, forks];
  199. case Op.MAKE_EMPTY_LIST:
  200. f.stack.push([]);
  201. break;
  202. case Op.MAKE_SINGLETON_LIST:
  203. x = f.stack.pop();
  204. f.stack.push([x]);
  205. break;
  206. case Op.LIST_ADD_TAIL:
  207. y = f.stack.pop();
  208. x = f.stack.pop();
  209. r = x.concat(y);
  210. f.stack.push(r);
  211. break;
  212. case Op.LIST_APPEND:
  213. y = f.stack.pop();
  214. x = f.stack.pop();
  215. r = x.concat(y);
  216. f.stack.push(r);
  217. break;
  218. case Op.POP:
  219. f.stack.pop();
  220. break;
  221. default:
  222. if (isTinyIntOpCode(op)) {
  223. f.stack.push(opCodeToTinyInt(op));
  224. }
  225. else {
  226. throw new Error('E_INVOP');
  227. }
  228. }
  229.  
  230. f.ip += 1;
  231. }
  232.  
  233. throw new Error('E_NORET');
  234. }
  235.  
  236. private log(args): number {
  237. console.log(args);
  238. return 0;
  239. }
  240. }
  241.  
  242. export {
  243. tinyIntToOpCode,
  244. Op,
  245. Object,
  246. Program,
  247. Frame,
  248. DelayedFrame,
  249. VM
  250. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement