рдЬрдВрдЧ рдХреЗ рд╕рд╛рде рджрд╣рдирд╢реАрд▓ рдкрд╛рд░реНрд╕рд░ рдХреА рдЦреЛрдЬ

рдирдорд╕реНрдХрд╛рд░, рд╣реЗрдмреНрд░! рдореИрдВ рдЖрдкрдХреЗ рд▓рд┐рдП "рд▓рд░реНрдирд┐рдВрдЧ рдкрд╛рд░реНрд╕рд░ рдХреЙрдореНрдмрд┐рдиреЗрдЯрд░ рд╡рд┐рде рд░рд╕реНрдЯ" рд▓реЗрдЦ рдХрд╛ рдЕрдиреБрд╡рд╛рдж рдкреНрд░рд╕реНрддреБрдд рдХрд░рддрд╛ рд╣реВрдВред


рдпрд╣ рд▓реЗрдЦ рдЙрди рд▓реЛрдЧреЛрдВ рдХреЗ рд▓рд┐рдП рджрд╣рдирд╢реАрд▓ рдкрд╛рд░реНрд╕рд░ рдХреА рдореВрд▓ рдмрд╛рддреЗрдВ рд╕рд┐рдЦрд╛рддрд╛ рд╣реИ рдЬреЛ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдЬрдВрдЧ рд╕реЗ рдкрд░рд┐рдЪрд┐рдд рд╣реИрдВред рдпрд╣ рдорд╛рдирд╛ рдЬрд╛рддрд╛ рд╣реИ рдХрд┐ рдХрд┐рд╕реА рдЕрдиреНрдп рдЬреНрдЮрд╛рди рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ, рдФрд░ рд╕рдм рдХреБрдЫ рдЬреЛ рд╕реАрдзреЗ рд░реБрд╕реНрдд рд╕реЗ рд╕рдВрдмрдВрдзрд┐рдд рдирд╣реАрдВ рд╣реИ, рд╕рд╛рде рд╣реА рдЗрд╕рдХреЗ рдЙрдкрдпреЛрдЧ рдХреЗ рдХреБрдЫ рдЕрдкреНрд░рддреНрдпрд╛рд╢рд┐рдд рдкрд╣рд▓реБрдУрдВ рдХреЛ рд╕рдордЭрд╛рдпрд╛ рдЬрд╛рдПрдЧрд╛ред рдпрджрд┐ рдЖрдк рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдирд╣реАрдВ рдЬрд╛рдирддреЗ рд╣реИрдВ, рддреЛ рдпрд╣ рд▓реЗрдЦ рдЖрдкрдХреЛ рдЬрдВрдЧ рдХреЛ рд╕реАрдЦрдиреЗ рдореЗрдВ рдорджрдж рдирд╣реАрдВ рдХрд░реЗрдЧрд╛, рдФрд░ рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ, рдЖрдк рд╕рдмрд╕реЗ рдЕрдзрд┐рдХ рд╕рдВрднрд╛рд╡рдирд╛ рд╣реИ рдХрд┐ рджрд╣рдирд╢реАрд▓ рдкрд╛рд░реНрд╕рд░ рдХреЛ рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рд╕рдордЭ рдирд╣реАрдВ рдкрд╛рдПрдВрдЧреЗред рдпрджрд┐ рдЖрдк рд░рд╕реНрдЯ рд╕реАрдЦрдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рддреЛ рдореИрдВ "рд░рд╕реНрдЯ рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рд▓реИрдВрдЧреНрд╡реЗрдЬ" рдкреБрд╕реНрддрдХ рдХреА рд╕рд┐рдлрд╛рд░рд┐рд╢ рдХрд░рддрд╛ рд╣реВрдВред


рд╢реБрд░реБрдЖрдд рдХреЗ рджреГрд╖реНрдЯрд┐рдХреЛрдг рд╕реЗ


рдкреНрд░рддреНрдпреЗрдХ рдкреНрд░реЛрдЧреНрд░рд╛рдорд░ рдХреЗ рдЬреАрд╡рди рдореЗрдВ, рдПрдХ рд╕рдордп рдЖрддрд╛ рд╣реИ рдЬрдм рдЙрд╕реЗ рдПрдХ рдкрд╛рд░реНрд╕рд░ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред


рдПрдХ рдиреМрд╕рд┐рдЦрд┐рдпрд╛ рдкреНрд░реЛрдЧреНрд░рд╛рдорд░ рдкреВрдЫреЗрдЧрд╛: "рдПрдХ рдкрд╛рд░реНрд╕рд░ рдХреНрдпрд╛ рд╣реИ?"


рдордзреНрдп-рд╕реНрддрд░реАрдп рдкреНрд░реЛрдЧреНрд░рд╛рдорд░ рдХрд╣реЗрдЧрд╛: "рдпрд╣ рд╕рд░рд▓ рд╣реИ, рдореИрдВ рдПрдХ рдирд┐рдпрдорд┐рдд рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рд▓рд┐рдЦреВрдВрдЧрд╛ред"


рдорд╛рд╕реНрдЯрд░ рдкреНрд░реЛрдЧреНрд░рд╛рдорд░ рдХрд╣реЗрдЧрд╛: "рджреВрд░ рд╣реЛ рдЬрд╛рдУ, рдореБрдЭреЗ рдкрддрд╛ рд╣реИ рдХрд┐ lex рдФрд░ yaccред"


рдПрдХ рдиреМрд╕рд┐рдЦрд┐рдпрд╛ рд╕рдмрд╕реЗ рдЕрдЪреНрдЫрд╛ рд▓рдЧрддрд╛ рд╣реИред


рдРрд╕рд╛ рдирд╣реАрдВ рдХрд┐ рдирд┐рдпрдорд┐рдд рднрд╛рд╡ рдЦрд░рд╛рдм рд╣реИрдВред (рд▓реЗрдХрд┐рди рдХреГрдкрдпрд╛, рдПрдХ рдЬрдЯрд┐рд▓ рдкрд╛рд░реНрд╕рд░ рдХреЛ рдПрдХ рдирд┐рдпрдорд┐рдд рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рдХреЗ рд░реВрдк рдореЗрдВ рд▓рд┐рдЦрдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рди рдХрд░реЗрдВред) рдРрд╕рд╛ рдирд╣реАрдВ рд╣реИ рдХрд┐ рд╢рдХреНрддрд┐рд╢рд╛рд▓реА рдЙрдкрдХрд░рдг рдЬреИрд╕реЗ рдХрд┐ рдкрд╛рд░реНрд╕рд░ рдФрд░ рд▓реЗрдХреНрд╕рд░ рдЬрдирд░реЗрдЯрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдореЗрдВ рдХреЛрдИ рдЦреБрд╢реА рдирд╣реАрдВ рд╣реИ рдЬреЛ рд╕рд╣рд╕реНрд░рд╛рдмреНрджреА рдХреЗ рд▓рд┐рдП рдкреВрд░реНрдгрддрд╛ рдХреЗ рд▓рд┐рдП рд╕рдореНрдорд╛рдирд┐рдд рдХрд┐рдП рдЧрдП рд╣реИрдВред рд▓реЗрдХрд┐рди рдкрд╛рд░реНрд╕рд░реНрд╕ рдХреА рдореВрд▓ рдмрд╛рддреЗрдВ рд╕реАрдЦрдирд╛ рдПрдХ рдЦреБрд╢реА рд╣реИ ред рдпрд╣ рднреА рд╣реИ рдХрд┐ рдЖрдк рдХреНрдпрд╛ рдпрд╛рдж рдХрд░реЗрдВрдЧреЗ рдЕрдЧрд░ рдЖрдк рдирд┐рдпрдорд┐рдд рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐рдпреЛрдВ рдпрд╛ рдкрд╛рд░реНрд╕рд░ рдЬрдирд░реЗрдЯрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╕рдордп рдШрдмрд░рд╛рддреЗ рд╣реИрдВ, рддреЛ рджреЛрдиреЛрдВ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рд╕рдорд╕реНрдпрд╛ рдкрд░ рдХреЗрд╡рд▓ рдЕрдореВрд░реНрдд рд╣реИрдВред рдПрдХ рд╢реБрд░реБрдЖрдд рдХреЗ рджрд┐рдорд╛рдЧ рдореЗрдВ, рдЬреИрд╕рд╛ рдХрд┐ рдПрдХ рдЖрджрдореА рдиреЗ рдХрд╣рд╛ , рдХрдИ рд╕рдВрднрд╛рд╡рдирд╛рдПрдВ рд╣реИрдВред рд╡рд┐рд╢реЗрд╖рдЬреНрдЮ рдХреЗ рдЕрдиреБрд╕рд╛рд░, рдХреЗрд╡рд▓ рдПрдХ рд╕рд╣реА рд╡рд┐рдХрд▓реНрдк рд╣реИред


рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ, рд╣рдо рд╕реАрдЦреЗрдВрдЧреЗ рдХрд┐ рд╕реНрдХреНрд░реИрдЪ рд╕реЗ рдкрд╛рд░реНрд╕рд░ рдХреИрд╕реЗ рдмрдирд╛рдпрд╛ рдЬрд╛рдП
рдПрдХ рдХрд╛рд░реНрдпрд╛рддреНрдордХ рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рднрд╛рд╖рд╛рдУрдВ рдореЗрдВ рд╕рд╛рдорд╛рдиреНрдп рд╡рд┐рдзрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛, рдЬрд┐рд╕реЗ рдХреЙрдореНрдмрд┐рдиреЗрдЯрд░рд┐рдпрд▓ рдкрд╛рд░реНрд╕рд░ рдХреЗ рд░реВрдк рдореЗрдВ рдЬрд╛рдирд╛ рдЬрд╛рддрд╛ рд╣реИред рдЬреИрд╕реЗ рд╣реА рдЖрдк рдЙрдирдХреЗ рдореВрд▓ рд╡рд┐рдЪрд╛рд░ рдХреЛ рд╕рдордЭ рд▓реЗрддреЗ рд╣реИрдВ, рд╡реИрд╕реЗ рд╣реА рдЖрд╢реНрдЪрд░реНрдпрдЬрдирдХ рд░реВрдк рд╕реЗ рд╢рдХреНрддрд┐рд╢рд╛рд▓реА рд╣реЛрдиреЗ рдХрд╛ рдлрд╛рдпрджрд╛ рд╣реЛрддрд╛ рд╣реИ, рдЬрдмрдХрд┐ рдореВрд▓ рд╕рд┐рджреНрдзрд╛рдВрдд рдХреЗ рдмрд╣реБрдд рдХрд░реАрдм рд░рд╣рддреЗ рд╣реИрдВред рдХреНрдпреЛрдВрдХрд┐ рдпрд╣рд╛рдВ рдПрдХрдорд╛рддреНрд░ рд╕рд╛рд░ рд╡реЗ рд╣реЛрдВрдЧреЗ рдЬреЛ рдЖрдк рдЦреБрдж рдмрдирд╛рддреЗ рд╣реИрдВред рдореБрдЦреНрдп рдХреЙрдореНрдмрд┐рдиреЗрдЯрд░ рдЬреЛ рдЖрдк рдпрд╣рд╛рдВ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗ рдЖрдк рдЦреБрдж рдХрд╛ рдирд┐рд░реНрдорд╛рдг рдХрд░реЗрдВрдЧреЗред


рдЗрд╕ рд▓реЗрдЦ рдХреЗ рд╕рд╛рде рдХреИрд╕реЗ рдХрд╛рдо рдХрд░реЗрдВ


рдпрд╣ рджреГрдврд╝рддрд╛ рд╕реЗ рдЕрдиреБрд╢рдВрд╕рд╛ рдХреА рдЬрд╛рддреА рд╣реИ рдХрд┐ рдЖрдк рдПрдХ рдирдИ рдЬрдВрдЧ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХреЗ рд╕рд╛рде рд╢реБрд░реВ рдХрд░реЗрдВ рдФрд░ src/lib.rs рдореЗрдВ рдХреЛрдб рд╕реНрдирд┐рдкреЗрдЯ src/lib.rs рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рдкрдврд╝рддреЗ рд╣реИрдВ (рдЖрдк рдЗрд╕реЗ рд╕реАрдзреЗ рдкреЗрдЬ рд╕реЗ рдкреЗрд╕реНрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдЗрд╕реЗ рдмреЗрд╣рддрд░ рджрд░реНрдЬ рдХрд░реЗрдВ, рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рдЖрдкрдХреЛ рдЧрд╛рд░рдВрдЯреА рджреЗрддрд╛ рд╣реИ рдХрд┐ рдЖрдк рдЗрд╕реЗ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдкрдврд╝реЗрдВрдЧреЗ)ред рдХреЛрдб рдХреЗ рд╕рднреА рднрд╛рдЧ рдЬрд┐рдирдХреА рдЖрдкрдХреЛ рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рд▓реЗрдЦ рдореЗрдВ рдХреНрд░рдо рдореЗрдВ рд╡реНрдпрд╡рд╕реНрдерд┐рдд рдХрд┐рдП рдЧрдП рд╣реИрдВред рдзреНрдпрд╛рди рд░рдЦреЗрдВ рдХрд┐ рдХрднреА-рдХрднреА рдЖрдкрдХреЗ рджреНрд╡рд╛рд░рд╛ рд▓рд┐рдЦреЗ рдЧрдП рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рд╕рдВрд╢реЛрдзрд┐рдд рд╕рдВрд╕реНрдХрд░рдг рдкреЗрд╢ рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВ, рдФрд░ рдЗрди рдорд╛рдорд▓реЛрдВ рдореЗрдВ рдЖрдкрдХреЛ рдкреБрд░рд╛рдиреЗ рд╕рдВрд╕реНрдХрд░рдг рдХреЛ рдирдП рдХреЗ рд╕рд╛рде рдмрджрд▓рдирд╛ рд╣реЛрдЧрд╛ред


