@@ -8,6 +8,12 @@
88
99import Foundation
1010
11+typealias Lines = [String]
12+typealias Element = [String]
13+let commentChars = CharacterSet.init(charactersIn: "#/")
14+let styleCharecters = CharacterSet.init(charactersIn: "_*")
15+
16+
1117enum BracketStyle {
1218 case square
1319 case round
@@ -61,11 +67,11 @@ default:
6167 if let surl = args.popFirst() {
6268 outputUrl = URL(fileURLWithPath: surl)
6369 }
64− case "-s":
70+ case "-b:s":
6571 style = .square
66− case "-r":
72+ case "-b:r":
6773 style = .round
68− case "-l":
74+ case "-b:l":
6975 style = .line
7076 default:
7177 return
@@ -81,7 +87,6 @@ enum ElementStyle: String {
8187 case italic = "italic"
8288 case boldItalic = "bold-italic"
8389}
84−let styleCharecters = CharacterSet.init(charactersIn: "_*")
8590extension String.SubSequence {
8691 var style: ElementStyle {
8792 let num = self.prefix(while: {styleCharecters.contains($0.unicodeScalars.first!)}).count
@@ -100,20 +105,55 @@ extension String.SubSequence {
100105 return self.trimmingCharacters(in: styleCharecters)
101106 }
102107}
103−func process(mth: String) -> String {
104− let whitespace = CharacterSet.whitespaces
108+
109+func process(element: Element) -> String {
110+ var out = ""
105111
112+ var inMatrix = false
113+ var first = false
106114 var seperated = false
107− var afterSeparator: [String.SubSequence] = []
115+ var afterSeparator: [Substring] = []
116+
117+ var small = false
118+
119+ let arrows = CharacterSet.init(charactersIn: "⟺⟷⟼⟻⟶⟹⟵⟸")
120+
121+ let nEl = element.map { (el) -> String in
122+ switch el {
123+ case let l where l.last == ">" && l.first == "<" && l.dropLast().dropFirst().filter({$0 == "="}).count > 0:
124+ small = true
125+ return "⟺"
126+ case let l where l.last == ">" && l.first == "<" && l.dropLast().dropFirst().filter({$0 == "-"}).count > 0:
127+ small = true
128+ return "⟷"
129+ case let l where l.last == ">" && l.first == "|" && l.dropLast().dropFirst().filter({$0 == "-"}).count > 0:
130+ small = true
131+ return "⟼"
132+ case let l where l.last == "|" && l.first == "<" && l.dropLast().dropFirst().filter({$0 == "-"}).count > 0:
133+ small = true
134+ return "⟻"
135+ case let l where l.last == ">" && l.dropLast().filter({$0 == "-"}).count > 0:
136+ small = true
137+ return "⟶"
138+ case let l where l.last == ">" && l.dropLast().filter({$0 == "="}).count > 0:
139+ small = true
140+ return "⟹"
141+ case let l where l.first == "<" && l.dropFirst().filter({$0 == "-"}).count > 0:
142+ small = true
143+ return "⟵"
144+ case let l where l.first == "<" && l.dropFirst().filter({$0 == "="}).count > 0:
145+ small = true
146+ return "⟸"
147+ default:
148+ return el
149+ }
150+ }
108151
109− var out = "<math>"
110− let lines = mth.split(separator: "\n", omittingEmptySubsequences: false)
111− .map {$0.trimmingCharacters(in: .whitespaces)}
112− var insideMatrix = false
113− func pureProcess(line: Substring) {
152+
153+ func process(line: Substring) {
114154 out.append("<mtr>")
115155 for element in line.split(
116− whereSeparator: {c in whitespace.contains(c.unicodeScalars.first!)}) {
156+ whereSeparator: {c in CharacterSet.whitespaces.contains(c.unicodeScalars.first!)}) {
117157 switch element {
118158 case "_":
119159 out.append("<mtd><mspace height=\"0.8em\"/></mtd>")
@@ -124,55 +164,99 @@ func process(mth: String) -> String {
124164 }
125165 out.append("</mtr>")
126166 }
127− func checkInsideMatrix() {
128− if insideMatrix {
129− if seperated {
130− out.append("</mtable><mo>|</mo><mtable>")
131− for line in afterSeparator {
132− pureProcess(line: line)
133− }
134− }
135− out.append("</mtable><mo>\(style.closing)</mo></mrow>")
136− insideMatrix = false
137− seperated = false
138− afterSeparator = []
167+ func process(comment: String) {
168+ if comment.hasPrefix("#") {
169+ out.append("<!-- \(comment.trimmingCharacters(in: commentChars).trimmingCharacters(in: .whitespaces)) -->")
139170 }
140171 }
141− func process(line: String.SubSequence) {
142− switch line {
143− case "":
144− checkInsideMatrix()
145− default:
146− if !insideMatrix {
147− out.append("<mrow><mo>\(style.opening)</mo><mtable>")
148− insideMatrix = true
149− }
150− pureProcess(line: line)
151− }
152−
153− }
154− for line in lines {
155− if !insideMatrix {
156− if lines.first?.contains("|") == true {
172+
173+ for line in nEl {
174+ if inMatrix {
175+ if first && line.contains("|") {
157176 seperated = true
158177 }
159− }
160− if line == "" {
161− process(line: Substring(line))
162− } else if seperated {
163− let split = line.split(separator: "|", maxSplits: 1, omittingEmptySubsequences: false)
164− if split.count != 2 {
165− print("Inconsistent syntax")
166− exit(0)
178+ switch line {
179+ case "]":
180+ if seperated {
181+ out.append("</mtable><mo stretchy=\"true\">|</mo><mtable>")
182+ for line in afterSeparator {
183+ process(line: line)
184+ }
185+ }
186+ out.append("</mtable><mo stretchy=\"true\">\(style.closing)</mo></mrow></mtd></mtr>")
187+ inMatrix = false
188+ seperated = false
189+ afterSeparator = []
190+ default:
191+ if seperated {
192+ let split = line.split(separator: "|", maxSplits: 1, omittingEmptySubsequences: false)
193+ if split.count != 2 {
194+ print("Inconsistent syntax. The `|` seperator isn't consistent within a matrix.")
195+ exit(0)
196+ }
197+ process(line: split[0])
198+ afterSeparator.append(split[1])
199+ } else {
200+ process(line: Substring(line))
201+ }
167202 }
168− process(line: split[0])
169− afterSeparator.append(split[1])
170203 } else {
171− process(line: Substring(line))
204+ switch line {
205+ case let l where l.hasPrefix("//"):
206+ break
207+ case let l where l.hasPrefix("#"):
208+ out.append("</mtable></math>\n\n")
209+ process(comment: l)
210+ out.append("\n\n<math><mtable>")
211+ break // TODO: Figure out what to do
212+ case "[":
213+ if !inMatrix {
214+ out.append("<mtr><mtd><mrow><mo stretchy=\"true\">\(style.opening)</mo><mtable>")
215+ inMatrix = true
216+ first = true
217+ continue
218+ } else {
219+ print("Inconsistent syntax. Opening a matrix from within a matrix.")
220+ exit(0)
221+ }
222+ case "":
223+ if !first {
224+ out.append("</mtable><mtable>")
225+ }
226+ first = true
227+ continue
228+ case let l where arrows.contains(l.first!.unicodeScalars.first!):
229+ out.append("<mtr><mtd><mo>\(line)</mo></mtd></mtr>")
230+ default:
231+ out.append("<mtr><mtd>\(small ? "<mstyle scriptlevel=\"1\">" : "")<mo>\(line)</mo>\(small ? "</mstyle>" : "")</mtd></mtr>")
232+ }
172233 }
234+ first = false
235+ }
236+ return out
237+}
238+
239+func process(mth: String) -> String {
240+ let elements = mth
241+ .split(separator: "\n", omittingEmptySubsequences: false)
242+ .map({$0.trimmingCharacters(in: .whitespaces)})
243+ .map({ l in
244+ var i = l.startIndex
245+ for u in 0..<max(0, l.count - 1) {
246+ if l[i] == "/" && l[l.index(after: i)] == "/" {
247+ return String(l.dropLast(l.count - u))
248+ }
249+ i = l.index(after: i)
250+ }
251+ return l
252+ })
253+ .split(separator: "")
254+ var out = "<math><mtable>"
255+ for el in elements {
256+ out.append(process(element: Array(el)))
257+ out.append("</mtable><mtable>")
173258 }
174− checkInsideMatrix()
175− out.append("</math>")
259+ out.append("</mtable></math>")
176260 return out
177261}
178262