From bb4bcbb7de0b2c0337ee2c3f355bd58e05612048 Mon Sep 17 00:00:00 2001 From: Jarvis Carroll Date: Tue, 3 Feb 2026 06:08:54 +0000 Subject: [PATCH] remove 'tk' atom from file positions --- src/hz_sophia.erl | 546 +++++++++++++++++++++++----------------------- 1 file changed, 273 insertions(+), 273 deletions(-) diff --git a/src/hz_sophia.erl b/src/hz_sophia.erl index f41443d..8d578c2 100644 --- a/src/hz_sophia.erl +++ b/src/hz_sophia.erl @@ -12,16 +12,16 @@ parse_literal(String) -> parse_literal(unknown_type(), String). parse_literal(Type, String) -> - case parse_expression(Type, {tk, 1, 1}, String) of - {ok, {Result, NewTk, NewString}} -> - parse_literal2(Result, NewTk, NewString); + case parse_expression(Type, {1, 1}, String) of + {ok, {Result, NewPos, NewString}} -> + parse_literal2(Result, NewPos, NewString); {error, Reason} -> {error, Reason} end. -parse_literal2(Result, Tk, String) -> +parse_literal2(Result, Pos, String) -> % We have parsed a valid expression. Now check that the string ends. - case next_token(Tk, String) of + case next_token(Pos, String) of {ok, {{eof, _, _, _, _}, _, _}} -> {ok, Result}; {ok, {{_, S, _, Row, Start, End}, _, _}} -> @@ -39,59 +39,59 @@ parse_literal2(Result, Tk, String) -> -define(IS_ALPHANUM(C), (?IS_ALPHA(C) or ?IS_NUM(C))). -define(IS_HEX(C), (?IS_NUM(C) or (((C) >= $A) and ((C) =< $F)) or (((C) >= $a) and ((C) =< $f)))). -next_token({tk, Row, Col}, []) -> - {ok, {{eof, "", Row, Col, Col}, {tk, Row, Col}, []}}; -next_token({tk, Row, Col}, " " ++ Rest) -> - next_token({tk, Row, Col + 1}, Rest); -next_token({tk, Row, Col}, "\t" ++ Rest) -> - next_token({tk, Row, Col + 1}, Rest); -next_token({tk, Row, _}, "\r\n" ++ Rest) -> - next_token({tk, Row + 1, 1}, Rest); -next_token({tk, Row, _}, "\r" ++ Rest) -> - next_token({tk, Row + 1, 1}, Rest); -next_token({tk, Row, _}, "\n" ++ Rest) -> - next_token({tk, Row + 1, 1}, Rest); -next_token(Tk, [C | _] = String) when ?IS_ALPHA(C) -> - alphanum_token(Tk, Tk, String, []); -next_token(Tk, [C | _] = String) when ?IS_NUM(C) -> - num_token(Tk, Tk, String, [], 0); -next_token({tk, Row, Col}, [$#, C | Rest]) when ?IS_HEX(C) -> - bytes_token({tk, Row, Col}, {tk, Row, Col + 1}, [C | Rest], "#", []); -next_token({tk, Row, Col}, "\"" ++ Rest) -> - string_token({tk, Row, Col}, {tk, Row, Col + 1}, Rest, "\"", <<>>); -next_token({tk, Row, Col}, [Char | Rest]) -> +next_token({Row, Col}, []) -> + {ok, {{eof, "", Row, Col, Col}, {Row, Col}, []}}; +next_token({Row, Col}, " " ++ Rest) -> + next_token({Row, Col + 1}, Rest); +next_token({Row, Col}, "\t" ++ Rest) -> + next_token({Row, Col + 1}, Rest); +next_token({Row, _}, "\r\n" ++ Rest) -> + next_token({Row + 1, 1}, Rest); +next_token({Row, _}, "\r" ++ Rest) -> + next_token({Row + 1, 1}, Rest); +next_token({Row, _}, "\n" ++ Rest) -> + next_token({Row + 1, 1}, Rest); +next_token(Pos, [C | _] = String) when ?IS_ALPHA(C) -> + alphanum_token(Pos, Pos, String, []); +next_token(Pos, [C | _] = String) when ?IS_NUM(C) -> + num_token(Pos, Pos, String, [], 0); +next_token({Row, Col}, [$#, C | Rest]) when ?IS_HEX(C) -> + bytes_token({Row, Col}, {Row, Col + 1}, [C | Rest], "#", []); +next_token({Row, Col}, "\"" ++ Rest) -> + string_token({Row, Col}, {Row, Col + 1}, Rest, "\"", <<>>); +next_token({Row, Col}, [Char | Rest]) -> Token = {character, [Char], Char, Row, Col, Col}, - {ok, {Token, {tk, Row, Col + 1}, Rest}}. + {ok, {Token, {Row, Col + 1}, Rest}}. -alphanum_token(Start, {tk, Row, Col}, [C | Rest], Acc) when ?IS_ALPHANUM(C) -> - alphanum_token(Start, {tk, Row, Col + 1}, Rest, [C | Acc]); -alphanum_token({tk, _, Start}, {tk, Row, End}, String, Acc) -> +alphanum_token(Start, {Row, Col}, [C | Rest], Acc) when ?IS_ALPHANUM(C) -> + alphanum_token(Start, {Row, Col + 1}, Rest, [C | Acc]); +alphanum_token({_, Start}, {Row, End}, String, Acc) -> AlphaString = lists:reverse(Acc), Token = {alphanum, AlphaString, AlphaString, Row, Start, End - 1}, - {ok, {Token, {tk, Row, End}, String}}. + {ok, {Token, {Row, End}, String}}. -num_token(Start, {tk, Row, Col}, [C | Rest], Chars, Value) when ?IS_NUM(C) -> +num_token(Start, {Row, Col}, [C | Rest], Chars, Value) when ?IS_NUM(C) -> NewValue = Value * 10 + (C - $0), - num_token(Start, {tk, Row, Col + 1}, Rest, [C | Chars], NewValue); -num_token(Start, {tk, Row, Col}, [$_, C | Rest], Chars, Value) when ?IS_NUM(C) -> + num_token(Start, {Row, Col + 1}, Rest, [C | Chars], NewValue); +num_token(Start, {Row, Col}, [$_, C | Rest], Chars, Value) when ?IS_NUM(C) -> NewValue = Value * 10 + (C - $0), - num_token(Start, {tk, Row, Col + 2}, Rest, [C, $_ | Chars], NewValue); -num_token({tk, _, Start}, {tk, Row, End}, String, Chars, Value) -> + num_token(Start, {Row, Col + 2}, Rest, [C, $_ | Chars], NewValue); +num_token({_, Start}, {Row, End}, String, Chars, Value) -> NumString = lists:reverse(Chars), Token = {integer, NumString, Value, Row, Start, End - 1}, - {ok, {Token, {tk, Row, End}, String}}. + {ok, {Token, {Row, End}, String}}. -bytes_token(Start, {tk, Row, Col}, [C | Rest], Chars, Digits) when ?IS_HEX(C) -> +bytes_token(Start, {Row, Col}, [C | Rest], Chars, Digits) when ?IS_HEX(C) -> Digit = convert_digit(C), - bytes_token(Start, {tk, Row, Col + 1}, Rest, [C | Chars], [Digit | Digits]); -bytes_token(Start, {tk, Row, Col}, [$_, C | Rest], Chars, Digits) when ?IS_HEX(C) -> + bytes_token(Start, {Row, Col + 1}, Rest, [C | Chars], [Digit | Digits]); +bytes_token(Start, {Row, Col}, [$_, C | Rest], Chars, Digits) when ?IS_HEX(C) -> Digit = convert_digit(C), - bytes_token(Start, {tk, Row, Col + 1}, Rest, [C, $_ | Chars], [Digit | Digits]); -bytes_token({tk, _, Start}, {tk, Row, End}, String, Chars, Digits) -> + bytes_token(Start, {Row, Col + 1}, Rest, [C, $_ | Chars], [Digit | Digits]); +bytes_token({_, Start}, {Row, End}, String, Chars, Digits) -> BytesString = lists:reverse(Chars), Value = reverse_combine_nibbles(Digits, <<>>), Token = {bytes, BytesString, Value, Row, Start, End - 1}, - {ok, {Token, {tk, Row, End}, String}}. + {ok, {Token, {Row, End}, String}}. convert_digit(C) when C >= $0, C =< $9 -> C - $0; @@ -108,54 +108,54 @@ reverse_combine_nibbles([D1], Acc) -> reverse_combine_nibbles([], Acc) -> Acc. -string_token(Start, {tk, Row, Col}, "\\x" ++ String, SourceChars, Value) -> - case escape_hex_code({tk, Row, Col}, {tk, Row, Col + 2}, String, "x\\" ++ SourceChars) of - {ok, {Codepoint, NewSourceChars, NewTk, NewString}} -> +string_token(Start, {Row, Col}, "\\x" ++ String, SourceChars, Value) -> + case escape_hex_code({Row, Col}, {Row, Col + 2}, String, "x\\" ++ SourceChars) of + {ok, {Codepoint, NewSourceChars, NewPos, NewString}} -> NewValue = <>, - string_token(Start, NewTk, NewString, NewSourceChars, NewValue); + string_token(Start, NewPos, NewString, NewSourceChars, NewValue); {error, Reason} -> {error, Reason} end; -string_token(Start, {tk, Row, Col}, [$\\, C | Rest], SourceChars, Value) -> +string_token(Start, {Row, Col}, [$\\, C | Rest], SourceChars, Value) -> case escape_char(C) of {ok, ByteVal} -> - string_token(Start, {tk, Row, Col + 2}, Rest, [C, $\ | SourceChars], <>); + string_token(Start, {Row, Col + 2}, Rest, [C, $\ | SourceChars], <>); error -> {error, {invalid_escape_code, [C], Row, Col}} end; -string_token({tk, _, Start}, {tk, Row, Col}, [$" | Rest], SourceChars, Value) -> +string_token({_, Start}, {Row, Col}, [$" | Rest], SourceChars, Value) -> SourceStr = lists:reverse([$" | SourceChars]), Token = {string, SourceStr, Value, Row, Start, Col}, - {ok, {Token, {tk, Row, Col + 1}, Rest}}; -string_token(Start, {tk, Row, Col}, [C | Rest], SourceChars, Value) -> + {ok, {Token, {Row, Col + 1}, Rest}}; +string_token(Start, {Row, Col}, [C | Rest], SourceChars, Value) -> % TODO: ERTS probably had to convert this FROM utf8 at some point, so why % bother, if we need to convert it back? I guess we could accept iolists if % we really wanted to waste time on this point... - string_token(Start, {tk, Row, Col + 1}, Rest, [C | SourceChars], <>). + string_token(Start, {Row, Col + 1}, Rest, [C | SourceChars], <>). -escape_hex_code(Start, {tk, Row, Col}, "{" ++ String, SourceChars) -> - escape_long_hex_code(Start, {tk, Row, Col + 1}, String, "{" ++ SourceChars, 0); -escape_hex_code(_, {tk, Row, Col}, [A, B | String], SourceChars) when ?IS_HEX(A), ?IS_HEX(B) -> +escape_hex_code(Start, {Row, Col}, "{" ++ String, SourceChars) -> + escape_long_hex_code(Start, {Row, Col + 1}, String, "{" ++ SourceChars, 0); +escape_hex_code(_, {Row, Col}, [A, B | String], SourceChars) when ?IS_HEX(A), ?IS_HEX(B) -> % As of writing this, the Sophia compiler will convert this byte from % extended ASCII to unicode... But it really shouldn't. The literal parser % does what the compiler should do. Byte = convert_digit(A) * 16 + convert_digit(B), - {ok, {Byte, [B, A | SourceChars], {tk, Row, Col + 2}, String}}; -escape_hex_code({tk, Row1, Col1}, _, _, _) -> + {ok, {Byte, [B, A | SourceChars], {Row, Col + 2}, String}}; +escape_hex_code({Row1, Col1}, _, _, _) -> {error, {invalid_escape_code, "\\x", Row1, Col1}}. -escape_long_hex_code(_, {tk, Row, Col}, "}" ++ String, SourceChars, Value) -> - {ok, {Value, "}" ++ SourceChars, {tk, Row, Col + 1}, String}}; -escape_long_hex_code(Start, {tk, Row, Col}, [C | String], SourceChars, Value) when ?IS_HEX(C) -> +escape_long_hex_code(_, {Row, Col}, "}" ++ String, SourceChars, Value) -> + {ok, {Value, "}" ++ SourceChars, {Row, Col + 1}, String}}; +escape_long_hex_code(Start, {Row, Col}, [C | String], SourceChars, Value) when ?IS_HEX(C) -> NewSourceChars = [C | SourceChars], NewValue = 16 * Value + convert_digit(C), - escape_long_hex_code(Start, {tk, Row, Col + 1}, String, NewSourceChars, NewValue); -escape_long_hex_code(_, {tk, Row, Col}, [C | _], _, _) -> + escape_long_hex_code(Start, {Row, Col + 1}, String, NewSourceChars, NewValue); +escape_long_hex_code(_, {Row, Col}, [C | _], _, _) -> {error, {invalid_hexadecimal, [C], Row, Col}}; -escape_long_hex_code(_, Tk, [], SourceChars, Value) -> +escape_long_hex_code(_, Pos, [], SourceChars, Value) -> % Just return as if the escape code were closed, and let the string parser % produce an unclosed string error instead. - {ok, {Value, SourceChars, Tk, []}}. + {ok, {Value, SourceChars, Pos, []}}. escape_char($b) -> {ok, $\b}; escape_char($e) -> {ok, $\e}; @@ -186,90 +186,90 @@ escape_char(_) -> error. %%% write the recursive code, thus programming the BEAM to implement the %%% pushdown automaton that we want. -parse_expression(Type, Tk, String) -> - case next_token(Tk, String) of - {ok, {Token, NewTk, NewString}} -> - parse_expression2(Type, NewTk, NewString, Token); +parse_expression(Type, Pos, String) -> + case next_token(Pos, String) of + {ok, {Token, NewPos, NewString}} -> + parse_expression2(Type, NewPos, NewString, Token); {error, Reason} -> {error, Reason} end. -parse_expression2(Type, Tk, String, {integer, _, Value, Row, Start, End}) -> +parse_expression2(Type, Pos, String, {integer, _, Value, Row, Start, End}) -> case Type of {_, _, integer} -> - {ok, {Value, Tk, String}}; + {ok, {Value, Pos, String}}; {_, _, unknown_type} -> - {ok, {Value, Tk, String}}; + {ok, {Value, Pos, String}}; {O, N, _} -> {error, {wrong_type, O, N, integer, Row, Start, End}} end; -parse_expression2(Type, Tk, String, {bytes, _, Value, Row, Start, End}) -> +parse_expression2(Type, Pos, String, {bytes, _, Value, Row, Start, End}) -> Len = byte_size(Value), Result = {bytes, Value}, case Type of {_, _, {bytes, [any]}} -> - {ok, {Result, Tk, String}}; + {ok, {Result, Pos, String}}; {_, _, {bytes, [Len]}} -> - {ok, {Result, Tk, String}}; + {ok, {Result, Pos, String}}; {_, _, {bytes, [ExpectedLen]}} -> {error, {bytes_wrong_size, ExpectedLen, Len, Row, Start, End}}; {_, _, unknown_type} -> - {ok, {Result, Tk, String}}; + {ok, {Result, Pos, String}}; {O, N, _} -> {error, {wrong_type, O, N, {bytes, [Len]}, Row, Start, End}} end; -parse_expression2(Type, Tk, String, {string, _, Value, Row, Start, End}) -> +parse_expression2(Type, Pos, String, {string, _, Value, Row, Start, End}) -> case Type of {_, _, string} -> - {ok, {Value, Tk, String}}; + {ok, {Value, Pos, String}}; {_, _, unknown_type} -> - {ok, {Value, Tk, String}}; + {ok, {Value, Pos, String}}; {O, N, _} -> {error, {wrong_type, O, N, string, Row, Start, End}} end; -parse_expression2(Type, Tk, String, {character, "[", _, Row, Start, _}) -> - parse_list(Type, Tk, String, Row, Start); -parse_expression2(Type, Tk, String, {character, "(", _, Row, Start, _}) -> - parse_tuple(Type, Tk, String, Row, Start); -parse_expression2(Type, Tk, String, {character, "{", _, Row, Start, _}) -> - parse_record_or_map(Type, Tk, String, Row, Start); -parse_expression2(Type, Tk, String, {alphanum, S, _, Row, Start, End}) -> - parse_alphanum(Type, Tk, String, S, Row, Start, End); +parse_expression2(Type, Pos, String, {character, "[", _, Row, Start, _}) -> + parse_list(Type, Pos, String, Row, Start); +parse_expression2(Type, Pos, String, {character, "(", _, Row, Start, _}) -> + parse_tuple(Type, Pos, String, Row, Start); +parse_expression2(Type, Pos, String, {character, "{", _, Row, Start, _}) -> + parse_record_or_map(Type, Pos, String, Row, Start); +parse_expression2(Type, Pos, String, {alphanum, S, _, Row, Start, End}) -> + parse_alphanum(Type, Pos, String, S, Row, Start, End); parse_expression2(_, _, _, {_, S, _, Row, Start, End}) -> {error, {unexpected_token, S, Row, Start, End}}. unknown_type() -> {unknown_type, already_normalized, unknown_type}. -expect_tokens([], Tk, String) -> - {ok, {Tk, String}}; -expect_tokens([Str | Rest], Tk, String) -> - case next_token(Tk, String) of - {ok, {{_, Str, _, _, _, _}, NewTk, NewString}} -> - expect_tokens(Rest, NewTk, NewString); +expect_tokens([], Pos, String) -> + {ok, {Pos, String}}; +expect_tokens([Str | Rest], Pos, String) -> + case next_token(Pos, String) of + {ok, {{_, Str, _, _, _, _}, NewPos, NewString}} -> + expect_tokens(Rest, NewPos, NewString); {ok, {{_, Actual, _, Row, Start, End}, _, _}} -> {error, {unexpected_token, Actual, Row, Start, End}} end. %%% Ambiguous Chain Object vs Identifier Parsing -parse_alphanum(Type, Tk, String, [C | _] = S, Row, Start, End) when ?IS_LATIN_UPPER(C) -> +parse_alphanum(Type, Pos, String, [C | _] = S, Row, Start, End) when ?IS_LATIN_UPPER(C) -> % From a programming perspective, we are trying to parse a constant, so % an alphanum token can really only be a constructor, or a chain object. % Chain objects start with lowercase prefixes, like ak_, so clearly this is % a variant constructor. - parse_variant(Type, Tk, String, S, Row, Start, End); -parse_alphanum(Type, Tk, String, S, Row, Start, End) -> + parse_variant(Type, Pos, String, S, Row, Start, End); +parse_alphanum(Type, Pos, String, S, Row, Start, End) -> % Inversely, variant constructors are always uppercase, so now that we have % handled that case, only chain objects are left. try case gmser_api_encoder:decode(unicode:characters_to_binary(S)) of {account_pubkey, Data} -> - typecheck_address(Type, Tk, String, Data, Row, Start, End); + typecheck_address(Type, Pos, String, Data, Row, Start, End); {contract_pubkey, Data} -> - typecheck_contract(Type, Tk, String, Data, Row, Start, End); + typecheck_contract(Type, Pos, String, Data, Row, Start, End); {signature, Data} -> - typecheck_signature(Type, Tk, String, Data, Row, Start, End); + typecheck_signature(Type, Pos, String, Data, Row, Start, End); {_, _} -> % Only a few chain objects are recognized by Sophia. The rest % are interpreted as identifiers, so we might as well give the @@ -280,61 +280,61 @@ parse_alphanum(Type, Tk, String, S, Row, Start, End) -> _:_ -> {error, {unexpected_identifier, S, Row, Start, End}} end. -typecheck_address({_, _, address}, Tk, String, Data, _, _, _) -> - {ok, {{address, Data}, Tk, String}}; -typecheck_address({_, _, contract}, Tk, String, Data, _, _, _) -> +typecheck_address({_, _, address}, Pos, String, Data, _, _, _) -> + {ok, {{address, Data}, Pos, String}}; +typecheck_address({_, _, contract}, Pos, String, Data, _, _, _) -> % The compiler would type error, but we should be lenient here. - {ok, {{contract, Data}, Tk, String}}; -typecheck_address({_, _, unknown_type}, Tk, String, Data, _, _, _) -> - {ok, {{address, Data}, Tk, String}}; + {ok, {{contract, Data}, Pos, String}}; +typecheck_address({_, _, unknown_type}, Pos, String, Data, _, _, _) -> + {ok, {{address, Data}, Pos, String}}; typecheck_address({O, N, _}, _, _, _, Row, Start, End) -> {error, {wrong_type, O, N, address, Row, Start, End}}. -typecheck_contract({_, _, contract}, Tk, String, Data, _, _, _) -> - {ok, {{contract, Data}, Tk, String}}; -typecheck_contract({_, _, address}, Tk, String, Data, _, _, _) -> +typecheck_contract({_, _, contract}, Pos, String, Data, _, _, _) -> + {ok, {{contract, Data}, Pos, String}}; +typecheck_contract({_, _, address}, Pos, String, Data, _, _, _) -> % The compiler would type error, but we should be lenient here. - {ok, {{address, Data}, Tk, String}}; -typecheck_contract({_, _, unknown_type}, Tk, String, Data, _, _, _) -> - {ok, {{contract, Data}, Tk, String}}; + {ok, {{address, Data}, Pos, String}}; +typecheck_contract({_, _, unknown_type}, Pos, String, Data, _, _, _) -> + {ok, {{contract, Data}, Pos, String}}; typecheck_contract({O, N, _}, _, _, _, Row, Start, End) -> {error, {wrong_type, O, N, contract, Row, Start, End}}. -typecheck_signature({_, _, signature}, Tk, String, Data, _, _, _) -> - {ok, {{bytes, Data}, Tk, String}}; -typecheck_signature({_, _, {bytes, [64]}}, Tk, String, Data, _, _, _) -> +typecheck_signature({_, _, signature}, Pos, String, Data, _, _, _) -> + {ok, {{bytes, Data}, Pos, String}}; +typecheck_signature({_, _, {bytes, [64]}}, Pos, String, Data, _, _, _) -> % The compiler would probably type-error, but whatever. - {ok, {{bytes, Data}, Tk, String}}; -typecheck_signature({_, _, {bytes, [any]}}, Tk, String, Data, _, _, _) -> + {ok, {{bytes, Data}, Pos, String}}; +typecheck_signature({_, _, {bytes, [any]}}, Pos, String, Data, _, _, _) -> % The compiler would probably type-error, but whatever. - {ok, {{bytes, Data}, Tk, String}}; -typecheck_signature({_, _, unknown_type}, Tk, String, Data, _, _, _) -> - {ok, {{bytes, Data}, Tk, String}}; + {ok, {{bytes, Data}, Pos, String}}; +typecheck_signature({_, _, unknown_type}, Pos, String, Data, _, _, _) -> + {ok, {{bytes, Data}, Pos, String}}; typecheck_signature({O, N, _}, _, _, _, Row, Start, End) -> {error, {wrong_type, O, N, signature, Row, Start, End}}. %%% List Parsing -parse_list({_, _, {list, [Inner]}}, Tk, String, Row, Start) -> - parse_list_loop(Inner, Tk, String, "]", Row, Start, []); -parse_list({_, _, unknown_type}, Tk, String, Row, Start) -> - parse_list_loop(unknown_type(), Tk, String, "]", Row, Start, []); +parse_list({_, _, {list, [Inner]}}, Pos, String, Row, Start) -> + parse_list_loop(Inner, Pos, String, "]", Row, Start, []); +parse_list({_, _, unknown_type}, Pos, String, Row, Start) -> + parse_list_loop(unknown_type(), Pos, String, "]", Row, Start, []); parse_list({O, N, _}, _, _, Row, Start) -> {error, {wrong_type, O, N, list, Row, Start, Start}}. -parse_list_loop(Inner, Tk, String, CloseChar, Row, Start, Acc) -> - case next_token(Tk, String) of - {ok, {{character, CloseChar, _, _, _, _}, NewTk, NewString}} -> - {ok, {lists:reverse(Acc), NewTk, NewString}}; - {ok, {Token, NewTk, NewString}} -> - parse_list_loop2(Inner, NewTk, NewString, CloseChar, Row, Start, Acc, Token) +parse_list_loop(Inner, Pos, String, CloseChar, Row, Start, Acc) -> + case next_token(Pos, String) of + {ok, {{character, CloseChar, _, _, _, _}, NewPos, NewString}} -> + {ok, {lists:reverse(Acc), NewPos, NewString}}; + {ok, {Token, NewPos, NewString}} -> + parse_list_loop2(Inner, NewPos, NewString, CloseChar, Row, Start, Acc, Token) end. -parse_list_loop2(Inner, Tk, String, CloseChar, Row, Start, Acc, Token) -> - case parse_expression2(Inner, Tk, String, Token) of - {ok, {Value, NewTk, NewString}} -> - parse_list_loop3(Inner, NewTk, NewString, CloseChar, Row, Start, [Value | Acc]); +parse_list_loop2(Inner, Pos, String, CloseChar, Row, Start, Acc, Token) -> + case parse_expression2(Inner, Pos, String, Token) of + {ok, {Value, NewPos, NewString}} -> + parse_list_loop3(Inner, NewPos, NewString, CloseChar, Row, Start, [Value | Acc]); {error, Reason} -> Wrapper = choose_list_error_wrapper(CloseChar), % TODO: Are tuple indices off by one from list indices? @@ -342,12 +342,12 @@ parse_list_loop2(Inner, Tk, String, CloseChar, Row, Start, Acc, Token) -> {error, Wrapped} end. -parse_list_loop3(Inner, Tk, String, CloseChar, Row, Start, Acc) -> - case next_token(Tk, String) of - {ok, {{character, CloseChar, _, _, _, _}, NewTk, NewString}} -> - {ok, {lists:reverse(Acc), NewTk, NewString}}; - {ok, {{character, ",", _, _, _, _}, NewTk, NewString}} -> - parse_list_loop(Inner, NewTk, NewString, CloseChar, Row, Start, Acc); +parse_list_loop3(Inner, Pos, String, CloseChar, Row, Start, Acc) -> + case next_token(Pos, String) of + {ok, {{character, CloseChar, _, _, _, _}, NewPos, NewString}} -> + {ok, {lists:reverse(Acc), NewPos, NewString}}; + {ok, {{character, ",", _, _, _, _}, NewPos, NewString}} -> + parse_list_loop(Inner, NewPos, NewString, CloseChar, Row, Start, Acc); {error, Reason} -> {error, Reason} end. @@ -357,22 +357,22 @@ choose_list_error_wrapper(")") -> tuple_element. %%% Ambiguous Parenthesis Parsing -parse_tuple({_, _, unknown_type}, Tk, String, Row, Start) -> +parse_tuple({_, _, unknown_type}, Pos, String, Row, Start) -> % An untyped tuple is a list of untyped terms, and weirdly our list parser % works perfectly for that, as long as we change the closing character to % be ")" instead of "]". - case parse_list_loop(unknown_type(), Tk, String, ")", Row, Start, []) of - {ok, {[Inner], NewTk, NewString}} -> + case parse_list_loop(unknown_type(), Pos, String, ")", Row, Start, []) of + {ok, {[Inner], NewPos, NewString}} -> % In Sophia, singleton tuples are unwrapped, and given the inner % type. - {ok, {Inner, NewTk, NewString}}; - {ok, {TermList, NewTk, NewString}} -> + {ok, {Inner, NewPos, NewString}}; + {ok, {TermList, NewPos, NewString}} -> Result = {tuple, list_to_tuple(TermList)}, - {ok, {Result, NewTk, NewString}}; + {ok, {Result, NewPos, NewString}}; {error, Reason} -> {error, Reason} end; -parse_tuple({O, N, T}, Tk, String, _, _) -> +parse_tuple({O, N, T}, Pos, String, _, _) -> % Typed tuple parsing is quite complex, because we also want to support % normal parentheses for grouping. It's not strictly necessary for % inputting data, since we don't have any infix operators in simple @@ -382,23 +382,23 @@ parse_tuple({O, N, T}, Tk, String, _, _) -> % Count how many ambiguous parens there are, including the one we already % saw. - case count_open_parens(Tk, String, 1) of - {ok, {Count, Token, NewTk, NewString}} -> + case count_open_parens(Pos, String, 1) of + {ok, {Count, Token, NewPos, NewString}} -> % Compare that to the amount of nesting tuple connectives are in % the type we are expected to produce. {ExcessCount, HeadType, Tails} = extract_tuple_type_info(Count, {O, N, T}, []), % Now work out what to do with all this information. - parse_tuple2(O, N, ExcessCount, HeadType, Tails, NewTk, NewString, Token); + parse_tuple2(O, N, ExcessCount, HeadType, Tails, NewPos, NewString, Token); {error, Reason} -> {error, Reason} end. -count_open_parens(Tk, String, Count) -> - case next_token(Tk, String) of - {ok, {{character, "(", _, _, _, _}, NewTk, NewString}} -> - count_open_parens(NewTk, NewString, Count + 1); - {ok, {Token, NewTk, NewString}} -> - {ok, {Count, Token, NewTk, NewString}}; +count_open_parens(Pos, String, Count) -> + case next_token(Pos, String) of + {ok, {{character, "(", _, _, _, _}, NewPos, NewString}} -> + count_open_parens(NewPos, NewString, Count + 1); + {ok, {Token, NewPos, NewString}} -> + {ok, {Count, Token, NewPos, NewString}}; {error, Reason} -> {error, Reason} end. @@ -412,15 +412,15 @@ extract_tuple_type_info(ParenCount, HeadType, Tails) -> parse_tuple2(_, _, _, {_, _, unknown_type}, [_ | _], _, _, _) -> {error, "Parsing of tuples with known lengths but unknown contents is not yet implemented."}; -parse_tuple2(O, N, ExcessCount, HeadType, Tails, Tk, String, {character, ")", _, Row, Col, _}) -> - parse_empty_tuple(O, N, ExcessCount, HeadType, Tails, Tk, String, Row, Col); -parse_tuple2(O, N, ExcessCount, HeadType, Tails, Tk, String, Token) -> +parse_tuple2(O, N, ExcessCount, HeadType, Tails, Pos, String, {character, ")", _, Row, Col, _}) -> + parse_empty_tuple(O, N, ExcessCount, HeadType, Tails, Pos, String, Row, Col); +parse_tuple2(O, N, ExcessCount, HeadType, Tails, Pos, String, Token) -> % Finished with parentheses for now, try and parse an expression out, to % get our head term. - case parse_expression2(HeadType, Tk, String, Token) of - {ok, {Result, NewTk, NewString}} -> + case parse_expression2(HeadType, Pos, String, Token) of + {ok, {Result, NewPos, NewString}} -> % Got a head term. Now try to build all the other tuple layers. - parse_tuple_tails(O, N, ExcessCount, Result, Tails, NewTk, NewString); + parse_tuple_tails(O, N, ExcessCount, Result, Tails, NewPos, NewString); {error, Reason} -> % TODO: Wrap errors here too. {error, Reason} @@ -434,44 +434,44 @@ parse_empty_tuple(_, _, 0, _, Tails, _, _, Row, Col) -> % got zero. ExpectCount = 1 + length(Tail), {error, {not_enough_elements, ExpectCount, 0, Row, Col}}; -parse_empty_tuple(O, N, ExcessCount, {_, _, {tuple, []}}, Tails, Tk, String, _, _) -> +parse_empty_tuple(O, N, ExcessCount, {_, _, {tuple, []}}, Tails, Pos, String, _, _) -> % If we have some ambiguous parentheses left, we now know one of them is % this empty tuple. HeadTerm = {tuple, {}}, NewExcessCount = ExcessCount - 1, % Now continue the loop as if it were an integer or something, in the head % position. - parse_tuple_tails(O, N, NewExcessCount, HeadTerm, Tails, Tk, String); + parse_tuple_tails(O, N, NewExcessCount, HeadTerm, Tails, Pos, String); parse_empty_tuple(_, _, _, {HeadO, HeadN, _}, _, _, _, Row, Col) -> % We were expecting a head term of a different type! {error, {wrong_type, HeadO, HeadN, unit, Row, Col, Col}}. -parse_tuple_tails(O, N, 0, HeadTerm, [TailTypes | ParentTails], Tk, String) -> +parse_tuple_tails(O, N, 0, HeadTerm, [TailTypes | ParentTails], Pos, String) -> % Tuples left to build, but no extra open parens to deal with, so we can % just parse multivalues naively, starting from the "we have a term, % waiting for a comma" stage of the loop. - case parse_multivalue3(TailTypes, Tk, String, -1, -1, [HeadTerm]) of - {ok, {Terms, NewTk, NewString}} -> + case parse_multivalue3(TailTypes, Pos, String, -1, -1, [HeadTerm]) of + {ok, {Terms, NewPos, NewString}} -> NewHead = {tuple, list_to_tuple(Terms)}, - parse_tuple_tails(O, N, 0, NewHead, ParentTails, NewTk, NewString); + parse_tuple_tails(O, N, 0, NewHead, ParentTails, NewPos, NewString); {error, Reason} -> % TODO: More error wrapping? {error, Reason} end; -parse_tuple_tails(_, _, 0, HeadTerm, [], Tk, String) -> +parse_tuple_tails(_, _, 0, HeadTerm, [], Pos, String) -> % No open parens left, no tuples left to build, we are done! - {ok, {HeadTerm, Tk, String}}; -parse_tuple_tails(O, N, ExcessCount, HeadTerm, Tails, Tk, String) -> + {ok, {HeadTerm, Pos, String}}; +parse_tuple_tails(O, N, ExcessCount, HeadTerm, Tails, Pos, String) -> % The ambiguous case, where we have a mix of tuple parens, and grouping % parens. We want to peek at the next token, to see if it closes a grouping % paren. - case next_token(Tk, String) of - {ok, {{character, ")", _, _, _, _}, NewTk, NewString}} -> + case next_token(Pos, String) of + {ok, {{character, ")", _, _, _, _}, NewPos, NewString}} -> % It is grouping! Close one excess paren, and continue. - parse_tuple_tails(O, N, ExcessCount - 1, HeadTerm, Tails, NewTk, NewString); - {ok, {{character, ",", _, _, _, _}, NewTk, NewString}} -> + parse_tuple_tails(O, N, ExcessCount - 1, HeadTerm, Tails, NewPos, NewString); + {ok, {{character, ",", _, _, _, _}, NewPos, NewString}} -> % It is a real tuple! Try the normal logic, then. - parse_tuple_tails2(O, N, ExcessCount, HeadTerm, Tails, NewTk, NewString); + parse_tuple_tails2(O, N, ExcessCount, HeadTerm, Tails, NewPos, NewString); {ok, {{_, Actual, _, Row, Start, End}, _, _}} -> % Anything else is just a boring parse error we can complain about. {error, {unexpected_token, Actual, Row, Start, End}}; @@ -479,11 +479,11 @@ parse_tuple_tails(O, N, ExcessCount, HeadTerm, Tails, Tk, String) -> {error, Reason} end. -parse_tuple_tails2(O, N, ExcessCount, HeadTerm, [TailTypes | ParentTails], Tk, String) -> - case parse_multivalue(TailTypes, Tk, String, -1, -1, [HeadTerm]) of - {ok, {Terms, NewTk, NewString}} -> +parse_tuple_tails2(O, N, ExcessCount, HeadTerm, [TailTypes | ParentTails], Pos, String) -> + case parse_multivalue(TailTypes, Pos, String, -1, -1, [HeadTerm]) of + {ok, {Terms, NewPos, NewString}} -> NewHead = {tuple, list_to_tuple(Terms)}, - parse_tuple_tails(O, N, ExcessCount, NewHead, ParentTails, NewTk, NewString); + parse_tuple_tails(O, N, ExcessCount, NewHead, ParentTails, NewPos, NewString); {error, Reason} -> % TODO: wrap errors? {error, Reason} @@ -504,43 +504,43 @@ parse_tuple_tails2(O, N, _, _, [], _, _) -> %%% Unambiguous Tuple/Variant Parsing -parse_multivalue(ElemTypes, Tk, String, Row, Start, Acc) -> - case next_token(Tk, String) of - {ok, {{character, ")", _, Row2, Start2, _}, NewTk, NewString}} -> - check_multivalue_long_enough(ElemTypes, NewTk, NewString, Row2, Start2, Acc); - {ok, {Token, NewTk, NewString}} -> - parse_multivalue2(ElemTypes, NewTk, NewString, Row, Start, Acc, Token) +parse_multivalue(ElemTypes, Pos, String, Row, Start, Acc) -> + case next_token(Pos, String) of + {ok, {{character, ")", _, Row2, Start2, _}, NewPos, NewString}} -> + check_multivalue_long_enough(ElemTypes, NewPos, NewString, Row2, Start2, Acc); + {ok, {Token, NewPos, NewString}} -> + parse_multivalue2(ElemTypes, NewPos, NewString, Row, Start, Acc, Token) end. -parse_multivalue2([Next | Rest], Tk, String, Row, Start, Acc, Token) -> - case parse_expression2(Next, Tk, String, Token) of - {ok, {Value, NewTk, NewString}} -> - parse_multivalue3(Rest, NewTk, NewString, Row, Start, [Value | Acc]); +parse_multivalue2([Next | Rest], Pos, String, Row, Start, Acc, Token) -> + case parse_expression2(Next, Pos, String, Token) of + {ok, {Value, NewPos, NewString}} -> + parse_multivalue3(Rest, NewPos, NewString, Row, Start, [Value | Acc]); {error, Reason} -> Wrapper = choose_list_error_wrapper(")"), % TODO: Are tuple indices off by one from list indices? Wrapped = wrap_error(Reason, {Wrapper, length(Acc)}), {error, Wrapped} end; -parse_multivalue2([], Tk, String, _, _, Acc, {character, ")", _, _, _, _}) -> - {ok, {lists:reverse(Acc), Tk, String}}; +parse_multivalue2([], Pos, String, _, _, Acc, {character, ")", _, _, _, _}) -> + {ok, {lists:reverse(Acc), Pos, String}}; parse_multivalue2([], _, _, _, _, _, {_, S, _, Row, Start, End}) -> {error, {unexpected_token, S, Row, Start, End}}. -parse_multivalue3(ElemTypes, Tk, String, Row, Start, Acc) -> - case next_token(Tk, String) of - {ok, {{character, ")", _, Row2, Start2, _}, NewTk, NewString}} -> - check_multivalue_long_enough(ElemTypes, NewTk, NewString, Row2, Start2, Acc); - {ok, {{character, ",", _, _, _, _}, NewTk, NewString}} -> - parse_multivalue(ElemTypes, NewTk, NewString, Row, Start, Acc); +parse_multivalue3(ElemTypes, Pos, String, Row, Start, Acc) -> + case next_token(Pos, String) of + {ok, {{character, ")", _, Row2, Start2, _}, NewPos, NewString}} -> + check_multivalue_long_enough(ElemTypes, NewPos, NewString, Row2, Start2, Acc); + {ok, {{character, ",", _, _, _, _}, NewPos, NewString}} -> + parse_multivalue(ElemTypes, NewPos, NewString, Row, Start, Acc); {ok, {{_, Actual, _, Row, Start, End}, _, _}} -> {error, {unexpected_token, Actual, Row, Start, End}}; {error, Reason} -> {error, Reason} end. -check_multivalue_long_enough([], Tk, String, _, _, Acc) -> - {ok, {lists:reverse(Acc), Tk, String}}; +check_multivalue_long_enough([], Pos, String, _, _, Acc) -> + {ok, {lists:reverse(Acc), Pos, String}}; check_multivalue_long_enough(Remaining, _, _, Row, Col, Got) -> GotCount = length(Got), ExpectCount = length(Remaining) + GotCount, @@ -548,8 +548,8 @@ check_multivalue_long_enough(Remaining, _, _, Row, Col, Got) -> %%% Variant parsing -parse_variant({_, _, {variant, Variants}}, Tk, String, Ident, Row, Start, End) -> - parse_variant2(Variants, Tk, String, Ident, Row, Start, End); +parse_variant({_, _, {variant, Variants}}, Pos, String, Ident, Row, Start, End) -> + parse_variant2(Variants, Pos, String, Ident, Row, Start, End); parse_variant({_, _, unknown_type}, _, _, _, Row, Start, End) -> {error, {unresolved_variant, Row, Start, End}}; parse_variant({O, N, _}, _, _, _, Row, Start, End) -> @@ -560,33 +560,33 @@ parse_variant({O, N, _}, _, _, _, Row, Start, End) -> % a variant. {error, {wrong_type, O, N, variant, Row, Start, End}}. -parse_variant2(Variants, Tk, String, Ident, Row, Start, End) -> +parse_variant2(Variants, Pos, String, Ident, Row, Start, End) -> case lookup_variant(Ident, Variants, 0) of {ok, {Tag, ElemTypes}} -> GetArity = fun({_, OtherElemTypes}) -> length(OtherElemTypes) end, Arities = lists:map(GetArity, Variants), - parse_variant3(Arities, Tag, ElemTypes, Tk, String); + parse_variant3(Arities, Tag, ElemTypes, Pos, String); error -> {error, {invalid_constructor, Ident, Row, Start, End}} end. -parse_variant3(Arities, Tag, [], Tk, String) -> +parse_variant3(Arities, Tag, [], Pos, String) -> % Parsing of 0-arity variants is different. Result = {variant, Arities, Tag, {}}, - {ok, {Result, Tk, String}}; -parse_variant3(Arities, Tag, ElemTypes, Tk, String) -> - case next_token(Tk, String) of - {ok, {{character, "(", _, Row, Start, _}, NewTk, NewString}} -> - parse_variant4(Arities, Tag, ElemTypes, NewTk, NewString, Row, Start); + {ok, {Result, Pos, String}}; +parse_variant3(Arities, Tag, ElemTypes, Pos, String) -> + case next_token(Pos, String) of + {ok, {{character, "(", _, Row, Start, _}, NewPos, NewString}} -> + parse_variant4(Arities, Tag, ElemTypes, NewPos, NewString, Row, Start); {ok, {{_, Actual, _, Row, Start, End}, _, _}} -> {error, {unexpected_token, Actual, Row, Start, End}} end. -parse_variant4(Arities, Tag, ElemTypes, Tk, String, Row, Start) -> - case parse_multivalue(ElemTypes, Tk, String, Row, Start, []) of - {ok, {Terms, NewTk, NewString}} -> +parse_variant4(Arities, Tag, ElemTypes, Pos, String, Row, Start) -> + case parse_multivalue(ElemTypes, Pos, String, Row, Start, []) of + {ok, {Terms, NewPos, NewString}} -> Result = {variant, Arities, Tag, list_to_tuple(Terms)}, - {ok, {Result, NewTk, NewString}}; + {ok, {Result, NewPos, NewString}}; {error, Reason} -> {error, Reason} end. @@ -600,16 +600,16 @@ lookup_variant(Ident, [_ | Rest], Tag) -> %%% Record parsing -parse_record_or_map({_, _, {map, [KeyType, ValueType]}}, Tk, String, _, _) -> - parse_map(KeyType, ValueType, Tk, String, #{}); -parse_record_or_map({_, _, {record, Fields}}, Tk, String, _, _) -> - parse_record(Fields, Tk, String, #{}); -parse_record_or_map({_, _, unknown_type}, Tk, String, _, _) -> - case next_token(Tk, String) of - {ok, {{character, "}", _, _, _, _}, NewTk, NewString}} -> - {ok, {#{}, NewTk, NewString}}; - {ok, {{character, "[", _, _, _, _}, NewTk, NewString}} -> - parse_map2(unknown_type(), unknown_type(), NewTk, NewString, #{}); +parse_record_or_map({_, _, {map, [KeyType, ValueType]}}, Pos, String, _, _) -> + parse_map(KeyType, ValueType, Pos, String, #{}); +parse_record_or_map({_, _, {record, Fields}}, Pos, String, _, _) -> + parse_record(Fields, Pos, String, #{}); +parse_record_or_map({_, _, unknown_type}, Pos, String, _, _) -> + case next_token(Pos, String) of + {ok, {{character, "}", _, _, _, _}, NewPos, NewString}} -> + {ok, {#{}, NewPos, NewString}}; + {ok, {{character, "[", _, _, _, _}, NewPos, NewString}} -> + parse_map2(unknown_type(), unknown_type(), NewPos, NewString, #{}); {ok, {{alphanum, _, _, Row, Start, End}, _, _}} -> {error, {unresolved_record, Row, Start, End}}; {ok, {{_, S, _, Row, Start, End}, _, _}} -> @@ -618,67 +618,67 @@ parse_record_or_map({_, _, unknown_type}, Tk, String, _, _) -> parse_record_or_map({O, N, _}, _, _, Row, Start) -> {error, {wrong_type, O, N, map, Row, Start, Start}}. -parse_record(Fields, Tk, String, Acc) -> - case next_token(Tk, String) of - {ok, {{alphanum, Ident, _, Row, Start, End}, NewTk, NewString}} -> - parse_record2(Fields, NewTk, NewString, Acc, Ident, Row, Start, End); - {ok, {{character, "}", _, Row, Start, End}, NewTk, NewString}} -> - parse_record_end(Fields, NewTk, NewString, Acc, Row, Start, End); +parse_record(Fields, Pos, String, Acc) -> + case next_token(Pos, String) of + {ok, {{alphanum, Ident, _, Row, Start, End}, NewPos, NewString}} -> + parse_record2(Fields, NewPos, NewString, Acc, Ident, Row, Start, End); + {ok, {{character, "}", _, Row, Start, End}, NewPos, NewString}} -> + parse_record_end(Fields, NewPos, NewString, Acc, Row, Start, End); {ok, {{_, S, _, Row, Start, End}, _, _}} -> {error, {unexpected_token, S, Row, Start, End}}; {error, Reason} -> {error, Reason} end. -parse_record2(Fields, Tk, String, Acc, Ident, Row, Start, End) -> +parse_record2(Fields, Pos, String, Acc, Ident, Row, Start, End) -> case lists:keyfind(Ident, 1, Fields) of {_, Type} -> - parse_record3(Fields, Tk, String, Acc, Ident, Row, Start, End, Type); + parse_record3(Fields, Pos, String, Acc, Ident, Row, Start, End, Type); false -> {error, {invalid_field, Ident, Row, Start, End}} end. -parse_record3(Fields, Tk, String, Acc, Ident, Row, Start, End, Type) -> +parse_record3(Fields, Pos, String, Acc, Ident, Row, Start, End, Type) -> case maps:is_key(Ident, Acc) of false -> - parse_record4(Fields, Tk, String, Acc, Ident, Type); + parse_record4(Fields, Pos, String, Acc, Ident, Type); true -> {error, {field_already_present, Ident, Row, Start, End}} end. -parse_record4(Fields, Tk, String, Acc, Ident, Type) -> - case expect_tokens(["="], Tk, String) of - {ok, {NewTk, NewString}} -> - parse_record5(Fields, NewTk, NewString, Acc, Ident, Type); +parse_record4(Fields, Pos, String, Acc, Ident, Type) -> + case expect_tokens(["="], Pos, String) of + {ok, {NewPos, NewString}} -> + parse_record5(Fields, NewPos, NewString, Acc, Ident, Type); {error, Reason} -> {error, Reason} end. -parse_record5(Fields, Tk, String, Acc, Ident, Type) -> - case parse_expression(Type, Tk, String) of - {ok, {Result, NewTk, NewString}} -> +parse_record5(Fields, Pos, String, Acc, Ident, Type) -> + case parse_expression(Type, Pos, String) of + {ok, {Result, NewPos, NewString}} -> NewAcc = maps:put(Ident, Result, Acc), - parse_record6(Fields, NewTk, NewString, NewAcc); + parse_record6(Fields, NewPos, NewString, NewAcc); {error, Reason} -> wrap_error(Reason, {record_field, Ident}) end. -parse_record6(Fields, Tk, String, Acc) -> - case next_token(Tk, String) of - {ok, {{character, ",", _, _, _, _}, NewTk, NewString}} -> - parse_record(Fields, NewTk, NewString, Acc); - {ok, {{character, "}", _, Row, Start, End}, NewTk, NewString}} -> - parse_record_end(Fields, NewTk, NewString, Acc, Row, Start, End); +parse_record6(Fields, Pos, String, Acc) -> + case next_token(Pos, String) of + {ok, {{character, ",", _, _, _, _}, NewPos, NewString}} -> + parse_record(Fields, NewPos, NewString, Acc); + {ok, {{character, "}", _, Row, Start, End}, NewPos, NewString}} -> + parse_record_end(Fields, NewPos, NewString, Acc, Row, Start, End); {ok, {{_, S, _, Row, Start, End}, _, _}} -> {error, {unexpected_token, S, Row, Start, End}}; {error, Reason} -> {error, Reason} end. -parse_record_end(Fields, Tk, String, FieldValues, Row, Start, End) -> +parse_record_end(Fields, Pos, String, FieldValues, Row, Start, End) -> case parse_record_final_loop(Fields, FieldValues, []) of {ok, Result} -> - {ok, {Result, Tk, String}}; + {ok, {Result, Pos, String}}; {error, {missing_field, Name}} -> {error, {missing_field, Name, Row, Start, End}} end. @@ -702,47 +702,47 @@ parse_record_final_loop([], _, FieldsReverse) -> %%% Map Parsing -parse_map(KeyType, ValueType, Tk, String, Acc) -> - case next_token(Tk, String) of - {ok, {{character, "[", _, _, _, _}, NewTk, NewString}} -> - parse_map2(KeyType, ValueType, NewTk, NewString, Acc); - {ok, {{character, "}", _, _, _, _}, NewTk, NewString}} -> - {ok, {Acc, NewTk, NewString}}; +parse_map(KeyType, ValueType, Pos, String, Acc) -> + case next_token(Pos, String) of + {ok, {{character, "[", _, _, _, _}, NewPos, NewString}} -> + parse_map2(KeyType, ValueType, NewPos, NewString, Acc); + {ok, {{character, "}", _, _, _, _}, NewPos, NewString}} -> + {ok, {Acc, NewPos, NewString}}; {ok, {{_, S, _, Row, Start, End}, _, _}} -> {error, {unexpected_token, S, Row, Start, End}} end. -parse_map2(KeyType, ValueType, Tk, String, Acc) -> - case parse_expression(KeyType, Tk, String) of - {ok, {Result, NewTk, NewString}} -> - parse_map3(KeyType, ValueType, NewTk, NewString, Acc, Result); +parse_map2(KeyType, ValueType, Pos, String, Acc) -> + case parse_expression(KeyType, Pos, String) of + {ok, {Result, NewPos, NewString}} -> + parse_map3(KeyType, ValueType, NewPos, NewString, Acc, Result); {error, Reason} -> wrap_error(Reason, {map_key, maps:size(Acc)}) end. -parse_map3(KeyType, ValueType, Tk, String, Acc, Key) -> - case expect_tokens(["]", "="], Tk, String) of - {ok, {NewTk, NewString}} -> - parse_map4(KeyType, ValueType, NewTk, NewString, Acc, Key); +parse_map3(KeyType, ValueType, Pos, String, Acc, Key) -> + case expect_tokens(["]", "="], Pos, String) of + {ok, {NewPos, NewString}} -> + parse_map4(KeyType, ValueType, NewPos, NewString, Acc, Key); {error, Reason} -> {error, Reason} end. -parse_map4(KeyType, ValueType, Tk, String, Acc, Key) -> - case parse_expression(ValueType, Tk, String) of - {ok, {Result, NewTk, NewString}} -> +parse_map4(KeyType, ValueType, Pos, String, Acc, Key) -> + case parse_expression(ValueType, Pos, String) of + {ok, {Result, NewPos, NewString}} -> NewAcc = maps:put(Key, Result, Acc), - parse_map5(KeyType, ValueType, NewTk, NewString, NewAcc); + parse_map5(KeyType, ValueType, NewPos, NewString, NewAcc); {error, Reason} -> {error, Reason} end. -parse_map5(KeyType, ValueType, Tk, String, Acc) -> - case next_token(Tk, String) of - {ok, {{character, ",", _, _, _, _}, NewTk, NewString}} -> - parse_map(KeyType, ValueType, NewTk, NewString, Acc); - {ok, {{character, "}", _, _, _, _}, NewTk, NewString}} -> - {ok, {Acc, NewTk, NewString}}; +parse_map5(KeyType, ValueType, Pos, String, Acc) -> + case next_token(Pos, String) of + {ok, {{character, ",", _, _, _, _}, NewPos, NewString}} -> + parse_map(KeyType, ValueType, NewPos, NewString, Acc); + {ok, {{character, "}", _, _, _, _}, NewPos, NewString}} -> + {ok, {Acc, NewPos, NewString}}; {ok, {{_, S, _, Row, Start, End}, _, _}} -> {error, {unexpected_token, S, Row, Start, End}} end.