From 78c9c67f38cba528249c16dc06b6fca9f9393f76 Mon Sep 17 00:00:00 2001 From: Jarvis Carroll Date: Fri, 13 Feb 2026 06:22:07 +0000 Subject: [PATCH] typecheck bits Sophia bitstrings aren't really something you initialize manually, so we have to make up a literal format for them. Failing that, we just accept arbitrary integers and bytearrays as bitstrings. --- src/hz_sophia.erl | 48 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/src/hz_sophia.erl b/src/hz_sophia.erl index ef6a55e..be294c2 100644 --- a/src/hz_sophia.erl +++ b/src/hz_sophia.erl @@ -236,13 +236,13 @@ parse_expression(Type, Pos, String) -> end. parse_expression2(Type, Pos, String, {integer, _, Value, Row, Start, End}) -> - case Type of - {_, _, integer} -> - {ok, {Value, Pos, String}}; - {_, _, unknown_type} -> - {ok, {Value, Pos, String}}; - {O, N, _} -> - {error, {wrong_type, O, N, integer, Row, Start, End}} + typecheck_integer(Type, Pos, String, Value, Row, Start, End); +parse_expression2(Type, Pos, String, {character, "-", _, _, _, _}) -> + case next_token(Pos, String) of + {ok, {{integer, _, Value, Row, Start, End}, NewPos, NewString}} -> + typecheck_integer(Type, NewPos, NewString, -Value, Row, Start, End); + {error, Reason} -> + {error, Reason} end; parse_expression2(Type, Pos, String, {bytes, _, Value, Row, Start, End}) -> Len = byte_size(Value), @@ -254,6 +254,10 @@ parse_expression2(Type, Pos, String, {bytes, _, Value, Row, Start, End}) -> {ok, {Result, Pos, String}}; {_, _, {bytes, [ExpectedLen]}} -> {error, {bytes_wrong_size, ExpectedLen, Len, Row, Start, End}}; + {_, _, bits} -> + Size = bit_size(Value), + <> = Value, + {ok, {{bits, IntValue}, Pos, String}}; {_, _, unknown_type} -> {ok, {Result, Pos, String}}; {O, N, _} -> @@ -323,6 +327,10 @@ parse_alphanum(Type, Pos, String, ["true"], Row, Start, End) -> typecheck_bool(Type, Pos, String, true, Row, Start, End); parse_alphanum(Type, Pos, String, ["false"], Row, Start, End) -> typecheck_bool(Type, Pos, String, false, Row, Start, End); +parse_alphanum(Type, Pos, String, ["Bits", "all"], Row, Start, End) -> + typecheck_bits(Type, Pos, String, -1, Row, Start, End); +parse_alphanum(Type, Pos, String, ["Bits", "none"], Row, Start, End) -> + typecheck_bits(Type, Pos, String, 0, Row, Start, End); parse_alphanum(Type, Pos, String, [[C | _] = S], Row, Start, End) when ?IS_LATIN_LOWER(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. @@ -350,6 +358,15 @@ parse_alphanum(Type, Pos, String, Path, Row, Start, End) -> % must be a variant constructor, or invalid. parse_variant(Type, Pos, String, Path, Row, Start, End). +typecheck_integer({_, _, integer}, Pos, String, Value, _, _, _) -> + {ok, {Value, Pos, String}}; +typecheck_integer({_, _, unknown_type}, Pos, String, Value, _, _, _) -> + {ok, {Value, Pos, String}}; +typecheck_integer({_, _, bits}, Pos, String, Value, _, _, _) -> + {ok, {{bits, Value}, Pos, String}}; +typecheck_integer({O, N, _}, _, _, _, Row, Start, End) -> + {error, {wrong_type, O, N, integer, Row, Start, End}}. + typecheck_bool({_, _, unknown_type}, Pos, String, Value, _, _, _) -> {ok, {Value, Pos, String}}; typecheck_bool({_, _, boolean}, Pos, String, Value, _, _, _) -> @@ -357,6 +374,13 @@ typecheck_bool({_, _, boolean}, Pos, String, Value, _, _, _) -> typecheck_bool({O, N, _}, _, _, _, Row, Start, End) -> {error, {wrong_type, O, N, boolean, Row, Start, End}}. +typecheck_bits({_, _, unknown_type}, Pos, String, Value, _, _, _) -> + {ok, {{bits, Value}, Pos, String}}; +typecheck_bits({_, _, bits}, Pos, String, Value, _, _, _) -> + {ok, {{bits, Value}, Pos, String}}; +typecheck_bits({O, N, _}, _, _, _, Row, Start, End) -> + {error, {wrong_type, O, N, bits, Row, Start, End}}. + typecheck_address({_, _, address}, Pos, String, Data, _, _, _) -> {ok, {{address, Data}, Pos, String}}; typecheck_address({_, _, contract}, Pos, String, Data, _, _, _) -> @@ -939,6 +963,7 @@ anon_types_test() -> % Integers. check_parser("123"), check_parser("1_2_3"), + check_parser("-123"), % Booleans. check_parser("true"), check_parser("false"), @@ -1038,6 +1063,15 @@ chain_objects_test() -> ok. +bits_test() -> + check_parser("Bits.all"), + check_parser("Bits.none"), + {_, Type} = compile_entrypoint_value_and_type("contract C = entrypoint f() = Bits.all", "f"), + check_sophia_to_fate(Type, "5", {bits, 5}), + check_sophia_to_fate(Type, "-5", {bits, -5}), + check_sophia_to_fate(Type, "#123", {bits, 256 + 32 + 3}), + ok. + singleton_records_test() -> TypeDef = "record singleton('a) = {it: 'a}", check_parser_with_typedef(TypeDef, "{it = 123}"),