on master help sign in
8 files changed+671
since splitsnapshots
unifiedsplit
README.md+37 Truther.xcodeproj/project.pbxproj+294 Truther.xcodeproj/project.xcworkspace/contents.xcworkspacedata+7 Truther.xcodeproj/xcuserdata/ilya.xcuserdatad/xcschemes/xcschememanagement.plist+22 Truther/Formatter.swift+39 Truther/Operator.swift+94 Truther/Truther.swift+159 Truther/main.swift+19
README.mdnew file+37
@@ -0,0 +1,37 @@
1+# Truther
2+
3+Makes a truth table for the given boolean function
4+
5+*All operators have equal precedence and are left-associative*
6+
7+## Usage
8+
9+```
10+truther "a * c (+) b"
11+```
12+
13+```
14+a | b | c | F
15+-------------
16+0 | 0 | 0 | 0
17+0 | 0 | 1 | 0
18+0 | 1 | 0 | 1
19+0 | 1 | 1 | 1
20+1 | 0 | 0 | 0
21+1 | 0 | 1 | 1
22+1 | 1 | 0 | 1
23+1 | 1 | 1 | 0
24+```
25+
26+## Available functions
27+
28+- `+` `or`
29+- `(+)` `xor` `/=`
30+- `*` `and` `&`
31+- `=>`
32+- `=/>`
33+- `<=`
34+- `</=`
35+- `o` `nor`
36+- `=` `<=>`
37+- `|` `nand`
Truther.xcodeproj/project.pbxprojnew file+294
@@ -0,0 +1,294 @@
1+// !$*UTF8*$!
2+{
3+ archiveVersion = 1;
4+ classes = {
5+ };
6+ objectVersion = 48;
7+ objects = {
8+
9+/* Begin PBXBuildFile section */
10+ 091685E31F8834C800CC8645 /* Formatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 091685E21F8834C800CC8645 /* Formatter.swift */; };
11+ 097824FA1F87E21400064ADB /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097824F91F87E21400064ADB /* main.swift */; };
12+ 097825011F87E23000064ADB /* Truther.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097825001F87E23000064ADB /* Truther.swift */; };
13+ 097825031F87E48500064ADB /* Operator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097825021F87E48500064ADB /* Operator.swift */; };
14+/* End PBXBuildFile section */
15+
16+/* Begin PBXCopyFilesBuildPhase section */
17+ 097824F41F87E21400064ADB /* CopyFiles */ = {
18+ isa = PBXCopyFilesBuildPhase;
19+ buildActionMask = 2147483647;
20+ dstPath = /usr/share/man/man1/;
21+ dstSubfolderSpec = 0;
22+ files = (
23+ );
24+ runOnlyForDeploymentPostprocessing = 1;
25+ };
26+/* End PBXCopyFilesBuildPhase section */
27+
28+/* Begin PBXFileReference section */
29+ 0915F8131F8907DB00D96279 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
30+ 091685E21F8834C800CC8645 /* Formatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Formatter.swift; sourceTree = "<group>"; };
31+ 097824F61F87E21400064ADB /* Truther */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = Truther; sourceTree = BUILT_PRODUCTS_DIR; };
32+ 097824F91F87E21400064ADB /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
33+ 097825001F87E23000064ADB /* Truther.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Truther.swift; sourceTree = "<group>"; };
34+ 097825021F87E48500064ADB /* Operator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Operator.swift; sourceTree = "<group>"; };
35+/* End PBXFileReference section */
36+
37+/* Begin PBXFrameworksBuildPhase section */
38+ 097824F31F87E21400064ADB /* Frameworks */ = {
39+ isa = PBXFrameworksBuildPhase;
40+ buildActionMask = 2147483647;
41+ files = (
42+ );
43+ runOnlyForDeploymentPostprocessing = 0;
44+ };
45+/* End PBXFrameworksBuildPhase section */
46+
47+/* Begin PBXGroup section */
48+ 097824ED1F87E21400064ADB = {
49+ isa = PBXGroup;
50+ children = (
51+ 0915F8131F8907DB00D96279 /* README.md */,
52+ 097824F81F87E21400064ADB /* Truther */,
53+ 097824F71F87E21400064ADB /* Products */,
54+ );
55+ sourceTree = "<group>";
56+ };
57+ 097824F71F87E21400064ADB /* Products */ = {
58+ isa = PBXGroup;
59+ children = (
60+ 097824F61F87E21400064ADB /* Truther */,
61+ );
62+ name = Products;
63+ sourceTree = "<group>";
64+ };
65+ 097824F81F87E21400064ADB /* Truther */ = {
66+ isa = PBXGroup;
67+ children = (
68+ 097824F91F87E21400064ADB /* main.swift */,
69+ 097825001F87E23000064ADB /* Truther.swift */,
70+ 091685E21F8834C800CC8645 /* Formatter.swift */,
71+ 097825021F87E48500064ADB /* Operator.swift */,
72+ );
73+ path = Truther;
74+ sourceTree = "<group>";
75+ };
76+/* End PBXGroup section */
77+
78+/* Begin PBXNativeTarget section */
79+ 097824F51F87E21400064ADB /* Truther */ = {
80+ isa = PBXNativeTarget;
81+ buildConfigurationList = 097824FD1F87E21400064ADB /* Build configuration list for PBXNativeTarget "Truther" */;
82+ buildPhases = (
83+ 097824F21F87E21400064ADB /* Sources */,
84+ 097824F31F87E21400064ADB /* Frameworks */,
85+ 097824F41F87E21400064ADB /* CopyFiles */,
86+ );
87+ buildRules = (
88+ );
89+ dependencies = (
90+ );
91+ name = Truther;
92+ productName = Truther;
93+ productReference = 097824F61F87E21400064ADB /* Truther */;
94+ productType = "com.apple.product-type.tool";
95+ };
96+/* End PBXNativeTarget section */
97+
98+/* Begin PBXProject section */
99+ 097824EE1F87E21400064ADB /* Project object */ = {
100+ isa = PBXProject;
101+ attributes = {
102+ LastSwiftUpdateCheck = 0900;
103+ LastUpgradeCheck = 0900;
104+ ORGANIZATIONNAME = "Ilya Kos";
105+ TargetAttributes = {
106+ 097824F51F87E21400064ADB = {
107+ CreatedOnToolsVersion = 9.0;
108+ ProvisioningStyle = Automatic;
109+ };
110+ };
111+ };
112+ buildConfigurationList = 097824F11F87E21400064ADB /* Build configuration list for PBXProject "Truther" */;
113+ compatibilityVersion = "Xcode 8.0";
114+ developmentRegion = en;
115+ hasScannedForEncodings = 0;
116+ knownRegions = (
117+ en,
118+ );
119+ mainGroup = 097824ED1F87E21400064ADB;
120+ productRefGroup = 097824F71F87E21400064ADB /* Products */;
121+ projectDirPath = "";
122+ projectRoot = "";
123+ targets = (
124+ 097824F51F87E21400064ADB /* Truther */,
125+ );
126+ };
127+/* End PBXProject section */
128+
129+/* Begin PBXSourcesBuildPhase section */
130+ 097824F21F87E21400064ADB /* Sources */ = {
131+ isa = PBXSourcesBuildPhase;
132+ buildActionMask = 2147483647;
133+ files = (
134+ 097825011F87E23000064ADB /* Truther.swift in Sources */,
135+ 097825031F87E48500064ADB /* Operator.swift in Sources */,
136+ 091685E31F8834C800CC8645 /* Formatter.swift in Sources */,
137+ 097824FA1F87E21400064ADB /* main.swift in Sources */,
138+ );
139+ runOnlyForDeploymentPostprocessing = 0;
140+ };
141+/* End PBXSourcesBuildPhase section */
142+
143+/* Begin XCBuildConfiguration section */
144+ 097824FB1F87E21400064ADB /* Debug */ = {
145+ isa = XCBuildConfiguration;
146+ buildSettings = {
147+ ALWAYS_SEARCH_USER_PATHS = NO;
148+ CLANG_ANALYZER_NONNULL = YES;
149+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
150+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
151+ CLANG_CXX_LIBRARY = "libc++";
152+ CLANG_ENABLE_MODULES = YES;
153+ CLANG_ENABLE_OBJC_ARC = YES;
154+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
155+ CLANG_WARN_BOOL_CONVERSION = YES;
156+ CLANG_WARN_COMMA = YES;
157+ CLANG_WARN_CONSTANT_CONVERSION = YES;
158+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
159+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
160+ CLANG_WARN_EMPTY_BODY = YES;
161+ CLANG_WARN_ENUM_CONVERSION = YES;
162+ CLANG_WARN_INFINITE_RECURSION = YES;
163+ CLANG_WARN_INT_CONVERSION = YES;
164+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
165+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
166+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
167+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
168+ CLANG_WARN_STRICT_PROTOTYPES = YES;
169+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
170+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
171+ CLANG_WARN_UNREACHABLE_CODE = YES;
172+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
173+ CODE_SIGN_IDENTITY = "Mac Developer";
174+ COPY_PHASE_STRIP = NO;
175+ DEBUG_INFORMATION_FORMAT = dwarf;
176+ ENABLE_STRICT_OBJC_MSGSEND = YES;
177+ ENABLE_TESTABILITY = YES;
178+ GCC_C_LANGUAGE_STANDARD = gnu11;
179+ GCC_DYNAMIC_NO_PIC = NO;
180+ GCC_NO_COMMON_BLOCKS = YES;
181+ GCC_OPTIMIZATION_LEVEL = 0;
182+ GCC_PREPROCESSOR_DEFINITIONS = (
183+ "DEBUG=1",
184+ "$(inherited)",
185+ );
186+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
187+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
188+ GCC_WARN_UNDECLARED_SELECTOR = YES;
189+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
190+ GCC_WARN_UNUSED_FUNCTION = YES;
191+ GCC_WARN_UNUSED_VARIABLE = YES;
192+ MACOSX_DEPLOYMENT_TARGET = 10.13;
193+ MTL_ENABLE_DEBUG_INFO = YES;
194+ ONLY_ACTIVE_ARCH = YES;
195+ SDKROOT = macosx;
196+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
197+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
198+ };
199+ name = Debug;
200+ };
201+ 097824FC1F87E21400064ADB /* Release */ = {
202+ isa = XCBuildConfiguration;
203+ buildSettings = {
204+ ALWAYS_SEARCH_USER_PATHS = NO;
205+ CLANG_ANALYZER_NONNULL = YES;
206+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
207+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
208+ CLANG_CXX_LIBRARY = "libc++";
209+ CLANG_ENABLE_MODULES = YES;
210+ CLANG_ENABLE_OBJC_ARC = YES;
211+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
212+ CLANG_WARN_BOOL_CONVERSION = YES;
213+ CLANG_WARN_COMMA = YES;
214+ CLANG_WARN_CONSTANT_CONVERSION = YES;
215+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
216+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
217+ CLANG_WARN_EMPTY_BODY = YES;
218+ CLANG_WARN_ENUM_CONVERSION = YES;
219+ CLANG_WARN_INFINITE_RECURSION = YES;
220+ CLANG_WARN_INT_CONVERSION = YES;
221+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
222+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
223+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
224+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
225+ CLANG_WARN_STRICT_PROTOTYPES = YES;
226+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
227+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
228+ CLANG_WARN_UNREACHABLE_CODE = YES;
229+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
230+ CODE_SIGN_IDENTITY = "Mac Developer";
231+ COPY_PHASE_STRIP = NO;
232+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
233+ ENABLE_NS_ASSERTIONS = NO;
234+ ENABLE_STRICT_OBJC_MSGSEND = YES;
235+ GCC_C_LANGUAGE_STANDARD = gnu11;
236+ GCC_NO_COMMON_BLOCKS = YES;
237+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
238+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
239+ GCC_WARN_UNDECLARED_SELECTOR = YES;
240+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
241+ GCC_WARN_UNUSED_FUNCTION = YES;
242+ GCC_WARN_UNUSED_VARIABLE = YES;
243+ MACOSX_DEPLOYMENT_TARGET = 10.13;
244+ MTL_ENABLE_DEBUG_INFO = NO;
245+ SDKROOT = macosx;
246+ SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
247+ };
248+ name = Release;
249+ };
250+ 097824FE1F87E21400064ADB /* Debug */ = {
251+ isa = XCBuildConfiguration;
252+ buildSettings = {
253+ CODE_SIGN_STYLE = Automatic;
254+ DEVELOPMENT_TEAM = 8J63JZYYHZ;
255+ PRODUCT_NAME = "$(TARGET_NAME)";
256+ SWIFT_VERSION = 4.0;
257+ };
258+ name = Debug;
259+ };
260+ 097824FF1F87E21400064ADB /* Release */ = {
261+ isa = XCBuildConfiguration;
262+ buildSettings = {
263+ CODE_SIGN_STYLE = Automatic;
264+ DEVELOPMENT_TEAM = 8J63JZYYHZ;
265+ PRODUCT_NAME = "$(TARGET_NAME)";
266+ SWIFT_VERSION = 4.0;
267+ };
268+ name = Release;
269+ };
270+/* End XCBuildConfiguration section */
271+
272+/* Begin XCConfigurationList section */
273+ 097824F11F87E21400064ADB /* Build configuration list for PBXProject "Truther" */ = {
274+ isa = XCConfigurationList;
275+ buildConfigurations = (
276+ 097824FB1F87E21400064ADB /* Debug */,
277+ 097824FC1F87E21400064ADB /* Release */,
278+ );
279+ defaultConfigurationIsVisible = 0;
280+ defaultConfigurationName = Release;
281+ };
282+ 097824FD1F87E21400064ADB /* Build configuration list for PBXNativeTarget "Truther" */ = {
283+ isa = XCConfigurationList;
284+ buildConfigurations = (
285+ 097824FE1F87E21400064ADB /* Debug */,
286+ 097824FF1F87E21400064ADB /* Release */,
287+ );
288+ defaultConfigurationIsVisible = 0;
289+ defaultConfigurationName = Release;
290+ };
291+/* End XCConfigurationList section */
292+ };
293+ rootObject = 097824EE1F87E21400064ADB /* Project object */;
294+}
Truther.xcodeproj/project.xcworkspace/contents.xcworkspacedatanew file+7
@@ -0,0 +1,7 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<Workspace
3+ version = "1.0">
4+ <FileRef
5+ location = "self:Truther.xcodeproj">
6+ </FileRef>
7+</Workspace>
Truther.xcodeproj/xcuserdata/ilya.xcuserdatad/xcschemes/xcschememanagement.plistnew file+22
@@ -0,0 +1,22 @@
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>SchemeUserState</key>
6+ <dict>
7+ <key>Truther.xcscheme</key>
8+ <dict>
9+ <key>orderHint</key>
10+ <integer>0</integer>
11+ </dict>
12+ </dict>
13+ <key>SuppressBuildableAutocreation</key>
14+ <dict>
15+ <key>097824F51F87E21400064ADB</key>
16+ <dict>
17+ <key>primary</key>
18+ <true/>
19+ </dict>
20+ </dict>
21+</dict>
22+</plist>
Truther/Formatter.swiftnew file+39
@@ -0,0 +1,39 @@
1+//
2+// Formatter.swift
3+// Truther
4+//
5+// Created by Ilya Kos on 10/7/17.
6+// Copyright © 2017 Ilya Kos. All rights reserved.
7+//
8+
9+import Foundation
10+
11+private let seperator = " | "
12+
13+class Formatter {
14+ static func format(table: [[String]]) -> String {
15+ var lengths: [Int] = []
16+ for i in 0..<table[0].count {
17+ var maxLength = 0
18+ for row in table {
19+ maxLength = max(maxLength, row[i].count)
20+ }
21+ lengths.append(maxLength)
22+ }
23+ var out = ""
24+ for i in 0..<table.count {
25+ let row = table[i]
26+ for u in 0..<row.count {
27+ out.append(row[u].padding(toLength: lengths[u], withPad: " ", startingAt: 0))
28+ out.append(seperator)
29+ }
30+ out = String(out.dropLast(seperator.count))
31+ out.append("\n")
32+ if i == 0 {
33+ out.append(String.init(repeating: "-", count: lengths.reduce(0, +) + seperator.count * (lengths.count - 1)))
34+ out.append("\n")
35+ }
36+ }
37+ return out
38+ }
39+}
Truther/Operator.swiftnew file+94
@@ -0,0 +1,94 @@
1+//
2+// Operator.swift
3+// Truther
4+//
5+// Created by Ilya Kos on 10/6/17.
6+// Copyright © 2017 Ilya Kos. All rights reserved.
7+//
8+
9+import Foundation
10+
11+enum Operator {
12+ case f0
13+ case f1
14+ case f2
15+ case f3
16+ case f4
17+ case f5
18+ case f6
19+ case f7
20+ case f8
21+ case f9
22+ case f10
23+ case f11
24+ case f12
25+ case f13
26+ case f14
27+ case f15
28+ var value: ((Bool, Bool) -> (Bool)) {
29+ switch self {
30+ case .f0:
31+ return {_, _ in false}
32+ case .f1:
33+ return {$0 && $1}
34+ case .f2:
35+ return { $0 && !$1 }
36+ case .f3:
37+ return {a, _ in a}
38+ case .f4:
39+ return {!$0 && $1}
40+ case .f5:
41+ return {_, b in b }
42+ case .f6:
43+ return {!($0 == $1)}
44+ case .f7:
45+ return {$0 || $1}
46+ case .f8:
47+ return {!($0 || $1)}
48+ case .f9:
49+ return {$0 == $1}
50+ case .f10:
51+ return {_, b in !b}
52+ case .f11:
53+ return {!(!$0 && $1)}
54+ case .f12:
55+ return {a, _ in !a}
56+ case .f13:
57+ return {!($0 && !$1)}
58+ case .f14:
59+ return {!($0 && $1)}
60+ case .f15:
61+ return {_, _ in true}
62+ }
63+ }
64+ static func process(_ op: Substring) -> Operator? {
65+ switch op.trimmingCharacters(in: .whitespaces).lowercased() {
66+ case "+", "or", "||":
67+ return .f7
68+ case "(+)", "⊕", "xor", "!=", "=!=", "=/=", "/=":
69+ return .f6
70+ case "*", "and", "&", "&&", "⚫︎":
71+ return .f1
72+ case "1":
73+ return .f15
74+ case "0":
75+ return .f0
76+ case "=/>", "=/=>", "-/>", "-/->", "!=>", "!->", "=!>", "-!>", "=!=>", "-!->":
77+ return .f2
78+ case "</=", "<=/=", "</-", "<-/-", "!<=", "!<-", "<!=", "<!-", "<=!=", "<-!-":
79+ return .f4
80+ case "o", "O", "о", "О", "◯", "⚬", "𐩒", "⚪︎", "nor", "web":
81+ return .f8
82+ case "=", "<=>", "==":
83+ return .f9
84+ case "<=", "<-", "<==", "<--":
85+ return .f11
86+ case "=>", "->", "==>", "-->":
87+ return .f13
88+ case "|", "nand", "shif":
89+ return .f14
90+ default:
91+ return nil
92+ }
93+ }
94+}
Truther/Truther.swiftnew file+159
@@ -0,0 +1,159 @@
1+//
2+// Truther.swift
3+// Truther
4+//
5+// Created by Ilya Kos on 10/6/17.
6+// Copyright © 2017 Ilya Kos. All rights reserved.
7+//
8+
9+import Foundation
10+
11+struct Truther {
12+ var formula: Formula
13+ func run() -> [(inp: [Bool], result: Bool)] {
14+ var out: [(inp: [Bool], result: Bool)] = []
15+ for i in 0..<Int(pow(2, Double(formula.variables.count))) {
16+ var t = 0
17+ var inp: [Bool] = []
18+ for _ in formula.variables {
19+ inp.append((UInt(i)>>t) & 1 == 1)
20+ t += 1
21+ }
22+ inp = inp.reversed()
23+ out.append((inp, formula.run(with: inp)))
24+ }
25+ return out
26+ }
27+}
28+
29+struct Formula {
30+ fileprivate func run(with inputs: [Bool]) -> Bool {
31+ var ins: [Variable: Bool] = [:]
32+ for (v, va) in zip(variables, inputs) {
33+ ins[v] = va
34+ }
35+ return value.evaluate(with: ins)
36+ }
37+ init(_ f: String) {
38+ var vars: Set<String> = Set()
39+ func process(_ s: Substring, startingLeft: FormulaElement? = nil) -> FormulaElement {
40+ if s.isEmpty {
41+ guard let startingLeft = startingLeft else {
42+ print("Internal error: Empty input")
43+ exit(1)
44+ }
45+ return startingLeft
46+ }
47+ var ns = s.trimmingCharacters(in: .whitespaces)
48+ if ns == "0" {
49+ return .constant(false)
50+ }
51+ if ns == "1" {
52+ return .constant(true)
53+ }
54+ if ns.trimmingCharacters(in: .whitespaces).reduce(true, {$0 && CharacterSet.letters.contains($1.unicodeScalars.first!)}) {
55+ vars.insert(String(s))
56+ return .variable(String(s))
57+ }
58+ func extractVar() -> Substring {
59+ if ns.first == "(" {
60+ let parts = extractBrackets(from: ns)
61+ ns = parts.after.trimmingCharacters(in: .whitespaces)
62+ return Substring(parts.wasInside.trimmingCharacters(in: .whitespaces))
63+ } else {
64+ if CharacterSet.whitespaces.contains((ns.first?.unicodeScalars.first)!) {
65+ print("Internal error: weird variable name first charecter \(ns.first!)")
66+ exit(1)
67+ }
68+ switch ns.first! {
69+ case "0":
70+ ns = ns.dropFirst().trimmingCharacters(in: .whitespaces)
71+ return "0"
72+ case "1":
73+ ns = ns.dropFirst().trimmingCharacters(in: .whitespaces)
74+ return "1"
75+ default:
76+ break
77+ }
78+ var i = ns.startIndex
79+ while i < ns.endIndex {
80+ if !CharacterSet.letters.contains(ns[i].unicodeScalars.first!) {
81+ break
82+ }
83+ i = ns.index(after: i)
84+ }
85+ let out = ns[..<i]
86+ ns = ns[i...].trimmingCharacters(in: .whitespaces)
87+ return out
88+ }
89+ }
90+ let left = startingLeft ?? process(extractVar())
91+ ns = ns.trimmingCharacters(in: .whitespaces)
92+ let isLetterOrNot = CharacterSet.letters.contains((ns.first?.unicodeScalars.first)!)
93+ var i = ns.startIndex
94+ while i < ns.endIndex {
95+ if CharacterSet.letters.contains(ns[i].unicodeScalars.first!) != isLetterOrNot || ns[i] == " " {
96+ break
97+ }
98+ i = ns.index(after: i)
99+ }
100+ guard let op = Operator.process(ns[..<i]) else {
101+ print("No such operator \(ns[..<i])")
102+ exit(1)
103+ }
104+ ns = ns[i...].trimmingCharacters(in: .whitespaces)
105+ let right = process(extractVar())
106+ return process(Substring(ns), startingLeft: .operation(left, op, right))
107+ }
108+ self.value = process(Substring(f))
109+ self.variables = vars.sorted()
110+ }
111+ let variables: [String]
112+ private let value: FormulaElement
113+}
114+
115+private func extractBrackets(from s: String) -> (wasInside: Substring, after: Substring) {
116+ var i = s.startIndex
117+ var brackets = 0
118+ while i < s.endIndex {
119+ switch s[i] {
120+ case "(":
121+ brackets += 1
122+ case ")":
123+ brackets -= 1
124+ default:
125+ break
126+ }
127+ if brackets == 0 {
128+ break
129+ }
130+ i = s.index(after: i)
131+ }
132+ if brackets != 0 {
133+ print("Mismatched brackets")
134+ exit(1)
135+ }
136+ return (s[s.index(after: s.startIndex)..<i], s[s.index(after: i)...])
137+}
138+
139+private typealias Variable = String
140+private indirect enum FormulaElement {
141+ case variable(Variable)
142+ case constant(Bool)
143+ case operation(FormulaElement, Operator, FormulaElement)
144+ func evaluate(with variables: [Variable: Bool]) -> Bool {
145+ switch self {
146+ case .variable(let v):
147+ if let va = variables[v] {
148+ return va
149+ } else {
150+ print("Internal error: didn't initialize all variables")
151+ exit(1)
152+ }
153+ case .operation(let l, let op, let r):
154+ return op.value(l.evaluate(with: variables), r.evaluate(with: variables))
155+ case .constant(let b):
156+ return b
157+ }
158+ }
159+}
Truther/main.swiftnew file+19
@@ -0,0 +1,19 @@
1+//
2+// main.swift
3+// Truther
4+//
5+// Created by Ilya Kos on 10/6/17.
6+// Copyright © 2017 Ilya Kos. All rights reserved.
7+//
8+
9+import Foundation
10+
11+if CommandLine.arguments.count > 1 {
12+ let form = Formula.init(CommandLine.arguments[1])
13+ let table = Truther.init(formula: form).run().map { $0.0 + [$0.1] }
14+ .map {$0.map {$0 ? "1" : "0"}}
15+
16+ print(Formatter.format(table: [form.variables + ["F"]] + table))
17+} else {
18+ print("You did't supply a formula")
19+}