рдХреЛрдб рдХреЛ 2018 рднрд╛рд╖рд╛ рд╕рдВрд╕реНрдХрд░рдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП rustc рд╕рдВрд╕реНрдХрд░рдг 1.34.0 рдХреЗ рд▓рд┐рдП рд▓рд┐рдЦрд╛ рдЧрдпрд╛ рдерд╛ред рдЖрдк рд╕рдВрдХрд▓рдХ рдХреЗ рдХрд┐рд╕реА рднреА рд╕рдВрд╕реНрдХрд░рдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░реЗрдВ рдХрд┐ рдЖрдк рдПрдХ рд░рд┐рд▓реАрдЬрд╝ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣реЗ рд╣реИрдВ рдЬреЛ 2018 рд╕рдВрд╕реНрдХрд░рдг рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рддрд╛ рд╣реИ (рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░реЗрдВ рдХрд┐ рдЖрдкрдХреЗ Cargo.toml рдореЗрдВ edition = "2018" )ред рдЗрд╕ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХреЛ рдмрд╛рд╣рд░реА рдирд┐рд░реНрднрд░рддрд╛ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИред


рдЕрдкреЗрдХреНрд╖рд╛ рдХреЗ рдЕрдиреБрд╕рд╛рд░ рд▓реЗрдЦ рдореЗрдВ рдкреНрд░рд╕реНрддреБрдд рдХрд┐рдП рдЧрдП рдкрд░реАрдХреНрд╖рдгреЛрдВ рдХреЛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, cargo test ред


Xcruciating Markup рднрд╛рд╖рд╛


рд╣рдо XML рдХреЗ рд╕рд░рд▓реАрдХреГрдд рд╕рдВрд╕реНрдХрд░рдг рдХреЗ рд▓рд┐рдП рдПрдХ рдкрд╛рд░реНрд╕рд░ рд▓рд┐рдЦрдиреЗ рдЬрд╛ рд░рд╣реЗ рд╣реИрдВред рдпрд╣ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрддрд╛ рд╣реИ:


 <parent-element> <single-element attribute="value" /> </parent-element> 

XML рддрддреНрд╡реЛрдВ рдХреЛ < рдЕрдХреНрд╖рд░ рдФрд░ рдПрдХ рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛ рдХреЗ рд╕рд╛рде рдЦреЛрд▓рд╛ рдЬрд╛рддрд╛ рд╣реИ рдЬрд┐рд╕рдореЗрдВ рдХрд┐рд╕реА рднреА рдЕрдХреНрд╖рд░, рд╕рдВрдЦреНрдпрд╛ рдФрд░ - рдмрд╛рдж рдПрдХ рдЕрдХреНрд╖рд░ рд╢рд╛рдорд┐рд▓ рд╣реЛрддрд╛ рд╣реИред рдЗрд╕рдХреЗ рдмрд╛рдж рд░рд┐рдХреНрдд рд╕реНрдерд╛рди рдФрд░ рд╡рд┐рд╢реЗрд╖рддрд╛ рдЬреЛрдбрд╝реЗ рдХреА рдПрдХ рд╡реИрдХрд▓реНрдкрд┐рдХ рд╕реВрдЪреА рд╣реИ: рдкрд╣рд▓реЗ рд╕реЗ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдПрдХ рдФрд░ рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛, рдЙрд╕рдХреЗ рдмрд╛рдж = рдФрд░ рджреЛрд╣рд░реЗ рдЙрджреНрдзрд░рдг рдореЗрдВ рдПрдХ рд╕реНрдЯреНрд░рд┐рдВрдЧред рдЕрдВрдд рдореЗрдВ, рдмрдЪреНрдЪреЛрдВ рдХреЗ рдмрд┐рдирд╛ рдПрдХ рддрддреНрд╡ рдХреЛ рдЗрдВрдЧрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдпрд╛ рддреЛ рдПрдХ рд╕рдорд╛рдкрди /> рдЪрд░рд┐рддреНрд░ рд╣реЛрддрд╛ рд╣реИ, рдпрд╛ > рдмрд╛рд▓ рддрддреНрд╡реЛрдВ рдХреЗ рдЕрдЧрд▓реЗ рдЕрдиреБрдХреНрд░рдо рдХреЗ рдЕрд╕реНрддрд┐рддреНрд╡ рдХреЛ рдЗрдВрдЧрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдФрд░ рдПрдХ рд╕рдорд╛рдкрди рдЯреИрдЧ </ рд╕рд╛рде рд╢реБрд░реВ рд╣реЛрддрд╛ рд╣реИ, рдЙрд╕рдХреЗ рдмрд╛рдж рдПрдХ рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛ рд╣реЛрддрд╛ рд╣реИ рдЬреЛ рдкреНрд░рд╛рд░рдВрднрд┐рдХ рдЯреИрдЧ рдФрд░ рдПрдХ рд╕рдорд╛рдкрди рдЪрд░рд┐рддреНрд░ рд╕реЗ рдореЗрд▓ рдЦрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред


рд╡рд╣ рд╕рдм рд╣рдо рд╕рдорд░реНрдерди рдХрд░реЗрдВрдЧреЗред рдХреЛрдИ рдирд╛рдорд╕реНрдерд╛рди, рдХреЛрдИ рдкрд╛рда рдиреЛрдбреНрд╕ рдирд╣реАрдВ рд╣реЛрдЧрд╛, рдФрд░ рд╕рдмрд╕реЗ рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ рдХреЛрдИ рд╕реНрдХреАрдорд╛ рдЬрд╛рдВрдЪ рдирд╣реАрдВ рд╣реЛрдЧреАред рд╣рдореЗрдВ рд╕реНрдЯреНрд░рд┐рдВрдЧреНрд╕ рдХреЗ рд▓рд┐рдП рдЙрджреНрдзрд░рдгреЛрдВ рд╕реЗ рдмрдЪрдиреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рднреА рдЪрд┐рдВрддрд╛ рдХрд░рдиреЗ рдХреА рдЬрд╝рд░реВрд░рдд рдирд╣реАрдВ рд╣реИ - рд╡реЗ рдкрд╣рд▓реЗ рджреЛрд╣рд░реЗ рдЙрджреНрдзрд░рдг рдЪрд┐рд╣реНрди рдХреЗ рд╕рд╛рде рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВ, рдФрд░ рд╡реЗ рдЕрдЧрд▓реЗ рдПрдХ рдХреЗ рд╕рд╛рде рд╕рдорд╛рдкреНрдд рд╣реЛрддреЗ рд╣реИрдВ, рдФрд░ рдпрд╣ рдмрд╛рдд рд╣реИред


рд╣рдо рдЗрди рддрддреНрд╡реЛрдВ рдХреЛ рдПрдХ рд╕рдВрд░рдЪрдирд╛ рдореЗрдВ рдкрд╛рд░реНрд╕ рдХрд░рдиреЗ рдЬрд╛ рд░рд╣реЗ рд╣реИрдВ рдЬреЛ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрддрд╛ рд╣реИ:


 #[derive(Clone, Debug, PartialEq, Eq)] struct Element { name: String, attributes: Vec<(String, String)>, children: Vec<Element>, } 

рдХреЛрдИ рдлреИрдВрд╕реА рдкреНрд░рдХрд╛рд░ рдирд╣реАрдВ рд╣реИрдВ, рдмрд╕ рдирд╛рдо рдХреЗ рд▓рд┐рдП рдПрдХ рд╕реНрдЯреНрд░рд┐рдВрдЧ (рдпрд╣ рдкреНрд░рддреНрдпреЗрдХ рдЯреИрдЧ рдХреА рд╢реБрд░реБрдЖрдд рдореЗрдВ рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛ рд╣реИ), рддрд╛рд░ рдХреЗ рдЬреЛрдбрд╝реЗ рдХреЗ рд░реВрдк рдореЗрдВ рд╡рд┐рд╢реЗрд╖рддрд╛ (рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛ рдФрд░ рдореВрд▓реНрдп) рдФрд░ рдмрдЪреНрдЪреЛрдВ рдХреА рдПрдХ рд╕реВрдЪреА рдЬреЛ рдмрд┐рд▓реНрдХреБрд▓ рдорд╛рддрд╛-рдкрд┐рддрд╛ рдХреА рддрд░рд╣ рджрд┐рдЦрддреА рд╣реИред


(рдпрджрд┐ рдЖрдк рдкреНрд░рд┐рдВрдЯ рдХрд░ рд░рд╣реЗ рд╣реИрдВ, рддреЛ derive рдЕрдиреБрднрд╛рдЧ рдХреЛ рд╢рд╛рдорд┐рд▓ рдХрд░рдирд╛ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░реЗрдВред рдЖрдкрдХреЛ рдмрд╛рдж рдореЗрдВ рдЗрд╕рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреАред)


Parser рдкрд░рд┐рднрд╛рд╖рд╛;


рдЦреИрд░, рдпрд╣ рдПрдХ parser рд▓рд┐рдЦрдиреЗ рдХрд╛ рд╕рдордп рд╣реИред


рдкрд╛рд░реНрд╕рд┐рдВрдЧ рд╕реВрдЪрдирд╛ рдХреА рдПрдХ рдзрд╛рд░рд╛ рд╕реЗ рд╕рдВрд░рдЪрд┐рдд рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рд╣реИред рдПрдХ рдкрд╛рд░реНрд╕рд░ рд╡рд╣ рд╣реИ рдЬреЛ рдЗрд╕ рд╕рдВрд░рдЪрдирд╛ рдХреЛ рд╕рд╛рдордиреЗ рд▓рд╛рддрд╛ рд╣реИред


рдЕрдиреБрд╢рд╛рд╕рди рдореЗрдВ рд╣рдо рдЦреЛрдЬ рдХрд░рдиреЗ рдЬрд╛ рд░рд╣реЗ рд╣реИрдВ, рдкрд╛рд░реНрд╕рд░, рдЕрдкрдиреЗ рд╕рд░рд▓рддрдо рд░реВрдк рдореЗрдВ, рдПрдХ рдлрд╝рдВрдХреНрд╢рди рд╣реИ рдЬреЛ рдХреБрдЫ рдЗрдирдкреБрдЯ рд▓реЗрддрд╛ рд╣реИ рдФрд░ рд╢реЗрд╖ рдЗрдирдкреБрдЯ рдХреЗ рд╕рд╛рде рдкрд╛рд░реНрд╕ рдХрд┐рдП рдЧрдП рдЖрдЙрдЯрдкреБрдЯ рдпрд╛ рд░рд┐рдЯрд░реНрди рджреЗрддрд╛ рд╣реИ, рдпрд╛ рдПрдХ рддреНрд░реБрдЯрд┐ рдХрд╣рддреА рд╣реИ "рдореИрдВ рдЗрд╕реЗ рдкрд╛рд░реНрд╕ рдирд╣реАрдВ рдХрд░ рд╕рдХрддрд╛ред"


рдкрд╛рд░реНрд╕рд░ рдЕрдкрдиреЗ рдЕрдзрд┐рдХ рдЬрдЯрд┐рд▓ рд░реВрдкреЛрдВ рдореЗрдВ рднреА рджрд┐рдЦрддрд╛ рд╣реИред рдЖрдк рдпрд╣ рдмрддрд╛ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рдЗрдирдкреБрдЯ, рдЖрдЙрдЯрдкреБрдЯ рдФрд░ рддреНрд░реБрдЯрд┐ рдХрд╛ рдХреНрдпрд╛ рдорддрд▓рдм рд╣реИ, рдФрд░ рдпрджрд┐ рдЖрдкрдХреЛ рдЕрдЪреНрдЫреЗ рддреНрд░реБрдЯрд┐ рд╡рд╛рд▓реЗ рд╕рдВрджреЗрд╢реЛрдВ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдкрд╛рд░реНрд╕рд░ рд╡рд╣реА рд░рд╣рддрд╛ рд╣реИ: рдРрд╕рд╛ рдХреБрдЫ рдЬреЛ рдЗрдирдкреБрдЯ рдХрд╛ рдЙрдкрднреЛрдЧ рдХрд░рддрд╛ рд╣реИ рдФрд░ рдХреБрдЫ рдХреЗ рд╕рд╛рде рдкрд╛рд░реНрд╕ рдЖрдЙрдЯрдкреБрдЯ рдХрд╛ рдЙрддреНрдкрд╛рджрди рдХрд░рддрд╛ рд╣реИ рдЗрдирдкреБрдЯ рд╕реЗ рдмрдЪреЗ рдпрд╛ рдЖрдкрдХреЛ рдмрддрд╛ рджреЗрдВ рдХрд┐ рдпрд╣ рдЖрдЙрдЯрдкреБрдЯ рдХреЗ рдЗрдирдкреБрдЯ рдХреЛ рдкрд╛рд░реНрд╕ рдирд╣реАрдВ рдХрд░ рд╕рдХрддрд╛ рд╣реИред


рдЗрд╕реЗ рдПрдХ рдкреНрд░рдХрд╛рд░ рдХреЗ рдлрдВрдХреНрд╢рди рдХреЗ рд░реВрдк рдореЗрдВ рд▓рд┐рдЦрддреЗ рд╣реИрдВред


 Fn(Input) -> Result<(Input, Output), Error> 

