Skip to content

Commit 86510db

Browse files
committed
Initial commit
0 parents  commit 86510db

7 files changed

Lines changed: 462 additions & 0 deletions

File tree

.gitignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
.DS_Store
2+
/.build
3+
/Packages
4+
/*.xcodeproj
5+
xcuserdata/
6+
DerivedData/
7+
.swiftpm/config/registries.json
8+
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
9+
.netrc
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>IDEDidComputeMac32BitWarning</key>
6+
<true/>
7+
</dict>
8+
</plist>

Package.swift

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// swift-tools-version: 5.5
2+
3+
import PackageDescription
4+
5+
let package = Package(
6+
name: "Logic Parser",
7+
products: [
8+
.library(
9+
name: "LogicParser",
10+
targets: [
11+
"LogicParser"
12+
]
13+
)
14+
],
15+
dependencies: [
16+
.package(
17+
url: "https://github.com/palle-k/Covfefe.git",
18+
.upToNextMinor(from: "0.6.0")
19+
)
20+
],
21+
targets: [
22+
.target(
23+
name: "LogicParser",
24+
dependencies: [
25+
"Covfefe"
26+
]
27+
)
28+
]
29+
)

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Logic Parser
2+
3+
A Swift library for parsing formal-logic expressions

Sources/LogicParser/Errors.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//
2+
// Errors.swift
3+
// Logic Parser
4+
//
5+
// Created by Gabriel Jacoby-Cooper on 4/4/22.
6+
//
7+
8+
import Foundation
9+
10+
enum LogicParsingError: Error {
11+
12+
case invalidSyntaxTree
13+
14+
case noLeafFound
15+
16+
case emptySubstring
17+
18+
case invalidCharacter
19+
20+
}
21+
22+
enum LogicNodeConfigurationError: Error {
23+
24+
case invalidChildrenType
25+
26+
case allChildrenAlreadyConfigured
27+
28+
}
Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
//
2+
// LogicNode.swift
3+
// Logic Parser
4+
//
5+
// Created by Gabriel Jacoby-Cooper on 3/28/22.
6+
//
7+
8+
/// A node in a formal-logic tree.
9+
public protocol LogicNode: AnyObject, CustomStringConvertible {
10+
11+
/// A human-readable name for this type of node.
12+
static var name: String { get }
13+
14+
/// The layout of the children of this type of node.
15+
///
16+
/// A node can have no children, only a lefthand child, only a righthand child, or both lefthand and righthand children.
17+
static var childrenType: LogicNodeChildrenType { get }
18+
19+
/// A description of this node and its children that’s suitable for printing.
20+
var description: String { get }
21+
22+
/// The parent of this node.
23+
var parent: (any LogicNode)! { get }
24+
25+
/// The lefthand child of this node.
26+
///
27+
/// The value of this property may be `nil` if ``childrenType-swift.type.property`` is ``LogicNodeChildrenType/none`` or ``LogicNodeChildrenType/rightOnly`` or if it just hasn’t been configured yet.
28+
var left: (any LogicNode)? { get }
29+
30+
/// The righthand child of this node.
31+
///
32+
/// The value of this property may be `nil` if ``childrenType-swift.type.property`` is ``LogicNodeChildrenType/none`` or ``LogicNodeChildrenType/leftOnly`` or if it just hasn’t been configured yet.
33+
var right: (any LogicNode)? { get }
34+
35+
}
36+
37+
extension LogicNode {
38+
39+
public var description: String {
40+
get {
41+
switch Self.childrenType {
42+
case .none:
43+
return Self.name
44+
case .leftOnly:
45+
return "(\(Self.name) \(self.left?.description ?? "nil")|_)"
46+
case .rightOnly:
47+
return "(\(Self.name) _|\(self.right?.description ?? "nil"))"
48+
case .leftAndRight:
49+
return "(\(Self.name) \(self.left?.description ?? "nil")|\(self.right?.description ?? "nil"))"
50+
}
51+
}
52+
}
53+
54+
func setNextChild(to child: any LogicNode) throws {
55+
guard let parent = self as? any WritableLogicNode, let child = child as? any WritableLogicNode else {
56+
return
57+
}
58+
try parent.setNextChild(to: child)
59+
}
60+
61+
}
62+
63+
fileprivate protocol WritableLogicNode: LogicNode {
64+
65+
var parent: (any LogicNode)! { get set }
66+
67+
var left: (any LogicNode)? { get set }
68+
69+
var right: (any LogicNode)? { get set }
70+
71+
}
72+
73+
extension WritableLogicNode {
74+
75+
func setNextChild(to child: any WritableLogicNode) throws {
76+
defer {
77+
child.parent = self
78+
}
79+
switch Self.childrenType {
80+
case .none:
81+
throw LogicNodeConfigurationError.invalidChildrenType
82+
case .leftOnly:
83+
guard self.left == nil else {
84+
throw LogicNodeConfigurationError.allChildrenAlreadyConfigured
85+
}
86+
self.left = child
87+
case .rightOnly:
88+
guard self.right == nil else {
89+
throw LogicNodeConfigurationError.allChildrenAlreadyConfigured
90+
}
91+
self.right = child
92+
case .leftAndRight:
93+
if self.left == nil {
94+
self.left = child
95+
} else if self.right == nil {
96+
self.right = child
97+
} else {
98+
throw LogicNodeConfigurationError.allChildrenAlreadyConfigured
99+
}
100+
}
101+
}
102+
103+
}
104+
105+
/// The possible layouts for children of a node.
106+
public enum LogicNodeChildrenType {
107+
108+
/// A layout that indicates the absence of any children.
109+
case none
110+
111+
/// A layout that indicates the presence of a lefthand child but the absence of a righthand child.
112+
case leftOnly
113+
114+
/// A layout that indicates the presence of a righthand child but the absence of a lefthand child.
115+
case rightOnly
116+
117+
/// A layout that indicates the presence of both lefthand and righthand children.
118+
case leftAndRight
119+
120+
}
121+
122+
/// A node that serves as the root of a formal-logic tree.
123+
public class RootNode: WritableLogicNode {
124+
125+
public static let name = "Root"
126+
127+
public static let childrenType: LogicNodeChildrenType = .leftOnly
128+
129+
public fileprivate(set) var parent: (any LogicNode)! {
130+
willSet {
131+
fatalError("[RootNode parent] Can’t set the parent of a root node")
132+
}
133+
}
134+
135+
public fileprivate(set) var left: (any LogicNode)?
136+
137+
public fileprivate(set) var right: (any LogicNode)? {
138+
willSet {
139+
fatalError("[RootNode right] Can’t set the right child of a root node")
140+
}
141+
}
142+
143+
}
144+
145+
/// A node that represents an atom in a formal-logic expression.
146+
public class AtomicNode: WritableLogicNode {
147+
148+
public static let name = "Atomic"
149+
150+
public static let childrenType: LogicNodeChildrenType = .none
151+
152+
public var description: String {
153+
get {
154+
return String(self.character)
155+
}
156+
}
157+
158+
public fileprivate(set) var parent: (any LogicNode)!
159+
160+
public fileprivate(set) var left: (any LogicNode)? {
161+
willSet {
162+
fatalError("[AtomicNode left] Can’t set the left child of an atomic node")
163+
}
164+
}
165+
166+
public fileprivate(set) var right: (any LogicNode)? {
167+
willSet {
168+
fatalError("[AtomicNode right] Can’t set the right child of an atomic node")
169+
}
170+
}
171+
172+
/// The character that’s associated with this atom.
173+
public let character: Character
174+
175+
/// Creates an atomic node.
176+
/// - Parameter character: The character to associate with the atom.
177+
init(_ character: Character) {
178+
self.character = character
179+
}
180+
181+
}
182+
183+
/// A node that represents a negation in a formal-logic expression.
184+
public class NegationNode: WritableLogicNode {
185+
186+
public static let name = "Negation"
187+
188+
public static let childrenType: LogicNodeChildrenType = .rightOnly
189+
190+
public fileprivate(set) var parent: (any LogicNode)!
191+
192+
public fileprivate(set) var left: (any LogicNode)? {
193+
willSet {
194+
fatalError("[NegationNode left] Can’t set the left child of a negation node")
195+
}
196+
}
197+
198+
public fileprivate(set) var right: (any LogicNode)?
199+
200+
}
201+
202+
/// A node that represents a conjunction in a formal-logic expression.
203+
public class ConjunctionNode: WritableLogicNode {
204+
205+
public static let name = "Conjunction"
206+
207+
public static let childrenType: LogicNodeChildrenType = .leftAndRight
208+
209+
public fileprivate(set) var parent: (any LogicNode)!
210+
211+
public fileprivate(set) var left: (any LogicNode)?
212+
213+
public fileprivate(set) var right: (any LogicNode)?
214+
215+
}
216+
217+
/// A node that represents a disjunction in a formal-logic expression.
218+
public class DisjunctionNode: WritableLogicNode {
219+
220+
public static let name = "Disjunction"
221+
222+
public static let childrenType: LogicNodeChildrenType = .leftAndRight
223+
224+
public fileprivate(set) var parent: (any LogicNode)!
225+
226+
public fileprivate(set) var left: (any LogicNode)?
227+
228+
public fileprivate(set) var right: (any LogicNode)?
229+
230+
}
231+
232+
/// A node that represents a conditional in a formal-logic expression.
233+
public class ConditionalNode: WritableLogicNode {
234+
235+
public static let name = "Conditional"
236+
237+
public static let childrenType: LogicNodeChildrenType = .leftAndRight
238+
239+
public fileprivate(set) var parent: (any LogicNode)!
240+
241+
public fileprivate(set) var left: (any LogicNode)?
242+
243+
public fileprivate(set) var right: (any LogicNode)?
244+
245+
}
246+
247+
/// A node that represents a biconditional in a formal-logic expression.
248+
public class BiconditionalNode: WritableLogicNode {
249+
250+
public static let name = "Biconditional"
251+
252+
public static let childrenType: LogicNodeChildrenType = .leftAndRight
253+
254+
public fileprivate(set) var parent: (any LogicNode)!
255+
256+
public fileprivate(set) var left: (any LogicNode)?
257+
258+
public fileprivate(set) var right: (any LogicNode)?
259+
260+
}

0 commit comments

Comments
 (0)