Refactor model

This commit is contained in:
Guille Gonzalez
2026-01-01 12:41:56 +01:00
parent fbfc1d0ecf
commit e66eeb4564
19 changed files with 1845 additions and 12 deletions

View File

@@ -0,0 +1,27 @@
import Foundation
extension Math {
final class Accent: Atom {
var innerList: AtomList?
override var finalized: Math.Atom {
let finalized = super.finalized
if let accent = finalized as? Accent {
accent.innerList = accent.innerList?.finalized
}
return finalized
}
init(_ accent: Accent) {
self.innerList = accent.innerList.map { AtomList($0) }
super.init(accent)
}
init(value: String = "", innerList: AtomList? = nil) {
self.innerList = innerList
super.init(type: .accent, nucleus: value)
}
}
}

View File

@@ -0,0 +1,41 @@
import Foundation
extension Math {
final class Color: Atom {
var colorString: String
var innerList: AtomList?
override var description: String {
[
"\\color",
"{\(colorString)}",
innerList.map { "{\($0)}" },
]
.compactMap(\.self)
.joined()
}
override var finalized: Math.Atom {
let finalized = super.finalized
if let color = finalized as? Color {
color.innerList = color.innerList?.finalized
}
return finalized
}
init(_ color: Color) {
self.colorString = color.colorString
self.innerList = color.innerList.map { AtomList($0) }
super.init(color)
}
init(colorString: String = "", innerList: AtomList? = nil) {
self.colorString = colorString
self.innerList = innerList
super.init(type: .color)
}
}
}

View File

@@ -0,0 +1,41 @@
import Foundation
extension Math {
final class ColorBox: Atom {
var colorString: String
var innerList: AtomList?
override var description: String {
[
"\\colorbox",
"{\(colorString)}",
innerList.map { "{\($0)}" },
]
.compactMap(\.self)
.joined()
}
override var finalized: Math.Atom {
let finalized = super.finalized
if let colorBox = finalized as? ColorBox {
colorBox.innerList = colorBox.innerList?.finalized
}
return finalized
}
init(_ colorBox: ColorBox) {
self.colorString = colorBox.colorString
self.innerList = colorBox.innerList.map { AtomList($0) }
super.init(colorBox)
}
init(colorString: String = "", innerList: AtomList? = nil) {
self.colorString = colorString
self.innerList = innerList
super.init(type: .colorBox)
}
}
}

View File

@@ -0,0 +1,71 @@
import Foundation
extension Math {
final class Fraction: Atom {
var hasRule: Bool
var leftDelimiter: String
var rightDelimiter: String
var numerator: AtomList?
var denominator: AtomList?
var isContinuedFraction: Bool = false
var alignment: String // "l", "r", "c" for left, right, center
override var description: String {
[
hasRule ? "\\frac" : "\\atop",
leftDelimiter.isEmpty ? nil : "[\(leftDelimiter)]",
rightDelimiter.isEmpty ? nil : "[\(rightDelimiter)]",
"{\(numerator?.description ?? "placeholder")}",
"{\(denominator?.description ?? "placeholder")}",
superscript.map { "^{\($0)}" },
`subscript`.map { "_{\($0)}" },
]
.compactMap(\.self)
.joined()
}
override var finalized: Math.Atom {
let finalized = super.finalized
if let fraction = finalized as? Fraction {
fraction.numerator = fraction.numerator?.finalized
fraction.denominator = fraction.denominator?.finalized
}
return finalized
}
init(_ fraction: Fraction) {
self.hasRule = fraction.hasRule
self.leftDelimiter = fraction.leftDelimiter
self.rightDelimiter = fraction.rightDelimiter
self.numerator = fraction.numerator.map { AtomList($0) }
self.denominator = fraction.denominator.map { AtomList($0) }
self.isContinuedFraction = fraction.isContinuedFraction
self.alignment = fraction.alignment
super.init(fraction)
}
init(
hasRule: Bool = true,
leftDelimiter: String = "",
rightDelimiter: String = "",
numerator: AtomList? = nil,
denominator: AtomList? = nil,
isContinuedFraction: Bool = false,
alignment: String = "c"
) {
self.hasRule = hasRule
self.leftDelimiter = leftDelimiter
self.rightDelimiter = rightDelimiter
self.numerator = numerator
self.denominator = denominator
self.isContinuedFraction = isContinuedFraction
self.alignment = alignment
super.init(type: .fraction)
}
}
}

