-module(css_select@internal@parser). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([lexer/0, parse_simple_selector/1]). -export_type([t/0, parse_error/1]). -type t() :: hash | dot | star | colon | equal_sign | prefix | suffix | l_bracket | r_bracket | {name, binary()} | {str_t, binary()}. -type parse_error(IYB) :: {lexer_error, nibble@lexer:error()} | {parse_error, list(nibble:dead_end(t(), IYB))}. -spec lexer() -> nibble@lexer:lexer(t(), nil). lexer() -> nibble@lexer:simple( [nibble@lexer:token(<<"#"/utf8>>, hash), nibble@lexer:token(<<"."/utf8>>, dot), nibble@lexer:token(<<"*"/utf8>>, star), nibble@lexer:token(<<":"/utf8>>, colon), nibble@lexer:token(<<"["/utf8>>, l_bracket), nibble@lexer:token(<<"]"/utf8>>, r_bracket), nibble@lexer:token(<<"="/utf8>>, equal_sign), nibble@lexer:token(<<"^="/utf8>>, prefix), nibble@lexer:token(<<"$="/utf8>>, suffix), nibble@lexer:string( <<"\""/utf8>>, fun(Field@0) -> {name, Field@0} end ), nibble@lexer:identifier( <<"^[\\w]"/utf8>>, <<"[\\w-_]"/utf8>>, gleam@set:new(), fun(Field@0) -> {name, Field@0} end )] ). -spec identifier_parser() -> nibble:parser(binary(), t(), any()). identifier_parser() -> nibble:take_map(<<"identifier"/utf8>>, fun(Tok) -> case Tok of {name, K} -> {some, K}; _ -> none end end). -spec class_parser() -> nibble:parser(css_select@selector:attribute_selector(), t(), any()). class_parser() -> nibble:do( nibble:token(dot), fun(_) -> nibble:do( identifier_parser(), fun(Class) -> nibble:return({class, Class}) end ) end ). -spec id_parser() -> nibble:parser(css_select@selector:attribute_selector(), t(), any()). id_parser() -> nibble:do( nibble:token(hash), fun(_) -> nibble:do( identifier_parser(), fun(Id) -> nibble:return({id, Id}) end ) end ). -spec any_parser() -> nibble:parser(css_select@selector:tag_selector(), any(), any()). any_parser() -> nibble:succeed(any). -spec tag_parser() -> nibble:parser(css_select@selector:tag_selector(), t(), any()). tag_parser() -> nibble:do(identifier_parser(), fun(Tag) -> nibble:return({tag, Tag}) end). -spec element_parser() -> nibble:parser(css_select@selector:tag_selector(), t(), any()). element_parser() -> nibble:one_of([tag_parser(), any_parser()]). -spec psuedo_parser() -> nibble:parser(css_select@selector:attribute_selector(), t(), any()). psuedo_parser() -> nibble:do( nibble:token(colon), fun(_) -> nibble:do( identifier_parser(), fun(Name) -> nibble:return({psuedo, Name}) end ) end ). -spec attr_parser() -> nibble:parser(css_select@selector:attribute_selector(), t(), any()). attr_parser() -> nibble:do( nibble:token(l_bracket), fun(_) -> nibble:do( identifier_parser(), fun(Key) -> Attribute_exists = (nibble:do( nibble:token(r_bracket), fun(_) -> nibble:return({attribute_exists, Key}) end )), Attribute_equals = (nibble:do( nibble:token(equal_sign), fun(_) -> nibble:do( identifier_parser(), fun(Value) -> nibble:do( nibble:token(r_bracket), fun(_) -> nibble:return( {attribute_equal, Key, Value} ) end ) end ) end )), Attribute_prefix = (nibble:do( nibble:token(prefix), fun(_) -> nibble:do( identifier_parser(), fun(Value@1) -> nibble:do( nibble:token(r_bracket), fun(_) -> nibble:return( {attribute_prefix, Key, Value@1} ) end ) end ) end )), Attribute_suffix = (nibble:do( nibble:token(suffix), fun(_) -> nibble:do( identifier_parser(), fun(Value@2) -> nibble:do( nibble:token(r_bracket), fun(_) -> nibble:return( {attribute_suffix, Key, Value@2} ) end ) end ) end )), nibble:one_of( [Attribute_exists, Attribute_equals, Attribute_prefix, Attribute_suffix] ) end ) end ). -spec attr_selector_parser() -> nibble:parser(css_select@selector:attribute_selector(), t(), any()). attr_selector_parser() -> nibble:one_of([class_parser(), id_parser(), attr_parser(), psuedo_parser()]). -spec parser() -> nibble:parser(css_select@selector:selector(), t(), any()). parser() -> nibble:do( element_parser(), fun(Tag_selector) -> nibble:do( nibble:many(attr_selector_parser()), fun(Attr_selectors) -> nibble:return( {element_selector, Tag_selector, Attr_selectors} ) end ) end ). -spec parse_simple_selector(binary()) -> {ok, css_select@selector:selector()} | {error, parse_error(any())}. parse_simple_selector(Input) -> _pipe = Input, _pipe@1 = nibble@lexer:run(_pipe, lexer()), _pipe@2 = gleam@result:map_error( _pipe@1, fun(Field@0) -> {lexer_error, Field@0} end ), gleam@result:'try'( _pipe@2, fun(Tokens) -> _pipe@3 = nibble:run(Tokens, parser()), gleam@result:map_error( _pipe@3, fun(Field@0) -> {parse_error, Field@0} end ) end ).