рдЕрдзрд┐рдХ рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ: рд╣рдорд╛рд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рд╣рдо рдкреНрд░рдХрд╛рд░реЛрдВ рдХреЛ рднрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ рдФрд░ рдЗрд╕ рдХреЗ рд╕рдорд╛рди рдПрдХ рдлрд╝рдВрдХреНрд╢рди рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВред рд╣рдо рдЬреЛ рдХрд░рдиреЗ рдЬрд╛ рд░рд╣реЗ рд╣реИрдВ рд╡рд╣ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЛ рдПрдХ Element рд╕реНрдЯреНрд░рдХреНрдЪрд░ рдореЗрдВ рдмрджрд▓ рджреЗрддрд╛ рд╣реИред рдлрд┐рд▓рд╣рд╛рд▓, рд╣рдо рддреНрд░реБрдЯрд┐ рд╕рдВрджреЗрд╢реЛрдВ рдХреЗ рд╡рд┐рд╡рд░рдг рдореЗрдВ рдирд╣реАрдВ рдЬрд╛рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП рдХреЗрд╡рд▓ рдЙрд╕ рдкрдВрдХреНрддрд┐ рдХрд╛ рд╣рд┐рд╕реНрд╕рд╛ рд▓реМрдЯрд╛рдПрдВ рдЬрд┐рд╕реЗ рд╣рдо рдкрд╛рд░реНрд╕ рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗред рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк, рд╣рдорд╛рд░рд╛ рдХрд╛рд░реНрдп рдЗрд╕ рддрд░рд╣ рджрд┐рдЦреЗрдЧрд╛:


 Fn(&str) -> Result<(&str, Element), &str> 

рд╣рдо рдПрдХ рд╕реНрдЯреНрд░рд┐рдВрдЧ рд╕реНрд▓рд╛рдЗрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ, рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рдПрдХ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЗ рдЯреБрдХрдбрд╝реЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдкреНрд░рднрд╛рд╡реА рд╕реВрдЪрдХ рд╣реИ, рдФрд░ рдлрд┐рд░ рд╣рдо рдЗрд╕реЗ рдЕрд▓рдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдЬреИрд╕рд╛ рдХрд┐ рд╣рдо рдЗрдирдкреБрдЯ рдбреЗрдЯрд╛ рдХреЛ "рдЙрдкрднреЛрдЧ" рдХрд░рдХреЗ, рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд┐рдП рдЧрдП рдЯреБрдХрдбрд╝реЗ рдХреЛ рдХрд╛рдЯрдХрд░ рдФрд░ рд╢реЗрд╖ рдХреЛ рдкрд░рд┐рдгрд╛рдо рдХреЗ рд╕рд╛рде рд╡рд╛рдкрд╕ рдХрд░рддреЗ рд╣реИрдВред


рдпрд╣ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреНрд▓реАрдирд░ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ &[u8] (рдЗрдирдкреБрдЯ рдХреЗ рд░реВрдк рдореЗрдВ ASCII рд╡рд░реНрдгреЛрдВ рд╕реЗ рдореЗрд▓ рдЦрд╛рддрд╛ рдмрд╛рдЗрдЯреНрд╕ рдХрд╛ рдПрдХ рдЯреБрдХрдбрд╝рд╛), рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рдХреНрдпреЛрдВрдХрд┐ рд╕реНрдЯреНрд░рд┐рдВрдЧ рд╕реНрд▓рд╛рдЗрд╕ рдЕрдзрд┐рдХрд╛рдВрд╢ рд╕реНрд▓рд╛рдЗрд╕реЛрдВ рдХреА рддреБрд▓рдирд╛ рдореЗрдВ рдереЛрдбрд╝рд╛ рдЕрд▓рдЧ рд╡реНрдпрд╡рд╣рд╛рд░ рдХрд░рддреЗ рд╣реИрдВ - рдЦрд╛рд╕рдХрд░ рдЬрдм рд╕реЗ рдЖрдк рдЙрдиреНрд╣реЗрдВ рдПрдХ рдХреЗ рд╕рд╛рде рдЕрдиреБрдХреНрд░рдорд┐рдд рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдирдВрдмрд░ input[0] , рдЖрдкрдХреЛ рдЯреБрдХрдбрд╝рд╛ input[0..1] рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдПред рджреВрд╕рд░реА рдУрд░, рдЙрдирдХреЗ рдкрд╛рд╕ рдХрдИ рддрд░реАрдХреЗ рд╣реИрдВ рдЬреЛ рдкрд╛рд░реНрд╕рд┐рдВрдЧ рд╕реНрдЯреНрд░рд┐рдВрдЧреНрд╕ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧреА рд╣реЛрддреЗ рд╣реИрдВ рдЬрд┐рдирдореЗрдВ рдмрд╛рдЗрдЯ рд╕реНрд▓рд╛рдЗрд╕ рдирд╣реАрдВ рд╣реЛрддреЗ рд╣реИрдВред


рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рд╣рдо рддрд░реАрдХреЛрдВ рдкрд░ рднрд░реЛрд╕рд╛ рдХрд░реЗрдВрдЧреЗ, рди рдХрд┐ рдЪрд░рд┐рддреНрд░ рд╕реВрдЪрдХрд╛рдВрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ, рдХреНрдпреЛрдВрдХрд┐ рдпреВрдирд┐рдХреЛрдбред UTF-8 рдореЗрдВ, рдФрд░ рд╕рднреА Rust рд╕реНрдЯреНрд░рд┐рдВрдЧреНрд╕ рдорд╛рдиреНрдп UTF-8 рд╕реНрдЯреНрд░рд┐рдВрдЧреНрд╕ рд╣реИрдВ, рдпреЗ рд╕реВрдЪрдХрд╛рдВрдХ рд╣рдореЗрд╢рд╛ рдЕрд▓рдЧ-рдЕрд▓рдЧ рд╡рд░реНрдгреЛрдВ рдХреЗ рдЕрдиреБрд░реВрдк рдирд╣реАрдВ рд╣реЛрддреЗ рд╣реИрдВ, рдФрд░ рд╕рднреА рдЗрдЪреНрдЫреБрдХ рдкрд╛рд░реНрдЯрд┐рдпреЛрдВ рдХреЗ рд▓рд┐рдП рдмреЗрд╣рддрд░ рд╣реИ рдХрд┐ рд╡реЗ рдорд╛рдирдХ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХреЛ рд╣рдорд╛рд░реЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╣реЗрдВред


рд╣рдорд╛рд░рд╛ рдкрд╣рд▓рд╛ рдкрд╛рд░реНрд╕рд░


рдЖрдЗрдП рдПрдХ рдРрд╕реЗ рдкрд╛рд░реНрд╕рд░ рдХреЛ рд▓рд┐рдЦрдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░реЗрдВ рдЬреЛ рд╕рд┐рд░реНрдл рдПрдХ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдореЗрдВ рдкрд╣рд▓реЗ рдЪрд░рд┐рддреНрд░ рдХреЛ рджреЗрдЦрддрд╛ рд╣реИ
рдФрд░ рдпрд╣ рддрдп рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдХреНрдпрд╛ рдпрд╣ рдкрддреНрд░ a ред


 fn the_letter_a(input: &str) -> Result<(&str, ()), &str> { match input.chars().next() { Some('a') => Ok((&input['a'.len_utf8()..], ())), _ => Err(input), } } 

рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рдЗрдирдкреБрдЯ рдФрд░ рдЖрдЙрдЯрдкреБрдЯ рдХреЗ рдкреНрд░рдХрд╛рд░реЛрдВ рдХреЛ рджреЗрдЦреЗрдВ: рд╣рдо рдЗрдирдкреБрдЯ рдХреЗ рд░реВрдк рдореЗрдВ рдПрдХ рд╕реНрдЯреНрд░рд┐рдВрдЧ рд╕реНрд▓рд╛рдЗрд╕ рд▓реЗрддреЗ рд╣реИрдВ рдФрд░ рд╣рдо (&str, ()) , рдпрд╛ &str рд╕рд╛рде рдПрдХ рддреНрд░реБрдЯрд┐ рдХреЗ рд╕рд╛рде Result рджреЗрддреЗ рд╣реИрдВред рдЬреЛрдбрд╝реА (&str, ()) рдПрдХ рджрд┐рд▓рдЪрд╕реНрдк рдмрд┐рдВрджреБ рд╣реИ: рдЬреИрд╕рд╛ рдХрд┐ рд╣рдордиреЗ рдХрд╣рд╛ рдХрд┐ рд╣рдореЗрдВ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╕рд╛рдордЧреНрд░реА рдХрд╛ рдПрдХ рдЯрдкрд▓ рд╡рд╛рдкрд╕ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП,
рдкрд╛рд░реНрд╕рд┐рдВрдЧ рдкрд░рд┐рдгрд╛рдо рдФрд░ рдмрд╛рдХреА рдЗрдирдкреБрдЯред &str рдЕрдЧрд▓рд╛ рдЗрдирдкреБрдЯ рд╣реИ, рдФрд░ рдкрд░рд┐рдгрд╛рдо рд╕рд┐рд░реНрдл рдПрдХ рдмреНрд▓реЙрдХ рдкреНрд░рдХрд╛рд░ () , рдХреНрдпреЛрдВрдХрд┐ рдпрджрд┐ рдпрд╣ рдкрд╛рд░реНрд╕рд░ рд╕рдлрд▓рддрд╛рдкреВрд░реНрд╡рдХ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, рддреЛ рдЗрд╕рдХрд╛ рдХреЗрд╡рд▓ рдПрдХ рдкрд░рд┐рдгрд╛рдо рд╣реЛ рд╕рдХрддрд╛ рд╣реИ (рд╣рдореЗрдВ рдкрддреНрд░ рдорд┐рд▓рд╛), рдФрд░ рд╣рдореЗрдВ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рд╡рд╛рдкрд╕ рдЖрдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ
рдкрддреНрд░ рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ рд╣рдореЗрдВ рдХреЗрд╡рд▓ рдпрд╣ рдЗрдВрдЧрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдХрд┐ рд╣рдо рдЗрд╕реЗ рдЦреЛрдЬрдиреЗ рдореЗрдВ рдХрд╛рдордпрд╛рдм рд░рд╣реЗред


рддреЛ, рдЪрд▓реЛ рдкрд╛рд░реНрд╕рд░ рдХреЗ рдХреЛрдб рдХреЛ рд╣реА рджреЗрдЦреЗрдВред рд╣рдордиреЗ рдордЬрд╛рдХ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдХрд┐ рдорд╛рдирдХ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдкрд░ рднрд░реЛрд╕рд╛ рдХрд░рдиреЗ рд╕реЗ рд╣рдо рдпреВрдирд┐рдХреЛрдб рдХреЗ рд╕рд╛рде рд╕рд┐рд░рджрд░реНрдж рд╕реЗ рдмрдЪ рд╕рдХрддреЗ рд╣реИрдВ: рд╣рдореЗрдВ chars() рд╡рд┐рдзрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЗ рдкрд╛рддреНрд░реЛрдВ рдкрд░ рдПрдХ рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рдкреНрд░рд╛рдкреНрдд рд╣реЛрддреА рд╣реИ рдФрд░ рдЗрд╕рдореЗрдВ рд╕реЗ рдкрд╣рд▓рд╛ рдЪрд░рд┐рддреНрд░ рд▓реЗрддреЗ рд╣реИрдВред рдпрд╣ Option рдореЗрдВ рд▓рд┐рдкрдЯреЗ рдЯрд╛рдЗрдк char рдХрд╛ рдПрдХ рддрддреНрд╡ рд╣реЛрдЧрд╛, рдЬрд┐рд╕рдореЗрдВ None рднреА рдЗрд╕рдХрд╛ рдорддрд▓рдм None рд╣реЛрдЧрд╛ рдХрд┐ рд╣рдо рдЦрд╛рд▓реА рд╕реНрдЯреНрд░рд┐рдВрдЧ рд╕реЗ char рдЦреАрдВрдЪрдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░ рд░рд╣реЗ рдереЗред


рдорд╛рдорд▓реЛрдВ рдХреЛ рдмрджрддрд░ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП, char рдЬрд░реВрд░реА рдирд╣реАрдВ рд╣реИ рдХрд┐ рдЖрдк рдЗрд╕реЗ рдПрдХ рдпреВрдирд┐рдХреЛрдб рдЪрд░рд┐рддреНрд░ рдХреЗ рд░реВрдк рдореЗрдВ рднреА рд╕реЛрдЪрддреЗ рд╣реИрдВред рдРрд╕рд╛ рд╣реЛрдиреЗ рдХреА рд╕рдВрднрд╛рд╡рдирд╛ рд╣реИ рдХрд┐ рдпреВрдирд┐рдХреЛрдб рдПрдХ "рдЧреНрд░реИрдлреЗрдо рдХреНрд▓рд╕реНрдЯрд░" рдХрд╣рд▓рд╛рддрд╛ рд╣реИ, рдЬрд┐рд╕рдореЗрдВ рдХрдИ char рд╢рд╛рдорд┐рд▓ рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВ, рдЬреЛ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ "рд╕реНрдХреЗрд▓рд░ рд╡реИрд▓реНрдпреВрдЬрд╝" рд╣реЛрддреЗ рд╣реИрдВ , рдЬреЛ рдЧреНрд░реИрдлреЗрдореА рдХреНрд▓рд╕реНрдЯрд░ рд╕реЗ рджреЛ рд╕реНрддрд░ рдиреАрдЪреЗ рд╣реЛрддреЗ рд╣реИрдВред рд╣рд╛рд▓рд╛рдБрдХрд┐, рдпрд╣ рдорд╛рд░реНрдЧ рдкрд╛рдЧрд▓рдкрди рдХреА рдУрд░ рдЬрд╛рддрд╛ рд╣реИ, рдФрд░ рд╣рдорд╛рд░реЗ рдЙрджреНрджреЗрд╢реНрдпреЛрдВ рдХреЗ рд▓рд┐рдП, рд╣рдо рдИрдорд╛рдирджрд╛рд░реА рд╕реЗ ASCII рдХреЗ рдмрд╛рд╣рд░ chars рджреЗрдЦрдиреЗ рдХреА рд╕рдВрднрд╛рд╡рдирд╛ рдирд╣реАрдВ рд╣реИ, рддреЛ рдЪрд▓реЛ рд╡рд╣рд╛рдБ рд░реБрдХреЗрдВред


