├── .gitattributes ├── .gitignore ├── .nuget └── packages.config ├── CSharpMonad.UnitTests ├── CSharpMonad.UnitTests.csproj ├── Properties │ └── AssemblyInfo.cs ├── packages.config └── src │ ├── Combined.cs │ ├── EitherTests.cs │ ├── ErrorUnitTests.cs │ ├── ExprParsers.cs │ ├── IOTests.cs │ ├── ImmutableListTests.cs │ ├── LangTests.cs │ ├── MLTests.cs │ ├── MemoizationTests.cs │ ├── OptionTests.cs │ ├── ParsecTests.cs │ ├── ReaderTests.cs │ ├── ReaderWriterStateTests.cs │ ├── StateTests.cs │ ├── TryTests.cs │ ├── WriterTests.cs │ └── lex │ ├── LexerTests.cs │ └── TokTests.cs ├── CSharpMonad.sln ├── CSharpMonad ├── CSharpMonad.csproj ├── CSharpMonad.sln ├── CSharpMonad.xproj ├── Properties │ └── AssemblyInfo.cs ├── lib │ └── Monad.dll ├── project.json ├── project.lock.json └── src │ ├── EitherLazy.cs │ ├── EitherStrict.cs │ ├── IAppendable.cs │ ├── IO.cs │ ├── RWS.cs │ ├── Reader.cs │ ├── State.cs │ ├── Try.cs │ ├── Writer.cs │ ├── ext │ ├── EnumerableExt.cs │ ├── ImmutableListExt.cs │ ├── LiftExt.cs │ ├── ObjectExt.cs │ └── TupleExt.cs │ ├── option-lazy │ ├── Just.cs │ ├── Nothing.cs │ └── Option.cs │ ├── option-strict │ ├── Just.cs │ ├── Nothing.cs │ └── OptionStrict.cs │ ├── parsec │ ├── Empty.cs │ ├── Parser.cs │ ├── ParserChar.cs │ ├── ParserError.cs │ ├── ParserException.cs │ ├── ParserExt.cs │ ├── ParserResult.cs │ ├── Parsers.cs │ ├── Prim.cs │ ├── SrcLoc.cs │ ├── Tok.cs │ ├── expr │ │ ├── Assoc.cs │ │ ├── ExprParser.cs │ │ ├── Operator.cs │ │ └── OperatorTable.cs │ ├── language │ │ ├── EmptyDef.cs │ │ ├── Haskell98Def.cs │ │ ├── HaskellDef.cs │ │ ├── HaskellStyle.cs │ │ └── JavaStyle.cs │ └── token │ │ ├── LanguageDef.cs │ │ ├── TokenParser.cs │ │ ├── TokenParsers.cs │ │ ├── TokenTypes.cs │ │ ├── bracketing │ │ └── Bracketing.cs │ │ ├── chars │ │ └── Chars.cs │ │ ├── idents │ │ └── Idents.cs │ │ ├── numbers │ │ └── Numbers.cs │ │ ├── ops │ │ └── Ops.cs │ │ └── strings │ │ └── Strings.cs │ └── utility │ ├── ImmutableList.cs │ ├── Lam.da.cs │ ├── Memoize.cs │ └── Unit.cs ├── LICENSE.md ├── README.md └── csharp-monad.1.0.1.nuspec /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | 9 | # Build results 10 | 11 | [Dd]ebug/ 12 | [Rr]elease/ 13 | x64/ 14 | build/ 15 | [Bb]in/ 16 | [Oo]bj/ 17 | 18 | .nuget 19 | packages/ 20 | 21 | # MSTest test Results 22 | [Tt]est[Rr]esult*/ 23 | [Bb]uild[Ll]og.* 24 | 25 | *_i.c 26 | *_p.c 27 | *.ilk 28 | *.meta 29 | *.obj 30 | *.pch 31 | *.pdb 32 | *.pgc 33 | *.pgd 34 | *.rsp 35 | *.sbr 36 | *.tlb 37 | *.tli 38 | *.tlh 39 | *.tmp 40 | *.tmp_proj 41 | *.log 42 | *.vspscc 43 | *.vssscc 44 | .builds 45 | *.pidb 46 | *.log 47 | *.scc 48 | 49 | # Visual C++ cache files 50 | ipch/ 51 | *.aps 52 | *.ncb 53 | *.opensdf 54 | *.sdf 55 | *.cachefile 56 | 57 | # Visual Studio profiler 58 | *.psess 59 | *.vsp 60 | *.vspx 61 | 62 | # Guidance Automation Toolkit 63 | *.gpState 64 | 65 | # ReSharper is a .NET coding add-in 66 | _ReSharper*/ 67 | *.[Rr]e[Ss]harper 68 | 69 | # TeamCity is a build add-in 70 | _TeamCity* 71 | 72 | # DotCover is a Code Coverage Tool 73 | *.dotCover 74 | 75 | # NCrunch 76 | *.ncrunch* 77 | .*crunch*.local.xml 78 | 79 | # Installshield output folder 80 | [Ee]xpress/ 81 | 82 | # DocProject is a documentation generator add-in 83 | DocProject/buildhelp/ 84 | DocProject/Help/*.HxT 85 | DocProject/Help/*.HxC 86 | DocProject/Help/*.hhc 87 | DocProject/Help/*.hhk 88 | DocProject/Help/*.hhp 89 | DocProject/Help/Html2 90 | DocProject/Help/html 91 | 92 | # Click-Once directory 93 | publish/ 94 | 95 | # Publish Web Output 96 | *.Publish.xml 97 | 98 | # NuGet Packages Directory 99 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 100 | #packages/ 101 | 102 | # Windows Azure Build Output 103 | csx 104 | *.build.csdef 105 | 106 | # Windows Store app package directory 107 | AppPackages/ 108 | 109 | # Others 110 | sql/ 111 | *.Cache 112 | ClientBin/ 113 | [Ss]tyle[Cc]op.* 114 | ~$* 115 | *~ 116 | *.dbmdl 117 | *.[Pp]ublish.xml 118 | *.pfx 119 | *.publishsettings 120 | 121 | # RIA/Silverlight projects 122 | Generated_Code/ 123 | 124 | # Backup & report files from converting an old project file to a newer 125 | # Visual Studio version. Backup files are not needed, because we have git ;-) 126 | _UpgradeReport_Files/ 127 | Backup*/ 128 | UpgradeLog*.XML 129 | UpgradeLog*.htm 130 | 131 | # SQL Server files 132 | App_Data/*.mdf 133 | App_Data/*.ldf 134 | 135 | 136 | #LightSwitch generated files 137 | GeneratedArtifacts/ 138 | _Pvt_Extensions/ 139 | ModelManifest.xml 140 | 141 | # ========================= 142 | # Windows detritus 143 | # ========================= 144 | 145 | # Windows image file caches 146 | Thumbs.db 147 | ehthumbs.db 148 | 149 | # Folder config file 150 | Desktop.ini 151 | 152 | # Recycle Bin used on file shares 153 | $RECYCLE.BIN/ 154 | 155 | # Mac desktop service store files 156 | .DS_Store 157 | /.vs/config/applicationhost.config 158 | /CSharpMonad/.vs/restore.dg 159 | *.lock.json 160 | /CSharpMonad/.vs/config/applicationhost.config 161 | -------------------------------------------------------------------------------- /.nuget/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /CSharpMonad.UnitTests/CSharpMonad.UnitTests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | Debug 8 | AnyCPU 9 | {496943F4-17B4-41CB-8013-5499543E3DA0} 10 | Library 11 | Properties 12 | CSharpMonad.UnitTests 13 | CSharpMonad.UnitTests 14 | v4.5 15 | 512 16 | 12.0.0 17 | 2.0 18 | 0a724ffb 19 | 20 | 21 | true 22 | full 23 | false 24 | bin\Debug\ 25 | DEBUG;TRACE 26 | prompt 27 | 4 28 | 29 | 30 | pdbonly 31 | true 32 | bin\Release\ 33 | TRACE 34 | prompt 35 | 4 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | ..\packages\xunit.abstractions.2.0.0-rc1-build2826\lib\net35\xunit.abstractions.dll 47 | 48 | 49 | ..\packages\xunit.assert.2.0.0-rc1-build2826\lib\portable-net45+aspnetcore50+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.assert.dll 50 | 51 | 52 | ..\packages\xunit.extensibility.core.2.0.0-rc1-build2826\lib\portable-net45+aspnetcore50+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.core.dll 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 | {254abd61-bedb-4478-9708-606e85310fe0} 85 | CSharpMonad 86 | 87 | 88 | 89 | 90 | 91 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 108 | -------------------------------------------------------------------------------- /CSharpMonad.UnitTests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Monad.UnitTests")] 9 | [assembly: AssemblyDescription("Monad library unit tests")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Monad.UnitTests")] 13 | [assembly: AssemblyCopyright("Copyright © Paul Louth 2014 - MIT License")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("64b47c63-9311-4431-bd6f-dbc8965bac9e")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /CSharpMonad.UnitTests/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /CSharpMonad.UnitTests/src/Combined.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | using System; 26 | using System.Linq; 27 | 28 | using Monad; 29 | using Xunit; 30 | using System.Reflection; 31 | 32 | namespace Monad.UnitTests 33 | { 34 | public class Combined 35 | { 36 | [Fact] 37 | public void Combined1() 38 | { 39 | var t1 = ErrIO(() => 1); 40 | var t2 = ErrIO(() => 2); 41 | var t3 = ErrIO(() => 3); 42 | 43 | var res = from one in t1 44 | from two in t2 45 | from thr in t3 46 | select one + two + thr; 47 | 48 | Assert.True(res().Value == 6); 49 | } 50 | 51 | [Fact] 52 | public void Combined2() 53 | { 54 | 55 | var t1 = ErrIO(() => 1); 56 | var t2 = ErrIO(() => 2); 57 | var t3 = ErrIO(() => 3); 58 | var fail = ErrIO(() => 59 | { 60 | throw new Exception("Error"); 61 | }); 62 | 63 | var res = from one in t1 64 | from two in t2 65 | from thr in t3 66 | from err in fail 67 | select one + two + thr + err; 68 | 69 | Assert.True(res().IsFaulted); 70 | } 71 | 72 | private Try ErrIO(IO fn) 73 | { 74 | return new Try(() => fn()); 75 | } 76 | 77 | private Try> Trans(IO inner) 78 | { 79 | return () => inner; 80 | } 81 | 82 | private Reader> Trans(Try inner) 83 | { 84 | return (env) => inner; 85 | } 86 | 87 | public IO Hello() 88 | { 89 | return () => "Hello,"; 90 | } 91 | 92 | public IO World() 93 | { 94 | return () => " World"; 95 | } 96 | 97 | // Messing 98 | [Fact] 99 | public void TransTest() 100 | { 101 | var errT = Trans(from h in Hello() 102 | from w in World() 103 | select h + w); 104 | 105 | var rdrT = Trans>(errT); 106 | 107 | Assert.True(rdrT("environ")().Value() == "Hello, World"); 108 | } 109 | 110 | public Try>> OpenFile(string fn) 111 | { 112 | return () => Option.Return(() => IO.Return(() => "Data"+fn)); 113 | } 114 | 115 | [Fact] 116 | public void TransTest2() 117 | { 118 | var mon = from ed1 in OpenFile("1") 119 | from ed2 in OpenFile("2") 120 | select Lift.M(ed1, ed2, (ioa,iob) => 121 | Lift.M(ioa, iob, (a,b) => 122 | a + b 123 | )); 124 | 125 | var res = mon(); 126 | 127 | Assert.True(res.Value().Value() == "Data1Data2"); 128 | } 129 | } 130 | } 131 | 132 | -------------------------------------------------------------------------------- /CSharpMonad.UnitTests/src/EitherTests.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | using System; 26 | using Xunit; 27 | using Monad; 28 | 29 | namespace Monad.UnitTests 30 | { 31 | public class EitherTests 32 | { 33 | [Fact] 34 | public void TestEitherBinding1() 35 | { 36 | var r = from lhs in Two() 37 | from rhs in Two() 38 | select lhs+rhs; 39 | 40 | Assert.True(r.IsRight() && r.Right() == 4); 41 | } 42 | 43 | [Fact] 44 | public void TestEitherBinding2() 45 | { 46 | var r = (from lhs in Two() 47 | from rhs in Error() 48 | select lhs + rhs) 49 | .Memo(); 50 | 51 | Assert.True(r().IsLeft && r().Left == "Error!!"); 52 | } 53 | 54 | 55 | [Fact] 56 | public void TestEitherBinding3() 57 | { 58 | var r = 59 | from lhs in Two() 60 | select lhs; 61 | 62 | Assert.True(r.IsRight() && r.Right() == 2); 63 | } 64 | 65 | [Fact] 66 | public void TestEitherBinding4() 67 | { 68 | var r = 69 | from lhs in Error() 70 | select lhs; 71 | 72 | Assert.True(r.IsLeft() && r.Left() == "Error!!"); 73 | } 74 | 75 | [Fact] 76 | public void TestEitherBinding5() 77 | { 78 | var r = 79 | from one in Two() 80 | from two in Error() 81 | from thr in Two() 82 | select one + two + thr; 83 | 84 | Assert.True(r.IsLeft() && r.Left() == "Error!!"); 85 | } 86 | 87 | [Fact] 88 | public void TestEitherMatch1() 89 | { 90 | var unit = 91 | (from one in Two() 92 | from two in Error() 93 | from thr in Two() 94 | select one + two + thr) 95 | .Match( 96 | Right: r => Assert.True(false), 97 | Left: l => Assert.True(l == "Error!!") 98 | ); 99 | 100 | Console.WriteLine(unit.ToString()); 101 | } 102 | 103 | [Fact] 104 | public void TestEitherMatch2() 105 | { 106 | var unit = 107 | (from one in Two() 108 | from two in Error() 109 | from thr in Two() 110 | select one + two + thr) 111 | .Match( 112 | right => Assert.False(true), 113 | left => Assert.True(left == "Error!!") 114 | ); 115 | Console.WriteLine(unit.ToString()); 116 | } 117 | 118 | [Fact] 119 | public void TestEitherMatch3() 120 | { 121 | var unit = 122 | (from one in Two() 123 | from two in Two() 124 | select one + two) 125 | .Match( 126 | Right: r => Assert.True(r == 4), 127 | Left: l => Assert.False(true) 128 | ); 129 | Console.WriteLine(unit.ToString()); 130 | } 131 | 132 | [Fact] 133 | public void TestEitherMatch4() 134 | { 135 | var unit = 136 | (from one in Two() 137 | from two in Two() 138 | select one + two) 139 | .Match( 140 | right => Assert.True(right == 4), 141 | left => Assert.False(true) 142 | ); 143 | Console.WriteLine(unit.ToString()); 144 | } 145 | 146 | [Fact] 147 | public void TestEitherMatch5() 148 | { 149 | var result = 150 | (from one in Two() 151 | from two in Two() 152 | select one + two) 153 | .Match( 154 | Right: r => r * 2, 155 | Left: l => 0 156 | ); 157 | 158 | Assert.True(result() == 8); 159 | } 160 | 161 | [Fact] 162 | public void TestEitherMatch6() 163 | { 164 | var result = 165 | (from one in Two() 166 | from err in Error() 167 | from two in Two() 168 | select one + two) 169 | .Match( 170 | Right: r => r * 2, 171 | Left: l => 0 172 | ); 173 | 174 | Assert.True(result() == 0); 175 | } 176 | 177 | public Either Two() 178 | { 179 | return () => 2; 180 | } 181 | 182 | public Either Error() 183 | { 184 | return () => "Error!!"; 185 | } 186 | } 187 | } 188 | 189 | -------------------------------------------------------------------------------- /CSharpMonad.UnitTests/src/ExprParsers.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | using Xunit; 26 | using Monad.Parsec; 27 | using System; 28 | using System.Collections.Generic; 29 | using System.Linq; 30 | using System.Text; 31 | using System.Threading.Tasks; 32 | 33 | namespace Monad.UnitTests 34 | { 35 | public class TestExpr 36 | { 37 | [Fact] 38 | public void ExpressionTests() 39 | { 40 | var ten = Eval("2*3+4"); 41 | 42 | Assert.True(ten == 10); 43 | 44 | var fourteen = Eval("2*(3+4)"); 45 | 46 | Assert.True(fourteen == 14); 47 | } 48 | 49 | 50 | public int Eval(string expr) 51 | { 52 | var r = New.Expr().Parse(expr); 53 | if (r.Value.Count() == 0) 54 | { 55 | return 999; 56 | } 57 | else 58 | { 59 | return r.Value.First().Item1; 60 | } 61 | } 62 | } 63 | 64 | 65 | public class New 66 | { 67 | public static Expr Expr() 68 | { 69 | return new Expr(); 70 | } 71 | public static Term Term() 72 | { 73 | return new Term(); 74 | } 75 | public static Factor Factor() 76 | { 77 | return new Factor(); 78 | } 79 | } 80 | 81 | public class Expr : Parser 82 | { 83 | public Expr() 84 | : 85 | base( 86 | inp => (from t in New.Term() 87 | from e in 88 | (from plus in Prim.Character('+') 89 | from expr in New.Expr() 90 | select expr) 91 | | Prim.Return(0) 92 | select t + e) 93 | .Parse(inp) 94 | ) 95 | { } 96 | } 97 | 98 | public class Term : Parser 99 | { 100 | public Term() 101 | : 102 | base( 103 | inp => (from f in New.Factor() 104 | from t in 105 | (from mult in Prim.Character('*') 106 | from term in New.Term() 107 | select term) 108 | | Prim.Return(1) 109 | select f * t) 110 | .Parse(inp) 111 | ) 112 | { } 113 | } 114 | 115 | public class Factor : Parser 116 | { 117 | public Factor() 118 | : 119 | base( 120 | inp => (from choice in 121 | (from d in Prim.Digit() 122 | select Int32.Parse(d.Value.ToString())) 123 | | (from open in Prim.Character('(') 124 | from expr in New.Expr() 125 | from close in Prim.Character(')') 126 | select expr) 127 | select choice) 128 | .Parse(inp) 129 | 130 | ) 131 | { } 132 | 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /CSharpMonad.UnitTests/src/IOTests.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | using System; 26 | using System.Collections.Generic; 27 | using System.Linq; 28 | using System.Text; 29 | using System.Threading.Tasks; 30 | using Monad; 31 | using Xunit; 32 | using System.Reflection; 33 | using System.IO; 34 | using Monad.Utility; 35 | 36 | namespace Monad.UnitTests 37 | { 38 | public class IOTests 39 | { 40 | [Fact] 41 | public void TestIOMonadLazyLoading() 42 | { 43 | var m = I.O(() => 44 | System.IO.File.ReadAllBytes(Assembly.GetCallingAssembly().Location) 45 | ); 46 | 47 | m (); 48 | } 49 | 50 | [Fact] 51 | public void TestIOMonadBinding() 52 | { 53 | string data = "Testing 123"; 54 | 55 | var result = from tmpFileName in GetTempFileName() 56 | from _ in WriteFile(tmpFileName, data) 57 | from dataFromFile in ReadFile(tmpFileName) 58 | from __ in DeleteFile(tmpFileName) 59 | select dataFromFile; 60 | 61 | Assert.True(result.Invoke() == "Testing 123"); 62 | } 63 | 64 | [Fact] 65 | public void TestIOMonadBindingFluent() 66 | { 67 | string data = "Testing 123"; 68 | 69 | var result = GetTempFileName() 70 | .Then( tmpFileName => { WriteFile(tmpFileName, data)(); return tmpFileName; } ) 71 | .Then( tmpFileName => { return new { tmpFileName, data = ReadFile(tmpFileName)() }; }) 72 | .Then( context => { DeleteFile(context.tmpFileName)(); return context.data; } ); 73 | 74 | Assert.True(result.Invoke() == "Testing 123"); 75 | } 76 | 77 | private static IO DeleteFile(string tmpFileName) 78 | { 79 | return () => 80 | Unit.Return( 81 | () => File.Delete(tmpFileName) 82 | ); 83 | } 84 | 85 | private static IO ReadFile(string tmpFileName) 86 | { 87 | return () => File.ReadAllText(tmpFileName); 88 | } 89 | 90 | private static IO WriteFile(string tmpFileName, string data) 91 | { 92 | return () => 93 | Unit.Return( 94 | () => File.WriteAllText(tmpFileName, data) 95 | ); 96 | } 97 | 98 | private static IO GetTempFileName() 99 | { 100 | return () => Path.GetTempFileName(); 101 | } 102 | } 103 | } -------------------------------------------------------------------------------- /CSharpMonad.UnitTests/src/ImmutableListTests.cs: -------------------------------------------------------------------------------- 1 | using Monad.Parsec; 2 | using Xunit; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using Monad.Utility; 9 | 10 | 11 | namespace Monad.UnitTests 12 | { 13 | public class ImmutableListTests 14 | { 15 | [Fact] 16 | public void EnumeratorTest1() 17 | { 18 | var list1 = new ImmutableList(new int[] { 0, 1, 2 }); 19 | 20 | int index = 0; 21 | foreach (var item in list1) 22 | { 23 | Assert.True(item == index); 24 | index++; 25 | } 26 | Assert.True(index == 3); 27 | } 28 | 29 | [Fact] 30 | public void EnumeratorTest2() 31 | { 32 | var list1 = new ImmutableList(new int[] { 0, 1, 2 }); 33 | var list2 = new ImmutableList(new int[] { 3, 4, 5 }); 34 | 35 | var list = list1.Concat(list2); 36 | 37 | int index = 0; 38 | foreach (var item in list) 39 | { 40 | Assert.True(item == index); 41 | index++; 42 | } 43 | 44 | Assert.True(index == 6); 45 | } 46 | 47 | [Fact] 48 | public void EnumeratorTest3() 49 | { 50 | var list1 = new ImmutableList(new int[] { 1, 2, 3 }); 51 | var list2 = new ImmutableList(new int[] { 4, 5, 6 }); 52 | 53 | var list = 0.Cons( list1.Concat(list2) ); 54 | 55 | int index = 0; 56 | foreach (var item in list) 57 | { 58 | Assert.True(item == index); 59 | index++; 60 | } 61 | 62 | Assert.True(index == 7); 63 | } 64 | 65 | [Fact] 66 | public void EnumeratorLengthTest1() 67 | { 68 | var list1 = new ImmutableList(new int[] { 0, 1, 2 }); 69 | var list2 = new ImmutableList(new int[] { 3, 4, 5 }); 70 | 71 | var list = list1.Concat(list2); 72 | 73 | Assert.True(list.Length == 6); 74 | 75 | list = list.Tail(); 76 | Assert.True(list.Length == 5); 77 | 78 | list = list.Tail(); 79 | list = list.Tail(); 80 | list = list.Tail(); 81 | list = list.Tail(); 82 | 83 | Assert.True(list.Length == 1); 84 | Assert.True(list.IsAlmostEmpty); 85 | 86 | list = list.Tail(); 87 | Assert.True(list.IsEmpty); 88 | 89 | Assert.Throws(() => list.Tail()); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /CSharpMonad.UnitTests/src/MemoizationTests.cs: -------------------------------------------------------------------------------- 1 | using Xunit; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Monad.UnitTests 9 | { 10 | public class MemoizationTests 11 | { 12 | int breakIt = 0; 13 | 14 | [Fact] 15 | public void MemoizationTest1() 16 | { 17 | var mon = (from one in One() 18 | from two in Two() 19 | from thr in Three() 20 | select one + two + thr) 21 | .Memo(); 22 | 23 | var res = mon(); 24 | Assert.True(res == 6); 25 | breakIt++; 26 | 27 | res = mon(); 28 | Assert.True(res == 6); 29 | } 30 | 31 | public Monad One() 32 | { 33 | return () => 1 + breakIt; 34 | } 35 | 36 | public Monad Two() 37 | { 38 | return () => 2 + breakIt; 39 | } 40 | 41 | public Monad Three() 42 | { 43 | return () => 3 + breakIt; 44 | } 45 | } 46 | 47 | public delegate T Monad(); 48 | 49 | public static class TestMonadExt 50 | { 51 | public static Monad Select(this Monad self, Func map) 52 | { 53 | return () => 54 | { 55 | var resT = self(); 56 | 57 | var resU = map(resT); 58 | 59 | return resU; 60 | }; 61 | } 62 | 63 | public static Monad SelectMany( 64 | this Monad self, 65 | Func> select, 66 | Func project 67 | ) 68 | { 69 | return () => 70 | { 71 | var resT = self(); 72 | var resU = select(resT)(); 73 | var resV = project(resT, resU); 74 | 75 | return resV; 76 | }; 77 | } 78 | 79 | /// 80 | /// Memoize the result 81 | /// 82 | public static Func Memo(this Monad self) 83 | { 84 | var res = self(); 85 | return () => res; 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /CSharpMonad.UnitTests/src/OptionTests.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | using Xunit; 26 | using System; 27 | using System.Collections.Generic; 28 | using System.Linq; 29 | using System.Text; 30 | using System.Threading.Tasks; 31 | using Monad; 32 | using Monad.Utility; 33 | 34 | namespace Monad.UnitTests 35 | { 36 | public class OptionTests 37 | { 38 | [Fact] 39 | public void TestBinding() 40 | { 41 | Option option = () => 1000.ToOption(); 42 | Option option2 = () => 2000.ToOption(); 43 | 44 | var result = from o in option 45 | select o; 46 | 47 | Assert.True(result.HasValue() && result.Value() == 1000); 48 | Assert.True(result.Match(Just: () => true, Nothing: () => false)()); 49 | Assert.True(result.Match(Just: () => true, Nothing: false)()); 50 | 51 | result = from o in option 52 | from o2 in option2 53 | select o2; 54 | 55 | Assert.True(result.HasValue() && result.Value() == 2000); 56 | Assert.True(result.Match(Just: () => true, Nothing: () => false)()); 57 | Assert.True(result.Match(Just: () => true, Nothing: false)()); 58 | 59 | result = from o in option 60 | from o2 in Nothing() 61 | select o2; 62 | 63 | Assert.True(result.HasValue() == false); 64 | } 65 | 66 | [Fact] 67 | public void TestEquals() 68 | { 69 | OptionStrict option = 1000.ToOptionStrict(); 70 | OptionStrict option2 = 1000.ToOptionStrict(); 71 | 72 | Assert.True(option == option2); 73 | } 74 | 75 | public Option Nothing() 76 | { 77 | return Option.Nothing(); 78 | } 79 | } 80 | } -------------------------------------------------------------------------------- /CSharpMonad.UnitTests/src/ReaderTests.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | using System; 26 | using System.Collections.Generic; 27 | using System.Linq; 28 | using System.Text; 29 | using System.Threading.Tasks; 30 | using Xunit; 31 | using Monad; 32 | 33 | namespace Monad.UnitTests 34 | { 35 | public class ReaderTests 36 | { 37 | [Fact] 38 | public void ReaderBindTest1() 39 | { 40 | var person = new Person { Name = "Joe", Surname = "Bloggs" }; 41 | 42 | var reader = from n in Name() 43 | from s in Surname() 44 | select n + " " + s; 45 | 46 | Assert.True(reader(person) == "Joe Bloggs"); 47 | 48 | } 49 | 50 | [Fact] 51 | public void ReaderAskTest1() 52 | { 53 | var person = new Person { Name = "Joe", Surname = "Bloggs" }; 54 | 55 | var reader = from p in Reader.Ask() 56 | select p.Name + " " + p.Surname; 57 | 58 | Assert.True(reader(person) == "Joe Bloggs"); 59 | 60 | } 61 | 62 | [Fact] 63 | public void ReaderAskTest2() 64 | { 65 | var person = new Person { Name = "Joe", Surname = "Bloggs" }; 66 | 67 | var reader = from p in Reader.Ask() 68 | let nl = p.Name.Length 69 | let sl = p.Surname.Length 70 | select nl * sl; 71 | 72 | Assert.True(reader(person) == 18); 73 | 74 | } 75 | 76 | [Fact] 77 | public void ReaderAskReturnAndBindTest() 78 | { 79 | var person = new Person { Name = "Joe", Surname = "Bloggs" }; 80 | 81 | var env = Reader.Return(10); 82 | 83 | var reader = from x in env 84 | from p in Reader.Ask() 85 | let nl = p.Name.Length 86 | let sl = p.Surname.Length 87 | select nl * sl * x; 88 | 89 | Assert.True(reader(person) == 180); 90 | } 91 | 92 | [Fact] 93 | public void ReaderAskReturnAndBindTest2() 94 | { 95 | var person = new Person { Name = "Joe", Surname = "Bloggs" }; 96 | 97 | var env = Reader.Return(10); 98 | 99 | var reader = from x in env 100 | from p in env.Ask() 101 | let nl = p.Name.Length 102 | let sl = p.Surname.Length 103 | select nl * sl * x; 104 | 105 | Assert.True(reader(person) == 180); 106 | } 107 | 108 | 109 | class Person 110 | { 111 | public string Name; 112 | public string Surname; 113 | } 114 | 115 | private static Reader Name() 116 | { 117 | return env => env.Name; 118 | } 119 | 120 | private static Reader Surname() 121 | { 122 | return env => env.Surname; 123 | } 124 | 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /CSharpMonad.UnitTests/src/ReaderWriterStateTests.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | using System; 26 | using System.Collections.Generic; 27 | using System.Linq; 28 | using System.Text; 29 | using System.Threading.Tasks; 30 | using Xunit; 31 | using Monad; 32 | 33 | namespace Monad.UnitTests 34 | { 35 | public class ReaderWriterStateTests 36 | { 37 | [Fact] 38 | public void ReaderWriterStateTest1() 39 | { 40 | var world = RWS.Return(0); 41 | 42 | var rws = (from _ in world 43 | from app in RWS.Get() 44 | from env in RWS.Ask() 45 | from x in Value(app.UsersLoggedIn, "Users logged in: " + app.UsersLoggedIn) 46 | from y in Value(100, "System folder: " + env.SystemFolder) 47 | from s in RWS.Put(new App { UsersLoggedIn = 35 }) 48 | from t in RWS.Tell("Process complete") 49 | select x * y) 50 | .Memo(new Env(), new App()); 51 | 52 | var res = rws(); 53 | 54 | Assert.True(res.Value == 3400); 55 | Assert.True(res.State.UsersLoggedIn == 35); 56 | Assert.True(res.Output.Count() == 3); 57 | Assert.True(res.Output.First() == "Users logged in: 34"); 58 | Assert.True(res.Output.Skip(1).First() == "System folder: C:/Temp"); 59 | Assert.True(res.Output.Skip(2).First() == "Process complete"); 60 | } 61 | 62 | public static RWS Value(int val, string log) 63 | { 64 | return (Env r, App s) => RWS.Tell(val, log); 65 | } 66 | } 67 | 68 | 69 | public class App 70 | { 71 | public int UsersLoggedIn = 34; 72 | } 73 | 74 | public class Env 75 | { 76 | public string SystemFolder = "C:/Temp"; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /CSharpMonad.UnitTests/src/StateTests.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | using System; 26 | using Monad; 27 | using Xunit; 28 | using Monad.Utility; 29 | 30 | namespace Monad.UnitTests 31 | { 32 | public class StateTests 33 | { 34 | [Fact] 35 | public void StateTest1() 36 | { 37 | var state = State.Return(); 38 | 39 | var sm = from w in state 40 | from x in DoSomething() 41 | from y in DoSomethingElse() 42 | select x + y; 43 | 44 | var res = sm("Hello"); 45 | 46 | 47 | Assert.True(res.State == "Hello, World"); 48 | Assert.True(res.Value == 3); 49 | } 50 | 51 | [Fact] 52 | public void StateTest2() 53 | { 54 | var sm = from x in State.Get() 55 | from y in State.Put("Hello"+x) 56 | select y; 57 | 58 | var res = sm(", World"); 59 | 60 | Assert.True(res.State == "Hello, World"); 61 | } 62 | 63 | [Fact] 64 | public void StateTest3() 65 | { 66 | var initial = State.Return(10); 67 | 68 | var sm = from x in initial 69 | from t in State.Get() 70 | from y in State.Put("Hello " + (x * 10) + t) 71 | select y; 72 | 73 | var res = sm(", World"); 74 | 75 | Assert.True(res.State == "Hello 100, World"); 76 | } 77 | 78 | [Fact] 79 | public void StateTest4() 80 | { 81 | var first = State.Return(10); 82 | var second = State.Return(3); 83 | 84 | var sm = from x in first 85 | from t in State.Get() 86 | from y in second 87 | from s in State.Put("Hello " + (x * y) + t) 88 | select s; 89 | 90 | var res = sm(", World"); 91 | 92 | Assert.True(res.State == "Hello 30, World"); 93 | } 94 | 95 | [Fact] 96 | public void StateTest5() 97 | { 98 | var first = State.Return(10); 99 | var second = State.Return(3); 100 | var third = State.Return(5); 101 | var fourth = State.Return(100); 102 | 103 | var sm = from x in first 104 | from t in State.Get() 105 | from y in second 106 | from s in State.Put("Hello " + (x * y) + t) 107 | from z in third 108 | from w in fourth 109 | from s1 in State.Get() 110 | from s2 in State.Put( s1 + " " + (z * w) ) 111 | select x * y * z * w; 112 | 113 | var res = sm(", World"); 114 | 115 | Assert.True(res.State == "Hello 30, World 500"); 116 | Assert.True(res.Value == 15000); 117 | } 118 | 119 | [Fact] 120 | public void StateTest6() 121 | { 122 | var first = State.Return(10); 123 | var second = State.Return(3); 124 | var third = State.Return(5); 125 | var fourth = State.Return(100); 126 | 127 | var sm = from x in first 128 | from t in State.Get( s => s + "yyy" ) 129 | from y in second 130 | from s in State.Put("Hello " + (x * y) + t) 131 | from z in third 132 | from w in fourth 133 | from s1 in State.Get() 134 | from s2 in State.Put( s1 + " " + (z * w) ) 135 | select x * y * z * w; 136 | 137 | var res = sm(", World"); // Invoke with the initial state 138 | 139 | Assert.True(res.State == "Hello 30, Worldyyy 500"); 140 | Assert.True(res.Value == 15000); 141 | } 142 | 143 | static State Put( S state ) 144 | { 145 | return _ => StateResult.Create(Unit.Default, state); 146 | } 147 | 148 | State DoSomethingElse() 149 | { 150 | return state => StateResult.Create(state + "rld",1); 151 | } 152 | 153 | State DoSomething() 154 | { 155 | return state => StateResult.Create(state + ", Wo",2); 156 | } 157 | } 158 | } 159 | 160 | -------------------------------------------------------------------------------- /CSharpMonad.UnitTests/src/TryTests.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Martin Thomalla 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | using System; 26 | using Xunit; 27 | using Monad; 28 | 29 | namespace Monad.UnitTests 30 | { 31 | public class TryTests 32 | { 33 | [Fact] 34 | public void TestTry() 35 | { 36 | var r = from lhs in Error() 37 | from rhs in Two() 38 | select lhs+rhs; 39 | 40 | Assert.True(r().IsFaulted && r().Exception.Message == "Error!!"); 41 | } 42 | 43 | [Fact] 44 | public void TestEitherBinding2() 45 | { 46 | var r = (from lhs in Two() 47 | from rhs in Error() 48 | select lhs + rhs) 49 | .TryMemo(); 50 | 51 | Assert.True(r().IsFaulted && r().Exception.Message == "Error!!"); 52 | } 53 | 54 | 55 | [Fact] 56 | public void TestEitherBinding3() 57 | { 58 | var r = 59 | from lhs in Two() 60 | select lhs; 61 | 62 | Assert.True(r().Value == 2); 63 | } 64 | 65 | [Fact] 66 | public void TestEitherBinding4() 67 | { 68 | var r = 69 | from lhs in Error() 70 | select lhs; 71 | 72 | Assert.True(r().IsFaulted && r().Exception.Message == "Error!!"); 73 | } 74 | 75 | [Fact] 76 | public void TestEitherBinding5() 77 | { 78 | var r = 79 | from one in Two() 80 | from two in Error() 81 | from thr in Two() 82 | select one + two + thr; 83 | 84 | Assert.True(r().IsFaulted && r().Exception.Message == "Error!!"); 85 | } 86 | 87 | [Fact] 88 | public void TestEitherMatch1() 89 | { 90 | var unit = 91 | (from one in Two() 92 | from two in Error() 93 | from thr in Two() 94 | select one + two + thr) 95 | .Match( 96 | Success: r => Assert.True(false), 97 | Fail: l => Assert.True(l.Message == "Error!!") 98 | ); 99 | 100 | Console.WriteLine(unit.ToString()); 101 | } 102 | 103 | [Fact] 104 | public void TestEitherMatch2() 105 | { 106 | var unit = 107 | (from one in Two() 108 | from two in Error() 109 | from thr in Two() 110 | select one + two + thr) 111 | .Match( 112 | succ => Assert.False(true), 113 | fail => Assert.True(fail.Message == "Error!!") 114 | ); 115 | Console.WriteLine(unit.ToString()); 116 | } 117 | 118 | [Fact] 119 | public void TestEitherMatch3() 120 | { 121 | var unit = 122 | (from one in Two() 123 | from two in Two() 124 | select one + two) 125 | .Match( 126 | Success: r => Assert.True(r == 4), 127 | Fail: l => Assert.False(true) 128 | ); 129 | Console.WriteLine(unit.ToString()); 130 | } 131 | 132 | [Fact] 133 | public void TestEitherMatch4() 134 | { 135 | var unit = 136 | (from one in Two() 137 | from two in Two() 138 | select one + two) 139 | .Match( 140 | succ => Assert.True(succ == 4), 141 | fail => Assert.False(true) 142 | ); 143 | Console.WriteLine(unit.ToString()); 144 | } 145 | 146 | [Fact] 147 | public void TestEitherMatch5() 148 | { 149 | var result = 150 | (from one in Two() 151 | from two in Two() 152 | select one + two) 153 | .Match( 154 | Success: r => r * 2, 155 | Fail: l => 0 156 | ); 157 | 158 | Assert.True(result() == 8); 159 | } 160 | 161 | [Fact] 162 | public void TestEitherMatch6() 163 | { 164 | var result = 165 | (from one in Two() 166 | from err in Error() 167 | from two in Two() 168 | select one + two) 169 | .Match( 170 | Success: r => r * 2, 171 | Fail: l => 0 172 | ); 173 | 174 | Assert.True(result() == 0); 175 | } 176 | 177 | public Try Two() 178 | { 179 | return () => 2; 180 | } 181 | 182 | public Try Error() 183 | { 184 | return () => { throw new Exception("Error!!"); }; 185 | } 186 | 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /CSharpMonad.UnitTests/src/WriterTests.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | using System; 26 | using System.Linq; 27 | using Xunit; 28 | using Monad.Utility; 29 | using Monad; 30 | 31 | namespace Monad.UnitTests 32 | { 33 | public class WriterTests 34 | { 35 | [Fact] 36 | public void Binding1() 37 | { 38 | var res = from a in LogNumber(3) 39 | from b in LogNumber(5) 40 | select a * b; 41 | 42 | var memo = res.Memo(); 43 | 44 | Assert.True(memo().Value == 15 && memo().Output.Count() == 2); 45 | Assert.True(memo().Output.First() == "Got number: 3"); 46 | Assert.True(memo().Output.Skip(1).First() == "Got number: 5"); 47 | } 48 | 49 | [Fact] 50 | public void Binding2() 51 | { 52 | var res = from a in LogNumber(3) 53 | from b in LogNumber(5) 54 | from _ in Writer.Tell("Gonna multiply these two") 55 | select a * b; 56 | 57 | var memo = res.Memo(); 58 | 59 | Assert.True(memo().Value == 15 && memo().Output.Count() == 3); 60 | Assert.True(memo().Output.First() == "Got number: 3"); 61 | Assert.True(memo().Output.Skip(1).First() == "Got number: 5"); 62 | Assert.True(memo().Output.Skip(2).First() == "Gonna multiply these two"); 63 | } 64 | 65 | private static Writer LogNumber(int num) 66 | { 67 | return () => Writer.Tell(num, "Got number: " + num); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /CSharpMonad.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.24720.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CSharpMonad.UnitTests", "CSharpMonad.UnitTests\CSharpMonad.UnitTests.csproj", "{496943F4-17B4-41CB-8013-5499543E3DA0}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{51C6DCA8-5534-4D6B-B7A1-FCA877421A47}" 9 | ProjectSection(SolutionItems) = preProject 10 | LICENSE.md = LICENSE.md 11 | README.md = README.md 12 | EndProjectSection 13 | EndProject 14 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{C753F430-F758-4309-AFE5-87B825D242FD}" 15 | ProjectSection(SolutionItems) = preProject 16 | .nuget\packages.config = .nuget\packages.config 17 | EndProjectSection 18 | EndProject 19 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CSharpMonad", "CSharpMonad\CSharpMonad.csproj", "{254ABD61-BEDB-4478-9708-606E85310FE0}" 20 | EndProject 21 | Global 22 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 23 | Debug|Any CPU = Debug|Any CPU 24 | Release|Any CPU = Release|Any CPU 25 | EndGlobalSection 26 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 27 | {496943F4-17B4-41CB-8013-5499543E3DA0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 28 | {496943F4-17B4-41CB-8013-5499543E3DA0}.Debug|Any CPU.Build.0 = Debug|Any CPU 29 | {496943F4-17B4-41CB-8013-5499543E3DA0}.Release|Any CPU.ActiveCfg = Release|Any CPU 30 | {496943F4-17B4-41CB-8013-5499543E3DA0}.Release|Any CPU.Build.0 = Release|Any CPU 31 | {254ABD61-BEDB-4478-9708-606E85310FE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 32 | {254ABD61-BEDB-4478-9708-606E85310FE0}.Debug|Any CPU.Build.0 = Debug|Any CPU 33 | {254ABD61-BEDB-4478-9708-606E85310FE0}.Release|Any CPU.ActiveCfg = Release|Any CPU 34 | {254ABD61-BEDB-4478-9708-606E85310FE0}.Release|Any CPU.Build.0 = Release|Any CPU 35 | EndGlobalSection 36 | GlobalSection(SolutionProperties) = preSolution 37 | HideSolutionNode = FALSE 38 | EndGlobalSection 39 | EndGlobal 40 | -------------------------------------------------------------------------------- /CSharpMonad/CSharpMonad.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 11.0 6 | Debug 7 | AnyCPU 8 | {254ABD61-BEDB-4478-9708-606E85310FE0} 9 | Library 10 | Properties 11 | Monad 12 | Monad 13 | en-US 14 | 512 15 | {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 16 | Profile7 17 | v4.5 18 | 19 | 20 | true 21 | full 22 | false 23 | bin\Debug\ 24 | DEBUG;TRACE 25 | prompt 26 | 4 27 | 28 | 29 | pdbonly 30 | true 31 | lib\ 32 | TRACE 33 | prompt 34 | 4 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 | 101 | -------------------------------------------------------------------------------- /CSharpMonad/CSharpMonad.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "CSharpMonad", "CSharpMonad.xproj", "{C0855756-19E8-4701-8980-4210040B5B5B}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {C0855756-19E8-4701-8980-4210040B5B5B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {C0855756-19E8-4701-8980-4210040B5B5B}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {C0855756-19E8-4701-8980-4210040B5B5B}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {C0855756-19E8-4701-8980-4210040B5B5B}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /CSharpMonad/CSharpMonad.xproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 14.0 5 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 6 | 7 | 8 | 9 | c0855756-19e8-4701-8980-4210040b5b5b 10 | CSharpMonad 11 | .\obj 12 | .\bin\ 13 | 14 | 15 | 16 | 2.0 17 | 18 | 19 | -------------------------------------------------------------------------------- /CSharpMonad/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | // General Information about an assembly is controlled through the following 4 | // set of attributes. Change these attribute values to modify the information 5 | // associated with an assembly. 6 | [assembly: AssemblyTitle("Monad")] 7 | [assembly: AssemblyDescription("Monad library")] 8 | [assembly: AssemblyConfiguration("")] 9 | [assembly: AssemblyCompany("")] 10 | [assembly: AssemblyProduct("Monad")] 11 | [assembly: AssemblyCopyright("Copyright © Paul Louth 2014 - MIT License")] 12 | [assembly: AssemblyTrademark("")] 13 | [assembly: AssemblyCulture("")] 14 | 15 | // Version information for an assembly consists of the following four values: 16 | // 17 | // Major Version 18 | // Minor Version 19 | // Build Number 20 | // Revision 21 | // 22 | // You can specify all the values or you can default the Build and Revision Numbers 23 | // by using the '*' as shown below: 24 | // [assembly: AssemblyVersion("1.0.*")] 25 | [assembly: AssemblyVersion("1.0.0.0")] 26 | [assembly: AssemblyFileVersion("1.0.0.0")] 27 | -------------------------------------------------------------------------------- /CSharpMonad/lib/Monad.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/louthy/csharp-monad/20b325e236e6df7d605061e12d6a84ef00634d88/CSharpMonad/lib/Monad.dll -------------------------------------------------------------------------------- /CSharpMonad/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "csharp-monad", 3 | "title": "csharp-monad", 4 | "version": "1.0.0-*", 5 | "authors": [ "Paul Louth" ], 6 | "description": "C# Monad Library", 7 | "packOptions": { 8 | "id": "csharp-monad", 9 | "title": "C# Monad Library", 10 | "owners": [ "paullouth" ], 11 | "tags": [ "C#", "Functional", "Monad", "Option", "Either", "Reader", "Writer", "State" ], 12 | "iconUrl": "https://camo.githubusercontent.com/08525ae465a9061150679d871731e77b399c2a94/687474703a2f2f7777772e34666f75722e6f72672f696d616765732f6c616e672d6578742d6c6f676f2e706e67", 13 | "summary": "A C# library of monads and a full set of parser combinators based on the Haskell Parsec library.\nEither \nEitherStrict \nIO \nOption \nOptionStrict \nParser \nReader \nRWS - Combined Reader/Writer/State\nState \nTry\nWriter", 14 | "releaseNotes": "", 15 | "projectUrl": "https://github.com/louthy/csharp-monad", 16 | "licenseUrl": "https://github.com/louthy/csharp-monad/blob/master/LICENSE.md" 17 | }, 18 | "copyright": "Copyright (c) Paul Louth", 19 | "configurations": { 20 | "Debug": { 21 | "buildOptions": { 22 | "define": [ "DEBUG", "TRACE" ], 23 | "compile": "*.cs" 24 | } 25 | }, 26 | "Release": { 27 | "buildOptions": { 28 | "define": [ "RELEASE", "TRACE" ], 29 | "optimize": true, 30 | "compile": "*.cs" 31 | } 32 | } 33 | }, 34 | "dependencies": { 35 | }, 36 | "frameworks": { 37 | "net45": { 38 | "frameworkAssemblies": { 39 | "System.Core": "4.0.0.0" 40 | }, 41 | "dependencies": { 42 | } 43 | }, 44 | "net46": { 45 | "frameworkAssemblies": { 46 | "System.Core": "4.0.0.0" 47 | }, 48 | "dependencies": { 49 | } 50 | }, 51 | "netcoreapp10": { 52 | "dependencies": { 53 | "System.Runtime.Extensions": "4.1.0", 54 | "System.Collections": "4.0.11", 55 | "System.Reflection": "4.1.0", 56 | "System.Linq": "4.1.0" 57 | } 58 | }, 59 | "netstandard13": { 60 | "dependencies": { 61 | "System.Runtime.Extensions": "4.1.0", 62 | "System.Collections": "4.0.11", 63 | "System.Reflection": "4.1.0", 64 | "System.Linq": "4.1.0" 65 | } 66 | } 67 | }, 68 | "buildOptions": { 69 | "optimize": true 70 | } 71 | } -------------------------------------------------------------------------------- /CSharpMonad/project.lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "locked": false, 3 | "version": 1, 4 | "targets": { 5 | ".NETPortable,Version=v4.5,Profile=Profile7": {} 6 | }, 7 | "libraries": {}, 8 | "projectFileDependencyGroups": { 9 | "": [], 10 | ".NETPortable,Version=v4.5,Profile=Profile7": [] 11 | } 12 | } -------------------------------------------------------------------------------- /CSharpMonad/src/IAppendable.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace Monad 3 | { 4 | /// 5 | /// Used to append/combine the current object and the one provided. 6 | /// This is used to support the operator+ overload on the monad types 7 | /// 8 | /// 9 | public interface IAppendable 10 | { 11 | T Append(T rhs); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /CSharpMonad/src/RWS.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | using System; 26 | using System.Collections.Generic; 27 | using System.Linq; 28 | using Monad.Utility; 29 | 30 | namespace Monad 31 | { 32 | /// 33 | /// The Reader Writer State monad 34 | /// 35 | public delegate RWSResult RWS(R r, S s); 36 | 37 | /// 38 | /// RWS result. 39 | /// 40 | public struct RWSResult 41 | { 42 | public readonly A Value; 43 | public readonly IEnumerable Output; 44 | public readonly S State; 45 | 46 | internal RWSResult(A value, IEnumerable output, S state) 47 | { 48 | Value = value; 49 | Output = output; 50 | State = state; 51 | } 52 | } 53 | 54 | /// 55 | /// RWSResult factory 56 | /// 57 | public static class RWSResult 58 | { 59 | public static RWSResult Create(A value, IEnumerable output, S state) 60 | { 61 | if (output == null) throw new ArgumentNullException("output"); 62 | return new RWSResult(value, output, state); 63 | } 64 | } 65 | 66 | /// 67 | /// Reader Writer State 68 | /// 69 | public static class RWS 70 | { 71 | public static RWS Return(A a) 72 | { 73 | return (R r, S s) => RWSResult.Create(a, new W[0], s); 74 | } 75 | 76 | public static RWSResult Tell(A a, W w) 77 | { 78 | return RWSResult.Create(a, new W[1] { w }, default(S)); 79 | } 80 | 81 | public static RWSResult Tell(A a, IEnumerable ws) 82 | { 83 | if (ws == null) throw new ArgumentNullException("ws"); 84 | return RWSResult.Create(a, ws, default(S)); 85 | } 86 | 87 | public static RWS Tell(W value) 88 | { 89 | return (R r, S s) => RWSResult.Create(Unit.Default, new W[1] { value }, s); 90 | } 91 | 92 | public static RWS Ask(Func f) 93 | { 94 | if (f == null) throw new ArgumentNullException("f"); 95 | return (R r, S s) => RWSResult.Create(f(r), new W[0], s); 96 | } 97 | 98 | public static RWS Ask() 99 | { 100 | return (R r, S s) => RWSResult.Create(r, new W[0], s); 101 | } 102 | 103 | public static RWS Get(Func f) 104 | { 105 | if (f == null) throw new ArgumentNullException("f"); 106 | return (R r, S s) => RWSResult.Create(s, new W[0], f(s)); 107 | } 108 | 109 | public static RWS Get() 110 | { 111 | return (R r, S s) => RWSResult.Create(s, new W[0], s); 112 | } 113 | 114 | public static RWS Put(S state) 115 | { 116 | return (R r, S s) => RWSResult.Create(Unit.Default, new W[0], state); 117 | } 118 | 119 | } 120 | 121 | /// 122 | /// Reader Writer State extension methods 123 | /// 124 | public static class RWSExt 125 | { 126 | public static RWS Ask(this RWS self, Func f) 127 | { 128 | if (f == null) throw new ArgumentNullException("f"); 129 | return (R r, S s) => RWSResult.Create(f(r), new W[0], s); 130 | } 131 | 132 | public static RWS Ask(this RWS self) 133 | { 134 | return (R r, S s) => RWSResult.Create(r, new W[0], s); 135 | } 136 | 137 | /// 138 | /// Select 139 | /// 140 | public static RWS Select(this RWS self, Func select) 141 | where S : class 142 | { 143 | if (select == null) throw new ArgumentNullException("select"); 144 | return (R r, S s) => 145 | { 146 | var resT = self(r, s); 147 | var resU = select(resT.Value); 148 | return RWSResult.Create(resU, resT.Output, resT.State ?? s); 149 | }; 150 | } 151 | 152 | /// 153 | /// Select Many 154 | /// 155 | public static RWS SelectMany( 156 | this RWS self, 157 | Func> bind, 158 | Func project 159 | ) 160 | where S : class 161 | { 162 | if (bind == null) throw new ArgumentNullException("bind"); 163 | if (project == null) throw new ArgumentNullException("project"); 164 | 165 | return (R r, S s) => 166 | { 167 | var resT = self(r, s); 168 | var resU = bind(resT.Value).Invoke(r, resT.State ?? s); 169 | var resV = project(resT.Value, resU.Value); 170 | 171 | return RWSResult.Create(resV, resT.Output.Concat(resU.Output), resU.State ?? resT.State ?? s); 172 | }; 173 | } 174 | 175 | /// 176 | /// Memoize the result 177 | /// 178 | public static Func> Memo(this RWS self, R r, S s) 179 | { 180 | var res = self(r, s); 181 | return () => res; 182 | } 183 | } 184 | } 185 | 186 | -------------------------------------------------------------------------------- /CSharpMonad/src/Reader.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | using System; 26 | 27 | namespace Monad 28 | { 29 | /// 30 | /// The reader monad 31 | /// Allows for an 'environment' value to be carried through bind functions 32 | /// 33 | /// Environment 34 | /// The underlying monadic type 35 | public delegate A Reader(E environment); 36 | 37 | /// 38 | /// Reader. 39 | /// 40 | public static class Reader 41 | { 42 | public static Reader Return(A value = default(A)) 43 | { 44 | return (E env) => value; 45 | } 46 | 47 | public static Reader Ask(Func f) 48 | { 49 | if (f == null) throw new ArgumentNullException("f"); 50 | return (E env) => f(env); 51 | } 52 | 53 | public static Reader Ask() 54 | { 55 | return (E env) => env; 56 | } 57 | } 58 | 59 | /// 60 | /// Reader monad extensions 61 | /// 62 | public static class ReaderExt 63 | { 64 | public static Reader Ask(this Reader self, Func f) 65 | { 66 | if (f == null) throw new ArgumentNullException("f"); 67 | return (E env) => f(env); 68 | } 69 | 70 | public static Reader Ask(this Reader self) 71 | { 72 | return (E env) => env; 73 | } 74 | 75 | /// 76 | /// Select 77 | /// 78 | public static Reader Select(this Reader self, Func select) 79 | { 80 | if (select == null) throw new ArgumentNullException("select"); 81 | return (E env) => select(self(env)); 82 | } 83 | 84 | /// 85 | /// Select Many 86 | /// 87 | public static Reader SelectMany( 88 | this Reader self, 89 | Func> bind, 90 | Func project 91 | ) 92 | { 93 | if (bind == null) throw new ArgumentNullException("bind"); 94 | if (project == null) throw new ArgumentNullException("project"); 95 | return (E env) => 96 | { 97 | var resT = self(env); 98 | var resU = bind(resT); 99 | var resV = project(resT, resU(env)); 100 | return resV; 101 | }; 102 | } 103 | 104 | /// 105 | /// Memoize the result 106 | /// 107 | public static Func Memo(this Reader self, E environment) 108 | { 109 | var res = self(environment); 110 | return () => res; 111 | } 112 | 113 | } 114 | } -------------------------------------------------------------------------------- /CSharpMonad/src/State.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | using System; 26 | using Monad.Utility; 27 | 28 | namespace Monad 29 | { 30 | public delegate StateResult State(S state); 31 | 32 | public static class State 33 | { 34 | public static State Return(A value = default(A)) 35 | { 36 | return (S state) => new StateResult(state, value); 37 | } 38 | 39 | public static State Get(Func f) 40 | { 41 | if (f == null) throw new ArgumentNullException("f"); 42 | return (S state) => StateResult.Create(state, f(state)); 43 | } 44 | 45 | public static State Get() 46 | { 47 | return (S state) => StateResult.Create(state, state); 48 | } 49 | 50 | public static State Put(S state) 51 | { 52 | return _ => StateResult.Create(state, Unit.Default); 53 | } 54 | } 55 | 56 | /// 57 | /// State result. 58 | /// 59 | public struct StateResult 60 | { 61 | public readonly A Value; 62 | public readonly S State; 63 | 64 | internal StateResult(S state, A value) 65 | { 66 | Value = value; 67 | State = state; 68 | } 69 | } 70 | 71 | /// 72 | /// State result factory 73 | /// 74 | public static class StateResult 75 | { 76 | public static StateResult Create(S state, A value) 77 | { 78 | return new StateResult(state, value); 79 | } 80 | } 81 | 82 | public static class StateExt 83 | { 84 | public static State With(this State self, Func f) 85 | { 86 | if (f == null) throw new ArgumentNullException("f"); 87 | return (S state) => 88 | { 89 | var res = self(state); 90 | return StateResult.Create(f(res.State), res.Value); 91 | }; 92 | } 93 | 94 | public static State Select(this State self, Func map) 95 | { 96 | if (map == null) throw new ArgumentNullException("map"); 97 | return (S state) => 98 | { 99 | var resT = self(state); 100 | return StateResult.Create(resT.State, map(resT.Value)); 101 | }; 102 | } 103 | 104 | public static State SelectMany( 105 | this State self, 106 | Func> bind, 107 | Func project 108 | ) 109 | { 110 | if (bind == null) throw new ArgumentNullException("bind"); 111 | if (project == null) throw new ArgumentNullException("project"); 112 | 113 | return (S state) => 114 | { 115 | var resT = self(state); 116 | var resU = bind(resT.Value)(resT.State); 117 | var resV = project(resT.Value, resU.Value); 118 | return new StateResult(resU.State, resV); 119 | }; 120 | } 121 | 122 | /// 123 | /// Memoize the result 124 | /// 125 | public static Func> Memo(this State self, S state) 126 | { 127 | var res = self(state); 128 | return () => res; 129 | } 130 | } 131 | } -------------------------------------------------------------------------------- /CSharpMonad/src/Writer.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | using System; 26 | using System.Collections.Generic; 27 | using System.Linq; 28 | using Monad.Utility; 29 | 30 | namespace Monad 31 | { 32 | /// 33 | /// The writer monad 34 | /// 35 | public delegate WriterResult Writer(); 36 | 37 | /// 38 | /// Writer result. 39 | /// 40 | public struct WriterResult 41 | { 42 | public readonly A Value; 43 | public readonly IEnumerable Output; 44 | 45 | internal WriterResult(A value, IEnumerable output) 46 | { 47 | if (output == null) throw new ArgumentNullException("output"); 48 | Value = value; 49 | Output = output; 50 | } 51 | } 52 | 53 | /// 54 | /// Writer result factory 55 | /// 56 | public static class WriterResult 57 | { 58 | public static WriterResult Create(A value, IEnumerable output) 59 | { 60 | if (output == null) throw new ArgumentNullException("output"); 61 | return new WriterResult(value, output); 62 | } 63 | } 64 | 65 | /// 66 | /// Writer 67 | /// 68 | public static class Writer 69 | { 70 | public static Writer Return(A a) 71 | { 72 | return () => WriterResult.Create(a, new W[0]); 73 | } 74 | 75 | public static WriterResult Tell(A a, W w) 76 | { 77 | return WriterResult.Create(a, new W[1] { w }); 78 | } 79 | 80 | public static WriterResult Tell(A a, IEnumerable ws) 81 | { 82 | if (ws == null) throw new ArgumentNullException("ws"); 83 | return WriterResult.Create(a, ws); 84 | } 85 | 86 | public static Writer Tell(W value) 87 | { 88 | return () => WriterResult.Create(Unit.Default, new W[1] { value }); 89 | } 90 | } 91 | 92 | /// 93 | /// Writer extension methods 94 | /// 95 | public static class WriterExt 96 | { 97 | /// 98 | /// Select 99 | /// 100 | public static Writer Select(this Writer self, Func select) 101 | { 102 | if (select == null) throw new ArgumentNullException("select"); 103 | return () => 104 | { 105 | var resT = self(); 106 | var resU = select(resT.Value); 107 | return WriterResult.Create(resU, resT.Output); 108 | }; 109 | } 110 | 111 | /// 112 | /// Select Many 113 | /// 114 | public static Writer SelectMany( 115 | this Writer self, 116 | Func> bind, 117 | Func project 118 | ) 119 | { 120 | if (bind == null) throw new ArgumentNullException("bind"); 121 | if (project == null) throw new ArgumentNullException("project"); 122 | 123 | return () => 124 | { 125 | var resT = self(); 126 | var resU = bind(resT.Value).Invoke(); 127 | var resV = project(resT.Value, resU.Value); 128 | 129 | return WriterResult.Create(resV, resT.Output.Concat(resU.Output)); 130 | }; 131 | } 132 | 133 | /// 134 | /// Memoize the result 135 | /// 136 | public static Func> Memo(this Writer self) 137 | { 138 | var res = self(); 139 | return () => res; 140 | } 141 | } 142 | } -------------------------------------------------------------------------------- /CSharpMonad/src/ext/EnumerableExt.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | using Monad.Parsec; 26 | using Monad.Utility; 27 | using System; 28 | using System.Collections.Generic; 29 | using System.Linq; 30 | 31 | namespace Monad 32 | { 33 | public static class EnumerableExt 34 | { 35 | public static T Head(this IEnumerable self) 36 | { 37 | return self.First(); 38 | } 39 | public static IEnumerable Tail(this IEnumerable self) 40 | { 41 | return self.Skip(1); 42 | } 43 | public static T Second(this IEnumerable self) 44 | { 45 | return self.Tail().Head(); 46 | } 47 | 48 | public static ImmutableList ToParserChar(this IEnumerable input) 49 | { 50 | int line = 1; 51 | int col = 1; 52 | 53 | var list = new List(); 54 | 55 | foreach (var c in input) 56 | { 57 | if (c == '\r') 58 | { 59 | continue; 60 | } 61 | 62 | list.Add(new ParserChar(c, SrcLoc.Return(line, col))); 63 | 64 | if (c == '\n') 65 | { 66 | line++; 67 | col = 1; 68 | } 69 | col++; 70 | } 71 | 72 | return new ImmutableList(list); 73 | } 74 | 75 | /// 76 | /// Foldr 77 | /// 78 | public static U Foldr(this IEnumerable self, Func func, U state) 79 | { 80 | foreach (var item in self) 81 | { 82 | state = func(item, state); 83 | } 84 | return state; 85 | } 86 | 87 | /// 88 | /// Foldr 89 | /// 90 | public static U Foldr(this IEnumerable self, Func func, U state) 91 | { 92 | foreach (var item in self) 93 | { 94 | state = func(state); 95 | } 96 | return state; 97 | } 98 | 99 | /// 100 | /// Foldl 101 | /// 102 | public static U Foldl(this IEnumerable self, Func func, U state) 103 | { 104 | return self.Reverse().Foldr(func, state); 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /CSharpMonad/src/ext/ImmutableListExt.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | using Monad.Parsec; 26 | using Monad.Utility; 27 | using System; 28 | 29 | namespace Monad 30 | { 31 | public static class ImmutableListExt 32 | { 33 | public static bool CanTake(this ImmutableList self, int amount) 34 | { 35 | return self.Length - amount >= 0; 36 | } 37 | 38 | public static string AsString(this ImmutableList self) 39 | { 40 | return String.Concat(self.Select(pc=>pc.Value)); 41 | } 42 | 43 | public static T Second(this ImmutableList self) 44 | { 45 | return self.Tail().Head(); 46 | } 47 | 48 | /// 49 | /// Foldr 50 | /// 51 | public static U Foldr(this ImmutableList self, Func func, U state) 52 | { 53 | foreach (var item in self) 54 | { 55 | state = func(item, state); 56 | } 57 | return state; 58 | } 59 | 60 | /// 61 | /// Foldr 62 | /// 63 | public static U Foldr(this ImmutableList self, Func func, U state) 64 | { 65 | foreach (var item in self) 66 | { 67 | state = func(state); 68 | } 69 | return state; 70 | } 71 | 72 | /// 73 | /// Foldl 74 | /// 75 | public static U Foldl(this ImmutableList self, Func func, U state) 76 | { 77 | var iter = self.GetReverseEnumerator(); 78 | while (iter.MoveNext()) 79 | { 80 | state = func(iter.Current, state); 81 | } 82 | return state; 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /CSharpMonad/src/ext/ObjectExt.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | using Monad.Utility; 26 | using System; 27 | 28 | namespace Monad 29 | { 30 | public static class ObjectExt 31 | { 32 | public static ImmutableList Cons(this T x, ImmutableList xs) 33 | { 34 | if (xs == null) throw new ArgumentNullException("xs"); 35 | return xs.InsertAtHead(x); 36 | } 37 | 38 | public static ImmutableList Cons(this T x) 39 | { 40 | return new ImmutableList(new T[1] { x }); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /CSharpMonad/src/ext/TupleExt.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | using System; 26 | 27 | namespace Monad 28 | { 29 | public static class TupleExtensions 30 | { 31 | public static R Apply(this Tuple self, Func func) 32 | { 33 | if (func == null) throw new ArgumentNullException("func"); 34 | return func(self.Item1, self.Item2); 35 | } 36 | 37 | public static R Apply(this Tuple self, Func func) 38 | { 39 | if (func == null) throw new ArgumentNullException("func"); 40 | return func(self.Item1, self.Item2, self.Item3); 41 | } 42 | 43 | public static R Apply(this Tuple self, Func func) 44 | { 45 | if (func == null) throw new ArgumentNullException("func"); 46 | return func(self.Item1, self.Item2, self.Item3, self.Item4); 47 | } 48 | 49 | public static R Apply(this Tuple self, Func func) 50 | { 51 | if (func == null) throw new ArgumentNullException("func"); 52 | return func(self.Item1, self.Item2, self.Item3, self.Item4, self.Item5); 53 | } 54 | 55 | public static void Apply(this Tuple self, Action func) 56 | { 57 | if (func == null) throw new ArgumentNullException("func"); 58 | func(self.Item1, self.Item2); 59 | } 60 | 61 | public static void Apply(this Tuple self, Action func) 62 | { 63 | if (func == null) throw new ArgumentNullException("func"); 64 | func(self.Item1, self.Item2, self.Item3); 65 | } 66 | 67 | public static void Apply(this Tuple self, Action func) 68 | { 69 | if (func == null) throw new ArgumentNullException("func"); 70 | func(self.Item1, self.Item2, self.Item3, self.Item4); 71 | } 72 | 73 | public static void Apply(this Tuple self, Action func) 74 | { 75 | if (func == null) throw new ArgumentNullException("func"); 76 | func(self.Item1, self.Item2, self.Item3, self.Item4, self.Item5); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /CSharpMonad/src/option-lazy/Just.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | using System; 26 | using System.Reflection; 27 | 28 | namespace Monad 29 | { 30 | /// 31 | /// Just case of the Option monad 32 | /// 33 | public class JustResult : OptionResult 34 | { 35 | static readonly string TypeOfT = typeof(T).ToString(); 36 | static readonly bool IsAppendable = typeof(IAppendable).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo()); 37 | private readonly T value; 38 | 39 | public JustResult(T value) 40 | { 41 | this.value = value; 42 | } 43 | 44 | public override string ToString() 45 | { 46 | return Value.ToString(); 47 | } 48 | 49 | public override T Value 50 | { 51 | get 52 | { 53 | return value; 54 | } 55 | } 56 | 57 | public override bool HasValue 58 | { 59 | get 60 | { 61 | return true; 62 | } 63 | } 64 | 65 | /// 66 | /// Monadic append 67 | /// If the lhs or rhs are in a Nothing state then Nothing propagates 68 | /// 69 | public override OptionResult Mappend(OptionResult rhs) 70 | { 71 | if (rhs == null) throw new ArgumentNullException("rhs"); 72 | if (!rhs.HasValue) 73 | { 74 | return rhs; 75 | } 76 | else 77 | { 78 | if (IsAppendable) 79 | { 80 | var lhs = this.Value as IAppendable; 81 | return new JustResult(lhs.Append(rhs.Value)); 82 | } 83 | else 84 | { 85 | // TODO: Consider replacing this with a Reflection.Emit which does this job efficiently. 86 | switch (TypeOfT) 87 | { 88 | case "System.Int64": 89 | return new JustResult((T)Convert.ChangeType((Convert.ToInt64(Value) + Convert.ToInt64(rhs.Value)), typeof(T))); 90 | case "System.UInt64": 91 | return new JustResult((T)Convert.ChangeType((Convert.ToUInt64(Value) + Convert.ToUInt64(rhs.Value)), typeof(T))); 92 | case "System.Int32": 93 | return new JustResult((T)Convert.ChangeType((Convert.ToInt32(Value) + Convert.ToInt32(rhs.Value)), typeof(T))); 94 | case "System.UInt32": 95 | return new JustResult((T)Convert.ChangeType((Convert.ToUInt32(Value) + Convert.ToUInt32(rhs.Value)), typeof(T))); 96 | case "System.Int16": 97 | return new JustResult((T)Convert.ChangeType((Convert.ToInt16(Value) + Convert.ToInt16(rhs.Value)), typeof(T))); 98 | case "System.UInt16": 99 | return new JustResult((T)Convert.ChangeType((Convert.ToUInt16(Value) + Convert.ToUInt16(rhs.Value)), typeof(T))); 100 | case "System.Decimal": 101 | return new JustResult((T)Convert.ChangeType((Convert.ToDecimal(Value) + Convert.ToDecimal(rhs.Value)), typeof(T))); 102 | case "System.Double": 103 | return new JustResult((T)Convert.ChangeType((Convert.ToDouble(Value) + Convert.ToDouble(rhs.Value)), typeof(T))); 104 | case "System.Single": 105 | return new JustResult((T)Convert.ChangeType((Convert.ToSingle(Value) + Convert.ToSingle(rhs.Value)), typeof(T))); 106 | case "System.Char": 107 | return new JustResult((T)Convert.ChangeType((Convert.ToChar(Value) + Convert.ToChar(rhs.Value)), typeof(T))); 108 | case "System.Byte": 109 | return new JustResult((T)Convert.ChangeType((Convert.ToByte(Value) + Convert.ToByte(rhs.Value)), typeof(T))); 110 | case "System.String": 111 | return new JustResult((T)Convert.ChangeType((Convert.ToString(Value) + Convert.ToString(rhs.Value)), typeof(T))); 112 | default: 113 | throw new InvalidOperationException("Type " + typeof(T).Name + " is not appendable. Consider implementing the IAppendable interface."); 114 | } 115 | } 116 | } 117 | } 118 | } 119 | } -------------------------------------------------------------------------------- /CSharpMonad/src/option-lazy/Nothing.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | using System; 26 | 27 | namespace Monad 28 | { 29 | /// 30 | /// Nothing case of the Option monad 31 | /// 32 | public class NothingResult : OptionResult 33 | { 34 | internal static OptionResult Default = new NothingResult(); 35 | 36 | public override string ToString() 37 | { 38 | return "[Nothing]"; 39 | } 40 | 41 | public override T Value 42 | { 43 | get 44 | { 45 | throw new InvalidOperationException("Option.Nothing has no value"); 46 | } 47 | } 48 | 49 | public override bool HasValue 50 | { 51 | get 52 | { 53 | return false; 54 | } 55 | } 56 | 57 | /// 58 | /// Monadic append 59 | /// If the lhs or rhs are in a Nothing state then Nothing propagates 60 | /// 61 | public override OptionResult Mappend(OptionResult rhs) 62 | { 63 | if (rhs == null) throw new ArgumentNullException("rhs"); 64 | return this; 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /CSharpMonad/src/option-strict/Just.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | using System; 26 | using System.Reflection; 27 | 28 | namespace Monad 29 | { 30 | /// 31 | /// Just case of the Option monad 32 | /// 33 | public class JustStrict : OptionStrict 34 | { 35 | static readonly string TypeOfT = typeof(T).ToString(); 36 | static readonly bool IsAppendable = typeof(IAppendable).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo()); 37 | private readonly T value; 38 | 39 | public JustStrict(T value) 40 | { 41 | this.value = value; 42 | } 43 | 44 | public override string ToString() 45 | { 46 | return Value.ToString(); 47 | } 48 | 49 | public override T Value 50 | { 51 | get 52 | { 53 | return value; 54 | } 55 | } 56 | 57 | public override bool HasValue 58 | { 59 | get 60 | { 61 | return true; 62 | } 63 | } 64 | 65 | public override R Match(Func Just, Func Nothing) 66 | { 67 | if (Just == null) throw new ArgumentNullException("Just"); 68 | if (Nothing == null) throw new ArgumentNullException("Nothing"); 69 | return Just(); 70 | } 71 | 72 | public override R Match(Func Just, Func Nothing) 73 | { 74 | if (Just == null) throw new ArgumentNullException("Just"); 75 | if (Nothing == null) throw new ArgumentNullException("Nothing"); 76 | return Just(Value); 77 | } 78 | 79 | public override R Match(Func Just, R Nothing) 80 | { 81 | if (Just == null) throw new ArgumentNullException("Just"); 82 | return Just(); 83 | } 84 | 85 | public override R Match(Func Just, R Nothing) 86 | { 87 | if (Just == null) throw new ArgumentNullException("Just"); 88 | return Just(Value); 89 | } 90 | 91 | 92 | /// 93 | /// Monadic append 94 | /// If the lhs or rhs are in a Nothing state then Nothing propagates 95 | /// 96 | public override OptionStrict Mappend(OptionStrict rhs) 97 | { 98 | if (rhs == null) throw new ArgumentNullException("rhs"); 99 | if (!rhs.HasValue) 100 | { 101 | return rhs; 102 | } 103 | else 104 | { 105 | if (IsAppendable) 106 | { 107 | var lhs = this.Value as IAppendable; 108 | return new JustStrict(lhs.Append(rhs.Value)); 109 | } 110 | else 111 | { 112 | // TODO: Consider replacing this with a Reflection.Emit which does this job efficiently. 113 | switch (TypeOfT) 114 | { 115 | case "System.Int64": 116 | return new JustStrict((T)Convert.ChangeType((Convert.ToInt64(Value) + Convert.ToInt64(rhs.Value)), typeof(T))); 117 | case "System.UInt64": 118 | return new JustStrict((T)Convert.ChangeType((Convert.ToUInt64(Value) + Convert.ToUInt64(rhs.Value)), typeof(T))); 119 | case "System.Int32": 120 | return new JustStrict((T)Convert.ChangeType((Convert.ToInt32(Value) + Convert.ToInt32(rhs.Value)), typeof(T))); 121 | case "System.UInt32": 122 | return new JustStrict((T)Convert.ChangeType((Convert.ToUInt32(Value) + Convert.ToUInt32(rhs.Value)), typeof(T))); 123 | case "System.Int16": 124 | return new JustStrict((T)Convert.ChangeType((Convert.ToInt16(Value) + Convert.ToInt16(rhs.Value)), typeof(T))); 125 | case "System.UInt16": 126 | return new JustStrict((T)Convert.ChangeType((Convert.ToUInt16(Value) + Convert.ToUInt16(rhs.Value)), typeof(T))); 127 | case "System.Decimal": 128 | return new JustStrict((T)Convert.ChangeType((Convert.ToDecimal(Value) + Convert.ToDecimal(rhs.Value)), typeof(T))); 129 | case "System.Double": 130 | return new JustStrict((T)Convert.ChangeType((Convert.ToDouble(Value) + Convert.ToDouble(rhs.Value)), typeof(T))); 131 | case "System.Single": 132 | return new JustStrict((T)Convert.ChangeType((Convert.ToSingle(Value) + Convert.ToSingle(rhs.Value)), typeof(T))); 133 | case "System.Char": 134 | return new JustStrict((T)Convert.ChangeType((Convert.ToChar(Value) + Convert.ToChar(rhs.Value)), typeof(T))); 135 | case "System.Byte": 136 | return new JustStrict((T)Convert.ChangeType((Convert.ToByte(Value) + Convert.ToByte(rhs.Value)), typeof(T))); 137 | case "System.String": 138 | return new JustStrict((T)Convert.ChangeType((Convert.ToString(Value) + Convert.ToString(rhs.Value)), typeof(T))); 139 | default: 140 | throw new InvalidOperationException("Type " + typeof(T).Name + " is not appendable. Consider implementing the IAppendable interface."); 141 | } 142 | } 143 | } 144 | } 145 | } 146 | } -------------------------------------------------------------------------------- /CSharpMonad/src/option-strict/Nothing.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | using System; 26 | 27 | namespace Monad 28 | { 29 | /// 30 | /// Nothing case of the OptionStrict monad 31 | /// 32 | public class NothingStrict : OptionStrict 33 | { 34 | public override string ToString() 35 | { 36 | return "[Nothing]"; 37 | } 38 | 39 | public override T Value 40 | { 41 | get 42 | { 43 | throw new InvalidOperationException("OptionStrict.Nothing has no value"); 44 | } 45 | } 46 | 47 | public override bool HasValue 48 | { 49 | get 50 | { 51 | return false; 52 | } 53 | } 54 | 55 | public override R Match(Func Just, Func Nothing) 56 | { 57 | if (Just == null) throw new ArgumentNullException("Just"); 58 | if (Nothing == null) throw new ArgumentNullException("Nothing"); 59 | return Nothing(); 60 | } 61 | 62 | public override R Match(Func Just, Func Nothing) 63 | { 64 | if (Just == null) throw new ArgumentNullException("Just"); 65 | if (Nothing == null) throw new ArgumentNullException("Nothing"); 66 | return Nothing(); 67 | } 68 | 69 | public override R Match(Func Just, R Nothing) 70 | { 71 | if (Just == null) throw new ArgumentNullException("Just"); 72 | return Nothing; 73 | } 74 | 75 | public override R Match(Func Just, R Nothing) 76 | { 77 | if (Just == null) throw new ArgumentNullException("Just"); 78 | return Nothing; 79 | } 80 | 81 | /// 82 | /// Monadic append 83 | /// If the lhs or rhs are in a Nothing state then Nothing propagates 84 | /// 85 | public override OptionStrict Mappend(OptionStrict rhs) 86 | { 87 | if (rhs == null) throw new ArgumentNullException("rhs"); 88 | return this; 89 | } 90 | } 91 | } -------------------------------------------------------------------------------- /CSharpMonad/src/parsec/Empty.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | using System; 26 | using System.Collections.Generic; 27 | using Monad.Utility; 28 | 29 | namespace Monad.Parsec 30 | { 31 | public static class Empty 32 | { 33 | public static IEnumerable>> Return() 34 | { 35 | return new Tuple>[0]; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /CSharpMonad/src/parsec/Parser.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | using System; 26 | using System.Collections.Generic; 27 | using System.Linq; 28 | using Monad.Utility; 29 | 30 | namespace Monad.Parsec 31 | { 32 | public interface IParser 33 | { 34 | } 35 | 36 | public class Parser : IParser 37 | { 38 | public readonly Func, ParserResult> Value; 39 | 40 | public Parser(Func, ParserResult> func) 41 | { 42 | if (func == null) throw new ArgumentNullException("func"); 43 | 44 | // This memoization will only work if the exact same reference 45 | // is passed to Parse. We could obviously hash the entire enumerable 46 | // but I suspect that would negate any benefits from the memoization. 47 | this.Value = func.Memo(); 48 | } 49 | 50 | public ParserResult Parse(ImmutableList input) 51 | { 52 | if (input == null) throw new ArgumentNullException("input"); 53 | return Value(input); 54 | } 55 | 56 | public ParserResult Parse(IEnumerable input) 57 | { 58 | if (input == null) throw new ArgumentNullException("input"); 59 | return Parse(input.ToParserChar()); 60 | } 61 | 62 | public static Parser Create(Func, ParserResult> func) 63 | { 64 | if (func == null) throw new ArgumentNullException("func"); 65 | return new Parser(func); 66 | } 67 | 68 | public static implicit operator Parser(Func, ParserResult> func) 69 | { 70 | if (func == null) throw new ArgumentNullException("func"); 71 | return new Parser(func); 72 | } 73 | 74 | public static implicit operator A(Parser parser) 75 | { 76 | if (parser == null) throw new ArgumentNullException("parser"); 77 | return from p in parser 78 | select p; 79 | } 80 | 81 | public static Parser operator |(Parser lhs, Parser rhs) 82 | { 83 | if (lhs == null) throw new ArgumentNullException("LHS of |"); 84 | if (rhs == null) throw new ArgumentNullException("RHS of |"); 85 | 86 | return lhs.Or(rhs); 87 | } 88 | 89 | public static Parser operator &(Parser lhs, Parser rhs) 90 | { 91 | if (lhs == null) throw new ArgumentNullException("lhs of &"); 92 | if (rhs == null) throw new ArgumentNullException("rhs of &"); 93 | return lhs.And(rhs); 94 | } 95 | 96 | public Parser> Mconcat(ImmutableList> parsers) 97 | { 98 | if (parsers == null) throw new ArgumentNullException("parsers"); 99 | 100 | return new Parser>( 101 | inp => 102 | { 103 | parsers = this.Cons(parsers); 104 | 105 | var final = ImmutableList.Empty(); 106 | var last = inp; 107 | 108 | foreach (var parser in parsers) 109 | { 110 | var res = parser.Parse(inp); 111 | if (res.IsFaulted) 112 | return new ParserResult>(res.Errors); 113 | 114 | final = final.Concat(res.Value.Select(r => r.Item1)); 115 | if (!res.Value.IsEmpty) 116 | last = res.Value.Last().Item2; 117 | } 118 | 119 | return new ParserResult>(Tuple.Create(final, last).Cons()); 120 | }); 121 | } 122 | 123 | public Parser> Mconcat(params Parser[] parsers) 124 | { 125 | if (parsers == null) throw new ArgumentNullException("parsers"); 126 | return Mconcat(new ImmutableList>(parsers)); 127 | } 128 | } 129 | } -------------------------------------------------------------------------------- /CSharpMonad/src/parsec/ParserChar.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | namespace Monad.Parsec 26 | { 27 | public struct ParserChar 28 | { 29 | public readonly char Value; 30 | public readonly SrcLoc Location; 31 | 32 | public ParserChar(char c, SrcLoc location = null) 33 | { 34 | Value = c; 35 | Location = location == null 36 | ? SrcLoc.Null 37 | : location; 38 | } 39 | 40 | public override string ToString() 41 | { 42 | return Value.ToString(); 43 | } 44 | 45 | public override int GetHashCode() 46 | { 47 | return Location == null ? Value.GetHashCode() : Location.GetHashCode(); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /CSharpMonad/src/parsec/ParserError.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | using System; 26 | using System.Collections.Generic; 27 | using System.Linq; 28 | using System.Text; 29 | using Monad.Utility; 30 | 31 | namespace Monad.Parsec 32 | { 33 | public class ParserError 34 | { 35 | public readonly string Message; 36 | public readonly string Expected; 37 | public readonly ImmutableList Input; 38 | public readonly SrcLoc Location; 39 | 40 | public ParserError(string expected, ImmutableList input, string message = "") 41 | { 42 | Message = message; 43 | Expected = expected; 44 | Input = input; 45 | if (input.IsEmpty) 46 | { 47 | Location = SrcLoc.EndOfSource; 48 | } 49 | else 50 | { 51 | Location = input.Head().Location; 52 | } 53 | } 54 | 55 | public static ParserError Create(string expected, ImmutableList input, string message = "") 56 | { 57 | return new ParserError(expected, input, message); 58 | } 59 | 60 | public static ParserError Create(char expected, ImmutableList input, string message = "") 61 | { 62 | return new ParserError(expected.ToString(), input, message); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /CSharpMonad/src/parsec/ParserException.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | using System; 26 | using System.Collections.Generic; 27 | using System.Linq; 28 | using System.Text; 29 | 30 | namespace Monad.Parsec 31 | { 32 | public class ParserException : Exception 33 | { 34 | public ParserException(string msg) 35 | : 36 | base(msg) 37 | { 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /CSharpMonad/src/parsec/ParserResult.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | using System; 26 | using System.Collections.Generic; 27 | using Monad.Utility; 28 | 29 | namespace Monad.Parsec 30 | { 31 | public class ParserResult 32 | { 33 | public readonly ImmutableList>> Value; 34 | public readonly ImmutableList Errors; 35 | 36 | public ParserResult(ImmutableList>> value) 37 | { 38 | Value = value; 39 | } 40 | 41 | public ParserResult(Tuple>[] value) 42 | { 43 | Value = new ImmutableList>>(value); 44 | } 45 | 46 | public ParserResult(ImmutableList errors) 47 | { 48 | Value = new ImmutableList>>(new Tuple>[0]); 49 | Errors = errors; 50 | } 51 | 52 | public bool IsFaulted 53 | { 54 | get 55 | { 56 | return Errors != null; 57 | } 58 | } 59 | } 60 | 61 | public static class ParserResult 62 | { 63 | public static ParserResult Fail(ImmutableList errors) 64 | { 65 | return new ParserResult(errors); 66 | } 67 | 68 | public static ParserResult Fail(ParserError[] errors) 69 | { 70 | return new ParserResult(new ImmutableList(errors)); 71 | } 72 | 73 | public static ParserResult Fail(ParserError error) 74 | { 75 | return new ParserResult(error.Cons()); 76 | } 77 | 78 | public static ParserResult Fail(string expected, ImmutableList input, string message = "") 79 | { 80 | return new ParserResult(new ParserError(expected,input,message).Cons()); 81 | } 82 | 83 | public static ParserResult Success(this ImmutableList>> self) 84 | { 85 | return new ParserResult(self); 86 | } 87 | 88 | public static ParserResult Success(this IEnumerable>> self) 89 | { 90 | return new ParserResult(new ImmutableList>>(self)); 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /CSharpMonad/src/parsec/SrcLoc.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | using System; 26 | 27 | namespace Monad.Parsec 28 | { 29 | /// 30 | /// Represents a location in the source 31 | /// 32 | public class SrcLoc 33 | { 34 | private static SrcLoc unit = new SrcLoc(0, 0,"(location:null)"); 35 | private static SrcLoc endOfSource = new SrcLoc(0, 0, "(end-of-source)"); 36 | 37 | public readonly int Line; 38 | public readonly int Column; 39 | 40 | private SrcLoc(int line, int column, string displayTemplate) 41 | { 42 | Line = line; 43 | Column = column; 44 | } 45 | 46 | public static SrcLoc Return(int line, int column) 47 | { 48 | return new SrcLoc(line, column,"({0},{1})"); 49 | } 50 | 51 | public static SrcLoc Null 52 | { 53 | get 54 | { 55 | return unit; 56 | } 57 | } 58 | 59 | public static SrcLoc EndOfSource 60 | { 61 | get 62 | { 63 | return endOfSource; 64 | } 65 | } 66 | 67 | public override string ToString() 68 | { 69 | return String.Format("({0},{1})", Line, Column); 70 | } 71 | 72 | public override int GetHashCode() 73 | { 74 | unchecked 75 | { 76 | return (Line << 16) | Column; 77 | } 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /CSharpMonad/src/parsec/expr/Assoc.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | using System; 26 | 27 | namespace Monad.Parsec.Expr 28 | { 29 | public enum Assoc 30 | { 31 | None, 32 | Left, 33 | Right 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /CSharpMonad/src/parsec/expr/Operator.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | using System; 26 | 27 | namespace Monad.Parsec.Expr 28 | { 29 | public enum OperatorType 30 | { 31 | None, 32 | Infix, 33 | Postfix, 34 | Prefix 35 | } 36 | 37 | public abstract class Operator 38 | { 39 | public readonly OperatorType Type; 40 | public readonly string Name; 41 | 42 | public Operator(OperatorType type, string name) 43 | { 44 | Type = type; 45 | Name = name; 46 | } 47 | } 48 | 49 | public class Infix : Operator 50 | { 51 | public readonly Assoc Assoc; 52 | public readonly Parser> Parser; 53 | 54 | public Infix(string name, Parser> parser, Assoc assoc) 55 | : 56 | base(OperatorType.Infix, name) 57 | { 58 | Parser = parser; 59 | Assoc = assoc; 60 | } 61 | } 62 | 63 | public class Prefix : Operator 64 | { 65 | public readonly Parser> Parser; 66 | 67 | public Prefix(string name, Parser> parser) 68 | : 69 | base(OperatorType.Prefix, name) 70 | { 71 | Parser = parser; 72 | } 73 | } 74 | 75 | public class Postfix : Operator 76 | { 77 | public readonly Parser> Parser; 78 | 79 | public Postfix(string name, Parser> parser) 80 | : 81 | base(OperatorType.Postfix, name) 82 | { 83 | Parser = parser; 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /CSharpMonad/src/parsec/expr/OperatorTable.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | using System; 26 | using System.Collections.Generic; 27 | using System.Linq; 28 | using System.Text; 29 | 30 | namespace Monad.Parsec.Expr 31 | { 32 | public class OperatorTable : IEnumerable>> 33 | { 34 | List>> ops = new List>>(); 35 | int current = -1; 36 | 37 | public OperatorTable() 38 | { 39 | } 40 | 41 | public OperatorTable AddRow() 42 | { 43 | current++; 44 | ops.Add(new Operator[0]); 45 | return this; 46 | } 47 | 48 | public OperatorTable Add(Operator op) 49 | { 50 | ops[current] = ops[current].Concat(op.Cons()); 51 | return this; 52 | } 53 | 54 | public IEnumerable>> AsImmutableList() 55 | { 56 | return ops; 57 | } 58 | 59 | public IEnumerator>> GetEnumerator() 60 | { 61 | return ((IEnumerable>>)ops).GetEnumerator(); 62 | } 63 | 64 | System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() 65 | { 66 | return ((IEnumerable>>)ops).GetEnumerator(); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /CSharpMonad/src/parsec/language/EmptyDef.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | using Monad.Parsec.Token; 26 | 27 | namespace Monad.Parsec.Language 28 | { 29 | /// 30 | /// This is the most minimal token definition. It is recommended to use 31 | /// this definition as the basis for other definitions. EmptyDef has 32 | /// no reserved names or operators, is case sensitive and doesn't accept 33 | /// comments, identifiers or operators 34 | /// 35 | public class EmptyDef : LanguageDef 36 | { 37 | public EmptyDef() 38 | { 39 | CommentStart = ""; 40 | CommentEnd = ""; 41 | CommentLine = ""; 42 | NestedComments = true; 43 | IdentStart = Prim.Letter().Or( Prim.Character('_') ); 44 | IdentLetter = Prim.LetterOrDigit().Or(Prim.Character('_').Or(Prim.Character('\''))); 45 | OpStart = OpLetter = Prim.OneOf(":!#$%&*+./<=>?@\\^|-~"); 46 | ReservedOpNames = new string[0]; 47 | ReservedNames = new string[0]; 48 | CaseSensitive = true; 49 | 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /CSharpMonad/src/parsec/language/Haskell98Def.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | namespace Monad.Parsec.Language 26 | { 27 | public class Haskell98Def : HaskellStyle 28 | { 29 | public Haskell98Def() 30 | { 31 | ReservedOpNames = new string[] {"::","..","=","\\","|","<-","->","@","~","=>"}; 32 | ReservedNames = new string[] {"let","in","case","of","if","then","else", 33 | "data","type", 34 | "class","default","deriving","do","import", 35 | "infix","infixl","infixr","instance","module", 36 | "newtype","where", 37 | "primitive" 38 | // "as","qualified","hiding" 39 | }; 40 | 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /CSharpMonad/src/parsec/language/HaskellDef.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | using System.Linq; 25 | 26 | namespace Monad.Parsec.Language 27 | { 28 | public class HaskellDef : Haskell98Def 29 | { 30 | public HaskellDef() 31 | { 32 | IdentLetter = IdentLetter.Or(Prim.Character('#')); 33 | ReservedNames = Enumerable.Concat( 34 | ReservedNames, 35 | new string[] { "foreign","import","export","primitive" 36 | ,"_ccall_","_casm_" 37 | ,"forall" 38 | }); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /CSharpMonad/src/parsec/language/HaskellStyle.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | namespace Monad.Parsec.Language 26 | { 27 | public class HaskellStyle : EmptyDef 28 | { 29 | public HaskellStyle() 30 | { 31 | CommentStart = "{-"; 32 | CommentEnd = "-}"; 33 | CommentLine = "--"; 34 | NestedComments = true; 35 | IdentStart = Prim.Letter(); 36 | IdentLetter = Prim.LetterOrDigit().Or(Prim.Character('_').Or(Prim.Character('\''))); 37 | OpStart = OpLetter = Prim.OneOf(":!#$%&*+./<=>?@\\^|-~"); 38 | ReservedOpNames = new string[0]; 39 | ReservedNames = new string[0]; 40 | CaseSensitive = true; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /CSharpMonad/src/parsec/language/JavaStyle.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | namespace Monad.Parsec.Language 26 | { 27 | /// 28 | /// This is a minimal token definition for Java style languages. It 29 | /// defines the style of comments, valid identifiers and case 30 | /// sensitivity. It does not define any reserved words or operators. 31 | /// 32 | public class JavaStyle : EmptyDef 33 | { 34 | public JavaStyle() 35 | { 36 | CommentStart = "/*"; 37 | CommentEnd = "*/"; 38 | CommentLine = "//"; 39 | NestedComments = true; 40 | IdentStart = Prim.Letter(); 41 | IdentLetter = Prim.LetterOrDigit().Or(Prim.Character('_').Or(Prim.Character('\''))); 42 | ReservedOpNames = new string[0]; 43 | ReservedNames = new string[0]; 44 | CaseSensitive = true; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /CSharpMonad/src/parsec/token/LanguageDef.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | using Monad.Utility; 26 | using System.Collections.Generic; 27 | using System.Linq; 28 | 29 | namespace Monad.Parsec.Token 30 | { 31 | public class LanguageDef : GeneralLanguageDef 32 | { 33 | } 34 | 35 | public class GeneralLanguageDef 36 | { 37 | /// 38 | /// Describes the start of a block comment. Use the empty string if the 39 | /// language doesn't support block comments. 40 | /// 41 | public string CommentStart; 42 | 43 | /// 44 | /// Describes the end of a block comment. Use the empty string if the 45 | /// language doesn't support block comments. 46 | /// 47 | public string CommentEnd; 48 | 49 | /// 50 | /// Describes the start of a line comment. Use the empty string if the 51 | /// language doesn't support line comments. 52 | /// 53 | public string CommentLine; 54 | 55 | /// 56 | /// Set to 'True' if the language supports nested block comments 57 | /// 58 | public bool NestedComments; 59 | 60 | /// 61 | /// This parser should accept any start characters of identifiers 62 | /// 63 | public Parser IdentStart; 64 | 65 | /// 66 | /// This parser should accept any legal tail characters of identifiers 67 | /// 68 | public Parser IdentLetter; 69 | 70 | /// 71 | /// This parser should accept any start characters of operators. For 72 | /// example \":!#$%&*+.\/\<=>?\@\\\\^|-~\"@ 73 | /// 74 | public Parser OpStart; 75 | 76 | /// 77 | /// This parser should accept any legal tail characters of operators. 78 | /// Note that this parser should even be defined if the language doesn't 79 | /// support user-defined operators, or otherwise the 'reservedOp' 80 | /// parser won't work correctly. 81 | /// 82 | public Parser OpLetter; 83 | 84 | /// 85 | /// The list of reserved identifiers 86 | /// 87 | public IEnumerable ReservedNames; 88 | 89 | /// 90 | /// The list of reserved operators 91 | /// 92 | public IEnumerable ReservedOpNames; 93 | 94 | /// 95 | /// The list of reserved operators 96 | /// 97 | public bool CaseSensitive; 98 | 99 | /// 100 | /// A distinct set of the characters in the start and end multiline comment anchors 101 | /// 102 | public Memo> CommentStartEndDistinctChars 103 | { 104 | get 105 | { 106 | return Memo.ize(() => 107 | Enumerable.Concat( 108 | CommentStart.Cast(), 109 | CommentEnd.Cast() 110 | ).Distinct() 111 | ); 112 | } 113 | } 114 | } 115 | 116 | } 117 | -------------------------------------------------------------------------------- /CSharpMonad/src/parsec/token/TokenParser.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | 26 | using Monad.Utility; 27 | using System; 28 | using System.Collections.Generic; 29 | using System.Linq; 30 | 31 | namespace Monad.Parsec.Token 32 | { 33 | /// 34 | /// Token parser 35 | /// 36 | /// 37 | public class TokenParser : GenTokenParser 38 | where T : Token 39 | { 40 | public TokenParser(LanguageDef def) 41 | : 42 | base(def) 43 | { 44 | } 45 | } 46 | 47 | /// 48 | /// Generic token parser 49 | /// 50 | /// 51 | public class GenTokenParser 52 | { 53 | public readonly Parser Identifier; 54 | public readonly Parser Operator; 55 | public readonly Parser CharLiteral; 56 | public readonly Parser StringLiteral; 57 | public readonly Parser Natural; 58 | public readonly Parser Integer; 59 | public readonly Parser Float; 60 | public readonly Parser NaturalOrFloat; 61 | public readonly Parser Decimal; 62 | public readonly Parser Hexadecimal; 63 | public readonly Parser Octal; 64 | public readonly Func> Symbol; 65 | public readonly Func, Parser> Lexeme; 66 | public readonly Parser WhiteSpace; 67 | 68 | public readonly Func, Monad.Parsec.Token.Bracketing.Parens> Parens; 69 | public readonly Func, Monad.Parsec.Token.Bracketing.Braces> Braces; 70 | public readonly Func, Monad.Parsec.Token.Bracketing.Angles> Angles; 71 | public readonly Func, Monad.Parsec.Token.Bracketing.Brackets> Brackets; 72 | 73 | public readonly Symbol Semi; 74 | public readonly Symbol Comma; 75 | public readonly Symbol Colon; 76 | public readonly Symbol Dot; 77 | public readonly Func, Parser>> SemiSep; 78 | public readonly Func, Parser>> SemiSep1; 79 | public readonly Func, Parser>> CommaSep; 80 | public readonly Func, Parser>> CommaSep1; 81 | 82 | private readonly IReadOnlyDictionary> reserved; 83 | private readonly IReadOnlyDictionary> reservedOp; 84 | 85 | public readonly Func> Reserved; 86 | public readonly Func> ReservedOp; 87 | 88 | public GenTokenParser(LanguageDef def) 89 | { 90 | Identifier = Tok.Id.Identifier(def); 91 | reserved = def.ReservedNames.ToDictionary(name => name, name => Tok.Id.Reserved(name, def) as Parser); 92 | Operator = Tok.Ops.Operator(def); 93 | reservedOp = def.ReservedOpNames.ToDictionary(name => name, name => Tok.Ops.ReservedOp(name, def) as Parser); 94 | CharLiteral = Tok.Chars.CharLiteral(); 95 | StringLiteral = Tok.Strings.StringLiteral(); 96 | Natural = Tok.Numbers.Natural(); 97 | Integer = Tok.Numbers.Integer(); 98 | 99 | // floating = Tok.Numbers.Floating(); TODO 100 | // naturalOrFloat = Tok.Numbers.NaturalOrFloating(); TODO 101 | 102 | WhiteSpace = Tok.WhiteSpace(def); 103 | Decimal = Tok.Numbers.Decimal(); 104 | Hexadecimal = Tok.Numbers.Hexadecimal(); 105 | Octal = Tok.Numbers.Octal(); 106 | Symbol = (string name) => Tok.Symbol(name); 107 | Lexeme = (Parser p) => Tok.Lexeme(p); 108 | 109 | Parens = (Parser p) => Tok.Bracketing.Parens(p); 110 | Braces = (Parser p) => Tok.Bracketing.Braces(p); 111 | Angles = (Parser p) => Tok.Bracketing.Angles(p); 112 | Brackets = (Parser p) => Tok.Bracketing.Brackets(p); 113 | 114 | Semi = Tok.Symbol(";"); 115 | Comma = Tok.Symbol(","); 116 | Colon = Tok.Symbol(":"); 117 | Dot = Tok.Symbol("."); 118 | CommaSep = (Parser p) => Prim.SepBy(p, Comma); 119 | SemiSep = (Parser p) => Prim.SepBy(p, Semi); 120 | CommaSep1 = (Parser p) => Prim.SepBy1(p, Comma); 121 | SemiSep1 = (Parser p) => Prim.SepBy1(p, Semi); 122 | 123 | Reserved = name => reserved[name]; 124 | ReservedOp = name => reservedOp[name]; 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /CSharpMonad/src/parsec/token/TokenParsers.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | using Monad.Utility; 26 | using System; 27 | 28 | namespace Monad.Parsec.Token 29 | { 30 | public class Symbol : Parser 31 | { 32 | public Symbol(string name) 33 | : 34 | base( 35 | inp => (from sym in Tok.Lexeme>(Prim.String(name)) 36 | select new SymbolToken(sym)) 37 | .Parse(inp) 38 | ) 39 | { 40 | } 41 | } 42 | 43 | public class Lexeme : Parser 44 | { 45 | public Lexeme(Parser p) 46 | : 47 | base( 48 | inp => 49 | (from x in p 50 | from w in Prim.WhiteSpace() 51 | select x) 52 | .Parse(inp) 53 | ) 54 | { 55 | } 56 | } 57 | 58 | public class OneLineComment : Parser 59 | { 60 | public OneLineComment(LanguageDef def) 61 | : 62 | base( 63 | inp => (from t in Prim.String(def.CommentLine) 64 | from d in Prim.Many(Prim.Satisfy(ch => ch != '\n', "anything but a newline")) 65 | select Unit.Default) 66 | .Parse(inp) 67 | ) 68 | { 69 | } 70 | } 71 | 72 | public class MultiLineComment : Parser 73 | { 74 | public MultiLineComment(LanguageDef def) 75 | : 76 | base( 77 | inp => (from open in Prim.Try(Prim.String(def.CommentStart)) 78 | from incom in 79 | def.NestedComments 80 | ? new InCommentMulti(def) as Parser 81 | : new InCommentSingle(def) as Parser 82 | select incom) 83 | .Parse(inp) 84 | ) 85 | { 86 | } 87 | } 88 | 89 | public class InCommentMulti : Parser 90 | { 91 | public InCommentMulti(LanguageDef def) 92 | : 93 | base( 94 | inp => 95 | { 96 | int depth = 1; 97 | while (depth > 0) 98 | { 99 | var res = Prim.String(def.CommentEnd).Parse(inp); 100 | if (!res.IsFaulted) 101 | { 102 | depth--; 103 | inp = res.Value.Head().Item2; 104 | continue; 105 | } 106 | 107 | res = Prim.String(def.CommentStart).Parse(inp); 108 | if (!res.IsFaulted) 109 | { 110 | depth++; 111 | inp = res.Value.Head().Item2; 112 | continue; 113 | } 114 | 115 | var resU = Prim.SkipMany(Prim.NoneOf(def.CommentStartEndDistinctChars.Value)).Parse(inp); 116 | if (resU.Value.Head().Item2.IsEmpty) 117 | { 118 | return Prim.Failure(ParserError.Create("end of comment", inp)).Parse(inp); 119 | } 120 | inp = resU.Value.Head().Item2; 121 | } 122 | return Prim.Return(Unit.Default).Parse(inp); 123 | }) 124 | { 125 | } 126 | } 127 | 128 | public class InCommentSingle : Parser 129 | { 130 | public InCommentSingle(LanguageDef def) 131 | : 132 | base( 133 | inp => 134 | { 135 | while (true) 136 | { 137 | var res = Prim.String(def.CommentEnd).Parse(inp); 138 | if (!res.IsFaulted) 139 | { 140 | return Prim.Return(Unit.Default).Parse(res.Value.Head().Item2); 141 | } 142 | 143 | var resU = Prim.SkipMany(Prim.NoneOf(def.CommentStartEndDistinctChars.Value)).Parse(inp); 144 | if (resU.Value.Head().Item2.IsEmpty) 145 | { 146 | return Prim.Failure(ParserError.Create("end of comment", inp)).Parse(inp); 147 | } 148 | inp = resU.Value.Head().Item2; 149 | } 150 | }) 151 | { 152 | } 153 | } 154 | 155 | public class WhiteSpace : Parser 156 | { 157 | public WhiteSpace(LanguageDef def) 158 | : 159 | base( 160 | inp => 161 | { 162 | var simpleSpace = Tok.SimpleSpace(); 163 | 164 | if (String.IsNullOrEmpty(def.CommentLine) && String.IsNullOrEmpty(def.CommentStart)) 165 | { 166 | return Prim.SkipMany( 167 | simpleSpace.Fail("") 168 | ).Parse(inp); 169 | } 170 | else if (String.IsNullOrEmpty(def.CommentLine)) 171 | { 172 | return Prim.SkipMany( 173 | simpleSpace | Tok.MultiLineComment(def).Fail("") 174 | ).Parse(inp); 175 | } 176 | else if (String.IsNullOrEmpty(def.CommentStart)) 177 | { 178 | return Prim.SkipMany( 179 | simpleSpace | Tok.OneLineComment(def).Fail("") 180 | ) 181 | .Parse(inp); 182 | } 183 | else 184 | { 185 | return Prim.SkipMany( 186 | simpleSpace | Tok.OneLineComment(def) | Tok.MultiLineComment(def).Fail("") 187 | ) 188 | .Parse(inp); 189 | } 190 | } 191 | ) 192 | { } 193 | } 194 | } -------------------------------------------------------------------------------- /CSharpMonad/src/parsec/token/TokenTypes.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | using System.Collections.Generic; 26 | using System.Linq; 27 | using Monad.Utility; 28 | 29 | namespace Monad.Parsec.Token 30 | { 31 | public interface IToken 32 | { 33 | } 34 | 35 | public abstract class Token : IToken 36 | { 37 | public readonly SrcLoc Location; 38 | 39 | public Token(SrcLoc location) 40 | { 41 | Location = location; 42 | } 43 | 44 | } 45 | 46 | public class IntegerToken : Token 47 | { 48 | public readonly int Value; 49 | 50 | public IntegerToken(int value, SrcLoc location = null) 51 | : 52 | base(location) 53 | { 54 | Value = value; 55 | } 56 | } 57 | 58 | public class FloatToken : Token 59 | { 60 | public readonly double Value; 61 | 62 | public FloatToken(double value, SrcLoc location = null) 63 | : 64 | base(location) 65 | { 66 | Value = value; 67 | } 68 | } 69 | 70 | public class NaturalOrFloatToken : Token 71 | { 72 | public readonly Token Value; 73 | 74 | public NaturalOrFloatToken(double value, SrcLoc location = null) 75 | : 76 | base(location) 77 | { 78 | Value = new FloatToken(value,location); 79 | } 80 | 81 | public NaturalOrFloatToken(int value, SrcLoc location = null) 82 | : 83 | base(location) 84 | { 85 | Value = new IntegerToken(value, location); 86 | } 87 | } 88 | 89 | public class CharToken : Token 90 | { 91 | public readonly ParserChar Value; 92 | 93 | public CharToken(ParserChar value, SrcLoc location = null) 94 | : 95 | base(location) 96 | { 97 | Value = value; 98 | } 99 | } 100 | 101 | public class CharLiteralToken : CharToken 102 | { 103 | public CharLiteralToken(ParserChar value, SrcLoc location = null) 104 | : 105 | base(value,location) 106 | { 107 | } 108 | } 109 | 110 | public class StringToken : Token 111 | { 112 | public readonly ImmutableList Value; 113 | 114 | public StringToken(ImmutableList value, SrcLoc location = null) 115 | : 116 | base(location) 117 | { 118 | Value = value; 119 | } 120 | } 121 | 122 | public class WhiteSpaceToken : StringToken 123 | { 124 | public WhiteSpaceToken(ImmutableList value, SrcLoc location = null) 125 | : 126 | base(value,location) 127 | { 128 | } 129 | } 130 | 131 | public class StringLiteralToken : StringToken 132 | { 133 | public StringLiteralToken(ImmutableList value, SrcLoc location = null) 134 | : 135 | base(value, location) 136 | { 137 | } 138 | } 139 | 140 | public class IdentifierToken : StringToken 141 | { 142 | public IdentifierToken(ImmutableList value, SrcLoc location = null) 143 | : 144 | base(value,location) 145 | { 146 | } 147 | } 148 | 149 | public class ReservedToken : StringToken 150 | { 151 | public ReservedToken(ImmutableList value, SrcLoc location = null) 152 | : 153 | base(value, location) 154 | { 155 | } 156 | } 157 | 158 | public class OperatorToken : StringToken 159 | { 160 | public OperatorToken(ImmutableList value, SrcLoc location = null) 161 | : 162 | base(value, location) 163 | { 164 | } 165 | } 166 | 167 | public class ReservedOpToken : StringToken 168 | { 169 | public ReservedOpToken(ImmutableList value, SrcLoc location = null) 170 | : 171 | base(value, location) 172 | { 173 | } 174 | } 175 | 176 | public class SymbolToken : StringToken 177 | { 178 | public SymbolToken(ImmutableList value, SrcLoc location = null) 179 | : 180 | base(value, location == null ? location = value.First().Location : location) 181 | { 182 | } 183 | } 184 | 185 | public class BracketingToken : Token 186 | { 187 | public readonly IEnumerable Tokens; 188 | 189 | public BracketingToken(IEnumerable tokens, SrcLoc location = null) 190 | : 191 | base(location) 192 | { 193 | Tokens = tokens; 194 | } 195 | } 196 | 197 | public class AnglesToken : BracketingToken 198 | { 199 | public AnglesToken(IEnumerable tokens, SrcLoc location = null) 200 | : 201 | base(tokens,location) 202 | { 203 | } 204 | } 205 | 206 | public class BracesToken : BracketingToken 207 | { 208 | public BracesToken(IEnumerable tokens, SrcLoc location = null) 209 | : 210 | base(tokens, location) 211 | { 212 | } 213 | } 214 | 215 | public class ParensToken : BracketingToken 216 | { 217 | public ParensToken(IEnumerable tokens, SrcLoc location = null) 218 | : 219 | base(tokens, location) 220 | { 221 | } 222 | } 223 | 224 | public class BracketsToken : BracketingToken 225 | { 226 | public BracketsToken(IEnumerable tokens, SrcLoc location = null) 227 | : 228 | base(tokens, location) 229 | { 230 | } 231 | } 232 | } 233 | -------------------------------------------------------------------------------- /CSharpMonad/src/parsec/token/bracketing/Bracketing.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | namespace Monad.Parsec.Token.Bracketing 26 | { 27 | public class Parens : Parser 28 | { 29 | public Parens(Parser betweenParser) 30 | : 31 | base( inp => Prim.Between( Tok.Symbol("("), Tok.Symbol(")"), betweenParser ) 32 | .Parse(inp) ) 33 | { } 34 | } 35 | public class Braces : Parser 36 | { 37 | public Braces(Parser betweenParser) 38 | : 39 | base(inp => Prim.Between(Tok.Symbol("{"), Tok.Symbol("}"), betweenParser) 40 | .Parse(inp)) 41 | { } 42 | } 43 | public class Angles : Parser 44 | { 45 | public Angles(Parser betweenParser) 46 | : 47 | base(inp => Prim.Between(Tok.Symbol("<"), Tok.Symbol(">"), betweenParser) 48 | .Parse(inp)) 49 | { } 50 | } 51 | public class Brackets : Parser 52 | { 53 | public Brackets(Parser betweenParser) 54 | : 55 | base(inp => Prim.Between(Tok.Symbol("["), Tok.Symbol("]"), betweenParser) 56 | .Parse(inp)) 57 | { } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /CSharpMonad/src/parsec/token/chars/Chars.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | using System; 26 | using System.Collections.Generic; 27 | using System.Linq; 28 | using Monad.Utility; 29 | 30 | namespace Monad.Parsec.Token.Chars 31 | { 32 | public class CharLiteral : Parser 33 | { 34 | public CharLiteral() 35 | : 36 | base( 37 | inp => Tok.Lexeme( 38 | Prim.Between( 39 | Prim.Character('\''), 40 | Prim.Character('\'').Fail("end of character"), 41 | new CharacterChar() 42 | )) 43 | .Select(ch => new CharLiteralToken(ch, inp.Head().Location)) 44 | .Fail("character") 45 | .Parse(inp) 46 | ) 47 | { } 48 | } 49 | 50 | public class CharacterChar : Parser 51 | { 52 | public CharacterChar() 53 | : 54 | base( 55 | inp => new CharLetter() 56 | .Or(Tok.Chars.CharEscape()) 57 | .Fail("literal character") 58 | .Parse(inp) 59 | ) 60 | { } 61 | } 62 | 63 | /// 64 | /// Valid non-escape, non-quote char 65 | /// 66 | public class CharLetter : Satisfy 67 | { 68 | public CharLetter() 69 | : 70 | base( 71 | c => (c != '\'') && (c != '\\') && (c > 26), 72 | "char letter" 73 | ) 74 | { } 75 | } 76 | 77 | /// 78 | /// Escape character (\) followed by an accepted escape code 79 | /// 80 | /// 81 | public class CharEscape : Parser 82 | { 83 | public CharEscape() 84 | : 85 | base( 86 | inp => (from c in Prim.Character('\\') 87 | from ec in Tok.Chars.EscapeCode() 88 | select ec) 89 | .Parse(inp) 90 | ) 91 | { } 92 | } 93 | 94 | /// 95 | /// Escape code set parser without the \ prefix 96 | /// 97 | /// 98 | public class EscapeCode : Parser 99 | { 100 | public EscapeCode() 101 | : 102 | base( 103 | inp => new CharEsc() 104 | .Or(new CharNum()) 105 | //.Or(Tok.CharAscii()) TODO 106 | //.Or(Tok.CharControl()) TODO 107 | .Parse(inp) 108 | ) 109 | { } 110 | } 111 | 112 | /// 113 | /// The single char escape codes without the \ prefix 114 | /// \a \b \f \n \r \t \v \\ \" \' 115 | /// 116 | /// 117 | public class CharEsc : Parser 118 | { 119 | public static IEnumerable> EscapeMap; 120 | 121 | static CharEsc() 122 | { 123 | EscapeMap = 124 | "abfnrtv\\\"\'".Cast().Zip( 125 | "\a\b\f\n\r\t\v\\\"\'".Cast(), 126 | (l, r) => Tuple.Create(l, r)); 127 | } 128 | 129 | public CharEsc() 130 | : 131 | base( 132 | inp => 133 | Prim.Choice( 134 | EscapeMap.Select(pair => new ParseEsc(pair.Item1, pair.Item2)) 135 | ) 136 | .Parse(inp) 137 | ) 138 | { } 139 | 140 | 141 | private class ParseEsc : Parser 142 | { 143 | public ParseEsc(char c, char code) 144 | : 145 | base( 146 | inp => 147 | { 148 | var r = Prim.Character(c).Parse(inp); 149 | if (r.IsFaulted) 150 | { 151 | return r; 152 | } 153 | else 154 | { 155 | var tuple = r.Value.First(); 156 | return ParserResult.Success( 157 | Tuple.Create>( 158 | new ParserChar( 159 | code, 160 | tuple.Item1.Location 161 | ), 162 | tuple.Item2 163 | ).Cons() 164 | ); 165 | } 166 | } 167 | ) 168 | { } 169 | } 170 | } 171 | 172 | public class CharNum : Parser 173 | { 174 | public CharNum() 175 | : 176 | base( 177 | inp => (from code in 178 | Tok.Numbers.Decimal() 179 | .Or(from d in Tok.Numbers.Hexadecimal() 180 | select d) 181 | .Or(from d in Tok.Numbers.Octal() 182 | select d) 183 | select new ParserChar((char)code.Value, code.Location)) 184 | .Parse(inp) 185 | ) 186 | { } 187 | } 188 | } -------------------------------------------------------------------------------- /CSharpMonad/src/parsec/token/idents/Idents.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | using System.Linq; 26 | using Monad.Utility; 27 | 28 | namespace Monad.Parsec.Token.Idents 29 | { 30 | internal static class IdentHelper 31 | { 32 | 33 | /// 34 | /// TODO: Make this pay attention to the case-sensitivity settings 35 | /// 36 | internal static Parser> CaseString(string str, GeneralLanguageDef languageDef) 37 | { 38 | return Prim.String(str); 39 | } 40 | 41 | /// 42 | /// TODO: Make this pay attention to the case-sensitivity settings 43 | /// 44 | internal static bool IsReservedName(ImmutableList name, GeneralLanguageDef languageDef) 45 | { 46 | return languageDef.ReservedNames.Contains(name.AsString()); 47 | } 48 | } 49 | 50 | public class Reserved : Parser 51 | { 52 | public Reserved(string name, GeneralLanguageDef languageDef) 53 | : 54 | base( 55 | inp => Tok.Lexeme( 56 | from cs in IdentHelper.CaseString(name, languageDef) 57 | from nf in Prim.NotFollowedBy( languageDef.IdentLetter ) 58 | .Fail("end of " + cs.AsString()) 59 | select new ReservedToken(cs,inp.Head().Location) 60 | ) 61 | .Parse(inp) 62 | ) 63 | { } 64 | } 65 | 66 | public class Identifier : Parser 67 | { 68 | public Identifier(GeneralLanguageDef languageDef) 69 | : 70 | base( 71 | inp => 72 | { 73 | var res = Tok.Lexeme( 74 | from name in new Ident(languageDef) 75 | where !IdentHelper.IsReservedName(name, languageDef) 76 | select new IdentifierToken(name, inp.First().Location) 77 | ) 78 | .Parse(inp); 79 | 80 | if (res.IsFaulted) 81 | return res; 82 | 83 | if (res.Value.IsEmpty) 84 | return ParserResult.Fail("unexpected: reserved word",inp); 85 | 86 | return res; 87 | } 88 | ) 89 | { } 90 | } 91 | 92 | public class Ident : Parser> 93 | { 94 | public Ident(GeneralLanguageDef languageDef) 95 | : 96 | base( 97 | inp =>(from c in languageDef.IdentStart 98 | from cs in Prim.Many(languageDef.IdentLetter) 99 | select c.Cons(cs)) 100 | .Fail("identifier") 101 | .Parse(inp) 102 | ) 103 | {} 104 | } 105 | 106 | } 107 | -------------------------------------------------------------------------------- /CSharpMonad/src/parsec/token/ops/Ops.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | using System.Linq; 26 | using Monad.Utility; 27 | 28 | namespace Monad.Parsec.Token.Ops 29 | { 30 | internal static class OpsHelper 31 | { 32 | /// 33 | /// TODO: Make this pay attention to the case-sensitivity settings 34 | /// 35 | internal static bool IsReservedOp(ImmutableList name, GeneralLanguageDef languageDef) 36 | { 37 | return languageDef.ReservedOpNames.Contains(name.AsString()); 38 | } 39 | } 40 | 41 | public class ReservedOp : Parser 42 | { 43 | public ReservedOp(string name, GeneralLanguageDef languageDef) 44 | : 45 | base( 46 | inp => Tok.Lexeme( 47 | from op in Prim.String(name) 48 | from nf in Prim.NotFollowedBy( languageDef.OpLetter ) 49 | .Fail("end of " + op.AsString()) 50 | select new ReservedOpToken(op, inp.First().Location) 51 | ) 52 | .Parse(inp) 53 | ) 54 | { } 55 | } 56 | 57 | public class Operator : Parser 58 | { 59 | public Operator(GeneralLanguageDef languageDef) 60 | : 61 | base( 62 | inp => 63 | { 64 | var res = Tok.Lexeme( 65 | from name in new Oper(languageDef) 66 | where !OpsHelper.IsReservedOp(name, languageDef) 67 | select new OperatorToken(name, inp.First().Location)) 68 | .Parse(inp); 69 | 70 | if (res.IsFaulted) 71 | return res; 72 | 73 | if (res.Value.IsEmpty) 74 | return ParserResult.Fail("unexpected: reserved operator", inp); 75 | 76 | return res; 77 | } 78 | ) 79 | { } 80 | } 81 | 82 | public class Oper : Parser> 83 | { 84 | public Oper(GeneralLanguageDef languageDef) 85 | : 86 | base( 87 | inp => (from c in languageDef.OpStart 88 | from cs in Prim.Many(languageDef.OpLetter) 89 | select c.Cons(cs)) 90 | .Fail("operator") 91 | .Parse(inp) 92 | ) 93 | {} 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /CSharpMonad/src/parsec/token/strings/Strings.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | namespace Monad.Parsec.Token.Strings 26 | { 27 | public class StringLiteral : Parser 28 | { 29 | public StringLiteral() 30 | : 31 | base( 32 | inp => (from l in Tok.Lexeme( 33 | from str in Prim.Between( 34 | Prim.Character('"'), 35 | Prim.Character('"').Fail("end of string"), 36 | Prim.Many( new StringChar() ) 37 | ) 38 | select str 39 | ) 40 | select new StringLiteralToken(l,inp.Head().Location) 41 | ) 42 | .Fail("literal string") 43 | .Parse(inp) 44 | ) 45 | { } 46 | } 47 | 48 | public class StringChar : Parser 49 | { 50 | public StringChar() 51 | : 52 | base( 53 | inp => (from c in new StringLetter() 54 | select c) 55 | .Or( new StringEscape() ) 56 | .Fail("string character") 57 | .Parse(inp) 58 | ) 59 | { } 60 | } 61 | 62 | public class StringLetter : Satisfy 63 | { 64 | public StringLetter() 65 | : 66 | base( c => (c != '"') && (c != '\\') && (c > 26), "string character" ) 67 | { } 68 | } 69 | 70 | public class StringEscape : Parser 71 | { 72 | public StringEscape() 73 | : 74 | base( 75 | inp => 76 | Prim.Character('\\') 77 | .And( 78 | new EscapeGap().And(Prim.Failure(ParserError.Create("", inp))) 79 | .Or(new EscapeEmpty().And(Prim.Failure(ParserError.Create("", inp)))) 80 | .Or(Tok.Chars.EscapeCode()) 81 | ) 82 | .Parse(inp) 83 | ) 84 | { } 85 | } 86 | 87 | public class EscapeGap : Parser 88 | { 89 | public EscapeGap() 90 | : 91 | base( 92 | inp => (from sp in Prim.Many1(Prim.Character(' ')) 93 | from ch in Prim.Character('\\') 94 | select ch) 95 | .Fail("end of string gap") 96 | .Parse(inp) 97 | ) 98 | {} 99 | } 100 | 101 | public class EscapeEmpty : Character 102 | { 103 | public EscapeEmpty() 104 | : 105 | base('&') 106 | { } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /CSharpMonad/src/utility/Lam.da.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Monad.Utility 4 | { 5 | /// 6 | /// Type inference helper 7 | /// 8 | public static class Lam 9 | { 10 | public static Func da(Func fn) 11 | { 12 | if (fn == null) throw new ArgumentNullException("fn"); 13 | return fn; 14 | } 15 | 16 | public static Func da(Func fn) 17 | { 18 | if (fn == null) throw new ArgumentNullException("fn"); 19 | return fn; 20 | } 21 | 22 | public static Func da(Func fn) 23 | { 24 | if (fn == null) throw new ArgumentNullException("fn"); 25 | return fn; 26 | } 27 | 28 | public static Func da(Func fn) 29 | { 30 | if (fn == null) throw new ArgumentNullException("fn"); 31 | return fn; 32 | } 33 | 34 | public static Func da(Func fn) 35 | { 36 | if (fn == null) throw new ArgumentNullException("fn"); 37 | return fn; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /CSharpMonad/src/utility/Memoize.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Monad.Utility 5 | { 6 | /// 7 | /// Create a memoized value 8 | /// 9 | public static class Memo 10 | { 11 | /// 12 | /// Create a memoized (cached) value, doesn't calculate the provided expression until the 13 | /// value is required, and once it has been calculated it will cache the value for future 14 | /// access. 15 | /// 16 | public static Memo ize(Func func) 17 | { 18 | if (func == null) throw new ArgumentNullException("func"); 19 | return new Memo(func); 20 | } 21 | } 22 | 23 | /// 24 | /// Create a memoized (cached) value, doesn't calculate the provided expression until the 25 | /// value is required, and once it has been calculated it will cache the value for future 26 | /// access. 27 | /// 28 | /// 29 | public class Memo 30 | { 31 | readonly Func func; 32 | WeakReference reference; 33 | 34 | /// 35 | /// Ctor 36 | /// 37 | /// Function to invoke to get the value when needed 38 | public Memo(Func func) 39 | { 40 | if (func == null) throw new ArgumentNullException("func"); 41 | this.func = func; 42 | } 43 | 44 | /// 45 | /// Access the value (this will cause the calculation if the value hasn't yet 46 | /// been memoized). 47 | /// 48 | public T Value 49 | { 50 | get 51 | { 52 | if (reference == null) 53 | { 54 | reference = new WeakReference(func()); 55 | } 56 | else if (!reference.IsAlive) 57 | { 58 | reference.Target = func(); 59 | } 60 | return (T)reference.Target; 61 | } 62 | } 63 | 64 | public bool HasValue 65 | { 66 | get 67 | { 68 | return reference != null && reference.IsAlive; 69 | } 70 | } 71 | 72 | /// 73 | /// Forget the memoized value 74 | /// 75 | public void Forget() 76 | { 77 | reference = null; 78 | } 79 | 80 | /// 81 | /// Allows implicit conversion from the Memo to T. 82 | /// 83 | public static implicit operator T(Memo memo) 84 | { 85 | return memo.Value; 86 | } 87 | } 88 | 89 | /// 90 | /// Extension method for Func 91 | /// 92 | public static class MemoExt 93 | { 94 | /// 95 | /// Memoize the function 96 | /// 97 | public static Func Memo(this Func f) 98 | { 99 | if (f == null) throw new ArgumentNullException("f"); 100 | Dictionary cache = new Dictionary(); 101 | return t => cache.ContainsKey(t) 102 | ? cache[t] 103 | : (cache[t] = f(t)); 104 | } 105 | 106 | /// 107 | /// Memoize the function 108 | /// 109 | public static Func Memo(this Func f) 110 | { 111 | if (f == null) throw new ArgumentNullException("f"); 112 | Func> del = (T1 t1) => (T2 t2) => f(t1, t2); 113 | del = del.Memo(); 114 | return (T1 t1, T2 t2) => del(t1)(t2); 115 | } 116 | 117 | /// 118 | /// Memoize the function 119 | /// 120 | public static Func Memo(this Func f) 121 | { 122 | if (f == null) throw new ArgumentNullException("f"); 123 | Func>> del = (T1 t1) => (T2 t2) => (T3 t3) => f(t1, t2, t3); 124 | del = del.Memo(); 125 | return (T1 t1, T2 t2, T3 t3) => del(t1)(t2)(t3); 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /CSharpMonad/src/utility/Unit.cs: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////////// 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2014 Paul Louth 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | using System; 26 | 27 | namespace Monad.Utility 28 | { 29 | /// 30 | /// A type with only one value, itself. 31 | /// This is the functional world's equivalent of Void. 32 | /// 33 | public struct Unit 34 | { 35 | /// 36 | /// Use a singleton so that ref equality works and to reduce any unnecessary 37 | /// thrashing of the GC from creating an object which is always the same. 38 | /// 39 | public static readonly Unit Default = new Unit(); 40 | 41 | /// 42 | /// Performs an action which instead of returning void will return Unit 43 | /// 44 | /// 45 | /// 46 | public static Unit Return(Action action) 47 | { 48 | if (action == null) throw new ArgumentNullException("action"); 49 | 50 | action(); 51 | return Default; 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016-2019 Paul Louth 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 | --------------------------------------------------------------------------------