diff --git a/src/core/grammar/Padding.re b/src/core/grammar/Padding.re index 9133f654..9df0d5ea 100644 --- a/src/core/grammar/Padding.re +++ b/src/core/grammar/Padding.re @@ -4,29 +4,29 @@ open Ppx_yojson_conv_lib.Yojson_conv.Primitives; // specifies preferred whitespace padding around a token [@deriving (show({with_path: false}), sexp, yojson, ord)] type t = { - // whether to pad token with spaces in horizontal layout - h: (bool, bool), - // whether to pad token with newlines in vertical layout + // whether to pad token with space in horizontal layout // (generally (true, true) but eg (false, true) for commas) - v: (bool, bool), - // whether to indent contents of the following cell + space: (bool, bool), + // whether vertical layout should be preferred on either side + break: (bool, bool), + // whether to indent contents of the following cell in vertical layout indent: bool, }; -let none = {h: (false, false), v: (false, false), indent: false}; +let none = {space: (false, false), break: (false, false), indent: false}; -let kw = (~l=true, ~r=true, ~indent=true, ()) => { - h: (l, r), - v: (l, r), +let kw = (~space=(true, true), ~break=(false, false), ~indent=true, ()) => { + space, + break, indent, }; -let op = (~l=true, ~r=true, ~indent=true, ()) => { - h: (l, r), - v: (l, r), +let op = (~space=(true, true), ~break=(false, false), ~indent=true, ()) => { + space, + break, indent, }; let brc = (side: Dir.t) => { - h: (false, false), - v: Dir.pick(side, ((false, true), (true, false))), + space: (false, false), + break: (false, false), indent: Dir.pick(side, (true, false)), }; diff --git a/src/core/material/Grout.re b/src/core/material/Grout.re index 053da6ae..15a046a2 100644 --- a/src/core/material/Grout.re +++ b/src/core/material/Grout.re @@ -8,7 +8,7 @@ module T = { let in_ = s => (s, Tip.(Conc, Conc)); let padding = ((_, (l, r)): t) => { let (l, r) = Tip.(is_conc(l), is_conc(r)); - Padding.op(~l, ~r, ~indent=r, ()); + Padding.op(~space=(l, r), ~indent=r, ()); }; let all = s => [op(s), pre(s), pos(s), in_(s)]; }; diff --git a/src/core/parser/Linter.re b/src/core/parser/Linter.re index 80d4d820..00e4a1c1 100644 --- a/src/core/parser/Linter.re +++ b/src/core/parser/Linter.re @@ -1,5 +1,6 @@ -let pad_wrap = (c: Cell.t) => { - let w = Wald.of_tok(Token.mk(~text=" ", Mtrl.Space(White(Sys)))); +let pad_wrap = (~break=false, c: Cell.t) => { + let text = break ? "\n" : " "; + let w = Wald.of_tok(Token.mk(~text, Mtrl.Space(White(Sys)))); let m = { // this choice only matters when c has caret let (l, r) = Meld.(mk(~l=c, w), mk(w, ~r=c)); @@ -11,7 +12,7 @@ let pad_wrap = (c: Cell.t) => { | Navigating => l }; }; - // let m = pad_r ? Meld.mk(~l=c, w) : Meld.mk(w, ~r=c); + // let m = spc_r ? Meld.mk(~l=c, w) : Meld.mk(w, ~r=c); // let m = Meld.mk(~l=c, w); Cell.put(m); }; @@ -33,11 +34,15 @@ let rec repad = (~l=Delim.root, ~r=Delim.root, c: Cell.t) => { |> Cell.put; | Some(_) when Cell.has_clean_cursor(c) => Cell.mark_clean(c) | Some(_) => - let (_, pad_l) = Delim.padding(l).h; - let (pad_r, _) = Delim.padding(r).h; + let (_, spc_l) = Delim.padding(l).space; + let (_, brk_l) = Delim.padding(l).break; + let (spc_r, _) = Delim.padding(r).space; + let (brk_r, _) = Delim.padding(r).break; + let no_pad = !(spc_l || spc_r || brk_l || brk_r); + let break = brk_l || brk_r; switch (Cell.get(c)) { - | None when !pad_l && !pad_r => c - | None => pad_wrap(c) + | None when no_pad => c + | None => pad_wrap(~break, c) | Some(m) => let pruned = Meld.to_chain(m) @@ -45,7 +50,7 @@ let rec repad = (~l=Delim.root, ~r=Delim.root, c: Cell.t) => { (c, tok: Token.t, acc) => { let found_space = Result.is_ok(Chain.unlink(acc)); switch (tok.mtrl) { - | Space(White(Sys)) when found_space || !pad_l && !pad_r => + | Space(White(Sys)) when found_space || no_pad => Chain.map_hd(Cell.Space.merge(c, ~fill=Cell.empty), acc) | _ => Chain.link(c, tok, acc) }; @@ -54,8 +59,8 @@ let rec repad = (~l=Delim.root, ~r=Delim.root, c: Cell.t) => { ); switch (Chain.unlink(pruned)) { | Ok(_) => Cell.put(Meld.of_chain(pruned)) - | Error(c) when !pad_l && !pad_r => c - | Error(c) => pad_wrap(c) + | Error(c) when no_pad => c + | Error(c) => pad_wrap(~break, c) }; }; }; diff --git a/src/hazel/Grammar.re b/src/hazel/Grammar.re index ef34b361..d87e2f2c 100644 --- a/src/hazel/Grammar.re +++ b/src/hazel/Grammar.re @@ -15,18 +15,19 @@ let t = (lbl: Label.t) => Regex.atom(Sym.t(lbl)); let nt = (srt: Sort.t) => Regex.atom(Sym.nt(srt)); let c = (~p=Padding.none, s) => t(Label.const(~padding=p, s)); -let kw = (~l=true, ~r=true, ~indent=true) => - c(~p=Padding.kw(~l, ~r, ~indent, ())); -let op = (~l=true, ~r=true, ~indent=true) => - c(~p=Padding.op(~l, ~r, ~indent, ())); +let kw = (~space=(true, true), ~break=(false, false), ~indent=true) => + c(~p=Padding.kw(~space, ~break, ~indent, ())); +let op = (~space=(true, true), ~break=(false, false), ~indent=true) => + c(~p=Padding.op(~space, ~break, ~indent, ())); let brc = (side: Dir.t) => c(~p=Padding.brc(side)); +let comma = op(~space=(false, true), ","); +let comma_sep = atom => seq([atom, Star(seq([comma, atom]))]); + module Typ = { let sort = Sort.of_str("Typ"); let typ = nt(sort); - let comma_sep = seq([typ, Star(seq([op(~l=false, ","), typ]))]); - let operand = alt([ c("Int"), @@ -36,7 +37,7 @@ module Typ = { //List type seq([c("list"), brc(L, "("), typ, brc(R, ")")]), //Tuple type - seq([brc(L, "("), comma_sep, brc(R, ")")]), + seq([brc(L, "("), comma_sep(typ), brc(R, ")")]), ]); let tbl = [ @@ -53,8 +54,6 @@ module Pat = { let sort = Sort.of_str("Pat"); let pat = nt(sort); - let comma_sep = seq([pat, Star(seq([op(~l=false, ","), pat]))]); - let bool_lit = alt([c("true"), c("false")]); let operand = alt([ @@ -64,8 +63,8 @@ module Pat = { bool_lit, //Constructor t(Id_upper), - seq([brc(L, "("), comma_sep, brc(R, ")")]), - seq([brc(L, "["), comma_sep, brc(R, "]")]), + seq([brc(L, "("), comma_sep(pat), brc(R, ")")]), + seq([brc(L, "["), comma_sep(pat), brc(R, "]")]), //Wild c("_"), ]); @@ -85,20 +84,30 @@ module Exp = { let sort = Sort.of_str("Exp"); let exp = nt(sort); - [@warning "-32"] - let comma_sep = seq([exp, Star(seq([op(~l=false, ","), exp]))]); - - let rul = seq([op("|"), nt(Pat.sort), op("=>"), exp]); let bool_lit = alt([c("true"), c("false")]); + let rul = + seq([op(~break=(true, false), "|"), nt(Pat.sort), op("=>"), exp]); + let case = seq([kw(~space=(false, true), "case"), exp, rul, star(rul)]); + + let let_ = + seq([ + kw("let", ~space=(false, true)), + nt(Pat.sort), + op("="), + exp, + kw("in", ~break=(false, true), ~indent=false), + exp, + ]); + let operand = alt([ t(Int_lit), t(Float_lit), t(Id_lower), bool_lit, - seq([brc(L, "("), comma_sep, brc(R, ")")]), - seq([brc(L, "["), comma_sep, brc(R, "]")]), + seq([brc(L, "("), comma_sep(exp), brc(R, ")")]), + seq([brc(L, "["), comma_sep(exp), brc(R, "]")]), ]); let op_alt = ss => alt(List.map(op, ss)); @@ -108,22 +117,24 @@ module Exp = { let tbl = [ //case - p(seq([kw(~l=false, "case"), exp, rul, star(rul)])), + p(case), //let + p(let_), + //fun + p( + seq([kw(~space=(false, true), "fun"), nt(Pat.sort), op("->"), exp]), + ), + //if p( seq([ - kw(~l=false, "let"), - nt(Pat.sort), - op("="), + kw(~space=(false, true), "if"), exp, - kw("in", ~indent=false), + kw("then"), + exp, + kw("else"), exp, ]), ), - //fun - p(seq([kw(~l=false, "fun"), nt(Pat.sort), op("->"), exp])), - //if - p(seq([kw(~l=false, "if"), exp, kw("then"), exp, kw("else"), exp])), //Math operations p(~a=L, seq([exp, add_op, exp])), p(~a=L, seq([exp, mult_op, exp])),