рд╣рдо Some('a') рдкреИрдЯрд░реНрди рдХреЗ рд▓рд┐рдП рдореИрдк рдХрд░рддреЗ рд╣реИрдВ, рдЬреЛ рдХрд┐ рд╣рдорд╛рд░реЗ рджреНрд╡рд╛рд░рд╛ рдЦреЛрдЬреЗ рдЬрд╛ рд░рд╣реЗ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдкрд░рд┐рдгрд╛рдо рд╣реИ, рдФрд░ рдпрджрд┐ рд╡рд╣ рдореИрдЪ рд╣реЛрддрд╛ рд╣реИ, рддреЛ рд╣рдо рдЕрдкрдиреА рд╕рдлрд▓рддрд╛ рдХреА рд╡рд╛рдкрд╕реА рдХрд░рддреЗ рд╣реИрдВ:
Ok((&input['a'.len_utf8()..], ())) ред рдпрд╣реА рд╣реИ, рд╣рдо рдЙрд╕ рднрд╛рдЧ рдХреЛ рд╣рдЯрд╛ рджреЗрддреЗ рд╣реИрдВ рдЬрд┐рд╕реЗ рд╣рдордиреЗ рд▓рд╛рдЗрди рд╕реНрд▓рд╛рдЗрд╕ рд╕реЗ рдкрд╛рд░реНрд╕ ( 'a' ) рдХрд┐рдпрд╛ рд╣реИ рдФрд░ рдмрд╛рдХреА рдХреЛ рдЕрдкрдиреЗ рдкрд╛рд░реНрд╕ рдХрд┐рдП рдЧрдП рдорд╛рди рдХреЗ рд╕рд╛рде рд▓реМрдЯрд╛рддреЗ рд╣реИрдВ, рдЬреЛ рдЕрднреА рдЦрд╛рд▓реА рд╣реИ
() ред рд╣рдореЗрд╢рд╛ рдпреВрдирд┐рдХреЛрдб рд░рд╛рдХреНрд╖рд╕ рдХреЛ рдпрд╛рдж рдХрд░рддреЗ рд╣реБрдП, рдХрд╛рдЯрдиреЗ рд╕реЗ рдкрд╣рд▓реЗ, рд╣рдо рдорд╛рдирдХ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЪрд░рд┐рддреНрд░ 'a' рдХреА рдпреВрдЯреАрдПрдл -8 рдореЗрдВ рд▓рдВрдмрд╛рдИ рдХрд╛ рдкрддрд╛ рд▓рдЧрд╛рддреЗ рд╣реИрдВ - рдпрд╣ 1 рд╣реИ (рд▓реЗрдХрд┐рди рдпреВрдирд┐рдХреЛрдб рд░рд╛рдХреНрд╖рд╕ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХрднреА рдирд╣реАрдВ рднреВрд▓рдирд╛ рдЪрд╛рд╣рд┐рдП)ред


рдпрджрд┐ рд╣рдореЗрдВ рдХреЛрдИ рдЕрдиреНрдп Some(char) рдорд┐рд▓рддрд╛ рд╣реИ, рдпрд╛ рдпрджрд┐ рд╣рдореЗрдВ None рдорд┐рд▓рддрд╛ рд╣реИ, рддреЛ рд╣рдо рдПрдХ рддреНрд░реБрдЯрд┐ рд▓реМрдЯрд╛рддреЗ рд╣реИрдВред рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рдпрд╛рдж рдХрд░рддреЗ рд╣реИрдВ, рд╣рдорд╛рд░реА рддреНрд░реБрдЯрд┐ рдХрд╛ рдкреНрд░рдХрд╛рд░ рдХреЗрд╡рд▓ рдПрдХ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдЯреБрдХрдбрд╝рд╛ рд╣реИ, рдЬрд┐рд╕реЗ рд╣рдордиреЗ input рд░реВрдк рдореЗрдВ рдкрд╛рд░рд┐рдд рдХрд┐рдпрд╛ input рдФрд░ рдЬрд┐рд╕реЗ рдкрд╛рд░реНрд╕ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдЗрд╕рдХреА рд╢реБрд░реБрдЖрдд a , рдЗрд╕рд▓рд┐рдП рдпрд╣ рд╣рдорд╛рд░реА рдЧрд▓рддреА рд╣реИред рдпрд╣ рдПрдХ рдмрдбрд╝реА рдЧрд▓рддреА рдирд╣реАрдВ рд╣реИ, рд▓реЗрдХрд┐рди рдХрдо рд╕реЗ рдХрдо рдпрд╣ "рдХрд╣реАрдВ рди рдХрд╣реАрдВ рдХреБрдЫ рдЧрд▓рдд рд╣реИ" рдХреА рддреБрд▓рдирд╛ рдореЗрдВ рдереЛрдбрд╝рд╛ рдмреЗрд╣рддрд░ рд╣реИред


рд╣рдореЗрдВ XML рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдЗрд╕ рдкрд╛рд░реНрд╕рд░ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ, рд▓реЗрдХрд┐рди рдкрд╣рд▓реА рдЪреАрдЬ рдЬреЛ рд╣рдореЗрдВ рдХрд░рдиреА рд╣реЛрдЧреА рд╡рд╣ рд╣реИ рд╢реБрд░реБрдЖрддреА рдЪрд░рд┐рддреНрд░ рдХреЛ рдвреВрдВрдврдирд╛ < , рдЗрд╕рд▓рд┐рдП рд╣рдореЗрдВ рдХреБрдЫ рдЗрд╕реА рддрд░рд╣ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рд╣рдореЗрдВ рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ > , / рдФрд░ = рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреА, рдЗрд╕рд▓рд┐рдП рд╣реЛ рд╕рдХрддрд╛ рд╣реИ рдХрд┐ рд╣рдо рдПрдХ рдРрд╕рд╛ рдлрд╝рдВрдХреНрд╢рди рдмрдирд╛ рд╕рдХреЗрдВ рдЬреЛ рд╣рдо рдЪрд╛рд╣рддреЗ рд╣реИрдВ рдЪрд░рд┐рддреНрд░ рдХреЗ рд▓рд┐рдП рдкрд╛рд░реНрд╕рд░ рдмрдирд╛рддрд╛ рд╣реИ?


рдкрд╛рд░реНрд╕рд░ рдмрдирд╛рдирд╛


