//Optimization for a simple 'for' cycle private bool TryOptimizeFor(DFor node, Hints hints, CompilerContext ctx) { if (options.NoOptimizations || node.Guard is not null || node.Pattern.NodeType is not NodeType.NamePattern and not NodeType.WildcardPattern || node.Target.NodeType is not NodeType.Range) { return(false); } var incName = node.Pattern is INamedNode nn ? nn.NodeName : null; if (incName is not null && incName.Length > 0 && char.IsUpper(incName[0])) { return(false); } var range = (DRange)node.Target; if (range.From is null) { return(false); } long step; var downTo = false; if (range.Step is not null && range.Step.NodeType is not NodeType.Integer) { if (range.Step is not DUnaryOperation u || u.Operator is not UnaryOperator.Neg || u.Node.NodeType is not NodeType.Integer) { return(false); } step = -((DIntegerLiteral)u.Node).Value; downTo = true; }
private void Build(DFor node, Hints hints, CompilerContext ctx) { ctx = new(ctx) { BlockSkip = cw.DefineLabel(), BlockExit = cw.DefineLabel(), BlockBreakExit = cw.DefineLabel() }; if (TryOptimizeFor(node, hints, ctx)) { return; } StartScope(ScopeKind.Loop, node.Location); hints = hints.Remove(Last); var inc = false; if (node.Pattern.NodeType == NodeType.NamePattern && !char.IsUpper(((DNamePattern)node.Pattern).Name[0] !)) { inc = true; } var sys = AddVariable(); var initSkip = cw.DefineLabel(); Build(node.Target, hints.Append(Push), ctx); cw.Briter(initSkip); cw.GetMember(Builtins.Iterate); cw.CallNullaryFunction(); cw.MarkLabel(initSkip); cw.GetIter(); cw.PopVar(sys); var iter = cw.DefineLabel(); cw.MarkLabel(iter); cw.PushVar(new ScopeVar(sys)); cw.CallNullaryFunction(); cw.Brterm(ctx.BlockExit); if (inc) { var ai = AddVariable(((DNamePattern)node.Pattern).Name !, node.Pattern.Location, VarFlags.None); cw.PopVar(ai); } else { BuildPattern(node.Pattern, hints, ctx); cw.Brfalse(ctx.BlockSkip); } if (node.Guard != null) { Build(node.Guard, hints.Append(Push), ctx); cw.Brfalse(ctx.BlockSkip); } var nh = hints.Remove(Push); Build(node.Body, nh, ctx); cw.MarkLabel(ctx.BlockSkip); cw.Br(iter); cw.MarkLabel(ctx.BlockExit); cw.Pop(); cw.PushNil(); AddLinePragma(node); cw.MarkLabel(ctx.BlockBreakExit); PopIf(hints); cw.Nop(); EndScope(); }
private void Build(DFor node, Hints hints, CompilerContext ctx) { ctx = new CompilerContext(ctx) { BlockSkip = cw.DefineLabel(), BlockExit = cw.DefineLabel(), BlockBreakExit = cw.DefineLabel() }; StartScope(false, node.Location); hints = hints.Remove(Last); var inc = -1; if (node.Pattern.NodeType == NodeType.NamePattern && GetTypeHandle(null, node.Pattern.GetName(), out var _, out var _) != CompilerError.None) { inc = AddVariable(node.Pattern.GetName(), node.Pattern, VarFlags.None); } var sys = AddVariable(); var initSkip = cw.DefineLabel(); Build(node.Target, hints.Append(Push), ctx); cw.Briter(initSkip); cw.GetMember(GetMemberNameId(Builtins.Iterator)); cw.FunPrep(0); cw.FunCall(0); cw.MarkLabel(initSkip); cw.PopVar(sys); var iter = cw.DefineLabel(); cw.MarkLabel(iter); cw.PushVar(new ScopeVar(sys)); cw.FunPrep(0); cw.FunCall(0); cw.Brterm(ctx.BlockExit); if (inc > -1) { cw.PopVar(inc); } else { BuildPattern(node.Pattern, hints, ctx); cw.Brfalse(ctx.BlockSkip); } if (node.Guard != null) { Build(node.Guard, hints.Append(Push), ctx); cw.Brfalse(ctx.BlockSkip); } var nh = hints.Has(Push) ? hints.Remove(Push).Append(ExpectPush) : hints.Remove(ExpectPush); Build(node.Body, nh, ctx); cw.MarkLabel(ctx.BlockSkip); cw.Br(iter); cw.MarkLabel(ctx.BlockExit); cw.Pop(); PushIf(hints); AddLinePragma(node); cw.MarkLabel(ctx.BlockBreakExit); cw.Nop(); EndScope(); }