Skip to content

Algorithms for toy examples

Sewen Thy edited this page Oct 4, 2022 · 10 revisions

Non-local Control Flows

We define the type of statements that causes non-local control flow to be: $NLCF = \{\text{return}, \text{break}, \text{continue} \}$. While exception raising/throwing is a non-control local flow statement, it would have the same effect on the program if it were in the extracted function or the original function.

type loopName=String
type NLCFResult<A, B, C>:
| Ok of A
| RetT of B 
| BrkT of C * loopName
| ContT of loopName

ExtractToFunctionNonLocalControlFlow()
1.  Initialize config = ConfigFrom(file, startSelected, endSelected)
2.  If config.hasNLCFStatements() then
3.    extractedFunction.returnType = NLCFResult<extractedFunction.returnType, config.returnType, config.loopType>
4.    wrapFunctionTextWithOk(config)
5.    replaceNLCFStatements(config)
6.  endIf
7.  Initialize extractedFunction = config.functionText()
8.  config.currentFunction.addAfter("\n\n")
9.  config.currentFunction.addAfter(extractedFunction)
10. Initialize functionCallStatement = ""
11. If config.hasReturnVariable() then
12.   functionCallStatement.append("let {config.returnVariable} = ")
13. endIf
14. If config.hadNLCFStatements() then
15    functionCallStatement.append("match ")
16. endIf
17. If config.hasQualifier() then
18.   functionCallStatement.append(config.qualifier + ".")
19. endIf
20. functionCallStatement.append("{config.extractedFunctionName}({config.extractedFunctionParametersText})")
21. If config.hasNLCFStatements() then
22.   functionCallStatement.append(" {\n")
23.   functionCallStatement.append("Ok(val) => val,\n")
24.   If config.containsNLCFReturn() then
25.     functionCallStatement.append("RetT(val) => return val,\n")
26    endIf
27.   For each breakT in config.NLCFBreaks() do
28.     functionCallStatement.append("BrkT(val, {breakT.loopName}) => break {breakT.loopName} val,\n")
29.   endFor
30.   For each contT in config.NLCFContinues() do
31.     functionCallStatement.append("ContT({contT.loopName}) => continue {contT.loopName},\n")
32.   endFor
33.   functionCallStatement.append("}\n")
34. endIf
35. config.selectedElements = functionCallStatement
36. renameFunctionParameters(extractedFunction, config.parameters)

wrapFunctionTextWithOk(config)
1.  config.selectedText = "Ok({config.selectedText})"

getLoopNameFromBrkOrContElement(element)
1.  Initialize loopIdentifier = PsiTreeUtil.findChildOfType(element, PsiQuoteIdentifier.class)
2.  Initialize loopParent = PsiTrueUtil.findParentOfType(element, PsiLoop.class)
3.  If loopIdentifier in config.elements or loopParent in config.elements:
4.    return None
5.  endIf
6.  Initialize loopName = ""
7.  If loopIdentifier != Null then
8.    loopName = loopIdentifier.text
9.  Else
10.   loopName = "'loopName{config.NLCFBreaks().length}"
11.   Initialize newLoopParent = PsiElement.createLoopStmtFromText("{loopName}: {loopParent.text}")
12.   loopParent.replace(newLoopParent)
13. endIf
13. return Some(loopName)

replaceNLCFStatements(config)
1.  For each element in config.elements do
2.    match element with 
3.      RsRetExprImpl(_) =>
4.        Initialize returnVal = PsiTreeUtil.findChildOfType(element, PsiExpression.class)
5.        Initialize newReturn = PsiElement.createReturnStmtFromText("return RetT({returnVal.text})")
6.        element.replaceWith(newReturn)
7.        config.hasReturnVariable = true
8.      RsBreakExprImpl(_) =>
9.        Initialize returnVal = PsiTreeUtil.findChildOfType(element, PsiExpression.class)
10.	  Initialize loopName = 
11.         match getLoopNameFromBrkOrContElement(element) with
12.           Some(name) => name
13.	      None => continue
14.	    endMatch
15.       Initialize newBreak = PsiElement.createReturnStmtFromText("return BrkT({returnVal.text}, {loopName})")
16.	  element.replaceWith(newBreak)
17.       config.NLCFBreaks().append(element)
18.      RsContExprImpl(_) => 
19.        Initialize loopName = 
20.          match getLoopNameFromBrkOrContElement(element) with
21.	       Some(name) => name
22.	       None => continue
23.	     endMatch
24.	   Initialize newContinue = PsiElement.createReturnStmtFromText("return ContT({loopName})")
25.	   element.replaceWith(newContinue)
26.        config.NLCFContinues().append(element)
27.    endMatch
28. endFor