рдЖрдЗрдП рдЗрд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рднреА рд╕реЛрдЪрддреЗ рд╣реИрдВ: рд╣рдо рдПрдХ рдлрд╝рдВрдХреНрд╢рди рд▓рд┐рдЦреЗрдВрдЧреЗ рдЬреЛ рдХрд┐рд╕реА рднреА рд▓рдВрдмрд╛рдИ рдХреЗ рд╕реНрдерд┐рд░ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЗ рд▓рд┐рдП рдПрдХ рдкрд╛рд░реНрд╕рд░ рдмрдирд╛рддрд╛ рд╣реИ, рдФрд░ рдХреЗрд╡рд▓ рдПрдХ рдЪрд░рд┐рддреНрд░ рдирд╣реАрдВред рдпрд╣ рдФрд░ рднреА рд╕рд░рд▓ рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рд▓рд╛рдЗрди рдХрд╛ рдЯреБрдХрдбрд╝рд╛ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдПрдХ рд╡реИрдз UTF-8 рд▓рд╛рдЗрди рдЯреБрдХрдбрд╝рд╛ рд╣реИ, рдФрд░ рд╣рдореЗрдВ рдпреВрдирд┐рдХреЛрдб рд░рд╛рдХреНрд╖рд╕ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╕реЛрдЪрдиреЗ рдХреА рдЬрд░реВрд░рдд рдирд╣реАрдВ рд╣реИред


 fn match_literal(expected: &'static str) -> impl Fn(&str) -> Result<(&str, ()), &str> { move |input| match input.get(0..expected.len()) { Some(next) if next == expected => { Ok((&input[expected.len()..], ())) } _ => Err(input), } } 

рдЕрдм рдпрд╣ рдереЛрдбрд╝рд╛ рдЕрд▓рдЧ рджрд┐рдЦрддрд╛ рд╣реИред


рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рдЖрдЗрдП рдкреНрд░рдХрд╛рд░реЛрдВ рдХреЛ рджреЗрдЦреЗрдВред рдЕрдм рд╣рдорд╛рд░рд╛ рдХрд╛рд░реНрдп рдПрдХ expected рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЛ рддрд░реНрдХ рдХреЗ рд░реВрдк рдореЗрдВ рд▓реЗрддрд╛ рд╣реИ рдФрд░ рдПрдХ рдкрд╛рд░реНрд╕рд░ рдХреЗ рд╕рдорд╛рди рдХреБрдЫ рджреЗрддрд╛ рд╣реИ, рди рдХрд┐ рд╕реНрд╡рдпрдВ рдкрд╛рд░реНрд╕рд░ рд╣реЛрдиреЗ рдХреЗ рдмрдЬрд╛рдпред рдпрд╣ рдПрдХ рдРрд╕рд╛ рдлрдВрдХреНрд╢рди рд╣реИ рдЬреЛ рдПрдХ рдЙрдЪреНрдЪ рдСрд░реНрдбрд░ рдлрд╝рдВрдХреНрд╢рди рджреЗрддрд╛ рд╣реИ ред рдЕрдирд┐рд╡рд╛рд░реНрдп рд░реВрдк рд╕реЗ, рд╣рдо рдПрдХ рдлрд╝рдВрдХреНрд╢рди рд▓рд┐рдЦ рд░рд╣реЗ рд╣реИрдВ рдЬреЛ рдкрд╣рд▓реЗ рд╣рдорд╛рд░реЗ the_letter_a рдлрд╝рдВрдХреНрд╢рди рдХреЗ рд╕рдорд╛рди рдлрд╝рдВрдХреНрд╢рди рдмрдирд╛рддрд╛ рд╣реИ ред


рдЗрд╕ рдкреНрд░рдХрд╛рд░, рдлрд╝рдВрдХреНрд╢рди рдХреЗ рд╢рд░реАрд░ рдореЗрдВ рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рдмрдЬрд╛рдп, рд╣рдо рдПрдХ рдХреНрд▓реЛрдЬрд░ рд▓реМрдЯрд╛рддреЗ рд╣реИрдВ рдЬреЛ рдЗрд╕ рдХрд╛рдо рдХреЛ рдХрд░рддрд╛ рд╣реИ рдФрд░ рдЬреЛ рдкрд┐рдЫрд▓реЗ рдПрдХ рд╕реЗ рд╡рд┐рд╢реНрд▓реЗрд╖рдХ рдХреЗ рд▓рд┐рдП рд╣рдорд╛рд░реЗ рдкреНрд░рдХрд╛рд░ рдХреЗ рд╣рд╕реНрддрд╛рдХреНрд╖рд░ рд╕реЗ рдореЗрд▓ рдЦрд╛рддрд╛ рд╣реИред


рдкреИрдЯрд░реНрди рдорд┐рд▓рд╛рди рд╕рдорд╛рди рджрд┐рдЦрддрд╛ рд╣реИ, рд╕рд┐рд╡рд╛рдп рдЗрд╕рдХреЗ рдХрд┐ рд╣рдо рдЕрдкрдиреЗ рд╕реНрдЯреНрд░рд┐рдВрдЧ рд╢рд╛рдмреНрджрд┐рдХ рд╕реЗ рд╕реАрдзреЗ рдореЗрд▓ рдирд╣реАрдВ рдЦрд╛ рд╕рдХрддреЗ рд╣реИрдВ, рдХреНрдпреЛрдВрдХрд┐ рд╣рдо рдирд╣реАрдВ рдЬрд╛рдирддреЗ рдХрд┐ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдХреНрдпрд╛ рд╣реЛрддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рд╣рдо рдорд┐рд▓рд╛рди рд╕реНрдерд┐рддрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ if next == expected ред рдЕрдиреНрдпрдерд╛, рдпрд╣ рд╕рд░реНрдХрд┐рдЯ рдХреЗ рд╢рд░реАрд░ рдХреЗ рдЕрдВрджрд░ рдкрд╣рд▓реЗ рдХреА рддрд░рд╣ рд╣реА рд╣реИред


рд╣рдорд╛рд░реЗ рдкрд╛рд░реНрд╕рд░ рдХрд╛ рдкрд░реАрдХреНрд╖рдг


рдЖрдЗрдП рдЗрд╕рдХреЗ рд▓рд┐рдП рдПрдХ рдкрд░реАрдХреНрд╖рдг рд▓рд┐рдЦреЗрдВ рддрд╛рдХрд┐ рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рд╣реЛ рд╕рдХреЗ рдХрд┐ рд╣рдо рдЗрд╕реЗ рдареАрдХ рдХрд░ рд▓реЗрдВред


 #[test] fn literal_parser() { let parse_joe = match_literal("Hello Joe!"); assert_eq!( Ok(("", ())), parse_joe("Hello Joe!") ); assert_eq!( Ok((" Hello Robert!", ())), parse_joe("Hello Joe! Hello Robert!") ); assert_eq!( Err("Hello Mike!"), parse_joe("Hello Mike!") ); } 

рдкрд╣рд▓реЗ рд╣рдо рдПрдХ рдкрд╛рд░реНрд╕рд░ рдмрдирд╛рддреЗ рд╣реИрдВ: match_literal("Hello Joe!") ред рдпрд╣ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХрд╛ рдЙрдкрднреЛрдЧ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП "Hello Joe!" рдФрд░ рдмрд╛рдХреА рд╕реНрдЯреНрд░рд┐рдВрдЧ рд╡рд╛рдкрд╕ рдХрд░реЗрдВ, рдпрд╛ рд╡рд┐рдлрд▓ рд░рд╣реЗрдВ рдФрд░ рдкреВрд░реЗ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЛ рд╡рд╛рдкрд╕ рдХрд░реЗрдВред


рдкрд╣рд▓реЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рд╣рдо рдЗрд╕реЗ рдареАрдХ рд╡рд╣реА рдкрдВрдХреНрддрд┐ рдкрд╛рд╕ рдХрд░рддреЗ рд╣реИрдВ рдЬрд┐рд╕рдХреА рд╣рдо рдЕрдкреЗрдХреНрд╖рд╛ рдХрд░рддреЗ рд╣реИрдВ, рдФрд░ рджреЗрдЦрддреЗ рд╣реИрдВ рдХрд┐ рдпрд╣ рдПрдХ рдЦрд╛рд▓реА рд╕реНрдЯреНрд░рд┐рдВрдЧ рдФрд░ рдорд╛рди рд▓реМрдЯрд╛рддрд╛ рд╣реИ () , рдЬрд┐рд╕рдХрд╛ рдЕрд░реНрде рд╣реИ "рд╣рдордиреЗ рдЕрдкреЗрдХреНрд╖рд┐рдд рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд┐рдпрд╛ рд╣реИ, рдФрд░ рдЖрдкрдХреЛ рдЗрд╕реЗ рд╡рд╛рдкрд╕ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИред"


рджреВрд╕рд░реЗ рдореЗрдВ, рд╣рдо рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЛ рдЦрд┐рд▓рд╛рддреЗ рд╣реИрдВ "Hello Joe! Hello Robert!" рдФрд░ рд╣рдо рджреЗрдЦрддреЗ рд╣реИрдВ рдХрд┐ рд╡рд╣ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ "Hello Joe!" рдФрд░ рдЗрдирдкреБрдЯ рдХреЗ рд╢реЗрд╖ рдХреЛ рд▓реМрдЯрд╛рддрд╛ рд╣реИ: " Hello Robert!" (рдЕрдЧреНрд░рдгреА рд╕реНрдерд╛рди рдФрд░ рдмрд╛рдХреА рд╕рдм рдХреБрдЫ)ред


рддреАрд╕рд░реЗ рдореЗрдВ, рд╣рдо рдЧрд▓рдд рдЗрдирдкреБрдЯ рджрд░реНрдЬ рдХрд░рддреЗ рд╣реИрдВ: "Hello Mike!" рдФрд░ рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рдпрд╣ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдПрдХ рддреНрд░реБрдЯрд┐ рдХреЗ рд╕рд╛рде рдЗрдирдкреБрдЯ рдХреЛ рдЕрд╕реНрд╡реАрдХрд╛рд░ рдХрд░рддрд╛ рд╣реИред рдРрд╕рд╛ рдирд╣реАрдВ рд╣реИ рдХрд┐ Mike рдЧрд▓рдд рд╣реИ, рдЖрдорддреМрд░ рдкрд░ рд╕рд┐рд░реНрдл рд╡рд╣реА рдирд╣реАрдВ рдЬреЛ рдкрд╛рд░реНрд╕рд░ рдХреА рддрд▓рд╛рд╢ рдореЗрдВ рдерд╛ред


рдХреБрдЫ рдХрдо рд╡рд┐рд╢рд┐рд╖реНрдЯ рдХреЗ рд▓рд┐рдП рдкрд╛рд░реНрд╕рд░


рддреЛ рдпрд╣ рд╣рдореЗрдВ < , > , = рдФрд░ рдпрд╣рд╛рдВ рддрдХ тАЛтАЛрдХрд┐ </ рдФрд░ /> рдХрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред рд╣рдо рд▓рдЧрднрдЧ рд╣реЛ рдЪреБрдХреЗ рд╣реИрдВ!


рдкреНрд░рд╛рд░рдВрднрд┐рдХ рдЪрд░рд┐рддреНрд░ рдХреЗ рдмрд╛рдж рдЕрдЧрд▓рд╛ < рддрддреНрд╡ рдХрд╛ рдирд╛рдо рд╣реИред рд╣рдо рдПрдХ рд╕рд╛рдзрд╛рд░рдг рд╕реНрдЯреНрд░рд┐рдВрдЧ рддреБрд▓рдирд╛ рдХреЗ рд╕рд╛рде рдРрд╕рд╛ рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗред рд▓реЗрдХрд┐рди рд╣рдо рдЗрд╕реЗ regex рдХреЗ рд╕рд╛рде рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ ...


... рд▓реЗрдХрд┐рди рдЪрд▓реЛ рд╡рд╛рдкрд╕ рдкрдХрдбрд╝реЛред рдпрд╣ рдПрдХ рдирд┐рдпрдорд┐рдд рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рд╣реЛрдЧреА рдЬреЛ рд╕рд░рд▓ рдХреЛрдб рдореЗрдВ рджреЛрд╣рд░рд╛рдиреЗ рдореЗрдВ рдмрд╣реБрдд рдЖрд╕рд╛рди рд╣реЛрдЧреА, рдФрд░ рдЗрд╕рдХреЗ рд▓рд┐рдП рд╣рдореЗрдВ regex рдкреИрдХреЗрдЬ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИред рдЖрдЗрдП рджреЗрдЦреЗрдВ рдХрд┐ рдХреНрдпрд╛ рд╣рдо рдЗрд╕рдХреЗ рд▓рд┐рдП рдЕрдкрдиреЗ рд╕реНрд╡рдпрдВ рдХреЗ рдкрд╛рд░реНрд╕рд░ рд▓рд┐рдЦ рд╕рдХрддреЗ рд╣реИрдВ, рдХреЗрд╡рд▓ рдорд╛рдирдХ рдЬрдВрдЧрд▓рд╛ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗред


рддрддреНрд╡ рдХреЗ рдирд╛рдо рдХреЗ рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛ рдХреЗ рд▓рд┐рдП рдирд┐рдпрдо рдХреЛ рдпрд╛рдж рдХрд░реЗрдВ, рдпрд╣ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрддрд╛ рд╣реИ: рдПрдХ рд╡рд░реНрдгрдорд╛рд▓рд╛ рд╡рд░реНрдг, рдЬрд┐рд╕рдХреЗ рдмрд╛рдж рд╢реВрдиреНрдп рдпрд╛ рдХрд┐рд╕реА рд╡рд░реНрдгрдорд╛рд▓рд╛ рдХреЗ рдкреНрд░рддреАрдХ рдХрд╛ рдЕрдзрд┐рдХ рд╣реЛрдирд╛,
рдЪрд░рд┐рддреНрд░, рд╕рдВрдЦреНрдпрд╛ рдпрд╛ рдбреИрд╢ред


 fn identifier(input: &str) -> Result<(&str, String), &str> { let mut matched = String::new(); let mut chars = input.chars(); match chars.next() { Some(next) if next.is_alphabetic() => matched.push(next), _ => return Err(input), } while let Some(next) = chars.next() { if next.is_alphanumeric() || next == '-' { matched.push(next); } else { break; } } let next_index = matched.len(); Ok((&input[next_index..], matched)) } 

рд╣рдореЗрд╢рд╛ рдХреА рддрд░рд╣, рд╣рдо рдкрд╣рд▓реЗ рдкреНрд░рдХрд╛рд░ рдХреЛ рджреЗрдЦрддреЗ рд╣реИрдВред рдЗрд╕ рдмрд╛рд░ рд╣рдо рдПрдХ рдкрд╛рд░реНрд╕рд░ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдлрд╝рдВрдХреНрд╢рди рдирд╣реАрдВ рд▓рд┐рдЦрддреЗ рд╣реИрдВ, рд╣рдо рд╕рд┐рд░реНрдл рдкрд╛рд░реНрд╕рд░ рдХреЛ рд╣реА рд▓рд┐рдЦрддреЗ рд╣реИрдВ, рдЬреИрд╕реЗ рдХрд┐ рдкрд╣рд▓реА рдмрд╛рд░ред рдпрд╣рд╛рдВ рдзреНрдпрд╛рди рджреЗрдиреЗ рдпреЛрдЧреНрдп рдЕрдВрддрд░ рдпрд╣ рд╣реИ рдХрд┐ рдкрд░рд┐рдгрд╛рдо рдкреНрд░рдХрд╛рд░ () рдмрдЬрд╛рдп () рд╣рдо рд╢реЗрд╖ рдЗрдирдкреБрдЯ рдХреЗ рд╕рд╛рде рдЯреНрдпреВрдкрд▓ рдореЗрдВ рдПрдХ String рд▓реМрдЯрд╛рддреЗ рд╣реИрдВред рдЗрд╕ String рдореЗрдВ рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛ рд╣реЛрдЧрд╛ рдЬрд┐рд╕реЗ рд╣рдордиреЗ рдЕрднреА рдкрд╛рд░реНрд╕ рдХрд┐рдпрд╛ рд╣реИред


рдЗрд╕реЗ рдзреНрдпрд╛рди рдореЗрдВ рд░рдЦрддреЗ рд╣реБрдП, рд╣рдо рдкрд╣рд▓реЗ рдПрдХ рдЦрд╛рд▓реА String рдмрдирд╛рддреЗ рд╣реИрдВ рдФрд░ рдЗрд╕реЗ matched рдХрд╣рддреЗ рд╣реИрдВред рдпрд╣ рд╣рдорд╛рд░рд╛ рдкрд░рд┐рдгрд╛рдо рд╣реЛрдЧрд╛ред рд╣рдореЗрдВ input рдореЗрдВ рдкрд╛рддреНрд░реЛрдВ рдХреЗ рд▓рд┐рдП рдПрдХ рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рднреА рдорд┐рд▓рддреА рд╣реИ, рдЬрд┐рд╕реЗ рд╣рдо рд╡рд┐рднрд╛рдЬрд┐рдд рдХрд░рдирд╛ рд╢реБрд░реВ рдХрд░рдиреЗ рдЬрд╛ рд░рд╣реЗ рд╣реИрдВред


рдкрд╣рд▓рд╛ рдХрджрдо рдпрд╣ рджреЗрдЦрдирд╛ рд╣реИ рдХрд┐ рдХреНрдпрд╛ рд╢реБрд░реБрдЖрдд рдореЗрдВ рдХреЛрдИ рдкреНрд░рддреАрдХ рд╣реИред рд╣рдо рдкрд╣рд▓реЗ рдЕрдХреНрд╖рд░ рдХреЛ next.is_alphabetic() рдФрд░ рдЬрд╛рдБрдЪрддреЗ рд╣реИрдВ рдХрд┐ рдХреНрдпрд╛ рд╡рд╣ рдЕрдХреНрд╖рд░ рд╣реИ: next.is_alphabetic() ред рдорд╛рдирдХ рд░рд╕реНрдЯ рд▓рд╛рдЗрдмреНрд░реЗрд░реА, рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ, рд╣рдореЗрдВ рдпреВрдирд┐рдХреЛрдб рдХреЗ рд╕рд╛рде рдорджрдж рдХрд░реЗрдЧреА - рдпрд╣ рдХрд┐рд╕реА рднреА рд╡рд░реНрдгрдорд╛рд▓рд╛ рдореЗрдВ рдЕрдХреНрд╖рд░реЛрдВ рдХреЗ рдЕрдиреБрд░реВрдк рд╣реЛрдЧрд╛, рдФрд░ рди рдХреЗрд╡рд▓ рдПрдПрд╕рд╕реАрдЖрдИрдЖрдИ рдореЗрдВред рдпрджрд┐ рдпрд╣ рдПрдХ рдкрддреНрд░ рд╣реИ, рддреЛ рд╣рдо рдЗрд╕реЗ matched рд╕реНрдЯреНрд░рд┐рдВрдЧ рдореЗрдВ рд╣рдорд╛рд░реЗ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдореЗрдВ рдбрд╛рд▓рддреЗ рд╣реИрдВ, рдФрд░ рдпрджрд┐ рдирд╣реАрдВ, рддреЛ рд╣рдо рддрддреНрд╡ рдХреЗ рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛ рдХреЛ рдирд╣реАрдВ рджреЗрдЦрддреЗ рд╣реИрдВ рдФрд░ рддреБрд░рдВрдд рдПрдХ рддреНрд░реБрдЯрд┐ рдХреЗ рд╕рд╛рде рд▓реМрдЯрддреЗ рд╣реИрдВред


рджреВрд╕рд░реЗ рдЪрд░рдг рдореЗрдВ, рд╣рдо is_alphanumeric() рд╕реЗ рд╡рд░реНрдгреЛрдВ рдХреЛ рдЦреАрдВрдЪрддреЗ рд░рд╣рддреЗ рд╣реИрдВ, рдЙрдиреНрд╣реЗрдВ рдЙрд╕ рдкрдВрдХреНрддрд┐ рддрдХ рднреЗрдЬрддреЗ рд╣реИрдВ, рдЬрд┐рд╕реЗ рд╣рдо рддрдм рддрдХ рдмрдирд╛рддреЗ рд╣реИрдВ рдЬрдм рддрдХ рдХрд┐ рд╣рдореЗрдВ is_alphanumeric() рдЪрд░рд┐рддреНрд░ рдирд╣реАрдВ is_alphanumeric() рдЬреЛ is_alphanumeric() рдлрд╝рдВрдХреНрд╢рди рдХреЛ рд╕рдВрддреБрд╖реНрдЯ рдирд╣реАрдВ рдХрд░рддрд╛ (рдпрд╣ is_alphabetic() рд╕рдорд╛рди рд╣реИ is_alphabetic() рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛ рдЗрд╕рдореЗрдВ рдХрд┐рд╕реА рд╡рд░реНрдгрдорд╛рд▓рд╛ рдореЗрдВ рд╕рдВрдЦреНрдпрд╛рдПрдБ рднреА рд╢рд╛рдорд┐рд▓ рд╣реИрдВ) рдпрд╛ рдкрд╛рдиреА '-' рдЫреАрдВрдЯрд╛ '-' ред


рдЬрдм рд╣рдо рдкрд╣рд▓реА рдмрд╛рд░ рдРрд╕рд╛ рдХреБрдЫ рджреЗрдЦрддреЗ рд╣реИрдВ рдЬреЛ рдЗрди рдорд╛рдирджрдВрдбреЛрдВ рдХреЛ рдкреВрд░рд╛ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рддреЛ рд╣рдо рдкрд╛рд░реНрд╕рд┐рдВрдЧ рдХреЛ рд╕рдорд╛рдкреНрдд рдХрд░рддреЗ рд╣реИрдВ, рд▓реВрдк рдХреЛ рддреЛрдбрд╝рддреЗ рд╣реИрдВ рдФрд░ рдПрдХ String рд▓реМрдЯрд╛рддреЗ рд╣реИрдВ, рдЬреЛ рд╣рдо input рд╕реЗ рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдЧрдП рдЯреБрдХрдбрд╝реЗ рдХреЛ рдХрд╛рдЯрдиреЗ рдХреЗ рд▓рд┐рдП рдпрд╛рдж рдХрд░рддреЗ рд╣реИрдВред рдЗрд╕реА рддрд░рд╣, рдпрджрд┐ рд╡рд░реНрдг рдПрдХ рдкреБрдирд░рд╛рд╡реГрддреНрдд рдореЗрдВ рд╕рдорд╛рдкреНрдд рд╣реЛрддреЗ рд╣реИрдВ, рддреЛ рдЗрд╕рдХрд╛ рдорддрд▓рдм рд╣реИ рдХрд┐ рд╣рдо рдЗрдирдкреБрдЯ рдХреЗ рдЕрдВрдд рддрдХ рдкрд╣реБрдВрдЪ рдЧрдП рд╣реИрдВред


рдпрд╣ рдзреНрдпрд╛рди рджреЗрдиреЗ рдпреЛрдЧреНрдп рд╣реИ рдХрд┐ рд╣рдо рдПрдХ рддреНрд░реБрдЯрд┐ рдХреЗ рд╕рд╛рде рд╡рд╛рдкрд╕ рдирд╣реАрдВ рдЖрддреЗ рд╣реИрдВ рдЬрдм рд╣рдо рдХреБрдЫ рдРрд╕рд╛ рджреЗрдЦрддреЗ рд╣реИрдВ рдЬреЛ рдЕрд▓реНрдлрд╝рд╛рдиреНрдпреВрдореЗрд░рд┐рдХ рдпрд╛ рдбреИрд╢ рдирд╣реАрдВ рд╣реИред рдЗрд╕ рдкрд╣рд▓реЗ рдЕрдХреНрд╖рд░ рд╕реЗ рдореЗрд▓ рдЦрд╛рдиреЗ рдХреЗ рдмрд╛рдж рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдПрдХ рд╡реИрдз рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд░реНрдпрд╛рдкреНрдд рд╣реИ, рдФрд░ рдпрд╣ рд╕рд╛рдорд╛рдиреНрдп рд╣реИ рдХрд┐ рд╣рдорд╛рд░реЗ рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛ рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХреЗ рд▓рд┐рдП рдЗрдирдкреБрдЯ рд▓рд╛рдЗрди рдореЗрдВ рдЕрдзрд┐рдХ рддрддреНрд╡ рд╣реЛрдВрдЧреЗ, рдЗрд╕рд▓рд┐рдП рд╣рдо рдХреЗрд╡рд▓ рдкрд╛рд░реНрд╕ рдХрд░рдирд╛ рдмрдВрдж рдХрд░ рджреЗрддреЗ рд╣реИрдВ рдФрд░ рдЕрдкрдирд╛ рдкрд░рд┐рдгрд╛рдо рд╡рд╛рдкрд╕ рдХрд░рддреЗ рд╣реИрдВред рдХреЗрд╡рд▓ рдЕрдЧрд░ рд╣рдореЗрдВ рдпрд╣ рдкрд╣рд▓рд╛ рдЕрдХреНрд╖рд░ рднреА рдирд╣реАрдВ рдорд┐рд▓рддрд╛ рд╣реИ, рддреЛ рд╣рдо рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдПрдХ рддреНрд░реБрдЯрд┐ рд▓реМрдЯрд╛рддреЗ рд╣реИрдВ, рдХреНрдпреЛрдВрдХрд┐ рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ рдХреЛрдИ рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛ рдирд╣реАрдВ рдерд╛ред


рдпрд╛рдж рд░рдЦреЗрдВ рдХрд┐ Element рд╕рдВрд░рдЪрдирд╛ рд╡рд╣ рд╣реИ рдЬреЛ рд╣рдо рдЕрдкрдиреЗ XML рджрд╕реНрддрд╛рд╡реЗрдЬрд╝ рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░рдиреЗ рдЬрд╛ рд░рд╣реЗ рд╣реИрдВред


 struct Element { name: String, attributes: Vec<(String, String)>, children: Vec<Element>, } 

рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рд╣рдордиреЗ рдкрд╣рд▓реЗ рднрд╛рдЧ, name рдХреНрд╖реЗрддреНрд░ рдХреЗ рд▓рд┐рдП рд╡рд┐рд╢реНрд▓реЗрд╖рдХ рдХреЛ рд╕рдорд╛рдкреНрдд рдХрд░ рджрд┐рдпрд╛ред String рдЬреЛ рд╣рдорд╛рд░реЗ рдкрд╛рд░реНрд╕рд░ рд░рд┐рдЯрд░реНрди рдХреЛ рд╕реАрдзреЗ рд╡рд╣рд╛рдВ рд▓реЗ рдЬрд╛рддреА рд╣реИред рдпрд╣ рдкреНрд░рддреНрдпреЗрдХ attribute рдХреЗ рдкрд╣рд▓реЗ рднрд╛рдЧ рдХреЗ рд▓рд┐рдП рд╕рд╣реА рдкрд╛рд░реНрд╕рд░ рднреА рд╣реИред


рдЖрдЗрдП рдЗрд╕реЗ рджреЗрдЦреЗрдВред


 #[test] fn identifier_parser() { assert_eq!( Ok(("", "i-am-an-identifier".to_string())), identifier("i-am-an-identifier") ); assert_eq!( Ok((" entirely an identifier", "not".to_string())), identifier("not entirely an identifier") ); assert_eq!( Err("!not at all an identifier"), identifier("!not at all an identifier") ); } 

рд╣рдо рджреЗрдЦрддреЗ рд╣реИрдВ рдХрд┐ рдкрд╣рд▓реЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рд╕реНрдЯреНрд░рд┐рдВрдЧ "i-am-an-identifier" рдкреВрд░реА рддрд░рд╣ "i-am-an-identifier" рдкрд╛рд░реНрд╕ рд╣реИ, рдХреЗрд╡рд▓ рдПрдХ рдЦрд╛рд▓реА рд╕реНрдЯреНрд░рд┐рдВрдЧ рдЫреЛрдбрд╝ рд░рд╣рд╛ рд╣реИред рджреВрд╕рд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рдкрд╛рд░реНрд╕рд░ рдПрдХ рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛ рдХреЗ рд░реВрдк рдореЗрдВ "not" рджреЗрддрд╛ рд╣реИ, рдФрд░ рд╢реЗрд╖ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЛ рд╢реЗрд╖ рдЗрдирдкреБрдЯ рдХреЗ рд░реВрдк рдореЗрдВ рд╡рд╛рдкрд╕ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рддреАрд╕рд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рдкрд╛рд░реНрд╕рд░ рддреБрд░рдВрдд рд╡рд┐рдлрд▓ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдкрд╣рд▓рд╛ рд╡рд░реНрдг рдЬреЛ рдЗрд╕реЗ рдкрд╛рддрд╛ рд╣реИ рд╡рд╣ рдПрдХ рдЕрдХреНрд╖рд░ рдирд╣реАрдВ рд╣реИред


combinators


рдЕрдм рд╣рдо рд╢реБрд░реБрдЖрддреА рдЪрд░рд┐рддреНрд░ рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ < , рдФрд░ рд╣рдо рдЕрдЧрд▓реЗ рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛ рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рд╣рдореЗрдВ рджреЛрдиреЛрдВ рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдЗрд╕рд▓рд┐рдП, рдЕрдЧрд▓рд╛ рдХрджрдо рдПрдХ рдФрд░ рдХреЙрдореНрдмрд┐рдиреЗрдЯрд░ рдкрд╛рд░реНрд╕рд░ рдлрд╝рдВрдХреНрд╢рди рд▓рд┐рдЦрдирд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдПрдХ рдЬреЛ рдЗрдирдкреБрдЯ рдХреЗ рд░реВрдк рдореЗрдВ рджреЛ рдкрд╛рд░реНрд╕рд░реНрд╕ рд▓реЗрддрд╛ рд╣реИ рдФрд░ рдПрдХ рдирдпрд╛ рдкрд╛рд░реНрд╕рд░ рджреЗрддрд╛ рд╣реИ рдЬреЛ рдЙрди рджреЛрдиреЛрдВ рдХреЛ рдХреНрд░рдо рдореЗрдВ рдкрд╛рд░реНрд╕ рдХрд░рддрд╛ рд╣реИред рджреВрд╕рд░реЗ рд╢рдмреНрджреЛрдВ рдореЗрдВ, рдПрдХ рдкрд╛рд░реНрд╕рд░ рдХреЙрдореНрдмрд┐рдиреЗрдЯрд░ рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рджреЛ рдкрд╛рд░реНрд╕рд░реЛрдВ рдХреЛ рдПрдХ рдирдП рдореЗрдВ рдЬреЛрдбрд╝рддрд╛ рд╣реИред рджреЗрдЦрддреЗ рд╣реИрдВ рдХрд┐ рдХреНрдпрд╛ рд╣рдо рдРрд╕рд╛ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред


 fn pair<P1, P2, R1, R2>(parser1: P1, parser2: P2) -> impl Fn(&str) -> Result<(&str, (R1, R2)), &str> where P1: Fn(&str) -> Result<(&str, R1), &str>, P2: Fn(&str) -> Result<(&str, R2), &str>, { move |input| match parser1(input) { Ok((next_input, result1)) => match parser2(next_input) { Ok((final_input, result2)) => Ok((final_input, (result1, result2))), Err(err) => Err(err), }, Err(err) => Err(err), } } 

рдпрд╣рд╛рдВ рдереЛрдбрд╝рд╛ рдореБрд╢реНрдХрд┐рд▓ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдЖрдк рдЬрд╛рдирддреЗ рд╣реИрдВ рдХрд┐ рдХреНрдпрд╛ рдХрд░рдирд╛ рд╣реИ: рдкреНрд░рдХрд╛рд░реЛрдВ рдХреЛ рджреЗрдЦрдХрд░ рд╢реБрд░реВ рдХрд░реЗрдВред


рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдЪрд╛рд░ рдкреНрд░рдХрд╛рд░ рдХреЗ рдЪрд░ рд╣реИрдВ: P1 , P1 P2 , R1 рдФрд░ R2 ред рдпреЗ рд╣реИрдВ Parser 1 , Parser 2 , Result 1 рдФрд░ Result 2 ред P1 рдФрд░ P2 рдлрд╝рдВрдХреНрд╢рдВрд╕ рд╣реИрдВ, рдФрд░ рдЖрдк рджреЗрдЦреЗрдВрдЧреЗ рдХрд┐ рд╡реЗ рдкрд╛рд░реНрд╕рд░ рдлрд╝рдВрдХреНрд╢рдВрд╕ рдХреЗ рдПрдХ рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рд╕реНрдерд╛рдкрд┐рдд рдкреИрдЯрд░реНрди рдХрд╛ рдкрд╛рд▓рди рдХрд░рддреЗ рд╣реИрдВ: рд░рд┐рдЯрд░реНрди рд╡реИрд▓реНрдпреВ рдХреА рддрд░рд╣, рд╡реЗ рдЗрдирдкреБрдЯ рдХреЗ рд░реВрдк рдореЗрдВ рд▓реЗрддреЗ рд╣реИрдВ &str рдЗрдирдкреБрдЯ рдХреЗ рд░реВрдк рдореЗрдВ рд▓реЗрддреЗ рд╣реИрдВ рдФрд░ рд╡рд╛рдкрд╕ рд▓реМрдЯрддреЗ рд╣реИрдВ рдФрд░ рд╢реЗрд╖ рдЗрдирдкреБрдЯ рдФрд░ рдкрд░рд┐рдгрд╛рдо, рдпрд╛ рдПрдХ рддреНрд░реБрдЯрд┐ Result рдЬреЛрдбрд╝реА рдХрд╛ рдкрд░рд┐рдгрд╛рдо рджреЗрддреЗ рд╣реИрдВред


рд▓реЗрдХрд┐рди рдкреНрд░рддреНрдпреЗрдХ рдлрд╝рдВрдХреНрд╢рди рдХреЗ рдкрд░рд┐рдгрд╛рдо рдкреНрд░рдХрд╛рд░реЛрдВ рдХреЛ рджреЗрдЦреЗрдВ: P1 рд╡рд╣ рдкрд╛рд░реНрд╕рд░ рд╣реИ рдЬреЛ R1 рджреЗрддрд╛ рд╣реИ рдпрджрд┐ рд╕рдлрд▓ рд╣реЛрддрд╛ рд╣реИ, рдФрд░ P2 рднреА R2 рджреЗрддрд╛ рд╣реИред рдФрд░ рд╣рдорд╛рд░реЗ рдлрд╝рдВрдХреНрд╢рди рд╕реЗ рд╡рд╛рдкрд╕ рд▓рд╛рдП рдЧрдП рдЕрдВрддрд┐рдо рдкрд╛рд░реНрд╕рд░ рдХрд╛ рдкрд░рд┐рдгрд╛рдо рд╣реИ (R1, R2) ред рдЗрд╕ рдкреНрд░рдХрд╛рд░, рдЗрд╕ рдкрд╛рд░реНрд╕рд░ рдХрд╛ рдХрд╛рд░реНрдп рдкрд╣рд▓реЗ рдЗрдирдкреБрдЯ рдкрд░ рд╡рд┐рд╢реНрд▓реЗрд╖рдХ P1 рдХреЛ рд╢реБрд░реВ рдХрд░рдирд╛ рд╣реИ, рдЗрд╕рдХреЗ рдкрд░рд┐рдгрд╛рдо рдХреЛ рд╕рд╣реЗрдЬрдирд╛ рд╣реИ, рдлрд┐рд░ P1 рд▓реМрдЯрд╛рдиреЗ рд╡рд╛рд▓реЗ рдЗрдирдкреБрдЯ рдкрд░ P2 рд╢реБрд░реВ рдХрд░рдирд╛ рд╣реИ, рдФрд░ рдпрджрд┐ рджреЛрдиреЛрдВ рдХрд╛рдо рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рд╣рдо рджреЛ рдкрд░рд┐рдгрд╛рдореЛрдВ рдХреЛ рдПрдХ рдЯреНрдпреВрдкрд▓ (R1, R2) рдореЗрдВ рд╕рдВрдпреЛрдЬрд┐рдд рдХрд░рддреЗ рд╣реИрдВред (R1, R2) ред


рдХреЛрдб рджрд┐рдЦрд╛рддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рд╡рд╣реА рд╣реИ рдЬреЛ рд╡рд╣ рдХрд░рддрд╛ рд╣реИред рд╣рдо рдкрд╣рд▓реЗ рдПрдирд╛рд▓рд╛рдЗрдЬрд╝рд░ рдХреЛ рдЗрдирдкреБрдЯ рдкрд░ рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВ, рдлрд┐рд░ рджреВрд╕рд░реЗ рдПрдирд╛рд▓рд╛рдЗрдЬрд╝рд░ рд╕реЗ, рдлрд┐рд░ рджреЛ рдкрд░рд┐рдгрд╛рдореЛрдВ рдХреЛ рдПрдХ рдЯреНрдпреВрдкрд▓ рдореЗрдВ рдЬреЛрдбрд╝рддреЗ рд╣реИрдВ рдФрд░ рдЙрд╕реЗ рд╡рд╛рдкрд╕ рдХрд░рддреЗ рд╣реИрдВред рдпрджрд┐ рдЗрдирдореЗрдВ рд╕реЗ рдХреЛрдИ рднреА рдкрд╛рд░реНрд╕рд░ рд╡рд┐рдлрд▓ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рд╣рдо рддреБрд░рдВрдд рдЙрд╕ рддреНрд░реБрдЯрд┐ рдХреЗ рд╕рд╛рде рд╡рд╛рдкрд╕ рдЖ рдЬрд╛рдПрдВрдЧреЗ рдЬреЛ рдЙрд╕рдиреЗ рдЬрд╛рд░реА рдХреА рдереАред


рдЗрд╕ рдкреНрд░рдХрд╛рд░, рд╣рдореЗрдВ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рд╣рдорд╛рд░реЗ рдкрд╣рд▓реЗ XML рдЯреИрдЧ match_literal рдкрд╣рд▓реЗ рдЯреБрдХрдбрд╝реЗ рдХреЛ match_literal рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╣рдорд╛рд░реЗ рджреЛ рдкрд╛рд░реНрд╕рд░реНрд╕, match_literal рдФрд░ identifier рдХреЛ рдорд┐рд▓рд╛рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред рдЪрд▓реЛ рдпрд╣ рджреЗрдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐ рдХреНрдпрд╛ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, рдПрдХ рдкрд░реАрдХреНрд╖рдг рд▓рд┐рдЦреЗрдВред


 #[test] fn pair_combinator() { let tag_opener = pair(match_literal("<"), identifier); assert_eq!( Ok(("/>", ((), "my-first-element".to_string()))), tag_opener("<my-first-element/>") ); assert_eq!(Err("oops"), tag_opener("oops")); assert_eq!(Err("!oops"), tag_opener("<!oops")); } 

рдХрд╛рдо рдХрд░рдиреЗ рд▓рдЧрддрд╛ рд╣реИ! рд▓реЗрдХрд┐рди рдЗрд╕ рдкреНрд░рдХрд╛рд░ рдХреЗ рдкрд░рд┐рдгрд╛рдо рдХреЛ рджреЗрдЦреЗрдВ: ((), String) ред рдЬрд╛рд╣рд┐рд░ рд╣реИ, рд╣рдо рдХреЗрд╡рд▓ рд╕рд╣реА рдореВрд▓реНрдп рдореЗрдВ рд░реБрдЪрд┐ рд░рдЦрддреЗ рд╣реИрдВ, String ред рдпрд╣ рдХрд╛рдлреА рдмрд╛рд░ рд╣реЛрдЧрд╛ - рд╣рдорд╛рд░реЗ рдХреБрдЫ рдкрд╛рд░реНрд╕рд░ рдХреЗрд╡рд▓ рдЙрддреНрдкрд╛рджрди рдореВрд▓реНрдпреЛрдВ рдХреЗ рдмрд┐рдирд╛ рдЗрдирдкреБрдЯ рдореЗрдВ рдкреИрдЯрд░реНрди рд╕реЗ рдореЗрд▓ рдЦрд╛рддреЗ рд╣реИрдВ, рдФрд░ рдЗрд╕рд▓рд┐рдП рдЙрдирдХреЗ рдЖрдЙрдЯрдкреБрдЯ рдХреЛ рд╕реБрд░рдХреНрд╖рд┐рдд рд░реВрдк рд╕реЗ рдЕрдирджреЗрдЦрд╛ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдЗрд╕ рдкреИрдЯрд░реНрди рдХреЗ рдЕрдиреБрдХреВрд▓ рд╣реЛрдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рджреЛ рдЕрдиреНрдп рдХреЙрдореНрдмреАрдиреЗрдЯрд░реЛрдВ рдХреЛ рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдЕрдкрдиреА pair рдХреЙрдореНрдмрд┐рдиреЗрдЯрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдЬрд╛ рд░рд╣реЗ рд╣реИрдВ: left , рдЬреЛ рдкрд╣рд▓реЗ рдкрд╛рд░реНрд╕рд░ рдХреЗ рдкрд░рд┐рдгрд╛рдо рдХреЛ рдмрддрд╛рддрд╛ рд╣реИ рдФрд░ рдХреЗрд╡рд▓ рджреВрд╕рд░реЗ рдХреЛ рд▓реМрдЯрд╛рддрд╛ рд╣реИ, рдФрд░ рдЗрд╕рдХреЗ рд╡рд┐рдкрд░реАрдд right ред рд╣рдордиреЗ рдКрдкрд░ рдЕрдкрдиреЗ рдкрд░реАрдХреНрд╖рдг рдореЗрдВ рдПрдХ рдкрд╛рд░реНрд╕рд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рд╣реИ, рдЬреЛ рдмрд╛рдПрдВ рд╣рд┐рд╕реНрд╕реЗ рдХреЛ рдЫреЛрдбрд╝ рджреЗрддрд╛ рд╣реИ рдФрд░ pair рдмрдЬрд╛рдп рдХреЗрд╡рд▓ рд╣рдорд╛рд░реЗ String рдмрдЪрд╛рддрд╛ рд╣реИред


рдлрдиреНрдиреЗрдХрд╛рд░ рдкрд░рд┐рдЪрдп


рд▓реЗрдХрд┐рди рдЗрд╕рд╕реЗ рдкрд╣рд▓реЗ рдХрд┐ рд╣рдо рдЖрдЧреЗ рдмрдврд╝рддреЗ рд╣реИрдВ, рдЖрдЗрдП рдПрдХ рдФрд░ рдХреЙрдореНрдмрд┐рдиреЗрдЯрд░ рдХрд╛ рдкрд░рд┐рдЪрдп рджреЗрдВ рдЬреЛ рдЗрди рджреЛ: map рдХреЗ рд▓реЗрдЦрди рдХреЛ рдмрд╣реБрдд рд╕рд░рд▓ рдХрд░реЗрдЧрд╛ред


рдЗрд╕ рдХреЙрдореНрдмреАрдиреЗрдЯрд░ рдХрд╛ рдПрдХ рдХрд╛рдо рд╣реИ: рдкрд░рд┐рдгрд╛рдо рдХреЗ рдкреНрд░рдХрд╛рд░ рдХреЛ рдмрджрд▓рдирд╛ред , , , ((), String) , String .


, , . : |(_left, right)| right . , Fn(A) -> B A тАФ , B тАФ .


 fn map<P, F, A, B>(parser: P, map_fn: F) -> impl Fn(&str) -> Result<(&str, B), &str> where P: Fn(&str) -> Result<(&str, A), &str>, F: Fn(A) -> B, { move |input| match parser(input) { Ok((next_input, result)) => Ok((next_input, map_fn(result))), Err(err) => Err(err), } } 

? P тАФ . A . F тАФ , P , , P , тАФ B A


parser(input) , , result map_fn(result) , A B , .


, , map , Result :


 fn map<P, F, A, B>(parser: P, map_fn: F) -> impl Fn(&str) -> Result<(&str, B), &str> where P: Fn(&str) -> Result<(&str, A), &str>, F: Fn(A) -> B, { move |input| parser(input) .map(|(next_input, result)| (next_input, map_fn(result))) } 

тАФ , ┬л┬╗ Haskell , . A , map , A B , B , . Rust, Option , Result , Iterator Future , . : - Rust, , , , , map .



, , : Fn(&str) -> Result<(&str, Output), &str> . , , , , , , , .


, :


 type ParseResult<'a, Output> = Result<(&'a str, Output), &'a str>; 

