Skip to content

Commit cb07403

Browse files
committed
refactor AST conversion
1 parent 2a45e37 commit cb07403

File tree

2 files changed

+212
-200
lines changed

2 files changed

+212
-200
lines changed
Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2021-2022 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
//
10+
//===----------------------------------------------------------------------===//
11+
12+
import _MatchingEngine
13+
14+
extension AST {
15+
var dslTree: DSLTree {
16+
return DSLTree(
17+
root.dslTreeNode, options: globalOptions?.dslTreeOptions)
18+
}
19+
}
20+
21+
extension AST.GlobalMatchingOptionSequence {
22+
var dslTreeOptions: DSLTree.Options {
23+
// TODO: map options
24+
return .init()
25+
}
26+
}
27+
28+
extension AST.Node {
29+
/// Converts an AST node to a `convertedRegexLiteral` node.
30+
var dslTreeNode: DSLTree.Node {
31+
func wrap(_ node: DSLTree.Node) -> DSLTree.Node {
32+
switch node {
33+
case .convertedRegexLiteral:
34+
// FIXME: DSL can have one item concats
35+
// assertionFailure("Double wrapping?")
36+
return node
37+
default:
38+
break
39+
}
40+
// TODO: Should we do this for the
41+
// single-concatenation child too, or should?
42+
// we wrap _that_?
43+
return .convertedRegexLiteral(node, self)
44+
}
45+
46+
// Convert the top-level node without wrapping
47+
func convert() -> DSLTree.Node {
48+
switch self {
49+
case let .alternation(v):
50+
let children = v.children.map(\.dslTreeNode)
51+
return .alternation(children)
52+
53+
case let .concatenation(v):
54+
// Coalesce adjacent children who can produce a
55+
// string literal representation
56+
let astChildren = v.children
57+
func coalesce(
58+
_ idx: Array<AST>.Index
59+
) -> (Array<AST>.Index, String)? {
60+
var result = ""
61+
var idx = idx
62+
while idx < astChildren.endIndex {
63+
let atom: AST.Atom? = astChildren[idx].as()
64+
65+
// TODO: For printing, nice to coalesce
66+
// scalars literals too. We likely need a different
67+
// approach even before we have a better IR.
68+
guard let char = atom?.singleCharacter else {
69+
break
70+
}
71+
result.append(char)
72+
astChildren.formIndex(after: &idx)
73+
}
74+
return result.count <= 1 ? nil : (idx, result)
75+
}
76+
77+
// No need to nest single children concatenations
78+
if astChildren.count == 1 {
79+
return astChildren.first!.dslTreeNode
80+
}
81+
82+
// Check for a single child post-coalescing
83+
if let (idx, str) = coalesce(astChildren.startIndex),
84+
idx == astChildren.endIndex
85+
{
86+
return .quotedLiteral(str)
87+
}
88+
89+
// Coalesce adjacent string children
90+
var curIdx = astChildren.startIndex
91+
var children = Array<DSLTree.Node>()
92+
while curIdx < astChildren.endIndex {
93+
if let (nextIdx, str) = coalesce(curIdx) {
94+
// TODO: Track source info...
95+
children.append(.quotedLiteral(str))
96+
curIdx = nextIdx
97+
} else {
98+
children.append(astChildren[curIdx].dslTreeNode)
99+
children.formIndex(after: &curIdx)
100+
}
101+
}
102+
return .concatenation(children)
103+
104+
case let .group(v):
105+
let child = v.child.dslTreeNode
106+
return .group(v.kind.value, child)
107+
108+
case let .conditional(v):
109+
let trueBranch = v.trueBranch.dslTreeNode
110+
let falseBranch = v.falseBranch.dslTreeNode
111+
return .conditional(
112+
v.condition.kind, trueBranch, falseBranch)
113+
114+
case let .quantification(v):
115+
let child = v.child.dslTreeNode
116+
return .quantification(
117+
v.amount.value, v.kind.value, child)
118+
119+
case let .quote(v):
120+
return .quotedLiteral(v.literal)
121+
122+
case let .trivia(v):
123+
return .trivia(v.contents)
124+
125+
case let .atom(v):
126+
return .atom(v.dslTreeAtom)
127+
128+
case let .customCharacterClass(ccc):
129+
return .customCharacterClass(ccc.dslTreeClass)
130+
131+
case .empty(_):
132+
return .empty
133+
134+
case let .groupTransform(v, transform):
135+
let child = v.child.dslTreeNode
136+
return .groupTransform(
137+
v.kind.value, child, transform)
138+
139+
case let .absentFunction(a):
140+
// TODO: What should this map to?
141+
return .absentFunction(a)
142+
}
143+
}
144+
145+
let converted = convert()
146+
return wrap(converted)
147+
}
148+
}
149+
150+
extension AST.CustomCharacterClass {
151+
var dslTreeClass: DSLTree.CustomCharacterClass {
152+
// TODO: Not quite 1-1
153+
func convert(
154+
_ member: Member
155+
) -> DSLTree.CustomCharacterClass.Member {
156+
switch member {
157+
case let .custom(ccc):
158+
return .custom(ccc.dslTreeClass)
159+
160+
case let .range(r):
161+
return .range(
162+
r.lhs.dslTreeAtom, r.rhs.dslTreeAtom)
163+
164+
case let .atom(a):
165+
return .atom(a.dslTreeAtom)
166+
167+
case let .quote(q):
168+
return .quotedLiteral(q.literal)
169+
170+
case let .setOperation(lhs, op, rhs):
171+
let lhs = DSLTree.CustomCharacterClass(
172+
members: lhs.map(convert),
173+
isInverted: false)
174+
let rhs = DSLTree.CustomCharacterClass(
175+
members: rhs.map(convert),
176+
isInverted: false)
177+
178+
switch op.value {
179+
case .subtraction:
180+
return .subtraction(lhs, rhs)
181+
case .intersection:
182+
return .intersection(lhs, rhs)
183+
case .symmetricDifference:
184+
return .symmetricDifference(lhs, rhs)
185+
}
186+
case let .trivia(t):
187+
return .trivia(t.contents)
188+
}
189+
}
190+
191+
return .init(
192+
members: members.map(convert),
193+
isInverted: self.isInverted)
194+
}
195+
}
196+
197+
extension AST.Atom {
198+
var dslTreeAtom: DSLTree.Atom {
199+
if let kind = assertionKind {
200+
return .assertion(kind)
201+
}
202+
203+
switch self.kind {
204+
case let .char(c): return .char(c)
205+
case let .scalar(s): return .scalar(s)
206+
case .any: return .any
207+
case let .backreference(r): return .backreference(r)
208+
209+
default: return .unconverted(self)
210+
}
211+
}
212+
}

0 commit comments

Comments
 (0)