public void DoEmitPartialApplicationCode(CompilerTarget target) { AstPlaceholder.DeterminePlaceholderIndices(Expressions.OfType<AstPlaceholder>()); var count = Expressions.Count; if (count == 0) { this.ConstFunc(null).EmitValueCode(target); return; } //only the very last condition may be a placeholder for (var i = 0; i < count; i++) { var value = Expressions[i]; var isPlaceholder = value.IsPlaceholder(); if (i == count - 1) { if (!isPlaceholder) { //there is no placeholder at all, wrap expression in const Debug.Assert(Expressions.All(e => !e.IsPlaceholder())); DoEmitCode(target,StackSemantics.Value); target.EmitCommandCall(Position, 1, Const.Alias); return; } } else { if (isPlaceholder) { _reportInvalidPlaceholders(target); return; } } } if (count == 0) { this.ConstFunc().EmitValueCode(target); } else if (count == 1) { Debug.Assert(Expressions[0].IsPlaceholder(), "Singleton ??-chain expected to consist of placeholder."); var placeholder = (AstPlaceholder) Expressions[0]; placeholder.IdFunc().EmitValueCode(target); } else { Debug.Assert(Expressions[count - 1].IsPlaceholder(), "Last expression in ??-chain expected to be placeholder."); var placeholder = (AstPlaceholder) Expressions[count - 1]; var prefix = new AstCoalescence(File, Line, Column); prefix.Expressions.AddRange(Expressions.Take(count - 1)); //check for null (keep a copy of prefix on stack) var constLabel = _generateEndLabel(); var endLabel = _generateEndLabel(); prefix._emitCode(target, constLabel, StackSemantics.Value); target.EmitDuplicate(Position); target.Emit(Position,OpCode.check_null); target.EmitJumpIfFalse(Position, constLabel); //prefix is null, identity function target.EmitPop(Position); placeholder.IdFunc().EmitValueCode(target); target.EmitJump(Position, endLabel); //prefix is not null, const function target.EmitLabel(Position, constLabel); target.EmitCommandCall(Position, 1, Const.Alias); target.EmitLabel(Position, endLabel); } }
protected void EmitArguments(CompilerTarget target, bool duplicateLast, int additionalArguments) { Object lastArg = null; foreach (AstExpr expr in Arguments) { Debug.Assert(expr != null, "Argument list of get-set-complex contains null reference"); if (ReferenceEquals(lastArg, expr)) target.EmitDuplicate(Position); else expr.EmitValueCode(target); lastArg = expr; } var argc = Arguments.Count; if (duplicateLast && argc > 0) { target.EmitDuplicate(Position); if (argc + additionalArguments > 1) target.EmitRotate(Position, -1, argc + 1 + additionalArguments); } }
private void _emitCode(CompilerTarget target, string endLabel, StackSemantics stackSemantics) { for (var i = 0; i < _expressions.Count; i++) { var expr = _expressions[i]; // Value semantics: duplicate of previous, rejected value needs to be popped // Effect semantics: no duplicates were created in the first place if (i > 0 && stackSemantics == StackSemantics.Value) target.EmitPop(Position); //For value semantics, we always generate a value //For effect semantics, we only need the intermediate expressions to create a value StackSemantics needValue; if (stackSemantics == StackSemantics.Value || i < _expressions.Count - 1) needValue = StackSemantics.Value; else needValue = StackSemantics.Effect; expr.EmitCode(target, needValue); //The last element doesn't need special handling, control just // falls into the surrounding code with the correct value on top of the stack if (i + 1 >= _expressions.Count) continue; if(stackSemantics == StackSemantics.Value) target.EmitDuplicate(Position); target.Emit(Position,OpCode.check_null); target.EmitJumpIfFalse(Position, endLabel); } }