ek9_apply_guard_pattern
Rewrites the construct's head to 'if x <- f()' (or ':=?', or ':=' with an explicit 'then x?', as the source assignment dictates) and deletes the standalone assignment and the redundant 'x?' check; answers status, edits[] and summary, an unsafe or unsupported shape as conflicts[].
When to use it
Turn 'x <- f()' followed by 'if x?' into the EK9 guard 'if x <- f()' - one call with file and symbol:'x' (the variable), or line on the control line.
When not to use it
- There is no surrounding control construct yet - use
ek9_surround_withto wrap first. - You just want an expression pulled into a local (no gating intent) - use
ek9_extract_variable. - The lifted local must survive past the construct as per-instance state - use
ek9_introduce_field.
Details
No mode parameter - the head operator is DERIVED from the source: '<-' stays '<-', ':=?' stays ':=?' (both gate the body per PreFlowCanSkipBody), a blind ':='/'='/':' stays ':=' with the gate explicit ('if x := f() then x?', 'while x := f() then x? and (cond)') and is refused before switch/try/for/do (kind blind-assignment-cannot-gate). Per-construct fold: switch guards on the MATCH SUBJECT ('v <- getV()'+'switch v' -> 'switch v <- getV()'); try/function has no control so folds bare ('try r <- open()'); loops keep their control/iteration as a 'then' clause ('while x <- src() then cond', 'for x <- src() then item in coll') and the guard is evaluated ONCE at loop entry, not per iteration. A compound 'if x? and cond' (isSet on either side of a two-operand 'and') lifts with the other operand preserved as a 'then' residual; an 'or', a three-way 'and', or nested 'x?' stays a compound-control-not-supported conflict (other kinds: switch-subject-not-the-guard-var, already-a-guard).
Arguments
| Argument | Type | Required | What it is |
|---|---|---|---|
file | string | yes | The EK9 source file (workspace-relative; an absolute path inside the workspace is accepted). |
line | integer | IDE refinement: the 1-based line of the control construct's opening line (if/while/do-while/for/switch/try). Omit it and pass symbol. | |
symbol | string | The variable to lift into the guard ('customer'); the tool finds the control construct that tests it. Prefer this to line. |
It also takes the arguments every tool takes.
Recorded calls
Real calls, recorded against small projects and checked on every build - a changed answer fails it. 3 of the 10 recorded are shown.
Lift declaration dryrun
Request
{
"dryRun" : true,
"file" : "Guarding.ek9",
"line" : 16
}
Response
{
"conflicts" : [ ],
"edits" : [ {
"after" : " if name <- lookup(id)",
"before" : " if name?",
"endLine" : 16,
"file" : "Guarding.ek9",
"startLine" : 16,
"type" : "replace"
}, {
"before" : " name <- lookup(id)",
"endLine" : 15,
"file" : "Guarding.ek9",
"startLine" : 15,
"type" : "delete"
} ],
"meta" : {
"serverMs" : "<timing>"
},
"risk" : {
"crossesModuleBoundary" : false,
"estimatedSeverity" : "trivial",
"fileCount" : 1,
"lineCount" : 2,
...
Cut short here: 9 more lines. The whole recorded call.
Try resource guard
Request
{
"dryRun" : true,
"file" : "Guarding.ek9",
"line" : 16
}
Response
{
"conflicts" : [ ],
"edits" : [ {
"after" : " try config <- getConfig(id)",
"before" : " try",
"endLine" : 16,
"file" : "Guarding.ek9",
"startLine" : 16,
"type" : "replace"
}, {
"before" : " config <- getConfig(id)",
"endLine" : 15,
"file" : "Guarding.ek9",
"startLine" : 15,
"type" : "delete"
} ],
"meta" : {
"serverMs" : "<timing>"
},
"risk" : {
"crossesModuleBoundary" : false,
"estimatedSeverity" : "trivial",
"fileCount" : 1,
"lineCount" : 2,
...
Cut short here: 9 more lines. The whole recorded call.
Do while guard
Request
{
"dryRun" : true,
"file" : "Guarding.ek9",
"line" : 17
}
Response
{
"conflicts" : [ ],
"edits" : [ {
"after" : " do step <- initial(id)",
"before" : " do",
"endLine" : 17,
"file" : "Guarding.ek9",
"startLine" : 17,
"type" : "replace"
}, {
"before" : " step <- initial(id)",
"endLine" : 16,
"file" : "Guarding.ek9",
"startLine" : 16,
"type" : "delete"
} ],
"meta" : {
"serverMs" : "<timing>"
},
"risk" : {
"crossesModuleBoundary" : false,
"estimatedSeverity" : "trivial",
"fileCount" : 1,
"lineCount" : 2,
...
Cut short here: 9 more lines. The whole recorded call.
See also
- Show me in the IDE: Chapter 10: guards, reshaped
- Show me in the IDE: Lift into Guard