Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support multi-line if-then-else #6408

Open
Tracked by #11442
jdunkerley opened this issue Apr 25, 2023 · 3 comments
Open
Tracked by #11442

Support multi-line if-then-else #6408

jdunkerley opened this issue Apr 25, 2023 · 3 comments
Assignees

Comments

@jdunkerley
Copy link
Member

jdunkerley commented Apr 25, 2023

Currently we can do:

if a==b then action else
    anotheraction

or

if a==b then
    action

It would be good to allow:

if a==b then
    action
else
    anotheraction

(we currently do this by using case a=b of to achieve similar results).

@jdunkerley
Copy link
Member Author

Will need some help from @kazcw

@JaroslavTulach
Copy link
Member

To debug the tests one has to:

Change to debug = 2 in [profile.test] section of the root Cargo.toml to see the local variables.

The handling of if_then and also _else is happening in fn if_body(segments: NonEmptyVec<MatchedSegment>) in built_in.rs. Simple one line if True then 0 else 1 sends in three segments. However trying to:

enso$ git diff lib/rust/parser/debug/tests/parse.rs
diff --git lib/rust/parser/debug/tests/parse.rs lib/rust/parser/debug/tests/parse.rs
index 4a22c36cc5..e6470a4eae 100644
--- lib/rust/parser/debug/tests/parse.rs
+++ lib/rust/parser/debug/tests/parse.rs
@@ -102,6 +102,23 @@ fn else_block() {
                           ((Ident else) (BodyBlock #((Ident False))))))]);
 }
 
+#[test]
+fn true_else_blocks() {
+    #[rustfmt::skip]
+    let lines = vec![
+        "if True then",
+        "    0",
+        "else",
+        "    1",
+    ];
+    let text = &lines.join("\n");
+    let expected = block![
+        (MultiSegmentApp #(((Ident if) (Ident True))
+                           ((Ident then) (BodyBlock #((Number () "0" ()))))
+                           ((Ident else) (BodyBlock #((Number () "0" ()))))))];
+    test(text, expected);
+}
+
 
 // === Comments ===
 

triggers just the if_then macro (and sends just two segments) as macro processing is terminated by resolvers.rs finish_current_line which has no idea there is going to be else somewhere below. else is then treated as a separate identifier invoked with the 1 block:

(BodyBlock #((MultiSegmentApp #(((Ident if) (Ident True)) ((Ident then)
(BodyBlock #((Number () \"0\" ()))))))
(ArgumentBlockApplication (Ident else) #((Number () \"1\" ())))))

I got an idea to disable the if_then macro by

enso$ git diff lib/rust/parser/src/macros/built_in.rs
diff --git lib/rust/parser/src/macros/built_in.rs lib/rust/parser/src/macros/built_in.rs
index 1f789687af..b6eecb4c8c 100644
--- lib/rust/parser/src/macros/built_in.rs
+++ lib/rust/parser/src/macros/built_in.rs
@@ -19,7 +19,7 @@ pub fn all() -> resolver::MacroMap {
 /// Built-in macro definitions that match anywhere in an expression.
 fn expression() -> resolver::SegmentMap<'static> {
     let mut macro_map = resolver::SegmentMap::default();
-    macro_map.register(if_then());
+//    macro_map.register(if_then());
     macro_map.register(if_then_else());
     macro_map.register(group());
     macro_map.register(lambda());

that prevents the first line to be recognized as if_then macro, but of course, it doesn't recognize multi line if_then_else either.

@radeusgd
Copy link
Member

radeusgd commented Dec 4, 2024

Just adding to that to clarify that if possible it would be best to also be able to 'chain' multiple conditions without introducing additional indentation, e.g.:

if cond1 then
    ...
else if cond2 then
    ...
else if cond3 then
    ...
else
    ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: 📤 Backlog
Development

No branches or pull requests

4 participants