public Instr Emit_RangeInc(Dot2Node node) { node.car.Compile(this); node.cdr.Compile(this); Pop(2); var instr = AppendInstruction(new Instr(OpCode.RangeInc, vm.CurrentScope.sp)); Push(); return(instr); }
private void Gen(CodeGenScope s, AstNode tree, int val) { int nt; int rlev = s.rlev; if (tree == null) { if (val != NOVAL) { GenOp_1(s, OpCode.LoadNIL, s.sp); Push(s, 1); } return; } s.rlev++; if (s.rlev > CodeGenScope.MAX_RLEV_LENGTH) { throw new Exception("too complex expression"); } s.lineno = tree.lineno; Console.WriteLine($"Gen: {tree}"); switch (tree.type) { case AstNodeType.LAMBDA: if (val != NOVAL) { int idx = LambdaBody(s, tree, true); GenOp_2(s, OpCode.Lambda, s.sp, idx); Push(s); } break; case AstNodeType.BLOCK: if (val != NOVAL) { int idx = LambdaBody(s, tree, true); GenOp_2(s, OpCode.Block, s.sp, idx); Push(s); } break; case AstNodeType.IF: int pos1, pos2; IfNode ifNode = tree.As <IfNode> (); AstNode elsepart = ifNode.@else; if (ifNode.cond == null) { Gen(s, elsepart, val); goto exit; } switch (ifNode.cond.type) { case AstNodeType.TRUE: case AstNodeType.INT: case AstNodeType.STR: Gen(s, ifNode.then, val); goto exit; case AstNodeType.FALSE: case AstNodeType.NIL: Gen(s, elsepart, val); goto exit; } Gen(s, ifNode.cond, val); Pop(s, 1); pos1 = GenJmp2(s, OpCode.JmpNot, s.sp, 0, val); Gen(s, ifNode.then, val); if (elsepart != null) { if (val != NOVAL) { Pop(s, 1); } pos2 = GenJmp(s, OpCode.Jmp, 0); Gen(s, elsepart, val); } else { if (val != NOVAL) { Pop(s, 1); pos2 = GenJmp(s, OpCode.Jmp, 0); GenOp_1(s, OpCode.LoadNIL, s.sp); Push(s, 1); } else { //dispatch ( s, pos1 ); } } break; case AstNodeType.AND: case AstNodeType.OR: case AstNodeType.WHILE: case AstNodeType.UNTIL: case AstNodeType.FOR: ForBody(s, tree); if (val != NOVAL) { Push(s); } break; case AstNodeType.CASE: // TODO: break; case AstNodeType.SCOPE: ScopeBody(s, tree, NOVAL); break; case AstNodeType.FCALL: case AstNodeType.CALL: GenCall(s, tree, 0, val, false); break; case AstNodeType.SCALL: GenCall(s, tree, 0, 0, true); break; case AstNodeType.DOT2: Dot2Node dot2Node = tree.As <Dot2Node> (); Gen(s, dot2Node.car, val); Gen(s, dot2Node.cdr, val); if (val != NOVAL) { Pop(s); Pop(s); GenOp_1(s, OpCode.RangeInc, s.sp); Push(s); } break; case AstNodeType.DOT3: Dot3Node dot3Node = tree.As <Dot3Node> (); Gen(s, dot3Node.car, val); Gen(s, dot3Node.cdr, val); if (val != NOVAL) { Pop(s); Pop(s); GenOp_1(s, OpCode.RangeExc, s.sp); Push(s); } break; case AstNodeType.COLON2: case AstNodeType.COLON3: case AstNodeType.ARRAY: case AstNodeType.HASH: case AstNodeType.KW_HASH: // TODO: break; case AstNodeType.SPLAT: // TODO: break; case AstNodeType.ASGN: GenAssignment(s, tree, s.sp, val); break; case AstNodeType.MASGN: case AstNodeType.OP_ASGN: case AstNodeType.SUPER: case AstNodeType.RETURN: case AstNodeType.YIELD: case AstNodeType.BREAK: case AstNodeType.NEXT: case AstNodeType.REDO: case AstNodeType.RETRY: // TODO: break; case AstNodeType.LVAR: if (val != NOVAL) { int idx = s.FindLocalVarIdx(nsym(tree)); if (idx > 0) { GenMove(s, s.sp, idx, val != 0); if (val != 0 && s.parser.on_eval) { GenOp_0(s, OpCode.Nop); } } else { int lv = 0; CodeGenScope up = s.prev; while (up != null) { idx = up.FindLocalVarIdx(nsym(tree)); if (idx > 0) { GenOp_3(s, OpCode.GetUpVar, s.sp, idx, lv); break; } lv++; up = up.prev; } } Push(s); } break; case AstNodeType.GVAR: int gsym = NewSym(s, nsym(tree)); GenOp_2(s, OpCode.GetGV, s.sp, gsym); if (val != 0) { Push(s); } break; case AstNodeType.IVAR: int isym = NewSym(s, nsym(tree)); GenOp_2(s, OpCode.GetIV, s.sp, isym); if (val != 0) { Push(s); } break; case AstNodeType.CVAR: int csym = NewSym(s, nsym(tree)); GenOp_2(s, OpCode.GetCV, s.sp, csym); if (val != NOVAL) { Push(s); } break; case AstNodeType.CONST: int cnstSym = NewSym(s, nsym(tree)); GenOp_2(s, OpCode.GetConst, s.sp, cnstSym); if (val != NOVAL) { Push(s); } break; case AstNodeType.DEFINED: Gen(s, tree, val); break; case AstNodeType.ARG: /* should not happen */ break; case AstNodeType.BLOCK_ARG: Gen(s, tree, val); break; case AstNodeType.INT: if (val != NOVAL) { int off = NewLiteral(s, tree.As <IntNode>().value); GenOp_2(s, OpCode.LoadI, s.sp, off); Push(s); } break; case AstNodeType.FLOAT: if (val != NOVAL) { int off = NewLiteral(s, tree.As <FloatNode>().value); GenOp_2(s, OpCode.LoadI, s.sp, off); Push(s); } break; case AstNodeType.STR: if (val != NOVAL) { int off = NewLiteral(s, Value.Str(tree.As <StringNode>().token)); GenOp_2(s, OpCode.String, s.sp, off); Push(s); } break; case AstNodeType.SYM: if (val != NOVAL) { int off = NewSym(s, nsym(tree)); GenOp_2(s, OpCode.LoadSYM, s.sp, off); Push(s); } break; case AstNodeType.SELF: if (val != NOVAL) { GenOp_1(s, OpCode.LoadSelf, s.sp); Push(s); } break; case AstNodeType.NIL: if (val != NOVAL) { GenOp_1(s, OpCode.LoadNIL, s.sp); Push(s); } break; case AstNodeType.TRUE: if (val != NOVAL) { GenOp_1(s, OpCode.LoadT, s.sp); Push(s); } break; case AstNodeType.FALSE: if (val != NOVAL) { GenOp_1(s, OpCode.LoadF, s.sp); Push(s); } break; case AstNodeType.CLASS: case AstNodeType.MODULE: case AstNodeType.SCLASS: case AstNodeType.DEF: case AstNodeType.SDEF: // TODO: break; case AstNodeType.CMD_LIST: foreach (var cmd in tree.As <ExpressionListNode> ().exprs) { Gen(s, cmd, val); } break; default: break; } exit: s.rlev = rlev; }