Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Смышляев Дмитрий #231

Open
wants to merge 63 commits into
base: master
Choose a base branch
from

Conversation

vafle228
Copy link

vafle228 and others added 23 commits November 17, 2024 15:34
- Также переименовал токенайзер
Засетапил архитектуру
- Сделал токенайзер
- Поправил ошибки в сканерах
- Добавил тесты для сканера спец символов
- Довез тесы для текстового сканера
- Поправил тесты для специального сканера
- Токены теперь не содержат строчку, но знают как ее найти
- Поправил сканеры, с учетом новой логики
- И поправил тесты до кучи
- Добавил сканер для чисел
- Добавил тесты для сканера чисел
- Отрефакторил другие сканеры
- Теперь токен получает сорс текст, чтобы строить велью
- Также появился дебаг ТуСтринг метод
- Довез тесты для токенизатора
- Добавил токенизатору новый сканер
- Добавил ентер между актом и ассертом )
Готовый токенайзер
- Написал тулзы для упрощения работы с матчами
- Накатил на это все тесты
- Добавил правило для примитивного италика
- Докинул ему добавление нескольких токен-типов
- Добавил повторение токен-типов
- Переименовал токен TEXT на токен WORD
- Теперь не лист тайпов, а настоящий паттерн
- Добавил звезду Клини
- Добавил первое совпадение
- Добавил метчу возможность билдить обратно лист

namespace Markdown.Generator;

public class HTMLGenerator

This comment was marked as resolved.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Согласен: сделаю, как начну генераторы пилить )

@@ -0,0 +1,20 @@
namespace Markdown.Tokenizer.Tokens;

public class Token(TokenType tokenType, int begin, int length, string sourceText)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Это DataClass, в нем нет логики (совсем чуть-чуть :D), только данные.
Давай тогда заиспользуем Record?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

И для чего сюда передавать сразу весь текст sourceText?
Не говорю, что это плохо, просто мне не совсем понятно.
И еще на подумать, в aspnet есть такой концепт - Do not retrieve more data than is necessary. Он говорит про минимизацию запросов при http взаимодействии, но в т.ч. красиво перекладывается на код и доменные модели.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Рекод сделаю :)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sourceText сюда передается с мыслью, чтобы токен мог достать свое значение из текста, в котором он существует. Соглашусь, что может выглядеть как переизбыток данных, но пока я еще не дописал полностью логику генератора хтмл, пусть он полежит тут (хотя бы для дебаг целей)

public int Length { get; } = length;
public TokenType TokenType { get; } = tokenType;

public string GetValue()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Мб свойством? Тут логики не особо много)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Будет свойство, согл


public override string ToString()
{
return $"Token {TokenType} | Value \"{GetValue()}\"";
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: Лучше не переопределять .ToString без лишней потребности. Не совсем очевидное поведение. В плане, без углубления в код нельзя понять, что .ToString делает именно это (я бы первым делом подумал, что он возвращает value, это стандартное поведение таких методов)

p.s. а если хочешь оставить что-то подобное для дебага, то можно заюзать Externsion метод по типу .ToDebugString

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Да да, знаю, что переопределять ту стринг это харам. Но это осмысленный харам, так как я хотел, чтобы мне дебагер писал, что лежит в листе, когда я по шагам гуляю. А если делать как предложил ты, то среда не подтянет этот метод, когда я буду в дебаге смотреть код

UNDERSCORE,
SPACE,
NEW_LINE,
NUMBER,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А чем NUMBER отличается от TEXT с точки зрения обработки?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

И похожий вопрос на засыпку: для чего хочешь использовать SPACE?)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NUMBER и TEXT отличаются тем, что число с _ воспринимается как число, а текст - как тег. SPACE же нужен, чтобы хендлить вариант, когда у меня будет разрыв тегов между слов wor_d hel_lo. Если не определить пробел, то сканер вернет мне последовательность TEXT _ TEXT _ TEXT которую легко спутать с тегом

{
public static void Main(string[] args)
{
var markdown = "This _is_ a __sample__ markdown _file_.\n";
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Советы категории Б: можешь вынести эту строчку в константу, чтобы потом, при добавлении новых примеров, можно было легко между ними переключаться :)

        const string firstExample = "This _is_ a __sample__ markdown _file_.\n";
        const string secondExample = "#This is another __sample__ markdown _file_";
        var markdown = firstExample;

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Окей, сделаю :)

var token = scanners
.Select(sc => sc.Scan(markdown, begin))
.First(token => token is not null);
begin += token!.Length; tokenList.Add(token);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Перенеси на новую строчку плиз, глазкам больно ахаха

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ахахахаха, ладно перенесу

if (tokenType is null) return null;

