diff --git a/lib/02_parsing/Ast.ml b/lib/02_parsing/Ast.ml index a5bf27e..12d1ec2 100644 --- a/lib/02_parsing/Ast.ml +++ b/lib/02_parsing/Ast.ml @@ -107,6 +107,7 @@ and statement = { } and statement_desc = + | CommentStatement of string | BreakStatement of int | ContinueStatement of int | UseStatement of uppercase_identifier option * expression diff --git a/lib/02_parsing/Pinc_Parser.ml b/lib/02_parsing/Pinc_Parser.ml index f95495b..fa8156a 100644 --- a/lib/02_parsing/Pinc_Parser.ml +++ b/lib/02_parsing/Pinc_Parser.ml @@ -24,8 +24,32 @@ let next t = ;; let peek t = - let token = get_next_token t in - Queue.add token t.next; + let token = + match Queue.peek_opt t.next with + | None -> + let token = Lexer.scan t.lexer in + Queue.add token t.next; + token + | Some token -> token + in + token.typ +;; + +let peek_2 t = + let token = + match Queue.to_seq t.next |> List.of_seq with + | [] -> + let token = Lexer.scan t.lexer in + Queue.add token t.next; + let token = Lexer.scan t.lexer in + Queue.add token t.next; + token + | [ _ ] -> + let token = Lexer.scan t.lexer in + Queue.add token t.next; + token + | _ :: token :: _ -> token + in token.typ ;; @@ -200,12 +224,20 @@ module Rules = struct match t.token.typ with | Token.LEFT_BRACE -> next t; - let statements = t |> Helpers.list ~fn:parse_statement in + let rec get_statements acc = + match parse_statement t with + | Some r when optional Token.SEMICOLON t -> get_statements (r :: acc) + | Some (Ast.{ statement_desc = CommentStatement _; _ } as r) -> + get_statements (r :: acc) + | Some r -> List.rev (r :: acc) + | _ -> List.rev acc + in + let statements = get_statements [] in t |> expect Token.RIGHT_BRACE; Ast.BlockExpression statements |> Option.some | _ -> - let* statement = parse_statement t in - Ast.BlockExpression [ statement ] |> Option.some + let* expr = parse_expression t in + expr.Ast.expression_desc |> Option.some in let expr_end = t.token.location in let expression_loc = Location.merge ~s:expr_start ~e:expr_end () in @@ -364,6 +396,10 @@ module Rules = struct let statement_start = t.token in let* statement_desc = match t.token.typ with + (* PARSING COMMENT STATEMENT *) + | Token.COMMENT s -> + next t; + Some (Ast.CommentStatement s) (* PARSING BREAK STATEMENT *) | Token.KEYWORD_BREAK -> next t; @@ -374,7 +410,6 @@ module Rules = struct i | _ -> 1 in - let _ = optional Token.SEMICOLON t in Some (Ast.BreakStatement num_loops) (* PARSING CONTINUE STATEMENT *) | Token.KEYWORD_CONTINUE -> @@ -386,7 +421,6 @@ module Rules = struct i | _ -> 1 in - let _ = optional Token.SEMICOLON t in Some (Ast.ContinueStatement num_loops) (* PARSING LET STATEMENT *) | Token.KEYWORD_LET -> ( @@ -398,7 +432,6 @@ module Rules = struct t |> expect Token.EQUAL; let end_token = t.token in let expression = parse_expression t in - let _ = optional Token.SEMICOLON t in match (is_mutable, is_nullable, expression) with | false, true, Some expression -> Some (Ast.OptionalLetStatement (Lowercase_Id identifier, expression)) @@ -427,7 +460,6 @@ module Rules = struct (Location.merge ~s:start_token.location ~e:end_token.location ()) "Expected expression as right hand side of mutation statement" in - let _ = optional Token.SEMICOLON t in Some (Ast.MutationStatement (Lowercase_Id (identifier, identifier_location), expression)) @@ -446,7 +478,6 @@ module Rules = struct t.token.location "Expected expression as right hand side of use statement" in - let _ = optional Token.SEMICOLON t in Some (Ast.UseStatement (Some (Uppercase_Id identifier), expression))) else ( let expression = @@ -457,7 +488,6 @@ module Rules = struct t.token.location "Expected to see a library next to the use keyword." in - let _ = optional Token.SEMICOLON t in Some (Ast.UseStatement (None, expression))) | _ -> let* expr = parse_expression t in @@ -496,16 +526,14 @@ module Rules = struct expr |> Option.map (fun expr -> expr.Ast.expression_desc) (* PARSING RECORD or BLOCK EXPRESSION *) | Token.LEFT_BRACE -> - next t; let is_record = - match t.token.typ with - | Token.IDENT_LOWER _ -> - let token = peek t in - token = Token.COLON || token = Token.QUESTIONMARK - | Token.RIGHT_BRACE -> true + match (peek t, peek_2 t) with + | Token.IDENT_LOWER _, (Token.COLON | Token.QUESTIONMARK) -> true + | Token.RIGHT_BRACE, _ -> true | _ -> false in if is_record then ( + next t; let attrs = t |> Helpers.separated_list ~sep:Token.COMMA ~fn:parse_record_field @@ -514,10 +542,9 @@ module Rules = struct in t |> expect Token.RIGHT_BRACE; Ast.Record attrs |> Option.some) - else ( - let statements = t |> Helpers.list ~fn:parse_statement in - t |> expect Token.RIGHT_BRACE; - Ast.BlockExpression statements |> Option.some) + else + let* expr = parse_block t in + Some expr.Ast.expression_desc (* PARSING FOR IN EXPRESSION *) | Token.KEYWORD_FOR -> ( next t; @@ -685,7 +712,7 @@ module Rules = struct and parse_expression ?(prio = -999) t = let rec loop ~prio ~left t = - if optional Token.SEMICOLON t then + if t.token.typ = Token.SEMICOLON then left else ( match parse_binary_operator t with diff --git a/lib/pinc_backend/Interpreter.ml b/lib/pinc_backend/Interpreter.ml index 62db568..0efaf1c 100644 --- a/lib/pinc_backend/Interpreter.ml +++ b/lib/pinc_backend/Interpreter.ml @@ -74,6 +74,7 @@ let rec get_uppercase_identifier_typ ~state ident = and eval_statement ~state statement = let result = match statement.Ast.statement_desc with + | Ast.CommentStatement _ -> state | Ast.LetStatement (Lowercase_Id ident, expression) -> eval_let ~state ~ident ~is_mutable:false ~is_optional:false expression | Ast.OptionalLetStatement (Lowercase_Id ident, expression) -> diff --git a/lib/pinc_backend/stdlib/Base__Array.pi b/lib/pinc_backend/stdlib/Base__Array.pi index db2c88c..daf6b89 100644 --- a/lib/pinc_backend/stdlib/Base__Array.pi +++ b/lib/pinc_backend/stdlib/Base__Array.pi @@ -1,46 +1,47 @@ library Base__Array { let make = fn (length) -> { 0..length - } + }; let init = fn (length, f) -> { for (index in make(length)) { f(index) } - } + }; let length = fn (array) -> { let mutable len = 0; - for (_ in array) len := len + 1; + for (_ in array) { + len := len + 1; + }; len - } + }; let first = fn (array) -> { array[0] - } + }; let last = fn (array) -> { let len = length(array); if len > 0 { array[len - 1] } - } + }; let take_until = fn (array, condition) -> { for (item in array) { if(condition(item)) break; item } - } + }; let slice = fn (array, offset, length) -> { for (index, item in array) { - if(index < offset) { continue }; - if(index == length + offset) { break }; - + if(index < offset) continue; + if(index == length + offset) break; item } - } + }; let chunk = fn (array, size) -> { let len = Base.Array.length(array); @@ -48,42 +49,42 @@ library Base__Array { 0..x |> Base.Array.mapi(fn (index, item) -> { Base.Array.slice(array, index * size, size) }); - } + }; let join = fn (array, sep) -> { let mutable result = ""; for (index, item in array) { if(index > 0) { - result := result ++ sep - } - result := result ++ item - } + result := result ++ sep; + }; + result := result ++ item; + }; result - } + }; let map = fn (array, f) -> { for (item in array) { f(item) } - } + }; let map_reverse = fn (array, f) -> { for (item in reverse array) { f(item) } - } + }; let mapi = fn (array, f) -> { for (index, item in array) { f(index, item) } - } + }; let mapi_reverse = fn (array, f) -> { for (index, item in reverse array) { f(index, item) } - } + }; let partition = fn (array, condition) -> { let len = Base.Array.length(array); @@ -100,7 +101,7 @@ library Base__Array { } }; part([], [], 0) - } + }; let filter = fn (array, condition) -> { let len = Base.Array.length(array); @@ -116,10 +117,11 @@ library Base__Array { } } }; + aux([], 0) - } + }; - let keep = filter + let keep = filter; let find = fn (array, condition) -> { let len = Base.Array.length(array); @@ -133,8 +135,9 @@ library Base__Array { } } }; + aux(0) - } + }; let exists = fn (array, condition) -> { let len = Base.Array.length(array); @@ -150,10 +153,11 @@ library Base__Array { false } }; - aux(0) - } - let some = exists + aux(0); + }; + + let some = exists; let for_all = fn (array, condition) -> { let len = Base.Array.length(array); @@ -167,7 +171,7 @@ library Base__Array { }; aux(true, 0) - } + }; let every = for_all; @@ -211,7 +215,7 @@ library Base__Array { let nth = fn (array, index) -> { array[index] - } + }; let sort = fn (array, f) -> { let merge = fn (a, b) -> { @@ -232,7 +236,7 @@ library Base__Array { } } } - } + }; let len = Base.Array.length(array); if len < 2 { @@ -243,7 +247,7 @@ library Base__Array { let second_half = array |> Base.Array.slice(h, len); merge(sort(first_half, f), sort(second_half, f)); } - } + }; let unique = fn (array) -> { let isSorted = false; @@ -255,8 +259,8 @@ library Base__Array { seen := seen <- value; result := result <- value; } - } + }; result - } + }; } \ No newline at end of file diff --git a/lib/pinc_backend/stdlib/Base__Char.pi b/lib/pinc_backend/stdlib/Base__Char.pi index ba910a8..d0a2388 100644 --- a/lib/pinc_backend/stdlib/Base__Char.pi +++ b/lib/pinc_backend/stdlib/Base__Char.pi @@ -1,9 +1,9 @@ library Base__Char { let is_whitespace = fn (char) -> { char == ' ' || char == '\012' || char == '\n' || char == '\r' || char == '\t' - } + }; let is_newline = fn (char) -> { char == '\n' || char == '\r' - } + }; } \ No newline at end of file diff --git a/lib/pinc_backend/stdlib/Base__Math.pi b/lib/pinc_backend/stdlib/Base__Math.pi index 8ac94b3..8580ba2 100644 --- a/lib/pinc_backend/stdlib/Base__Math.pi +++ b/lib/pinc_backend/stdlib/Base__Math.pi @@ -6,7 +6,7 @@ library Base__Math { } else { n - (1 + mod) } - } + }; - let ceil = fn n -> -(Base.Math.floor(-n)) + let ceil = fn n -> -(Base.Math.floor(-n)); } \ No newline at end of file diff --git a/lib/pinc_backend/stdlib/Base__String.pi b/lib/pinc_backend/stdlib/Base__String.pi index 5387ed0..6c5a491 100644 --- a/lib/pinc_backend/stdlib/Base__String.pi +++ b/lib/pinc_backend/stdlib/Base__String.pi @@ -1,95 +1,98 @@ library Base__String { let length = fn (string) -> { let mutable len = 0; - for (_ in string) len := len + 1; + for (_ in string) { + len := len + 1; + }; + len - } + }; let map = fn (string, f) -> { let mutable result = ""; for (char in string) { - result := result ++ f(char) - } + result := result ++ f(char); + }; result - } + }; let map_reverse = fn (string, f) -> { let mutable result = ""; for (char in reverse string) { - result := result ++ f(char) - } + result := result ++ f(char); + }; result - } + }; let mapi = fn (string, f) -> { let mutable result = ""; for (index, char in string) { - result := result ++ f(index, char) - } + result := result ++ f(index, char); + }; result - } + }; let mapi_reverse = fn (string, f) -> { let mutable result = ""; for (index, char in reverse string) { - result := result ++ f(index, char) - } + result := result ++ f(index, char); + }; result - } + }; let iter = fn (string, f) -> { for (char in string) { f(char) } - } + }; let iter_reverse = fn (string, f) -> { for (char in reverse string) { f(char) } - } + }; let iteri = fn (string, f) -> { for (index, char in string) { f(index, char) } - } + }; let iteri_reverse = fn (string, f) -> { for (index, char in reverse string) { f(index, char) } - } + }; let uppercase_ascii = fn (string) -> { map(string, fn (c) -> { if (c >= 'a' && c <= 'z') c - 32 else c }) - } + }; let lowercase_ascii = fn (string) -> { map(string, fn (c) -> { if (c >= 'A' && c <= 'Z') c + 32 else c - }); - } + }) + }; let capitalize_ascii = fn (string) -> { mapi(string, fn (index, c) -> { if (index == 0 && c >= 'a' && c <= 'z') c - 32 else c }) - } + }; let nl2br = fn (string) -> { let mutable result = ""; for (char in string) { if (Base.Char.is_newline(char)) { - result := result ++ "
" + result := result ++ "
"; } else { - result := result ++ char + result := result ++ char; } - } + }; result - } + }; let trim = fn (string) -> { let len = length(string); @@ -101,7 +104,7 @@ library Base__String { } else { break; } - } + }; for (char in reverse string) { if (Base.Char.is_whitespace(char)) { @@ -109,14 +112,14 @@ library Base__String { } else { break; } - } + }; if (j >= i) { sub(string, i, (j - i + 1)) } else { "" } - } + }; let sub = fn (string, ofs, len) -> { if (ofs < 0 || len < 0) { @@ -127,11 +130,11 @@ library Base__String { if(index < ofs) continue; if(index >= ofs + len) continue; - result := result ++ char - } + result := result ++ char; + }; result } - } + }; let split = fn (string, sep) -> { let mutable result = []; @@ -140,10 +143,10 @@ library Base__String { for (i in reverse 0...j) { if (string[i] == sep) { result := [sub(string, (i + 1), (j - i - 1))] @@ result; - j := i + j := i; } }; [sub(string, 0, j)] @@ result - } + }; } \ No newline at end of file diff --git a/test/char/data.pi b/test/char/data.pi index 2a0b5f4..97d7852 100644 --- a/test/char/data.pi +++ b/test/char/data.pi @@ -1,42 +1,6 @@ -library String { - let length = fn (string) -> { - let mutable len = 0; - for (_ in string) len := len + 1; - len - } - - let uppercase_ascii = fn (string) -> { - let mutable result = ""; - for (c in string) { - let new_char = if (c >= 'a' && c <= 'z') c - 32 else c - - result := result ++ new_char - } - result - } - - let lowercase_ascii = fn (string) -> { - let mutable result = ""; - for (c in string) { - let new_char = if (c >= 'A' && c <= 'Z') c + 32 else c - - result := result ++ new_char - } - result - } - - let capitalize_ascii = fn (string) -> { - let mutable result = ""; - for (index, c in string) { - let new_char = if (index == 0 && c >= 'a' && c <= 'z') c - 32 else c - - result := result ++ new_char - } - result - } -} - component C { + use Base; + let char = 'c';
diff --git a/test/interpreter_error/run.t b/test/interpreter_error/run.t index 4ecff73..44e98c9 100644 --- a/test/interpreter_error/run.t +++ b/test/interpreter_error/run.t @@ -20,11 +20,11 @@ $ NO_COLOR="1" print . BadTransformer_Arity - ERROR in file ./tag_transformer_arity.pi:6:25-64 + ERROR in file ./tag_transformer_arity.pi:6:25-63 5 │ component BadTransformer_Arity_Child { - 6 │ let text = #String :: fn (a, b) -> Base.String.uppercase(a);; - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 6 │ let text = #String :: fn (a, b) -> Base.String.uppercase(a); + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 7 │ A transformer has to accept exactly one argument (the tag value). diff --git a/test/interpreter_error/tag_transformer_arity.pi b/test/interpreter_error/tag_transformer_arity.pi index 8d6dd61..2fb07d3 100644 --- a/test/interpreter_error/tag_transformer_arity.pi +++ b/test/interpreter_error/tag_transformer_arity.pi @@ -3,7 +3,7 @@ component BadTransformer_Arity { } component BadTransformer_Arity_Child { - let text = #String :: fn (a, b) -> Base.String.uppercase(a);; + let text = #String :: fn (a, b) -> Base.String.uppercase(a); text } diff --git a/test/mutation/data.pi b/test/mutation/data.pi index 32f00f1..6375070 100644 --- a/test/mutation/data.pi +++ b/test/mutation/data.pi @@ -5,7 +5,7 @@ component Component { let mutable b = "initial"; if (a == "mutated") { b := "mutated"; - } + }; let mutable c = "initial"; let print_c = fn () -> c; diff --git a/test/parse_error/string_interpolation.pi b/test/parse_error/string_interpolation.pi index 43f5f83..49ffac3 100644 --- a/test/parse_error/string_interpolation.pi +++ b/test/parse_error/string_interpolation.pi @@ -1,5 +1,5 @@ component Component { - let fail = #String + let fail = #String;
{fail} diff --git a/test/store/StoreValueProvider.pi b/test/store/StoreValueProvider.pi index 1e71ab2..8e51ed5 100644 --- a/test/store/StoreValueProvider.pi +++ b/test/store/StoreValueProvider.pi @@ -8,7 +8,7 @@ component StoreValueProvider { phone: "+1 111 000 111", email: "some@email.invalid", address: "Somewhere in the World", - }; + }, }; let products = [ diff --git a/test/store/stores.pi b/test/store/stores.pi index 899e2b1..de5aac2 100644 --- a/test/store/stores.pi +++ b/test/store/stores.pi @@ -7,10 +7,10 @@ store Settings(single: true) { phone: #String, email: #String, address: #String :: fn v -> v ++ " ... or am I??", - }); -}; + }), +} store Products { title: #String, code: #Int :: fn v -> v * 2, -}; \ No newline at end of file +}