-module(taffy@native). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/taffy/native.gleam"). -export([parse/1, parse_all/1]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. ?MODULEDOC( " Native YAML parsing backend wrapping the `fast_yaml` C NIF (libyaml).\n" " Erlang target only — requires `fast_yaml` in your dependencies.\n" " Output is the same `YamlValue` shape as the pure-Gleam parser but\n" " ~3-7× faster on large documents.\n" "\n" " ```gleam\n" " import taffy/native\n" "\n" " let assert Ok(value) = native.parse(\"name: John\\nage: 30\")\n" " ```\n" "\n" " One known divergence from the pure parser: `fast_yaml` represents both\n" " `{}` and `[]` as the empty Erlang list at the term level, so the\n" " distinction can't be recovered from the decoded value alone. Taffy\n" " resolves the ambiguity in favour of `Mapping([])` since `{}` is the\n" " more common author intent; users who need `Sequence([])` for `[]`\n" " should use the pure parser.\n" ). -file("src/taffy/native.gleam", 64). -spec format_error(gleam@dynamic:dynamic_()) -> taffy@parser@types:parse_error(). format_error(Err) -> {parse_error, <<"fast_yaml decode error: "/utf8, (gleam@string:inspect(Err))/binary>>, 0}. -file("src/taffy/native.gleam", 103). -spec try_as_string(gleam@dynamic:dynamic_()) -> gleam@option:option(taffy@value:yaml_value()). try_as_string(Val) -> _pipe = taffy_ffi:to_string(Val), _pipe@1 = gleam@result:map(_pipe, fun taffy@parser@scalar:parse_scalar/1), gleam@option:from_result(_pipe@1). -file("src/taffy/native.gleam", 85). -spec try_as_int(gleam@dynamic:dynamic_()) -> gleam@option:option(taffy@value:yaml_value()). try_as_int(Val) -> _pipe = taffy_ffi:to_int(Val), _pipe@1 = gleam@result:map(_pipe, fun(Field@0) -> {int, Field@0} end), gleam@option:from_result(_pipe@1). -file("src/taffy/native.gleam", 89). -spec try_as_float(gleam@dynamic:dynamic_()) -> gleam@option:option(taffy@value:yaml_value()). try_as_float(Val) -> _pipe = taffy_ffi:to_float(Val), _pipe@1 = gleam@result:map(_pipe, fun(Field@0) -> {float, Field@0} end), gleam@option:from_result(_pipe@1). -file("src/taffy/native.gleam", 97). -spec try_as_sequence(gleam@dynamic:dynamic_()) -> gleam@option:option(taffy@value:yaml_value()). try_as_sequence(Val) -> _pipe = taffy_ffi:to_list(Val), _pipe@1 = gleam@result:map( _pipe, fun(Items) -> {sequence, gleam@list:map(Items, fun convert_value/1)} end ), gleam@option:from_result(_pipe@1). -file("src/taffy/native.gleam", 75). -spec convert_value(gleam@dynamic:dynamic_()) -> taffy@value:yaml_value(). convert_value(Val) -> _pipe = try_as_int(Val), _pipe@1 = gleam@option:lazy_or(_pipe, fun() -> try_as_float(Val) end), _pipe@2 = gleam@option:lazy_or(_pipe@1, fun() -> try_as_mapping(Val) end), _pipe@3 = gleam@option:lazy_or(_pipe@2, fun() -> try_as_sequence(Val) end), _pipe@4 = gleam@option:lazy_or(_pipe@3, fun() -> try_as_string(Val) end), gleam@option:unwrap(_pipe@4, null). -file("src/taffy/native.gleam", 68). -spec decode_documents(gleam@dynamic:dynamic_()) -> list(taffy@value:yaml_value()). decode_documents(Docs) -> case taffy_ffi:to_list(Docs) of {ok, Items} -> gleam@list:map(Items, fun convert_value/1); {error, _} -> [convert_value(Docs)] end. -file("src/taffy/native.gleam", 32). ?DOC( " Parse a single document via `fast_yaml`. The error type matches the\n" " pure parser's so callers can swap backends without changing their\n" " error-handling. `pos` is always 0 here — `fast_yaml` doesn't expose a\n" " position on its error path.\n" ). -spec parse(binary()) -> {ok, taffy@value:yaml_value()} | {error, taffy@parser@types:parse_error()}. parse(Input) -> application:ensure_all_started(erlang:binary_to_atom(<<"fast_yaml"/utf8>>)), case fast_yaml:decode(Input) of {ok, Docs} -> case decode_documents(Docs) of [First | _] -> {ok, First}; [] -> {ok, null} end; {error, Err} -> {error, format_error(Err)} end. -file("src/taffy/native.gleam", 47). ?DOC( " Parse a multi-document stream via `fast_yaml`. Same error semantics\n" " as `parse`.\n" ). -spec parse_all(binary()) -> {ok, list(taffy@value:yaml_value())} | {error, taffy@parser@types:parse_error()}. parse_all(Input) -> application:ensure_all_started(erlang:binary_to_atom(<<"fast_yaml"/utf8>>)), case fast_yaml:decode(Input) of {ok, Docs} -> {ok, decode_documents(Docs)}; {error, Err} -> {error, format_error(Err)} end. -file("src/taffy/native.gleam", 125). -spec decode_pair(gleam@dynamic:dynamic_()) -> {ok, {binary(), taffy@value:yaml_value()}} | {error, nil}. decode_pair(Item) -> gleam@result:'try'( taffy_ffi:decode_tuple2(Item), fun(_use0) -> {Key, Raw_val} = _use0, gleam@result:'try'( taffy_ffi:to_string(Key), fun(K) -> {ok, {K, convert_value(Raw_val)}} end ) end ). -file("src/taffy/native.gleam", 109). -spec try_proplist(gleam@dynamic:dynamic_()) -> gleam@option:option(list({binary(), taffy@value:yaml_value()})). try_proplist(Val) -> gleam@option:then( begin _pipe = taffy_ffi:to_list(Val), gleam@option:from_result(_pipe) end, fun(Items) -> case Items of [] -> {some, []}; _ -> case gleam@list:all(Items, fun taffy_ffi:is_tuple2/1) of true -> {some, gleam@list:filter_map(Items, fun decode_pair/1)}; false -> none end end end ). -file("src/taffy/native.gleam", 93). -spec try_as_mapping(gleam@dynamic:dynamic_()) -> gleam@option:option(taffy@value:yaml_value()). try_as_mapping(Val) -> _pipe = try_proplist(Val), gleam@option:map(_pipe, fun(Field@0) -> {mapping, Field@0} end).