├── .gitignore ├── LICENSE ├── Logo.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcshareddata │ └── xcschemes │ ├── Logo.xcscheme │ └── LogoCompilerTests.xcscheme ├── Logo ├── AppDelegate.swift ├── Assets.xcassets │ ├── >.imageset │ │ ├── >@2x.png │ │ ├── >@3x.png │ │ └── Contents.json │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon-App-20x20@1x.png │ │ ├── Icon-App-20x20@2x.png │ │ ├── Icon-App-20x20@3x.png │ │ ├── Icon-App-29x29@1x.png │ │ ├── Icon-App-29x29@2x.png │ │ ├── Icon-App-29x29@3x.png │ │ ├── Icon-App-40x40@1x.png │ │ ├── Icon-App-40x40@2x.png │ │ ├── Icon-App-40x40@3x.png │ │ ├── Icon-App-60x60@2x.png │ │ ├── Icon-App-60x60@3x.png │ │ ├── Icon-App-76x76@1x.png │ │ ├── Icon-App-76x76@2x.png │ │ ├── Icon-App-83.5x83.5@2x.png │ │ └── ItunesArtwork@2x.png │ └── Contents.json ├── Base.lproj │ └── Main.storyboard ├── Calculator │ └── Controller │ │ └── CalculatorViewController.swift ├── Info.plist ├── LaunchScreen.storyboard ├── Lexer │ ├── Controller │ │ └── LexerViewController.swift │ └── Model │ │ ├── Lexer.swift │ │ └── LexerItem.swift ├── Main │ ├── Controller │ │ ├── MainViewController+Plot.swift │ │ └── MainViewController.swift │ └── View │ │ └── DynamicTextLayer.swift └── REPL │ ├── Controller │ ├── REPLViewController+Plot.swift │ ├── REPLViewController+TableViewDataSource.swift │ ├── REPLViewController+TableViewDelegate.swift │ └── REPLViewController.swift │ └── Model │ └── Cmd.swift ├── LogoCompiler ├── AST │ ├── ASTNode.swift │ └── ASTNodeType.swift ├── Error │ └── LogoError.swift ├── Extension │ ├── Character+Extension.swift │ └── String+FontSize.swift ├── Info.plist ├── LogoCompiler.h ├── Simple │ ├── SimpleASTNode.swift │ ├── SimpleCalculator.swift │ ├── SimpleLexer.swift │ ├── SimpleParser.swift │ └── SimpleScript.swift ├── Token.swift ├── TokenReader.swift └── TokenType.swift ├── LogoCompilerTests ├── Info.plist ├── SimpleCalculatorTests.swift ├── SimpleLexerTests.swift ├── SimpleParserTests.swift └── SimpleScriptTests.swift ├── LogoTests ├── Info.plist └── LogoTests.swift ├── README.md └── screenshot ├── ast.png ├── ast2.png ├── editor.png ├── parse.png ├── repl.png └── token.png /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | ## Playgrounds 32 | timeline.xctimeline 33 | playground.xcworkspace 34 | 35 | # Swift Package Manager 36 | # 37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 38 | # Packages/ 39 | # Package.pins 40 | # Package.resolved 41 | .build/ 42 | 43 | # CocoaPods 44 | # 45 | # We recommend against adding the Pods directory to your .gitignore. However 46 | # you should judge for yourself, the pros and cons are mentioned at: 47 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 48 | # 49 | # Pods/ 50 | 51 | # Carthage 52 | # 53 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 54 | # Carthage/Checkouts 55 | 56 | Carthage/Build 57 | 58 | # fastlane 59 | # 60 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 61 | # screenshots whenever they are needed. 62 | # For more information about the recommended setup visit: 63 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 64 | 65 | fastlane/report.xml 66 | fastlane/Preview.html 67 | fastlane/screenshots/**/*.png 68 | fastlane/test_output 69 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 iOS Dev Log 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Logo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 8B082EDD230CD76100C4B7FE /* MainViewController+Plot.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B082EDC230CD76100C4B7FE /* MainViewController+Plot.swift */; }; 11 | 8B082EDF230CDD2D00C4B7FE /* String+FontSize.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B082EDE230CDD2D00C4B7FE /* String+FontSize.swift */; }; 12 | 8B082EE1230CDD4D00C4B7FE /* DynamicTextLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B082EE0230CDD4D00C4B7FE /* DynamicTextLayer.swift */; }; 13 | 8B082EE3230CF7DF00C4B7FE /* SimpleParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B082EE2230CF7DF00C4B7FE /* SimpleParser.swift */; }; 14 | 8B082EE5230CF94A00C4B7FE /* SimpleASTNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B082EE4230CF94A00C4B7FE /* SimpleASTNode.swift */; }; 15 | 8B082EE7230D165000C4B7FE /* SimpleParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B082EE6230D165000C4B7FE /* SimpleParserTests.swift */; }; 16 | 8B7057C0230FE6E8007D26C8 /* SimpleScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B7057BF230FE6E7007D26C8 /* SimpleScript.swift */; }; 17 | 8B7057C2230FF249007D26C8 /* SimpleScriptTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B7057C1230FF249007D26C8 /* SimpleScriptTests.swift */; }; 18 | 8BB49260230A54800045C41F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BB4925F230A54800045C41F /* AppDelegate.swift */; }; 19 | 8BB49262230A54800045C41F /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BB49261230A54800045C41F /* MainViewController.swift */; }; 20 | 8BB49265230A54800045C41F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8BB49263230A54800045C41F /* Main.storyboard */; }; 21 | 8BB49267230A548B0045C41F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8BB49266230A548B0045C41F /* Assets.xcassets */; }; 22 | 8BB49275230A548B0045C41F /* LogoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BB49274230A548B0045C41F /* LogoTests.swift */; }; 23 | 8BB4928D230A54F70045C41F /* LogoCompiler.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8BB49284230A54F60045C41F /* LogoCompiler.framework */; }; 24 | 8BB49294230A54F70045C41F /* SimpleCalculatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BB49293230A54F70045C41F /* SimpleCalculatorTests.swift */; }; 25 | 8BB49296230A54F70045C41F /* LogoCompiler.h in Headers */ = {isa = PBXBuildFile; fileRef = 8BB49286230A54F60045C41F /* LogoCompiler.h */; settings = {ATTRIBUTES = (Public, ); }; }; 26 | 8BB49299230A54F70045C41F /* LogoCompiler.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8BB49284230A54F60045C41F /* LogoCompiler.framework */; }; 27 | 8BB4929A230A54F70045C41F /* LogoCompiler.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 8BB49284230A54F60045C41F /* LogoCompiler.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 28 | 8BB492A3230A553D0045C41F /* SimpleLexer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BB492A2230A553D0045C41F /* SimpleLexer.swift */; }; 29 | 8BB492A5230A55550045C41F /* SimpleLexerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BB492A4230A55550045C41F /* SimpleLexerTests.swift */; }; 30 | 8BB492A7230A566E0045C41F /* TokenReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BB492A6230A566E0045C41F /* TokenReader.swift */; }; 31 | 8BB492A9230A569B0045C41F /* Token.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BB492A8230A569B0045C41F /* Token.swift */; }; 32 | 8BB492AB230A56B90045C41F /* TokenType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BB492AA230A56B90045C41F /* TokenType.swift */; }; 33 | 8BB492AD230A85230045C41F /* Character+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BB492AC230A85230045C41F /* Character+Extension.swift */; }; 34 | 8BB492AF230AA7470045C41F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8BB492AE230AA7470045C41F /* LaunchScreen.storyboard */; }; 35 | 8BB492B4230AA9CD0045C41F /* LexerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BB492B3230AA9CD0045C41F /* LexerViewController.swift */; }; 36 | 8BB492B8230AAB820045C41F /* Lexer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BB492B7230AAB820045C41F /* Lexer.swift */; }; 37 | 8BB492BA230AABAF0045C41F /* LexerItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BB492B9230AABAF0045C41F /* LexerItem.swift */; }; 38 | 8BB4A26B231518E90038F188 /* REPLViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BB4A26A231518E90038F188 /* REPLViewController.swift */; }; 39 | 8BB4A26D23151FFB0038F188 /* REPLViewController+TableViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BB4A26C23151FFB0038F188 /* REPLViewController+TableViewDataSource.swift */; }; 40 | 8BB4A2712315207F0038F188 /* Cmd.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BB4A2702315207F0038F188 /* Cmd.swift */; }; 41 | 8BB4A27523152BAF0038F188 /* REPLViewController+Plot.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BB4A27423152BAF0038F188 /* REPLViewController+Plot.swift */; }; 42 | 8BB4A2772315392D0038F188 /* REPLViewController+TableViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BB4A2762315392D0038F188 /* REPLViewController+TableViewDelegate.swift */; }; 43 | 8BF7500D230B82BF00632F35 /* SimpleCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BF7500C230B82BF00632F35 /* SimpleCalculator.swift */; }; 44 | 8BF7500F230B833500632F35 /* ASTNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BF7500E230B833500632F35 /* ASTNode.swift */; }; 45 | 8BF75011230B83D200632F35 /* ASTNodeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BF75010230B83D200632F35 /* ASTNodeType.swift */; }; 46 | 8BF75013230B8AE700632F35 /* LogoError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BF75012230B8AE700632F35 /* LogoError.swift */; }; 47 | 8BF75017230BA3B500632F35 /* CalculatorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BF75016230BA3B500632F35 /* CalculatorViewController.swift */; }; 48 | /* End PBXBuildFile section */ 49 | 50 | /* Begin PBXContainerItemProxy section */ 51 | 8BB49271230A548B0045C41F /* PBXContainerItemProxy */ = { 52 | isa = PBXContainerItemProxy; 53 | containerPortal = 8BB49254230A54800045C41F /* Project object */; 54 | proxyType = 1; 55 | remoteGlobalIDString = 8BB4925B230A54800045C41F; 56 | remoteInfo = Logo; 57 | }; 58 | 8BB4928E230A54F70045C41F /* PBXContainerItemProxy */ = { 59 | isa = PBXContainerItemProxy; 60 | containerPortal = 8BB49254230A54800045C41F /* Project object */; 61 | proxyType = 1; 62 | remoteGlobalIDString = 8BB49283230A54F60045C41F; 63 | remoteInfo = LogoCompiler; 64 | }; 65 | 8BB49290230A54F70045C41F /* PBXContainerItemProxy */ = { 66 | isa = PBXContainerItemProxy; 67 | containerPortal = 8BB49254230A54800045C41F /* Project object */; 68 | proxyType = 1; 69 | remoteGlobalIDString = 8BB4925B230A54800045C41F; 70 | remoteInfo = Logo; 71 | }; 72 | 8BB49297230A54F70045C41F /* PBXContainerItemProxy */ = { 73 | isa = PBXContainerItemProxy; 74 | containerPortal = 8BB49254230A54800045C41F /* Project object */; 75 | proxyType = 1; 76 | remoteGlobalIDString = 8BB49283230A54F60045C41F; 77 | remoteInfo = LogoCompiler; 78 | }; 79 | /* End PBXContainerItemProxy section */ 80 | 81 | /* Begin PBXCopyFilesBuildPhase section */ 82 | 8BB4929E230A54F80045C41F /* Embed Frameworks */ = { 83 | isa = PBXCopyFilesBuildPhase; 84 | buildActionMask = 2147483647; 85 | dstPath = ""; 86 | dstSubfolderSpec = 10; 87 | files = ( 88 | 8BB4929A230A54F70045C41F /* LogoCompiler.framework in Embed Frameworks */, 89 | ); 90 | name = "Embed Frameworks"; 91 | runOnlyForDeploymentPostprocessing = 0; 92 | }; 93 | /* End PBXCopyFilesBuildPhase section */ 94 | 95 | /* Begin PBXFileReference section */ 96 | 8B082EDC230CD76100C4B7FE /* MainViewController+Plot.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MainViewController+Plot.swift"; sourceTree = ""; }; 97 | 8B082EDE230CDD2D00C4B7FE /* String+FontSize.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+FontSize.swift"; sourceTree = ""; }; 98 | 8B082EE0230CDD4D00C4B7FE /* DynamicTextLayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DynamicTextLayer.swift; sourceTree = ""; }; 99 | 8B082EE2230CF7DF00C4B7FE /* SimpleParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleParser.swift; sourceTree = ""; }; 100 | 8B082EE4230CF94A00C4B7FE /* SimpleASTNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleASTNode.swift; sourceTree = ""; }; 101 | 8B082EE6230D165000C4B7FE /* SimpleParserTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleParserTests.swift; sourceTree = ""; }; 102 | 8B7057BF230FE6E7007D26C8 /* SimpleScript.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleScript.swift; sourceTree = ""; }; 103 | 8B7057C1230FF249007D26C8 /* SimpleScriptTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleScriptTests.swift; sourceTree = ""; }; 104 | 8BB4925C230A54800045C41F /* Logo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Logo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 105 | 8BB4925F230A54800045C41F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 106 | 8BB49261230A54800045C41F /* MainViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = ""; }; 107 | 8BB49264230A54800045C41F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 108 | 8BB49266230A548B0045C41F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 109 | 8BB4926B230A548B0045C41F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 110 | 8BB49270230A548B0045C41F /* LogoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LogoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 111 | 8BB49274230A548B0045C41F /* LogoTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogoTests.swift; sourceTree = ""; }; 112 | 8BB49276230A548B0045C41F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 113 | 8BB49284230A54F60045C41F /* LogoCompiler.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = LogoCompiler.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 114 | 8BB49286230A54F60045C41F /* LogoCompiler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LogoCompiler.h; sourceTree = ""; }; 115 | 8BB49287230A54F60045C41F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 116 | 8BB4928C230A54F60045C41F /* LogoCompilerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LogoCompilerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 117 | 8BB49293230A54F70045C41F /* SimpleCalculatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleCalculatorTests.swift; sourceTree = ""; }; 118 | 8BB49295230A54F70045C41F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 119 | 8BB492A2230A553D0045C41F /* SimpleLexer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleLexer.swift; sourceTree = ""; }; 120 | 8BB492A4230A55550045C41F /* SimpleLexerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleLexerTests.swift; sourceTree = ""; }; 121 | 8BB492A6230A566E0045C41F /* TokenReader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = TokenReader.swift; path = ../TokenReader.swift; sourceTree = ""; }; 122 | 8BB492A8230A569B0045C41F /* Token.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Token.swift; path = ../Token.swift; sourceTree = ""; }; 123 | 8BB492AA230A56B90045C41F /* TokenType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = TokenType.swift; path = ../TokenType.swift; sourceTree = ""; }; 124 | 8BB492AC230A85230045C41F /* Character+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Character+Extension.swift"; sourceTree = ""; }; 125 | 8BB492AE230AA7470045C41F /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; 126 | 8BB492B3230AA9CD0045C41F /* LexerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LexerViewController.swift; sourceTree = ""; }; 127 | 8BB492B7230AAB820045C41F /* Lexer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Lexer.swift; sourceTree = ""; }; 128 | 8BB492B9230AABAF0045C41F /* LexerItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LexerItem.swift; sourceTree = ""; }; 129 | 8BB4A26A231518E90038F188 /* REPLViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = REPLViewController.swift; sourceTree = ""; }; 130 | 8BB4A26C23151FFB0038F188 /* REPLViewController+TableViewDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "REPLViewController+TableViewDataSource.swift"; sourceTree = ""; }; 131 | 8BB4A2702315207F0038F188 /* Cmd.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Cmd.swift; sourceTree = ""; }; 132 | 8BB4A27423152BAF0038F188 /* REPLViewController+Plot.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "REPLViewController+Plot.swift"; sourceTree = ""; }; 133 | 8BB4A2762315392D0038F188 /* REPLViewController+TableViewDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "REPLViewController+TableViewDelegate.swift"; sourceTree = ""; }; 134 | 8BF7500C230B82BF00632F35 /* SimpleCalculator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleCalculator.swift; sourceTree = ""; }; 135 | 8BF7500E230B833500632F35 /* ASTNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ASTNode.swift; sourceTree = ""; }; 136 | 8BF75010230B83D200632F35 /* ASTNodeType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ASTNodeType.swift; sourceTree = ""; }; 137 | 8BF75012230B8AE700632F35 /* LogoError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogoError.swift; sourceTree = ""; }; 138 | 8BF75016230BA3B500632F35 /* CalculatorViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalculatorViewController.swift; sourceTree = ""; }; 139 | /* End PBXFileReference section */ 140 | 141 | /* Begin PBXFrameworksBuildPhase section */ 142 | 8BB49259230A54800045C41F /* Frameworks */ = { 143 | isa = PBXFrameworksBuildPhase; 144 | buildActionMask = 2147483647; 145 | files = ( 146 | 8BB49299230A54F70045C41F /* LogoCompiler.framework in Frameworks */, 147 | ); 148 | runOnlyForDeploymentPostprocessing = 0; 149 | }; 150 | 8BB4926D230A548B0045C41F /* Frameworks */ = { 151 | isa = PBXFrameworksBuildPhase; 152 | buildActionMask = 2147483647; 153 | files = ( 154 | ); 155 | runOnlyForDeploymentPostprocessing = 0; 156 | }; 157 | 8BB49281230A54F60045C41F /* Frameworks */ = { 158 | isa = PBXFrameworksBuildPhase; 159 | buildActionMask = 2147483647; 160 | files = ( 161 | ); 162 | runOnlyForDeploymentPostprocessing = 0; 163 | }; 164 | 8BB49289230A54F60045C41F /* Frameworks */ = { 165 | isa = PBXFrameworksBuildPhase; 166 | buildActionMask = 2147483647; 167 | files = ( 168 | 8BB4928D230A54F70045C41F /* LogoCompiler.framework in Frameworks */, 169 | ); 170 | runOnlyForDeploymentPostprocessing = 0; 171 | }; 172 | /* End PBXFrameworksBuildPhase section */ 173 | 174 | /* Begin PBXGroup section */ 175 | 8B082ED4230BFAC600C4B7FE /* View */ = { 176 | isa = PBXGroup; 177 | children = ( 178 | 8B082EE0230CDD4D00C4B7FE /* DynamicTextLayer.swift */, 179 | ); 180 | path = View; 181 | sourceTree = ""; 182 | }; 183 | 8B082ED7230CD60600C4B7FE /* Token */ = { 184 | isa = PBXGroup; 185 | children = ( 186 | 8BB492A6230A566E0045C41F /* TokenReader.swift */, 187 | 8BB492A8230A569B0045C41F /* Token.swift */, 188 | 8BB492AA230A56B90045C41F /* TokenType.swift */, 189 | ); 190 | path = Token; 191 | sourceTree = ""; 192 | }; 193 | 8B082ED8230CD65500C4B7FE /* AST */ = { 194 | isa = PBXGroup; 195 | children = ( 196 | 8BF7500E230B833500632F35 /* ASTNode.swift */, 197 | 8BF75010230B83D200632F35 /* ASTNodeType.swift */, 198 | ); 199 | path = AST; 200 | sourceTree = ""; 201 | }; 202 | 8B082ED9230CD66100C4B7FE /* Extension */ = { 203 | isa = PBXGroup; 204 | children = ( 205 | 8BB492AC230A85230045C41F /* Character+Extension.swift */, 206 | 8B082EDE230CDD2D00C4B7FE /* String+FontSize.swift */, 207 | ); 208 | path = Extension; 209 | sourceTree = ""; 210 | }; 211 | 8B082EDA230CD66E00C4B7FE /* Simple */ = { 212 | isa = PBXGroup; 213 | children = ( 214 | 8B082EE4230CF94A00C4B7FE /* SimpleASTNode.swift */, 215 | 8BB492A2230A553D0045C41F /* SimpleLexer.swift */, 216 | 8BF7500C230B82BF00632F35 /* SimpleCalculator.swift */, 217 | 8B082EE2230CF7DF00C4B7FE /* SimpleParser.swift */, 218 | 8B7057BF230FE6E7007D26C8 /* SimpleScript.swift */, 219 | ); 220 | path = Simple; 221 | sourceTree = ""; 222 | }; 223 | 8B082EDB230CD67C00C4B7FE /* Error */ = { 224 | isa = PBXGroup; 225 | children = ( 226 | 8BF75012230B8AE700632F35 /* LogoError.swift */, 227 | ); 228 | path = Error; 229 | sourceTree = ""; 230 | }; 231 | 8BB49253230A54800045C41F = { 232 | isa = PBXGroup; 233 | children = ( 234 | 8BB4925E230A54800045C41F /* Logo */, 235 | 8BB49273230A548B0045C41F /* LogoTests */, 236 | 8BB49285230A54F60045C41F /* LogoCompiler */, 237 | 8BB49292230A54F70045C41F /* LogoCompilerTests */, 238 | 8BB4925D230A54800045C41F /* Products */, 239 | ); 240 | sourceTree = ""; 241 | }; 242 | 8BB4925D230A54800045C41F /* Products */ = { 243 | isa = PBXGroup; 244 | children = ( 245 | 8BB4925C230A54800045C41F /* Logo.app */, 246 | 8BB49270230A548B0045C41F /* LogoTests.xctest */, 247 | 8BB49284230A54F60045C41F /* LogoCompiler.framework */, 248 | 8BB4928C230A54F60045C41F /* LogoCompilerTests.xctest */, 249 | ); 250 | name = Products; 251 | sourceTree = ""; 252 | }; 253 | 8BB4925E230A54800045C41F /* Logo */ = { 254 | isa = PBXGroup; 255 | children = ( 256 | 8BB4A268231517360038F188 /* REPL */, 257 | 8BF75014230BA36500632F35 /* Calculator */, 258 | 8BB492BB230AB4780045C41F /* Main */, 259 | 8BB492B2230AA9BB0045C41F /* Lexer */, 260 | 8BB4925F230A54800045C41F /* AppDelegate.swift */, 261 | 8BB49263230A54800045C41F /* Main.storyboard */, 262 | 8BB49266230A548B0045C41F /* Assets.xcassets */, 263 | 8BB4926B230A548B0045C41F /* Info.plist */, 264 | 8BB492AE230AA7470045C41F /* LaunchScreen.storyboard */, 265 | ); 266 | path = Logo; 267 | sourceTree = ""; 268 | }; 269 | 8BB49273230A548B0045C41F /* LogoTests */ = { 270 | isa = PBXGroup; 271 | children = ( 272 | 8BB49274230A548B0045C41F /* LogoTests.swift */, 273 | 8BB49276230A548B0045C41F /* Info.plist */, 274 | ); 275 | path = LogoTests; 276 | sourceTree = ""; 277 | }; 278 | 8BB49285230A54F60045C41F /* LogoCompiler */ = { 279 | isa = PBXGroup; 280 | children = ( 281 | 8BB49286230A54F60045C41F /* LogoCompiler.h */, 282 | 8BB49287230A54F60045C41F /* Info.plist */, 283 | 8B082ED7230CD60600C4B7FE /* Token */, 284 | 8B082ED9230CD66100C4B7FE /* Extension */, 285 | 8B082ED8230CD65500C4B7FE /* AST */, 286 | 8B082EDA230CD66E00C4B7FE /* Simple */, 287 | 8B082EDB230CD67C00C4B7FE /* Error */, 288 | ); 289 | path = LogoCompiler; 290 | sourceTree = ""; 291 | }; 292 | 8BB49292230A54F70045C41F /* LogoCompilerTests */ = { 293 | isa = PBXGroup; 294 | children = ( 295 | 8BB49295230A54F70045C41F /* Info.plist */, 296 | 8BB492A4230A55550045C41F /* SimpleLexerTests.swift */, 297 | 8BB49293230A54F70045C41F /* SimpleCalculatorTests.swift */, 298 | 8B082EE6230D165000C4B7FE /* SimpleParserTests.swift */, 299 | 8B7057C1230FF249007D26C8 /* SimpleScriptTests.swift */, 300 | ); 301 | path = LogoCompilerTests; 302 | sourceTree = ""; 303 | }; 304 | 8BB492B2230AA9BB0045C41F /* Lexer */ = { 305 | isa = PBXGroup; 306 | children = ( 307 | 8BB492B6230AAB610045C41F /* Controller */, 308 | 8BB492B5230AAB5A0045C41F /* Model */, 309 | ); 310 | path = Lexer; 311 | sourceTree = ""; 312 | }; 313 | 8BB492B5230AAB5A0045C41F /* Model */ = { 314 | isa = PBXGroup; 315 | children = ( 316 | 8BB492B7230AAB820045C41F /* Lexer.swift */, 317 | 8BB492B9230AABAF0045C41F /* LexerItem.swift */, 318 | ); 319 | path = Model; 320 | sourceTree = ""; 321 | }; 322 | 8BB492B6230AAB610045C41F /* Controller */ = { 323 | isa = PBXGroup; 324 | children = ( 325 | 8BB492B3230AA9CD0045C41F /* LexerViewController.swift */, 326 | ); 327 | path = Controller; 328 | sourceTree = ""; 329 | }; 330 | 8BB492BB230AB4780045C41F /* Main */ = { 331 | isa = PBXGroup; 332 | children = ( 333 | 8B082ED4230BFAC600C4B7FE /* View */, 334 | 8BB492BC230AB47E0045C41F /* Controller */, 335 | ); 336 | path = Main; 337 | sourceTree = ""; 338 | }; 339 | 8BB492BC230AB47E0045C41F /* Controller */ = { 340 | isa = PBXGroup; 341 | children = ( 342 | 8BB49261230A54800045C41F /* MainViewController.swift */, 343 | 8B082EDC230CD76100C4B7FE /* MainViewController+Plot.swift */, 344 | ); 345 | path = Controller; 346 | sourceTree = ""; 347 | }; 348 | 8BB4A268231517360038F188 /* REPL */ = { 349 | isa = PBXGroup; 350 | children = ( 351 | 8BB4A26F231520660038F188 /* Model */, 352 | 8BB4A2692315174C0038F188 /* Controller */, 353 | ); 354 | path = REPL; 355 | sourceTree = ""; 356 | }; 357 | 8BB4A2692315174C0038F188 /* Controller */ = { 358 | isa = PBXGroup; 359 | children = ( 360 | 8BB4A26A231518E90038F188 /* REPLViewController.swift */, 361 | 8BB4A26C23151FFB0038F188 /* REPLViewController+TableViewDataSource.swift */, 362 | 8BB4A2762315392D0038F188 /* REPLViewController+TableViewDelegate.swift */, 363 | 8BB4A27423152BAF0038F188 /* REPLViewController+Plot.swift */, 364 | ); 365 | path = Controller; 366 | sourceTree = ""; 367 | }; 368 | 8BB4A26F231520660038F188 /* Model */ = { 369 | isa = PBXGroup; 370 | children = ( 371 | 8BB4A2702315207F0038F188 /* Cmd.swift */, 372 | ); 373 | path = Model; 374 | sourceTree = ""; 375 | }; 376 | 8BF75014230BA36500632F35 /* Calculator */ = { 377 | isa = PBXGroup; 378 | children = ( 379 | 8BF75015230BA37A00632F35 /* Controller */, 380 | ); 381 | path = Calculator; 382 | sourceTree = ""; 383 | }; 384 | 8BF75015230BA37A00632F35 /* Controller */ = { 385 | isa = PBXGroup; 386 | children = ( 387 | 8BF75016230BA3B500632F35 /* CalculatorViewController.swift */, 388 | ); 389 | path = Controller; 390 | sourceTree = ""; 391 | }; 392 | /* End PBXGroup section */ 393 | 394 | /* Begin PBXHeadersBuildPhase section */ 395 | 8BB4927F230A54F60045C41F /* Headers */ = { 396 | isa = PBXHeadersBuildPhase; 397 | buildActionMask = 2147483647; 398 | files = ( 399 | 8BB49296230A54F70045C41F /* LogoCompiler.h in Headers */, 400 | ); 401 | runOnlyForDeploymentPostprocessing = 0; 402 | }; 403 | /* End PBXHeadersBuildPhase section */ 404 | 405 | /* Begin PBXNativeTarget section */ 406 | 8BB4925B230A54800045C41F /* Logo */ = { 407 | isa = PBXNativeTarget; 408 | buildConfigurationList = 8BB49279230A548B0045C41F /* Build configuration list for PBXNativeTarget "Logo" */; 409 | buildPhases = ( 410 | 8BB49258230A54800045C41F /* Sources */, 411 | 8BB49259230A54800045C41F /* Frameworks */, 412 | 8BB4925A230A54800045C41F /* Resources */, 413 | 8BB4929E230A54F80045C41F /* Embed Frameworks */, 414 | ); 415 | buildRules = ( 416 | ); 417 | dependencies = ( 418 | 8BB49298230A54F70045C41F /* PBXTargetDependency */, 419 | ); 420 | name = Logo; 421 | productName = Logo; 422 | productReference = 8BB4925C230A54800045C41F /* Logo.app */; 423 | productType = "com.apple.product-type.application"; 424 | }; 425 | 8BB4926F230A548B0045C41F /* LogoTests */ = { 426 | isa = PBXNativeTarget; 427 | buildConfigurationList = 8BB4927C230A548B0045C41F /* Build configuration list for PBXNativeTarget "LogoTests" */; 428 | buildPhases = ( 429 | 8BB4926C230A548B0045C41F /* Sources */, 430 | 8BB4926D230A548B0045C41F /* Frameworks */, 431 | 8BB4926E230A548B0045C41F /* Resources */, 432 | ); 433 | buildRules = ( 434 | ); 435 | dependencies = ( 436 | 8BB49272230A548B0045C41F /* PBXTargetDependency */, 437 | ); 438 | name = LogoTests; 439 | productName = LogoTests; 440 | productReference = 8BB49270230A548B0045C41F /* LogoTests.xctest */; 441 | productType = "com.apple.product-type.bundle.unit-test"; 442 | }; 443 | 8BB49283230A54F60045C41F /* LogoCompiler */ = { 444 | isa = PBXNativeTarget; 445 | buildConfigurationList = 8BB4929B230A54F80045C41F /* Build configuration list for PBXNativeTarget "LogoCompiler" */; 446 | buildPhases = ( 447 | 8BB4927F230A54F60045C41F /* Headers */, 448 | 8BB49280230A54F60045C41F /* Sources */, 449 | 8BB49281230A54F60045C41F /* Frameworks */, 450 | 8BB49282230A54F60045C41F /* Resources */, 451 | ); 452 | buildRules = ( 453 | ); 454 | dependencies = ( 455 | ); 456 | name = LogoCompiler; 457 | productName = LogoCompiler; 458 | productReference = 8BB49284230A54F60045C41F /* LogoCompiler.framework */; 459 | productType = "com.apple.product-type.framework"; 460 | }; 461 | 8BB4928B230A54F60045C41F /* LogoCompilerTests */ = { 462 | isa = PBXNativeTarget; 463 | buildConfigurationList = 8BB4929F230A54F80045C41F /* Build configuration list for PBXNativeTarget "LogoCompilerTests" */; 464 | buildPhases = ( 465 | 8BB49288230A54F60045C41F /* Sources */, 466 | 8BB49289230A54F60045C41F /* Frameworks */, 467 | 8BB4928A230A54F60045C41F /* Resources */, 468 | ); 469 | buildRules = ( 470 | ); 471 | dependencies = ( 472 | 8BB4928F230A54F70045C41F /* PBXTargetDependency */, 473 | 8BB49291230A54F70045C41F /* PBXTargetDependency */, 474 | ); 475 | name = LogoCompilerTests; 476 | productName = LogoCompilerTests; 477 | productReference = 8BB4928C230A54F60045C41F /* LogoCompilerTests.xctest */; 478 | productType = "com.apple.product-type.bundle.unit-test"; 479 | }; 480 | /* End PBXNativeTarget section */ 481 | 482 | /* Begin PBXProject section */ 483 | 8BB49254230A54800045C41F /* Project object */ = { 484 | isa = PBXProject; 485 | attributes = { 486 | LastSwiftUpdateCheck = 1030; 487 | LastUpgradeCheck = 1030; 488 | ORGANIZATIONNAME = iOSDevLog; 489 | TargetAttributes = { 490 | 8BB4925B230A54800045C41F = { 491 | CreatedOnToolsVersion = 10.3; 492 | }; 493 | 8BB4926F230A548B0045C41F = { 494 | CreatedOnToolsVersion = 10.3; 495 | TestTargetID = 8BB4925B230A54800045C41F; 496 | }; 497 | 8BB49283230A54F60045C41F = { 498 | CreatedOnToolsVersion = 10.3; 499 | LastSwiftMigration = 1030; 500 | }; 501 | 8BB4928B230A54F60045C41F = { 502 | CreatedOnToolsVersion = 10.3; 503 | TestTargetID = 8BB4925B230A54800045C41F; 504 | }; 505 | }; 506 | }; 507 | buildConfigurationList = 8BB49257230A54800045C41F /* Build configuration list for PBXProject "Logo" */; 508 | compatibilityVersion = "Xcode 9.3"; 509 | developmentRegion = en; 510 | hasScannedForEncodings = 0; 511 | knownRegions = ( 512 | en, 513 | Base, 514 | ); 515 | mainGroup = 8BB49253230A54800045C41F; 516 | productRefGroup = 8BB4925D230A54800045C41F /* Products */; 517 | projectDirPath = ""; 518 | projectRoot = ""; 519 | targets = ( 520 | 8BB4925B230A54800045C41F /* Logo */, 521 | 8BB4926F230A548B0045C41F /* LogoTests */, 522 | 8BB49283230A54F60045C41F /* LogoCompiler */, 523 | 8BB4928B230A54F60045C41F /* LogoCompilerTests */, 524 | ); 525 | }; 526 | /* End PBXProject section */ 527 | 528 | /* Begin PBXResourcesBuildPhase section */ 529 | 8BB4925A230A54800045C41F /* Resources */ = { 530 | isa = PBXResourcesBuildPhase; 531 | buildActionMask = 2147483647; 532 | files = ( 533 | 8BB492AF230AA7470045C41F /* LaunchScreen.storyboard in Resources */, 534 | 8BB49267230A548B0045C41F /* Assets.xcassets in Resources */, 535 | 8BB49265230A54800045C41F /* Main.storyboard in Resources */, 536 | ); 537 | runOnlyForDeploymentPostprocessing = 0; 538 | }; 539 | 8BB4926E230A548B0045C41F /* Resources */ = { 540 | isa = PBXResourcesBuildPhase; 541 | buildActionMask = 2147483647; 542 | files = ( 543 | ); 544 | runOnlyForDeploymentPostprocessing = 0; 545 | }; 546 | 8BB49282230A54F60045C41F /* Resources */ = { 547 | isa = PBXResourcesBuildPhase; 548 | buildActionMask = 2147483647; 549 | files = ( 550 | ); 551 | runOnlyForDeploymentPostprocessing = 0; 552 | }; 553 | 8BB4928A230A54F60045C41F /* Resources */ = { 554 | isa = PBXResourcesBuildPhase; 555 | buildActionMask = 2147483647; 556 | files = ( 557 | ); 558 | runOnlyForDeploymentPostprocessing = 0; 559 | }; 560 | /* End PBXResourcesBuildPhase section */ 561 | 562 | /* Begin PBXSourcesBuildPhase section */ 563 | 8BB49258230A54800045C41F /* Sources */ = { 564 | isa = PBXSourcesBuildPhase; 565 | buildActionMask = 2147483647; 566 | files = ( 567 | 8BB4A2712315207F0038F188 /* Cmd.swift in Sources */, 568 | 8B082EE1230CDD4D00C4B7FE /* DynamicTextLayer.swift in Sources */, 569 | 8B082EDD230CD76100C4B7FE /* MainViewController+Plot.swift in Sources */, 570 | 8BB49262230A54800045C41F /* MainViewController.swift in Sources */, 571 | 8BB49260230A54800045C41F /* AppDelegate.swift in Sources */, 572 | 8BB4A26B231518E90038F188 /* REPLViewController.swift in Sources */, 573 | 8BB492B8230AAB820045C41F /* Lexer.swift in Sources */, 574 | 8BB4A26D23151FFB0038F188 /* REPLViewController+TableViewDataSource.swift in Sources */, 575 | 8BB4A27523152BAF0038F188 /* REPLViewController+Plot.swift in Sources */, 576 | 8BB492BA230AABAF0045C41F /* LexerItem.swift in Sources */, 577 | 8BB4A2772315392D0038F188 /* REPLViewController+TableViewDelegate.swift in Sources */, 578 | 8BF75017230BA3B500632F35 /* CalculatorViewController.swift in Sources */, 579 | 8BB492B4230AA9CD0045C41F /* LexerViewController.swift in Sources */, 580 | ); 581 | runOnlyForDeploymentPostprocessing = 0; 582 | }; 583 | 8BB4926C230A548B0045C41F /* Sources */ = { 584 | isa = PBXSourcesBuildPhase; 585 | buildActionMask = 2147483647; 586 | files = ( 587 | 8BB49275230A548B0045C41F /* LogoTests.swift in Sources */, 588 | ); 589 | runOnlyForDeploymentPostprocessing = 0; 590 | }; 591 | 8BB49280230A54F60045C41F /* Sources */ = { 592 | isa = PBXSourcesBuildPhase; 593 | buildActionMask = 2147483647; 594 | files = ( 595 | 8BB492A9230A569B0045C41F /* Token.swift in Sources */, 596 | 8BF7500F230B833500632F35 /* ASTNode.swift in Sources */, 597 | 8BB492AD230A85230045C41F /* Character+Extension.swift in Sources */, 598 | 8B7057C0230FE6E8007D26C8 /* SimpleScript.swift in Sources */, 599 | 8BB492AB230A56B90045C41F /* TokenType.swift in Sources */, 600 | 8BF75011230B83D200632F35 /* ASTNodeType.swift in Sources */, 601 | 8BF7500D230B82BF00632F35 /* SimpleCalculator.swift in Sources */, 602 | 8B082EE5230CF94A00C4B7FE /* SimpleASTNode.swift in Sources */, 603 | 8B082EDF230CDD2D00C4B7FE /* String+FontSize.swift in Sources */, 604 | 8BF75013230B8AE700632F35 /* LogoError.swift in Sources */, 605 | 8B082EE3230CF7DF00C4B7FE /* SimpleParser.swift in Sources */, 606 | 8BB492A7230A566E0045C41F /* TokenReader.swift in Sources */, 607 | 8BB492A3230A553D0045C41F /* SimpleLexer.swift in Sources */, 608 | ); 609 | runOnlyForDeploymentPostprocessing = 0; 610 | }; 611 | 8BB49288230A54F60045C41F /* Sources */ = { 612 | isa = PBXSourcesBuildPhase; 613 | buildActionMask = 2147483647; 614 | files = ( 615 | 8B7057C2230FF249007D26C8 /* SimpleScriptTests.swift in Sources */, 616 | 8BB492A5230A55550045C41F /* SimpleLexerTests.swift in Sources */, 617 | 8B082EE7230D165000C4B7FE /* SimpleParserTests.swift in Sources */, 618 | 8BB49294230A54F70045C41F /* SimpleCalculatorTests.swift in Sources */, 619 | ); 620 | runOnlyForDeploymentPostprocessing = 0; 621 | }; 622 | /* End PBXSourcesBuildPhase section */ 623 | 624 | /* Begin PBXTargetDependency section */ 625 | 8BB49272230A548B0045C41F /* PBXTargetDependency */ = { 626 | isa = PBXTargetDependency; 627 | target = 8BB4925B230A54800045C41F /* Logo */; 628 | targetProxy = 8BB49271230A548B0045C41F /* PBXContainerItemProxy */; 629 | }; 630 | 8BB4928F230A54F70045C41F /* PBXTargetDependency */ = { 631 | isa = PBXTargetDependency; 632 | target = 8BB49283230A54F60045C41F /* LogoCompiler */; 633 | targetProxy = 8BB4928E230A54F70045C41F /* PBXContainerItemProxy */; 634 | }; 635 | 8BB49291230A54F70045C41F /* PBXTargetDependency */ = { 636 | isa = PBXTargetDependency; 637 | target = 8BB4925B230A54800045C41F /* Logo */; 638 | targetProxy = 8BB49290230A54F70045C41F /* PBXContainerItemProxy */; 639 | }; 640 | 8BB49298230A54F70045C41F /* PBXTargetDependency */ = { 641 | isa = PBXTargetDependency; 642 | target = 8BB49283230A54F60045C41F /* LogoCompiler */; 643 | targetProxy = 8BB49297230A54F70045C41F /* PBXContainerItemProxy */; 644 | }; 645 | /* End PBXTargetDependency section */ 646 | 647 | /* Begin PBXVariantGroup section */ 648 | 8BB49263230A54800045C41F /* Main.storyboard */ = { 649 | isa = PBXVariantGroup; 650 | children = ( 651 | 8BB49264230A54800045C41F /* Base */, 652 | ); 653 | name = Main.storyboard; 654 | sourceTree = ""; 655 | }; 656 | /* End PBXVariantGroup section */ 657 | 658 | /* Begin XCBuildConfiguration section */ 659 | 8BB49277230A548B0045C41F /* Debug */ = { 660 | isa = XCBuildConfiguration; 661 | buildSettings = { 662 | ALWAYS_SEARCH_USER_PATHS = NO; 663 | CLANG_ANALYZER_NONNULL = YES; 664 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 665 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 666 | CLANG_CXX_LIBRARY = "libc++"; 667 | CLANG_ENABLE_MODULES = YES; 668 | CLANG_ENABLE_OBJC_ARC = YES; 669 | CLANG_ENABLE_OBJC_WEAK = YES; 670 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 671 | CLANG_WARN_BOOL_CONVERSION = YES; 672 | CLANG_WARN_COMMA = YES; 673 | CLANG_WARN_CONSTANT_CONVERSION = YES; 674 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 675 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 676 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 677 | CLANG_WARN_EMPTY_BODY = YES; 678 | CLANG_WARN_ENUM_CONVERSION = YES; 679 | CLANG_WARN_INFINITE_RECURSION = YES; 680 | CLANG_WARN_INT_CONVERSION = YES; 681 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 682 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 683 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 684 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 685 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 686 | CLANG_WARN_STRICT_PROTOTYPES = YES; 687 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 688 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 689 | CLANG_WARN_UNREACHABLE_CODE = YES; 690 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 691 | CODE_SIGN_IDENTITY = "iPhone Developer"; 692 | COPY_PHASE_STRIP = NO; 693 | DEBUG_INFORMATION_FORMAT = dwarf; 694 | ENABLE_STRICT_OBJC_MSGSEND = YES; 695 | ENABLE_TESTABILITY = YES; 696 | GCC_C_LANGUAGE_STANDARD = gnu11; 697 | GCC_DYNAMIC_NO_PIC = NO; 698 | GCC_NO_COMMON_BLOCKS = YES; 699 | GCC_OPTIMIZATION_LEVEL = 0; 700 | GCC_PREPROCESSOR_DEFINITIONS = ( 701 | "DEBUG=1", 702 | "$(inherited)", 703 | ); 704 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 705 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 706 | GCC_WARN_UNDECLARED_SELECTOR = YES; 707 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 708 | GCC_WARN_UNUSED_FUNCTION = YES; 709 | GCC_WARN_UNUSED_VARIABLE = YES; 710 | IPHONEOS_DEPLOYMENT_TARGET = 12.4; 711 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 712 | MTL_FAST_MATH = YES; 713 | ONLY_ACTIVE_ARCH = YES; 714 | SDKROOT = iphoneos; 715 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 716 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 717 | }; 718 | name = Debug; 719 | }; 720 | 8BB49278230A548B0045C41F /* Release */ = { 721 | isa = XCBuildConfiguration; 722 | buildSettings = { 723 | ALWAYS_SEARCH_USER_PATHS = NO; 724 | CLANG_ANALYZER_NONNULL = YES; 725 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 726 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 727 | CLANG_CXX_LIBRARY = "libc++"; 728 | CLANG_ENABLE_MODULES = YES; 729 | CLANG_ENABLE_OBJC_ARC = YES; 730 | CLANG_ENABLE_OBJC_WEAK = YES; 731 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 732 | CLANG_WARN_BOOL_CONVERSION = YES; 733 | CLANG_WARN_COMMA = YES; 734 | CLANG_WARN_CONSTANT_CONVERSION = YES; 735 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 736 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 737 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 738 | CLANG_WARN_EMPTY_BODY = YES; 739 | CLANG_WARN_ENUM_CONVERSION = YES; 740 | CLANG_WARN_INFINITE_RECURSION = YES; 741 | CLANG_WARN_INT_CONVERSION = YES; 742 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 743 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 744 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 745 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 746 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 747 | CLANG_WARN_STRICT_PROTOTYPES = YES; 748 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 749 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 750 | CLANG_WARN_UNREACHABLE_CODE = YES; 751 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 752 | CODE_SIGN_IDENTITY = "iPhone Developer"; 753 | COPY_PHASE_STRIP = NO; 754 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 755 | ENABLE_NS_ASSERTIONS = NO; 756 | ENABLE_STRICT_OBJC_MSGSEND = YES; 757 | GCC_C_LANGUAGE_STANDARD = gnu11; 758 | GCC_NO_COMMON_BLOCKS = YES; 759 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 760 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 761 | GCC_WARN_UNDECLARED_SELECTOR = YES; 762 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 763 | GCC_WARN_UNUSED_FUNCTION = YES; 764 | GCC_WARN_UNUSED_VARIABLE = YES; 765 | IPHONEOS_DEPLOYMENT_TARGET = 12.4; 766 | MTL_ENABLE_DEBUG_INFO = NO; 767 | MTL_FAST_MATH = YES; 768 | SDKROOT = iphoneos; 769 | SWIFT_COMPILATION_MODE = wholemodule; 770 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 771 | VALIDATE_PRODUCT = YES; 772 | }; 773 | name = Release; 774 | }; 775 | 8BB4927A230A548B0045C41F /* Debug */ = { 776 | isa = XCBuildConfiguration; 777 | buildSettings = { 778 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 779 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 780 | CODE_SIGN_STYLE = Automatic; 781 | DEVELOPMENT_TEAM = ""; 782 | INFOPLIST_FILE = Logo/Info.plist; 783 | LD_RUNPATH_SEARCH_PATHS = ( 784 | "$(inherited)", 785 | "@executable_path/Frameworks", 786 | ); 787 | PRODUCT_BUNDLE_IDENTIFIER = com.iosdevlog.Logo; 788 | PRODUCT_NAME = "$(TARGET_NAME)"; 789 | SWIFT_VERSION = 5.0; 790 | TARGETED_DEVICE_FAMILY = "1,2"; 791 | }; 792 | name = Debug; 793 | }; 794 | 8BB4927B230A548B0045C41F /* Release */ = { 795 | isa = XCBuildConfiguration; 796 | buildSettings = { 797 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 798 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 799 | CODE_SIGN_STYLE = Automatic; 800 | DEVELOPMENT_TEAM = ""; 801 | INFOPLIST_FILE = Logo/Info.plist; 802 | LD_RUNPATH_SEARCH_PATHS = ( 803 | "$(inherited)", 804 | "@executable_path/Frameworks", 805 | ); 806 | PRODUCT_BUNDLE_IDENTIFIER = com.iosdevlog.Logo; 807 | PRODUCT_NAME = "$(TARGET_NAME)"; 808 | SWIFT_VERSION = 5.0; 809 | TARGETED_DEVICE_FAMILY = "1,2"; 810 | }; 811 | name = Release; 812 | }; 813 | 8BB4927D230A548B0045C41F /* Debug */ = { 814 | isa = XCBuildConfiguration; 815 | buildSettings = { 816 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 817 | BUNDLE_LOADER = "$(TEST_HOST)"; 818 | CODE_SIGN_STYLE = Automatic; 819 | INFOPLIST_FILE = LogoTests/Info.plist; 820 | LD_RUNPATH_SEARCH_PATHS = ( 821 | "$(inherited)", 822 | "@executable_path/Frameworks", 823 | "@loader_path/Frameworks", 824 | ); 825 | PRODUCT_BUNDLE_IDENTIFIER = com.iosdevlog.LogoTests; 826 | PRODUCT_NAME = "$(TARGET_NAME)"; 827 | SWIFT_VERSION = 5.0; 828 | TARGETED_DEVICE_FAMILY = "1,2"; 829 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Logo.app/Logo"; 830 | }; 831 | name = Debug; 832 | }; 833 | 8BB4927E230A548B0045C41F /* Release */ = { 834 | isa = XCBuildConfiguration; 835 | buildSettings = { 836 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 837 | BUNDLE_LOADER = "$(TEST_HOST)"; 838 | CODE_SIGN_STYLE = Automatic; 839 | INFOPLIST_FILE = LogoTests/Info.plist; 840 | LD_RUNPATH_SEARCH_PATHS = ( 841 | "$(inherited)", 842 | "@executable_path/Frameworks", 843 | "@loader_path/Frameworks", 844 | ); 845 | PRODUCT_BUNDLE_IDENTIFIER = com.iosdevlog.LogoTests; 846 | PRODUCT_NAME = "$(TARGET_NAME)"; 847 | SWIFT_VERSION = 5.0; 848 | TARGETED_DEVICE_FAMILY = "1,2"; 849 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Logo.app/Logo"; 850 | }; 851 | name = Release; 852 | }; 853 | 8BB4929C230A54F80045C41F /* Debug */ = { 854 | isa = XCBuildConfiguration; 855 | buildSettings = { 856 | CLANG_ENABLE_MODULES = YES; 857 | CODE_SIGN_IDENTITY = ""; 858 | CODE_SIGN_STYLE = Automatic; 859 | CURRENT_PROJECT_VERSION = 1; 860 | DEFINES_MODULE = YES; 861 | DYLIB_COMPATIBILITY_VERSION = 1; 862 | DYLIB_CURRENT_VERSION = 1; 863 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 864 | INFOPLIST_FILE = LogoCompiler/Info.plist; 865 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 866 | LD_RUNPATH_SEARCH_PATHS = ( 867 | "$(inherited)", 868 | "@executable_path/Frameworks", 869 | "@loader_path/Frameworks", 870 | ); 871 | PRODUCT_BUNDLE_IDENTIFIER = com.iosdevlog.LogoCompiler; 872 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 873 | SKIP_INSTALL = YES; 874 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 875 | SWIFT_VERSION = 5.0; 876 | TARGETED_DEVICE_FAMILY = "1,2"; 877 | VERSIONING_SYSTEM = "apple-generic"; 878 | VERSION_INFO_PREFIX = ""; 879 | }; 880 | name = Debug; 881 | }; 882 | 8BB4929D230A54F80045C41F /* Release */ = { 883 | isa = XCBuildConfiguration; 884 | buildSettings = { 885 | CLANG_ENABLE_MODULES = YES; 886 | CODE_SIGN_IDENTITY = ""; 887 | CODE_SIGN_STYLE = Automatic; 888 | CURRENT_PROJECT_VERSION = 1; 889 | DEFINES_MODULE = YES; 890 | DYLIB_COMPATIBILITY_VERSION = 1; 891 | DYLIB_CURRENT_VERSION = 1; 892 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 893 | INFOPLIST_FILE = LogoCompiler/Info.plist; 894 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 895 | LD_RUNPATH_SEARCH_PATHS = ( 896 | "$(inherited)", 897 | "@executable_path/Frameworks", 898 | "@loader_path/Frameworks", 899 | ); 900 | PRODUCT_BUNDLE_IDENTIFIER = com.iosdevlog.LogoCompiler; 901 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 902 | SKIP_INSTALL = YES; 903 | SWIFT_VERSION = 5.0; 904 | TARGETED_DEVICE_FAMILY = "1,2"; 905 | VERSIONING_SYSTEM = "apple-generic"; 906 | VERSION_INFO_PREFIX = ""; 907 | }; 908 | name = Release; 909 | }; 910 | 8BB492A0230A54F80045C41F /* Debug */ = { 911 | isa = XCBuildConfiguration; 912 | buildSettings = { 913 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 914 | CODE_SIGN_STYLE = Automatic; 915 | INFOPLIST_FILE = LogoCompilerTests/Info.plist; 916 | LD_RUNPATH_SEARCH_PATHS = ( 917 | "$(inherited)", 918 | "@executable_path/Frameworks", 919 | "@loader_path/Frameworks", 920 | ); 921 | PRODUCT_BUNDLE_IDENTIFIER = com.iosdevlog.LogoCompilerTests; 922 | PRODUCT_NAME = "$(TARGET_NAME)"; 923 | SWIFT_VERSION = 5.0; 924 | TARGETED_DEVICE_FAMILY = "1,2"; 925 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Logo.app/Logo"; 926 | }; 927 | name = Debug; 928 | }; 929 | 8BB492A1230A54F80045C41F /* Release */ = { 930 | isa = XCBuildConfiguration; 931 | buildSettings = { 932 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 933 | CODE_SIGN_STYLE = Automatic; 934 | INFOPLIST_FILE = LogoCompilerTests/Info.plist; 935 | LD_RUNPATH_SEARCH_PATHS = ( 936 | "$(inherited)", 937 | "@executable_path/Frameworks", 938 | "@loader_path/Frameworks", 939 | ); 940 | PRODUCT_BUNDLE_IDENTIFIER = com.iosdevlog.LogoCompilerTests; 941 | PRODUCT_NAME = "$(TARGET_NAME)"; 942 | SWIFT_VERSION = 5.0; 943 | TARGETED_DEVICE_FAMILY = "1,2"; 944 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Logo.app/Logo"; 945 | }; 946 | name = Release; 947 | }; 948 | /* End XCBuildConfiguration section */ 949 | 950 | /* Begin XCConfigurationList section */ 951 | 8BB49257230A54800045C41F /* Build configuration list for PBXProject "Logo" */ = { 952 | isa = XCConfigurationList; 953 | buildConfigurations = ( 954 | 8BB49277230A548B0045C41F /* Debug */, 955 | 8BB49278230A548B0045C41F /* Release */, 956 | ); 957 | defaultConfigurationIsVisible = 0; 958 | defaultConfigurationName = Release; 959 | }; 960 | 8BB49279230A548B0045C41F /* Build configuration list for PBXNativeTarget "Logo" */ = { 961 | isa = XCConfigurationList; 962 | buildConfigurations = ( 963 | 8BB4927A230A548B0045C41F /* Debug */, 964 | 8BB4927B230A548B0045C41F /* Release */, 965 | ); 966 | defaultConfigurationIsVisible = 0; 967 | defaultConfigurationName = Release; 968 | }; 969 | 8BB4927C230A548B0045C41F /* Build configuration list for PBXNativeTarget "LogoTests" */ = { 970 | isa = XCConfigurationList; 971 | buildConfigurations = ( 972 | 8BB4927D230A548B0045C41F /* Debug */, 973 | 8BB4927E230A548B0045C41F /* Release */, 974 | ); 975 | defaultConfigurationIsVisible = 0; 976 | defaultConfigurationName = Release; 977 | }; 978 | 8BB4929B230A54F80045C41F /* Build configuration list for PBXNativeTarget "LogoCompiler" */ = { 979 | isa = XCConfigurationList; 980 | buildConfigurations = ( 981 | 8BB4929C230A54F80045C41F /* Debug */, 982 | 8BB4929D230A54F80045C41F /* Release */, 983 | ); 984 | defaultConfigurationIsVisible = 0; 985 | defaultConfigurationName = Release; 986 | }; 987 | 8BB4929F230A54F80045C41F /* Build configuration list for PBXNativeTarget "LogoCompilerTests" */ = { 988 | isa = XCConfigurationList; 989 | buildConfigurations = ( 990 | 8BB492A0230A54F80045C41F /* Debug */, 991 | 8BB492A1230A54F80045C41F /* Release */, 992 | ); 993 | defaultConfigurationIsVisible = 0; 994 | defaultConfigurationName = Release; 995 | }; 996 | /* End XCConfigurationList section */ 997 | }; 998 | rootObject = 8BB49254230A54800045C41F /* Project object */; 999 | } 1000 | -------------------------------------------------------------------------------- /Logo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Logo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Logo.xcodeproj/xcshareddata/xcschemes/Logo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 43 | 49 | 50 | 51 | 52 | 53 | 59 | 60 | 61 | 62 | 63 | 64 | 74 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 95 | 101 | 102 | 103 | 104 | 106 | 107 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /Logo.xcodeproj/xcshareddata/xcschemes/LogoCompilerTests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 14 | 15 | 17 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 39 | 40 | 41 | 42 | 48 | 49 | 51 | 52 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /Logo/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Logo 4 | // 5 | // Created by developer on 8/19/19. 6 | // Copyright © 2019 iOSDevLog. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /Logo/Assets.xcassets/>.imageset/>@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iOSDevLog/Logo/3a8046e49e8021f0999de3c1c8f0a69229225d56/Logo/Assets.xcassets/>.imageset/>@2x.png -------------------------------------------------------------------------------- /Logo/Assets.xcassets/>.imageset/>@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iOSDevLog/Logo/3a8046e49e8021f0999de3c1c8f0a69229225d56/Logo/Assets.xcassets/>.imageset/>@3x.png -------------------------------------------------------------------------------- /Logo/Assets.xcassets/>.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : ">@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : ">@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Logo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "ItunesArtwork@2x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } -------------------------------------------------------------------------------- /Logo/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iOSDevLog/Logo/3a8046e49e8021f0999de3c1c8f0a69229225d56/Logo/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /Logo/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iOSDevLog/Logo/3a8046e49e8021f0999de3c1c8f0a69229225d56/Logo/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /Logo/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iOSDevLog/Logo/3a8046e49e8021f0999de3c1c8f0a69229225d56/Logo/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /Logo/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iOSDevLog/Logo/3a8046e49e8021f0999de3c1c8f0a69229225d56/Logo/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /Logo/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iOSDevLog/Logo/3a8046e49e8021f0999de3c1c8f0a69229225d56/Logo/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /Logo/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iOSDevLog/Logo/3a8046e49e8021f0999de3c1c8f0a69229225d56/Logo/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /Logo/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iOSDevLog/Logo/3a8046e49e8021f0999de3c1c8f0a69229225d56/Logo/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /Logo/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iOSDevLog/Logo/3a8046e49e8021f0999de3c1c8f0a69229225d56/Logo/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /Logo/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iOSDevLog/Logo/3a8046e49e8021f0999de3c1c8f0a69229225d56/Logo/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /Logo/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iOSDevLog/Logo/3a8046e49e8021f0999de3c1c8f0a69229225d56/Logo/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /Logo/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iOSDevLog/Logo/3a8046e49e8021f0999de3c1c8f0a69229225d56/Logo/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /Logo/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iOSDevLog/Logo/3a8046e49e8021f0999de3c1c8f0a69229225d56/Logo/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /Logo/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iOSDevLog/Logo/3a8046e49e8021f0999de3c1c8f0a69229225d56/Logo/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /Logo/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iOSDevLog/Logo/3a8046e49e8021f0999de3c1c8f0a69229225d56/Logo/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /Logo/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iOSDevLog/Logo/3a8046e49e8021f0999de3c1c8f0a69229225d56/Logo/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png -------------------------------------------------------------------------------- /Logo/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Logo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda. 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 184 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 299 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | -------------------------------------------------------------------------------- /Logo/Calculator/Controller/CalculatorViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CalculatorViewController.swift 3 | // Logo 4 | // 5 | // Created by developer on 8/20/19. 6 | // Copyright © 2019 iOSDevLog. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import LogoCompiler 11 | 12 | class CalculatorViewController: UITableViewController { 13 | var dataSource: [[String]]! 14 | let sections = ["Programm", "Calculating Programm"] 15 | 16 | override func viewDidLoad() { 17 | super.viewDidLoad() 18 | } 19 | 20 | // MARK: - Table view data source 21 | 22 | override func numberOfSections(in tableView: UITableView) -> Int { 23 | return dataSource.count 24 | } 25 | 26 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 27 | return dataSource[section].count 28 | } 29 | 30 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 31 | let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) 32 | 33 | let str = dataSource[indexPath.section][indexPath.row] 34 | 35 | cell.textLabel?.text = str 36 | 37 | return cell 38 | } 39 | 40 | override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { 41 | return sections[section] 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Logo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Logo/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 24 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /Logo/Lexer/Controller/LexerViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LexerViewController.swift 3 | // Logo 4 | // 5 | // Created by developer on 8/19/19. 6 | // Copyright © 2019 iOSDevLog. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import LogoCompiler 11 | 12 | class LexerViewController: UITableViewController { 13 | // MARK: - Property 14 | var lexer: Lexer! 15 | 16 | // MARK: - Life Cycle 17 | override func viewDidLoad() { 18 | super.viewDidLoad() 19 | 20 | self.title = lexer.title 21 | self.tableView.tableFooterView = UIView() 22 | } 23 | 24 | // MARK: - TableViewDatasource 25 | override func numberOfSections(in tableView: UITableView) -> Int { 26 | return lexer.lexerItems.count 27 | } 28 | 29 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 30 | return lexer.lexerItems[section].tokens.count 31 | } 32 | 33 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 34 | let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) 35 | 36 | let token = lexer.lexerItems[indexPath.section].tokens[indexPath.row] 37 | 38 | cell.textLabel?.text = "\(token.getType()!)" 39 | cell.detailTextLabel?.text = token.getText() 40 | 41 | return cell 42 | } 43 | 44 | // MARK: - TableViewDelegate 45 | override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { 46 | return lexer.lexerItems[section].title 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Logo/Lexer/Model/Lexer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Lexer.swift 3 | // Logo 4 | // 5 | // Created by developer on 8/19/19. 6 | // Copyright © 2019 iOSDevLog. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import LogoCompiler 11 | 12 | class Lexer { 13 | var title: String 14 | var lexerItems = [LexerItem]() 15 | 16 | init(title: String, lexerItems: [LexerItem]) { 17 | self.title = title 18 | self.lexerItems = lexerItems 19 | } 20 | 21 | init() { 22 | self.title = "" 23 | self.lexerItems = [LexerItem]() 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Logo/Lexer/Model/LexerItem.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LexerItem.swift 3 | // Logo 4 | // 5 | // Created by developer on 8/19/19. 6 | // Copyright © 2019 iOSDevLog. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import LogoCompiler 11 | 12 | class LexerItem { 13 | public var title: String = "" 14 | public var tokens = [Token]() 15 | 16 | init(title: String, tokens: [Token]) { 17 | self.title = title 18 | self.tokens = tokens 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Logo/Main/Controller/MainViewController+Plot.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MainViewController+Plot.swift 3 | // Logo 4 | // 5 | // Created by developer on 8/21/19. 6 | // Copyright © 2019 iOSDevLog. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension MainViewController { 12 | var panelBounds: CGRect { 13 | get { 14 | return self.panelView.bounds 15 | } 16 | } 17 | 18 | var panelWidth: CGFloat { 19 | get { 20 | return self.panelView.bounds.width 21 | } 22 | } 23 | 24 | var panelHeight: CGFloat { 25 | get { 26 | return self.panelView.bounds.height 27 | } 28 | } 29 | 30 | var halfPanelWidth: CGFloat { 31 | get { 32 | return self.panelWidth / 2 33 | } 34 | } 35 | 36 | var halfPanelHeight: CGFloat { 37 | get { 38 | return self.panelHeight / 2 39 | } 40 | } 41 | 42 | var panelCenter: CGPoint { 43 | get { 44 | return CGPoint(x: halfPanelWidth, y: halfPanelHeight) 45 | } 46 | } 47 | 48 | func addNode(_ position: CGPoint, text: String? = nil, color: UIColor = UIColor.red, radius: CGFloat = 20) { 49 | let shapeLayer = CAShapeLayer() 50 | shapeLayer.path = UIBezierPath(roundedRect: CGRect(x: position.x - radius, y: position.y - radius, width: radius * 2, height: radius * 2), cornerRadius: radius).cgPath 51 | shapeLayer.fillColor = color.cgColor 52 | panelView.layer.addSublayer(shapeLayer) 53 | 54 | if let text = text { 55 | let textLayer = CATextLayer() 56 | textLayer.fontSize = 28 57 | let size = text.size(ofFont: textLayer.font as! UIFont) 58 | textLayer.bounds = CGRect(x: 0, y: 0, width: size.width, height: size.height) 59 | textLayer.position = position 60 | textLayer.string = text 61 | textLayer.alignmentMode = .center 62 | textLayer.foregroundColor = UIColor.black.cgColor 63 | textLayer.contentsScale = UIScreen.main.scale 64 | panelView.layer.addSublayer(textLayer) 65 | } 66 | } 67 | 68 | func addLine(_ startPosition: CGPoint, endPosition: CGPoint) { 69 | let shapeLayer = CAShapeLayer() 70 | shapeLayer.strokeColor = UIColor.green.cgColor 71 | shapeLayer.frame = self.panelBounds 72 | shapeLayer.lineWidth = 2.0 73 | shapeLayer.fillColor = UIColor.blue.cgColor 74 | 75 | let openSquarePath = UIBezierPath() 76 | openSquarePath.move(to: startPosition) 77 | openSquarePath.addLine(to: endPosition) 78 | 79 | shapeLayer.path = openSquarePath.cgPath 80 | panelView.layer.addSublayer(shapeLayer) 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /Logo/Main/Controller/MainViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MainViewController.swift 3 | // Logo 4 | // 5 | // Created by developer on 8/19/19. 6 | // Copyright © 2019 iOSDevLog. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import LogoCompiler 11 | 12 | class MainViewController: UIViewController { 13 | var lexer: SimpleLexer! 14 | var calculator: SimpleCalculator! 15 | var parser: SimpleParser! 16 | 17 | // MARK: - Outlet 18 | @IBOutlet weak var editorTextView: UITextView! 19 | @IBOutlet weak var panelView: UIView! 20 | @IBOutlet weak var panelScrollView: UIScrollView! 21 | 22 | // MARK: - Life Cycle 23 | override func viewDidLoad() { 24 | super.viewDidLoad() 25 | 26 | self.lexer = SimpleLexer() 27 | self.calculator = SimpleCalculator() 28 | self.parser = SimpleParser() 29 | 30 | editorTextView.text = """ 31 | int a = 15; 32 | int b = 19; 33 | 1+2-3+4*5-6; 34 | int c = 1519; 35 | int result = a+b*c; 36 | """ 37 | let tap = UITapGestureRecognizer(target: self, action: #selector(self.tap)) 38 | self.panelView.addGestureRecognizer(tap) 39 | } 40 | 41 | override func touchesBegan(_ touches: Set, with event: UIEvent?) { 42 | super.touchesBegan(touches, with: event) 43 | 44 | self.view.endEditing(true) 45 | } 46 | 47 | // MARK: - Action 48 | @IBAction func lexer(_ sender: UIBarButtonItem) { 49 | let script = editorTextView.text! 50 | DispatchQueue.global().async { [weak self] in 51 | let tokenReader = self?.lexer.tokenize(code: script) 52 | let lexer = Lexer(title: "Lexer", lexerItems: [LexerItem]()) 53 | var tokens = [Token]() 54 | var section = 0 55 | var token: Token? = tokenReader?.read() 56 | while let _token = token { 57 | tokens.append(_token) 58 | if _token.getType() == TokenType.SemiColon { 59 | let item = LexerItem(title: "\(section)", tokens: tokens) 60 | lexer.lexerItems.append(item) 61 | tokens = [Token]() 62 | section += 1 63 | } 64 | token = tokenReader?.read() 65 | } 66 | 67 | DispatchQueue.main.async { 68 | self?.performSegue(withIdentifier: "lexerSegue", sender: lexer) 69 | } 70 | } 71 | } 72 | 73 | @IBAction func calculator(_ sender: UIBarButtonItem) { 74 | let script = editorTextView.text! 75 | DispatchQueue.global().async { [weak self] in 76 | self?.calculator.evaluate(script: script) 77 | var dataSource = [[String]]() 78 | 79 | if let asts = self?.calculator.asts, let evaluates = self?.calculator.evaluates { 80 | dataSource.append(asts) 81 | dataSource.append(evaluates) 82 | DispatchQueue.main.async { 83 | self?.performSegue(withIdentifier: "calculatorSegue", sender: dataSource) 84 | if let tree = self?.calculator.tree { 85 | if let sublayers = self?.panelView.layer.sublayers { 86 | for layer in sublayers { 87 | layer.removeFromSuperlayer() 88 | } 89 | } 90 | self?.dumpAST(node: tree, position: CGPoint(x: self!.panelWidth / CGFloat(2), y: CGFloat(44))) 91 | } 92 | } 93 | } 94 | } 95 | } 96 | 97 | @IBAction func parse(_ sender: UIBarButtonItem) { 98 | let script = editorTextView.text! 99 | DispatchQueue.global().async { [weak self] in 100 | self?.parser.evaluate(code: script) 101 | var dataSource = [[String]]() 102 | 103 | if let asts = self?.parser.asts { 104 | dataSource.append(asts) 105 | DispatchQueue.main.async { 106 | guard self != nil else { 107 | return 108 | } 109 | self!.performSegue(withIdentifier: "calculatorSegue", sender: dataSource) 110 | if let tree = self!.parser.tree { 111 | if let sublayers = self?.panelView.layer.sublayers { 112 | for layer in sublayers { 113 | layer.removeFromSuperlayer() 114 | } 115 | } 116 | self!.dumpAST(node: tree, position: CGPoint(x: self!.panelWidth / CGFloat(2), y: CGFloat(44))) 117 | 118 | let rect = CGRect(x: (self!.panelWidth - self!.panelScrollView.bounds.width) / 2, y: 0, width: self!.panelScrollView.bounds.width, height: self!.panelScrollView.bounds.height) 119 | self!.panelScrollView.scrollRectToVisible(rect, animated: true) 120 | } 121 | } 122 | } 123 | } 124 | } 125 | 126 | @IBAction func clear(_ sender: UIBarButtonItem) { 127 | editorTextView.text = "" 128 | } 129 | 130 | // MARK: - Helper 131 | @objc func tap() { 132 | self.editorTextView.resignFirstResponder() 133 | } 134 | 135 | func dumpAST(node: ASTNode, position: CGPoint, level: Int = 1) { 136 | let childCount = node.getChildren().count 137 | let alpha: CGFloat = childCount > 0 ? 0.1 : 1 138 | let color: UIColor = node.getType()?.color.withAlphaComponent(alpha) ?? UIColor.magenta 139 | 140 | self.addNode(position, text: node.getText(), color: color) 141 | let newLevel = level + 1 142 | 143 | for index in 0.. Int { 13 | return cmds.count 14 | } 15 | 16 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 17 | let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) 18 | 19 | let cmd = cmds[indexPath.row] 20 | 21 | cell.textLabel?.text = cmd.input 22 | cell.detailTextLabel?.text = cmd.output 23 | 24 | return cell 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Logo/REPL/Controller/REPLViewController+TableViewDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // REPLViewController+TableViewDelegate.swift 3 | // Logo 4 | // 5 | // Created by developer on 8/27/19. 6 | // Copyright © 2019 iOSDevLog. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension REPLViewController: UITableViewDelegate { 12 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 13 | let cmd = self.cmds[indexPath.row] 14 | 15 | if let tree = cmd.tree { 16 | plot(tree: tree) 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Logo/REPL/Controller/REPLViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // REPLViewController.swift 3 | // Logo 4 | // 5 | // Created by developer on 8/27/19. 6 | // Copyright © 2019 iOSDevLog. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import LogoCompiler 11 | 12 | class REPLViewController: UIViewController { 13 | var cmds: [Cmd]! 14 | var parser: SimpleParser! 15 | var script: SimpleScript! 16 | 17 | @IBOutlet weak var tableView: UITableView! 18 | @IBOutlet weak var panelScrollView: UIScrollView! 19 | @IBOutlet weak var panelView: UIView! 20 | @IBOutlet weak var cmdTextField: UITextField! 21 | @IBOutlet weak var execButton: UIButton! 22 | @IBOutlet weak var bottomConstraint: NSLayoutConstraint! 23 | 24 | override func viewDidLoad() { 25 | super.viewDidLoad() 26 | 27 | self.parser = SimpleParser() 28 | self.script = SimpleScript() 29 | SimpleScript.verbose = true 30 | 31 | self.cmds = [Cmd]() 32 | 33 | self.tableView.dataSource = self 34 | self.tableView.delegate = self 35 | self.tableView.tableFooterView = UIView() 36 | 37 | NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil) 38 | NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil) 39 | NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChange), name: UIResponder.keyboardWillChangeFrameNotification, object: nil) 40 | 41 | self.execButton.addTarget(self, action: #selector(exec), for: .touchUpInside) 42 | } 43 | 44 | override func viewDidAppear(_ animated: Bool) { 45 | super.viewDidAppear(animated) 46 | 47 | fakeData() 48 | } 49 | 50 | func fakeData() { 51 | let lines = [ 52 | "2+3;", 53 | "int age = 10;", 54 | "int tmp;", 55 | "tmp = 10*2;", 56 | "c", 57 | "age = age + tmp;", 58 | "int a = 15;", 59 | "int b = 19;", 60 | "1+2-3+4*5-6;", 61 | "int c = 1519;", 62 | "int result = a+b*c;", 63 | ] 64 | 65 | for line in lines { 66 | execCmd(code: line) 67 | } 68 | } 69 | 70 | @objc 71 | func keyboardWillShow(notification: NSNotification) { 72 | print("keyboardWillShow") 73 | } 74 | 75 | @objc 76 | func keyboardWillHide(notification: NSNotification) { 77 | print("keyboardWillHide") 78 | } 79 | 80 | @objc 81 | func keyboardWillChange(notification: NSNotification) { 82 | print("keyboardWillChange") 83 | // let duration = notification.userInfo![UIResponder.keyboardAnimationDurationUserInfoKey] as! Double 84 | // let curve = notification.userInfo![UIResponder.keyboardAnimationCurveUserInfoKey] as! UInt 85 | let curFrame = (notification.userInfo![UIResponder.keyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue 86 | let targetFrame = (notification.userInfo![UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue 87 | let deltaY = targetFrame.origin.y - curFrame.origin.y 88 | 89 | self.bottomConstraint.constant += deltaY 90 | } 91 | 92 | 93 | 94 | @objc func exec() { 95 | let code = self.cmdTextField.text 96 | 97 | defer { 98 | self.cmdTextField.text = "" 99 | } 100 | 101 | execCmd(code: code) 102 | } 103 | 104 | func execCmd(code: String?) { 105 | guard code != nil else { 106 | cmdTextField.becomeFirstResponder() 107 | return 108 | } 109 | 110 | do { 111 | let line = code! 112 | if line.hasSuffix(";") { 113 | let tree = try self.parser.parse(code: line) 114 | 115 | if let tree = tree { 116 | if SimpleScript.verbose { 117 | self.parser.dumpAST(node: tree, indent: "") 118 | } 119 | let result = try self.script.evaluate(node: tree, indent: "") 120 | var output = "nil" 121 | if let result = result { 122 | output = String(describing: result) 123 | } 124 | let cmd = Cmd(input: line, output: output, tree: tree) 125 | self.cmds.append(cmd) 126 | self.tableView.reloadData() 127 | let lastIndexPath = IndexPath(row: self.cmds.count - 1, section: 0) 128 | DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in 129 | self?.tableView.scrollToRow(at: lastIndexPath, at: .bottom, animated: true) 130 | } 131 | 132 | plot(tree: tree) 133 | } 134 | } else { 135 | let cmd = Cmd(input: code!, output: "cmd should end with ‘;’", tree: nil) 136 | self.cmds.append(cmd) 137 | self.tableView.reloadData() 138 | } 139 | } catch LogoError.logo(let logoError) { 140 | print(logoError) 141 | let cmd = Cmd(input: code!, output: logoError, tree: nil) 142 | self.cmds.append(cmd) 143 | self.tableView.reloadData() 144 | } catch { 145 | print(error) 146 | print("\n>") 147 | } 148 | } 149 | 150 | func plot(tree: ASTNode) { 151 | if let sublayers = self.panelView.layer.sublayers { 152 | for layer in sublayers { 153 | layer.removeFromSuperlayer() 154 | } 155 | } 156 | self.dumpAST(node: tree, position: CGPoint(x: self.panelWidth / CGFloat(2), y: CGFloat(44))) 157 | let rect = CGRect(x: (self.panelWidth - self.panelScrollView.bounds.width) / 2, y: 0, width: self.panelScrollView.bounds.width, height: self.panelScrollView.bounds.height) 158 | self.panelScrollView.scrollRectToVisible(rect, animated: true) 159 | } 160 | 161 | func dumpAST(node: ASTNode, position: CGPoint, level: Int = 1) { 162 | let childCount = node.getChildren().count 163 | let alpha: CGFloat = childCount > 0 ? 0.1 : 1 164 | let color: UIColor = node.getType()?.color.withAlphaComponent(alpha) ?? UIColor.magenta 165 | 166 | self.addNode(position, text: node.getText(), color: color) 167 | let newLevel = level + 1 168 | 169 | for index in 0.. ASTNode? 18 | 19 | // 子节点 20 | func getChildren() -> [ASTNode] 21 | 22 | // AST类型 23 | func getType() -> ASTNodeType? 24 | 25 | // 文本值 26 | func getText() -> String? 27 | } 28 | -------------------------------------------------------------------------------- /LogoCompiler/AST/ASTNodeType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ASTNodeType.swift 3 | // LogoCompiler 4 | // 5 | // Created by developer on 8/20/19. 6 | // Copyright © 2019 iOSDevLog. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | * AST节点的类型。 13 | */ 14 | public enum ASTNodeType { 15 | case 16 | Programm, // 程序入口,根节点 17 | 18 | IntDeclaration, // 整型变量声明 19 | ExpressionStmt, // 表达式语句,即表达式后面跟个分号 20 | AssignmentStmt, // 赋值语句 21 | 22 | Primary, // 基础表达式 23 | Multiplicative, // 乘法表达式 24 | Additive, // 加法表达式 25 | 26 | Identifier, // 标识符 27 | IntLiteral // 整型字面量 28 | 29 | public var color: UIColor { 30 | switch self { 31 | case .Programm: 32 | return UIColor.black 33 | case .IntDeclaration: 34 | return UIColor.blue 35 | case .ExpressionStmt: 36 | return UIColor.green 37 | case .AssignmentStmt: 38 | return UIColor.gray 39 | case .Primary: 40 | return UIColor.red 41 | case .Multiplicative: 42 | return UIColor.purple 43 | case .Additive: 44 | return UIColor.brown 45 | case .Identifier: 46 | return UIColor.yellow 47 | case .IntLiteral: 48 | return UIColor.cyan 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /LogoCompiler/Error/LogoError.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LogoError.swift 3 | // LogoCompiler 4 | // 5 | // Created by developer on 8/20/19. 6 | // Copyright © 2019 iOSDevLog. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public enum LogoError: Error { 12 | case logo(error: String) 13 | } 14 | -------------------------------------------------------------------------------- /LogoCompiler/Extension/Character+Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Character+Extension.swift 3 | // LogoCompiler 4 | // 5 | // Created by developer on 8/19/19. 6 | // Copyright © 2019 iOSDevLog. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | // MARK: - Properties 12 | public extension Character { 13 | /// Check if character is emoji 14 | /// - example: Character("😊").isEmoji -> true 15 | var isEmoji: Bool { 16 | let scalarValue = String(self).unicodeScalars.first!.value 17 | switch scalarValue { 18 | case 0x3030, 0x00AE, 0x00A9, // Special Character > 特殊字符 19 | 0x1D000...0x1F77F, // Emoticons > 情感符 20 | 0x2100...0x27BF, // Misc symbols and Dingbats > 21 | 0xFE00...0xFE0F, // Variation Selectors > 变异选择符 22 | 0x1F900...0x1F9FF: // Supplemental Symbols and Pictographs > 补充的符号和象形文字 23 | return true 24 | default: 25 | return false 26 | } 27 | } 28 | 29 | /// Check if character is number 30 | /// - example: Character("1").isNummber 31 | var isNumber: Bool { 32 | return Int(String(self)) != nil 33 | } 34 | 35 | /// Check if character is a letter(字母) 36 | /// - example: (1) Character("4").isLetter -> false, (2) Character("a").isLetter -> True 37 | var isLetter: Bool { 38 | return String(self).rangeOfCharacter(from: .letters, options: .numeric, range: nil) != nil 39 | } 40 | 41 | /// Check if character is lowercased 42 | /// - example: (1) Character("a").isLowercased -> true, (2) Character("A").isLowercased -> false 43 | var isLowercased: Bool { 44 | return String(self) == String(self).lowercased() 45 | } 46 | 47 | /// Check if character is uppercased 48 | /// - example: (1) Character("a").isUppercased -> true, (2) Character("A").isUppercased -> true 49 | var isUppercased: Bool { 50 | return String(self) == String(self).uppercased() 51 | } 52 | 53 | /// Check if character is white space(空格) 54 | /// - example: (1) Character(" ").isWhiteSpace -> true, (2) Character("A").isWhiteSpace -> false 55 | var isWhiteSpace: Bool { 56 | return String(self) == " "; 57 | } 58 | 59 | /// Integer value from character (if applicable) 60 | /// - example: (1) Character("1").int -> 1, (2) Character("A").int -> nil 61 | var int: Int? { 62 | return Int(String(self)) 63 | } 64 | 65 | // String value from character 66 | var string: String { 67 | return String(self) 68 | } 69 | 70 | /// Return the character lowercased 71 | var lowercased: Character { 72 | return String(self).lowercased().first! 73 | } 74 | 75 | /// Return the character uppercased 76 | var uppercased: Character { 77 | return String(self).uppercased().first! 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /LogoCompiler/Extension/String+FontSize.swift: -------------------------------------------------------------------------------- 1 | // 2 | // String+FontSize.swift 3 | // LogoCompiler 4 | // 5 | // Created by developer on 8/21/19. 6 | // Copyright © 2019 iOSDevLog. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public extension String { 12 | func size(ofFont font: UIFont) -> CGSize { 13 | return (self as NSString).size(withAttributes: [NSAttributedString.Key.font: font]) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /LogoCompiler/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | 22 | 23 | -------------------------------------------------------------------------------- /LogoCompiler/LogoCompiler.h: -------------------------------------------------------------------------------- 1 | // 2 | // LogoCompiler.h 3 | // LogoCompiler 4 | // 5 | // Created by developer on 8/19/19. 6 | // Copyright © 2019 iOSDevLog. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for LogoCompiler. 12 | FOUNDATION_EXPORT double LogoCompilerVersionNumber; 13 | 14 | //! Project version string for LogoCompiler. 15 | FOUNDATION_EXPORT const unsigned char LogoCompilerVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /LogoCompiler/Simple/SimpleASTNode.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SimpleASTNode.swift 3 | // LogoCompiler 4 | // 5 | // Created by developer on 8/21/19. 6 | // Copyright © 2019 iOSDevLog. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | * 一个简单的AST节点的实现。 13 | * 属性包括:类型、文本值、父节点、子节点。 14 | */ 15 | public class SimpleASTNode: ASTNode { 16 | var parent: SimpleASTNode? = nil 17 | var children = [ASTNode]() 18 | var nodeType: ASTNodeType? = nil 19 | var text: String? = nil 20 | 21 | public init(nodeType: ASTNodeType?, text: String?) { 22 | self.nodeType = nodeType 23 | self.text = text 24 | } 25 | 26 | public func getParent() -> ASTNode? { 27 | return parent 28 | } 29 | 30 | public func getChildren() -> [ASTNode] { 31 | let readonlyChildren = children 32 | return readonlyChildren 33 | } 34 | 35 | public func getType() -> ASTNodeType? { 36 | return nodeType 37 | } 38 | 39 | public func getText() -> String? { 40 | return text 41 | } 42 | 43 | func add(child: SimpleASTNode) { 44 | children.append(child) 45 | child.parent = self 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /LogoCompiler/Simple/SimpleCalculator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SimpleCalculator.swift 3 | // LogoCompiler 4 | // 5 | // Created by developer on 8/20/19. 6 | // Copyright © 2019 iOSDevLog. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | * 实现一个计算器,但计算的结合性是有问题的。因为它使用了下面的语法规则: 13 | * 14 | * additive -> multiplicative | multiplicative + additive 15 | * multiplicative -> primary | primary + multiplicative 16 | * 17 | * 递归项在右边,会自然的对应右结合。我们真正需要的是左结合。 18 | */ 19 | public class SimpleCalculator { 20 | // MARK: - Property 21 | public var asts = [String]() 22 | public var evaluates = [String]() 23 | public var tree: ASTNode? 24 | 25 | // MARK: - Life Cycle 26 | public init() { 27 | 28 | } 29 | 30 | // MARK: - Helper 31 | /** 32 | * 执行脚本,并打印输出AST和求值过程。 33 | * @param script 34 | */ 35 | public func evaluate(script: String) { 36 | self.asts.removeAll() 37 | self.evaluates.removeAll() 38 | 39 | do { 40 | if let tree = try parse(code: script) { 41 | self.tree = tree 42 | dumpAST(node: tree, indent: "") 43 | _ = evaluate(node: tree, indent: "") 44 | } 45 | } catch LogoError.logo(let logoError) { 46 | print(logoError) 47 | } catch { 48 | print(error) 49 | } 50 | } 51 | 52 | /** 53 | * 解析脚本,并返回根节点 54 | * @param code 55 | * @return 56 | * @throws Exception 57 | */ 58 | func parse(code: String) throws -> ASTNode? { 59 | let lexer = SimpleLexer() 60 | let tokens = lexer.tokenize(code: code) 61 | 62 | let rootNode = try prog(tokens: tokens) 63 | 64 | return rootNode 65 | } 66 | 67 | /** 68 | * 对某个AST节点求值,并打印求值过程。 69 | * @param node 70 | * @param indent 打印输出时的缩进量,用tab控制 71 | * @return 72 | */ 73 | func evaluate(node: ASTNode, indent: String) -> Int { 74 | var result = 0 75 | let str = "\(indent) Calculating: \(String(describing: node.getType()!))" 76 | print(str) 77 | evaluates.append(str) 78 | 79 | if let type = node.getType() { 80 | switch type { 81 | case .Programm: 82 | for child in node.getChildren() { 83 | result = evaluate(node: child, indent: indent + "\t") 84 | } 85 | break 86 | case .Additive: 87 | let child1 = node.getChildren()[0] 88 | let value1 = evaluate(node: child1, indent: indent + "\t") 89 | let child2 = node.getChildren()[1] 90 | let value2 = evaluate(node: child2, indent: indent + "\t") 91 | 92 | if node.getText() == "+" { 93 | result = value1 + value2 94 | } else { 95 | result = value1 - value2 96 | } 97 | break 98 | case .Multiplicative: 99 | let child1 = node.getChildren()[0] 100 | let value1 = evaluate(node: child1, indent: indent + "\t") 101 | let child2 = node.getChildren()[1] 102 | let value2 = evaluate(node: child2, indent: indent + "\t") 103 | 104 | if node.getText() == "*" { 105 | result = value1 * value2 106 | } else { 107 | result = value1 / value2 108 | } 109 | break 110 | case .Primary: 111 | result = Int(node.getText()!)! 112 | break 113 | case .IntLiteral: 114 | result = Int(node.getText()!)! 115 | break 116 | default: 117 | break 118 | } 119 | } 120 | 121 | let resultStr = "\(indent) Result: \(result)" 122 | print(resultStr) 123 | evaluates.append(resultStr) 124 | 125 | return result; 126 | } 127 | /** 128 | * 语法解析:根节点 129 | * @return 130 | * @throws Exception 131 | */ 132 | private func prog(tokens: TokenReader) throws -> SimpleASTNode? { 133 | let node = SimpleASTNode(nodeType: .Programm, text: "Calculator") 134 | let child = try additive(tokens: tokens) 135 | 136 | if let child = child { 137 | node.add(child: child) 138 | } 139 | 140 | return node 141 | } 142 | 143 | /** 144 | * 整型变量声明语句,如: 145 | * int a; 146 | * int b = 2*3; 147 | * 148 | * @return 149 | * @throws Exception 150 | */ 151 | public func intDeclare(tokens: TokenReader) throws -> SimpleASTNode? { 152 | var node: SimpleASTNode? = nil 153 | var token = tokens.peek(); // 预读 154 | 155 | if token?.getType() == .Int { 156 | token = tokens.read() // 消耗掉int 157 | if tokens.peek()?.getType() == .Identifier { // 匹配标识符 158 | token = tokens.read() // 消耗掉标识符 159 | // 创建当前节点,并把变量名记到AST节点的文本值中,这里新建一个变量子节点也是可以的 160 | node = SimpleASTNode(nodeType: .IntDeclaration, text: token?.getText()); 161 | token = tokens.peek(); //预读 162 | if token?.getType() == .Assignment { 163 | _ = tokens.read(); // 消耗掉等号 164 | let child = try additive(tokens: tokens) // 匹配一个表达式 165 | 166 | if child == nil { 167 | throw LogoError.logo(error: "invalide variable initialization, expecting an expression") 168 | } else { 169 | node?.add(child: child!) 170 | } 171 | } 172 | } else { 173 | throw LogoError.logo(error: "variable name expected") 174 | } 175 | 176 | if node != nil { 177 | token = tokens.peek() 178 | if token?.getType() == .SemiColon { 179 | _ = tokens.read() 180 | } else { 181 | throw LogoError.logo(error: "invalid statement, expecting semicolon") 182 | } 183 | } 184 | } 185 | 186 | return node 187 | } 188 | 189 | /** 190 | * 语法解析:加法表达式 191 | * @return 192 | * @throws Exception 193 | */ 194 | private func additive(tokens: TokenReader) throws -> SimpleASTNode? { 195 | let child1 = try multiplicative(tokens: tokens) 196 | var node = child1 197 | 198 | var token = tokens.peek() 199 | 200 | if let child1 = child1, let _ = token { 201 | if token?.getType() == .Plus || token?.getType() == .Minus { 202 | token = tokens.read() 203 | let child2 = try additive(tokens: tokens) 204 | 205 | if let child2 = child2 { 206 | node = SimpleASTNode(nodeType: .Additive, text: token?.getText()) 207 | node?.add(child: child1) 208 | node?.add(child: child2) 209 | } else { 210 | throw LogoError.logo(error: "invalid additive expression, expecting the right part.") 211 | } 212 | } 213 | } 214 | 215 | return node 216 | } 217 | 218 | /** 219 | * 语法解析:乘法表达式 220 | * @return 221 | * @throws Exception 222 | */ 223 | private func multiplicative(tokens: TokenReader) throws -> SimpleASTNode? { 224 | let child1: SimpleASTNode? = try primary(tokens: tokens) 225 | var node = child1 226 | var token = tokens.peek() 227 | 228 | if let child1 = child1, let _ = token { 229 | if token?.getType() == .Star || token?.getType() == .Slash { 230 | token = tokens.read() 231 | let child2 = try primary(tokens: tokens) 232 | 233 | if let child2 = child2 { 234 | node = SimpleASTNode(nodeType: .Multiplicative, text: token?.getText()) 235 | node?.add(child: child1) 236 | node?.add(child: child2) 237 | } else { 238 | throw LogoError.logo(error: "invalid multiplicative expression, expecting the right part.") 239 | } 240 | } 241 | } 242 | 243 | return node 244 | } 245 | 246 | /** 247 | * 语法解析:基础表达式 248 | * @return 249 | * @throws Exception 250 | */ 251 | private func primary(tokens: TokenReader) throws -> SimpleASTNode? { 252 | var node: SimpleASTNode? = nil 253 | var token = tokens.peek() 254 | 255 | if let _token = token { 256 | if _token.getType() == .IntLiteral { 257 | token = tokens.read() 258 | node = SimpleASTNode(nodeType: .IntLiteral, text: token?.getText()) 259 | } else if token?.getType() == .Identifier { 260 | token = tokens.read() 261 | node = SimpleASTNode(nodeType: .Identifier, text: token?.getText()) 262 | } else if token?.getType() == .LeftParen { 263 | let _ = tokens.read() 264 | node = try additive(tokens: tokens) 265 | 266 | if let _ = node { 267 | if token?.getType() == .RightParen { 268 | let _ = tokens.read() 269 | } else { 270 | throw LogoError.logo(error: "expecting right parenthesis") 271 | } 272 | } else { 273 | throw LogoError.logo(error: "expecting an additive expression inside parenthesis") 274 | } 275 | } 276 | } 277 | 278 | return node // 这个方法也做了 AST 的简化,就是不用构造一个 primary 节点,直接返回子节点。因为它只有一个子节点。 279 | } 280 | 281 | /** 282 | * 打印输出AST的树状结构 283 | * @param node 284 | * @param indent 缩进字符,由tab组成,每一级多一个tab 285 | */ 286 | func dumpAST(node: ASTNode, indent: String) { 287 | let str = "\(indent)\(String(describing: node.getType()!)) \(String(describing: node.getText()!))" 288 | print(str) 289 | asts.append(str) 290 | for child in node.getChildren() { 291 | dumpAST(node: child, indent: indent + "\t"); 292 | } 293 | } 294 | } 295 | -------------------------------------------------------------------------------- /LogoCompiler/Simple/SimpleLexer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SimpleLexer.swift 3 | // LogoCompiler 4 | // 5 | // Created by developer on 8/19/19. 6 | // Copyright © 2019 iOSDevLog. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | * 一个简单的手写的词法分析器。 13 | * 能够为后面的简单计算器、简单脚本语言产生Token。 14 | */ 15 | public class SimpleLexer { 16 | 17 | // MARK: - Property 18 | // 下面几个变量是在解析过程中用到的临时变量,如果要优化的话,可以塞到方法里隐藏起来 19 | // 临时保存token的文本 20 | private var tokenText: String? = nil 21 | // 保存解析出来的Token 22 | private var tokens: [Token]? = nil 23 | // 当前正在解析的Token 24 | private var token: SimpleToken? = nil 25 | 26 | // MARK: - Life Cycle 27 | public init() { 28 | } 29 | 30 | // MARK: - Character 31 | /// 是否是字母 32 | private func isAlpha(ch: Character) -> Bool { 33 | return ch.isLetter 34 | } 35 | 36 | /// 是否是数字 37 | private func isDigit(ch: Character) -> Bool { 38 | return ch.isNumber 39 | } 40 | 41 | /// 是否是空白字符 42 | private func isBlank(ch: Character) -> Bool { 43 | return String(ch) == " " 44 | || String(ch) == "\t" 45 | || String(ch) == "\n"; 46 | 47 | } 48 | 49 | /** 50 | * 有限状态机进入初始状态。 51 | * 这个初始状态其实并不做停留,它马上进入其他状态。 52 | * 开始解析的时候,进入初始状态;某个Token解析完毕,也进入初始状态,在这里把Token记下来,然后建立一个新的Token。 53 | * @param ch 54 | * @return 55 | */ 56 | private func initToken(ch: Character) -> DfaState { 57 | if (tokenText?.count ?? 0) > 0 { 58 | token?.text = tokenText 59 | tokens?.append(token!) 60 | 61 | tokenText = "" 62 | token = SimpleToken() 63 | } 64 | 65 | var newState = DfaState.Initial 66 | 67 | if ch.isLetter { // 第一个字符是字母 68 | if (String(ch) == "i") { 69 | newState = .Id_int1 70 | } else { 71 | newState = .Id // 进入Id状态 72 | } 73 | token?.type = .Identifier 74 | tokenText?.append(ch) 75 | } else if ch.isNumber { // 第一个字符是数字 76 | newState = .IntLiteral 77 | token?.type = .IntLiteral 78 | tokenText?.append(ch) 79 | } else { 80 | switch String(ch) { 81 | case ">": 82 | newState = .GT 83 | token?.type = .GT 84 | tokenText?.append(ch) 85 | break 86 | case "+": 87 | newState = .Plus 88 | token?.type = .Plus 89 | tokenText?.append(ch) 90 | break 91 | case "-": 92 | newState = .Minus 93 | token?.type = .Minus 94 | tokenText?.append(ch) 95 | break 96 | case "*": 97 | newState = .Star 98 | token?.type = .Star 99 | tokenText?.append(ch) 100 | break 101 | case "/": 102 | newState = .Slash 103 | token?.type = .Slash 104 | tokenText?.append(ch) 105 | break 106 | case ";": 107 | newState = .SemiColon 108 | token?.type = .SemiColon 109 | tokenText?.append(ch) 110 | break 111 | case "(": 112 | newState = .LeftParen 113 | token?.type = .LeftParen 114 | tokenText?.append(ch) 115 | break 116 | case ")": 117 | newState = .RightParen 118 | token?.type = .RightParen 119 | tokenText?.append(ch) 120 | break 121 | case "=": 122 | newState = .Assignment 123 | token?.type = .Assignment 124 | tokenText?.append(ch) 125 | break 126 | default: 127 | newState = .Initial; // skip all unknown patterns 128 | break 129 | } 130 | } 131 | 132 | return newState 133 | } 134 | 135 | /** 136 | * 解析字符串,形成Token。 137 | * 这是一个有限状态自动机,在不同的状态中迁移。 138 | * @param code 139 | * @return 140 | */ 141 | public func tokenize(code: String) -> SimpleTokenReader { 142 | tokens = [Token]() 143 | guard code.count > 0 else { 144 | return SimpleTokenReader(tokens: tokens!) 145 | } 146 | tokenText = "" 147 | token = SimpleToken() 148 | 149 | var state = DfaState.Initial 150 | 151 | for ch in code { 152 | switch state { 153 | case .Initial: 154 | state = initToken(ch: ch) // 重新确定后续状态 155 | break 156 | case .If: 157 | state = initToken(ch: ch); // 退出当前状态,并保存Token 158 | break 159 | case .Id_if1: 160 | state = initToken(ch: ch); // 退出当前状态,并保存Token 161 | break 162 | case .Id_if2: 163 | state = initToken(ch: ch); // 退出当前状态,并保存Token 164 | break 165 | case .Else: 166 | state = initToken(ch: ch); // 退出当前状态,并保存Token 167 | break 168 | case .Id_else1: 169 | state = initToken(ch: ch); // 退出当前状态,并保存Token 170 | break 171 | case .Id_else2: 172 | state = initToken(ch: ch); // 退出当前状态,并保存Token 173 | break 174 | case .Id_else3: 175 | state = initToken(ch: ch); // 退出当前状态,并保存Token 176 | break 177 | case .Id_else4: 178 | state = initToken(ch: ch); // 退出当前状态,并保存Token 179 | break 180 | case .Int: 181 | state = initToken(ch: ch); // 退出当前状态,并保存Token 182 | break 183 | case .Id_int1: 184 | if String(ch) == "n" { 185 | state = .Id_int2 186 | tokenText?.append(ch) 187 | } else if isDigit(ch: ch) || isAlpha(ch: ch) { 188 | state = .Id // 切换回Id状态 189 | tokenText?.append(ch) 190 | } else { 191 | state = initToken(ch: ch) 192 | } 193 | case .Id_int2: 194 | if String(ch) == "t" { 195 | state = .Id_int3 196 | tokenText?.append(ch) 197 | } else if isDigit(ch: ch) || isAlpha(ch: ch) { 198 | state = .Id // 切换回Id状态 199 | tokenText?.append(ch) 200 | } else { 201 | state = initToken(ch: ch) 202 | } 203 | break 204 | case .Id_int3: 205 | if isBlank(ch: ch) { 206 | token?.type = .Int 207 | state = initToken(ch: ch) 208 | } else { 209 | state = .Id 210 | tokenText?.append(ch) 211 | } 212 | break 213 | case .Id: 214 | if isAlpha(ch: ch) || isDigit(ch: ch) { 215 | tokenText?.append(ch) // 保持标识符状态 216 | } else { 217 | state = initToken(ch: ch) // 退出标识符状态,并保存 Token 218 | } 219 | break 220 | case .GT: 221 | if String(ch) == "=" { 222 | token?.type = .GE // 转换成 GE 223 | state = .GE 224 | tokenText?.append(ch) 225 | } else { 226 | state = initToken(ch: ch) // 退出 GT 状态,并保存 Token 227 | } 228 | break 229 | case .GE: 230 | state = initToken(ch: ch) // 退出 GE 状态,并保存 Token 231 | break 232 | case .Assignment: 233 | state = initToken(ch: ch) // 退出 Assignment 状态,并保存 Token 234 | break 235 | case .Plus: 236 | state = initToken(ch: ch) // 退出 Plus 状态,并保存 Token 237 | break 238 | case .Minus: 239 | state = initToken(ch: ch) // 退出 Minus 状态,并保存 Token 240 | break 241 | case .Star: 242 | state = initToken(ch: ch) // 退出 Star 状态,并保存 Token 243 | break 244 | case .Slash: 245 | state = initToken(ch: ch) // 退出 Slash 状态,并保存 Token 246 | break 247 | case .SemiColon: 248 | state = initToken(ch: ch) // 退出 SemiColon 状态,并保存 Token 249 | break 250 | case .LeftParen: 251 | state = initToken(ch: ch) // 退出当前状态,并保存Token 252 | break 253 | case .RightParen: 254 | state = initToken(ch: ch) // 退出当前状态,并保存Token 255 | break 256 | case .IntLiteral: 257 | if isDigit(ch: ch) { 258 | tokenText?.append(ch) // 继续保持在数字字面量状态 259 | } else { 260 | state = initToken(ch: ch) // 退出当前状态,并保存Token 261 | } 262 | break 263 | } 264 | } 265 | 266 | // 把最后一个token送进去 267 | if (tokenText?.count ?? 0) > 0 { 268 | _ = initToken(ch: code.last!); 269 | } 270 | 271 | return SimpleTokenReader(tokens: tokens!) 272 | } 273 | 274 | public static func dump(tokenReader: SimpleTokenReader) { 275 | print("text\ttype") 276 | var token: Token? = tokenReader.read() 277 | while let _token = token { 278 | print("\(String(describing: _token.getText()!))\t\t\(String(describing: _token.getType()!))") 279 | token = tokenReader.read() 280 | } 281 | } 282 | 283 | // MARK: Private enum 284 | /** 285 | * 有限状态机的各种状态。 286 | */ 287 | private enum DfaState { 288 | case 289 | Initial, 290 | 291 | If, Id_if1, Id_if2, Else, Id_else1, Id_else2, Id_else3, Id_else4, Int, Id_int1, Id_int2, Id_int3, Id, GT, GE, 292 | 293 | Assignment, 294 | 295 | Plus, Minus, Star, Slash, 296 | 297 | SemiColon, 298 | LeftParen, 299 | RightParen, 300 | 301 | IntLiteral 302 | } 303 | 304 | // MARK: - private class 305 | /** 306 | * Token的一个简单实现。只有类型和文本值两个属性。 307 | */ 308 | private class SimpleToken: Token { 309 | // Token类型 310 | var type: TokenType? 311 | 312 | // 文本值 313 | var text: String? 314 | 315 | func getType() -> TokenType? { 316 | return type 317 | } 318 | 319 | func getText() -> String? { 320 | return text 321 | } 322 | 323 | } 324 | 325 | /** 326 | * 一个简单的Token流。是把一个Token列表进行了封装。 327 | */ 328 | public class SimpleTokenReader: TokenReader { 329 | var tokens = [Token]() 330 | var pos = 0 331 | 332 | public init(tokens: [Token]) { 333 | self.tokens = tokens 334 | } 335 | 336 | public func read() -> Token? { 337 | if pos < tokens.count { 338 | let token = tokens[pos] 339 | pos += 1 340 | return token 341 | } 342 | 343 | return nil 344 | } 345 | 346 | public func peek() -> Token? { 347 | if pos < tokens.count { 348 | return tokens[pos] 349 | } 350 | 351 | return nil 352 | } 353 | 354 | public func unread() { 355 | if pos > 0 { 356 | pos -= 1 357 | } 358 | } 359 | 360 | public func getPosition() -> Int { 361 | return pos 362 | } 363 | 364 | public func setPosition(position: Int) { 365 | if (position >= 0 && position < tokens.count) { 366 | pos = position 367 | } 368 | } 369 | } 370 | } 371 | -------------------------------------------------------------------------------- /LogoCompiler/Simple/SimpleParser.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SimpleParser.swift 3 | // LogoCompiler 4 | // 5 | // Created by developer on 8/21/19. 6 | // Copyright © 2019 iOSDevLog. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public class SimpleParser { 12 | // MARK: - Property 13 | public var asts = [String]() 14 | public var tree: ASTNode? 15 | 16 | // MARK: - Life Cycle 17 | public init() { 18 | 19 | } 20 | 21 | // MARK: - Helper 22 | public func evaluate(code: String) { 23 | do { 24 | if let tree = try self.parse(code: code) { 25 | self.tree = tree 26 | asts = [String]() 27 | self.dumpAST(node: tree, indent: "") 28 | } 29 | } catch LogoError.logo(let logoError) { 30 | print(logoError) 31 | } catch { 32 | print(error) 33 | } 34 | } 35 | 36 | /** 37 | * 解析脚本,并返回根节点 38 | * @param code 39 | * @return 40 | * @throws Exception 41 | */ 42 | public func parse(code: String) throws -> ASTNode? { 43 | let lexer = SimpleLexer() 44 | let tokens = lexer.tokenize(code: code) 45 | 46 | let rootNode = try prog(tokens: tokens) 47 | 48 | return rootNode 49 | } 50 | 51 | /** 52 | * 语法解析:根节点 53 | * @return 54 | * @throws Exception 55 | */ 56 | private func prog(tokens: TokenReader) throws -> SimpleASTNode? { 57 | let node = SimpleASTNode(nodeType: .Programm, text: "AST") 58 | 59 | while tokens.peek() != nil { 60 | var child = try intDeclare(tokens: tokens) 61 | 62 | if child == nil { 63 | child = try expressionStatement(tokens: tokens) 64 | } 65 | 66 | if child == nil { 67 | child = try assignmentStatement(tokens: tokens) 68 | } 69 | 70 | if let _child = child { 71 | node.add(child: _child) 72 | } else { 73 | throw LogoError.logo(error: "unknown statement"); 74 | } 75 | } 76 | 77 | return node 78 | } 79 | 80 | /** 81 | * 表达式语句,即表达式后面跟个分号。 82 | * @return 83 | * @throws Exception 84 | */ 85 | public func expressionStatement(tokens: TokenReader) throws -> SimpleASTNode? { 86 | let pos = tokens.getPosition() 87 | var node = try additive(tokens: tokens) 88 | 89 | if let _ = node { 90 | let token = tokens.peek() 91 | if token?.getType() == .SemiColon { 92 | _ = tokens.read() 93 | } else { 94 | node = nil 95 | tokens.setPosition(position: pos) 96 | } 97 | } 98 | 99 | return node // 直接返回子节点,简化了AST。 100 | } 101 | 102 | /** 103 | * 赋值语句,如age = 10*2; 104 | * @return 105 | * @throws Exception 106 | */ 107 | public func assignmentStatement(tokens: TokenReader) throws -> SimpleASTNode? { 108 | var node: SimpleASTNode? = nil 109 | var token = tokens.peek(); // 预读,看看下面是不是标识符 110 | 111 | if token?.getType() == .Identifier { 112 | token = tokens.read() // 读入标识符 113 | node = SimpleASTNode(nodeType: .AssignmentStmt, text: token?.getText()) 114 | token = tokens.peek(); // 预读,看看下面是不是等号 115 | if token?.getType() == .Assignment { 116 | _ = tokens.read(); // 取出等号 117 | let child = try additive(tokens: tokens) // 匹配一个表达式 118 | if child == nil { // 出错,等号右面没有一个合法的表达式 119 | throw LogoError.logo(error: "invalide assignment statement, expecting an expression") 120 | } else { 121 | node?.add(child: child!) // 添加子节点 122 | token = tokens.peek(); // 预读,看看后面是不是分号 123 | if token?.getType() == .SemiColon { 124 | _ = tokens.read() // 消耗掉这个分号 125 | } else { // 报错,缺少分号 126 | throw LogoError.logo(error: "invalid statement, expecting semicolon") 127 | } 128 | } 129 | } else { 130 | tokens.unread() // 回溯,吐出之前消化掉的标识符 131 | node = nil 132 | } 133 | } 134 | 135 | return node 136 | } 137 | 138 | /** 139 | * 整型变量声明语句,如: 140 | * int a; 141 | * int b = 2*3; 142 | * 143 | * @return 144 | * @throws Exception 145 | */ 146 | public func intDeclare(tokens: TokenReader) throws -> SimpleASTNode? { 147 | var node: SimpleASTNode? = nil 148 | var token = tokens.peek(); // 预读 149 | 150 | if token?.getType() == .Int { 151 | token = tokens.read() // 消耗掉int 152 | if tokens.peek()?.getType() == .Identifier { // 匹配标识符 153 | token = tokens.read() // 消耗掉标识符 154 | // 创建当前节点,并把变量名记到AST节点的文本值中,这里新建一个变量子节点也是可以的 155 | node = SimpleASTNode(nodeType: .IntDeclaration, text: token?.getText()) 156 | token = tokens.peek(); // 预读 157 | if token?.getType() == .Assignment { 158 | _ = tokens.read(); // 消耗掉等号 159 | let child = try additive(tokens: tokens) // 匹配一个表达式 160 | 161 | if child == nil { 162 | throw LogoError.logo(error: "invalide variable initialization, expecting an expression") 163 | } else { 164 | node?.add(child: child!) 165 | } 166 | } 167 | } else { 168 | throw LogoError.logo(error: "variable name expected") 169 | } 170 | 171 | if node != nil { 172 | token = tokens.peek() 173 | if token?.getType() == .SemiColon { 174 | _ = tokens.read() 175 | } else { 176 | throw LogoError.logo(error: "invalid statement, expecting semicolon") 177 | } 178 | } 179 | } 180 | 181 | return node 182 | } 183 | 184 | /** 185 | * 语法解析:加法表达式 186 | * @return 187 | * @throws Exception 188 | */ 189 | private func additive(tokens: TokenReader) throws -> SimpleASTNode? { 190 | var child1 = try multiplicative(tokens: tokens) // 应用add规则 191 | var node = child1 192 | 193 | if child1 != nil { 194 | while true { // 循环应用add'规则 195 | var token = tokens.peek() 196 | if token?.getType() == .Plus || token?.getType() == .Minus { 197 | token = tokens.read() // 读出加号 198 | let child2 = try multiplicative(tokens: tokens) // 计算下级节点 199 | if child2 != nil { 200 | node = SimpleASTNode(nodeType: .Additive, text: token?.getText()) 201 | node?.add(child: child1!) // 注意,新节点在顶层,保证正确的结合性 202 | node?.add(child: child2!) 203 | child1 = node 204 | } else { 205 | throw LogoError.logo(error: "invalid additive expression, expecting the right part.") 206 | } 207 | } else { 208 | break 209 | } 210 | } 211 | } 212 | 213 | return node 214 | } 215 | 216 | /** 217 | * 语法解析:乘法表达式 218 | * @return 219 | * @throws Exception 220 | */ 221 | private func multiplicative(tokens: TokenReader) throws -> SimpleASTNode? { 222 | var child1: SimpleASTNode? = try primary(tokens: tokens) 223 | var node = child1 224 | 225 | if child1 != nil { 226 | while true { 227 | var token = tokens.peek() 228 | if token?.getType() == .Star || token?.getType() == .Slash { 229 | token = tokens.read() 230 | let child2 = try primary(tokens: tokens) 231 | 232 | if child2 != nil { 233 | node = SimpleASTNode(nodeType: .Multiplicative, text: token?.getText()) 234 | node?.add(child: child1!) 235 | node?.add(child: child2!) 236 | child1 = node 237 | } else { 238 | throw LogoError.logo(error: "invalid multiplicative expression, expecting the right part.") 239 | } 240 | } else { 241 | break 242 | } 243 | } 244 | } 245 | 246 | return node 247 | } 248 | 249 | /** 250 | * 语法解析:基础表达式 251 | * @return 252 | * @throws Exception 253 | */ 254 | private func primary(tokens: TokenReader) throws -> SimpleASTNode? { 255 | var node: SimpleASTNode? = nil 256 | var token = tokens.peek() 257 | 258 | if token != nil { 259 | if token!.getType() == .IntLiteral { 260 | token = tokens.read() 261 | node = SimpleASTNode(nodeType: .IntLiteral, text: token?.getText()) 262 | } else if token!.getType() == .Identifier { 263 | token = tokens.read() 264 | node = SimpleASTNode(nodeType: .Identifier, text: token?.getText()) 265 | } else if token!.getType() == .LeftParen { 266 | let _ = tokens.read() 267 | node = try additive(tokens: tokens) 268 | 269 | if node != nil { 270 | token = tokens.peek() 271 | if token?.getType() == .RightParen { 272 | let _ = tokens.read() 273 | } else { 274 | throw LogoError.logo(error: "expecting right parenthesis") 275 | } 276 | } else { 277 | throw LogoError.logo(error: "expecting an additive expression inside parenthesis") 278 | } 279 | } 280 | } 281 | 282 | return node // 这个方法也做了 AST 的简化,就是不用构造一个 primary 节点,直接返回子节点。因为它只有一个子节点。 283 | } 284 | 285 | /** 286 | * 打印输出AST的树状结构 287 | * @param node 288 | * @param indent 缩进字符,由tab组成,每一级多一个tab 289 | */ 290 | public func dumpAST(node: ASTNode, indent: String) { 291 | let str = "\(indent)\(String(describing: node.getType()!)) \(String(describing: node.getText()!))" 292 | print(str) 293 | asts.append(str) 294 | for child in node.getChildren() { 295 | dumpAST(node: child, indent: indent + "\t"); 296 | } 297 | } 298 | } 299 | -------------------------------------------------------------------------------- /LogoCompiler/Simple/SimpleScript.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SimpleScript.swift 3 | // LogoCompiler 4 | // 5 | // Created by developer on 8/23/19. 6 | // Copyright © 2019 iOSDevLog. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | * 一个简单的脚本解释器。 13 | * 所支持的语法,请参见SimpleParser.java 14 | * 15 | * 运行脚本: 16 | * 在命令行下,键入:java SimpleScript 17 | * 则进入一个REPL界面。你可以依次敲入命令。比如: 18 | * > 2+3; 19 | * > int age = 10; 20 | * > int b; 21 | * > b = 10*2; 22 | * > age = age + b; 23 | * > exit(); //退出REPL界面。 24 | * 25 | * 你还可以使用一个参数 -v,让每次执行脚本的时候,都输出AST和整个计算过程。 26 | * 27 | */ 28 | public class SimpleScript { 29 | // MARK: - Property 30 | var variables = [String: Int?]() 31 | public static var verbose = false 32 | 33 | public init() { 34 | 35 | } 36 | 37 | // MARK: - Helper 38 | public func evaluate(node: ASTNode, indent: String) throws -> Int? { 39 | var result: Int? = nil 40 | 41 | if SimpleScript.verbose { 42 | print("\(indent)Calculating: \(String(describing: node.getType()!))") 43 | } 44 | 45 | if let type = node.getType() { 46 | switch type { 47 | case .Programm: 48 | for child in node.getChildren() { 49 | result = try evaluate(node: child, indent: indent) 50 | } 51 | break 52 | case .ExpressionStmt: 53 | break 54 | case .AssignmentStmt: 55 | let varName = node.getText()! 56 | if !variables.keys.contains(varName) { 57 | throw LogoError.logo(error: "unknown variable: \(varName)") 58 | } //接着执行下面的代码 59 | fallthrough 60 | case .IntDeclaration: 61 | let varName = node.getText()! 62 | var varValue: Int? = nil 63 | 64 | if node.getChildren().count > 0 { 65 | let child = node.getChildren()[0] 66 | result = try evaluate(node: child, indent: "\t") 67 | varValue = Int(result!) 68 | } 69 | variables[varName] = varValue 70 | break 71 | case .Primary: 72 | break 73 | case .Multiplicative: 74 | let child1 = node.getChildren()[0] 75 | let value1 = try evaluate(node: child1, indent: "\t") 76 | let child2 = node.getChildren()[1] 77 | let value2 = try evaluate(node: child2, indent: "\t") 78 | 79 | if node.getText()! == "*" { 80 | result = value1! * value2! 81 | } else { 82 | result = value1! / value2! 83 | } 84 | break 85 | case .Additive: 86 | let child1 = node.getChildren()[0] 87 | let value1 = try evaluate(node: child1, indent: "\t") 88 | let child2 = node.getChildren()[1] 89 | let value2 = try evaluate(node: child2, indent: "\t") 90 | 91 | if node.getText()! == "+" { 92 | result = value1! + value2! 93 | } else { 94 | result = value1! - value2! 95 | } 96 | break 97 | case .Identifier: 98 | let varName = node.getText()! 99 | if variables.keys.contains(varName) { 100 | let value = variables[varName] 101 | 102 | if value != nil { 103 | result = value! 104 | } else { 105 | throw LogoError.logo(error: "variable \(varName) has not been set any value") 106 | } 107 | } else { 108 | throw LogoError.logo(error: "unknown variable: \(varName)") 109 | } 110 | break 111 | case .IntLiteral: 112 | result = Int(node.getText()!) 113 | break 114 | } 115 | 116 | if SimpleScript.verbose { 117 | print("\(indent)Result: \(String(describing: result))") 118 | } else if indent == "" { // 顶层的语句 119 | if node.getType() == .IntDeclaration || node.getType() == .AssignmentStmt { 120 | print("\(String(describing: node.getText())): \(String(describing: result))") 121 | } else { 122 | print(String(describing: result)) 123 | } 124 | } 125 | } 126 | 127 | return result 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /LogoCompiler/Token.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Token.swift 3 | // LogoCompiler 4 | // 5 | // Created by developer on 8/19/19. 6 | // Copyright © 2019 iOSDevLog. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | /** 11 | * 一个简单的Token。 12 | * 只有类型和文本值两个属性。 13 | */ 14 | public protocol Token { 15 | 16 | /** 17 | * Token的类型 18 | * @return 19 | */ 20 | func getType() -> TokenType? 21 | 22 | /** 23 | * Token的文本值 24 | * @return 25 | */ 26 | func getText() -> String? 27 | 28 | } 29 | -------------------------------------------------------------------------------- /LogoCompiler/TokenReader.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TokenReader.swift 3 | // LogoCompiler 4 | // 5 | // Created by developer on 8/19/19. 6 | // Copyright © 2019 iOSDevLog. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | /** 11 | * 一个Token流。由Lexer生成。Parser可以从中获取Token。 12 | */ 13 | public protocol TokenReader { 14 | /** 15 | * 返回Token流中下一个Token,并从流中取出。 如果流已经为空,返回null; 16 | */ 17 | func read() -> Token? 18 | /** 19 | * 返回Token流中下一个Token,但不从流中取出。 如果流已经为空,返回null; 20 | */ 21 | func peek() -> Token? 22 | 23 | /** 24 | * Token流回退一步。恢复原来的Token。 25 | */ 26 | func unread() 27 | 28 | /** 29 | * 获取Token流当前的读取位置。 30 | * @return 31 | */ 32 | func getPosition() -> Int 33 | 34 | /** 35 | * 设置Token流当前的读取位置 36 | * @param position 37 | */ 38 | func setPosition(position: Int) 39 | } 40 | -------------------------------------------------------------------------------- /LogoCompiler/TokenType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TokenType.swift 3 | // LogoCompiler 4 | // 5 | // Created by developer on 8/19/19. 6 | // Copyright © 2019 iOSDevLog. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | /** 11 | * Token的类型 12 | */ 13 | public enum TokenType { 14 | case 15 | Plus, // + 16 | Minus, // - 17 | Star, // * 18 | Slash, // / 19 | 20 | GE, // >= 21 | GT, // > 22 | EQ, // == 23 | LE, // <= 24 | LT, // < 25 | 26 | SemiColon, // ; 27 | LeftParen, // ( 28 | RightParen, // ) 29 | 30 | Assignment, // = 31 | 32 | If, 33 | Else, 34 | 35 | Int, 36 | 37 | Identifier, //标识符 38 | 39 | IntLiteral, //整型字面量 40 | StringLiteral //字符串字面量 41 | } 42 | -------------------------------------------------------------------------------- /LogoCompilerTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /LogoCompilerTests/SimpleCalculatorTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SimpleCalculatorTests.swift 3 | // SimpleCalculatorTests 4 | // 5 | // Created by developer on 8/19/19. 6 | // Copyright © 2019 iOSDevLog. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import LogoCompiler 11 | 12 | class SimpleCalculatorTests: XCTestCase { 13 | 14 | override func setUp() { 15 | // Put setup code here. This method is called before the invocation of each test method in the class. 16 | } 17 | 18 | override func tearDown() { 19 | // Put teardown code here. This method is called after the invocation of each test method in the class. 20 | } 21 | 22 | func testCalculator() { 23 | let calculator = SimpleCalculator() 24 | var script = "int a = b+3;" 25 | print("解析变量声明语句: \(script)") 26 | let lexer = SimpleLexer() 27 | let tokens = lexer.tokenize(code: script) 28 | 29 | do { 30 | if let node = try calculator.intDeclare(tokens: tokens) { 31 | calculator.dumpAST(node: node,indent: "") 32 | } 33 | } catch { 34 | print(error) 35 | } 36 | 37 | // 测试表达式 38 | script = "2+3*5" 39 | print("\n计算: \(script),看上去一切正常。") 40 | calculator.evaluate(script: script) 41 | 42 | script = "2+3+4" 43 | print("\n计算: \(script),结合性出现错误。") 44 | calculator.evaluate(script: script) 45 | } 46 | 47 | func testPerformanceExample() { 48 | // This is an example of a performance test case. 49 | self.measure { 50 | // Put the code you want to measure the time of here. 51 | } 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /LogoCompilerTests/SimpleLexerTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SimpleLexerTests.swift 3 | // LogoCompilerTests 4 | // 5 | // Created by developer on 8/19/19. 6 | // Copyright © 2019 iOSDevLog. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import LogoCompiler 11 | 12 | class SimpleLexerTests: XCTestCase { 13 | 14 | override func setUp() { 15 | // Put setup code here. This method is called before the invocation of each test method in the class. 16 | } 17 | 18 | override func tearDown() { 19 | // Put teardown code here. This method is called after the invocation of each test method in the class. 20 | } 21 | 22 | func testSimpleLexerExample() { 23 | let lexer = SimpleLexer() 24 | 25 | // 测试 int 的解析 26 | var script = "int age = 45;" 27 | print("\nparse:\t\(script)") 28 | var tokenReader = lexer.tokenize(code: script) 29 | SimpleLexer.dump(tokenReader: tokenReader) 30 | 31 | // 测试 inta 的解析 32 | script = "inta age = 45;" 33 | print("\nparse:\t\(script)") 34 | tokenReader = lexer.tokenize(code: script) 35 | SimpleLexer.dump(tokenReader: tokenReader) 36 | 37 | // 测试 in 的解析 38 | script = "in age = 45;" 39 | print("\nparse:\t\(script)") 40 | tokenReader = lexer.tokenize(code: script) 41 | SimpleLexer.dump(tokenReader: tokenReader) 42 | 43 | // 测试 >= 的解析 44 | script = "age >= 45;" 45 | print("\nparse:\t\(script)") 46 | tokenReader = lexer.tokenize(code: script) 47 | SimpleLexer.dump(tokenReader: tokenReader) 48 | 49 | // 测试 > 的解析 50 | script = "age > 45;" 51 | print("\nparse:\t\(script)") 52 | tokenReader = lexer.tokenize(code: script) 53 | SimpleLexer.dump(tokenReader: tokenReader) 54 | 55 | // 测试 +-*/ 的解析 56 | script = "int a = 3; int b = 4; int c = 5; int x = a+b*c;" 57 | print("\nparse:\t\(script)") 58 | tokenReader = lexer.tokenize(code: script) 59 | SimpleLexer.dump(tokenReader: tokenReader) 60 | } 61 | 62 | func testPerformanceExample() { 63 | // This is an example of a performance test case. 64 | self.measure { 65 | // Put the code you want to measure the time of here. 66 | } 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /LogoCompilerTests/SimpleParserTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SimpleParserTests.swift 3 | // LogoCompilerTests 4 | // 5 | // Created by developer on 8/21/19. 6 | // Copyright © 2019 iOSDevLog. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import LogoCompiler 11 | 12 | class SimpleParserTests: XCTestCase { 13 | 14 | override func setUp() { 15 | // Put setup code here. This method is called before the invocation of each test method in the class. 16 | } 17 | 18 | override func tearDown() { 19 | // Put teardown code here. This method is called after the invocation of each test method in the class. 20 | } 21 | 22 | func testParser() { 23 | let parser = SimpleParser() 24 | let script = "int age = 45+2; age= 20; age+10*2;" 25 | print("语法分析: \(script)") 26 | 27 | do { 28 | if let node = try parser.parse(code: script) { 29 | parser.dumpAST(node: node,indent: "") 30 | } 31 | } catch { 32 | print(error) 33 | } 34 | } 35 | 36 | func testPerformanceExample() { 37 | // This is an example of a performance test case. 38 | self.measure { 39 | // Put the code you want to measure the time of here. 40 | } 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /LogoCompilerTests/SimpleScriptTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SimpleScriptTests.swift 3 | // LogoCompilerTests 4 | // 5 | // Created by developer on 8/23/19. 6 | // Copyright © 2019 iOSDevLog. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import LogoCompiler 11 | 12 | class SimpleScriptTests: XCTestCase { 13 | 14 | override func setUp() { 15 | // Put setup code here. This method is called before the invocation of each test method in the class. 16 | } 17 | 18 | override func tearDown() { 19 | // Put teardown code here. This method is called after the invocation of each test method in the class. 20 | } 21 | 22 | func testScript() { 23 | print("Simple script language!") 24 | 25 | SimpleScript.verbose = true 26 | let parser = SimpleParser() 27 | let script = SimpleScript() 28 | 29 | var scriptText = "" 30 | 31 | print("\n>") 32 | 33 | let lines = [ 34 | "2+3;", 35 | "int age = 10;", 36 | "int b;", 37 | "b = 10*2;", 38 | "age = age + b;" 39 | ] 40 | 41 | for line in lines { 42 | do { 43 | scriptText += line + "\n" 44 | 45 | if line.hasSuffix(";") { 46 | let tree = try parser.parse(code: scriptText) 47 | 48 | if let tree = tree { 49 | if SimpleScript.verbose { 50 | parser.dumpAST(node: tree, indent: "") 51 | } 52 | _ = try script.evaluate(node: tree, indent: "") 53 | } 54 | scriptText = "" 55 | } 56 | } catch LogoError.logo(let logoError) { 57 | print(logoError) 58 | } catch { 59 | print(error) 60 | print("\n>") 61 | scriptText = "" 62 | } 63 | } 64 | 65 | } 66 | 67 | func testPerformanceExample() { 68 | // This is an example of a performance test case. 69 | self.measure { 70 | // Put the code you want to measure the time of here. 71 | } 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /LogoTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /LogoTests/LogoTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LogoTests.swift 3 | // LogoTests 4 | // 5 | // Created by developer on 8/19/19. 6 | // Copyright © 2019 iOSDevLog. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import Logo 11 | 12 | class LogoTests: XCTestCase { 13 | 14 | override func setUp() { 15 | // Put setup code here. This method is called before the invocation of each test method in the class. 16 | } 17 | 18 | override func tearDown() { 19 | // Put teardown code here. This method is called after the invocation of each test method in the class. 20 | } 21 | 22 | func testExample() { 23 | // This is an example of a functional test case. 24 | // Use XCTAssert and related functions to verify your tests produce the correct results. 25 | } 26 | 27 | func testPerformanceExample() { 28 | // This is an example of a performance test case. 29 | self.measure { 30 | // Put the code you want to measure the time of here. 31 | } 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Logo 2 | 3 | --- 4 | 5 | Logo Programming Language for iOS 6 | 7 | ## Screenshot 8 | 9 | ![repl](screenshot/repl.png) 10 | 11 | ![ast](screenshot/ast.png) 12 | 13 | ![ast2](screenshot/ast2.png) 14 | 15 | ![token](screenshot/token.png) 16 | 17 | ![parse](screenshot/parse.png) 18 | 19 | ## Contacts 20 | 21 | Weblog: [http://2019.iosdevlog.com/](https://2019.iosdevlog.com/) 22 | 23 | 微信公众号: AI开发日志 24 | 25 | ![AIDevLog](https://2019.iosdevlog.com/uploads/AIDevLog.png) 26 | 27 | ## License 28 | 29 | slmethod is released under the MIT license. See [LICENSE](LICENSE) for details. 30 | -------------------------------------------------------------------------------- /screenshot/ast.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iOSDevLog/Logo/3a8046e49e8021f0999de3c1c8f0a69229225d56/screenshot/ast.png -------------------------------------------------------------------------------- /screenshot/ast2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iOSDevLog/Logo/3a8046e49e8021f0999de3c1c8f0a69229225d56/screenshot/ast2.png -------------------------------------------------------------------------------- /screenshot/editor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iOSDevLog/Logo/3a8046e49e8021f0999de3c1c8f0a69229225d56/screenshot/editor.png -------------------------------------------------------------------------------- /screenshot/parse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iOSDevLog/Logo/3a8046e49e8021f0999de3c1c8f0a69229225d56/screenshot/parse.png -------------------------------------------------------------------------------- /screenshot/repl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iOSDevLog/Logo/3a8046e49e8021f0999de3c1c8f0a69229225d56/screenshot/repl.png -------------------------------------------------------------------------------- /screenshot/token.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iOSDevLog/Logo/3a8046e49e8021f0999de3c1c8f0a69229225d56/screenshot/token.png --------------------------------------------------------------------------------