Passed complete MTMathListBuilderTest suite.
This commit is contained in:
@@ -98,11 +98,11 @@ public class MTMathAtomFactory {
|
||||
"widetilde" : "\u{0303}"
|
||||
]
|
||||
|
||||
var _accentValueToName: [String: String]? = nil
|
||||
public var accentValueToName: [String: String] {
|
||||
static var _accentValueToName: [String: String]? = nil
|
||||
public static var accentValueToName: [String: String] {
|
||||
if _accentValueToName == nil {
|
||||
var output = [String: String]()
|
||||
|
||||
|
||||
for (key, value) in Self.accents {
|
||||
if let existingValue = output[value] {
|
||||
if key.count > existingValue.count {
|
||||
@@ -113,17 +113,14 @@ public class MTMathAtomFactory {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
output[value] = key
|
||||
}
|
||||
|
||||
_accentValueToName = output
|
||||
}
|
||||
|
||||
return _accentValueToName!
|
||||
}
|
||||
|
||||
public var supportedLatexSymbols: [String: MTMathAtom] = [
|
||||
public static var supportedLatexSymbols: [String: MTMathAtom] = [
|
||||
"square" : MTMathAtomFactory.placeholder(),
|
||||
|
||||
// Greek characters
|
||||
@@ -386,14 +383,12 @@ public class MTMathAtomFactory {
|
||||
"scriptscriptstyle" : MTMathStyle(style: .scriptOfScript),
|
||||
]
|
||||
|
||||
var latexSymbolNames = [String]()
|
||||
|
||||
var _textToLatexSymbolName: [String: String]? = nil
|
||||
public var textToLatexSymbolName: [String: String] {
|
||||
get {
|
||||
if self._textToLatexSymbolName == nil {
|
||||
var output = [String: String]()
|
||||
for (key, atom) in self.supportedLatexSymbols {
|
||||
for (key, atom) in Self.supportedLatexSymbols {
|
||||
if atom.nucleus.count == 0 {
|
||||
continue
|
||||
}
|
||||
@@ -423,35 +418,32 @@ public class MTMathAtomFactory {
|
||||
public static let sharedInstance = MTMathAtomFactory()
|
||||
|
||||
static let fontStyles : [String: MTFontStyle] = [
|
||||
"mathnormal" : (.defaultStyle),
|
||||
"mathrm": (.roman),
|
||||
"textrm": (.roman),
|
||||
"rm": (.roman),
|
||||
"mathbf": (.bold),
|
||||
"bf": (.bold),
|
||||
"textbf": (.bold),
|
||||
"mathcal": (.caligraphic),
|
||||
"cal": (.caligraphic),
|
||||
"mathtt": (.typewriter),
|
||||
"texttt": (.typewriter),
|
||||
"mathit": (.italic),
|
||||
"textit": (.italic),
|
||||
"mit": (.italic),
|
||||
"mathsf": (.sansSerif),
|
||||
"textsf": (.sansSerif),
|
||||
"mathfrak": (.fraktur),
|
||||
"frak": (.fraktur),
|
||||
"mathbb": (.blackboard),
|
||||
"mathbfit": (.boldItalic),
|
||||
"bm": (.boldItalic),
|
||||
"text": (.roman),
|
||||
"mathnormal" : .defaultStyle,
|
||||
"mathrm": .roman,
|
||||
"textrm": .roman,
|
||||
"rm": .roman,
|
||||
"mathbf": .bold,
|
||||
"bf": .bold,
|
||||
"textbf": .bold,
|
||||
"mathcal": .caligraphic,
|
||||
"cal": .caligraphic,
|
||||
"mathtt": .typewriter,
|
||||
"texttt": .typewriter,
|
||||
"mathit": .italic,
|
||||
"textit": .italic,
|
||||
"mit": .italic,
|
||||
"mathsf": .sansSerif,
|
||||
"textsf": .sansSerif,
|
||||
"mathfrak": .fraktur,
|
||||
"frak": .fraktur,
|
||||
"mathbb": .blackboard,
|
||||
"mathbfit": .boldItalic,
|
||||
"bm": .boldItalic,
|
||||
"text": .roman,
|
||||
]
|
||||
|
||||
public static func fontStyleWithName(_ fontName:String) -> MTFontStyle? {
|
||||
if let style = fontStyles[fontName] {
|
||||
return style
|
||||
}
|
||||
return nil
|
||||
return fontStyles[fontName]
|
||||
}
|
||||
|
||||
public static func fontNameForStyle(_ fontStyle:MTFontStyle) -> String {
|
||||
@@ -600,13 +592,15 @@ public class MTMathAtomFactory {
|
||||
If the latex symbol is unknown this will return nil. This supports LaTeX aliases as well.
|
||||
*/
|
||||
public static func atom(forLatexSymbol name: String) -> MTMathAtom? {
|
||||
var _name = name
|
||||
var name = name
|
||||
|
||||
if let canonicalName = aliases[name] {
|
||||
_name = canonicalName
|
||||
name = canonicalName
|
||||
}
|
||||
|
||||
if let atom = sharedInstance.supportedLatexSymbols[_name] {
|
||||
if let atom = supportedLatexSymbols[name] {
|
||||
if name == "int" { return MTMathAtomFactory.operatorWithName( "\u{222B}", limits: false) }
|
||||
if name == "sum" { return MTMathAtomFactory.operatorWithName( "\u{2211}", limits: true) }
|
||||
return atom
|
||||
}
|
||||
|
||||
@@ -626,7 +620,7 @@ public class MTMathAtomFactory {
|
||||
return nil
|
||||
}
|
||||
|
||||
return Self.sharedInstance.textToLatexSymbolName[atom.nucleus]
|
||||
return sharedInstance.textToLatexSymbolName[atom.nucleus]
|
||||
}
|
||||
|
||||
/** Define a latex symbol for rendering. This function allows defining custom symbols that are
|
||||
@@ -635,12 +629,12 @@ public class MTMathAtomFactory {
|
||||
`[MTMathAtomFactory addLatexSymbol:@"lcm" value:[MTMathAtomFactory operatorWithName:@"lcm" limits: false)]` */
|
||||
|
||||
public static func add(latexSymbol name: String, value: MTMathAtom) {
|
||||
Self.sharedInstance.supportedLatexSymbols[name] = value
|
||||
Self.sharedInstance.textToLatexSymbolName[value.nucleus] = name
|
||||
supportedLatexSymbols[name] = value
|
||||
sharedInstance.textToLatexSymbolName[value.nucleus] = name
|
||||
}
|
||||
|
||||
/** Returns a large opertor for the given name. If limits is true, limits are set up on
|
||||
the operator and displyed differently. */
|
||||
the operator and displayed differently. */
|
||||
public static func operatorWithName(_ name: String, limits: Bool) -> MTLargeOperator {
|
||||
return MTLargeOperator(value: name, limits: limits)
|
||||
}
|
||||
@@ -650,7 +644,7 @@ public class MTMathAtomFactory {
|
||||
returns nil. The `innerList` of the returned `MTAccent` is nil.
|
||||
*/
|
||||
public static func accent(withName name: String) -> MTAccent? {
|
||||
if let accentValue = Self.accents[name] {
|
||||
if let accentValue = accents[name] {
|
||||
return MTAccent(value: accentValue)
|
||||
}
|
||||
return nil
|
||||
@@ -659,7 +653,7 @@ public class MTMathAtomFactory {
|
||||
/** Returns the accent name for the given accent. This is the reverse of the above
|
||||
function. */
|
||||
public static func accentName(_ accent: MTAccent) -> String? {
|
||||
return Self.sharedInstance.accentValueToName[accent.nucleus]
|
||||
return accentValueToName[accent.nucleus]
|
||||
}
|
||||
|
||||
/** Creates a new boundary atom for the given delimiter name. If the delimiter name
|
||||
@@ -765,7 +759,7 @@ public class MTMathAtomFactory {
|
||||
} else if env == "eqalign" || env == "split" || env == "aligned" {
|
||||
if table.numColumns != 2 {
|
||||
let message = "\(env) environment can only have 2 columns"
|
||||
if error != nil {
|
||||
if error == nil {
|
||||
error = NSError(domain: MTParseError, code: MTParseErrors.invalidNumColumns.rawValue, userInfo: [NSLocalizedDescriptionKey:message])
|
||||
}
|
||||
return nil
|
||||
@@ -789,7 +783,7 @@ public class MTMathAtomFactory {
|
||||
} else if env == "displaylines" || env == "gather" {
|
||||
if table.numColumns != 1 {
|
||||
let message = "\(env) environment can only have 1 column"
|
||||
if error != nil {
|
||||
if error == nil {
|
||||
error = NSError(domain: MTParseError, code: MTParseErrors.invalidNumColumns.rawValue, userInfo: [NSLocalizedDescriptionKey:message])
|
||||
}
|
||||
return nil
|
||||
@@ -804,7 +798,7 @@ public class MTMathAtomFactory {
|
||||
} else if env == "eqnarray" {
|
||||
if table.numColumns != 3 {
|
||||
let message = "\(env) environment can only have 3 columns"
|
||||
if error != nil {
|
||||
if error == nil {
|
||||
error = NSError(domain: MTParseError, code: MTParseErrors.invalidNumColumns.rawValue, userInfo: [NSLocalizedDescriptionKey:message])
|
||||
}
|
||||
return nil
|
||||
@@ -821,7 +815,7 @@ public class MTMathAtomFactory {
|
||||
} else if env == "cases" {
|
||||
if table.numColumns != 2 {
|
||||
let message = "cases environment can only have 2 columns"
|
||||
if error != nil {
|
||||
if error == nil {
|
||||
error = NSError(domain: MTParseError, code: MTParseErrors.invalidNumColumns.rawValue, userInfo: [NSLocalizedDescriptionKey:message])
|
||||
}
|
||||
return nil
|
||||
@@ -852,9 +846,7 @@ public class MTMathAtomFactory {
|
||||
return inner
|
||||
} else {
|
||||
let message = "Unknown environment \(env)"
|
||||
if error != nil {
|
||||
error = NSError(domain: MTParseError, code: MTParseErrors.invalidNumColumns.rawValue, userInfo: [NSLocalizedDescriptionKey:message])
|
||||
}
|
||||
error = NSError(domain: MTParseError, code: MTParseErrors.invalidEnv.rawValue, userInfo: [NSLocalizedDescriptionKey:message])
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,13 +78,29 @@ public enum MTFontStyle:Int {
|
||||
boldItalic
|
||||
}
|
||||
|
||||
public class MTMathAtom: CustomStringConvertible {
|
||||
public class MTMathAtom: NSObject, NSCopying {
|
||||
|
||||
public var type: MTMathAtomType
|
||||
public var subScript: MTMathList?
|
||||
public var superScript: MTMathList?
|
||||
public var nucleus: String = ""
|
||||
public var childAtoms = [MTMathAtom]() // atoms that fused to create this one
|
||||
public var indexRange = NSRange(location: 0, length: 0) // indexRange in list that this atom tracks:
|
||||
|
||||
var fontStyle: MTFontStyle = .defaultStyle
|
||||
var fusedAtoms: MTMathList?
|
||||
|
||||
public func copy(with zone: NSZone? = nil) -> Any {
|
||||
let atom = MTMathAtom.atom(withType: type, value: nucleus)
|
||||
atom.type = self.type
|
||||
atom.nucleus = self.nucleus
|
||||
atom.subScript = self.subScript?.copy() as? MTMathList
|
||||
atom.superScript = self.subScript?.copy() as? MTMathList
|
||||
atom.indexRange = self.indexRange
|
||||
atom.fontStyle = self.fontStyle
|
||||
return atom
|
||||
}
|
||||
|
||||
public static func atom(withType type:MTMathAtomType, value:String) -> MTMathAtom {
|
||||
switch type {
|
||||
case .largeOperator:
|
||||
@@ -118,8 +134,7 @@ public class MTMathAtom: CustomStringConvertible {
|
||||
if self.isScriptAllowed() {
|
||||
self.superScript = list
|
||||
} else {
|
||||
print("superscripts not allowed for atom \(self.type.rawValue)")
|
||||
self.superScript = nil
|
||||
NSException(name: NSExceptionName(rawValue: "Error"), reason: "Superscripts not allowed for atom \(self.type.rawValue)").raise()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,12 +142,11 @@ public class MTMathAtom: CustomStringConvertible {
|
||||
if self.isScriptAllowed() {
|
||||
self.subScript = list
|
||||
} else {
|
||||
print("subscripts not allowed for atom \(self.type.rawValue)")
|
||||
self.subScript = nil
|
||||
NSException(name: NSExceptionName(rawValue: "Error"), reason: "Subscripts not allowed for atom \(self.type.rawValue)").raise()
|
||||
}
|
||||
}
|
||||
|
||||
public var description: String {
|
||||
public override var description: String {
|
||||
var string = ""
|
||||
|
||||
string += self.nucleus
|
||||
@@ -146,7 +160,6 @@ public class MTMathAtom: CustomStringConvertible {
|
||||
return string
|
||||
}
|
||||
|
||||
public var nucleus: String = ""
|
||||
public var finalized: MTMathAtom {
|
||||
let finalized = self
|
||||
if finalized.superScript != nil {
|
||||
@@ -158,12 +171,6 @@ public class MTMathAtom: CustomStringConvertible {
|
||||
return finalized
|
||||
}
|
||||
|
||||
// atoms that fused to create this one
|
||||
public var childAtoms = [MTMathAtom]()
|
||||
|
||||
// indexRange in list that this atom tracks:
|
||||
public var indexRange = NSRange(location: 0, length: 0)
|
||||
|
||||
public var string:String {
|
||||
var str = self.nucleus
|
||||
if let superScript = self.superScript {
|
||||
@@ -183,7 +190,7 @@ public class MTMathAtom: CustomStringConvertible {
|
||||
self.superScript == nil,
|
||||
self.type == atom.type
|
||||
else {
|
||||
print("Can't fuse these 2 atom")
|
||||
print("Can't fuse these 2 atoms")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -228,6 +235,16 @@ public class MTFraction: MTMathAtom {
|
||||
public var numerator: MTMathList? = MTMathList()
|
||||
public var denominator: MTMathList? = MTMathList()
|
||||
|
||||
public override func copy(with zone: NSZone? = nil) -> Any {
|
||||
let frac = super.copy(with: zone) as! MTFraction
|
||||
frac.numerator = self.numerator?.copy() as? MTMathList
|
||||
frac.denominator = self.denominator?.copy() as? MTMathList
|
||||
frac.hasRule = self.hasRule
|
||||
frac.leftDelimiter = self.leftDelimiter
|
||||
frac.rightDelimiter = self.rightDelimiter
|
||||
return frac
|
||||
}
|
||||
|
||||
override public var description: String {
|
||||
var string = ""
|
||||
if self.hasRule {
|
||||
@@ -280,6 +297,13 @@ public class MTRadical: MTMathAtom {
|
||||
self.init(type: .radical, value: "")
|
||||
}
|
||||
|
||||
public override func copy(with zone: NSZone? = nil) -> Any {
|
||||
let rad = super.copy(with: zone) as! MTRadical
|
||||
rad.radicand = self.radicand?.copy() as? MTMathList
|
||||
rad.degree = self.degree?.copy() as? MTMathList
|
||||
return rad
|
||||
}
|
||||
|
||||
override public var description: String {
|
||||
var string = "\\sqrt"
|
||||
|
||||
@@ -314,9 +338,16 @@ public class MTRadical: MTMathAtom {
|
||||
public class MTLargeOperator: MTMathAtom {
|
||||
public var limits: Bool = false
|
||||
|
||||
convenience init(value: String, limits: Bool = false) {
|
||||
self.init(type: .largeOperator, value: value)
|
||||
init(value: String, limits: Bool) {
|
||||
super.init(type: .largeOperator, value: value)
|
||||
self.limits = limits
|
||||
//print("Operator \(value) limits:\(limits)")
|
||||
}
|
||||
|
||||
public override func copy(with zone: NSZone? = nil) -> Any {
|
||||
let op = super.copy(with: zone) as! MTLargeOperator
|
||||
op.limits = self.limits
|
||||
return op
|
||||
}
|
||||
}
|
||||
|
||||
@@ -339,6 +370,14 @@ public class MTInner: MTMathAtom {
|
||||
}
|
||||
}
|
||||
|
||||
public override func copy(with zone: NSZone? = nil) -> Any {
|
||||
let inner = super.copy(with: zone) as! MTInner
|
||||
inner.innerList = self.innerList?.copy() as? MTMathList
|
||||
inner.leftBoundary = self.leftBoundary?.copy() as? MTMathAtom
|
||||
inner.rightBoundary = self.rightBoundary?.copy() as? MTMathAtom
|
||||
return inner
|
||||
}
|
||||
|
||||
init() {
|
||||
super.init(type: .inner, value: "")
|
||||
}
|
||||
@@ -375,9 +414,7 @@ public class MTInner: MTMathAtom {
|
||||
|
||||
override public var finalized: MTMathAtom {
|
||||
let finalized: MTInner = super.finalized as! MTInner
|
||||
|
||||
finalized.innerList = finalized.innerList?.finalized
|
||||
|
||||
return finalized
|
||||
}
|
||||
}
|
||||
@@ -387,12 +424,16 @@ public class MTOverLine: MTMathAtom {
|
||||
|
||||
override public var finalized: MTMathAtom {
|
||||
let finalized: MTOverLine = super.finalized as! MTOverLine
|
||||
|
||||
finalized.innerList = finalized.innerList?.finalized
|
||||
|
||||
return finalized
|
||||
}
|
||||
|
||||
public override func copy(with zone: NSZone? = nil) -> Any {
|
||||
let op = super.copy(with: zone) as! MTOverLine
|
||||
op.innerList = self.innerList?.copy() as? MTMathList
|
||||
return op
|
||||
}
|
||||
|
||||
convenience init() {
|
||||
self.init(type: .overline, value: "")
|
||||
}
|
||||
@@ -403,12 +444,16 @@ public class MTUnderLine: MTMathAtom {
|
||||
|
||||
override public var finalized: MTMathAtom {
|
||||
let finalized: MTUnderLine = super.finalized as! MTUnderLine
|
||||
|
||||
finalized.innerList = finalized.innerList?.finalized
|
||||
|
||||
return finalized
|
||||
}
|
||||
|
||||
public override func copy(with zone: NSZone? = nil) -> Any {
|
||||
let op = super.copy(with: zone) as! MTUnderLine
|
||||
op.innerList = self.innerList?.copy() as? MTMathList
|
||||
return op
|
||||
}
|
||||
|
||||
convenience init() {
|
||||
self.init(type: .underline, value: "")
|
||||
}
|
||||
@@ -419,12 +464,16 @@ public class MTAccent: MTMathAtom {
|
||||
|
||||
override public var finalized: MTMathAtom {
|
||||
let finalized: MTAccent = super.finalized as! MTAccent
|
||||
|
||||
finalized.innerList = finalized.innerList?.finalized
|
||||
|
||||
return finalized
|
||||
}
|
||||
|
||||
public override func copy(with zone: NSZone? = nil) -> Any {
|
||||
let op = super.copy(with: zone) as! MTAccent
|
||||
op.innerList = self.innerList?.copy() as? MTMathList
|
||||
return op
|
||||
}
|
||||
|
||||
convenience init(value: String) {
|
||||
self.init(type: .accent, value: value)
|
||||
}
|
||||
@@ -437,6 +486,13 @@ public class MTMathSpace: MTMathAtom {
|
||||
self.init(type: .space, value: "")
|
||||
self.space = space
|
||||
}
|
||||
|
||||
public override func copy(with zone: NSZone? = nil) -> Any {
|
||||
let op = super.copy(with: zone) as! MTMathSpace
|
||||
op.space = self.space
|
||||
return op
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public enum MTLineStyle {
|
||||
@@ -466,6 +522,12 @@ public class MTMathStyle: MTMathAtom {
|
||||
self.init(type: .style, value: "")
|
||||
self.style = style
|
||||
}
|
||||
|
||||
public override func copy(with zone: NSZone? = nil) -> Any {
|
||||
let op = super.copy(with: zone) as! MTMathStyle
|
||||
op.style = self.style
|
||||
return op
|
||||
}
|
||||
}
|
||||
|
||||
public class MTMathColor: MTMathAtom {
|
||||
@@ -484,6 +546,13 @@ public class MTMathColor: MTMathAtom {
|
||||
self.init()
|
||||
}
|
||||
|
||||
public override func copy(with zone: NSZone? = nil) -> Any {
|
||||
let op = super.copy(with: zone) as! MTMathColor
|
||||
op.colorString = self.colorString
|
||||
op.innerList = self.innerList?.copy() as? MTMathList
|
||||
return op
|
||||
}
|
||||
|
||||
public override var string: String {
|
||||
"\\color{\(self.colorString)}{\(self.innerList!.string)}"
|
||||
}
|
||||
@@ -505,6 +574,13 @@ public class MTMathColorbox: MTMathAtom {
|
||||
self.init()
|
||||
}
|
||||
|
||||
public override func copy(with zone: NSZone? = nil) -> Any {
|
||||
let op = super.copy(with: zone) as! MTMathColorbox
|
||||
op.colorString = self.colorString
|
||||
op.innerList = self.innerList?.copy() as? MTMathList
|
||||
return op
|
||||
}
|
||||
|
||||
public override var string: String {
|
||||
"\\colorbox{\(self.colorString)}{\(self.innerList!.string)}"
|
||||
}
|
||||
@@ -523,8 +599,6 @@ public class MTMathTable: MTMathAtom {
|
||||
public var environment: String?
|
||||
public var interColumnSpacing: CGFloat = 0
|
||||
public var interRowAdditionalSpacing: CGFloat = 0
|
||||
// public var numColumns = 0
|
||||
// public var numRows = 0
|
||||
|
||||
override public var finalized: MTMathAtom {
|
||||
let finalized: MTMathTable = super.finalized as! MTMathTable
|
||||
@@ -543,6 +617,21 @@ public class MTMathTable: MTMathAtom {
|
||||
self.environment = environment
|
||||
}
|
||||
|
||||
public override func copy(with zone: NSZone? = nil) -> Any {
|
||||
let op = super.copy(with: zone) as! MTMathTable
|
||||
op.interRowAdditionalSpacing = self.interRowAdditionalSpacing
|
||||
op.interColumnSpacing = self.interColumnSpacing
|
||||
op.environment = self.environment
|
||||
var cellCopy = [[MTMathList]]()
|
||||
cellCopy.reserveCapacity(self.cells.count)
|
||||
for row in self.cells {
|
||||
let newRow = [MTMathList](row)
|
||||
cellCopy.append(newRow)
|
||||
}
|
||||
op.cells = cellCopy
|
||||
return op
|
||||
}
|
||||
|
||||
public func set(cell list: MTMathList, forRow row:Int, column:Int) {
|
||||
if self.cells.count <= row {
|
||||
for _ in self.cells.count...row {
|
||||
@@ -592,12 +681,19 @@ public class MTMathTable: MTMathAtom {
|
||||
}
|
||||
|
||||
// represent list of math objects
|
||||
extension MTMathList: CustomStringConvertible {
|
||||
public var description: String { self.atoms.description }
|
||||
extension MTMathList {
|
||||
public override var description: String { self.atoms.description }
|
||||
public var string: String { self.description }
|
||||
}
|
||||
|
||||
public class MTMathList {
|
||||
public class MTMathList: NSObject, NSCopying {
|
||||
|
||||
public func copy(with zone: NSZone? = nil) -> Any {
|
||||
let list = MTMathList()
|
||||
list.atoms = [MTMathAtom](self.atoms)
|
||||
return list
|
||||
}
|
||||
|
||||
public var atoms = [MTMathAtom]()
|
||||
|
||||
public var finalized: MTMathList {
|
||||
@@ -658,7 +754,7 @@ public class MTMathList {
|
||||
self.atoms.append(atom)
|
||||
}
|
||||
|
||||
public init() {
|
||||
public override init() {
|
||||
self.atoms = []
|
||||
}
|
||||
|
||||
@@ -666,7 +762,7 @@ public class MTMathList {
|
||||
if self.isAtomAllowed(atom) {
|
||||
self.atoms.append(atom)
|
||||
} else {
|
||||
print("error, cannot add atom of type \(atom.type.rawValue) into atomlist")
|
||||
NSException(name: NSExceptionName(rawValue: "Error"), reason: "Cannot add atom of type \(atom.type.rawValue) into mathlist").raise()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -674,7 +770,7 @@ public class MTMathList {
|
||||
if self.isAtomAllowed(atom) {
|
||||
self.atoms.insert(atom, at: index)
|
||||
} else {
|
||||
print("error, cannot add atom of type \(atom.type.rawValue) into atomlist")
|
||||
NSException(name: NSExceptionName(rawValue: "Error"), reason: "Cannot add atom of type \(atom.type.rawValue) into mathlist").raise()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -99,16 +99,16 @@ public class MTMathListBuilder {
|
||||
self.spacesAllowed = false
|
||||
}
|
||||
|
||||
func build() -> MTMathList? {
|
||||
if let list = self.buildInternal(false) {
|
||||
if self.hasCharacters {
|
||||
print("Mismatched braces: \(self.string)")
|
||||
return nil
|
||||
}
|
||||
return list
|
||||
} else {
|
||||
public func build() -> MTMathList? {
|
||||
let list = self.buildInternal(false)
|
||||
if self.hasCharacters && error == nil {
|
||||
self.setError(.mismatchBraces, message: "Mismatched braces: \(self.string)")
|
||||
return nil
|
||||
}
|
||||
if error != nil {
|
||||
return nil
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
public static func build(fromString string: String) -> MTMathList? {
|
||||
@@ -116,14 +116,12 @@ public class MTMathListBuilder {
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
public static func build(fromString string: String, error:inout NSError) -> MTMathList? {
|
||||
public static func build(fromString string: String, error:inout NSError?) -> MTMathList? {
|
||||
let builder = MTMathListBuilder(string: string)
|
||||
let output = builder.build()
|
||||
if builder.error != nil {
|
||||
error = builder.error!
|
||||
error = builder.error
|
||||
return nil
|
||||
} else {
|
||||
error = NSError()
|
||||
}
|
||||
return output
|
||||
}
|
||||
@@ -213,9 +211,7 @@ public class MTMathListBuilder {
|
||||
cell.atoms.removeFirst()
|
||||
}
|
||||
}
|
||||
|
||||
str += mathListToString(cell)
|
||||
|
||||
if j < row.count - 1 {
|
||||
str += "&"
|
||||
}
|
||||
@@ -224,7 +220,6 @@ public class MTMathListBuilder {
|
||||
str += "\\\\ "
|
||||
}
|
||||
}
|
||||
|
||||
if table.environment != nil {
|
||||
str += "\\end{\(table.environment!)}"
|
||||
}
|
||||
@@ -331,11 +326,11 @@ public class MTMathListBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
func buildInternal(_ oneCharOnly: Bool) -> MTMathList? {
|
||||
public func buildInternal(_ oneCharOnly: Bool) -> MTMathList? {
|
||||
return self.buildInternal(oneCharOnly, stopChar: nil)
|
||||
}
|
||||
|
||||
func buildInternal(_ oneCharOnly: Bool, stopChar stop: Character?) -> MTMathList? {
|
||||
public func buildInternal(_ oneCharOnly: Bool, stopChar stop: Character?) -> MTMathList? {
|
||||
let list = MTMathList()
|
||||
assert(!(oneCharOnly && stop != nil), "Cannot set both oneCharOnly and stopChar.")
|
||||
var prevAtom: MTMathAtom? = nil
|
||||
@@ -391,8 +386,7 @@ public class MTMathListBuilder {
|
||||
assert(stop == nil, "This should have been handled before")
|
||||
// We encountered a closing brace when there is no stop set, that means there was no
|
||||
// corresponding opening brace.
|
||||
let errorMessage = "Mismatched braces."
|
||||
self.setError(.mismatchBraces, message:errorMessage)
|
||||
self.setError(.mismatchBraces, message:"Mismatched braces.")
|
||||
return nil
|
||||
} else if char == "\\" {
|
||||
let command = readCommand()
|
||||
@@ -607,16 +601,17 @@ public class MTMathListBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
static var fractionCommands: [String:[Character]] {
|
||||
[
|
||||
"over": [],
|
||||
"atop" : [],
|
||||
"choose" : [ "(", ")"],
|
||||
"brack" : [ "[", "]"],
|
||||
"brace" : [ "{", "}"]
|
||||
]
|
||||
}
|
||||
|
||||
func stopCommand(_ command: String, list:MTMathList, stopChar:Character?) -> MTMathList? {
|
||||
var fractionCommands: [String:[Character]] {
|
||||
[
|
||||
"over": [],
|
||||
"atop" : [],
|
||||
"choose" : [ "(", ")"],
|
||||
"brack" : [ "[", "]"],
|
||||
"brace" : [ "{", "}"]
|
||||
]
|
||||
}
|
||||
if command == "right" {
|
||||
if currentInnerAtom == nil {
|
||||
let errorMessage = "Missing \\left";
|
||||
@@ -629,7 +624,7 @@ public class MTMathListBuilder {
|
||||
}
|
||||
// return the list read so far.
|
||||
return list
|
||||
} else if let delims = fractionCommands[command] {
|
||||
} else if let delims = Self.fractionCommands[command] {
|
||||
var frac:MTFraction! = nil;
|
||||
if command == "over" {
|
||||
frac = MTFraction()
|
||||
@@ -662,11 +657,11 @@ public class MTMathListBuilder {
|
||||
if currentEnv == nil {
|
||||
let errorMessage = "Missing \\begin";
|
||||
self.setError(.missingBegin, message:errorMessage)
|
||||
return nil;
|
||||
return nil
|
||||
}
|
||||
let env = self.readEnvironment()
|
||||
if env == nil {
|
||||
return nil;
|
||||
return nil
|
||||
}
|
||||
if env! != currentEnv!.envName {
|
||||
let errorMessage = "Begin environment name \(currentEnv!.envName!) does not match end name: \(env!)"
|
||||
@@ -683,7 +678,7 @@ public class MTMathListBuilder {
|
||||
// Applies the modifier to the atom. Returns true if modifier applied.
|
||||
func applyModifier(_ modifier:String, atom:MTMathAtom?) -> Bool {
|
||||
if modifier == "limits" {
|
||||
if atom!.type != .largeOperator {
|
||||
if atom?.type != .largeOperator {
|
||||
let errorMessage = "Limits can only be applied to an operator."
|
||||
self.setError(.invalidLimits, message:errorMessage)
|
||||
} else {
|
||||
@@ -695,14 +690,13 @@ public class MTMathListBuilder {
|
||||
if atom?.type != .largeOperator {
|
||||
let errorMessage = "No limits can only be applied to an operator."
|
||||
self.setError(.invalidLimits, message:errorMessage)
|
||||
return true
|
||||
} else {
|
||||
let op = atom as! MTLargeOperator
|
||||
op.limits = false
|
||||
}
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
|
||||
func setError(_ code:MTParseErrors, message:String) {
|
||||
@@ -795,7 +789,7 @@ public class MTMathListBuilder {
|
||||
func readEnvironment() -> String? {
|
||||
if !self.expectCharacter("{") {
|
||||
// We didn't find an opening brace, so no env found.
|
||||
print("Missing {")
|
||||
self.setError(.characterNotFound, message: "Missing {")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -804,7 +798,7 @@ public class MTMathListBuilder {
|
||||
|
||||
if !self.expectCharacter("}") {
|
||||
// We didn"t find an closing brace, so invalid format.
|
||||
print("Missing {")
|
||||
self.setError(.characterNotFound, message: "Missing }")
|
||||
return nil;
|
||||
}
|
||||
return env
|
||||
@@ -872,7 +866,7 @@ public class MTMathListBuilder {
|
||||
return nil
|
||||
}
|
||||
|
||||
var error:NSError?
|
||||
var error:NSError? = self.error
|
||||
let table = MTMathAtomFactory.table(withEnvironment: currentEnv?.envName, rows: rows, error: &error)
|
||||
if table == nil && self.error == nil {
|
||||
self.error = error
|
||||
@@ -892,7 +886,7 @@ public class MTMathListBuilder {
|
||||
let boundary = MTMathAtomFactory.boundary(forDelimiter: delim!)
|
||||
if boundary == nil {
|
||||
let errorMessage = "Invalid delimiter for \(delimiterType): \(delim!)"
|
||||
self.setError(.missingDelimiter, message:errorMessage)
|
||||
self.setError(.invalidDelimiter, message:errorMessage)
|
||||
return nil
|
||||
}
|
||||
return boundary
|
||||
|
||||
@@ -71,12 +71,12 @@ class MTMathUILabel : MTView {
|
||||
var latex = "" {
|
||||
didSet {
|
||||
self.error = nil
|
||||
var error = NSError()
|
||||
var error : NSError? = nil
|
||||
self.mathList = MTMathListBuilder.build(fromString: latex, error: &error)
|
||||
if error != NSError() {
|
||||
if error != nil {
|
||||
self.mathList = nil
|
||||
self.error = error
|
||||
self.errorLabel?.text = error.localizedDescription
|
||||
self.errorLabel?.text = error!.localizedDescription
|
||||
self.errorLabel?.frame = self.bounds
|
||||
self.errorLabel?.isHidden = !self.displayErrorInline
|
||||
} else {
|
||||
|
||||
@@ -195,9 +195,9 @@ final class SwiftMathRenderTests: XCTestCase {
|
||||
let data = getTestData()
|
||||
for testCase in data {
|
||||
let str = testCase.build
|
||||
var error = NSError()
|
||||
var error : NSError? = nil
|
||||
let list = MTMathListBuilder.build(fromString: str, error: &error)
|
||||
XCTAssert(error.code == 0)
|
||||
XCTAssertNil(error)
|
||||
let desc = "Error for string:\(str)"
|
||||
let atomTypes = testCase.atomType
|
||||
self.checkAtomTypes(list, types:atomTypes, desc:desc)
|
||||
@@ -212,9 +212,9 @@ final class SwiftMathRenderTests: XCTestCase {
|
||||
let data = getTestDataSuperScript()
|
||||
for testCase in data {
|
||||
let str = testCase.build
|
||||
var error = NSError()
|
||||
var error : NSError? = nil
|
||||
let list = MTMathListBuilder.build(fromString: str, error:&error)
|
||||
XCTAssert(error.code == NSNotFound)
|
||||
XCTAssertNil(error)
|
||||
let desc = "Error for string:\(str)"
|
||||
let atomTypes = testCase.atomType
|
||||
checkAtomTypes(list, types:atomTypes, desc:desc)
|
||||
@@ -246,9 +246,9 @@ final class SwiftMathRenderTests: XCTestCase {
|
||||
let data = getTestDataSubScript()
|
||||
for testCase in data {
|
||||
let str = testCase.build
|
||||
var error = NSError()
|
||||
var error : NSError? = nil
|
||||
let list = MTMathListBuilder.build(fromString: str, error:&error)
|
||||
XCTAssert(error.code == NSNotFound)
|
||||
XCTAssertNil(error)
|
||||
let desc = "Error for string:\(str)"
|
||||
let atomTypes = testCase.atomType
|
||||
checkAtomTypes(list, types:atomTypes, desc:desc)
|
||||
@@ -280,9 +280,9 @@ final class SwiftMathRenderTests: XCTestCase {
|
||||
let data = getTestDataSuperSubScript()
|
||||
for testCase in data {
|
||||
let str = testCase.build
|
||||
var error = NSError()
|
||||
var error : NSError? = nil
|
||||
let list = MTMathListBuilder.build(fromString: str, error:&error)
|
||||
XCTAssert(error.code == NSNotFound)
|
||||
XCTAssertNil(error)
|
||||
let desc = "Error for string:\(str)"
|
||||
let atomTypes = testCase.atomType
|
||||
checkAtomTypes(list, types:atomTypes, desc:desc)
|
||||
@@ -508,7 +508,7 @@ final class SwiftMathRenderTests: XCTestCase {
|
||||
for testCase in data {
|
||||
let str = testCase.build
|
||||
|
||||
var error = NSError()
|
||||
var error : NSError? = nil
|
||||
let list = MTMathListBuilder.build(fromString: str, error: &error)!
|
||||
|
||||
XCTAssertNotNil(list, str);
|
||||
@@ -1149,26 +1149,30 @@ final class SwiftMathRenderTests: XCTestCase {
|
||||
let data = getTestDataParseErrors()
|
||||
for testCase in data {
|
||||
let str = testCase.0
|
||||
var error = NSError()
|
||||
var error : NSError? = nil
|
||||
if str == "\\begin{displaylines} x & y \\end{displaylines}" {
|
||||
let x = 0
|
||||
}
|
||||
let list = MTMathListBuilder.build(fromString: str, error:&error)
|
||||
let desc = "Error for string:\(str)"
|
||||
XCTAssertNil(list, desc)
|
||||
XCTAssertNotNil(error, desc)
|
||||
XCTAssertEqual(error.domain, MTParseError, desc)
|
||||
XCTAssertEqual(error!.domain, MTParseError, desc)
|
||||
let code = error!.code
|
||||
let num = testCase.1
|
||||
let code = num.rawValue
|
||||
XCTAssertEqual(error.code, code, desc)
|
||||
XCTAssertEqual(error!.code, num.rawValue, desc)
|
||||
}
|
||||
}
|
||||
|
||||
func testCustom() throws {
|
||||
let str = "\\lcm(a,b)";
|
||||
var error = NSError()
|
||||
var error : NSError? = nil
|
||||
var list = MTMathListBuilder.build(fromString: str, error:&error)
|
||||
XCTAssertNil(list);
|
||||
XCTAssert(error.code == NSNotFound)
|
||||
XCTAssertNil(list)
|
||||
XCTAssertNotNil(error)
|
||||
|
||||
MTMathAtomFactory.add(latexSymbol: "lcm", value: MTMathAtomFactory.operatorWithName("lcm", limits:false))
|
||||
error = nil
|
||||
list = MTMathListBuilder.build(fromString: str, error:&error)
|
||||
let atomTypes = [MTMathAtomType.largeOperator, .open, .variable, .punctuation, .variable, .close]
|
||||
self.checkAtomTypes(list, types:atomTypes, desc:"Error for lcm")
|
||||
@@ -1319,7 +1323,7 @@ final class SwiftMathRenderTests: XCTestCase {
|
||||
XCTAssertEqual((list.atoms.count), 1, desc)
|
||||
op = list.atoms[0] as! MTLargeOperator
|
||||
XCTAssertEqual(op.type, .largeOperator, desc)
|
||||
XCTAssertTrue(op.limits);
|
||||
XCTAssertTrue(op.limits)
|
||||
|
||||
// convert it back to latex
|
||||
latex = MTMathListBuilder.mathListToString(list)
|
||||
|
||||
Reference in New Issue
Block a user