Skip to content

Commit

Permalink
Parse entities in subscripts and superscripts
Browse files Browse the repository at this point in the history
  • Loading branch information
amake committed Oct 14, 2024
1 parent 9222b4d commit 2061ff3
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 18 deletions.
70 changes: 60 additions & 10 deletions lib/src/org/model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1861,40 +1861,90 @@ class OrgEntity extends OrgLeafNode {
}
}

class OrgSubscript extends OrgLeafNode {
OrgSubscript(this.leading, this.body);
class OrgSubscript extends OrgParentNode {
OrgSubscript(this.leading, this.body, this.trailing);

final String leading;
final String body;
final OrgContent body;
final String trailing;

@override
List<OrgNode> get children => [body];

@override
bool contains(Pattern pattern) =>
leading.contains(pattern) || body.contains(pattern);
leading.contains(pattern) ||
body.contains(pattern) ||
trailing.contains(pattern);

@override
String toString() => 'OrgSubscript';

@override
_toMarkupImpl(OrgSerializer buf) {
buf
..write(leading)
..write(body);
..visit(body)
..write(trailing);
}

@override
OrgSubscript fromChildren(List<OrgNode> children) =>
copyWith(body: children.single as OrgContent);

OrgSubscript copyWith({
String? leading,
OrgContent? body,
String? trailing,
}) =>
OrgSubscript(
leading ?? this.leading,
body ?? this.body,
trailing ?? this.trailing,
);
}

class OrgSuperscript extends OrgLeafNode {
OrgSuperscript(this.leading, this.body);
class OrgSuperscript extends OrgParentNode {
OrgSuperscript(this.leading, this.body, this.trailing);

final String leading;
final String body;
final OrgContent body;
final String trailing;

@override
List<OrgNode> get children => [body];

@override
bool contains(Pattern pattern) =>
leading.contains(pattern) || body.contains(pattern);
leading.contains(pattern) ||
body.contains(pattern) ||
trailing.contains(pattern);

@override
String toString() => 'OrgSuperscript';

@override
_toMarkupImpl(OrgSerializer buf) {
buf
..write(leading)
..write(body);
..visit(body)
..write(trailing);
}

@override
OrgSuperscript fromChildren(List<OrgNode> children) =>
copyWith(body: children.single as OrgContent);

OrgSuperscript copyWith({
String? leading,
OrgContent? body,
String? trailing,
}) =>
OrgSuperscript(
leading ?? this.leading,
body ?? this.body,
trailing ?? this.trailing,
);
}

class OrgLocalVariables extends OrgLeafNode {
Expand Down
37 changes: 31 additions & 6 deletions lib/src/org/parser.dart
Original file line number Diff line number Diff line change
Expand Up @@ -186,18 +186,43 @@ class OrgContentParserDefinition extends OrgContentGrammarDefinition {

@override
Parser subscript() => super.subscript().map((values) {
final leading = values[0] as String;
final body = values[1] as String;
return OrgSubscript(leading, body);
var leading = values[0] as String;
var trailing = '';
var body = values[1] as String;
if (body.startsWith('{') && body.endsWith('}')) {
leading += '{';
trailing += '}';
body = body.substring(1, body.length - 1);
}
final content = buildFrom(_subSuperscriptRichBody())
.castList<OrgNode>()
.end()
.parse(body)
.value;
return OrgSubscript(leading, OrgContent(content), trailing);
});

@override
Parser superscript() => super.superscript().map((values) {
final leading = values[0] as String;
final body = values[1] as String;
return OrgSuperscript(leading, body);
var leading = values[0] as String;
var trailing = '';
var body = values[1] as String;
if (body.startsWith('{') && body.endsWith('}')) {
leading += '{';
trailing += '}';
body = body.substring(1, body.length - 1);
}
final content = buildFrom(_subSuperscriptRichBody())
.castList<OrgNode>()
.end()
.parse(body)
.value;
return OrgSuperscript(leading, OrgContent(content), trailing);
});

/// Only used on this layer to parse subscript and superscript content
Parser _subSuperscriptRichBody() => (ref0(entity) | ref0(plainText)).star();

@override
Parser macroReference() => super
.macroReference()
Expand Down
7 changes: 7 additions & 0 deletions test/org/model/subscript_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ void main() {
final definition = OrgContentParserDefinition();
final parser =
seq2(letter(), definition.buildFrom(definition.subscript())).end();
test('with entity', () {
final result = parser.parse(r'a_\alpha');
final (_, OrgSubscript sup) = result.value;
expect(sup.contains('alpha'), isTrue);
expect(sup.contains(r'\alpha'), isFalse);
expect(sup.toMarkup(), r'_\alpha');
});
test('nested bracketed expression', () {
final result = parser.parse('a_{a1 {b2}}');
final (_, OrgSubscript sup) = result.value;
Expand Down
30 changes: 29 additions & 1 deletion test/org/parser/subscript_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,39 @@ void main() {
final definition = OrgContentParserDefinition();
final parser =
seq2(letter(), definition.buildFrom(definition.subscript())).end();
test('with entity', () {
final result = parser.parse(r'a_\alpha');
final (_, OrgSubscript sup) = result.value;
expect(sup.leading, '_');
final body = sup.body.children.single as OrgEntity;
expect(body.name, 'alpha');
expect(sup.trailing, '');
});
test('with text and entity', () {
final result = parser.parse(r'a_{1 + \alpha}');
final (_, OrgSubscript sup) = result.value;
expect(sup.leading, '_{');
final body1 = sup.body.children[0] as OrgPlainText;
expect(body1.content, '1 + ');
final body2 = sup.body.children[1] as OrgEntity;
expect(body2.name, 'alpha');
expect(sup.trailing, '}');
});
test('nested bracketed expression', () {
final result = parser.parse('a_{a1 {b2}}');
final (_, OrgSubscript sup) = result.value;
expect(sup.leading, '_{');
final body = sup.body.children.single as OrgPlainText;
expect(body.content, 'a1 {b2}');
expect(sup.trailing, '}');
});
test('nested sexp', () {
final result = parser.parse('a_(a1 (b2))');
final (_, OrgSubscript sup) = result.value;
expect(sup.leading, '_');
expect(sup.body, '{a1 {b2}}');
final body = sup.body.children.single as OrgPlainText;
expect(body.content, '(a1 (b2))');
expect(sup.trailing, '');
});
});
}
30 changes: 29 additions & 1 deletion test/org/parser/superscript_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,39 @@ void main() {
final definition = OrgContentParserDefinition();
final parser =
seq2(letter(), definition.buildFrom(definition.superscript())).end();
test('with entity', () {
final result = parser.parse(r'a^\alpha');
final (_, OrgSuperscript sup) = result.value;
expect(sup.leading, '^');
final body = sup.body.children.single as OrgEntity;
expect(body.name, 'alpha');
expect(sup.trailing, '');
});
test('with text and entity', () {
final result = parser.parse(r'a^{1 + \alpha}');
final (_, OrgSuperscript sup) = result.value;
expect(sup.leading, '^{');
final body1 = sup.body.children[0] as OrgPlainText;
expect(body1.content, '1 + ');
final body2 = sup.body.children[1] as OrgEntity;
expect(body2.name, 'alpha');
expect(sup.trailing, '}');
});
test('nested bracketed expression', () {
final result = parser.parse('a^{a1 {b2}}');
final (_, OrgSuperscript sup) = result.value;
expect(sup.leading, '^{');
final body = sup.body.children.single as OrgPlainText;
expect(body.content, 'a1 {b2}');
expect(sup.trailing, '}');
});
test('nested sexp', () {
final result = parser.parse('a^(a1 (b2))');
final (_, OrgSuperscript sup) = result.value;
expect(sup.leading, '^');
expect(sup.body, '{a1 {b2}}');
final body = sup.body.children.single as OrgPlainText;
expect(body.content, '(a1 (b2))');
expect(sup.trailing, '');
});
});
}

0 comments on commit 2061ff3

Please sign in to comment.