diff --git a/lib/02_parsing/Lexer.ml b/lib/02_parsing/Lexer.ml index 2cf6124..0d30908 100644 --- a/lib/02_parsing/Lexer.ml +++ b/lib/02_parsing/Lexer.ml @@ -549,7 +549,8 @@ let scan_template_text t = | `Chr '\n' -> eat t; Buffer.add_char buf '\n'; - Buffer.contents buf + skip_indentation t; + loop buf t | `Chr '<' -> ( match peek t with | `Chr '/' -> Buffer.contents buf diff --git a/lib/02_parsing/Parser.ml b/lib/02_parsing/Parser.ml index ba543c6..6d292d8 100644 --- a/lib/02_parsing/Parser.ml +++ b/lib/02_parsing/Parser.ml @@ -238,7 +238,7 @@ module Rules = struct and parse_block t = let expression_annotations = parse_annotations t in let expr_start = t.token.location in - let* expression_desc = + let* expression_parenthesized, expression_desc = match t.token.typ with | Token.LEFT_BRACE -> next t; @@ -250,14 +250,22 @@ module Rules = struct in let statements = get_statements [] in t |> expect Token.RIGHT_BRACE; - Parsetree.P_BlockExpression statements |> Option.some + (false, Parsetree.P_BlockExpression statements) |> Option.some | _ -> let* expr = parse_expression t in - expr.Parsetree.expression_desc |> Option.some + (expr.Parsetree.expression_parenthesized, expr.Parsetree.expression_desc) + |> Option.some in let expr_end = t.token.location in let expression_loc = Location.merge ~s:expr_start ~e:expr_end () in - Parsetree.{ expression_desc; expression_loc; expression_annotations } |> Option.some + Parsetree. + { + expression_desc; + expression_loc; + expression_annotations; + expression_parenthesized; + } + |> Option.some and parse_tag ~name t = let start_token = t.token in @@ -339,6 +347,7 @@ module Rules = struct { expression_loc = location; expression_desc = Parsetree.P_Record []; + expression_parenthesized = false; expression_annotations = []; } | Some comment -> Parsetree.P_TemplateComment comment) @@ -538,7 +547,7 @@ module Rules = struct and parse_expression_part t = let expression_annotations = parse_annotations t in let expr_start = t.token.location in - let* expression_desc, expr_end = + let* expression_parenthesized, expression_desc, expr_end = match t.token.typ with (* PARSING PARENTHESIZED EXPRESSION *) | Token.LEFT_PAREN -> @@ -546,7 +555,8 @@ module Rules = struct let expr = parse_expression t in t |> expect Token.RIGHT_PAREN; let end_location = t.token.location in - expr |> Option.map (fun expr -> (expr.Parsetree.expression_desc, end_location)) + expr + |> Option.map (fun expr -> (true, expr.Parsetree.expression_desc, end_location)) (* PARSING RECORD or BLOCK EXPRESSION *) | Token.LEFT_BRACE -> let is_record = @@ -562,11 +572,11 @@ module Rules = struct in t |> expect Token.RIGHT_BRACE; let end_location = t.token.location in - Some (Parsetree.P_Record attrs, end_location)) + Some (false, Parsetree.P_Record attrs, end_location)) else let* expr = parse_block t in let end_location = t.token.location in - Some (expr.Parsetree.expression_desc, end_location) + Some (false, expr.Parsetree.expression_desc, end_location) (* PARSING FOR IN EXPRESSION *) | Token.KEYWORD_FOR -> ( next t; @@ -593,7 +603,8 @@ module Rules = struct "Expected expression as body of for loop" | Some body -> Some - ( Parsetree.P_ForInExpression + ( false, + Parsetree.P_ForInExpression { index; iterator; reverse; iterable = expr1; body }, end_location )) (* PARSING FN EXPRESSION *) @@ -626,10 +637,11 @@ module Rules = struct let end_location = t.token.location in next t; Option.some - @@ (Parsetree.P_ExternalFunction { parameters; name }, end_location) + @@ (false, Parsetree.P_ExternalFunction { parameters; name }, end_location) | _ -> let* body = t |> parse_block in - Option.some @@ (Parsetree.P_Function { parameters; body }, end_location)) + Option.some + @@ (false, Parsetree.P_Function { parameters; body }, end_location)) (* PARSING IF EXPRESSION *) | Token.KEYWORD_IF -> next t; @@ -658,6 +670,7 @@ module Rules = struct { expression_loc = statement_loc; expression_desc = P_BlockExpression [ s ]; + expression_parenthesized = false; expression_annotations = statement_annotations; } in @@ -686,19 +699,21 @@ module Rules = struct { expression_loc = statement_loc; expression_desc = P_BlockExpression [ s ]; + expression_parenthesized = false; expression_annotations = statement_annotations; }) else None in Option.some - @@ ( Parsetree.P_ConditionalExpression { condition; consequent; alternate }, + @@ ( false, + Parsetree.P_ConditionalExpression { condition; consequent; alternate }, end_location ) (* PARSING TAG EXPRESSION *) | Token.TAG name -> let end_location = t.token.location in next t; - parse_tag ~name t |> Option.map (fun tag -> (tag, end_location)) + parse_tag ~name t |> Option.map (fun tag -> (false, tag, end_location)) (* PARSING TEMPLATE EXPRESSION *) | Token.TEMPLATE_NEWLINE | Token.HTML_TEXT _ @@ -708,13 +723,14 @@ module Rules = struct | Token.HTML_DOCTYPE _ -> let* template_node = parse_template_node t in let end_location = t.token.location in - Option.some @@ (Parsetree.P_TemplateExpression template_node, end_location) + Option.some + @@ (false, Parsetree.P_TemplateExpression template_node, end_location) (* PARSING IDENTIFIER EXPRESSION *) | Token.IDENT_LOWER identifier -> let end_location = t.token.location in next t; Option.some - @@ (Parsetree.P_LowercaseIdentifierExpression identifier, end_location) + @@ (false, Parsetree.P_LowercaseIdentifierExpression identifier, end_location) | Token.IDENT_UPPER identifier -> ( let end_location = t.token.location in next t; @@ -732,10 +748,13 @@ module Rules = struct match get_path [ identifier ] with | [ identifier ] -> Option.some - @@ (Parsetree.P_UppercaseIdentifierExpression identifier, end_location) + @@ ( false, + Parsetree.P_UppercaseIdentifierExpression identifier, + end_location ) | path -> Option.some - @@ ( Parsetree.P_UppercaseIdentifierPathExpression path, + @@ ( false, + Parsetree.P_UppercaseIdentifierPathExpression path, t.prev_token.location )) (* PARSING VALUE EXPRESSION *) | Token.DOUBLE_QUOTE -> @@ -743,27 +762,27 @@ module Rules = struct let s = t |> Helpers.list ~fn:parse_string_template in let end_location = t.token.location in t |> expect Token.DOUBLE_QUOTE; - Option.some @@ (Parsetree.(P_String s), end_location) + Option.some @@ (false, Parsetree.(P_String s), end_location) | Token.INT i -> let end_location = t.token.location in next t; - Option.some @@ (Parsetree.(P_Int i), end_location) + Option.some @@ (false, Parsetree.(P_Int i), end_location) | Token.CHAR c -> let end_location = t.token.location in next t; - Option.some @@ (Parsetree.(P_Char c), end_location) + Option.some @@ (false, Parsetree.(P_Char c), end_location) | Token.FLOAT f -> let end_location = t.token.location in next t; - Option.some @@ (Parsetree.(P_Float f), end_location) + Option.some @@ (false, Parsetree.(P_Float f), end_location) | Token.KEYWORD_TRUE -> let end_location = t.token.location in next t; - Option.some @@ (Parsetree.(P_Bool true), end_location) + Option.some @@ (false, Parsetree.(P_Bool true), end_location) | Token.KEYWORD_FALSE -> let end_location = t.token.location in next t; - Option.some @@ (Parsetree.(P_Bool false), end_location) + Option.some @@ (false, Parsetree.(P_Bool false), end_location) | Token.LEFT_BRACK -> next t; let expressions = @@ -771,11 +790,20 @@ module Rules = struct in let end_location = t.token.location in expect Token.RIGHT_BRACK t; - Option.some @@ (Parsetree.(P_Array expressions), end_location) - | _ -> parse_unary_expression t |> Option.map (fun expr -> (expr, t.token.location)) + Option.some @@ (false, Parsetree.(P_Array expressions), end_location) + | _ -> + parse_unary_expression t + |> Option.map (fun expr -> (false, expr, t.token.location)) in let expression_loc = Location.merge ~s:expr_start ~e:expr_end () in - Parsetree.{ expression_desc; expression_loc; expression_annotations } |> Option.some + Parsetree. + { + expression_desc; + expression_loc; + expression_annotations; + expression_parenthesized; + } + |> Option.some and parse_binary_operator t = match t.token.typ with @@ -850,7 +878,13 @@ module Rules = struct Location.merge ~s:expression_start ~e:expression_end () in let left = - Parsetree.{ expression_desc; expression_loc; expression_annotations } + Parsetree. + { + expression_desc; + expression_loc; + expression_annotations; + expression_parenthesized = false; + } in loop ~left ~prio t)) in diff --git a/lib/02_parsing/Parsetree.ml b/lib/02_parsing/Parsetree.ml index 86e6fb4..f6388eb 100644 --- a/lib/02_parsing/Parsetree.ml +++ b/lib/02_parsing/Parsetree.ml @@ -68,6 +68,7 @@ and string_template_desc = and expression = { expression_loc : Pinc_Diagnostics.Location.t; expression_desc : expression_desc; + expression_parenthesized : bool; expression_annotations : annotation list; } diff --git a/lib/pinc_format/Formatter.ml b/lib/pinc_format/Formatter.ml index eee13bd..c3a7b53 100644 --- a/lib/pinc_format/Formatter.ml +++ b/lib/pinc_format/Formatter.ml @@ -189,7 +189,7 @@ and format_tag (tag : Parsetree.tag_desc) = let transformer = match tag.transformer with | None -> empty - | Some expr -> space ^^ repeat 2 colon ^^ space ^^ format_expression expr + | Some expr -> space ^^ twice colon ^^ space ^^ format_expression expr in sharp ^^ format_tag_kind tag.tag ^^ arguments ^^ transformer @@ -218,7 +218,7 @@ and format_binary_expression left op right = let l = format_expression left in let r = format_expression right in match op with - | Parsetree.Operators.Binary.EQUAL -> l ^^ space ^^ repeat 2 equals ^^ space ^^ r + | Parsetree.Operators.Binary.EQUAL -> l ^^ space ^^ twice equals ^^ space ^^ r | Parsetree.Operators.Binary.NOT_EQUAL -> l ^^ space ^^ bang ^^ equals ^^ space ^^ r | Parsetree.Operators.Binary.GREATER -> l ^^ space ^^ rangle ^^ space ^^ r | Parsetree.Operators.Binary.GREATER_EQUAL -> @@ -229,18 +229,18 @@ and format_binary_expression left op right = | Parsetree.Operators.Binary.MINUS -> l ^^ space ^^ minus ^^ space ^^ r | Parsetree.Operators.Binary.TIMES -> l ^^ space ^^ star ^^ space ^^ r | Parsetree.Operators.Binary.DIV -> l ^^ space ^^ slash ^^ space ^^ r - | Parsetree.Operators.Binary.POW -> l ^^ space ^^ repeat 2 star ^^ space ^^ r + | Parsetree.Operators.Binary.POW -> l ^^ space ^^ twice star ^^ space ^^ r | Parsetree.Operators.Binary.MODULO -> l ^^ space ^^ percent ^^ space ^^ r - | Parsetree.Operators.Binary.CONCAT -> l ^^ space ^^ repeat 2 plus ^^ space ^^ r - | Parsetree.Operators.Binary.AND -> l ^^ space ^^ repeat 2 ampersand ^^ space ^^ r - | Parsetree.Operators.Binary.OR -> l ^^ space ^^ repeat 2 bar ^^ space ^^ r + | Parsetree.Operators.Binary.CONCAT -> l ^^ space ^^ twice plus ^^ space ^^ r + | Parsetree.Operators.Binary.AND -> l ^^ space ^^ twice ampersand ^^ space ^^ r + | Parsetree.Operators.Binary.OR -> l ^^ space ^^ twice bar ^^ space ^^ r | Parsetree.Operators.Binary.DOT_ACCESS -> l ^^ dot ^^ r | Parsetree.Operators.Binary.BRACKET_ACCESS -> l ^^ brackets r | Parsetree.Operators.Binary.FUNCTION_CALL -> l ^^ parens r | Parsetree.Operators.Binary.PIPE -> l ^^ space ^^ bar ^^ rangle ^^ space ^^ r | Parsetree.Operators.Binary.ARRAY_ADD -> l ^^ space ^^ at ^^ space ^^ r - | Parsetree.Operators.Binary.MERGE -> l ^^ space ^^ repeat 2 at ^^ space ^^ r - | Parsetree.Operators.Binary.RANGE -> l ^^ repeat 2 dot ^^ r + | Parsetree.Operators.Binary.MERGE -> l ^^ space ^^ twice at ^^ space ^^ r + | Parsetree.Operators.Binary.RANGE -> l ^^ twice dot ^^ r | Parsetree.Operators.Binary.INCLUSIVE_RANGE -> l ^^ repeat 3 dot ^^ r and format_for_in ~index ~iterator ~reverse ~iterable ~body = @@ -277,6 +277,22 @@ and format_block statements = let statements = List.map (fun s -> format_statement s) statements in lbrace ^^ nest 2 (break 1 ^^ separate hardline statements) ^^ break 1 ^^ rbrace +and format_template_children children = + let had_newline = ref false in + let children = + match children with + | [] -> empty + | children -> + let len = List.length children in + concat + @@ List.mapi + (fun i x -> + let last = i = len - 1 in + format_template_node ~had_newline ~last x) + children + in + (!had_newline, children) + and format_html_template_node ~html_tag_identifier ~html_tag_attributes ~html_tag_children = let open_tag = @@ -292,29 +308,29 @@ and format_html_template_node ~html_tag_identifier ~html_tag_attributes ~html_ta in let close_tag = match html_tag_children with - | [] -> char ' ' ^^ slash ^^ rangle + | [] -> space ^^ slash ^^ rangle | _ -> langle ^^ slash ^^ string html_tag_identifier ^^ rangle in - let children = - match html_tag_children with - | [] -> empty - | children -> separate_map empty format_template_node children + let had_newline, children = format_template_children html_tag_children in + let end_line = + if had_newline then + ifflat empty hardline + else + empty in - group - (open_tag - ^^ nest 2 (ifflat empty hardline ^^ children) - ^^ ifflat empty hardline - ^^ close_tag) + group (open_tag ^^ nest 2 children ^^ end_line ^^ close_tag) and format_fragment_template_node ~fragement_children = let open_tag = langle ^^ rangle in - let children = concat_map format_template_node fragement_children in + let had_newline, children = format_template_children fragement_children in let close_tag = langle ^^ slash ^^ rangle in - group - (open_tag - ^^ nest 2 (ifflat empty hardline ^^ children) - ^^ ifflat empty hardline - ^^ close_tag) + let end_line = + if had_newline then + ifflat empty hardline + else + empty + in + open_tag ^^ nest 2 children ^^ end_line ^^ close_tag and format_component_template_node ~component_tag_identifier @@ -336,18 +352,19 @@ and format_component_template_node | [] -> space ^^ slash ^^ rangle | _ -> langle ^^ slash ^^ format_uppercase_id component_tag_identifier ^^ rangle in - let children = - match component_tag_children with - | [] -> empty - | children -> concat_map format_template_node children + let had_newline, children = format_template_children component_tag_children in + let end_line = + if had_newline then + ifflat empty hardline + else + empty in - group - (open_tag - ^^ nest 2 (ifflat empty hardline ^^ children) - ^^ ifflat empty hardline - ^^ close_tag) + open_tag ^^ nest 2 children ^^ end_line ^^ close_tag -and format_template_node (node : Parsetree.template_node) = +and format_template_node + ?(had_newline = ref false) + ?(last = false) + (node : Parsetree.template_node) = let annotations = format_annotations node.template_node_annotations in let desc = match node.template_node_desc with @@ -368,9 +385,14 @@ and format_template_node (node : Parsetree.template_node) = format_fragment_template_node ~fragement_children | P_ExpressionTemplateNode template_expression_node_expression -> braces (format_expression template_expression_node_expression) - | P_TextTemplateNode "" -> empty - | P_TextTemplateNode "\n" -> hardline - | P_TextTemplateNode s -> arbitrary_string s + | P_TextTemplateNode "\n" when last -> + had_newline := true; + empty + | P_TextTemplateNode s when last -> + had_newline := String.ends_with ~suffix:"\n" s; + let xs = String.split_on_char '\n' s in + separate2 hardline empty (List.map string xs) + | P_TextTemplateNode s -> separate hardline (lines s) in annotations ^^ desc @@ -403,9 +425,12 @@ and format_expression (exression : Parsetree.expression) = | P_UnaryExpression (op, expr) -> format_unary_expression op expr | P_BinaryExpression (left, op, right) -> format_binary_expression left op right in - annotations ^^ desc - -and format_comment_stmt s = format_comment s + annotations + ^^ + if exression.expression_parenthesized then + parens desc + else + desc and format_break_stmt i = let num = diff --git a/lib/pinc_format/Formatter.mli b/lib/pinc_format/Formatter.mli new file mode 100644 index 0000000..f0f8777 --- /dev/null +++ b/lib/pinc_format/Formatter.mli @@ -0,0 +1 @@ +val format : Pinc_Parser.parsetree -> string diff --git a/lib/pinc_format/dune b/lib/pinc_format/dune index 9dcb924..2c0d23f 100644 --- a/lib/pinc_format/dune +++ b/lib/pinc_format/dune @@ -2,4 +2,4 @@ (name Pinc_Format) (public_name pinc-lang.format) (flags :standard -open Pinc_Core) - (libraries pprint Pinc_Core Pinc_Source Pinc_Parser)) + (libraries pretty_expressive pprint Pinc_Core Pinc_Source Pinc_Parser)) diff --git a/test/format/data.pi b/test/format/data.pi index 1782441..7447869 100644 --- a/test/format/data.pi +++ b/test/format/data.pi @@ -55,7 +55,8 @@ component Component(label: "Long Name of $(c)", icon: "/images/icons/page-docs.s

diff --git a/test/format/run.t b/test/format/run.t index 725e886..864742e 100644 --- a/test/format/run.t +++ b/test/format/run.t @@ -24,11 +24,9 @@

  • {fruit}
  • }} - - {"Aliqua in elit sunt in anim culpa nostrud elit. + {"Aliqua in elit sunt in anim culpa nostrud elit. Elit voluptate nisi laborum est eu esse non exercitation minim. - Nisi ea enim minim quis."} - + Nisi ea enim minim quis."} } @@ -80,7 +78,8 @@