var notNullType = (TokenType)tokenType;
return new Token(notNullType, begin, 1, markdown);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А как будешь разбираться с bold? Это, если что, __. Тут уже два символа. К GetTokenType тот же вопрос)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Как я описывал выше: токены это язык, который мой автомат собирается распознавать. Поэтому болд для меня это +- такая вещь __ TEXT __

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Не. я к тому, что сейчас все заточено под 1 символ (абсолютно все). bold в 2 символа может добавить проблем, если сразу не подумать над ним.
Если в следующих коммитах уже есть решение, то гуд)

}

public static bool CanScan(char symbol)
=> GetTokenType(symbol) != null;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А если у нас будет текст вида Всем_привет!?
Потом будешь разбирать в автомате? Кажется, все сломается. Ну, у меня ощущение такое.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Оно не должно сломаться, так как автомат не найдет закрывающей _ и просто проскочит на следующий символ


private static TokenType? GetTokenType(char symbol) => symbol switch
{
' ' => TokenType.SPACE,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: мб словарем сделать? Удобнее будет :)
https://marcduerst.com/2019/10/30/mapping-with-dictionary-instead-switch/

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Словарь так словарь: ща поправлю :)

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Не, NIT - это буквально "докопаться". Такие треды можешь не исправлять, если не хочешь/считаешь свое решение лучше. Я тут просто варианты накидываю)

- Немного пошаманил с неймингом
- Чутка переделал ноду
- Отказался от метч объектов
- Поделил ноды на текст ноду и тег ноду
- Добавил разных экстеншенов, чтобы код был более читабельным
- Теперь италик тег умеет определять, когда он метчит тег в слове или вне его
- Тесты на пробел перед закрывающим
- Тесты на пробел после открывающего
@@ -0,0 +1,7 @@
namespace Markdown.Parser.Nodes;

public class Node(NodeType nodeType, int consumed)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Опять Data class)

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Не понимаю, за что отвечает int Consumed. Это не Length случайно?


namespace Markdown.Parser.Nodes;

public class TextNode(int start, int consumed, List<Token> source) : Node(NodeType.TEXT, consumed)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А вот тут точно нарушение SRP и всего вместе взятого (или я не понимаю). Почему сюда весь source закидывается?.. Почему не только нужные токены?

{
public Node? Match(List<Token> tokens, int begin = 0)
{
throw new NotImplementedException();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А хде...

}

private static TagNode BuildNode(TextNode textNode)
=> new(NodeType.ITALIC, textNode, textNode.Consumed + 2);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Я бы не завязывался на + 2. В md есть разные форматы, поэтому лучше вынести в константу

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

И как будто есть смысл вынести такой Factory метод в сами ноды, как думаешь?

public Node? Match(List<Token> tokens, int begin = 0)
{
if (pattern.Count == 0) return null;
if (tokens.Count - begin < pattern.Count) return null;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: почему думаешь, что лучше вернуть null, чем выкинуть Exception?

{
var node = pattern.Match(tokens, begin);
if (node is null) return nodes;
begin += node.Consumed; nodes.Add(node);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

перенос

public static class ListExtensions
{
public static string ToText(this List<Token> tokens)
=> tokens.Aggregate(new StringBuilder(), (sb, t) => sb.Append(t.Value)).ToString();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.Join?

}

private static bool IsText(Token token)
=> token.TokenType is TokenType.WORD or TokenType.SPACE;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Number? New Line?

vafle228 and others added 29 commits December 2, 2024 17:15
- Италик тег стал еще более устойчив
- Код похорошел, новые плюхи появились, плохие ушли
- Более семантично теперь
- Более стойкий болд тег
- Более строгие тесты
- Добавил новый токен
- Добавил новый тип нод
- Поправил тестики
- Добавил тег параграфа
- Накидал тестов для тега
- Поправил тег инворд италик тег
- Поправил инворд болд тег
- Начал рефакторинг тегов
- Вернулся к кондитионал руле
- Честно прописал условия для границ тегов подчерка
- Некоторые тесты перекочевали в InWord аналоги
- Решил переименовать булевы рулы в специальный рулы (чем они и являются)
- Теперь все еквивалент матчи строги к порядку
- Теперь ноды не хранят в себе лист токенов
- Пошел править все ноды с этим обновлением
- Переделал италик тег на новые ноды
- Поменял токены для уменьшения их ответственности
- Добавил тесты для заголовка
- Переименовал метчи в ноды в некоторых тестках
- Добавил новый тип токена
- Поправил тесты и сканеры
- Поправил рулы параграфа
- Написал сам тег + тесты
- Ескейп тег теперь настоящий тег
- Ескейп тег принимает токены, которые он будет ескейпить
- Параграф теперь умеет ескейпить все андерскоры
- Добавил тестики для бади рулы
- Написал саму бади рулу
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants