package gw.rating.flow.domain uses com.google.common.collect.ImmutableList uses gw.util.Pair uses java.util.concurrent.atomic.AtomicInteger class IfStatement extends BlockStatement { public final var Conditions : List> final var _codeSize: int private static final var _conditionCount: AtomicInteger as ConditionCount = new AtomicInteger(0) override property get CodeSize(): int { return _codeSize } construct(cod : List>) { this(cod, null) } construct(cod : List>, aHighlightElement: RateRoutineHighlightElement) { super(ImmutableList.copyOf(cod*.Second)) Conditions = ImmutableList.copyOf(cod) Conditions.each(\cond -> { cond.Second.Parent = this }) _highlightElement = aHighlightElement _codeSize = cod*.First*.CodeSize.sum() + super.CodeSize /* Accounts for the statements, cod*.Second */ } override function generate(generationContext: GenerationContext) { _start = generationContext.beginCodeGen() addLocalVariableDeclarations(generationContext) if (generationContext.WorksheetsEnabled) { generateWrapped(generationContext) } else { generateUnwrapped(generationContext) } _end = generationContext.endCodeGen() } override function getOffendingOperand(issue: gw.lang.parser.IParseIssue) : CalcStepOperand { return Conditions.firstWhere(\ c -> c.First.Start.First <= issue.Line and c.First.End.First >= issue.Line and c.First.Start.Second <= issue.Column and c.First.End.Second >= issue.Column).First } override function getOffendingSubStatement(issue: gw.lang.parser.IParseIssue) : Statement { var stmt = (Conditions.firstWhere(\ p -> p.Second.Start.First <= issue.Line and p.Second.End.First >= issue.Line)).Second if (stmt == null) { return this } return stmt.getOffendingSubStatement(issue) } /** * This should generate something like: * * _log.beginConditional() * * var $$cond0 = CONDITION * _log.setConditionalResult($$cond0) * * if ($$cond0) { * STATEMENT * } else { * _log.endConditional() * * var $$cond1: boolean * ... * } * * _log.endConditional() * * We don't need to worry about exceptions being thrown in the midst of evaluating a condition or while executing a * branch. If that happens, worksheet logging stops. The worksheet may be left with the wrong entry container and * operand container, but that shouldn't matter. After an exception, the worksheet contents should only be accessed * via the root container and not the entry container or the operand container. * * @param generationContext */ private function generateWrapped(generationContext: GenerationContext) { var elseSeen = false var closeBraceCount = 0 for (cond in Conditions index i) { if (elseSeen) { throw new IllegalStateException("Cannot have if, elseif or else after else") } if (cond.First == null) { generationContext.append(" else {\n") generationContext.WorksheetHelper.endConditional(:isEndif = false) generationContext.WorksheetHelper.logElse() generationContext.append('\n') cond.Second.generate(generationContext) generationContext.appendNewlineIfNeeded().append("}\n") elseSeen = true } else if (i > 0) { generationContext.append(" else {\n") generationContext.WorksheetHelper.endConditional(:isEndif = false) generateWrapped(generationContext, cond, i) closeBraceCount++ } else { generateWrapped(generationContext, cond, i) } } if (not elseSeen) { generationContext.append('\n') } generationContext.append("}\n".repeat(closeBraceCount)) generationContext.WorksheetHelper.endConditional(:isEndif = true) } private function generateUnwrapped(generationContext: GenerationContext) { // now append if (condition1) { stmt } // elseif (condition2) { stmt } etc. var elseSeen = false for (cond in Conditions index i) { if (elseSeen) { throw new IllegalStateException("Cannot have if, elseif or else after else") } if (cond.First == null) { generationContext.append(" else {\n") elseSeen = true } else { generationContext.append((i == 0) ? "if (" : " else if (") /** * This is for working around Java's "method too large" exception on some SBT/ERC rate routines. * We turn if, else, and else if bodies into lambdas and execute them. * The lambdas translate to inner classes and so have the effect of breaking down large rate routines. */ if (generationContext.CodegenStrategy == SIMPLE) { generationContext.append("(\\ -> {return ") cond.First.generate(generationContext) generationContext.append("})()") } else { cond.First.generate(generationContext) } generationContext.append(") {\n") } /** * This is for working around Java's "method too large" exception on some SBT/ERC rate routines. * We turn if, else, and else if bodies into lambdas and execute them. * The lambdas translate to inner classes and so have the effect of breaking down large rate routines. */ if (generationContext.CodegenStrategy == SIMPLE) { generationContext.append("(\\ -> {\n") cond.Second.generate(generationContext) generationContext.append("\n})()") } else { cond.Second.generate(generationContext) } generationContext.append("\n}") } } private function generateWrapped(generationContext: GenerationContext, condition: Pair, idx: int) { var conditionCount = _conditionCount.getAndIncrement() var conditionVarName = "$$cond${conditionCount}" var operand = condition.First var statement = condition.Second generateWrapped(generationContext, operand, idx, conditionVarName) generationContext.append("if (${conditionVarName}) {\n") statement.generate(generationContext) generationContext.appendNewlineIfNeeded().append("}") } /** * This should generate something like: * * _log.beginConditional() * var $$cond0 = CONDITION * _log.setConditionalResult($$cond0) * * @param operand the condition of the if or else if * @param conditionVarName variable name for condition */ private function generateWrapped(generationContext: GenerationContext, operand: CalcStepOperand, idx: int, conditionVarName: String) { generationContext.WorksheetHelper.beginConditional(idx) generationContext.append("var ${conditionVarName} = ") if (operand typeis ConditionalOperand) { operand.SubOperands.eachWithIndex(\elt, i -> { if (elt.OperatorType != null) { generationContext.append(' ').append(elt.OperatorType.LogicalOperator).append(' ') } elt.generate(generationContext) }) } else { operand.generate(generationContext) } generationContext.append('\n') generationContext.WorksheetHelper.setConditionalResult(conditionVarName) } }