diff --git a/format/src/pretty_print.rs b/format/src/pretty_print.rs index c65f46908b..d86a8b151c 100644 --- a/format/src/pretty_print.rs +++ b/format/src/pretty_print.rs @@ -203,9 +203,12 @@ where Expr::IfElse(ref body, ref if_true, ref if_false) => { let space = newline(arena, expr); chain![arena; - arena.text("if ").append(pretty(body)).group(), - arena.space(), - "then", + chain![arena; + "if ", + pretty(body), + arena.space(), + "then" + ].group(), space.clone().append(pretty(if_true)).nest(INDENT).group(), space.clone(), "else", @@ -480,7 +483,7 @@ where self.pretty_expr_(bound.span.end(), body) ], Expr::MacroExpansion { ref original, .. } => { - return self.pretty_expr_(previous_end, original) + return self.pretty_expr_(previous_end, original); } Expr::Error(_) => arena.text(""), }; @@ -522,9 +525,12 @@ where let arena = self.arena; match if_false.value { Expr::IfElse(ref body, ref if_true, ref if_false) => chain![arena; - arena.text(" if ").append(pretty(body)).group(), - arena.space(), - "then", + chain![arena; + " if ", + pretty(body), + arena.space(), + "then" + ].group(), space.clone().append(pretty(if_true)).nest(INDENT).group(), space.clone(), "else", @@ -1026,7 +1032,7 @@ fn newline<'a, Id, A>( fn forced_new_line(expr: &SpannedExpr) -> bool { match expr.value { - Expr::LetBindings(..) | Expr::Match(..) | Expr::TypeBindings(..) => true, + Expr::LetBindings(..) | Expr::Match(..) | Expr::TypeBindings(..) | Expr::Do(..) => true, Expr::Lambda(ref lambda) => forced_new_line(&lambda.body), Expr::Tuple { ref elems, .. } => elems.iter().any(forced_new_line), Expr::Record { diff --git a/format/tests/pretty_print.rs b/format/tests/pretty_print.rs index 244a0e6eab..30fc2f61ee 100644 --- a/format/tests/pretty_print.rs +++ b/format/tests/pretty_print.rs @@ -373,15 +373,43 @@ test abc 1232 "" #[test] fn if_else_multiple() { let expr = r#" -if x -then y -else if z -then w +if x then y +else if z then w else 0 "#; assert_diff!(&format_expr(expr).unwrap(), expr, " ", 0); } +#[test] +fn if_else_multiple_let_multiline_1() { + let expr = r#" +if x then + f 123 483 +else if z then + "12312" +else + do x = 1 + x +"#; + assert_diff!(&format_expr(expr).unwrap(), expr, " ", 0); +} + +#[test] +fn if_else_multiple_multiline_2() { + let expr = r#" +if x then + do z = io + io +else if z then + type X = Int + 123 +else + let x = 1 + x +"#; + assert_diff!(&format_expr(expr).unwrap(), expr, " ", 0); +} + #[test] fn fully_break_function_type() { let expr = r#" diff --git a/repl/src/repl.glu b/repl/src/repl.glu index 5f0f5f458a..427282b60b 100644 --- a/repl/src/repl.glu +++ b/repl/src/repl.glu @@ -13,7 +13,7 @@ let { ReadlineError } = import! rustyline_types let { Color } = import! repl_types let repl_prim = import! repl.prim let { (<<), (<|) } = import! std.function -let effect @ { Eff, Reader, Lift, ask, ? } = import! std.effect +let effect @ { Eff, Reader, Lift, ask, asks, ? } = import! std.effect let { Applicative, wrap, (*>) } = import! std.applicative let { flat_map, (>>=) } = import! std.monad let { foldl } = import! std.foldable @@ -21,19 +21,38 @@ let { foldl } = import! std.foldable let { (<>) } = import! std.prelude let (++) = (<>) -type ReplEffect r a = [| reader : Reader CpuPool, lift : Lift IO | r |] a - -let run_interruptible_io cpu_pool action : CpuPool - -> IO String +rec +type ReplEffect r a = [| reader : Reader Repl, lift : Lift IO | r |] a +type Repl = { + commands : Commands, + editor : Editor, + cpu_pool : CpuPool, + color : Color, + prompt : String +} +type ReplAction = + | Continue + | Quit +type Cmd = { + name : String, + alias : String, + info : String, + action : String -> Eff (ReplEffect r) ReplAction +} +type Commands = Map String Cmd +in +let run_interruptible_io action : + IO String -> Eff (ReplEffect r) (Result String String) = + do cpu_pool = asks (\r -> r.cpu_pool) do eval_thread = effect.lift <| thread.new_thread () let interruptible_action = repl_prim.finish_or_interrupt cpu_pool eval_thread action effect.lift <| io.catch (io.functor.map Ok interruptible_action) (wrap << Err) -let load_file cpu_pool filename : CpuPool -> String -> Eff (ReplEffect r) String = +let load_file filename : String -> Eff (ReplEffect r) String = let last_slash = match string.rfind filename "/" with | None -> 0 @@ -44,35 +63,24 @@ let load_file cpu_pool filename : CpuPool -> String -> Eff (ReplEffect r) String do result = io.load_script modulename expr wrap result - do result = run_interruptible_io cpu_pool action + do result = run_interruptible_io action match result with | Ok x -> wrap x | Err x -> wrap x -let run_file cpu_pool filename : CpuPool -> String -> Eff (ReplEffect r) () = +let run_file filename : String -> Eff (ReplEffect r) () = let action = do expr = io.read_file_to_string filename do result = io.run_expr expr wrap (result.value ++ " : " ++ result.typ) - do result = run_interruptible_io cpu_pool action + do result = run_interruptible_io action effect.lift <| (match result with | Ok _ -> io.println "" | Err x -> io.println x) -type ReplAction = - | Continue - | Quit -type Cmd = { - name : String, - alias : String, - info : String, - action : String -> Eff (ReplEffect r) ReplAction -} -type Commands = Map String Cmd - -let make_commands cpu_pool : CpuPool -> Commands = +let commands : Commands = let print_result result = effect.lift <| (match result with @@ -121,14 +129,14 @@ let make_commands cpu_pool : CpuPool -> Commands = info = "Loads the file at \'folder/module.ext\' and stores it at \'module\'", action = \arg -> - (load_file cpu_pool arg >>= (effect.lift << io.println)) + (load_file arg >>= (effect.lift << io.println)) *> wrap Continue, }, { name = "script", alias = "s", info = "Runs the script at `FILENAME`", - action = \arg -> run_file cpu_pool arg *> wrap Continue, + action = \arg -> run_file arg *> wrap Continue, }, { name = "debug", @@ -190,45 +198,31 @@ let do_command commands line : Commands -> String -> Eff (ReplEffect r) ReplActi effect.lift <| io.println "Expected a command such as `:h`" *> wrap Continue -let store line : String -> IO ReplAction = - let line = string.trim line - match string.find line " " with - | Some bind_end -> - let binding = string.slice line 0 bind_end - let expr = string.slice line bind_end (string.len line) - io.load_script binding expr *> wrap Continue - | None -> io.println "Expected binding in definition" *> wrap Continue - -type Repl = { - commands : Commands, - editor : Editor, - cpu_pool : CpuPool, - color : Color, - prompt : String -} +let loop _ : () -> Eff (ReplEffect r) () = + do repl = ask -let loop repl : Repl -> Eff (ReplEffect r) () = let run_line line = if string.is_empty (string.trim line) then wrap Continue else if string.starts_with line ":" then do_command repl.commands line else + do cpu_pool = asks (\r -> r.cpu_pool) let action = do eval_thread = thread.new_thread () let eval_action = repl_prim.eval_line repl.color line - repl_prim.finish_or_interrupt repl.cpu_pool eval_thread eval_action + repl_prim.finish_or_interrupt cpu_pool eval_thread eval_action effect.lift <| io.catch action io.println *> wrap Continue do line_result = effect.lift <| rustyline.readline repl.editor repl.prompt match line_result with | Err Eof -> wrap () - | Err Interrupted -> loop repl + | Err Interrupted -> loop () | Ok line -> do continue = run_line line match continue with - | Continue -> loop repl + | Continue -> loop () | Quit -> do _ = effect.lift <| rustyline.save_history repl.editor wrap () @@ -237,8 +231,7 @@ let run color prompt : Color -> String -> IO () = do _ = io.println "gluon (:h for help, :q to quit)" do editor = rustyline.new_editor () do cpu_pool = repl_prim.new_cpu_pool 1 - let commands = make_commands cpu_pool let repl = { commands, editor, cpu_pool, color, prompt } - effect.run_lift (effect.run_reader cpu_pool (loop repl)) + effect.run_lift (effect.run_reader repl (loop ())) run diff --git a/std/parser.glu b/std/parser.glu index b90329b6a7..b4f96ec1de 100644 --- a/std/parser.glu +++ b/std/parser.glu @@ -151,10 +151,9 @@ let take1 predicate : (Char -> Bool) -> Parser String = let take_ stream2 = match uncons stream2 with | Some record -> - if predicate record.char - then take_ record.rest - else if stream.start == stream2.start - then Err { position = stream.start, message = "Unexpected token" } + if predicate record.char then take_ record.rest + else if stream.start == stream2.start then + Err { position = stream.start, message = "Unexpected token" } else Ok { value = string.slice stream.buffer stream.start stream2.start, buffer = stream2, @@ -220,8 +219,7 @@ let one_of s : String -> Parser Char = False else let c = string.char_at s i - if first == c - then True + if first == c then True else one_of_ (i + char.len_utf8 c) one_of_ 0) <|> fail ("Expected one of `" <> s <> "`") @@ -240,7 +238,8 @@ let sep_by parser sep : Parser a -> Parser b -> Parser (List a) = /// Like `sep_by1` but applies the function returned by `op` on the left fold of successive parses let chainl1 p op : Parser a -> Parser (a -> a -> a) -> Parser a = do l = p - let rest x = ( + let rest x = + ( do f = op do r = p rest (f x r)) <|> wrap x diff --git a/std/stream.glu b/std/stream.glu index b6e5d5b243..4ae135ad15 100644 --- a/std/stream.glu +++ b/std/stream.glu @@ -28,8 +28,7 @@ let from f : (Int -> Option a) -> Stream a = let of xs : Array a -> Stream a = from (\i -> - if i < array.len xs - then Some (array.index xs i) + if i < array.len xs then Some (array.index xs i) else None) let repeat x : a -> Stream a = diff --git a/std/test.glu b/std/test.glu index a6181fd5d9..8725d47646 100644 --- a/std/test.glu +++ b/std/test.glu @@ -29,13 +29,11 @@ let group = Group let assert x = if x then () else error "Assertion failed" let assert_eq l r : [Show a] -> [Eq a] -> a -> a -> Eff [| writer : Test | r |] () = - if l == r - then wrap () + if l == r then wrap () else effect.tell (Cons ("Assertion failed: " <> show l <> " != " <> show r) Nil) let assert_neq l r : [Show a] -> [Eq a] -> a -> a -> Eff [| writer : Test | r |] () = - if l /= r - then wrap () + if l /= r then wrap () else effect.tell (Cons ("Assertion failed: " <> show l <> " == " <> show r) Nil) rec let run_raw test : Eff [| writer : Test | r |] a -> Eff [| | r |] (List String) =