Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 18 additions & 8 deletions src/Fable.Transforms/Dart/Replacements.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1874,14 +1874,24 @@ let arrayModule (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (_: Ex

let lists (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (thisArg: Expr option) (args: Expr list) =
match i.CompiledName, thisArg, args with
// Use methods for Head and Tail (instead of Get(ListHead) for example) to check for empty lists
| ReplaceName [ "get_Head", "head"
"get_Tail", "tail"
"get_Item", "item"
"get_Length", "length"
"GetSlice", "getSlice" ] methName,
Some x,
_ ->
// list.Head and list.Tail raise InvalidOperationException, List.head and List.tail ArgumentException
| ("get_Head" | "get_Tail"), Some x, _ ->
let mangledName =
Naming.buildNameWithoutSanitationFrom "FSharpList" false i.CompiledName ""

Helper.LibCall(
com,
"List",
mangledName,
t,
[],
i.SignatureArgTypes,
genArgs = i.GenericArgs,
thisArg = x,
?loc = r
)
|> Some
| ReplaceName [ "get_Item", "item"; "get_Length", "length"; "GetSlice", "getSlice" ] methName, Some x, _ ->
let args =
match args with
| [ ExprType Unit ] -> [ x ]
Expand Down
15 changes: 7 additions & 8 deletions src/Fable.Transforms/Python/Replacements.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2107,14 +2107,13 @@ let arrayModule (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (_: Ex

let lists (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (thisArg: Expr option) (args: Expr list) =
match i.CompiledName, thisArg, args with
// Use methods for Head and Tail (instead of Get(ListHead) for example) to check for empty lists
| ReplaceName [ "get_Head", "head"
"get_Tail", "tail"
"get_Item", "item"
"get_Length", "length"
"GetSlice", "getSlice" ] methName,
Some x,
_ ->
// list.Head and list.Tail raise InvalidOperationException, List.head and List.tail ArgumentException
| ("get_Head" | "get_Tail"), Some x, _ ->
let mangledName =
Naming.buildNameWithoutSanitationFrom "FSharpList" false i.CompiledName ""

Helper.LibCall(com, "list", mangledName, t, [], thisArg = x, ?loc = r) |> Some
| ReplaceName [ "get_Item", "item"; "get_Length", "length"; "GetSlice", "getSlice" ] methName, Some x, _ ->
let args =
match args with
| [ ExprType Unit ] -> [ x ]
Expand Down
10 changes: 7 additions & 3 deletions src/Fable.Transforms/Replacements.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2283,8 +2283,6 @@ let nativeArrayFunctions =
"Filter", "filter"
"ForAll", "every"
"Iterate", "forEach"
"Reduce", "reduce"
"ReduceBack", "reduceRight"
"SortInPlaceWith", "sort"
|]

Expand Down Expand Up @@ -2403,7 +2401,13 @@ let arrayModule (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (_: Ex

let lists (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (thisArg: Expr option) (args: Expr list) =
match i.CompiledName, thisArg, args with
// Use methods for Head and Tail (instead of Get(ListHead) for example) to check for empty lists
// list.Head and list.Tail raise InvalidOperationException, List.head and List.tail ArgumentException
// PHP's FSharpList has no such members, so PHP keeps the head/tail functions below.
| ("get_Head" | "get_Tail"), Some x, _ when com.Options.Language <> Php ->
let mangledName =
Naming.buildNameWithoutSanitationFrom "FSharpList" false i.CompiledName ""

Helper.LibCall(com, "List", mangledName, t, [], thisArg = x, ?loc = r) |> Some
| ReplaceName [ "get_Head", "head"
"get_Tail", "tail"
"get_Item", "item"
Expand Down
2 changes: 1 addition & 1 deletion src/fable-library-beam/Range.fs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ let makeRangeStepFunction<'T when 'T: comparison> (step: 'T) (stop: 'T) (zero: '
let stepComparedWithZero = compare step zero

if stepComparedWithZero = 0 then
failwith "The step of a range cannot be zero"
invalidArg "step" "The step of a range cannot be zero."

let stepGreaterThanZero = stepComparedWithZero > 0

Expand Down
24 changes: 19 additions & 5 deletions src/fable-library-beam/Seq.fs
Original file line number Diff line number Diff line change
Expand Up @@ -992,15 +992,15 @@ let reduce folder (xs: seq<'T>) =
if e.MoveNext() then
loop e.Current
else
invalidOp SR.inputSequenceEmpty
invalidArg "source" SR.inputSequenceEmpty

let reduceBack folder (xs: seq<'T>) =
let arr = toArray xs

if arr.Length > 0 then
Array.reduceBack folder arr
else
invalidOp SR.inputSequenceEmpty
invalidArg "source" SR.inputSequenceEmpty

let replicate n x = initialize n (fun _ -> x)

Expand Down Expand Up @@ -1035,7 +1035,7 @@ let skip count (source: seq<'T>) =
try
for _ = 1 to count do
if not (e.MoveNext()) then
invalidArg "source" SR.notEnoughElements
invalidOp SR.notEnoughElements

let compensation () = ()
Enumerator.enumerateThenFinally compensation e
Expand All @@ -1057,7 +1057,21 @@ let skipWhile predicate (xs: seq<'T>) =
)
)

let tail (xs: seq<'T>) = skip 1 xs
// FSharp.Core's Seq.tail raises ArgumentException on an empty input, Seq.skip InvalidOperationException
let tail (xs: seq<'T>) =
mkSeq (fun () ->
let e = ofSeq xs

try
if not (e.MoveNext()) then
invalidArg "source" SR.notEnoughElements

let compensation () = ()
Enumerator.enumerateThenFinally compensation e
with _ ->
e.Dispose()
reraise ()
)

let take count (xs: seq<'T>) =
generateIndexed
Expand All @@ -1067,7 +1081,7 @@ let take count (xs: seq<'T>) =
if e.MoveNext() then
Some(e.Current)
else
invalidArg "source" SR.notEnoughElements
invalidOp SR.notEnoughElements
else
None
)
Expand Down
60 changes: 44 additions & 16 deletions src/fable-library-beam/fable_list.erl
Original file line number Diff line number Diff line change
Expand Up @@ -225,10 +225,16 @@ sort_by_descending(Fn, Comparer, List) ->
sort_with(Fn, List) ->
lists:sort(fun(A, B) -> (Fn(A))(B) =< 0 end, List).

index_not_found() ->
erlang:error(#{
exn_type => key_not_found_exception,
message => <<"An index satisfying the predicate was not found in the collection.">>
}).

find(Fn, List) ->
case lists:dropwhile(fun(E) -> not Fn(E) end, List) of
[H | _] -> H;
[] -> erlang:error(<<"key_not_found">>)
[] -> index_not_found()
end.

try_find(Fn, List) ->
Expand All @@ -245,7 +251,7 @@ find_index(Fn, [H | T], I) ->
false -> find_index(Fn, T, I + 1)
end;
find_index(_Fn, [], _I) ->
erlang:error(<<"key_not_found">>).
index_not_found().

try_find_index(Fn, List) ->
try_find_index(Fn, List, 0).
Expand Down Expand Up @@ -387,7 +393,8 @@ try_item(_, _) ->
undefined.

exactly_one([X]) -> X;
exactly_one(_) -> erlang:error(<<"Sequence contains more than one element">>).
exactly_one([]) -> invalid_arg(<<"source">>, <<"The input sequence was empty.">>);
exactly_one(_) -> invalid_arg(<<"source">>, <<"The input sequence contains more than one element.">>).

try_exactly_one([X]) -> fable_option:some(X);
try_exactly_one(_) -> undefined.
Expand Down Expand Up @@ -580,7 +587,7 @@ map_fold_back(Fn, List, State) ->

pick(Fn, List) ->
case try_pick(Fn, List) of
undefined -> erlang:error(<<"key_not_found">>);
undefined -> index_not_found();
V -> V
end.

Expand All @@ -594,7 +601,7 @@ try_pick(Fn, [H | T]) ->

find_index_back(Fn, List) ->
case try_find_index_back(Fn, List) of
undefined -> erlang:error(<<"key_not_found">>);
undefined -> index_not_found();
Idx -> Idx
end.

Expand Down Expand Up @@ -673,7 +680,11 @@ get_slice(Lower, Upper, List) ->
take(Count, List) ->
case erlang:length(List) >= Count of
true -> lists:sublist(List, Count);
false -> erlang:error(<<"The input sequence has an insufficient number of elements.">>)
false ->
erlang:error(#{
exn_type => invalid_operation_exception,
message => <<"The input sequence has an insufficient number of elements.">>
})
end.

%% ---- Random functions --------------------------------------------------------
Expand All @@ -697,13 +708,13 @@ random_shuffle(Xs) ->

-spec random_choice_by(fun((ok) -> float()), list()) -> term().
random_choice_by(_Randomizer, []) ->
erlang:error(<<"The input sequence was empty.">>);
invalid_arg(<<"source">>, <<"The input sequence was empty.">>);
random_choice_by(Randomizer, Xs) ->
Len = erlang:length(Xs),
R = Randomizer(ok),
if
R < 0.0; R >= 1.0 ->
erlang:error(iolist_to_binary(io_lib:format("The index is outside the legal range.~nrandomizer returned ~w, should be in range [0.0, 1.0).", [R])));
randomizer_out_of_range(R);
true ->
lists:nth(erlang:trunc(R * Len) + 1, Xs)
end.
Expand All @@ -720,9 +731,9 @@ random_choice(Xs) ->
random_choices_by(Randomizer, Count, Xs) ->
if
Count < 0 ->
erlang:error(<<"The input must be non-negative.">>);
invalid_arg(<<"count">>, <<"The input must be non-negative.">>);
Count > 0 andalso Xs =:= [] ->
erlang:error(<<"The input sequence was empty.">>);
invalid_arg(<<"source">>, <<"The input sequence was empty.">>);
true ->
Arr = erlang:list_to_tuple(Xs),
Len = erlang:tuple_size(Arr),
Expand All @@ -736,7 +747,7 @@ choices_loop(Randomizer, Arr, Len, N, Acc) ->
R = Randomizer(ok),
if
R < 0.0; R >= 1.0 ->
erlang:error(iolist_to_binary(io_lib:format("The index is outside the legal range.~nrandomizer returned ~w, should be in range [0.0, 1.0).", [R])));
randomizer_out_of_range(R);
true ->
E = erlang:element(erlang:trunc(R * Len) + 1, Arr),
choices_loop(Randomizer, Arr, Len, N - 1, [E | Acc])
Expand All @@ -754,14 +765,14 @@ random_choices(Count, Xs) ->
random_sample_by(Randomizer, Count, Xs) ->
if
Count < 0 ->
erlang:error(<<"The input must be non-negative.">>);
invalid_arg(<<"count">>, <<"The input must be non-negative.">>);
true ->
Len = erlang:length(Xs),
if
Len =:= 0 andalso Count > 0 ->
erlang:error(<<"The input sequence was empty.">>);
invalid_arg(<<"source">>, <<"The input sequence was empty.">>);
Count > Len ->
erlang:error(<<"The input sequence has an insufficient number of elements.">>);
invalid_arg(<<"count">>, <<"The input sequence has an insufficient number of elements.">>);
true ->
sample_loop(Randomizer, erlang:list_to_tuple(Xs), Len, Count, 0)
end
Expand All @@ -782,7 +793,7 @@ sample_loop(Randomizer, Arr, Len, Count, I) ->
R = Randomizer(ok),
if
R < 0.0; R >= 1.0 ->
erlang:error(iolist_to_binary(io_lib:format("The index is outside the legal range.~nrandomizer returned ~w, should be in range [0.0, 1.0).", [R])));
randomizer_out_of_range(R);
true ->
J = I + erlang:trunc(R * (Len - I)),
EI = erlang:element(I + 1, Arr),
Expand All @@ -798,11 +809,28 @@ shuffle_loop(Randomizer, Arr, I) ->
R = Randomizer(ok),
if
R < 0.0; R >= 1.0 ->
erlang:error(iolist_to_binary(io_lib:format("The index is outside the legal range.~nrandomizer returned ~w, should be in range [0.0, 1.0).", [R])));
randomizer_out_of_range(R);
true ->
J = erlang:trunc(R * (I + 1)),
EI = erlang:element(I + 1, Arr),
EJ = erlang:element(J + 1, Arr),
Arr2 = erlang:setelement(I + 1, erlang:setelement(J + 1, Arr, EI), EJ),
shuffle_loop(Randomizer, Arr2, I - 1)
end.

randomizer_out_of_range(R) ->
erlang:error(#{
exn_type => argument_out_of_range_exception,
message => iolist_to_binary(
io_lib:format(
"The index is outside the legal range.~nrandomizer returned ~w, should be in range [0.0, 1.0). (Parameter 'randomizer')",
[R]
)
)
}).

invalid_arg(ParamName, Message) ->
erlang:error(#{
exn_type => argument_exception,
message => fable_utils:argument_exception_message(Message, ParamName)
}).
10 changes: 8 additions & 2 deletions src/fable-library-beam/fable_map.erl
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ iterate(Fn, Map) ->
find_key(Fn, Map) ->
case lists:dropwhile(fun({K, V}) -> not (Fn(K))(V) end, maps:to_list(Map)) of
[{K, _} | _] -> K;
[] -> erlang:error(<<"key_not_found">>)
[] -> key_not_found(<<"An index satisfying the predicate was not found in the collection.">>)
end.

try_find_key(Fn, Map) ->
Expand Down Expand Up @@ -109,7 +109,7 @@ try_get_value(Key, Map, OutRef) ->

pick(Fn, Map) ->
case try_pick(Fn, Map) of
undefined -> erlang:error(<<"key_not_found">>);
undefined -> key_not_found(<<"The given key was not present in the dictionary.">>);
V -> V
end.

Expand Down Expand Up @@ -142,3 +142,9 @@ change(Key, Fn, Map) ->
NewV -> maps:put(Key, NewV, Map)
end
end.

key_not_found(Message) ->
erlang:error(#{
exn_type => key_not_found_exception,
message => Message
}).
Loading
Loading