diff --git a/lib/02_parsing/Ast.ml b/lib/02_parsing/Ast.ml index ff31796..85a0507 100644 --- a/lib/02_parsing/Ast.ml +++ b/lib/02_parsing/Ast.ml @@ -105,8 +105,8 @@ and expression_desc = | BlockExpression of statement list | ConditionalExpression of { condition : expression; - consequent : statement; - alternate : statement option; + consequent : expression; + alternate : expression option; } | UnaryExpression of Operators.Unary.t * expression | BinaryExpression of expression * Operators.Binary.t * expression diff --git a/lib/02_parsing/Parser.ml b/lib/02_parsing/Parser.ml index ab230f5..597af53 100644 --- a/lib/02_parsing/Parser.ml +++ b/lib/02_parsing/Parser.ml @@ -622,10 +622,34 @@ module Rules = struct let* condition = t |> parse_expression in let end_location = t.token.location in let _ = optional Token.RIGHT_PAREN t in - let* consequent = t |> parse_statement in + let* consequent = + match parse_statement t with + | None -> None + | Some { statement_loc = _; statement_desc = P_ExpressionStatement e } -> + Some e + | Some ({ statement_loc; _ } as s) -> + Some + Parsetree. + { + expression_loc = statement_loc; + expression_desc = P_BlockExpression [ s ]; + } + in let alternate = - if optional Token.KEYWORD_ELSE t then - t |> parse_statement + if optional Token.KEYWORD_ELSE t then ( + match + parse_statement t + with + | None -> None + | Some { statement_loc = _; statement_desc = P_ExpressionStatement e } -> + Some e + | Some ({ statement_loc; _ } as s) -> + Some + Parsetree. + { + expression_loc = statement_loc; + expression_desc = P_BlockExpression [ s ]; + }) else None in diff --git a/lib/02_parsing/Parsetree.ml b/lib/02_parsing/Parsetree.ml index 706fab6..6ce64eb 100644 --- a/lib/02_parsing/Parsetree.ml +++ b/lib/02_parsing/Parsetree.ml @@ -1,3 +1,5 @@ +module Operators = Operators + type uppercase_identifier = P_Uppercase_Id of (string * Pinc_Diagnostics.Location.t) and lowercase_identifier = P_Lowercase_Id of (string * Pinc_Diagnostics.Location.t) @@ -98,8 +100,8 @@ and expression_desc = | P_BlockExpression of statement list | P_ConditionalExpression of { condition : expression; - consequent : statement; - alternate : statement option; + consequent : expression; + alternate : expression option; } | P_UnaryExpression of Operators.Unary.t * expression | P_BinaryExpression of expression * Operators.Binary.t * expression diff --git a/lib/02_parsing/Transformer.ml b/lib/02_parsing/Transformer.ml index f6ade42..8fce0c1 100644 --- a/lib/02_parsing/Transformer.ml +++ b/lib/02_parsing/Transformer.ml @@ -359,8 +359,8 @@ and transform_for_in env ~index ~iterator ~reverse ~iterable ~body = and transform_conditional env ~condition ~consequent ~alternate = let env, condition = transform_expression env condition in - let env, consequent = transform_statement env consequent in - let env, alternate = Option.fold_map ~init:env ~f:transform_statement alternate in + let env, consequent = transform_expression env consequent in + let env, alternate = Option.fold_map ~init:env ~f:transform_expression alternate in (env, ConditionalExpression { condition; consequent; alternate }) and transform_block env statements = diff --git a/lib/pinc_backend/Interpreter.ml b/lib/pinc_backend/Interpreter.ml index 6d86134..2149579 100644 --- a/lib/pinc_backend/Interpreter.ml +++ b/lib/pinc_backend/Interpreter.ml @@ -1060,8 +1060,8 @@ and eval_if ~state ~condition ~alternate ~consequent = condition |> eval_expression ~state |> State.get_output |> Value.is_true in match (condition_matches, alternate) with - | true, _ -> consequent |> eval_statement ~state - | false, Some alt -> alt |> eval_statement ~state + | true, _ -> consequent |> eval_expression ~state + | false, Some alt -> alt |> eval_expression ~state | false, None -> state |> State.add_output @@ -1070,7 +1070,7 @@ and eval_if ~state ~condition ~alternate ~consequent = ~loc: (Location.merge ~s:condition.expression_loc - ~e:consequent.statement_loc + ~e:consequent.expression_loc ()) ()) diff --git a/lib/pinc_format/Formatter.ml b/lib/pinc_format/Formatter.ml index 111513b..c49093b 100644 --- a/lib/pinc_format/Formatter.ml +++ b/lib/pinc_format/Formatter.ml @@ -68,7 +68,27 @@ and format_array a = in brackets @@ group (separate (comma ^^ space) array ^^ ifflat empty (comma ^^ break 1)) -and format_record _r = empty (* TODO *) +and format_record = function + | [] -> braces empty + | lst -> + let lst = + List.map + (fun (key, (required, value)) -> + nest + 2 + (hardline + ^^ string key + ^^ (match required with + | `Optional -> qmark + | `Required -> empty) + ^^ colon + ^^ blank 1 + ^^ format_expression value)) + lst + in + lbrace + ^^ group (separate (comma ^^ space) lst ^^ ifflat empty (comma ^^ break 1)) + ^^ rbrace and format_external_function parameters name = let parameters = @@ -108,15 +128,118 @@ and format_function parameters body = ^^ space ^^ format_expression body -and format_function_call _function_definition _arguments = empty (* TODO *) -and format_uppercase_id_path_expression _path = empty (* TODO *) +and format_function_call function_definition arguments = + let arguments = + match arguments with + | [] -> empty + | lst -> + let lst = + List.map + (fun value -> nest 2 (ifflat empty (break 1) ^^ format_expression value)) + lst + in + group (separate (comma ^^ space) lst ^^ ifflat empty (comma ^^ break 1)) + in + format_expression function_definition ^^ parens arguments + +and format_uppercase_id_path_expression path = + separate_map dot format_uppercase_id_expression path + and format_uppercase_id_expression id = string id and format_lowercase_id_expression id = string id -and format_tag (_tag : Parsetree.tag) = empty (* TODO *) -and format_unary_expression _op _right = empty (* TODO *) -and format_binary_expression _left _op _right = empty (* TODO *) -and format_for_in ~index:_ ~iterator:_ ~reverse:_ ~iterable:_ ~body:_ = empty (* TODO *) -and format_conditional ~condition:_ ~consequent:_ ~alternate:_ = empty (* TODO *) + +and format_tag (tag : Parsetree.tag_desc) = + let arguments = + match tag.attributes with + | [] -> empty + | attrs -> parens @@ Helpers.comma_separated_attributes format_expression attrs + in + let transformer = + match tag.transformer with + | None -> empty + | Some expr -> space ^^ repeat 2 colon ^^ space ^^ format_expression expr + in + sharp ^^ format_tag_kind tag.tag ^^ arguments ^^ transformer + +and format_tag_kind = function + | Parsetree.P_Tag_String -> string "String" + | Parsetree.P_Tag_Int -> string "Int" + | Parsetree.P_Tag_Float -> string "Float" + | Parsetree.P_Tag_Boolean -> string "Boolean" + | Parsetree.P_Tag_Array -> string "Array" + | Parsetree.P_Tag_Record -> string "Record" + | Parsetree.P_Tag_Slot -> string "Slot" + | Parsetree.P_Tag_Store -> string "Store" + | Parsetree.P_Tag_SetContext -> string "SetContext" + | Parsetree.P_Tag_GetContext -> string "GetContext" + | Parsetree.P_Tag_CreatePortal -> string "CreatePortal" + | Parsetree.P_Tag_Portal -> string "Portal" + | Parsetree.P_Tag_Custom s -> string s + +and format_unary_expression op right = + let r = format_expression right in + match op with + | Parsetree.Operators.Unary.MINUS -> minus ^^ r + | Parsetree.Operators.Unary.NOT -> bang ^^ r + +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.NOT_EQUAL -> l ^^ space ^^ bang ^^ equals ^^ space ^^ r + | Parsetree.Operators.Binary.GREATER -> l ^^ space ^^ rangle ^^ space ^^ r + | Parsetree.Operators.Binary.GREATER_EQUAL -> + l ^^ space ^^ rangle ^^ equals ^^ space ^^ r + | Parsetree.Operators.Binary.LESS -> l ^^ space ^^ langle ^^ space ^^ r + | Parsetree.Operators.Binary.LESS_EQUAL -> l ^^ space ^^ langle ^^ equals ^^ space ^^ r + | Parsetree.Operators.Binary.PLUS -> l ^^ space ^^ plus ^^ space ^^ r + | 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.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.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.INCLUSIVE_RANGE -> l ^^ repeat 3 dot ^^ r + +and format_for_in ~index ~iterator ~reverse ~iterable ~body = + string "for" + ^^ space + ^^ lparen + ^^ optional format_lowercase_id index + ^^ optional (Fun.const comma) index + ^^ optional (Fun.const space) index + ^^ format_lowercase_id iterator + ^^ space + ^^ string "in" + ^^ space + ^^ (if reverse then + string "reverse" ^^ space + else + empty) + ^^ format_expression iterable + ^^ rparen + ^^ space + ^^ format_expression body + +and format_conditional ~condition ~consequent ~alternate = + string "if" + ^^ space + ^^ parens (format_expression condition) + ^^ space + ^^ format_expression consequent + ^^ optional + (fun expr -> space ^^ string "else" ^^ space ^^ format_expression expr) + alternate and format_block statements = let statements = List.map (fun s -> format_statement s) statements in @@ -219,7 +342,7 @@ and format_expression (exression : Parsetree.expression) = | P_UppercaseIdentifierPathExpression path -> format_uppercase_id_path_expression path | P_UppercaseIdentifierExpression id -> format_uppercase_id_expression id | P_LowercaseIdentifierExpression id -> format_lowercase_id_expression id - | P_TagExpression tag -> format_tag tag + | P_TagExpression { tag_desc; tag_loc = _ } -> format_tag tag_desc | P_ForInExpression { index; iterator; reverse; iterable; body } -> format_for_in ~index ~iterator ~reverse ~iterable ~body | P_ConditionalExpression { condition; consequent; alternate } -> @@ -250,11 +373,11 @@ and format_continue_stmt i = string "continue" ^^ num ^^ semi and format_use_stmt id expr = - string "let" - ^^ space - ^^ optional (fun id -> format_uppercase_id id ^^ space) id - ^^ equals + string "use" ^^ space + ^^ (match id with + | None -> empty + | Some id -> format_uppercase_id id ^^ space ^^ equals ^^ space) ^^ format_expression expr ^^ semi diff --git a/test/format/data.pi b/test/format/data.pi index 7022b28..7ab784e 100644 --- a/test/format/data.pi +++ b/test/format/data.pi @@ -1,6 +1,15 @@ page Docs(label: "Docs", icon: "/images/icons/page-docs.svg",) { + use Math = Base.Math; + let fruits = ["apples","oranges","bannanas", "melons"]; + + let calculations = { + math: 5 / 3 + 5 * 7, + math2:(3 + 5) / 5 * 7, + math3?:if(false) 3 * 4 + }; + <> <> @@ -22,7 +31,20 @@ page Docs(label: "Docs", icon: "/images/icons/page-docs.svg",) { } component Component(label: "Long Name of $(c)", icon: "/images/icons/page-docs.svg", groups: ["Some Group", "Another Group", "And another group"]) { - let fruits = ["apples","oranges","bannanas", "melons", "and a bunch more very healthy things you can eat"]; + #Portal(key: "stylesheets", push: ); + + let fruits = #Array(key:"fruits", of: #String()); + + let tag? = #Selection(label: "SEO Tag", options: [ + { label: "h1", value: "h1" }, + { label: "h2", value: "h2" }, + { label: "h3", value: "h3" }, + { label: "h4", value: "h4" }, + { label: "h5", value: "h5" }, + { label: "h6", value: "h6" }, + ]) :: fn v -> Base.Fn.default(v, "h1"); + + let tags = #Array(label: "Tags", initialSize: 1, max: 5, of: #String(label: "Tag")); <> @@ -32,7 +54,7 @@ component Component(label: "Long Name of $(c)", icon: "/images/icons/page-docs.s /> @@ -53,9 +75,7 @@ component Mutation { a := "mutated"; let mutable b = "initial"; - if (a == "mutated") { - b := "mutated"; - }; + if (a == "mutated") b := "mutated"; let mutable c = "initial"; let print_c = fn () -> c; diff --git a/test/format/run.t b/test/format/run.t index bf47521..e024023 100644 --- a/test/format/run.t +++ b/test/format/run.t @@ -1,13 +1,21 @@ $ pincfmt ./data.pi page Docs(label: "Docs", icon: "/images/icons/page-docs.svg") { + use Math = Base.Math; let fruits = ["apples", "oranges", "bannanas", "melons"]; + let calculations = { + math: 5 / 3 + 5 * 7, + math2: 3 + 5 / 5 * 7, + math3?: if (false) 3 * 4, + }; <> <>
<>

Aliqua in elit sunt in anim culpa nostrud elit. @@ -22,20 +30,47 @@ icon: "/images/icons/page-docs.svg", groups: ["Some Group", "Another Group", "And another group"], ) { - let fruits = [ - "apples", - "oranges", - "bannanas", - "melons", - "and a bunch more very healthy things you can eat", - ]; + #Portal(key: "stylesheets", push: ) + let fruits = #Array(key: "fruits", of: #String); + let tag? = #Selection( + label: "SEO Tag", + options: [ + { + label: "h1", + value: "h1", + }, + { + label: "h2", + value: "h2", + }, + { + label: "h3", + value: "h3", + }, + { + label: "h4", + value: "h4", + }, + { + label: "h5", + value: "h5", + }, + { + label: "h6", + value: "h6", + }, + ], + ) :: fn (v) -> Base.Fn.default(v, "h1"); + let tags = #Array(label: "Tags", initialSize: 1, max: 5, of: #String(label: "Tag")); <> <>

<>
    - {} + {for (fruit in reverse fruits) { +
  • {fruit}
  • + }}

Aliqua in elit sunt in anim culpa nostrud elit. @@ -53,7 +88,9 @@ let mutable a = "initial"; a := "mutated"; let mutable b = "initial"; - + if (a == "mutated") { + b := "mutated"; + } let mutable c = "initial"; let print_c = fn () -> c; c := "mutated"; @@ -64,7 +101,7 @@

a: {a} b: {b} - print_c(): {} - print_d(): {} + print_c(): {print_c()} + print_d(): {print_d()}
}