-
Notifications
You must be signed in to change notification settings - Fork 1
Algorithms for toy examples
Sewen Thy edited this page Oct 4, 2022
·
10 revisions
We define the type of statements that causes non-local control flow to be:
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