, , , ParseResult<String> . , , Rust . , rustc , , .


'a , , .


. , , . , .


 trait Parser<'a, Output> { fn parse(&self, input: &'a str) -> ParseResult<'a, Output>; } 

: parse() , : , , .


, , :


 impl<'a, F, Output> Parser<'a, Output> for F where F: Fn(&'a str) -> ParseResult<Output>, { fn parse(&self, input: &'a str) -> ParseResult<'a, Output> { self(input) } } 

, , , Parser , .


, , . map , .


 fn map<'a, P, F, A, B>(parser: P, map_fn: F) -> impl Parser<'a, B> where P: Parser<'a, A>, F: Fn(A) -> B, { move |input| parser.parse(input) .map(|(next_input, result)| (next_input, map_fn(result))) } 

: , parser.parse(input) , , P , , Parser , , Parser . , . 'a' , , .


pair , :


 fn pair<'a, P1, P2, R1, R2>(parser1: P1, parser2: P2) -> impl Parser<'a, (R1, R2)> where P1: Parser<'a, R1>, P2: Parser<'a, R2>, { move |input| match parser1.parse(input) { Ok((next_input, result1)) => match parser2.parse(next_input) { Ok((final_input, result2)) => Ok((final_input, (result1, result2))), Err(err) => Err(err), }, Err(err) => Err(err), } } 

