├── .gitignore
├── .paket
└── Paket.Restore.targets
├── LICENSE
├── README.md
├── build.fsx
├── compiler.sln
├── fake.cmd
├── fake.sh
├── paket.dependencies
├── paket.lock
└── src
└── HastiLang.Core
├── BaseTypes.fs
├── ErrorExtensions.fs
├── HastiLang.Core.fsproj
├── HigherPipes.fs
├── IdeUtils.fs
├── IndentationParser.fs
├── InterpreterStates.fs
├── MSILCompiler.fs
├── ParserConfig.fs
├── ParserConfigs.fs
├── ParserUtils.fs
├── Parsers.fs
└── paket.references
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015/2017 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # Visual Studio 2017 auto generated files
33 | Generated\ Files/
34 |
35 | # MSTest test Results
36 | [Tt]est[Rr]esult*/
37 | [Bb]uild[Ll]og.*
38 |
39 | # NUNIT
40 | *.VisualState.xml
41 | TestResult.xml
42 |
43 | # Build Results of an ATL Project
44 | [Dd]ebugPS/
45 | [Rr]eleasePS/
46 | dlldata.c
47 |
48 | # Benchmark Results
49 | BenchmarkDotNet.Artifacts/
50 |
51 | # .NET Core
52 | project.lock.json
53 | project.fragment.lock.json
54 | artifacts/
55 | **/Properties/launchSettings.json
56 |
57 | # StyleCop
58 | StyleCopReport.xml
59 |
60 | # Files built by Visual Studio
61 | *_i.c
62 | *_p.c
63 | *_i.h
64 | *.ilk
65 | *.meta
66 | *.obj
67 | *.iobj
68 | *.pch
69 | *.pdb
70 | *.ipdb
71 | *.pgc
72 | *.pgd
73 | *.rsp
74 | *.sbr
75 | *.tlb
76 | *.tli
77 | *.tlh
78 | *.tmp
79 | *.tmp_proj
80 | *.log
81 | *.vspscc
82 | *.vssscc
83 | .builds
84 | *.pidb
85 | *.svclog
86 | *.scc
87 |
88 | # Chutzpah Test files
89 | _Chutzpah*
90 |
91 | # Visual C++ cache files
92 | ipch/
93 | *.aps
94 | *.ncb
95 | *.opendb
96 | *.opensdf
97 | *.sdf
98 | *.cachefile
99 | *.VC.db
100 | *.VC.VC.opendb
101 |
102 | # Visual Studio profiler
103 | *.psess
104 | *.vsp
105 | *.vspx
106 | *.sap
107 |
108 | # Visual Studio Trace Files
109 | *.e2e
110 |
111 | # TFS 2012 Local Workspace
112 | $tf/
113 |
114 | # Guidance Automation Toolkit
115 | *.gpState
116 |
117 | # ReSharper is a .NET coding add-in
118 | _ReSharper*/
119 | *.[Rr]e[Ss]harper
120 | *.DotSettings.user
121 |
122 | # JustCode is a .NET coding add-in
123 | .JustCode
124 |
125 | # TeamCity is a build add-in
126 | _TeamCity*
127 |
128 | # DotCover is a Code Coverage Tool
129 | *.dotCover
130 |
131 | # AxoCover is a Code Coverage Tool
132 | .axoCover/*
133 | !.axoCover/settings.json
134 |
135 | # Visual Studio code coverage results
136 | *.coverage
137 | *.coveragexml
138 |
139 | # NCrunch
140 | _NCrunch_*
141 | .*crunch*.local.xml
142 | nCrunchTemp_*
143 |
144 | # MightyMoose
145 | *.mm.*
146 | AutoTest.Net/
147 |
148 | # Web workbench (sass)
149 | .sass-cache/
150 |
151 | # Installshield output folder
152 | [Ee]xpress/
153 |
154 | # DocProject is a documentation generator add-in
155 | DocProject/buildhelp/
156 | DocProject/Help/*.HxT
157 | DocProject/Help/*.HxC
158 | DocProject/Help/*.hhc
159 | DocProject/Help/*.hhk
160 | DocProject/Help/*.hhp
161 | DocProject/Help/Html2
162 | DocProject/Help/html
163 |
164 | # Click-Once directory
165 | publish/
166 |
167 | # Publish Web Output
168 | *.[Pp]ublish.xml
169 | *.azurePubxml
170 | # Note: Comment the next line if you want to checkin your web deploy settings,
171 | # but database connection strings (with potential passwords) will be unencrypted
172 | *.pubxml
173 | *.publishproj
174 |
175 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
176 | # checkin your Azure Web App publish settings, but sensitive information contained
177 | # in these scripts will be unencrypted
178 | PublishScripts/
179 |
180 | # NuGet Packages
181 | *.nupkg
182 | # The packages folder can be ignored because of Package Restore
183 | **/[Pp]ackages/*
184 | # except build/, which is used as an MSBuild target.
185 | !**/[Pp]ackages/build/
186 | # Uncomment if necessary however generally it will be regenerated when needed
187 | #!**/[Pp]ackages/repositories.config
188 | # NuGet v3's project.json files produces more ignorable files
189 | *.nuget.props
190 | *.nuget.targets
191 |
192 | # Microsoft Azure Build Output
193 | csx/
194 | *.build.csdef
195 |
196 | # Microsoft Azure Emulator
197 | ecf/
198 | rcf/
199 |
200 | # Windows Store app package directories and files
201 | AppPackages/
202 | BundleArtifacts/
203 | Package.StoreAssociation.xml
204 | _pkginfo.txt
205 | *.appx
206 |
207 | # Visual Studio cache files
208 | # files ending in .cache can be ignored
209 | *.[Cc]ache
210 | # but keep track of directories ending in .cache
211 | !*.[Cc]ache/
212 |
213 | # Others
214 | ClientBin/
215 | ~$*
216 | *~
217 | *.dbmdl
218 | *.dbproj.schemaview
219 | *.jfm
220 | *.pfx
221 | *.publishsettings
222 | orleans.codegen.cs
223 |
224 | # Including strong name files can present a security risk
225 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
226 | #*.snk
227 |
228 | # Since there are multiple workflows, uncomment next line to ignore bower_components
229 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
230 | #bower_components/
231 |
232 | # RIA/Silverlight projects
233 | Generated_Code/
234 |
235 | # Backup & report files from converting an old project file
236 | # to a newer Visual Studio version. Backup files are not needed,
237 | # because we have git ;-)
238 | _UpgradeReport_Files/
239 | Backup*/
240 | UpgradeLog*.XML
241 | UpgradeLog*.htm
242 | ServiceFabricBackup/
243 | *.rptproj.bak
244 |
245 | # SQL Server files
246 | *.mdf
247 | *.ldf
248 | *.ndf
249 |
250 | # Business Intelligence projects
251 | *.rdl.data
252 | *.bim.layout
253 | *.bim_*.settings
254 | *.rptproj.rsuser
255 |
256 | # Microsoft Fakes
257 | FakesAssemblies/
258 |
259 | # GhostDoc plugin setting file
260 | *.GhostDoc.xml
261 |
262 | # Node.js Tools for Visual Studio
263 | .ntvs_analysis.dat
264 | node_modules/
265 |
266 | # Visual Studio 6 build log
267 | *.plg
268 |
269 | # Visual Studio 6 workspace options file
270 | *.opt
271 |
272 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
273 | *.vbw
274 |
275 | # Visual Studio LightSwitch build output
276 | **/*.HTMLClient/GeneratedArtifacts
277 | **/*.DesktopClient/GeneratedArtifacts
278 | **/*.DesktopClient/ModelManifest.xml
279 | **/*.Server/GeneratedArtifacts
280 | **/*.Server/ModelManifest.xml
281 | _Pvt_Extensions
282 |
283 | # Paket dependency manager
284 | .paket/paket.exe
285 | paket-files/
286 |
287 | # FAKE - F# Make
288 | .fake/
289 |
290 | # JetBrains Rider
291 | .idea/
292 | *.sln.iml
293 |
294 | # CodeRush
295 | .cr/
296 |
297 | # Python Tools for Visual Studio (PTVS)
298 | __pycache__/
299 | *.pyc
300 |
301 | # Cake - Uncomment if you are using it
302 | # tools/**
303 | # !tools/packages.config
304 |
305 | # Tabs Studio
306 | *.tss
307 |
308 | # Telerik's JustMock configuration file
309 | *.jmconfig
310 |
311 | # BizTalk build output
312 | *.btp.cs
313 | *.btm.cs
314 | *.odx.cs
315 | *.xsd.cs
316 |
317 | # OpenCover UI analysis results
318 | OpenCover/
319 |
320 | # Azure Stream Analytics local run output
321 | ASALocalRun/
322 |
323 | # MSBuild Binary and Structured Log
324 | *.binlog
325 |
326 | # NVidia Nsight GPU debugger configuration file
327 | *.nvuser
328 |
329 | # MFractors (Xamarin productivity tool) working folder
330 | .mfractor/
331 | /.ionide/symbolCache.db
332 |
--------------------------------------------------------------------------------
/.paket/Paket.Restore.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath)
8 |
9 | $(MSBuildVersion)
10 | 15.0.0
11 | false
12 | true
13 |
14 | true
15 | $(MSBuildThisFileDirectory)
16 | $(MSBuildThisFileDirectory)..\
17 | $(PaketRootPath)paket-files\paket.restore.cached
18 | $(PaketRootPath)paket.lock
19 | classic
20 | proj
21 | assembly
22 | native
23 | /Library/Frameworks/Mono.framework/Commands/mono
24 | mono
25 |
26 |
27 | $(PaketRootPath)paket.bootstrapper.exe
28 | $(PaketToolsPath)paket.bootstrapper.exe
29 | $([System.IO.Path]::GetDirectoryName("$(PaketBootStrapperExePath)"))\
30 |
31 |
32 |
33 |
34 | $(PaketRootPath)paket.exe
35 | $(PaketToolsPath)paket.exe
36 | $(PaketToolsPath)paket.exe
37 | $(_PaketBootStrapperExeDir)paket.exe
38 | paket.exe
39 |
40 |
41 | $(PaketRootPath)paket
42 | $(PaketToolsPath)paket
43 | $(PaketToolsPath)paket
44 |
45 |
46 | $(PaketRootPath)paket.exe
47 | $(PaketToolsPath)paket.exe
48 |
49 |
50 | $(PaketBootStrapperExeDir)paket.exe
51 |
52 |
53 | paket
54 |
55 |
56 | <_PaketExeExtension>$([System.IO.Path]::GetExtension("$(PaketExePath)"))
57 | dotnet "$(PaketExePath)"
58 | $(MonoPath) --runtime=v4.0.30319 "$(PaketExePath)"
59 | "$(PaketExePath)"
60 |
61 |
62 | "$(PaketBootStrapperExePath)"
63 | $(MonoPath) --runtime=v4.0.30319 "$(PaketBootStrapperExePath)"
64 |
65 |
66 |
67 |
68 | true
69 | true
70 |
71 |
72 | True
73 |
74 | $(BaseIntermediateOutputPath.TrimEnd('\').TrimEnd('\/'))
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 | true
89 | $(NoWarn);NU1603;NU1604;NU1605;NU1608
90 | false
91 | true
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 | $([System.IO.File]::ReadAllText('$(PaketRestoreCacheFile)'))
101 |
102 |
103 |
104 |
105 |
106 |
108 | $([System.Text.RegularExpressions.Regex]::Split(`%(Identity)`, `": "`)[0].Replace(`"`, ``).Replace(` `, ``))
109 | $([System.Text.RegularExpressions.Regex]::Split(`%(Identity)`, `": "`)[1].Replace(`"`, ``).Replace(` `, ``))
110 |
111 |
112 |
113 |
114 | %(PaketRestoreCachedKeyValue.Value)
115 | %(PaketRestoreCachedKeyValue.Value)
116 |
117 |
118 |
119 |
120 | true
121 | false
122 | true
123 |
124 |
125 |
129 |
130 | true
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 | $(PaketIntermediateOutputPath)\$(MSBuildProjectFile).paket.references.cached
150 |
151 | $(MSBuildProjectFullPath).paket.references
152 |
153 | $(MSBuildProjectDirectory)\$(MSBuildProjectName).paket.references
154 |
155 | $(MSBuildProjectDirectory)\paket.references
156 |
157 | false
158 | true
159 | true
160 | references-file-or-cache-not-found
161 |
162 |
163 |
164 |
165 | $([System.IO.File]::ReadAllText('$(PaketReferencesCachedFilePath)'))
166 | $([System.IO.File]::ReadAllText('$(PaketOriginalReferencesFilePath)'))
167 | references-file
168 | false
169 |
170 |
171 |
172 |
173 | false
174 |
175 |
176 |
177 |
178 | true
179 | target-framework '$(TargetFramework)' or '$(TargetFrameworks)' files @(PaketResolvedFilePaths)
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 | false
191 | true
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 | $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',').Length)
203 | $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[0])
204 | $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[1])
205 | $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[4])
206 | $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[5])
207 |
208 |
209 | %(PaketReferencesFileLinesInfo.PackageVersion)
210 | All
211 | runtime
212 | runtime
213 | true
214 | true
215 |
216 |
217 |
218 |
219 | $(PaketIntermediateOutputPath)/$(MSBuildProjectFile).paket.clitools
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 | $([System.String]::Copy('%(PaketCliToolFileLines.Identity)').Split(',')[0])
229 | $([System.String]::Copy('%(PaketCliToolFileLines.Identity)').Split(',')[1])
230 |
231 |
232 | %(PaketCliToolFileLinesInfo.PackageVersion)
233 |
234 |
235 |
236 |
240 |
241 |
242 |
243 |
244 |
245 | false
246 |
247 |
248 |
249 |
250 |
251 | <_NuspecFilesNewLocation Include="$(PaketIntermediateOutputPath)\$(Configuration)\*.nuspec"/>
252 |
253 |
254 |
255 |
256 |
257 | $(MSBuildProjectDirectory)/$(MSBuildProjectFile)
258 | true
259 | false
260 | true
261 | false
262 | true
263 | false
264 | true
265 | false
266 | true
267 | $(PaketIntermediateOutputPath)\$(Configuration)
268 | $(PaketIntermediateOutputPath)
269 |
270 |
271 |
272 | <_NuspecFiles Include="$(AdjustedNuspecOutputPath)\*.$(PackageVersion.Split(`+`)[0]).nuspec"/>
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
330 |
331 |
374 |
375 |
417 |
418 |
459 |
460 |
461 |
462 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Hasti Language
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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # کامپایلر
4 | این مخزن محل توسعه کامپایلر زبان برنامه نویسی هستی است
5 |
6 | این پروژه صرفا تحقیقاتی است و به هدف استفاده خارج از محیط آموزشی ساخته نشده است
7 |
8 |
9 |
10 | **This is only for research and not intended to be used**
11 |
--------------------------------------------------------------------------------
/build.fsx:
--------------------------------------------------------------------------------
1 | #load ".fake/build.fsx/intellisense.fsx"
2 | open Fake.Core
3 | open Fake.DotNet
4 | open Fake.IO
5 | open Fake.IO.FileSystemOperators
6 | open Fake.IO.Globbing.Operators
7 | open Fake.Core.TargetOperators
8 |
9 | Target.create "Clean" (fun _ ->
10 | !! "src/**/bin"
11 | ++ "src/**/obj"
12 | |> Shell.cleanDirs
13 | )
14 |
15 | Target.create "Build" (fun _ ->
16 | !! "src/**/*.*proj"
17 | |> Seq.iter (DotNet.build id)
18 | )
19 |
20 | Target.create "All" ignore
21 |
22 | "Clean"
23 | ==> "Build"
24 | ==> "All"
25 |
26 | Target.runOrDefault "All"
27 |
--------------------------------------------------------------------------------
/compiler.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.26124.0
5 | MinimumVisualStudioVersion = 15.0.26124.0
6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".paket", ".paket", "{1CE5F572-30E7-4244-B600-753CC413A8E6}"
7 | ProjectSection(SolutionItems) = preProject
8 | paket.dependencies = paket.dependencies
9 | EndProjectSection
10 | EndProject
11 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{FC93A659-4436-4A37-AC5E-0EFF1B66A619}"
12 | EndProject
13 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "HastiLang.Core", "src\HastiLang.Core\HastiLang.Core.fsproj", "{898D5D40-411C-4D1D-AAB4-B4FFC8835BE8}"
14 | EndProject
15 | Global
16 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
17 | Debug|Any CPU = Debug|Any CPU
18 | Debug|x64 = Debug|x64
19 | Debug|x86 = Debug|x86
20 | Release|Any CPU = Release|Any CPU
21 | Release|x64 = Release|x64
22 | Release|x86 = Release|x86
23 | EndGlobalSection
24 | GlobalSection(SolutionProperties) = preSolution
25 | HideSolutionNode = FALSE
26 | EndGlobalSection
27 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
28 | {898D5D40-411C-4D1D-AAB4-B4FFC8835BE8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
29 | {898D5D40-411C-4D1D-AAB4-B4FFC8835BE8}.Debug|Any CPU.Build.0 = Debug|Any CPU
30 | {898D5D40-411C-4D1D-AAB4-B4FFC8835BE8}.Debug|x64.ActiveCfg = Debug|Any CPU
31 | {898D5D40-411C-4D1D-AAB4-B4FFC8835BE8}.Debug|x64.Build.0 = Debug|Any CPU
32 | {898D5D40-411C-4D1D-AAB4-B4FFC8835BE8}.Debug|x86.ActiveCfg = Debug|Any CPU
33 | {898D5D40-411C-4D1D-AAB4-B4FFC8835BE8}.Debug|x86.Build.0 = Debug|Any CPU
34 | {898D5D40-411C-4D1D-AAB4-B4FFC8835BE8}.Release|Any CPU.ActiveCfg = Release|Any CPU
35 | {898D5D40-411C-4D1D-AAB4-B4FFC8835BE8}.Release|Any CPU.Build.0 = Release|Any CPU
36 | {898D5D40-411C-4D1D-AAB4-B4FFC8835BE8}.Release|x64.ActiveCfg = Release|Any CPU
37 | {898D5D40-411C-4D1D-AAB4-B4FFC8835BE8}.Release|x64.Build.0 = Release|Any CPU
38 | {898D5D40-411C-4D1D-AAB4-B4FFC8835BE8}.Release|x86.ActiveCfg = Release|Any CPU
39 | {898D5D40-411C-4D1D-AAB4-B4FFC8835BE8}.Release|x86.Build.0 = Release|Any CPU
40 | EndGlobalSection
41 | GlobalSection(NestedProjects) = preSolution
42 | {898D5D40-411C-4D1D-AAB4-B4FFC8835BE8} = {FC93A659-4436-4A37-AC5E-0EFF1B66A619}
43 | EndGlobalSection
44 | EndGlobal
45 |
--------------------------------------------------------------------------------
/fake.cmd:
--------------------------------------------------------------------------------
1 | SET TOOL_PATH=.fake
2 |
3 | IF NOT EXIST "%TOOL_PATH%\fake.exe" (
4 | dotnet tool install fake-cli --tool-path ./%TOOL_PATH%
5 | )
6 |
7 | "%TOOL_PATH%/fake.exe" %*
--------------------------------------------------------------------------------
/fake.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -eu
4 | set -o pipefail
5 |
6 | # liberated from https://stackoverflow.com/a/18443300/433393
7 | realpath() {
8 | OURPWD=$PWD
9 | cd "$(dirname "$1")"
10 | LINK=$(readlink "$(basename "$1")")
11 | while [ "$LINK" ]; do
12 | cd "$(dirname "$LINK")"
13 | LINK=$(readlink "$(basename "$1")")
14 | done
15 | REALPATH="$PWD/$(basename "$1")"
16 | cd "$OURPWD"
17 | echo "$REALPATH"
18 | }
19 |
20 | TOOL_PATH=$(realpath .fake)
21 | FAKE="$TOOL_PATH"/fake
22 |
23 | if ! [ -e "$FAKE" ]
24 | then
25 | dotnet tool install fake-cli --tool-path "$TOOL_PATH"
26 | fi
27 | "$FAKE" "$@"
28 |
--------------------------------------------------------------------------------
/paket.dependencies:
--------------------------------------------------------------------------------
1 | source https://www.nuget.org/api/v2
2 | nuget FSharp.Core
3 | nuget FParsec
4 |
5 | // [ FAKE GROUP ]
6 | group Build
7 | storage none
8 | source https://api.nuget.org/v3/index.json
9 | nuget Fake.DotNet.Cli
10 | nuget Fake.IO.FileSystem
11 | nuget Fake.Core.Target
12 |
--------------------------------------------------------------------------------
/src/HastiLang.Core/BaseTypes.fs:
--------------------------------------------------------------------------------
1 | module BaseTypes
2 |
3 | type HstAtomicTypeName = TypeName of string
4 | and HstIdentifier = HstIdentifier of string
5 | and HstUnit = HstUnit of unit
6 |
7 | and HstType =
8 | | TypeAlias of string * HstTypeSig
9 | | RecordType of HstAtomicTypeName * (HstIdentifier * HstType) list
10 | | SumType of (HstAtomicTypeName * HstType) list
11 |
12 | and HstTypeSig =
13 | | Atomic of HstAtomicTypeName
14 | | Chain of HstAtomicTypeName list
15 |
16 | and HstBinding =
17 | { identifier : HstIdentifier
18 | args : HstIdentifier list option
19 | bindingType : HstTypeSig
20 | exps : HstStatement list }
21 |
22 | and HstIfStmt =
23 | { cond : HstExpression
24 | thendo : HstStatement list }
25 |
26 | and HstIfElseStmt =
27 | { cond : HstExpression
28 | thendo: HstStatement list
29 | elsedo : HstStatement list }
30 |
31 | and HstExpression =
32 | | ExpValue of HstValue
33 | | ExpOpCall of HstOperatorCall
34 | | BindingExpr of HstIdentifier
35 |
36 | and HstStatement =
37 | | IfStmt of HstIfStmt
38 | | IfElseStmt of HstIfElseStmt
39 | | TypeDef of HstType
40 | | Binding of HstBinding
41 | | Value of HstValue
42 | | OperatorCall of HstOperatorCall
43 | | PrintStatement of HstExpression
44 | | Loop of HstLoop
45 | | FuncCall of HstFuncCall
46 |
47 | and HstFuncCall =
48 | { id : HstIdentifier
49 | callArgs : HstCallArg list }
50 |
51 | and HstLoop =
52 | { fromIndex : HstNumber
53 | toIndex : HstNumber
54 | boundIdf : HstIdentifier
55 | body : HstStatement list }
56 |
57 | and HstValue =
58 | | Number of HstNumber
59 | | String of HstString
60 | | RecordInstance of HstRecordInstance
61 | | Boolean of HstBoolean
62 | | Unit
63 |
64 | and HstNumber =
65 | | Float of float
66 | | Integer of int
67 |
68 | and HstCallArg =
69 | | CallValue of HstValue
70 | | CallIdf of HstIdentifier
71 |
72 | and HstString = string
73 |
74 | and HstRecordInstance = HstAtomicTypeName * Map
75 |
76 | and HstBoolean = HstTrue | HstFalse
77 |
78 | and HstOperator = Operator of HstString
79 |
80 | and HstOperatorCall =
81 | { op : HstOperator
82 | exp1 : HstExpression
83 | exp2 : HstExpression }
--------------------------------------------------------------------------------
/src/HastiLang.Core/ErrorExtensions.fs:
--------------------------------------------------------------------------------
1 | module ErrorExtensions
2 | open FParsec.Internals
3 | open FParsec
4 |
5 | let rep (a:string) b (text:string) = text.Replace(a, b)
6 |
7 | let toPersian (text:string) =
8 | text
9 | |> rep "The error occured at the end of the line" "خطایی در آخر خط رخ داده است"
10 | |> rep "Expecting:" "انتظار:"
11 | |> rep "Note:" "یادداشت:"
12 | |> rep "Unexpected:" "غیرمنتظره:"
13 | |> rep " or " " یا "
14 | |> rep " and " " و "
15 | |> rep ", " "، "
16 | |> rep " could not be parsed because: " " نتوانست تجزیه شود به دلیل: "
17 | |> rep "The error occurred at the end of the input stream." "خطایی در انتهای ورودی رخ داده است."
18 | |> rep "Error in Ln:" "خطا در خط:"
19 | |> rep "Col:" "ستون:"
20 | |> rep "end of input" "پایان ورودی"
21 | |> rep "or" "یا"
--------------------------------------------------------------------------------
/src/HastiLang.Core/HastiLang.Core.fsproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/HastiLang.Core/HigherPipes.fs:
--------------------------------------------------------------------------------
1 | module HigherPipes
2 |
3 | open FParsec
4 |
5 | let pipe6 p1 p2 p3 p4 p5 p6 f =
6 | pipe4 p1 p2 p3 (tuple3 p4 p5 p6)
7 | (fun x1 x2 x3 (x4, x5, x6) -> f x1 x2 x3 x4 x5 x6)
8 |
9 | let pipe7 p1 p2 p3 p4 p5 p6 p7 f =
10 | pipe4 p1 p2 p3 (tuple4 p4 p5 p6 p7)
11 | (fun x1 x2 x3 (x4, x5, x6, x7) -> f x1 x2 x3 x4 x5 x6 x7)
--------------------------------------------------------------------------------
/src/HastiLang.Core/IdeUtils.fs:
--------------------------------------------------------------------------------
1 | namespace HastiLang.Core.Ide
2 |
3 | open Parsers
4 | open BaseTypes
5 |
6 | module IdeUtils =
7 | open Parsers
8 | let RunParser = Parsers.test
9 |
10 |
11 | module CodeRunner =
12 | open InterpreterStates
13 | open System.Collections.Generic
14 |
15 | let rec eval (expr:HstExpression) (session:Session) =
16 | let inline checkEq a b = if a = b then Ok (Boolean HstTrue) else Ok (Boolean HstFalse)
17 | match expr with
18 | | ExpValue a -> Ok a
19 | | BindingExpr a ->
20 | if session.bindings.ContainsKey a then
21 | let instr = session.bindings.[a].exps |> List.last
22 | match instr with
23 | | Value x -> Ok x
24 | | _ -> Error "خطا در پایان بدنه انقیاد"
25 | else Error "انقیادی با نام مورد نظر وجود نداشت"
26 | | ExpOpCall c ->
27 | match c.op with
28 | | Operator "+" ->
29 | match (eval c.exp1 session, eval c.exp2 session) with
30 | | (Ok (Number j), Ok (Number k)) ->
31 | match (j, k ) with
32 | | (Float m , Float n) -> m + n |> (Float >> Number >> Ok)
33 | | (Integer m, Integer n) -> m + n |> (Integer >> Number >> Ok)
34 | | (Float m, Integer n) -> m + (float n) |> (Float >> Number >> Ok)
35 | | (Integer m, Float n) -> (float m) + n |> (Float >> Number >> Ok)
36 | | (Ok (String s1), Ok (String s2)) -> s1 + s2 |> (String >> Ok)
37 | | _ -> Error "مقدار جمع غیر قابل محاسبه است"
38 |
39 | | Operator "*" ->
40 | match (eval c.exp1 session, eval c.exp2 session ) with
41 | | (Ok (Number j), Ok (Number k)) ->
42 | match (j, k ) with
43 | | (Float m , Float n) -> m * n |> (Float >> Number >> Ok)
44 | | (Integer m, Integer n) -> m * n |> (Integer >> Number >> Ok)
45 | | (Float m, Integer n) -> m * (float n) |> (Float >> Number >> Ok)
46 | | (Integer m, Float n) -> (float m) * n |> (Float >> Number >> Ok)
47 | | Ok (Number j), Ok (String s) | Ok (String s), Ok (Number j) ->
48 | match j with
49 | | Float f -> String.replicate (int f) s |> (String >> Ok)
50 | | Integer i -> String.replicate i s |> (String >> Ok)
51 |
52 | | _ -> Error "مقدار ضرب غیر قابل محاسبه است"
53 |
54 | | Operator "%" ->
55 | match (eval c.exp1 session, eval c.exp2 session ) with
56 | | (Ok (Number j), Ok (Number k)) ->
57 | match (j, k ) with
58 | | (Float m , Float n) -> m % n |> (Float >> Number >> Ok)
59 | | (Integer m, Integer n) -> m % n |> (Integer >> Number >> Ok)
60 | | (Float m, Integer n) -> m % (float n) |> (Float >> Number >> Ok)
61 | | (Integer m, Float n) -> (float m) % n |> (Float >> Number >> Ok)
62 | | _ -> Error "مقدار باقی مانده غیر قابل محاسبه است"
63 |
64 | | Operator "==" ->
65 | match (eval c.exp1 session, eval c.exp2 session) with
66 | | (Ok (Number j), Ok (Number k)) ->
67 | match (j, k ) with
68 | | (Float m , Float n) -> checkEq m n
69 | | (Integer m, Integer n) -> checkEq m n
70 | | (Float m, Integer n) -> Error "نوع صحیح با اعشاری هم خوانی ندارد"
71 | | (Integer m, Float n) -> Error "نوع صحیح با اعشاری هم خوانی ندارد"
72 | | (Ok (String s1), Ok (String s2)) -> checkEq s1 s2
73 | | (Ok (Boolean b1), Ok (Boolean b2)) -> checkEq b1 b2
74 | | _ -> Error "برابری غیر قابل محاسبه است"
75 |
76 | | _ -> Error "اپراتور تعریف نشده"
77 |
78 | let evalBool (expr:HstExpression) (session:Session) =
79 | match eval expr session with
80 | | Ok (Boolean hb) -> match hb with HstTrue -> Ok true | HstFalse -> Ok false
81 | | Error s -> Error (sprintf "%s (باید یک عبارت با نتیجه بولی قرار بگیرد))" s)
82 | | _ -> Error "باید یک عبارت با نتیجه بولی قرار بگیرد"
83 |
84 |
85 | let createSession() =
86 | {
87 | definedTypes = Dictionary()
88 | bindings = Dictionary()
89 | }
90 |
91 | let statementPrint (stmt:HstExpression) session =
92 | match eval stmt session with
93 | | Ok x ->
94 | match x with
95 | | Number x -> x.ToString()
96 | | String x -> x
97 | | Boolean x -> if x = HstTrue then "درست" else "غلط"
98 | | RecordInstance _ -> "نوع:رکورد"
99 | | Unit -> "واحد"
100 | | Error e -> sprintf "خطا در محاسبه (%s)" e
101 |
102 | let rec exec (stmts:HstStatement list) (prints:List) (session:Session) =
103 | for s in stmts do
104 | match s with
105 | | PrintStatement p -> prints.Add (statementPrint p session)
106 | | Binding b -> session.bindings.Add (b.identifier, b)
107 | | IfStmt ifs ->
108 | match evalBool ifs.cond session with
109 | | Ok true -> (exec ifs.thendo prints session) |> ignore
110 | | Error x -> prints.Add x
111 | | _ -> ()
112 | | IfElseStmt ifs ->
113 | match evalBool ifs.cond session with
114 | | Ok true -> (exec ifs.thendo prints session) |> ignore
115 | | Ok false -> (exec ifs.elsedo prints session) |> ignore
116 | | Error x -> prints.Add x
117 | | Loop x -> let lpFunc = loopExecutator x.body prints session x.boundIdf
118 | match (x.fromIndex, x.toIndex) with
119 | | (Integer a, Integer b) -> lpFunc a b
120 | | (Float a, Integer b) -> lpFunc (int a) b
121 | | (Integer a, Float b) -> lpFunc a (int b)
122 | | (Float a, Float b) -> lpFunc (int a) (int b)
123 | | FuncCall f -> let funcBinding = session.bindings.[f.id]
124 | execFunc funcBinding prints session f.callArgs
125 | | _ -> ()
126 |
127 | prints
128 |
129 | and loopExecutator body prints session idf a b =
130 | let hasIdf = session.bindings.ContainsKey idf
131 | let oldBinding = if hasIdf then Some (session.bindings.[idf]) else None
132 | if hasIdf then session.bindings.Remove idf |> ignore
133 | let createValueBinding idf a = { identifier = idf
134 | args = None
135 | bindingType = Atomic (TypeName "عدد")
136 | exps = [a |> (Integer >> Number >> Value)]
137 | }
138 | session.bindings.Add (idf, createValueBinding idf a)
139 | for i = a to b do
140 | let newValue = createValueBinding idf i
141 | session.bindings.[idf] <- newValue
142 | (exec body prints session) |> ignore
143 |
144 | match oldBinding with
145 | | None -> session.bindings.Remove idf |> ignore
146 | | Some x -> session.bindings.[idf] <- x
147 |
148 | and execFunc funcBinding prints session (callArgs:HstCallArg list) =
149 | match funcBinding.args with
150 | | None -> prints.Add "آرگومانی برای اجرای تابع پاس داده نشده بود"
151 | | Some ar when ar.Length <> callArgs.Length -> prints.Add "آزگومان های تابع با تعداد آرگومان های درخواستی مطابقت نداشت. در این نسخه اعمال جزیی پشتیبانی نمیشود"
152 | | Some binds ->
153 | let zipArgsAndIdfs = binds |> List.zip callArgs
154 | let createSessionByCallArgs() =
155 | let bs = Dictionary()
156 | zipArgsAndIdfs |> List.iter (fun (arg, idf) ->
157 | match arg with
158 | | CallValue x -> bs.Add (idf, { identifier = idf
159 | args = None
160 | bindingType = Atomic (TypeName "Dynamic")
161 | exps = [Value x] })
162 | | CallIdf a ->
163 | if session.bindings.ContainsKey a then
164 | let instr = session.bindings.[a].exps |> List.last
165 | match instr with
166 | | Value x -> bs.Add (idf, { identifier = idf
167 | args = None
168 | bindingType = Atomic (TypeName "Dynamic")
169 | exps = [Value x] })
170 | | _ -> prints.Add "خطا در پایان بدنه انقیاد"
171 | else prints.Add "انقیادی با نام مورد نظر وجود نداشت"
172 |
173 | )
174 | { definedTypes = Dictionary()
175 | bindings = bs}
176 |
177 | let tempSession = createSessionByCallArgs()
178 |
179 | exec funcBinding.exps prints tempSession |> ignore
--------------------------------------------------------------------------------
/src/HastiLang.Core/IndentationParser.fs:
--------------------------------------------------------------------------------
1 | module IndentationParserWithBacktracking
2 |
3 | open FParsec
4 | open ParserConfigs
5 |
6 | let skipIndentation (stream: CharStream) =
7 | let mutable indentation = stream.SkipNewlineThenWhitespace(tabStopDistance, false)
8 | while stream.Peek() = '#' do
9 | stream.SkipRestOfLine(false) // skip comment
10 | indentation <- stream.SkipNewlineThenWhitespace(tabStopDistance, false)
11 | indentation
12 |
13 | let indented p : Parser<_> =
14 | fun stream ->
15 | let state = stream.State
16 | let indentation = skipIndentation stream
17 | let expectedIndentation = stream.UserState.Indentation
18 | if indentation < expectedIndentation || stream.IsEndOfStream then
19 | stream.BacktrackTo(state)
20 | Reply(Error, NoErrorMessages)
21 | elif indentation = expectedIndentation then
22 | p stream
23 | else // indentation > expectedIndentation
24 | Reply(Error, messageError "فاصله گذاری نامناسب")
25 |
26 | let indentedBlock p =
27 | Inline.Many(stateFromFirstElement = (fun x -> [x]),
28 | foldState = (fun xs x -> x::xs),
29 | resultFromState = List.rev,
30 | firstElementParser = p,
31 | elementParser = indented p)
32 |
33 | let indentedMany1 (p: Parser<'t>) label : Parser<'t list> =
34 | let indentedBlock = indentedBlock p
35 | fun stream ->
36 | let oldIndentation = stream.UserState.Indentation
37 | let indentation = skipIndentation stream
38 | if indentation <= oldIndentation then
39 | Reply(Error, expected (if indentation < 0 then "خط جدید" else "فاصله " + label))
40 | else
41 | stream.UserState <- {stream.UserState with Indentation = indentation}
42 | let reply = indentedBlock stream
43 | if reply.Status = Ok then
44 | stream.UserState <- {stream.UserState with Indentation = oldIndentation}
45 | reply
--------------------------------------------------------------------------------
/src/HastiLang.Core/InterpreterStates.fs:
--------------------------------------------------------------------------------
1 | module InterpreterStates
2 |
3 | open BaseTypes
4 | open System.Collections.Generic
5 |
6 | type Session = {
7 | definedTypes : Dictionary
8 | bindings : Dictionary
9 | }
10 |
11 |
--------------------------------------------------------------------------------
/src/HastiLang.Core/MSILCompiler.fs:
--------------------------------------------------------------------------------
1 | module MSILCompiler
2 |
3 | /// To be done
--------------------------------------------------------------------------------
/src/HastiLang.Core/ParserConfig.fs:
--------------------------------------------------------------------------------
1 | module ParserConfig
2 | open FParsec
3 |
4 | let tabStopDistance = 8 // must be a power of 2
5 |
6 | module IndentationParserWithBacktracking =
7 | type UserState =
8 | {Indentation: int}
9 | with
10 | static member Create() = {Indentation = -1}
11 |
12 | type CharStream = CharStream
13 | type Parser<'t> = Parser<'t, UserState>
14 |
15 | let skipIndentation (stream: CharStream) =
16 | let mutable indentation = stream.SkipNewlineThenWhitespace(tabStopDistance, false)
17 | while stream.Peek() = '#' do
18 | stream.SkipRestOfLine(false) // skip comment
19 | indentation <- stream.SkipNewlineThenWhitespace(tabStopDistance, false)
20 | indentation
21 |
22 | let indented p : Parser<_> =
23 | fun stream ->
24 | let state = stream.State
25 | let indentation = skipIndentation stream
26 | let expectedIndentation = stream.UserState.Indentation
27 | if indentation < expectedIndentation || stream.IsEndOfStream then
28 | stream.BacktrackTo(state)
29 | Reply(Error, NoErrorMessages)
30 | elif indentation = expectedIndentation then
31 | p stream
32 | else // indentation > expectedIndentation
33 | Reply(Error, messageError "wrong indentation")
34 |
35 | let indentedBlock p =
36 | Inline.Many(stateFromFirstElement = (fun x -> [x]),
37 | foldState = (fun xs x -> x::xs),
38 | resultFromState = List.rev,
39 | firstElementParser = p,
40 | elementParser = indented p)
41 |
42 | let indentedMany1 (p: Parser<'t>) label : Parser<'t list> =
43 | let indentedBlock = indentedBlock p
44 | fun stream ->
45 | let oldIndentation = stream.UserState.Indentation
46 | let indentation = skipIndentation stream
47 | if indentation <= oldIndentation then
48 | Reply(Error, expected (if indentation < 0 then "newline" else "indented " + label))
49 | else
50 | stream.UserState <- {stream.UserState with Indentation = indentation}
51 | let reply = indentedBlock stream
52 | if reply.Status = Ok then
53 | stream.UserState <- {stream.UserState with Indentation = oldIndentation}
54 | reply
55 |
56 | module IndentationParserWithoutBacktracking =
57 | type LastParsedIndentation() =
58 | []
59 | val mutable Value: int32
60 | []
61 | val mutable EndIndex: int64
62 |
63 | type UserState =
64 | {Indentation: int
65 | // We put LastParsedIndentation into the UserState so that we
66 | // can conveniently use a separate instance for each stream.
67 | // The members of the LastParsedIndentation instance will be mutated
68 | // directly and hence won't be affected by any stream backtracking.
69 | LastParsedIndentation: LastParsedIndentation}
70 | with
71 | static member Create() = {Indentation = -1
72 | LastParsedIndentation = LastParsedIndentation(EndIndex = -1L)}
73 |
74 | type CharStream = CharStream
75 | type Parser<'t> = Parser<'t, UserState>
76 |
77 | // If this function is called at the same index in the stream
78 | // where the function previously stopped, then the previously
79 | // returned indentation will be returned again.
80 | // This way we can avoid backtracking at the end of indented blocks.
81 | let skipIndentation (stream: CharStream) =
82 | let lastParsedIndentation = stream.UserState.LastParsedIndentation
83 | if lastParsedIndentation.EndIndex = stream.Index then
84 | lastParsedIndentation.Value
85 | else
86 | let mutable indentation = stream.SkipNewlineThenWhitespace(tabStopDistance, false)
87 | while stream.Peek() = '#' do
88 | stream.SkipRestOfLine(false) // skip comment
89 | indentation <- stream.SkipNewlineThenWhitespace(tabStopDistance, false)
90 | lastParsedIndentation.EndIndex <- stream.Index
91 | lastParsedIndentation.Value <- indentation
92 | indentation
93 |
94 | let indentedMany1 (p: Parser<'t>) label : Parser<'t list> =
95 | fun stream ->
96 | let oldIndentation = stream.UserState.Indentation
97 | let indentation = skipIndentation stream
98 | if indentation <= oldIndentation then
99 | Reply(Error, expected (if indentation < 0 then "newline" else "indented " + label))
100 | else
101 | stream.UserState <- {stream.UserState with Indentation = indentation}
102 | let results = ResizeArray()
103 | let mutable stateTag = stream.StateTag
104 | let mutable reply = p stream // parse the first element
105 | let mutable newIndentation = 0
106 | while reply.Status = Ok
107 | && (results.Add(reply.Result)
108 | newIndentation <- skipIndentation stream
109 | newIndentation = indentation)
110 | do
111 | stateTag <- stream.StateTag
112 | reply <- p stream
113 | if reply.Status = Ok
114 | || (stream.IsEndOfStream && results.Count > 0 && stream.StateTag = stateTag)
115 | then
116 | if newIndentation < indentation || stream.IsEndOfStream then
117 | stream.UserState <- {stream.UserState with Indentation = oldIndentation}
118 | Reply(List.ofSeq results)
119 | else
120 | Reply(Error, messageError "wrong indentation")
121 | else // p failed
122 | Reply(reply.Status, reply.Error)
--------------------------------------------------------------------------------
/src/HastiLang.Core/ParserConfigs.fs:
--------------------------------------------------------------------------------
1 | module ParserConfigs
2 | open FParsec
3 |
4 | let tabStopDistance = 8 // must be a power of 2
5 |
6 |
7 | type IndentationState =
8 | {Indentation: int}
9 | with
10 | static member Create() = {Indentation = -1}
11 |
12 | type CharStream = CharStream
13 | type Parser<'t> = Parser<'t, IndentationState>
14 |
--------------------------------------------------------------------------------
/src/HastiLang.Core/ParserUtils.fs:
--------------------------------------------------------------------------------
1 | module ParserUtils
2 |
3 | open FParsec
4 | open ParserConfigs
5 |
6 | let achoice (ps:Parser<'a, 'u> seq) = choice [for x in ps -> attempt x]
--------------------------------------------------------------------------------
/src/HastiLang.Core/Parsers.fs:
--------------------------------------------------------------------------------
1 | module Parsers
2 | open System
3 | open FParsec
4 | open ErrorExtensions
5 | open BaseTypes
6 |
7 | open ParserConfigs
8 |
9 | module Signs =
10 | let eq = "="
11 | let colon = ":"
12 | let lightArrow = "->"
13 | let oPara = "("
14 | let cPara = ")"
15 |
16 | let availableOpChars = ['+'; '='; '$'; '|'; '>'; '<'; '*'; '/'; '%']
17 |
18 | module ParserAliases =
19 | let str = pstring
20 | let isBlank = fun c -> c = ' ' || c = '\t'
21 | let ws = skipMany1SatisfyL isBlank "فاصله"
22 |
23 |
24 | module SignParsers =
25 | open ParserAliases
26 | open Signs
27 | let peq : Parser<_> = str eq
28 | let sigc : Parser<_> = str ":" .>> ws
29 | let plight : Parser<_> = str lightArrow .>> ws
30 | let poPara : Parser<_> = str oPara
31 | let pcPara : Parser<_> = str cPara
32 |
33 | module Keywords =
34 | let use' = "استفاده"
35 | let type' = "نوع"
36 | let with' = "با"
37 | let if' = "اگه"
38 | let then' = "اونوقت"
39 | let else' = "وگرنه"
40 | let true' = "درست"
41 | let false' = "غلط"
42 |
43 | let from' = "از"
44 | let ta' = "تا"
45 |
46 | let print' = "بنویس"
47 |
48 | let keywords = [
49 | use'; type'; with'; if'; then'; else'; true'; false'; print';
50 | from'; ta';
51 | ]
52 |
53 |
54 | module KeywordParsers =
55 | open ParserAliases
56 | open Keywords
57 | let keyword str = pstring str //>>? nextCharSatisfiesNot (fun c -> isLetter c || isDigit c) > str
58 |
59 | let pkw_use : Parser<_> = keyword use'
60 | let pkw_type : Parser<_> = keyword type'
61 | let pkw_with : Parser<_> = keyword with'
62 | let pkw_if : Parser<_> = keyword if' .>>? ws
63 | let pkw_then : Parser<_> = keyword then'
64 | let pkw_else : Parser<_> = keyword else'
65 |
66 | let pkw_from : Parser<_> = keyword from'
67 | let pkw_ta : Parser<_> = keyword ta'
68 |
69 | let pkw_true : Parser<_> = stringReturn true' HstTrue
70 | let pkw_false : Parser<_> = stringReturn false' HstFalse
71 |
72 | let pkw_print : Parser<_> = keyword print'
73 |
74 | module ReserveParsers =
75 | open Keywords
76 | open ParserAliases
77 | let notReserved : Parser<_> =
78 | let strWs x = str x .>> ws
79 | keywords |> List.map (strWs >> notFollowedBy) |> List.reduce (>>?)
80 |
81 |
82 | let idf = notReserved >>? identifier (IdentifierOptions()) .>> ws > "شناساگر"
83 | let idfn = notReserved >>? identifier (IdentifierOptions()) > "شناساگر"
84 |
85 | module LiteralParsers =
86 | open KeywordParsers
87 | open ParserAliases
88 | open ReserveParsers
89 | /// Parses a string literal
90 | let stringLiteral : Parser<_> =
91 | let normalCharSnippet = many1Satisfy (fun c -> c <> '/' && c <> '"')
92 | let specialChars = anyOf "/نرت\"" > "یکی از کاراکتر های ویژه «ن» یا «ر» یا «ت» انتظار میرفت"
93 | let escapedChar = pstring "/" >>. (specialChars |>> function
94 | | 'ن' -> "\n"
95 | | 'ر' -> "\r"
96 | | 'ت' -> "\t"
97 | | c -> string c) .>> (pstring "/" > "انتهای کاراکتر ویژه باید با «/» تمام شود")
98 | between (pstring "\"") (pstring "\"")
99 | (manyStrings (normalCharSnippet <|> escapedChar)) > "رشته متنی"
100 |
101 | let numLiteral : Parser = (attempt pint32 > "عدد صحیح" |>> Integer) <|>
102 | (attempt pfloat > "عدد اعشاری" |>> Float)
103 |
104 | let precordInstance : Parser<_> = str "رکورد"
105 | let pbool = (attempt pkw_true <|> attempt pkw_false) > "مقدار بولی"
106 |
107 | let punit = stringReturn "()" Unit
108 |
109 | let pliteral : Parser = (attempt stringLiteral |>> String) <|>
110 | (attempt numLiteral |>> Number) <|>
111 | (attempt pbool |>> Boolean) <|>
112 | (attempt punit)
113 |
114 |
115 | let poperator : Parser = many1Satisfy (fun c -> Signs.availableOpChars |> List.contains c) |>> Operator
116 |
117 |
118 | module LanguageConstructParsers =
119 | open SignParsers
120 | open KeywordParsers
121 | open LiteralParsers
122 | open ParserAliases
123 | open BaseTypes
124 | open ReserveParsers
125 | open IndentationParserWithBacktracking
126 | open ParserUtils
127 |
128 | let comment : Parser<_> = pstring "#" >>. skipRestOfLine false
129 | let wsEol = skipManySatisfy isBlank >>. optional comment
130 | let owsEol = optional wsEol
131 | let nl : Parser<_> = newline
132 | let indNewline = indentedMany1 nl "خط بندی جدید"
133 |
134 | let ptypesig : Parser = sepBy1 idf plight |>>
135 | fun x -> if x.Length = 1 then Atomic (TypeName x.[0])
136 | else (x |> List.map TypeName) |> Chain
137 |
138 |
139 |
140 |
141 | let pexpr, pexprRef = createParserForwardedToRef()
142 | let pparaExpr, pparaExprRef = createParserForwardedToRef()
143 | let value = pliteral |>> Value
144 |
145 | let valueExpr = pliteral |>> ExpValue
146 |
147 | let bindingExpr = idfn |>> (HstIdentifier >> BindingExpr)
148 |
149 | let valOrBindExpr = attempt valueExpr <|> attempt bindingExpr
150 |
151 | let opCall =
152 | pipe3 (valOrBindExpr .>>? ws)
153 | (poperator .>>? ws)
154 | (pexpr)
155 |
156 | (fun exp1 op exp2 -> { op = op; exp1 = exp1; exp2 = exp2})
157 |
158 | let opCallExpr = opCall |>> ExpOpCall
159 |
160 | let paraOpCallExpr = poPara >>? opCallExpr .>>? pcPara
161 |
162 | do pexprRef := achoice [
163 | paraOpCallExpr
164 | opCallExpr
165 | valueExpr
166 | bindingExpr
167 | ]
168 |
169 | let pstatement, pstatementRef = createParserForwardedToRef()
170 | let indentedStatements, indentedStatementsRef = createParserForwardedToRef()
171 |
172 |
173 |
174 | let ifStmt =
175 | pipe2 (pkw_if >>? pexpr .>>? ws .>>? pkw_then .>>? wsEol)
176 | (indentedStatements .>>? wsEol)
177 |
178 | (fun cond thn -> IfStmt { cond = cond; thendo = thn }) > "عبارت شرطی"
179 |
180 | let ifStmtInline =
181 | pipe2 (pkw_if >>? pexpr)
182 | (ws >>? pkw_then >>? ws >>? pstatement)
183 |
184 | (fun cond thn -> IfStmt { cond = cond; thendo = [thn] }) > "عبارت شرطی"
185 |
186 | let ifElseStmt =
187 | pipe3 (pkw_if >>? pexpr .>>? ws .>>? pkw_then .>>? wsEol)
188 | (indentedStatements .>>? wsEol)
189 | (indented pkw_else >>? indentedStatements .>>? wsEol)
190 |
191 | (fun cond thn els -> IfElseStmt { cond = cond; thendo = thn; elsedo = els }) > "عبارت شرطی"
192 |
193 | let ifElseStmtInline =
194 | pipe3 (pkw_if >>? pexpr)
195 | (ws >>? pkw_then >>? ws >>? pstatement)
196 | (ws >>? pkw_else >>? ws >>? pstatement)
197 |
198 | (fun cond thn els -> IfElseStmt { cond = cond; thendo = [thn]; elsedo = [els] }) > "عبارت شرطی"
199 |
200 | let binding =
201 | pipe3 (many1 idf .>>? sigc)
202 | (ptypesig .>>? peq .>>? wsEol)
203 | (indentedStatements)
204 |
205 | (fun id tsig body -> Binding {
206 | identifier = HstIdentifier id.[0]
207 | args = if id.Length > 1 then Some (id.[1..] |> List.map HstIdentifier) else None
208 | bindingType = tsig
209 | exps = body
210 | })
211 |
212 | let basicBinding =
213 | pipe3 (many1 idf .>>? sigc)
214 | (ptypesig .>>? peq .>>? ws)
215 | (pstatement .>>? wsEol)
216 |
217 | (fun id tsig stmt -> Binding {
218 | identifier = HstIdentifier id.[0]
219 | args = if id.Length > 1 then Some (id.[1..] |> List.map HstIdentifier) else None
220 | bindingType = tsig
221 | exps = [stmt]
222 | })
223 |
224 | let ploop =
225 | pipe4 (pkw_from >>? ws >>? idf .>>? peq .>>? ws)
226 | (numLiteral .>>? ws)
227 | (pkw_ta >>? ws >>? numLiteral .>>? ws .>>? pkw_then .>>? wsEol)
228 | (indentedStatements .>>? wsEol)
229 |
230 | (fun idf from' to' body -> { boundIdf = HstIdentifier idf; fromIndex = from'; toIndex = to'; body = body }) |>> Loop
231 |
232 | let ploopInline =
233 | pipe4 (pkw_from >>? ws >>? idf .>>? peq .>>? ws)
234 | (numLiteral .>>? ws)
235 | (pkw_ta >>? ws >>? numLiteral .>>? ws .>>? pkw_then .>>? ws)
236 | (pstatement)
237 |
238 | (fun idf from' to' stmt -> { boundIdf = HstIdentifier idf ; fromIndex = from'; toIndex = to'; body = [stmt] }) |>> Loop
239 |
240 |
241 | let typedef =
242 | pipe2 (idf .>>? sigc)
243 | pkw_type
244 |
245 | (fun id _ -> TypeAlias (id, (TypeName "x") |> Atomic) |> TypeDef)
246 |
247 | let pcallArg = attempt (pliteral |>> CallValue) <|> attempt (idfn |>> (HstIdentifier >> CallIdf))
248 |
249 | let funcCall =
250 | pipe2 idfn
251 | (many1 (ws >>? pcallArg))
252 |
253 | (fun idf callArgs -> { id = HstIdentifier idf; callArgs = callArgs }) |>> FuncCall
254 |
255 | let printStmt = (pkw_print >>? ws >>? pexpr) |>> PrintStatement
256 |
257 | do pstatementRef := achoice [
258 | ifElseStmt
259 | ifElseStmtInline
260 | ifStmt
261 | ifStmtInline
262 | value
263 | typedef
264 | binding
265 | basicBinding
266 | printStmt
267 | ploop
268 | ploopInline
269 | funcCall
270 | ]
271 |
272 | do indentedStatementsRef := indentedMany1 pstatement "عبارت"
273 |
274 | let parastatement = optional poPara >>? pstatement .>>? optional pcPara
275 |
276 |
277 | let document = indentedStatements .>> spaces .>> eof
278 |
279 | open FParsec.Error
280 |
281 | let longestMathRuleSplit (err:string) =
282 | err.Split([|"The parser backtracked after:"|], StringSplitOptions.None)
283 | |> Array.last
284 |
285 | type CompilerAnswer() = class end
286 |
287 | type CompilerSuccess(result) =
288 | inherit CompilerAnswer()
289 | member __.Result : HstStatement list = result
290 |
291 | type CompilerFailure(result:string) =
292 | inherit CompilerAnswer()
293 | member __.Error = result
294 |
295 | let test str =
296 | match runParserOnString LanguageConstructParsers.document (IndentationState.Create()) "" (str) with
297 | | Success(result, _, _) -> CompilerSuccess result :> CompilerAnswer
298 | | Failure(errorMsg, err, _) -> CompilerFailure (errorMsg |> toPersian |> longestMathRuleSplit) :> CompilerAnswer
299 |
300 |
--------------------------------------------------------------------------------
/src/HastiLang.Core/paket.references:
--------------------------------------------------------------------------------
1 | FSharp.Core
2 | FParsec
--------------------------------------------------------------------------------