1 module zua.compiler.compiler; 2 import zua.compiler.sourcemap; 3 import zua.compiler.utils; 4 import zua.compiler.ir; 5 import zua.vm.engine; 6 import std.uuid; 7 import std.range; 8 9 private struct Variable { 10 bool heap; 11 ulong index; 12 } 13 14 private class Environment { 15 private ulong[UUID] vars; 16 private bool[UUID] closureMap; 17 private ulong[UUID] upvalues; 18 private ulong varIndex = 0; 19 bool hasReturn = false; 20 21 this(FunctionExpr func) { 22 ulong uvIndex = 0; 23 foreach (id; func.upvalues) { 24 upvalues[id] = uvIndex; 25 uvIndex++; 26 } 27 foreach (id; func.closed) { 28 closureMap[id] = true; 29 } 30 } 31 32 bool isRef(UUID var) { 33 return (var in closureMap) != null; 34 } 35 36 bool isUpvalue(UUID var) { 37 return (var in upvalues) != null; 38 } 39 40 void set(Function func, UUID id) { 41 func.code ~= new MonadInstruction(getSetOp(id), get(id)); 42 } 43 44 void get(Function func, UUID id) { 45 func.code ~= new MonadInstruction(getGetOp(id), get(id)); 46 } 47 48 Opcode getSetOp(UUID var) { 49 if (var in closureMap) 50 return Opcode.SetRef; 51 else if (var in upvalues) 52 return Opcode.SetC; 53 else 54 return Opcode.Set; 55 } 56 57 Opcode getGetOp(UUID var) { 58 if (var in closureMap) 59 return Opcode.GetRef; 60 else if (var in upvalues) 61 return Opcode.GetC; 62 else 63 return Opcode.Get; 64 } 65 66 ulong get(UUID var) { 67 if (var in vars) { 68 return vars[var]; 69 } 70 else if (var in upvalues) { 71 return upvalues[var]; 72 } 73 else { 74 vars[var] = varIndex; 75 varIndex++; 76 return varIndex - 1; 77 } 78 } 79 80 } 81 82 private class Compiler { 83 84 Function func; 85 Function[] scopeStack; 86 87 Environment env; 88 Environment[] envStack; 89 90 UUID[] breakStack; 91 UUID[] continueStack; 92 UUID[] variadicStack; 93 94 Indices prevIndices; 95 96 void pack(Expr[] tuple) { 97 foreach (e; tuple) { 98 if (auto call = cast(CallExpr) e) { 99 compile(call.base); 100 if (call.method.isNull) { 101 maybePack(call.args); 102 func.code ~= new AtomicInstruction(Opcode.Call); 103 } 104 else { 105 func.code ~= new MonadInstruction(Opcode.NamecallPrep, getString(call.method.get)); 106 maybePack(call.args); 107 func.code ~= new AtomicInstruction(Opcode.Namecall); 108 } 109 } 110 else { 111 compile(e); 112 } 113 } 114 func.code ~= new MonadInstruction(Opcode.Pack, tuple.length); 115 } 116 117 void maybePack(Expr expr) { 118 if (auto call = cast(CallExpr) expr) { 119 compile(call.base); 120 if (call.method.isNull) { 121 maybePack(call.args); 122 func.code ~= new AtomicInstruction(Opcode.Call); 123 } 124 else { 125 func.code ~= new MonadInstruction(Opcode.NamecallPrep, getString(call.method.get)); 126 maybePack(call.args); 127 func.code ~= new AtomicInstruction(Opcode.Namecall); 128 } 129 } 130 else { 131 compile(expr); 132 } 133 } 134 135 void maybePack(Expr[] tuple) { 136 if (tuple.length == 1) { 137 maybePack(tuple[0]); 138 } 139 else { 140 pack(tuple); 141 } 142 } 143 144 void declare(UUID[] vars, Expr[] values) { 145 maybePack(values); 146 func.code ~= new MonadInstruction(Opcode.Unpack, vars.length); 147 foreach (id; vars) { 148 if (env.isRef(id)) 149 func.code ~= new MonadInstruction(Opcode.Mkhv, env.get(id)); 150 env.set(func, id); 151 } 152 } 153 154 ulong getString(string str) { 155 auto res = func.data.length; 156 func.data ~= str; 157 return res; 158 } 159 160 void pushString(string str) { 161 func.code ~= new MonadInstruction(Opcode.LdStr, getString(str)); 162 } 163 164 Indices indexNode(IRNode node) { 165 // import std.stdio : writeln; 166 167 // writeln(node.start.index); 168 // writeln(node.end.index + node.end.rawValue.length); 169 return new Indices(node.start.index, node.end.index + node.end.rawValue.length); 170 } 171 172 /** Compile an IR node */ 173 void compile(Stat stat) { 174 auto save = prevIndices; // @suppress(dscanner.suspicious.unmodified) 175 prevIndices = indexNode(stat); 176 func.code ~= prevIndices; 177 if (auto s = cast(AssignStat) stat) 178 compilev(s); 179 else if (auto s = cast(ExprStat) stat) 180 compilev(s); 181 else if (auto s = cast(Block) stat) 182 compilev(s); 183 else if (auto s = cast(DeclarationStat) stat) 184 compilev(s); 185 else if (auto s = cast(WhileStat) stat) 186 compilev(s); 187 else if (auto s = cast(RepeatStat) stat) 188 compilev(s); 189 else if (auto s = cast(IfStat) stat) 190 compilev(s); 191 else if (auto s = cast(NumericForStat) stat) 192 compilev(s); 193 else if (auto s = cast(ForeachStat) stat) 194 compilev(s); 195 else if (auto s = cast(ReturnStat) stat) 196 compilev(s); 197 else if (auto s = cast(AtomicStat) stat) 198 compilev(s); 199 else 200 assert(0); 201 prevIndices = save; 202 func.code ~= prevIndices; 203 } 204 205 /// ditto 206 void compile(Expr expr) { 207 auto save = prevIndices; // @suppress(dscanner.suspicious.unmodified) 208 prevIndices = indexNode(expr); 209 func.code ~= prevIndices; 210 if (auto e = cast(AtomicExpr) expr) 211 compilev(e); 212 else if (auto e = cast(NumberExpr) expr) 213 compilev(e); 214 else if (auto e = cast(StringExpr) expr) 215 compilev(e); 216 else if (auto e = cast(FunctionExpr) expr) 217 compilev(e); 218 else if (auto e = cast(BinaryExpr) expr) 219 compilev(e); 220 else if (auto e = cast(UnaryExpr) expr) 221 compilev(e); 222 else if (auto e = cast(TableExpr) expr) 223 compilev(e); 224 else if (auto e = cast(LvalueExpr) expr) 225 compile(e); 226 else if (auto e = cast(BracketExpr) expr) 227 compilev(e); 228 else if (auto e = cast(CallExpr) expr) 229 compilev(e); 230 else 231 assert(0); 232 prevIndices = save; 233 func.code ~= prevIndices; 234 } 235 236 /// ditto 237 void compile(LvalueExpr expr) { 238 auto save = prevIndices; // @suppress(dscanner.suspicious.unmodified) 239 prevIndices = indexNode(expr); 240 func.code ~= prevIndices; 241 if (auto e = cast(GlobalExpr) expr) 242 compilev(e); 243 else if (auto e = cast(LocalExpr) expr) 244 compilev(e); 245 else if (auto e = cast(UpvalueExpr) expr) 246 compilev(e); 247 else if (auto e = cast(IndexExpr) expr) 248 compilev(e); 249 else 250 assert(0); 251 prevIndices = save; 252 func.code ~= prevIndices; 253 } 254 255 /// ditto 256 void compilev(Expr[] tuple) { 257 if (tuple.length == 0) { 258 func.code ~= new AtomicInstruction(Opcode.LdNil); 259 } 260 else { 261 compile(tuple[0]); 262 foreach (e; tuple[1 .. $]) { 263 compile(e); 264 func.code ~= new AtomicInstruction(Opcode.Drop); 265 } 266 } 267 } 268 269 /// ditto 270 void compilev(AssignStat stat) { 271 if (stat.keys.length == 1) { 272 auto key = stat.keys[0]; 273 if (auto e = cast(IndexExpr) key) { 274 compile(e.base); 275 compile(e.key); 276 } 277 else if (auto e = cast(GlobalExpr) key) { 278 func.code ~= new AtomicInstruction(Opcode.Getfenv); 279 pushString(e.name); 280 } 281 compile(stat.values[0]); 282 if (auto e = cast(LocalExpr) key) { 283 env.set(func, e.id); 284 } 285 else if (auto e = cast(UpvalueExpr) key) { 286 env.set(func, e.id); 287 } 288 else { 289 func.code ~= new AtomicInstruction(Opcode.SetTable); 290 } 291 return; 292 } 293 294 ulong dropCount = 0; 295 foreach (key; stat.keys) { 296 if (auto e = cast(IndexExpr) key) { 297 compile(e.base); 298 compile(e.key); 299 dropCount += 2; 300 } 301 else if (!cast(LocalExpr) key && !cast(UpvalueExpr) key && !cast(GlobalExpr) key) 302 assert(0); 303 } 304 maybePack(stat.values); 305 // a, b, c = d, e, f 306 func.code ~= new MonadInstruction(Opcode.UnpackRev, stat.keys.length); 307 // stack: f, e, d <top> 308 ulong offset = stat.keys.length; 309 foreach (key; stat.keys.retro) { 310 if (auto e = cast(GlobalExpr) key) { 311 pushString(e.name); 312 func.code ~= new AtomicInstruction(Opcode.Getfenv); 313 func.code ~= new AtomicInstruction(Opcode.SetTableRev); 314 } 315 else if (auto e = cast(LocalExpr) key) { 316 env.set(func, e.id); 317 } 318 else if (auto e = cast(UpvalueExpr) key) { 319 env.set(func, e.id); 320 } 321 else if (auto e = cast(IndexExpr) key) { 322 func.code ~= new MonadInstruction(Opcode.Introspect, offset); 323 offset++; 324 func.code ~= new MonadInstruction(Opcode.Introspect, offset + 1); 325 offset++; 326 func.code ~= new AtomicInstruction(Opcode.SetTableRev); 327 offset -= 3; 328 offset += 2; 329 offset++; // to make up for decrementing right after 330 } 331 else 332 assert(0); 333 334 offset--; 335 } 336 func.code ~= new MonadInstruction(Opcode.DropTuple, dropCount); 337 } 338 339 /// ditto 340 void compilev(ExprStat stat) { 341 compile(stat.expr); 342 func.code ~= new AtomicInstruction(Opcode.Drop); 343 } 344 345 /// ditto 346 void compilev(Block stat) { 347 foreach (s; stat.body) 348 compile(s); 349 } 350 351 /// ditto 352 void compilev(DeclarationStat stat) { 353 declare(stat.keys, stat.values); 354 } 355 356 /// ditto 357 void compilev(WhileStat stat) { 358 const UUID start = randomUUID(); 359 const UUID skip = randomUUID(); 360 func.code ~= new Label(start); 361 compile(stat.cond); 362 func.code ~= new MonadInstruction(Opcode.JmpF, skip); 363 compile(stat.body); 364 func.code ~= new MonadInstruction(Opcode.Jmp, start); 365 func.code ~= new Label(skip); 366 } 367 368 /// ditto 369 void compilev(RepeatStat stat) { 370 const UUID start = randomUUID(); 371 func.code ~= new Label(start); 372 compile(stat.body); 373 compile(stat.endCond); 374 func.code ~= new MonadInstruction(Opcode.JmpF, start); 375 } 376 377 /// ditto 378 void compilev(IfStat stat) { 379 const UUID finished = randomUUID(); 380 foreach (entry; stat.entries) { 381 compile(entry.cond); 382 const UUID skip = randomUUID(); 383 func.code ~= new MonadInstruction(Opcode.JmpF, skip); 384 compile(entry.body); 385 func.code ~= new MonadInstruction(Opcode.Jmp, finished); 386 func.code ~= new Label(skip); 387 } 388 if (!stat.elseBody.isNull) 389 compile(stat.elseBody.get); 390 func.code ~= new Label(finished); 391 } 392 393 /// ditto 394 void compilev(NumericForStat stat) { 395 const UUID endLabel = randomUUID(); 396 const UUID breakLabel = randomUUID(); 397 const UUID continueLabel = randomUUID(); 398 compile(stat.low); 399 compile(stat.high); 400 if (stat.step.isNull) { 401 func.code ~= new MonadInstruction(Opcode.LdNum, 1.0); 402 } 403 else { 404 compile(stat.step.get); 405 func.code ~= new AtomicInstruction(Opcode.Dup); 406 func.code ~= new MonadInstruction(Opcode.LdNum, 0.0); 407 func.code ~= new AtomicInstruction(Opcode.Eq); 408 func.code ~= new MonadInstruction(Opcode.JmpT, endLabel); 409 } 410 const bool isRef = env.isRef(stat.var); 411 const UUID iteratorVar = randomUUID(); 412 if (isRef) { 413 func.code ~= new MonadInstruction(Opcode.ForPrep, env.get(iteratorVar)); 414 } 415 else { 416 func.code ~= new MonadInstruction(Opcode.ForPrep, env.get(stat.var)); 417 } 418 const UUID jumpBack = randomUUID(); 419 func.code ~= new Label(jumpBack); 420 func.code ~= new MonadInstruction(Opcode.Loop, breakLabel); 421 const UUID start = randomUUID(); 422 func.code ~= new Label(start); 423 if (isRef) { 424 func.code ~= new MonadInstruction(Opcode.Mkhv, env.get(stat.var)); 425 func.code ~= new MonadInstruction(Opcode.Get, env.get(iteratorVar)); 426 func.code ~= new MonadInstruction(Opcode.SetRef, env.get(stat.var)); 427 } 428 breakStack ~= breakLabel; 429 continueStack ~= continueLabel; 430 compile(stat.body); 431 breakStack = breakStack[0 .. $ - 1]; 432 continueStack = continueStack[0 .. $ - 1]; 433 func.code ~= new Label(continueLabel); 434 func.code ~= new MonadInstruction(Opcode.Jmp, jumpBack); 435 func.code ~= new Label(breakLabel); 436 func.code ~= new AtomicInstruction(Opcode.DropLoop); 437 func.code ~= new Label(endLabel); 438 } 439 440 /// ditto 441 void compilev(ForeachStat stat) { 442 const UUID fvar = randomUUID(); 443 const UUID svar = randomUUID(); 444 const UUID var = randomUUID(); 445 maybePack(stat.iter); 446 func.code ~= new MonadInstruction(Opcode.Unpack, 3); 447 env.set(func, fvar); 448 env.set(func, svar); 449 env.set(func, var); 450 451 const UUID breakLabel = randomUUID(); 452 const UUID continueLabel = randomUUID(); 453 454 func.code ~= new Label(continueLabel); 455 env.get(func, fvar); 456 env.get(func, svar); 457 env.get(func, var); 458 func.code ~= new MonadInstruction(Opcode.Pack, 2); 459 func.code ~= new AtomicInstruction(Opcode.Call); 460 func.code ~= new MonadInstruction(Opcode.Unpack, stat.vars.length); 461 env.set(func, var); 462 env.get(func, var); 463 foreach (v; stat.vars) { 464 if (env.isRef(v)) { 465 func.code ~= new MonadInstruction(Opcode.Mkhv, env.get(v)); 466 } 467 env.set(func, v); 468 } 469 env.get(func, var); 470 func.code ~= new MonadInstruction(Opcode.JmpNil, breakLabel); 471 breakStack ~= breakLabel; 472 continueStack ~= continueLabel; 473 compile(stat.body); 474 breakStack = breakStack[0 .. $ - 1]; 475 continueStack = continueStack[0 .. $ - 1]; 476 func.code ~= new MonadInstruction(Opcode.Jmp, continueLabel); 477 func.code ~= new Label(breakLabel); 478 } 479 480 /// ditto 481 void compilev(ReturnStat stat) { 482 env.hasReturn = true; 483 maybePack(stat.values); 484 func.code ~= new AtomicInstruction(Opcode.Ret); 485 } 486 487 /// ditto 488 void compilev(AtomicStat stat) { 489 switch (stat.type) { 490 case AtomicStatType.Break: 491 func.code ~= new MonadInstruction(Opcode.Jmp, breakStack[$ - 1]); 492 break; 493 default: 494 assert(0); 495 } 496 } 497 498 /// ditto 499 void compilev(GlobalExpr expr) { 500 func.code ~= new AtomicInstruction(Opcode.Getfenv); 501 pushString(expr.name); 502 func.code ~= new AtomicInstruction(Opcode.GetTable); 503 } 504 505 /// ditto 506 void compilev(LocalExpr expr) { 507 const ulong i = env.get(expr.id); 508 func.code ~= new MonadInstruction(env.isRef(expr.id) ? Opcode.GetRef 509 : Opcode.Get, OperandValue(i)); 510 } 511 512 /// ditto 513 void compilev(UpvalueExpr expr) { 514 const ulong i = env.get(expr.id); 515 func.code ~= new MonadInstruction(Opcode.GetC, OperandValue(i)); 516 } 517 518 /// ditto 519 void compilev(IndexExpr expr) { 520 compile(expr.base); 521 compile(expr.key); 522 func.code ~= new AtomicInstruction(Opcode.GetTable); 523 } 524 525 /// ditto 526 void compilev(BracketExpr expr) { 527 compile(expr.expr); 528 } 529 530 /// ditto 531 void compilev(CallExpr expr) { 532 compile(expr.base); 533 if (expr.method.isNull) { 534 maybePack(expr.args); 535 func.code ~= new AtomicInstruction(Opcode.Call); 536 } 537 else { 538 func.code ~= new MonadInstruction(Opcode.NamecallPrep, getString(expr.method.get)); 539 maybePack(expr.args); 540 func.code ~= new AtomicInstruction(Opcode.Namecall); 541 } 542 func.code ~= new MonadInstruction(Opcode.Unpack, 1); 543 } 544 545 /// ditto 546 void compilev(AtomicExpr expr) { 547 switch (expr.type) { 548 case AtomicExprType.Nil: 549 func.code ~= new AtomicInstruction(Opcode.LdNil); 550 break; 551 case AtomicExprType.False: 552 func.code ~= new AtomicInstruction(Opcode.LdFalse); 553 break; 554 case AtomicExprType.True: 555 func.code ~= new AtomicInstruction(Opcode.LdTrue); 556 break; 557 case AtomicExprType.VariadicTuple: 558 env.get(func, variadicStack[$ - 1]); 559 break; 560 default: 561 assert(0); 562 } 563 } 564 565 /// ditto 566 void compilev(NumberExpr expr) { 567 func.code ~= new MonadInstruction(Opcode.LdNum, OperandValue(expr.value)); 568 } 569 570 /// ditto 571 void compilev(StringExpr expr) { 572 pushString(expr.value); 573 } 574 575 /// ditto 576 void compilev(FunctionExpr expr, bool toplevel = false) { 577 ulong[] upvalues; 578 579 foreach (id; expr.upvalues) { 580 assert(env.isRef(id)); 581 if (env.isUpvalue(id)) { 582 upvalues ~= ~env.get(id); // complements are a sort of "magic number" 583 } 584 else { 585 upvalues ~= env.get(id); 586 } 587 } 588 589 auto child = new Function; 590 591 if (!toplevel) { 592 func.code ~= new LdFun(func.functions.length, upvalues); 593 func.functions ~= child; 594 } 595 596 scopeStack ~= func; 597 envStack ~= env; 598 599 func = child; 600 child.upvalues = expr.upvalues.length; 601 // child.locals = expr.localsCount; 602 603 env = new Environment(expr); 604 605 if (expr.variadic) { 606 UUID variadic = randomUUID(); 607 variadicStack.assumeSafeAppend ~= variadic; 608 func.code ~= new AtomicInstruction(Opcode.LdArgs); 609 if (expr.args.length > 0) 610 func.code ~= new MonadInstruction(Opcode.UnpackD, expr.args.length); 611 env.set(func, variadic); 612 foreach (arg; expr.args) { 613 env.set(func, arg); 614 } 615 } 616 else { 617 variadicStack.assumeSafeAppend ~= UUID(); 618 if (expr.args.length > 0) { 619 func.code ~= new AtomicInstruction(Opcode.LdArgs); 620 func.code ~= new MonadInstruction(Opcode.Unpack, expr.args.length); 621 foreach (arg; expr.args) { 622 env.set(func, arg); 623 } 624 } 625 } 626 627 compile(expr.body); 628 629 variadicStack = variadicStack[0 .. $ - 1]; 630 631 child.locals = env.vars.length; 632 633 if (!env.hasReturn) { 634 func.code ~= new MonadInstruction(Opcode.Pack, 0); 635 func.code ~= new AtomicInstruction(Opcode.Ret); 636 } 637 638 if (!toplevel) { 639 func = scopeStack[$ - 1]; 640 } 641 scopeStack = scopeStack[0 .. $ - 1]; 642 643 env = envStack[$ - 1]; 644 envStack = envStack[0 .. $ - 1]; 645 } 646 647 /// ditto 648 void compilev(BinaryExpr expr) { 649 if (expr.op == BinaryOperation.And) { 650 compile(expr.lhs); 651 func.code ~= new AtomicInstruction(Opcode.Dup); 652 const UUID jmp = randomUUID(); 653 func.code ~= new MonadInstruction(Opcode.JmpF, jmp); 654 func.code ~= new AtomicInstruction(Opcode.Drop); 655 compile(expr.rhs); 656 func.code ~= new Label(jmp); 657 } 658 else if (expr.op == BinaryOperation.Or) { 659 compile(expr.lhs); 660 func.code ~= new AtomicInstruction(Opcode.Dup); 661 const UUID jmp = randomUUID(); 662 func.code ~= new MonadInstruction(Opcode.JmpT, jmp); 663 func.code ~= new AtomicInstruction(Opcode.Drop); 664 compile(expr.rhs); 665 func.code ~= new Label(jmp); 666 } 667 else { 668 Opcode op; 669 switch (expr.op) { 670 case BinaryOperation.Add: 671 op = Opcode.Add; 672 break; 673 case BinaryOperation.Sub: 674 op = Opcode.Sub; 675 break; 676 case BinaryOperation.Mul: 677 op = Opcode.Mul; 678 break; 679 case BinaryOperation.Div: 680 op = Opcode.Div; 681 break; 682 case BinaryOperation.Exp: 683 op = Opcode.Exp; 684 break; 685 case BinaryOperation.Mod: 686 op = Opcode.Mod; 687 break; 688 case BinaryOperation.Concat: 689 op = Opcode.Concat; 690 break; 691 case BinaryOperation.CmpLt: 692 op = Opcode.Lt; 693 break; 694 case BinaryOperation.CmpLe: 695 op = Opcode.Le; 696 break; 697 case BinaryOperation.CmpGt: 698 op = Opcode.Gt; 699 break; 700 case BinaryOperation.CmpGe: 701 op = Opcode.Ge; 702 break; 703 case BinaryOperation.CmpEq: 704 op = Opcode.Eq; 705 break; 706 case BinaryOperation.CmpNe: 707 op = Opcode.Ne; 708 break; 709 default: 710 assert(0); 711 } 712 compile(expr.lhs); 713 compile(expr.rhs); 714 func.code ~= new AtomicInstruction(op); 715 } 716 } 717 718 /// ditto 719 void compilev(UnaryExpr expr) { 720 Opcode op; 721 switch (expr.op) { 722 case UnaryOperation.Negate: 723 op = Opcode.Unm; 724 break; 725 case UnaryOperation.Not: 726 op = Opcode.Not; 727 break; 728 case UnaryOperation.Length: 729 op = Opcode.Len; 730 break; 731 default: 732 assert(0); 733 } 734 compile(expr.expr); 735 func.code ~= new AtomicInstruction(op); 736 } 737 738 /// ditto 739 void compilev(TableExpr expr) { 740 func.code ~= new AtomicInstruction(Opcode.NewTable); 741 // auto dupIns = new MonadInstruction(Opcode.DupN, 1); 742 // func.code ~= dupIns; 743 Expr[] array; 744 foreach (field; expr.fields) { 745 if (TableField* f = field.peek!TableField) { 746 func.code ~= new AtomicInstruction(Opcode.Dup); 747 // dupIns.value.peek!OperandValue.i++; 748 compile(f.key); 749 compile(f.value); 750 func.code ~= new AtomicInstruction(Opcode.SetTable); 751 } 752 else { 753 array ~= *field.peek!Expr; 754 } 755 } 756 func.code ~= new AtomicInstruction(Opcode.Dup); 757 foreach (field; array) { 758 maybePack(field); 759 } 760 // if (array.length > 0) { 761 func.code ~= new MonadInstruction(Opcode.SetArray, array.length); 762 // } 763 // else { 764 // dupIns.value.peek!OperandValue.i--; 765 // } 766 } 767 768 immutable(ubyte)[] buffer(Indices toplevelIndices, SourceMap map) { 769 return func.serialize(toplevelIndices, map); 770 } 771 772 } 773 774 /** Compile a top-level function */ 775 immutable(ubyte)[] compile(SourceMap map, FunctionExpr func) { 776 Compiler compiler = new Compiler; 777 compiler.compilev(func, true); 778 return compiler.buffer(new Indices(func.start.index, func.end.index + func.end.rawValue.length), map); 779 }