рдирдорд╕реНрдХрд╛рд░, рд╣реЗрдмреНрд░! рдореИрдВ рдЖрдкрдХреЗ рд▓рд┐рдП "рд▓рд░реНрдирд┐рдВрдЧ рдкрд╛рд░реНрд╕рд░ рдХреЙрдореНрдмрд┐рдиреЗрдЯрд░ рд╡рд┐рде рд░рд╕реНрдЯ" рд▓реЗрдЦ рдХрд╛ рдЕрдиреБрд╡рд╛рдж рдкреНрд░рд╕реНрддреБрдд рдХрд░рддрд╛ рд╣реВрдВред
рдпрд╣ рд▓реЗрдЦ рдЙрди рд▓реЛрдЧреЛрдВ рдХреЗ рд▓рд┐рдП рджрд╣рдирд╢реАрд▓ рдкрд╛рд░реНрд╕рд░ рдХреА рдореВрд▓ рдмрд╛рддреЗрдВ рд╕рд┐рдЦрд╛рддрд╛ рд╣реИ рдЬреЛ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдЬрдВрдЧ рд╕реЗ рдкрд░рд┐рдЪрд┐рдд рд╣реИрдВред рдпрд╣ рдорд╛рдирд╛ рдЬрд╛рддрд╛ рд╣реИ рдХрд┐ рдХрд┐рд╕реА рдЕрдиреНрдп рдЬреНрдЮрд╛рди рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ, рдФрд░ рд╕рдм рдХреБрдЫ рдЬреЛ рд╕реАрдзреЗ рд░реБрд╕реНрдд рд╕реЗ рд╕рдВрдмрдВрдзрд┐рдд рдирд╣реАрдВ рд╣реИ, рд╕рд╛рде рд╣реА рдЗрд╕рдХреЗ рдЙрдкрдпреЛрдЧ рдХреЗ рдХреБрдЫ рдЕрдкреНрд░рддреНрдпрд╛рд╢рд┐рдд рдкрд╣рд▓реБрдУрдВ рдХреЛ рд╕рдордЭрд╛рдпрд╛ рдЬрд╛рдПрдЧрд╛ред рдпрджрд┐ рдЖрдк рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдирд╣реАрдВ рдЬрд╛рдирддреЗ рд╣реИрдВ, рддреЛ рдпрд╣ рд▓реЗрдЦ рдЖрдкрдХреЛ рдЬрдВрдЧ рдХреЛ рд╕реАрдЦрдиреЗ рдореЗрдВ рдорджрдж рдирд╣реАрдВ рдХрд░реЗрдЧрд╛, рдФрд░ рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ, рдЖрдк рд╕рдмрд╕реЗ рдЕрдзрд┐рдХ рд╕рдВрднрд╛рд╡рдирд╛ рд╣реИ рдХрд┐ рджрд╣рдирд╢реАрд▓ рдкрд╛рд░реНрд╕рд░ рдХреЛ рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рд╕рдордЭ рдирд╣реАрдВ рдкрд╛рдПрдВрдЧреЗред рдпрджрд┐ рдЖрдк рд░рд╕реНрдЯ рд╕реАрдЦрдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рддреЛ рдореИрдВ "рд░рд╕реНрдЯ рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рд▓реИрдВрдЧреНрд╡реЗрдЬ" рдкреБрд╕реНрддрдХ рдХреА рд╕рд┐рдлрд╛рд░рд┐рд╢ рдХрд░рддрд╛ рд╣реВрдВред
рд╢реБрд░реБрдЖрдд рдХреЗ рджреГрд╖реНрдЯрд┐рдХреЛрдг рд╕реЗ
рдкреНрд░рддреНрдпреЗрдХ рдкреНрд░реЛрдЧреНрд░рд╛рдорд░ рдХреЗ рдЬреАрд╡рди рдореЗрдВ, рдПрдХ рд╕рдордп рдЖрддрд╛ рд╣реИ рдЬрдм рдЙрд╕реЗ рдПрдХ рдкрд╛рд░реНрд╕рд░ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред
рдПрдХ рдиреМрд╕рд┐рдЦрд┐рдпрд╛ рдкреНрд░реЛрдЧреНрд░рд╛рдорд░ рдкреВрдЫреЗрдЧрд╛: "рдПрдХ рдкрд╛рд░реНрд╕рд░ рдХреНрдпрд╛ рд╣реИ?"
рдордзреНрдп-рд╕реНрддрд░реАрдп рдкреНрд░реЛрдЧреНрд░рд╛рдорд░ рдХрд╣реЗрдЧрд╛: "рдпрд╣ рд╕рд░рд▓ рд╣реИ, рдореИрдВ рдПрдХ рдирд┐рдпрдорд┐рдд рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рд▓рд┐рдЦреВрдВрдЧрд╛ред"
рдорд╛рд╕реНрдЯрд░ рдкреНрд░реЛрдЧреНрд░рд╛рдорд░ рдХрд╣реЗрдЧрд╛: "рджреВрд░ рд╣реЛ рдЬрд╛рдУ, рдореБрдЭреЗ рдкрддрд╛ рд╣реИ рдХрд┐ 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