: parser.parse(input) parser(input) .


, pair , map .


 fn pair<'a, P1, P2, R1, R2>(parser1: P1, parser2: P2) -> impl Parser<'a, (R1, R2)> where P1: Parser<'a, R1>, P2: Parser<'a, R2>, { move |input| { parser1.parse(input).and_then(|(next_input, result1)| { parser2.parse(next_input) .map(|(last_input, result2)| (last_input, (result1, result2))) }) } } 

and_then Result map , , Result , Result . match . and_then , , map , left right .


Left Right


pair map , left right :


 fn left<'a, P1, P2, R1, R2>(parser1: P1, parser2: P2) -> impl Parser<'a, R1> where P1: Parser<'a, R1>, P2: Parser<'a, R2>, { map(pair(parser1, parser2), |(left, _right)| left) } fn right<'a, P1, P2, R1, R2>(parser1: P1, parser2: P2) -> impl Parser<'a, R2> where P1: Parser<'a, R1>, P2: Parser<'a, R2>, { map(pair(parser1, parser2), |(_left, right)| right) } 

pair , , map , .


, , .


, Parser ParseResult . match_literal :


 fn match_literal<'a>(expected: &'static str) -> impl Parser<'a, ()> { move |input: &'a str| match input.get(0..expected.len()) { Some(next) if next == expected => Ok((&input[expected.len()..], ())), _ => Err(input), } } 

, , тАФ &'a str , rustc .