View File

@@ -0,0 +1,68 @@
import Foundation
extension Math {
final class Inner: Atom {
var innerList: AtomList?
var leftBoundary: Atom? {
didSet {
if let leftBoundary, leftBoundary.type != .boundary {
assertionFailure("Left boundary must be of type 'boundary'")
self.leftBoundary = nil
}
}
}
var rightBoundary: Atom? {
didSet {
if let rightBoundary, rightBoundary.type != .boundary {
assertionFailure("Right boundary must be of type 'boundary'")
self.rightBoundary = nil
}
}
}
override var description: String {
[
"\\inner",
leftBoundary.map { "[\($0.nucleus)]" },
innerList.map { "{\($0)}" },
rightBoundary.map { "[\($0.nucleus)]" },
superscript.map { "^{\($0)}" },
`subscript`.map { "_{\($0)}" },
]
.compactMap(\.self)
.joined()
}
override var finalized: Math.Atom {
let finalized = super.finalized
if let inner = finalized as? Inner {
inner.innerList = inner.innerList?.finalized
}
return finalized
}
init(_ inner: Inner) {
self.innerList = inner.innerList.map { AtomList($0) }
self.leftBoundary = inner.leftBoundary.map { $0.copy() }
self.rightBoundary = inner.rightBoundary.map { $0.copy() }
super.init(inner)
}
init(
innerList: AtomList? = nil,
leftBoundary: Atom? = nil,
rightBoundary: Atom? = nil
) {
self.innerList = innerList
self.leftBoundary = leftBoundary
self.rightBoundary = rightBoundary
super.init(type: .inner)
}
}
}

View File

@@ -0,0 +1,17 @@
import Foundation
extension Math {
final class LargeOperator: Atom {
var limits: Bool
init(_ largeOperator: LargeOperator) {
self.limits = largeOperator.limits
super.init(largeOperator)
}
init(limits: Bool = false) {
self.limits = limits
super.init(type: .largeOperator)
}
}
}

View File

@@ -0,0 +1,27 @@
import Foundation
extension Math {
final class Overline: Atom {
var innerList: AtomList?
override var finalized: Math.Atom {
let finalized = super.finalized
if let overline = finalized as? Overline {
overline.innerList = overline.innerList?.finalized
}
return finalized
}
init(_ overline: Overline) {
self.innerList = overline.innerList.map { AtomList($0) }
super.init(overline)
}
init(innerList: AtomList? = nil) {
self.innerList = innerList
super.init(type: .overline)
}
}
}

View File

@@ -0,0 +1,45 @@
import Foundation
extension Math {
final class Radical: Atom {
var radicand: AtomList?
var degree: AtomList?
override var description: String {
[
"\\sqrt",
degree.map { "[\($0)]" },
"{\(radicand?.description ?? "placeholder")}",
superscript.map { "^{\($0)}" },
`subscript`.map { "_{\($0)}" },
]
.compactMap(\.self)
.joined()
}
override var finalized: Math.Atom {
let finalized = super.finalized
if let radical = finalized as? Radical {
radical.radicand = radical.radicand?.finalized
radical.degree = radical.degree?.finalized
}
return finalized
}
init(_ radical: Radical) {
self.radicand = radical.radicand.map { AtomList($0) }
self.degree = radical.degree.map { AtomList($0) }
super.init(radical)
}
init(radicand: AtomList? = nil, degree: AtomList? = nil) {
self.radicand = radicand
self.degree = degree
super.init(type: .radical)
}
}
}

View File

@@ -0,0 +1,17 @@
import Foundation
extension Math {
final class Space: Atom {
var amount: CGFloat
init(_ space: Space) {
self.amount = space.amount
super.init(space)
}
init(amount: CGFloat = 0) {
self.amount = amount
super.init(type: .space)
}
}
}

