Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
2ba94fb
При обращении к незарегистрированной вершине, теперь происходит её р…
Mar 23, 2026
d106e30
Добавил проверку на то, что RuleDef известен как DSL тип, на то, что …
Mar 23, 2026
6587b00
Теперь мы пишем правила, называя элементы в них, как в Java Parser, и…
Mar 23, 2026
aea3982
Добавлен простой тест DSL + код => отформатированный код, более сложн…
Mar 23, 2026
14ff3a5
Поправил, чтобы теперь с одним именем можно было писать несколько раз…
Mar 31, 2026
74c8b12
del old func require
Mar 31, 2026
303069a
На основе последней правки про разные типы правил с одним названием, …
Mar 31, 2026
fdd0b00
spec не бывает null, readProperty либо кидает ошибку, либо возвращает…
Mar 31, 2026
7a287c4
переменная property не бывает null, функция property либо кидает ошиб…
Mar 31, 2026
6732552
Добавил полноценное правило на форматирование, пока что не использует…
Mar 31, 2026
928ea6f
Добавил тесты из документации, <node*> и <node?> пока что не поддержи…
Apr 1, 2026
2b775ae
Вышла новая версия gradle
Apr 15, 2026
3dece05
Ввожу концепцию: если для вершины выбранно DSL правило и построены bi…
Apr 15, 2026
05c58d3
Реализация этой концепции
Apr 15, 2026
04d3824
Поправил тесты, теперь там нет хардкода, форматируется по общим правилам
Apr 15, 2026
ff0dc06
Добавил много тестов на форматирование от CompilationUnit до листьев AST
Apr 15, 2026
a008f2f
Обновил версию javaparser, до того, который поддерживает 25 java
May 1, 2026
e7f7875
если для <Statement> правила есть, но, например, конкретный whileStmt…
May 1, 2026
5520308
Добавил вывод для вершин без правил через PrettyPriner Java Parser + …
May 1, 2026
d5abed8
теперь тест в while, которого нет в правилах успешно проходит, код не…
May 1, 2026
95822a9
раньще был хардкод, в нём был прописан пробел при выводе
May 1, 2026
6c145e2
50 тестов на парсинг конструкций, которых нет в правилах
May 1, 2026
19300c6
Добавил тесты на проверку новвоведений (много конструкций, на которые…
May 1, 2026
812fc36
Удалил синтаксис для sql подобного типа правил, который уже не исполь…
May 4, 2026
cc162a6
Добавил пользовательскую инструкцию на то, как писать правила, когда …
May 6, 2026
370e583
Добавил возможность вынести в placeholder компоненты, которые не явля…
May 6, 2026
74432fc
Написал тесты на те ситуации, когда в правилах участвуют компоненты, …
May 6, 2026
5a04a5d
Добавил в гайд часть про то, как писать правила на не Node
May 8, 2026
c8fef30
Поправил опечатку
May 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
400 changes: 400 additions & 0 deletions HowToWriteRules.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ dependencies {
antlr("org.antlr:antlr4:4.13.2")
implementation("org.antlr:antlr4-runtime:4.13.2")

implementation("com.github.javaparser:javaparser-core:3.27.1")
implementation("com.github.javaparser:javaparser-core:3.28.0")

testRuntimeOnly("org.junit.platform:junit-platform-launcher")
testImplementation(platform("org.junit:junit-bom:5.10.0"))
Expand Down
4 changes: 1 addition & 3 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.0-bin.zip
networkTimeout=10000
validateDistributionUrl=true
distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.0-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
62 changes: 0 additions & 62 deletions src/main/antlr/SqlLikeRequestLexer.g4

This file was deleted.

97 changes: 0 additions & 97 deletions src/main/antlr/SqlLikeRequestParser.g4

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

nit: мне казалось, что это было удалено N PR-ов назад

This file was deleted.

10 changes: 10 additions & 0 deletions src/main/java/org/example/ebnfFormatter/match/AppliedRule.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.example.ebnfFormatter.match;

import org.example.ebnfFormatter.model.RuleDef;

public record AppliedRule(
String logicalName,
RuleDef rule,
Object sourceValue,
Bindings bindings
) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.example.ebnfFormatter.match;

public record AppliedRuleValue(AppliedRule appliedRule) implements BoundValue {
@Override
public Object legacyValue() {
return appliedRule.sourceValue();
}
}
123 changes: 111 additions & 12 deletions src/main/java/org/example/ebnfFormatter/match/Bindings.java
Original file line number Diff line number Diff line change
@@ -1,59 +1,158 @@
package org.example.ebnfFormatter.match;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

public final class Bindings {

private final Map<String, Object> bindingsByName = new LinkedHashMap<>();
private final Map<String, List<BoundValue>> bindingsByName = new LinkedHashMap<>();

public boolean bind(String name, Object value) {
return bind(name, new RawValue(value));
}

public boolean bind(String name, BoundValue value) {
if (!bindingsByName.containsKey(name)) {
bindingsByName.put(name, value);
bindingsByName.put(name, new ArrayList<>(List.of(value)));
return true;
}
return Objects.equals(bindingsByName.get(name), value);

List<BoundValue> existing = bindingsByName.get(name);
return existing.size() == 1 && Objects.equals(existing.getFirst(), value);
}

public boolean bindAll(String name, List<BoundValue> values) {
if (!bindingsByName.containsKey(name)) {
bindingsByName.put(name, new ArrayList<>(values));
return true;
}

return Objects.equals(bindingsByName.get(name), values);
}

public void append(String name, BoundValue value) {
bindingsByName.computeIfAbsent(name, ignored -> new ArrayList<>()).add(value);
}

public void appendAll(Bindings other) {
for (Map.Entry<String, List<BoundValue>> entry : other.bindingsByName.entrySet()) {
bindingsByName
.computeIfAbsent(entry.getKey(), ignored -> new ArrayList<>())
.addAll(entry.getValue());
}
}

public Bindings copy() {
Bindings copy = new Bindings();
copy.bindingsByName.putAll(this.bindingsByName);
for (Map.Entry<String, List<BoundValue>> entry : bindingsByName.entrySet()) {
copy.bindingsByName.put(entry.getKey(), new ArrayList<>(entry.getValue()));
}
return copy;
}

public void replaceWith(Bindings other) {
bindingsByName.clear();
bindingsByName.putAll(other.bindingsByName);
for (Map.Entry<String, List<BoundValue>> entry : other.bindingsByName.entrySet()) {
bindingsByName.put(entry.getKey(), new ArrayList<>(entry.getValue()));
}
}

public Object getRequired(String name) {
if (!bindingsByName.containsKey(name)) {
List<BoundValue> values = findValuesInternal(name);
if (values == null) {
throw new IllegalArgumentException("No binding for name: " + name);
}
return bindingsByName.get(name);
return unwrapForLegacyUse(values);
}

public Object find(String name) {
return bindingsByName.get(name);
List<BoundValue> values = findValuesInternal(name);
if (values == null || values.isEmpty()) {
return null;
}
return unwrapForLegacyUse(values);
}

public List<BoundValue> getRequiredValues(String name) {
List<BoundValue> values = findValuesInternal(name);
if (values == null) {
throw new IllegalArgumentException("No binding for name: " + name);
}
return List.copyOf(values);
}

public List<BoundValue> findValues(String name) {
List<BoundValue> values = findValuesInternal(name);
if (values == null) {
return List.of();
}
return List.copyOf(values);
}

public boolean hasBinding(String name) {
return bindingsByName.containsKey(name);
return findValuesInternal(name) != null;
}

public Set<String> getBindingNames() {
return Collections.unmodifiableSet(bindingsByName.keySet());
}

public Map<String, Object> asUnmodifiableMap() {
return Collections.unmodifiableMap(bindingsByName);
public Map<String, List<BoundValue>> asUnmodifiableMap() {
Map<String, List<BoundValue>> copy = new LinkedHashMap<>();
for (Map.Entry<String, List<BoundValue>> entry : bindingsByName.entrySet()) {
copy.put(entry.getKey(), List.copyOf(entry.getValue()));
}
return Collections.unmodifiableMap(copy);
}

@Override
public String toString() {
return bindingsByName.toString();
}
}

private List<BoundValue> findValuesInternal(String name) {
List<BoundValue> exact = bindingsByName.get(name);
if (exact != null) {
return exact;
}

String normalized = stripQuantifierSuffix(name);
if (normalized.equals(name)) {
return null;
}
return bindingsByName.get(normalized);
}

private String stripQuantifierSuffix(String name) {
if (name == null || name.isEmpty()) {
return name;
}

char last = name.charAt(name.length() - 1);
return switch (last) {
case '?', '*', '+' -> name.substring(0, name.length() - 1);
default -> name;
};
}

private Object unwrapForLegacyUse(List<BoundValue> values) {
if (values.isEmpty()) {
return null;
}

if (values.size() == 1) {
return values.getFirst().legacyValue();
}

List<Object> legacyValues = new ArrayList<>(values.size());
for (BoundValue value : values) {
legacyValues.add(value.legacyValue());
}
return legacyValues;
}
}
5 changes: 5 additions & 0 deletions src/main/java/org/example/ebnfFormatter/match/BoundValue.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.example.ebnfFormatter.match;

public sealed interface BoundValue permits RawValue, AppliedRuleValue {
Object legacyValue();
}
Loading
Loading