identifier , , , :


 fn identifier(input: &str) -> ParseResult<String> { 

. () . .


 #[test] fn right_combinator() { let tag_opener = right(match_literal("<"), identifier); assert_eq!( Ok(("/>", "my-first-element".to_string())), tag_opener.parse("<my-first-element/>") ); assert_eq!(Err("oops"), tag_opener.parse("oops")); assert_eq!(Err("!oops"), tag_opener.parse("<!oops")); } 


. < . ? .


, , . , .


, , - , : .


( ) . .


тАФ , <element attribute="value"/> , . , , .


identifier , . , .


 fn one_or_more<'a, P, A>(parser: P) -> impl Parser<'a, Vec<A>> where P: Parser<'a, A>, { move |mut input| { let mut result = Vec::new(); if let Ok((next_input, first_item)) = parser.parse(input) { input = next_input; result.push(first_item); } else { return Err(input); } while let Ok((next_input, next_item)) = parser.parse(input) { input = next_input; result.push(next_item); } Ok((input, result)) } } 

, , , A , Vec<A> тАФ A .


identifier . , , . , , .


, : ? :


 fn zero_or_more<'a, P, A>(parser: P) -> impl Parser<'a, Vec<A>> where P: Parser<'a, A>, { move |mut input| { let mut result = Vec::new(); while let Ok((next_input, next_item)) = parser.parse(input) { input = next_input; result.push(next_item); } Ok((input, result)) } } 

, , .


 #[test] fn one_or_more_combinator() { let parser = one_or_more(match_literal("ha")); assert_eq!(Ok(("", vec![(), (), ()])), parser.parse("hahaha")); assert_eq!(Err("ahah"), parser.parse("ahah")); assert_eq!(Err(""), parser.parse("")); } #[test] fn zero_or_more_combinator() { let parser = zero_or_more(match_literal("ha")); assert_eq!(Ok(("", vec![(), (), ()])), parser.parse("hahaha")); assert_eq!(Ok(("ahah", vec![])), parser.parse("ahah")); assert_eq!(Ok(("", vec![])), parser.parse("")); } 

: one_or_more , , zero_or_more , .


, , . one_or_more zero_or_more , - :


 fn one_or_more<'a, P, A>(parser: P) -> impl Parser<'a, Vec<A>> where P: Parser<'a, A>, { map(pair(parser, zero_or_more(parser)), |(head, mut tail)| { tail.insert(0, head); tail }) } 

Rust, cons Vec , , Lisp, , . , : .


, : , . : ( ). , , Clone , , , .


. , one_or_more , , , , , - , , RangeBound : range(0..) zero_or_more , range(1..) one_or_more , range(5..=6) , .


. zero_or_more one_or_more .


, тАФ , Rc ?



, one_or_more zero_or_more .


, . , . , , , > /> . , . , , , , .


. .


-. match_literal , . ? - , Unicode, . Rust, , char is_whitespace , is_alphabetic is_alphanumeric .


-. , , is_whitespace , identifier .


-. , . any_char , char , , pred , , : pred(any_char, |c| c.is_whitespace()) . , , : .


any_char , , UTF-8.


 fn any_char(input: &str) -> ParseResult<char> { match input.chars().next() { Some(next) => Ok((&input[next.len_utf8()..], next)), _ => Err(input), } } 

pred , , . , . , true , . , .


 fn pred<'a, P, A, F>(parser: P, predicate: F) -> impl Parser<'a, A> where P: Parser<'a, A>, F: Fn(&A) -> bool, { move |input| { if let Ok((next_input, value)) = parser.parse(input) { if predicate(&value) { return Ok((next_input, value)); } } Err(input) } } 

, , :


 #[test] fn predicate_combinator() { let parser = pred(any_char, |c| *c == 'o'); assert_eq!(Ok(("mg", 'o')), parser.parse("omg")); assert_eq!(Err("lol"), parser.parse("lol")); } 

, whitespace_char :


 fn whitespace_char<'a>() -> impl Parser<'a, char> { pred(any_char, |c| c.is_whitespace()) } 

, whitespace_char , , , , , . space1 space0 .


 fn space1<'a>() -> impl Parser<'a, Vec<char>> { one_or_more(whitespace_char()) } fn space0<'a>() -> impl Parser<'a, Vec<char>> { zero_or_more(whitespace_char()) } 


? , , . identifier ( , any_char pred *_or_more ). match_literal("=") = . , . , , .


 fn quoted_string<'a>() -> impl Parser<'a, String> { map( right( match_literal("\""), left( zero_or_more(pred(any_char, |c| *c != '"')), match_literal("\""), ), ), |chars| chars.into_iter().collect(), ) } 

, , , , .


map - , , , , , : . map right , right тАФ , : match_literal("\"") . .


right тАФ . left , , left , , , match_literal("\"") тАФ . , тАФ .


pred any_char , , , zero_or_more , :


  • ,

right left .


, . , zero_or_more ? Vec<A> A . any_char char . , , Vec<char> . map : , Vec<char> String , , String Iterator<Item = char> , vec_of_chars.into_iter().collect() , String .


, , , , , , , , .


 #[test] fn quoted_string_parser() { assert_eq!( Ok(("", "Hello Joe!".to_string())), quoted_string().parse("\"Hello Joe!\"") ); } 

, , , , .


,


, , = . , .


. , Vec<(String, String)> , (String, String) , zero_or_more . , .


 fn attribute_pair<'a>() -> impl Parser<'a, (String, String)> { pair(identifier, right(match_literal("="), quoted_string())) } 

! : pair , identifier , String , right = , , quoted_string , String .


zero_or_more , , .


 fn attributes<'a>() -> impl Parser<'a, Vec<(String, String)>> { zero_or_more(right(space1(), attribute_pair())) } 

: ,
. right .


.


 #[test] fn attribute_parser() { assert_eq!( Ok(( "", vec![ ("one".to_string(), "1".to_string()), ("two".to_string(), "2".to_string()) ] )), attributes().parse(" one=\"1\" two=\"2\"") ); } 

! !


, , rustc , , . , . , rustc, , , #![type_length_limit = "тАжsome big numberтАж"] , . , #![type_length_limit = "16777216"] , . , !



, , , , NP-. element: , , , zero_or_more , ?


, , . , , , : < , . , (String, Vec<(String, String)>) .


 fn element_start<'a>() -> impl Parser<'a, (String, Vec<(String, String)>)> { right(match_literal("<"), pair(identifier, attributes())) } 

, , .


 fn single_element<'a>() -> impl Parser<'a, Element> { map( left(element_start(), match_literal("/>")), |(name, attributes)| Element { name, attributes, children: vec![], }, ) } 

, , тАФ Element !


.


 #[test] fn single_element_parser() { assert_eq!( Ok(( "", Element { name: "div".to_string(), attributes: vec![("class".to_string(), "float".to_string())], children: vec![] } )), single_element().parse("<div class=\"float\"/>") ); } 

тАж , .


single_element , , , . , , , тАФ , тАФ .


, , ...



- Rust, , , .


. , :


 enum List<A> { Cons(A, List<A>), Nil, } 

rustc , List<A> , List::<A>::Cons List<A> , . rustc, , , .


, Rust. , Rust, , , , . , .


, . , List::Cons A A , A A . , , , , List::Cons , . , Rust тАФ Box .


 enum List<A> { Cons(A, Box<List<A>>), Nil, } 

Box , . , , Box<dyn Parser<'a, A>> .


. ? , - , , . : . . , , SIMD ( ).


, Parser Box , .


 struct BoxedParser<'a, Output> { parser: Box<dyn Parser<'a, Output> + 'a>, } impl<'a, Output> BoxedParser<'a, Output> { fn new<P>(parser: P) -> Self where P: Parser<'a, Output> + 'a, { BoxedParser { parser: Box::new(parser), } } } impl<'a, Output> Parser<'a, Output> for BoxedParser<'a, Output> { fn parse(&self, input: &'a str) -> ParseResult<'a, Output> { self.parser.parse(input) } } 

, , BoxedParser box . BoxedParser ( BoxedParser , ), BoxedParser::new(parser) , , Box . , Parser , .


Box , BoxedParser Parser , . , , , , , , , , . .



, , , .


, ? , , . quoted_string :


 fn quoted_string<'a>() -> impl Parser<'a, String> { map( right( match_literal("\""), left( zero_or_more(pred(any_char, |c| *c != '"')), match_literal("\""), ), ), |chars| chars.into_iter().collect(), ) } 

, . Parser ?


, , impl Trait , impl Trait .


тАж BoxedParser . , impl Parser<'a, A> , , BoxedParser<'a, A> .


, , , Parser .


map , Parser :


 trait Parser<'a, Output> { fn parse(&self, input: &'a str) -> ParseResult<'a, Output>; fn map<F, NewOutput>(self, map_fn: F) -> BoxedParser<'a, NewOutput> where Self: Sized + 'a, Output: 'a, NewOutput: 'a, F: Fn(Output) -> NewOutput + 'a, { BoxedParser::new(map(self, map_fn)) } } 

'a , , . , тАФ , , impl Trait .


quoted_string :


 fn quoted_string<'a>() -> impl Parser<'a, String> { right( match_literal("\""), left( zero_or_more(pred(any_char, |c| *c != '"')), match_literal("\""), ), ) .map(|chars| chars.into_iter().collect()) } 

, , .map() right() .


pair , left right , , , , pair . , , map , .


тАФ pred . Parser :


 fn pred<F>(self, pred_fn: F) -> BoxedParser<'a, Output> where Self: Sized + 'a, Output: 'a, F: Fn(&Output) -> bool + 'a, { BoxedParser::new(pred(self, pred_fn)) } 

quoted_string pred , :


 zero_or_more(any_char.pred(|c| *c != '"')), 

, , , zero_or_more тАФ ┬л any_char ┬╗, . , zero_or_more one_or_more .


quoted_string , map single_element :


 fn single_element<'a>() -> impl Parser<'a, Element> { left(element_start(), match_literal("/>")).map(|(name, attributes)| Element { name, attributes, children: vec![], }) } 

element_start , , , . ...


тАж , . , .


map pred Box тАФ !



. single_element , , > , /> . , , .


 fn open_element<'a>() -> impl Parser<'a, Element> { left(element_start(), match_literal(">")).map(|(name, attributes)| Element { name, attributes, children: vec![], }) } 

, ? , , , zero_or_more , ? , , тАФ : , , .


, , : , , . , , , . , , , , , , .


 fn either<'a, P1, P2, A>(parser1: P1, parser2: P2) -> impl Parser<'a, A> where P1: Parser<'a, A>, P2: Parser<'a, A>, { move |input| match parser1.parse(input) { ok @ Ok(_) => ok, Err(_) => parser2.parse(input), } } 

element , , ( open_element , element ).


 fn element<'a>() -> impl Parser<'a, Element> { either(single_element(), open_element()) } 

. , , , . , ?


 fn close_element<'a>(expected_name: String) -> impl Parser<'a, String> { right(match_literal("</"), left(identifier, match_literal(">"))) .pred(move |name| name == &expected_name) } 

pred , ?


, :


 fn parent_element<'a>() -> impl Parser<'a, Element> { pair( open_element(), left(zero_or_more(element()), close_element(тАжoops)), ) } 

close_element ? , .


. , parent_element , open_element element parent_element , , XML.


, , and_then ? , . and_then : -, , , , . pair , , , , . , and_then Result Option , , , Result Option , , ( , )).


, .


 fn and_then<'a, P, F, A, B, NextP>(parser: P, f: F) -> impl Parser<'a, B> where P: Parser<'a, A>, NextP: Parser<'a, B>, F: Fn(A) -> NextP, { move |input| match parser.parse(input) { Ok((next_input, result)) => f(result).parse(next_input), Err(err) => Err(err), } } 

, , P , , A . F , map A B , , and_then A NextP , B . тАФ B , , , NextP .


: , , , , f ( A ), , f(result) , B . . , , , B


: P , , f P , NextP , , .


Parser , map , .


 fn and_then<F, NextParser, NewOutput>(self, f: F) -> BoxedParser<'a, NewOutput> where Self: Sized + 'a, Output: 'a, NewOutput: 'a, NextParser: Parser<'a, NewOutput> + 'a, F: Fn(Output) -> NextParser + 'a, { BoxedParser::new(and_then(self, f)) } 

, , ?


, pair :


 fn pair<'a, P1, P2, R1, R2>(parser1: P1, parser2: P2) -> impl Parser<'a, (R1, R2)> where P1: Parser<'a, R1> + 'a, P2: Parser<'a, R2> + 'a, R1: 'a + Clone, R2: 'a, { parser1.and_then(move |result1| parser2.map(move |result2| (result1.clone(), result2))) } 

, : parser2.map() parser2 , Fn , FnOnce , parser2 , . , Rust. , , pair .


, Rust, close_element , , .


:


 fn parent_element<'a>() -> impl Parser<'a, Element> { pair( open_element(), left(zero_or_more(element()), close_element(тАжoops)), ) } 

, and_then , close_element .


 fn parent_element<'a>() -> impl Parser<'a, Element> { open_element().and_then(|el| { left(zero_or_more(element()), close_element(el.name.clone())).map(move |children| { let mut el = el.clone(); el.children = children; el }) }) } 

, and_then open_element() , , close_element . , open_element and_then . , Element open_element , , , .


, map , Element ( el ) . clone() , Fn . ( Vec<Element> ) Element , .


, , element , open_element parent_element , , , , !


"" ?


, , map ┬л┬╗ Haskell?


and_then тАФ , Rust, , map . flat_map Iterator , , .


тАФ "". Thing<A> , and_then , A Thing<B> , Thing<B> тАФ .


, , Option<A> , , Some(A) None , , Some(A) , Some(B)


. , Future<A> , and_then Future<B> , Future<B> Future<A> , Future<A> . Future<A> , тАФ 1 , Future<B> . , Future , and_then , Future , . , Future , .


, Rust , , , , , , , . .


, Redux


.


, XML, . , ( , , < div / > , ).


.


 fn whitespace_wrap<'a, P, A>(parser: P) -> impl Parser<'a, A> where P: Parser<'a, A>, { right(space0(), left(parser, space0())) } 

element , element , , , .


 fn element<'a>() -> impl Parser<'a, Element> { whitespace_wrap(either(single_element(), parent_element())) } 

!


, ! , .


 #[test] fn xml_parser() { let doc = r#" <top label="Top"> <semi-bottom label="Bottom"/> <middle> <bottom label="Another bottom"/> </middle> </top>"#; let parsed_doc = Element { name: "top".to_string(), attributes: vec![("label".to_string(), "Top".to_string())], children: vec![ Element { name: "semi-bottom".to_string(), attributes: vec![("label".to_string(), "Bottom".to_string())], children: vec![], }, Element { name: "middle".to_string(), attributes: vec![], children: vec![Element { name: "bottom".to_string(), attributes: vec![("label".to_string(), "Another bottom".to_string())], children: vec![], }], }, ], }; assert_eq!(Ok(("", parsed_doc)), element().parse(doc)); } 

, - , , :


 #[test] fn mismatched_closing_tag() { let doc = r#" <top> <bottom/> </middle>"#; assert_eq!(Err("</middle>"), element().parse(doc)); } 

, . , , , , . , , , , . , , , , , .


: , ! , , , 2 .


, , . !



, , Rust , , - , , , .


, pom , , .


Rust nom , pom ( , ), , .


Rust combine , .


Haskell Parsec .


, ┬л Haskell┬╗ , , Haskell.



Bodil Stokke Creative Commons Attribution-NonCommercial-ShareAlike 4.0. , http://creativecommons.org/licenses/by-nc-sa/4.0/ .



1: .


2: , .



andreevlex funkill

Source: https://habr.com/ru/post/hi469213/


All Articles