Использование парсер-комбинаторов на Sprache
Задача
Подходы к решению
1. Парсеры, написанные вручную
2. Регулярные выражения
3. Генераторы парсеров
3. Генераторы парсеров (ANTLR)
4. Парсер-комбинаторы
Sprache - C# Parser Framework
Parser
Primitive parsers
Parsers and combinators - Sequence
Parsers and combinators - Or
Parsers and combinators - Optional
Parsers and combinators - Many
Строим свои парсеры
Off-topic: Select, SelectMany, Where C#
Off-topic: Select, SelectMany, Where C#
Примеры задач
1. Парсинг из текста
1. Парсинг из текста
Demo 1 (парсинг из текста)
2. Шаблонизатор
Demo 2 (шаблонизатор)
3. WWW-Authenticate challenge
3. WWW-Authenticate challenge
Demo 3 (WWW-Authenticate challenge)
Автор библиотеки Nicholas Blumhardt Контрибьютор других известных библиотек
Парсеры, построенные на Sprache
181.27K
Category: programmingprogramming

Использование парсер-комбинаторов на Sprache для построения DSL

1. Использование парсер-комбинаторов на Sprache

Использование парсеркомбинаторов на Sprache
Евгений Романовский
Разработчик команды Диадок

2. Задача

«Восстановить» объект из строки
Шаблонизатор с подстановкой переменных

3. Подходы к решению

4. 1. Парсеры, написанные вручную

Подходят, когда решение очевидно (Split, IndexOf, Substring)
public class SecurityToken
{
public string UserId { get; set; }
public DateTime ValidTo { get; set; }
}
Нужно распарсить строку
"8cb9f238-e0e4-431c-86a6-9ac52b9cb6b9;2017-04-20T00:00:00Z"

5. 2. Регулярные выражения

Относительно простая грамматика в простых случаях
Трудно читать и поддерживать
Невозможно работать с вложенными данными
Не масштабируется на более сложные грамматики

6. 3. Генераторы парсеров