View File

@@ -0,0 +1,41 @@
import Foundation
extension Math {
final class Style: Atom {
enum Level: Int {
case display
case text
case script
case scriptOfScript
var isScript: Bool {
switch self {
case .script, .scriptOfScript:
return true
default:
return false
}
}
var isNotScript: Bool {
!isScript
}
func next() -> Level {
Level(rawValue: rawValue + 1) ?? .display
}
}
var level: Level
init(_ style: Style) {
self.level = style.level
super.init(style)
}
init(level: Level = .display) {
self.level = level
super.init(type: .style)
}
}
}

View File

@@ -0,0 +1,101 @@
import Foundation
extension Math {
final class Table: Atom {
enum ColumnAlignment {
case left
case center
case right
}
var alignments: [ColumnAlignment]
var cells: [[AtomList]]
var environment: String
var interColumnSpacing: CGFloat
var interRowAdditionalSpacing: CGFloat
override var finalized: Math.Atom {
let finalized = super.finalized
if let table = finalized as? Table {
table.cells = table.cells.map { row in
row.map { $0.finalized }
}
}
return finalized
}
init(_ table: Table) {
self.alignments = table.alignments
self.cells = table.cells.map { row in
row.map { AtomList($0) }
}
self.environment = table.environment
self.interColumnSpacing = table.interColumnSpacing
self.interRowAdditionalSpacing = table.interRowAdditionalSpacing
super.init(table)
}
init(
alignments: [ColumnAlignment] = [],
cells: [[AtomList]] = [],
environment: String = "",
interColumnSpacing: CGFloat = 0,
interRowAdditionalSpacing: CGFloat = 0
) {
self.alignments = alignments
self.cells = cells
self.environment = environment
self.interColumnSpacing = interColumnSpacing
self.interRowAdditionalSpacing = interRowAdditionalSpacing
super.init(type: .table)
}
func setCell(_ cell: AtomList, forRow row: Int, column: Int) {
if cells.count <= row {
for _ in cells.count...row {
cells.append([])
}
}
if cells[row].count <= column {
for _ in cells[row].count...column {
cells[row].append(AtomList())
}
}
cells[row][column] = cell
}
func setAlignment(_ alignment: ColumnAlignment, forColumn column: Int) {
if alignments.count <= column {
for _ in alignments.count...column {
alignments.append(.center)
}
}
alignments[column] = alignment
}
func alignment(forColumn column: Int) -> ColumnAlignment {
if alignments.count <= column {
return .center
}
return alignments[column]
}
var numberOfColumns: Int {
var count = 0
for row in cells {
count = max(count, row.count)
}
return count
}
var numberOfRows: Int {
cells.count
}
}
}

View File

@@ -0,0 +1,41 @@
import Foundation
extension Math {
final class TextColor: Atom {
var colorString: String
var innerList: AtomList?
override var description: String {
[
"\\textcolor",
"{\(colorString)}",
innerList.map { "{\($0)}" },
]
.compactMap(\.self)
.joined()
}
override var finalized: Math.Atom {
let finalized = super.finalized
if let textColor = finalized as? TextColor {
textColor.innerList = textColor.innerList?.finalized
}
return finalized
}
init(_ textColor: TextColor) {
self.colorString = textColor.colorString
self.innerList = textColor.innerList.map { AtomList($0) }
super.init(textColor)
}
init(colorString: String = "", innerList: AtomList? = nil) {
self.colorString = colorString
self.innerList = innerList
super.init(type: .textColor)
}
}
}

View File

@@ -0,0 +1,27 @@
import Foundation
extension Math {
final class Underline: Atom {
var innerList: AtomList?
override var finalized: Math.Atom {
let finalized = super.finalized
if let underline = finalized as? Underline {
underline.innerList = underline.innerList?.finalized
}
return finalized
}
init(_ underline: Underline) {
self.innerList = underline.innerList.map { AtomList($0) }
super.init(underline)
}
init(innerList: AtomList? = nil) {
self.innerList = innerList
super.init(type: .underline)
}
}
}