+// Copyright (C) 2024 Rubén Beltrán del Río
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see https://map.tranquil.systems.
import CoreGraphics
import Foundation
+struct MapParser {
+ static func parse(content: String) -> ParsedMap {
+
+ let parsers = [
+ AnyMapParserStrategy(NoteParserStrategy()),
+ AnyMapParserStrategy(VertexParserStrategy()),
+ AnyMapParserStrategy(EdgeParserStrategy()),
+ AnyMapParserStrategy(BlockerParserStrategy()),
+ AnyMapParserStrategy(OpportunityParserStrategy()),
+ AnyMapParserStrategy(StageParserStrategy()),
+ AnyMapParserStrategy(GroupParserStrategy()),
+ ]
+ let builder = MapBuilder()
+
+ let lines = content.split(whereSeparator: \.isNewline)
+
+ for (index, line) in lines.enumerated() {
+ for parser in parsers {
+ if parser.canHandle(line: String(line)) {
+ let (type, object) = parser.handle(
+ index: index, line: String(line), vertices: builder.vertices)
+ builder.addObjectToMap(type: type, object: object)
+ break
+ }
+ }
+ }
+
+ return builder.build()
+ }
+}
+
// MARK: - Types
struct MapParsingPatterns {
static let vertex = try! NSRegularExpression(
pattern:
- "([^\\(\\[\\]]*?)[\\s]*\\([\\s]*([0-9]+.?[0-9]*)[\\s]*,[\\s]*([0-9]+.?[0-9]*)[\\s]*\\)[\\s]*(?:\\[(.*?)\\])?",
- options: .caseInsensitive)
+ "^([^\\(\\[\\]]*?)[\\s]*\\([\\s]*([0-9]+.?[0-9]*)[\\s]*,[\\s]*([0-9]+.?[0-9]*)[\\s]*\\)[\\s]*(?:\\[(.*?)\\])?[\\s]*$",
+ options: [.caseInsensitive, .anchorsMatchLines])
static let edge = try! NSRegularExpression(
- pattern: "(.+?)[\\s]*-([->])[\\s]*(.+)", options: .caseInsensitive)
+ pattern: "^(.+?)[\\s]*-([->])[\\s]*(.+)", options: [.caseInsensitive, .anchorsMatchLines])
static let blocker = try! NSRegularExpression(
- pattern: "\\[(Blocker)\\][\\s]*(.+)", options: .caseInsensitive)
+ pattern: "^\\[(Blocker)\\][\\s]*(.+)", options: [.caseInsensitive, .anchorsMatchLines])
static let opportunity = try! NSRegularExpression(
- pattern: "\\[(Evolution)\\][\\s]*(.+)[\\s]+([-+])[\\s]*([0-9]+.?[0-9]*)",
- options: .caseInsensitive)
+ pattern: "^\\[(Evolution)\\][\\s]*(.+)[\\s]+([-+])[\\s]*([0-9]+.?[0-9]*)",
+ options: [.caseInsensitive, .anchorsMatchLines])
static let note = try! NSRegularExpression(
- pattern: "\\[(Note)\\][\\s]*\\([\\s]*([0-9]+.?[0-9]*)[\\s]*,[\\s]*([0-9]+.?[0-9]*)[\\s]*\\)[\\s]*(.*)",
- options: .caseInsensitive)
+ pattern:
+ "^\\[(Note)\\][\\s]*\\([\\s]*([0-9]+.?[0-9]*)[\\s]*,[\\s]*([0-9]+.?[0-9]*)[\\s]*\\)[\\s]*(.*)",
+ options: [.caseInsensitive, .anchorsMatchLines])
static let stage = try! NSRegularExpression(
- pattern: "\\[(I{1,3})\\][\\s]*([0-9]+.?[0-9]*)", options: .caseInsensitive)
+ pattern: "^\\[(I{1,3})\\][\\s]*([0-9]+.?[0-9]*)",
+ options: [.caseInsensitive, .anchorsMatchLines])
+ static let group = try! NSRegularExpression(
+ pattern: "^\\[(Group)\\][\\s]*(.+)", options: [.caseInsensitive, .anchorsMatchLines])
}
struct ParsedMap {
let opportunities: [Opportunity]
let notes: [Note]
let stages: [CGFloat]
+ let groups: [[Vertex]]
static let empty: ParsedMap = ParsedMap(
- vertices: [], edges: [], blockers: [], opportunities: [], notes: [], stages: defaultDimensions)
+ vertices: [], edges: [], blockers: [], opportunities: [], notes: [], stages: defaultDimensions,
+ groups: [])
}
-struct Vertex {
+struct Vertex: Identifiable, Hashable {
let id: Int
let label: String
let position: CGPoint
private var opportunities: [Opportunity] = []
private var notes: [Note] = []
private var stages: [CGFloat] = defaultDimensions
+ private var groups: [[Vertex]] = []
func addObjectToMap(type: Any.Type, object: Any) {
if type == Vertex.self {
let opportunity = object as! Opportunity
opportunities.append(opportunity)
}
-
+
if type == Note.self {
let note = object as! Note
notes.append(note)
let stageDimensions = object as! StageDimensions
stages[stageDimensions.index] = stageDimensions.dimensions
}
+
+ if type == [Vertex].self {
+ let group = object as! [Vertex]
+ groups.append(group)
+ }
}
func build() -> ParsedMap {
let mappedVertices = vertices.map { label, vertex in return vertex }
return ParsedMap(
- vertices: mappedVertices, edges: edges, blockers: blockers, opportunities: opportunities, notes: notes,
- stages: stages)
+ vertices: mappedVertices, edges: edges, blockers: blockers, opportunities: opportunities,
+ notes: notes,
+ stages: stages, groups: groups)
}
}