• Генерирует классы на целевом языке (Java, C#, …) во время
сборки проекта, которые способные разбирать грамматику
• Требует времени для изучения и интеграции
• Подходит для очень сложных вещей, где важна скорость разбора
• ANTLR (http://www.antlr.org)

7. 3. Генераторы парсеров (ANTLR)

grammar Speak;
/* Parser Rules */
chat
: line line EOF ;
line
: name SAYS word NEWLINE;
name
: WORD ;
word
: WORD ;
/* Lexer Rules */
fragment A
: ('A'|'a') ;
fragment S
: ('S'|'s') ;
fragment Y
: ('Y'|'y') ;
fragment LOWERCASE : [a-z] ;
fragment UPPERCASE : [A-Z] ;
SAYS
WORD
WHITESPACE
NEWLINE
: SAYS ;
: (LOWERCASE | UPPERCASE)+ ;
: (' '|'\t')+ -> skip ;
: ('\r'? '\n' | '\r')+ ;

8. 4. Парсер-комбинаторы

Мини-язык описания
Логика написана на том же языке, что и остальное приложение
(C#)
Техника пришла из функциональных языков

9. Sprache - C# Parser Framework

• Легко писать
• Легко поддерживать
• Хорошо сочетается с TDD
• Маленький размер библиотеки
https://github.com/sprache/Sprache

10. Parser

public delegate IResult<T> Parser<out T>(IInput input);
public interface IResult<out T>
{
success
T Value { get; }
bool WasSuccessful { get; }
IInput Remainder { get; }
}
in
A
failure

11. Primitive parsers

Parse.Char('<')
Parse.Digit
Parse.WhiteSpace
Parse.Numeric
Parse.AnyChar
Parse.LineEnd
Parse.LetterOrDigit

12. Parsers and combinators - Sequence

AB
success
success
in
in
A
failure
from letter in Parse.Letter
from digit in Parse.Digit
success
in
B
failure
failure

13. Parsers and combinators - Or

A or B
success
success
in
in
A
failure
success
in
B
failure
failure
from letter in Parse.Letter.Or(Parse.Digit)

14. Parsers and combinators - Optional

A?
success
success
in
in
A
failure
failure
from letter in Parse.Letter.Optional()

15. Parsers and combinators - Many

A*
success
success
in
in
A
failure
failure
from letters in Parse.Letter.Many()

16. Строим свои парсеры

Parser<string> identifier =
from leading in Parse.WhiteSpace.Many()
from first in Parse.Letter.Once()
from rest in Parse.LetterOrDigit.Many()
from trailing in Parse.WhiteSpace.Many()
O_O
select new string(first.Concat(rest).ToArray());
var id = identifier.Parse(" abc123
Assert.AreEqual("abc123", id);
");

17. Off-topic: Select, SelectMany, Where C#

public static IEnumerable<U> Select<T, U>(this
IEnumerable<T> source, Func<T, U> selector)
public static IEnumerable<U> SelectMany<T, U, V>(this
IEnumerable<U> parser, Func<T, Parser<U>> selector,
Func<T, U, V> projector)
public static IEnumerable<T> Where<T>(this IEnumerable<T>
source, Func<T, bool> predicate)

18. Off-topic: Select, SelectMany, Where C#

public static Parser<U> Select<T, U>(this Parser<T>
parser, Func<T, U> convert)
public static Parser<V> SelectMany<T, U, V>(this
Parser<T> parser, Func<T, Parser<U>> selector, Func<T, U,
V> projector)
public static Parser<T> Where<T>(this Parser<T> parser,
Func<T, bool> predicate)

19. Примеры задач

20. 1. Парсинг из текста

public class Person
public class Property
{
{
}
public Person(…)
public Property(…)
{
{
Type = type;
Name = name;
Properties = properties;
Value = value;
}
}
public string Type { get; }
public string Name { get; }
public IEnumerable<Property> Properties { get; }
public string Value { get; }
}

21. 1. Парсинг из текста

magician
[
name
age
]
‘Merlin’
100500

22. Demo 1 (парсинг из текста)

23. 2. Шаблонизатор

var props = new Dictionary<string, object>
{
{"Number", "MX-123"},
{"Date", new DateTime(2017, 04, 19)},
{"Caption", "Счет"}
};
string template = "{{Caption}} №{{Number}} от {{Date}}";
"Счет №MX-123 от 19.04.17"

24. Demo 2 (шаблонизатор)

25. 3. WWW-Authenticate challenge

HTTP 401 Unauthorized
# Basic challenge
WWW-Authenticate: Basic realm="FooCorp"
# OAuth 2.0 challenge after sending an expired token
WWW-Authenticate: Bearer realm="FooCorp", error=invalid_token,
error_description="The access token has expired"

26. 3. WWW-Authenticate challenge

# from RFC-2617 (HTTP Basic and Digest authentication)
challenge
auth-scheme
auth-param
= auth-scheme 1*SP 1#auth-param
= token
= token "=" ( token | quoted-string )
# from RFC2616 (HTTP/1.1)
token
separators
quoted-string
qdtext
quoted-pair
=
=
|
|
|
=
=
=
1*<any CHAR except CTLs or separators>
"(" | ")" | "<" | ">" | "@"
"," | ";" | ":" | "\" | <">
"/" | "[" | "]" | "?" | "="
"{" | "}" | SP | HT
( <"> *(qdtext | quoted-pair ) <"> )
<any TEXT except <">>
"\" CHAR

27. Demo 3 (WWW-Authenticate challenge)

28. Автор библиотеки Nicholas Blumhardt Контрибьютор других известных библиотек

• Serilog
• Stateless
• Autofac
• …
Автор библиотеки
Nicholas Blumhardt
Контрибьютор других
известных библиотек

29. Парсеры, построенные на Sprache

• The template parser in
Octostache
• The XAML binding expression
Парсеры,
построенные на
Sprache
parser in OmniXaml
• The query parser in Seq
• The connection string parser in
EasyNetQ
• Sprache appears in the credits
for JetBrains ReSharper

30.

Вопросы?
http://bit.ly/dotnet_feedback
Евгений Романовский
[email protected]
kontur.ru
English     Русский Rules