1
0
gretmn102 3 жил өмнө
parent
commit
2ce0908e4a

+ 164 - 14
.gitignore

@@ -1,8 +1,146 @@
+# Created by https://www.gitignore.io/api/f#,linux,windows,macos,vim,emacs,visualstudio,visualstudiocode
+
+### F# ###
+lib/debug
+lib/release
+Debug
+*.suo
+*.user
+obj
+bin
+*.exe
+!/.paket/paket.bootstrapper.exe
+
+
+### Linux ###
+*~
+
+# temporary files which can be created if a process still has a handle open of a deleted file
+.fuse_hidden*
+
+# KDE directory preferences
+.directory
+
+# Linux trash folder which might appear on any partition or disk
+.Trash-*
+
+
+### Windows ###
+# Windows image file caches
+Thumbs.db
+ehthumbs.db
+
+# Folder config file
+Desktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Windows Installer files
+*.cab
+*.msi
+*.msm
+*.msp
+
+# Windows shortcuts
+*.lnk
+
+
+### macOS ###
+*.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+.com.apple.timemachine.donotpresent
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
+
+
+### Vim ###
+# swap
+[._]*.s[a-w][a-z]
+[._]s[a-w][a-z]
+# session
+Session.vim
+# temporary
+.netrwhist
+*~
+# auto-generated tag files
+tags
+
+
+### Emacs ###
+# -*- mode: gitignore; -*-
+*~
+\#*\#
+/.emacs.desktop
+/.emacs.desktop.lock
+*.elc
+auto-save-list
+tramp
+.\#*
+
+# Org-mode
+.org-id-locations
+*_archive
+
+# flymake-mode
+*_flymake.*
+
+# eshell files
+/eshell/history
+/eshell/lastdir
+
+# elpa packages
+/elpa/
+
+# reftex files
+*.rel
+
+# AUCTeX auto folder
+/auto/
+
+# cask packages
+.cask/
+dist/
+
+# Flycheck
+flycheck_*.el
+
+# server auth directory
+/server/
+
+# projectiles files
+.projectile
+
+### VisualStudioCode ###
+.vscode
+
+
+
+### VisualStudio ###
 ## Ignore Visual Studio temporary files, build results, and
 ## files generated by popular Visual Studio add-ons.
 
-QSParser.fsyacc.output
-
 # User-specific files
 *.suo
 *.user
@@ -20,7 +158,8 @@ QSParser.fsyacc.output
 x64/
 x86/
 bld/
-[Bb]in/s
+build/
+[Bb]in/
 [Oo]bj/
 [Ll]og/
 
@@ -44,6 +183,7 @@ dlldata.c
 
 # DNX
 project.lock.json
+project.fragment.lock.json
 artifacts/
 
 *_i.c
@@ -82,6 +222,8 @@ ipch/
 *.opensdf
 *.sdf
 *.cachefile
+*.VC.db
+*.VC.VC.opendb
 
 # Visual Studio profiler
 *.psess
@@ -140,17 +282,20 @@ publish/
 # Publish Web Output
 *.[Pp]ublish.xml
 *.azurePubxml
-# TODO: Comment the next line if you want to checkin your web deploy settings 
+# TODO: Comment the next line if you want to checkin your web deploy settings
 # but database connection strings (with potential passwords) will be unencrypted
 *.pubxml
 *.publishproj
 
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
 # NuGet Packages
 *.nupkg
 # The packages folder can be ignored because of Package Restore
 **/packages/*
-# except build/, which is used as an MSBuild target.
-!**/packages/build/
 # Uncomment if necessary however generally it will be regenerated when needed
 #!**/packages/repositories.config
 # NuGet v3's project.json files produces more ignoreable files
@@ -165,12 +310,11 @@ csx/
 ecf/
 rcf/
 
-# Microsoft Azure ApplicationInsights config file
-ApplicationInsights.config
-
-# Windows Store app package directory
+# Windows Store app package directories and files
 AppPackages/
 BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
 
 # Visual Studio cache files
 # files ending in .cache can be ignored
@@ -189,6 +333,10 @@ ClientBin/
 node_modules/
 orleans.codegen.cs
 
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+
 # RIA/Silverlight projects
 Generated_Code/
 
@@ -234,12 +382,14 @@ _Pvt_Extensions
 
 # Paket dependency manager
 .paket/paket.exe
+paket-files/
 
 # FAKE - F# Make
 .fake/
 
-/.ionide/
+# JetBrains Rider
+.idea/
+*.sln.iml
 
-/QSParse/QSLexer.fs
-/QSParse/QSParser.fs
-/QSParse/QSParser.fsi
+/Output/
+/.ionide/

+ 494 - 0
.paket/Paket.Restore.targets

@@ -0,0 +1,494 @@
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <!-- Prevent dotnet template engine to parse this file -->
+  <!--/-:cnd:noEmit-->
+  <PropertyGroup>
+    <!-- make MSBuild track this file for incremental builds. -->
+    <!-- ref https://blogs.msdn.microsoft.com/msbuild/2005/09/26/how-to-ensure-changes-to-a-custom-target-file-prompt-a-rebuild/ -->
+    <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
+
+    <DetectedMSBuildVersion>$(MSBuildVersion)</DetectedMSBuildVersion>
+    <DetectedMSBuildVersion Condition="'$(MSBuildVersion)' == ''">15.0.0</DetectedMSBuildVersion>
+    <MSBuildSupportsHashing>false</MSBuildSupportsHashing>
+    <MSBuildSupportsHashing Condition=" '$(DetectedMSBuildVersion)' &gt; '15.8.0' ">true</MSBuildSupportsHashing>
+    <!-- Mark that this target file has been loaded.  -->
+    <IsPaketRestoreTargetsFileLoaded>true</IsPaketRestoreTargetsFileLoaded>
+    <PaketToolsPath>$(MSBuildThisFileDirectory)</PaketToolsPath>
+    <PaketRootPath>$(MSBuildThisFileDirectory)..\</PaketRootPath>
+    <PaketRestoreCacheFile>$(PaketRootPath)paket-files\paket.restore.cached</PaketRestoreCacheFile>
+    <PaketLockFilePath>$(PaketRootPath)paket.lock</PaketLockFilePath>
+    <PaketBootstrapperStyle>classic</PaketBootstrapperStyle>
+    <PaketBootstrapperStyle Condition="Exists('$(PaketToolsPath)paket.bootstrapper.proj')">proj</PaketBootstrapperStyle>
+    <PaketExeImage>assembly</PaketExeImage>
+    <PaketExeImage Condition=" '$(PaketBootstrapperStyle)' == 'proj' ">native</PaketExeImage>
+    <MonoPath Condition="'$(MonoPath)' == '' AND Exists('/Library/Frameworks/Mono.framework/Commands/mono')">/Library/Frameworks/Mono.framework/Commands/mono</MonoPath>
+    <MonoPath Condition="'$(MonoPath)' == ''">mono</MonoPath>
+
+    <!-- PaketBootStrapper  -->
+    <PaketBootStrapperExePath Condition=" '$(PaketBootStrapperExePath)' == '' AND Exists('$(PaketRootPath)paket.bootstrapper.exe')">$(PaketRootPath)paket.bootstrapper.exe</PaketBootStrapperExePath>
+    <PaketBootStrapperExePath Condition=" '$(PaketBootStrapperExePath)' == '' ">$(PaketToolsPath)paket.bootstrapper.exe</PaketBootStrapperExePath>
+    <PaketBootStrapperExeDir Condition=" Exists('$(PaketBootStrapperExePath)') " >$([System.IO.Path]::GetDirectoryName("$(PaketBootStrapperExePath)"))\</PaketBootStrapperExeDir>
+
+    <PaketBootStrapperCommand Condition=" '$(OS)' == 'Windows_NT' ">"$(PaketBootStrapperExePath)"</PaketBootStrapperCommand>
+    <PaketBootStrapperCommand Condition=" '$(OS)' != 'Windows_NT' ">$(MonoPath) --runtime=v4.0.30319 "$(PaketBootStrapperExePath)"</PaketBootStrapperCommand>
+
+    <!-- Disable automagic references for F# DotNet SDK -->
+    <!-- This will not do anything for other project types -->
+    <!-- see https://github.com/fsharp/fslang-design/blob/master/tooling/FST-1002-fsharp-in-dotnet-sdk.md -->
+    <DisableImplicitFSharpCoreReference>true</DisableImplicitFSharpCoreReference>
+    <DisableImplicitSystemValueTupleReference>true</DisableImplicitSystemValueTupleReference>
+
+    <!-- Disable Paket restore under NCrunch build -->
+    <PaketRestoreDisabled Condition="'$(NCrunch)' == '1'">True</PaketRestoreDisabled>
+
+    <!-- Disable test for CLI tool completely - overrideable via properties in projects or via environment variables -->
+    <PaketDisableCliTest Condition=" '$(PaketDisableCliTest)' == '' ">False</PaketDisableCliTest>
+
+    <PaketIntermediateOutputPath Condition=" '$(PaketIntermediateOutputPath)' == '' ">$(BaseIntermediateOutputPath.TrimEnd('\').TrimEnd('\/'))</PaketIntermediateOutputPath>
+  </PropertyGroup>
+
+  <!-- Resolve how paket should be called -->
+  <!-- Current priority is: local (1: repo root, 2: .paket folder) => 3: as CLI tool => as bootstrapper (4: proj Bootstrapper style, 5: BootstrapperExeDir) => 6: global path variable -->
+  <Target Name="SetPaketCommand" >
+    <!-- Test if paket is available in the standard locations. If so, that takes priority. Case 1/2 - non-windows specific -->
+    <PropertyGroup Condition=" '$(OS)' != 'Windows_NT' ">
+      <!-- no windows, try native paket as default, root => tool -->
+      <PaketExePath Condition=" '$(PaketExePath)' == '' AND Exists('$(PaketRootPath)paket') ">$(PaketRootPath)paket</PaketExePath>
+      <PaketExePath Condition=" '$(PaketExePath)' == '' AND Exists('$(PaketToolsPath)paket') ">$(PaketToolsPath)paket</PaketExePath>
+    </PropertyGroup>
+
+    <!-- Test if paket is available in the standard locations. If so, that takes priority. Case 2/2 - same across platforms -->
+    <PropertyGroup>
+      <!-- root => tool -->
+      <PaketExePath Condition=" '$(PaketExePath)' == '' AND Exists('$(PaketRootPath)paket.exe') ">$(PaketRootPath)paket.exe</PaketExePath>
+      <PaketExePath Condition=" '$(PaketExePath)' == '' AND Exists('$(PaketToolsPath)paket.exe') ">$(PaketToolsPath)paket.exe</PaketExePath>
+    </PropertyGroup>
+
+    <!-- If paket hasn't be found in standard locations, test for CLI tool usage. -->
+    <!-- First test: Is CLI configured to be used in "dotnet-tools.json"? - can result in a false negative; only a positive outcome is reliable. -->
+    <PropertyGroup Condition=" '$(PaketExePath)' == '' ">
+      <_DotnetToolsJson Condition="Exists('$(PaketRootPath)/.config/dotnet-tools.json')">$([System.IO.File]::ReadAllText("$(PaketRootPath)/.config/dotnet-tools.json"))</_DotnetToolsJson>
+      <_ConfigContainsPaket Condition=" '$(_DotnetToolsJson)' != ''">$(_DotnetToolsJson.Contains('"paket"'))</_ConfigContainsPaket>
+      <_ConfigContainsPaket Condition=" '$(_ConfigContainsPaket)' == ''">false</_ConfigContainsPaket>
+    </PropertyGroup>
+
+    <!-- Second test: Call 'dotnet paket' and see if it returns without an error. Mute all the output. Only run if previous test failed and the test has not been disabled. -->
+    <!-- WARNING: This method can lead to processes hanging forever, and should be used as little as possible. See https://github.com/fsprojects/Paket/issues/3705 for details. -->
+    <Exec Condition=" '$(PaketExePath)' == '' AND !$(PaketDisableCliTest) AND !$(_ConfigContainsPaket)" Command="dotnet paket --version" IgnoreExitCode="true" StandardOutputImportance="low" StandardErrorImportance="low" >
+      <Output TaskParameter="ExitCode" PropertyName="LocalPaketToolExitCode" />
+    </Exec>
+
+    <!-- If paket is installed as CLI use that. Again, only if paket haven't already been found in standard locations. -->
+    <PropertyGroup Condition=" '$(PaketExePath)' == '' AND ($(_ConfigContainsPaket) OR '$(LocalPaketToolExitCode)' == '0') ">
+      <_PaketCommand>dotnet paket</_PaketCommand>
+    </PropertyGroup>
+
+    <!-- If neither local files nor CLI tool can be found, final attempt is searching for boostrapper config before falling back to global path variable. -->
+    <PropertyGroup Condition=" '$(PaketExePath)' == '' AND '$(_PaketCommand)' == '' ">
+      <!-- Test for bootstrapper setup -->
+      <PaketExePath Condition=" '$(PaketExePath)' == '' AND '$(PaketBootstrapperStyle)' == 'proj' ">$(PaketToolsPath)paket</PaketExePath>
+      <PaketExePath Condition=" '$(PaketExePath)' == '' AND Exists('$(PaketBootStrapperExeDir)') ">$(PaketBootStrapperExeDir)paket</PaketExePath>
+
+      <!-- If all else fails, use global path approach. -->
+      <PaketExePath Condition=" '$(PaketExePath)' == ''">paket</PaketExePath>
+    </PropertyGroup>
+
+    <!-- If not using CLI, setup correct execution command. -->
+    <PropertyGroup Condition=" '$(_PaketCommand)' == '' ">
+      <_PaketExeExtension>$([System.IO.Path]::GetExtension("$(PaketExePath)"))</_PaketExeExtension>
+      <_PaketCommand Condition=" '$(_PaketCommand)' == '' AND '$(_PaketExeExtension)' == '.dll' ">dotnet "$(PaketExePath)"</_PaketCommand>
+      <_PaketCommand Condition=" '$(_PaketCommand)' == '' AND '$(OS)' != 'Windows_NT' AND '$(_PaketExeExtension)' == '.exe' ">$(MonoPath) --runtime=v4.0.30319 "$(PaketExePath)"</_PaketCommand>
+      <_PaketCommand Condition=" '$(_PaketCommand)' == '' ">"$(PaketExePath)"</_PaketCommand>
+    </PropertyGroup>
+
+    <!-- The way to get a property to be available outside the target is to use this task. -->
+    <CreateProperty Value="$(_PaketCommand)">
+      <Output TaskParameter="Value" PropertyName="PaketCommand"/>
+    </CreateProperty>
+
+  </Target>
+
+  <Target Name="PaketBootstrapping" Condition="Exists('$(PaketToolsPath)paket.bootstrapper.proj')">
+    <MSBuild Projects="$(PaketToolsPath)paket.bootstrapper.proj" Targets="Restore" />
+  </Target>
+
+  <!-- Official workaround for https://docs.microsoft.com/en-us/visualstudio/msbuild/getfilehash-task?view=vs-2019 -->
+  <UsingTask TaskName="Microsoft.Build.Tasks.GetFileHash" AssemblyName="Microsoft.Build.Tasks.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" Condition=" '$(MSBuildSupportsHashing)' == 'true' And '$(DetectedMSBuildVersion)' &lt; '16.0.360' " />
+  <UsingTask TaskName="Microsoft.Build.Tasks.VerifyFileHash" AssemblyName="Microsoft.Build.Tasks.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" Condition=" '$(MSBuildSupportsHashing)' == 'true' And '$(DetectedMSBuildVersion)' &lt; '16.0.360' " />
+  <Target Name="PaketRestore" Condition="'$(PaketRestoreDisabled)' != 'True'" BeforeTargets="_GenerateDotnetCliToolReferenceSpecs;_GenerateProjectRestoreGraphPerFramework;_GenerateRestoreGraphWalkPerFramework;CollectPackageReferences" DependsOnTargets="SetPaketCommand;PaketBootstrapping">
+
+    <!-- Step 1 Check if lockfile is properly restored (if the hash of the lockfile and the cache-file match) -->
+    <PropertyGroup>
+      <PaketRestoreRequired>true</PaketRestoreRequired>
+      <NoWarn>$(NoWarn);NU1603;NU1604;NU1605;NU1608</NoWarn>
+      <CacheFilesExist>false</CacheFilesExist>
+      <CacheFilesExist Condition=" Exists('$(PaketRestoreCacheFile)') And Exists('$(PaketLockFilePath)') ">true</CacheFilesExist>
+    </PropertyGroup>
+
+    <!-- Read the hash of the lockfile -->
+    <GetFileHash Condition=" '$(MSBuildSupportsHashing)' == 'true' And '$(CacheFilesExist)' == 'true' " Files="$(PaketLockFilePath)" Algorithm="SHA256" HashEncoding="hex" >
+      <Output TaskParameter="Hash" PropertyName="PaketRestoreLockFileHash" />
+    </GetFileHash>
+    <!-- Read the hash of the cache, which is json, but a very simple key value object -->
+    <PropertyGroup Condition=" '$(MSBuildSupportsHashing)' == 'true' And '$(CacheFilesExist)' == 'true' ">
+        <PaketRestoreCachedContents>$([System.IO.File]::ReadAllText('$(PaketRestoreCacheFile)'))</PaketRestoreCachedContents>
+    </PropertyGroup>
+    <ItemGroup Condition=" '$(MSBuildSupportsHashing)' == 'true' And '$(CacheFilesExist)' == 'true' ">
+        <!-- Parse our simple 'paket.restore.cached' json ...-->
+        <PaketRestoreCachedSplitObject Include="$([System.Text.RegularExpressions.Regex]::Split(`$(PaketRestoreCachedContents)`, `{|}|,`))"></PaketRestoreCachedSplitObject>
+        <!-- Keep Key, Value ItemGroup-->
+        <PaketRestoreCachedKeyValue Include="@(PaketRestoreCachedSplitObject)"
+            Condition=" $([System.Text.RegularExpressions.Regex]::Split(`%(Identity)`, `&quot;: &quot;`).Length) &gt; 1 ">
+          <Key>$([System.Text.RegularExpressions.Regex]::Split(`%(Identity)`, `": "`)[0].Replace(`"`, ``).Replace(` `, ``))</Key>
+          <Value>$([System.Text.RegularExpressions.Regex]::Split(`%(Identity)`, `": "`)[1].Replace(`"`, ``).Replace(` `, ``))</Value>
+        </PaketRestoreCachedKeyValue>
+    </ItemGroup>
+    <PropertyGroup Condition=" '$(MSBuildSupportsHashing)' == 'true' And '$(CacheFilesExist)' == 'true' ">
+        <!-- Retrieve the hashes we are interested in -->
+        <PackagesDownloadedHash Condition=" '%(PaketRestoreCachedKeyValue.Key)' == 'packagesDownloadedHash' ">%(PaketRestoreCachedKeyValue.Value)</PackagesDownloadedHash>
+        <ProjectsRestoredHash Condition=" '%(PaketRestoreCachedKeyValue.Key)' == 'projectsRestoredHash' ">%(PaketRestoreCachedKeyValue.Value)</ProjectsRestoredHash>
+    </PropertyGroup>
+
+    <PropertyGroup Condition=" '$(MSBuildSupportsHashing)' == 'true' And '$(CacheFilesExist)' == 'true' ">
+      <!-- If the restore file doesn't exist we need to restore, otherwise only if hashes don't match -->
+      <PaketRestoreRequired>true</PaketRestoreRequired>
+      <PaketRestoreRequired Condition=" '$(PaketRestoreLockFileHash)' == '$(ProjectsRestoredHash)' ">false</PaketRestoreRequired>
+      <PaketRestoreRequired Condition=" '$(PaketRestoreLockFileHash)' == '' ">true</PaketRestoreRequired>
+    </PropertyGroup>
+
+	<!--
+		This value should match the version in the props generated by paket
+		If they differ, this means we need to do a restore in order to ensure correct dependencies
+	-->
+    <PropertyGroup Condition="'$(PaketPropsVersion)' != '5.185.3' ">
+      <PaketRestoreRequired>true</PaketRestoreRequired>
+    </PropertyGroup>
+
+    <!-- Do a global restore if required -->
+    <Warning Text="This version of MSBuild (we assume '$(DetectedMSBuildVersion)' or older) doesn't support GetFileHash, so paket fast restore is disabled." Condition=" '$(MSBuildSupportsHashing)' != 'true' " />
+    <Error Text="Stop build because of PAKET_ERROR_ON_MSBUILD_EXEC and we always call the bootstrapper" Condition=" '$(PAKET_ERROR_ON_MSBUILD_EXEC)' == 'true' AND '$(PaketBootstrapperStyle)' == 'classic' AND Exists('$(PaketBootStrapperExePath)') AND !(Exists('$(PaketExePath)'))" />
+    <Exec Command='$(PaketBootStrapperCommand)' Condition=" '$(PaketBootstrapperStyle)' == 'classic' AND Exists('$(PaketBootStrapperExePath)') AND !(Exists('$(PaketExePath)'))" ContinueOnError="false" />
+    <Error Text="Stop build because of PAKET_ERROR_ON_MSBUILD_EXEC and we need a full restore (hashes don't match)" Condition=" '$(PAKET_ERROR_ON_MSBUILD_EXEC)' == 'true' AND '$(PaketRestoreRequired)' == 'true' AND '$(PaketDisableGlobalRestore)' != 'true'" />
+    <Exec Command='$(PaketCommand) restore' Condition=" '$(PaketRestoreRequired)' == 'true' AND '$(PaketDisableGlobalRestore)' != 'true' " ContinueOnError="false" />
+
+    <!-- Step 2 Detect project specific changes -->
+    <ItemGroup>
+      <MyTargetFrameworks Condition="'$(TargetFramework)' != '' " Include="$(TargetFramework)"></MyTargetFrameworks>
+      <!-- Don't include all frameworks when msbuild explicitly asks for a single one -->
+      <MyTargetFrameworks Condition="'$(TargetFrameworks)' != '' AND '$(TargetFramework)' == '' " Include="$(TargetFrameworks)"></MyTargetFrameworks>
+      <PaketResolvedFilePaths Include="@(MyTargetFrameworks -> '$(PaketIntermediateOutputPath)\$(MSBuildProjectFile).%(Identity).paket.resolved')"></PaketResolvedFilePaths>
+    </ItemGroup>
+
+    <PropertyGroup>
+      <PaketReferencesCachedFilePath>$(PaketIntermediateOutputPath)\$(MSBuildProjectFile).paket.references.cached</PaketReferencesCachedFilePath>
+      <!-- MyProject.fsproj.paket.references has the highest precedence -->
+      <PaketOriginalReferencesFilePath>$(MSBuildProjectFullPath).paket.references</PaketOriginalReferencesFilePath>
+      <!-- MyProject.paket.references -->
+      <PaketOriginalReferencesFilePath Condition=" !Exists('$(PaketOriginalReferencesFilePath)')">$(MSBuildProjectDirectory)\$(MSBuildProjectName).paket.references</PaketOriginalReferencesFilePath>
+      <!-- paket.references -->
+      <PaketOriginalReferencesFilePath Condition=" !Exists('$(PaketOriginalReferencesFilePath)')">$(MSBuildProjectDirectory)\paket.references</PaketOriginalReferencesFilePath>
+
+      <DoAllResolvedFilesExist>false</DoAllResolvedFilesExist>
+      <DoAllResolvedFilesExist Condition="Exists(%(PaketResolvedFilePaths.Identity))">true</DoAllResolvedFilesExist>
+      <PaketRestoreRequired>true</PaketRestoreRequired>
+      <PaketRestoreRequiredReason>references-file-or-cache-not-found</PaketRestoreRequiredReason>
+    </PropertyGroup>
+
+    <!-- Step 2 a Detect changes in references file -->
+    <PropertyGroup Condition="Exists('$(PaketOriginalReferencesFilePath)') AND Exists('$(PaketReferencesCachedFilePath)') ">
+      <PaketRestoreCachedHash>$([System.IO.File]::ReadAllText('$(PaketReferencesCachedFilePath)'))</PaketRestoreCachedHash>
+      <PaketRestoreReferencesFileHash>$([System.IO.File]::ReadAllText('$(PaketOriginalReferencesFilePath)'))</PaketRestoreReferencesFileHash>
+      <PaketRestoreRequiredReason>references-file</PaketRestoreRequiredReason>
+      <PaketRestoreRequired Condition=" '$(PaketRestoreReferencesFileHash)' == '$(PaketRestoreCachedHash)' ">false</PaketRestoreRequired>
+    </PropertyGroup>
+
+    <PropertyGroup Condition="!Exists('$(PaketOriginalReferencesFilePath)') AND !Exists('$(PaketReferencesCachedFilePath)') ">
+      <!-- If both don't exist there is nothing to do. -->
+      <PaketRestoreRequired>false</PaketRestoreRequired>
+    </PropertyGroup>
+
+    <!-- Step 2 b detect relevant changes in project file (new targetframework) -->
+    <PropertyGroup Condition=" '$(DoAllResolvedFilesExist)' != 'true' ">
+      <PaketRestoreRequired>true</PaketRestoreRequired>
+      <PaketRestoreRequiredReason>target-framework '$(TargetFramework)' or '$(TargetFrameworks)' files @(PaketResolvedFilePaths)</PaketRestoreRequiredReason>
+    </PropertyGroup>
+
+    <!-- Step 3 Restore project specific stuff if required -->
+    <Message Condition=" '$(PaketRestoreRequired)' == 'true' " Importance="low" Text="Detected a change ('$(PaketRestoreRequiredReason)') in the project file '$(MSBuildProjectFullPath)', calling paket restore" />
+    <Error Text="Stop build because of PAKET_ERROR_ON_MSBUILD_EXEC and we detected a change ('$(PaketRestoreRequiredReason)') in the project file '$(MSBuildProjectFullPath)'" Condition=" '$(PAKET_ERROR_ON_MSBUILD_EXEC)' == 'true' AND '$(PaketRestoreRequired)' == 'true' " />
+    <Exec Command='$(PaketCommand) restore --project "$(MSBuildProjectFullPath)" --output-path "$(PaketIntermediateOutputPath)" --target-framework "$(TargetFrameworks)"' Condition=" '$(PaketRestoreRequired)' == 'true' AND '$(TargetFramework)' == '' " ContinueOnError="false" />
+    <Exec Command='$(PaketCommand) restore --project "$(MSBuildProjectFullPath)" --output-path "$(PaketIntermediateOutputPath)" --target-framework "$(TargetFramework)"' Condition=" '$(PaketRestoreRequired)' == 'true' AND '$(TargetFramework)' != '' " ContinueOnError="false" />
+
+    <!-- This shouldn't actually happen, but just to be sure. -->
+    <PropertyGroup>
+      <DoAllResolvedFilesExist>false</DoAllResolvedFilesExist>
+      <DoAllResolvedFilesExist Condition="Exists(%(PaketResolvedFilePaths.Identity))">true</DoAllResolvedFilesExist>
+    </PropertyGroup>
+    <Error Condition=" '$(DoAllResolvedFilesExist)' != 'true' AND '$(ResolveNuGetPackages)' != 'False' " Text="One Paket file '@(PaketResolvedFilePaths)' is missing while restoring $(MSBuildProjectFile). Please delete 'paket-files/paket.restore.cached' and call 'paket restore'." />
+
+    <!-- Step 4 forward all msbuild properties (PackageReference, DotNetCliToolReference) to msbuild -->
+    <ReadLinesFromFile Condition="($(DesignTimeBuild) != true OR '$(PaketPropsLoaded)' != 'true') AND '@(PaketResolvedFilePaths)' != ''" File="%(PaketResolvedFilePaths.Identity)" >
+      <Output TaskParameter="Lines" ItemName="PaketReferencesFileLines"/>
+    </ReadLinesFromFile>
+
+    <ItemGroup Condition="($(DesignTimeBuild) != true OR '$(PaketPropsLoaded)' != 'true') AND '@(PaketReferencesFileLines)' != '' " >
+      <PaketReferencesFileLinesInfo Include="@(PaketReferencesFileLines)" >
+        <Splits>$([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',').Length)</Splits>
+        <PackageName>$([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[0])</PackageName>
+        <PackageVersion>$([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[1])</PackageVersion>
+        <AllPrivateAssets>$([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[4])</AllPrivateAssets>
+        <CopyLocal Condition="'%(PaketReferencesFileLinesInfo.Splits)' == '6'">$([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[5])</CopyLocal>
+      </PaketReferencesFileLinesInfo>
+      <PackageReference Include="%(PaketReferencesFileLinesInfo.PackageName)">
+        <Version>%(PaketReferencesFileLinesInfo.PackageVersion)</Version>
+        <PrivateAssets Condition=" ('%(PaketReferencesFileLinesInfo.AllPrivateAssets)' == 'true') Or ('$(PackAsTool)' == 'true') ">All</PrivateAssets>
+        <ExcludeAssets Condition=" '%(PaketReferencesFileLinesInfo.Splits)' == '6' And %(PaketReferencesFileLinesInfo.CopyLocal) == 'false'">runtime</ExcludeAssets>
+        <ExcludeAssets Condition=" '%(PaketReferencesFileLinesInfo.Splits)' != '6' And %(PaketReferencesFileLinesInfo.AllPrivateAssets) == 'exclude'">runtime</ExcludeAssets>
+        <Publish Condition=" '$(PackAsTool)' == 'true' ">true</Publish>
+        <AllowExplicitVersion>true</AllowExplicitVersion>
+      </PackageReference>
+    </ItemGroup>
+
+    <PropertyGroup>
+      <PaketCliToolFilePath>$(PaketIntermediateOutputPath)/$(MSBuildProjectFile).paket.clitools</PaketCliToolFilePath>
+    </PropertyGroup>
+
+    <ReadLinesFromFile File="$(PaketCliToolFilePath)" >
+      <Output TaskParameter="Lines" ItemName="PaketCliToolFileLines"/>
+    </ReadLinesFromFile>
+
+    <ItemGroup Condition=" '@(PaketCliToolFileLines)' != '' " >
+      <PaketCliToolFileLinesInfo Include="@(PaketCliToolFileLines)" >
+        <PackageName>$([System.String]::Copy('%(PaketCliToolFileLines.Identity)').Split(',')[0])</PackageName>
+        <PackageVersion>$([System.String]::Copy('%(PaketCliToolFileLines.Identity)').Split(',')[1])</PackageVersion>
+      </PaketCliToolFileLinesInfo>
+      <DotNetCliToolReference Include="%(PaketCliToolFileLinesInfo.PackageName)">
+        <Version>%(PaketCliToolFileLinesInfo.PackageVersion)</Version>
+      </DotNetCliToolReference>
+    </ItemGroup>
+
+    <!-- Disabled for now until we know what to do with runtime deps - https://github.com/fsprojects/Paket/issues/2964
+    <PropertyGroup>
+      <RestoreConfigFile>$(PaketIntermediateOutputPath)/$(MSBuildProjectFile).NuGet.Config</RestoreConfigFile>
+    </PropertyGroup> -->
+
+  </Target>
+
+  <Target Name="PaketDisableDirectPack" AfterTargets="_IntermediatePack" BeforeTargets="GenerateNuspec" Condition="('$(IsPackable)' == '' Or '$(IsPackable)' == 'true') And Exists('$(PaketIntermediateOutputPath)/$(MSBuildProjectFile).references')" >
+    <PropertyGroup>
+      <ContinuePackingAfterGeneratingNuspec>false</ContinuePackingAfterGeneratingNuspec>
+    </PropertyGroup>
+  </Target>
+
+  <Target Name="PaketOverrideNuspec" DependsOnTargets="SetPaketCommand" AfterTargets="GenerateNuspec" Condition="('$(IsPackable)' == '' Or '$(IsPackable)' == 'true') And Exists('$(PaketIntermediateOutputPath)/$(MSBuildProjectFile).references')" >
+    <ItemGroup>
+      <_NuspecFilesNewLocation Include="$(PaketIntermediateOutputPath)\$(Configuration)\*.nuspec"/>
+      <MSBuildMajorVersion Include="$(DetectedMSBuildVersion.Replace(`-`, `.`).Split(`.`)[0])" />
+      <MSBuildMinorVersion Include="$(DetectedMSBuildVersion.Replace(`-`, `.`).Split(`.`)[1])" />
+    </ItemGroup>
+
+    <PropertyGroup>
+      <PaketProjectFile>$(MSBuildProjectDirectory)/$(MSBuildProjectFile)</PaketProjectFile>
+      <ContinuePackingAfterGeneratingNuspec>true</ContinuePackingAfterGeneratingNuspec>
+      <UseMSBuild16_0_Pack>false</UseMSBuild16_0_Pack>
+      <UseMSBuild16_0_Pack Condition=" '@(MSBuildMajorVersion)' >= '16' ">true</UseMSBuild16_0_Pack>
+      <UseMSBuild15_9_Pack>false</UseMSBuild15_9_Pack>
+      <UseMSBuild15_9_Pack Condition=" '@(MSBuildMajorVersion)' == '15' AND '@(MSBuildMinorVersion)' > '8' ">true</UseMSBuild15_9_Pack>
+      <UseMSBuild15_8_Pack>false</UseMSBuild15_8_Pack>
+      <UseMSBuild15_8_Pack Condition=" '$(NuGetToolVersion)' != '4.0.0' AND (! $(UseMSBuild15_9_Pack)) AND (! $(UseMSBuild16_0_Pack)) ">true</UseMSBuild15_8_Pack>
+      <UseNuGet4_Pack>false</UseNuGet4_Pack>
+      <UseNuGet4_Pack Condition=" (! $(UseMSBuild15_8_Pack)) AND (! $(UseMSBuild15_9_Pack)) AND (! $(UseMSBuild16_0_Pack)) ">true</UseNuGet4_Pack>
+      <AdjustedNuspecOutputPath>$(PaketIntermediateOutputPath)\$(Configuration)</AdjustedNuspecOutputPath>
+      <AdjustedNuspecOutputPath Condition="@(_NuspecFilesNewLocation) == ''">$(PaketIntermediateOutputPath)</AdjustedNuspecOutputPath>
+    </PropertyGroup>
+
+    <ItemGroup>
+      <_NuspecFiles Include="$(AdjustedNuspecOutputPath)\*.$(PackageVersion.Split(`+`)[0]).nuspec"/>
+    </ItemGroup>
+
+    <Error Text="Error Because of PAKET_ERROR_ON_MSBUILD_EXEC (not calling fix-nuspecs)" Condition=" '$(PAKET_ERROR_ON_MSBUILD_EXEC)' == 'true' " />
+    <Exec Condition="@(_NuspecFiles) != ''" Command='$(PaketCommand) fix-nuspecs files "@(_NuspecFiles)" project-file "$(PaketProjectFile)" ' />
+    <Error Condition="@(_NuspecFiles) == ''" Text='Could not find nuspec files in "$(AdjustedNuspecOutputPath)" (Version: "$(PackageVersion)"), therefore we cannot call "paket fix-nuspecs" and have to error out!' />
+
+    <ConvertToAbsolutePath Condition="@(_NuspecFiles) != ''" Paths="@(_NuspecFiles)">
+      <Output TaskParameter="AbsolutePaths" PropertyName="NuspecFileAbsolutePath" />
+    </ConvertToAbsolutePath>
+
+    <!-- Call Pack -->
+    <PackTask Condition="$(UseMSBuild16_0_Pack)"
+              PackItem="$(PackProjectInputFile)"
+              PackageFiles="@(_PackageFiles)"
+              PackageFilesToExclude="@(_PackageFilesToExclude)"
+              PackageVersion="$(PackageVersion)"
+              PackageId="$(PackageId)"
+              Title="$(Title)"
+              Authors="$(Authors)"
+              Description="$(Description)"
+              Copyright="$(Copyright)"
+              RequireLicenseAcceptance="$(PackageRequireLicenseAcceptance)"
+              LicenseUrl="$(PackageLicenseUrl)"
+              ProjectUrl="$(PackageProjectUrl)"
+              IconUrl="$(PackageIconUrl)"
+              ReleaseNotes="$(PackageReleaseNotes)"
+              Tags="$(PackageTags)"
+              DevelopmentDependency="$(DevelopmentDependency)"
+              BuildOutputInPackage="@(_BuildOutputInPackage)"
+              TargetPathsToSymbols="@(_TargetPathsToSymbols)"
+              SymbolPackageFormat="$(SymbolPackageFormat)"
+              TargetFrameworks="@(_TargetFrameworks)"
+              AssemblyName="$(AssemblyName)"
+              PackageOutputPath="$(PackageOutputAbsolutePath)"
+              IncludeSymbols="$(IncludeSymbols)"
+              IncludeSource="$(IncludeSource)"
+              PackageTypes="$(PackageType)"
+              IsTool="$(IsTool)"
+              RepositoryUrl="$(RepositoryUrl)"
+              RepositoryType="$(RepositoryType)"
+              SourceFiles="@(_SourceFiles->Distinct())"
+              NoPackageAnalysis="$(NoPackageAnalysis)"
+              MinClientVersion="$(MinClientVersion)"
+              Serviceable="$(Serviceable)"
+              FrameworkAssemblyReferences="@(_FrameworkAssemblyReferences)"
+              ContinuePackingAfterGeneratingNuspec="$(ContinuePackingAfterGeneratingNuspec)"
+              NuspecOutputPath="$(AdjustedNuspecOutputPath)"
+              IncludeBuildOutput="$(IncludeBuildOutput)"
+              BuildOutputFolders="$(BuildOutputTargetFolder)"
+              ContentTargetFolders="$(ContentTargetFolders)"
+              RestoreOutputPath="$(RestoreOutputAbsolutePath)"
+              NuspecFile="$(NuspecFileAbsolutePath)"
+              NuspecBasePath="$(NuspecBasePath)"
+              NuspecProperties="$(NuspecProperties)"
+              PackageLicenseFile="$(PackageLicenseFile)"
+              PackageLicenseExpression="$(PackageLicenseExpression)"
+              PackageLicenseExpressionVersion="$(PackageLicenseExpressionVersion)" />
+
+    <PackTask Condition="$(UseMSBuild15_9_Pack)"
+              PackItem="$(PackProjectInputFile)"
+              PackageFiles="@(_PackageFiles)"
+              PackageFilesToExclude="@(_PackageFilesToExclude)"
+              PackageVersion="$(PackageVersion)"
+              PackageId="$(PackageId)"
+              Title="$(Title)"
+              Authors="$(Authors)"
+              Description="$(Description)"
+              Copyright="$(Copyright)"
+              RequireLicenseAcceptance="$(PackageRequireLicenseAcceptance)"
+              LicenseUrl="$(PackageLicenseUrl)"
+              ProjectUrl="$(PackageProjectUrl)"
+              IconUrl="$(PackageIconUrl)"
+              ReleaseNotes="$(PackageReleaseNotes)"
+              Tags="$(PackageTags)"
+              DevelopmentDependency="$(DevelopmentDependency)"
+              BuildOutputInPackage="@(_BuildOutputInPackage)"
+              TargetPathsToSymbols="@(_TargetPathsToSymbols)"
+              SymbolPackageFormat="$(SymbolPackageFormat)"
+              TargetFrameworks="@(_TargetFrameworks)"
+              AssemblyName="$(AssemblyName)"
+              PackageOutputPath="$(PackageOutputAbsolutePath)"
+              IncludeSymbols="$(IncludeSymbols)"
+              IncludeSource="$(IncludeSource)"
+              PackageTypes="$(PackageType)"
+              IsTool="$(IsTool)"
+              RepositoryUrl="$(RepositoryUrl)"
+              RepositoryType="$(RepositoryType)"
+              SourceFiles="@(_SourceFiles->Distinct())"
+              NoPackageAnalysis="$(NoPackageAnalysis)"
+              MinClientVersion="$(MinClientVersion)"
+              Serviceable="$(Serviceable)"
+              FrameworkAssemblyReferences="@(_FrameworkAssemblyReferences)"
+              ContinuePackingAfterGeneratingNuspec="$(ContinuePackingAfterGeneratingNuspec)"
+              NuspecOutputPath="$(AdjustedNuspecOutputPath)"
+              IncludeBuildOutput="$(IncludeBuildOutput)"
+              BuildOutputFolder="$(BuildOutputTargetFolder)"
+              ContentTargetFolders="$(ContentTargetFolders)"
+              RestoreOutputPath="$(RestoreOutputAbsolutePath)"
+              NuspecFile="$(NuspecFileAbsolutePath)"
+              NuspecBasePath="$(NuspecBasePath)"
+              NuspecProperties="$(NuspecProperties)"/>
+
+    <PackTask Condition="$(UseMSBuild15_8_Pack)"
+              PackItem="$(PackProjectInputFile)"
+              PackageFiles="@(_PackageFiles)"
+              PackageFilesToExclude="@(_PackageFilesToExclude)"
+              PackageVersion="$(PackageVersion)"
+              PackageId="$(PackageId)"
+              Title="$(Title)"
+              Authors="$(Authors)"
+              Description="$(Description)"
+              Copyright="$(Copyright)"
+              RequireLicenseAcceptance="$(PackageRequireLicenseAcceptance)"
+              LicenseUrl="$(PackageLicenseUrl)"
+              ProjectUrl="$(PackageProjectUrl)"
+              IconUrl="$(PackageIconUrl)"
+              ReleaseNotes="$(PackageReleaseNotes)"
+              Tags="$(PackageTags)"
+              DevelopmentDependency="$(DevelopmentDependency)"
+              BuildOutputInPackage="@(_BuildOutputInPackage)"
+              TargetPathsToSymbols="@(_TargetPathsToSymbols)"
+              TargetFrameworks="@(_TargetFrameworks)"
+              AssemblyName="$(AssemblyName)"
+              PackageOutputPath="$(PackageOutputAbsolutePath)"
+              IncludeSymbols="$(IncludeSymbols)"
+              IncludeSource="$(IncludeSource)"
+              PackageTypes="$(PackageType)"
+              IsTool="$(IsTool)"
+              RepositoryUrl="$(RepositoryUrl)"
+              RepositoryType="$(RepositoryType)"
+              SourceFiles="@(_SourceFiles->Distinct())"
+              NoPackageAnalysis="$(NoPackageAnalysis)"
+              MinClientVersion="$(MinClientVersion)"
+              Serviceable="$(Serviceable)"
+              FrameworkAssemblyReferences="@(_FrameworkAssemblyReferences)"
+              ContinuePackingAfterGeneratingNuspec="$(ContinuePackingAfterGeneratingNuspec)"
+              NuspecOutputPath="$(AdjustedNuspecOutputPath)"
+              IncludeBuildOutput="$(IncludeBuildOutput)"
+              BuildOutputFolder="$(BuildOutputTargetFolder)"
+              ContentTargetFolders="$(ContentTargetFolders)"
+              RestoreOutputPath="$(RestoreOutputAbsolutePath)"
+              NuspecFile="$(NuspecFileAbsolutePath)"
+              NuspecBasePath="$(NuspecBasePath)"
+              NuspecProperties="$(NuspecProperties)"/>
+
+    <PackTask Condition="$(UseNuGet4_Pack)"
+              PackItem="$(PackProjectInputFile)"
+              PackageFiles="@(_PackageFiles)"
+              PackageFilesToExclude="@(_PackageFilesToExclude)"
+              PackageVersion="$(PackageVersion)"
+              PackageId="$(PackageId)"
+              Title="$(Title)"
+              Authors="$(Authors)"
+              Description="$(Description)"
+              Copyright="$(Copyright)"
+              RequireLicenseAcceptance="$(PackageRequireLicenseAcceptance)"
+              LicenseUrl="$(PackageLicenseUrl)"
+              ProjectUrl="$(PackageProjectUrl)"
+              IconUrl="$(PackageIconUrl)"
+              ReleaseNotes="$(PackageReleaseNotes)"
+              Tags="$(PackageTags)"
+              TargetPathsToAssemblies="@(_TargetPathsToAssemblies->'%(FinalOutputPath)')"
+              TargetPathsToSymbols="@(_TargetPathsToSymbols)"
+              TargetFrameworks="@(_TargetFrameworks)"
+              AssemblyName="$(AssemblyName)"
+              PackageOutputPath="$(PackageOutputAbsolutePath)"
+              IncludeSymbols="$(IncludeSymbols)"
+              IncludeSource="$(IncludeSource)"
+              PackageTypes="$(PackageType)"
+              IsTool="$(IsTool)"
+              RepositoryUrl="$(RepositoryUrl)"
+              RepositoryType="$(RepositoryType)"
+              SourceFiles="@(_SourceFiles->Distinct())"
+              NoPackageAnalysis="$(NoPackageAnalysis)"
+              MinClientVersion="$(MinClientVersion)"
+              Serviceable="$(Serviceable)"
+              AssemblyReferences="@(_References)"
+              ContinuePackingAfterGeneratingNuspec="$(ContinuePackingAfterGeneratingNuspec)"
+              NuspecOutputPath="$(AdjustedNuspecOutputPath)"
+              IncludeBuildOutput="$(IncludeBuildOutput)"
+              BuildOutputFolder="$(BuildOutputTargetFolder)"
+              ContentTargetFolders="$(ContentTargetFolders)"
+              RestoreOutputPath="$(RestoreOutputAbsolutePath)"
+              NuspecFile="$(NuspecFileAbsolutePath)"
+              NuspecBasePath="$(NuspecBasePath)"
+              NuspecProperties="$(NuspecProperties)"/>
+  </Target>
+  <!--/+:cnd:noEmit-->
+</Project>

BIN
.paket/paket.bootstrapper.exe


+ 130 - 0
.paket/paket.targets

@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+
+  <PropertyGroup>
+    <!-- Enable the restore command to run before builds -->
+    <RestorePackages Condition=" '$(RestorePackages)' == '' ">true</RestorePackages>
+    <PaketToolsPath>$(MSBuildThisFileDirectory)</PaketToolsPath>
+    <PaketRootPath>$(MSBuildThisFileDirectory)..\</PaketRootPath>
+    <PaketLockFilePath>$(PaketRootPath)paket.lock</PaketLockFilePath>
+    <PaketRestoreCacheFile>$(PaketRootPath)paket-files\paket.restore.cached</PaketRestoreCacheFile>
+    <MonoPath Condition="'$(MonoPath)' == '' And Exists('/Library/Frameworks/Mono.framework/Commands/mono')">/Library/Frameworks/Mono.framework/Commands/mono</MonoPath>
+    <MonoPath Condition="'$(MonoPath)' == ''">mono</MonoPath>
+
+    <!-- Disable test for CLI tool completely - overrideable via properties in projects or via environment variables -->
+    <PaketDisableCliTest Condition=" '$(PaketDisableCliTest)' == '' ">False</PaketDisableCliTest>
+  </PropertyGroup>
+
+  <!-- Resolve how paket should be called -->
+  <!-- Current priority is: local (1: repo root, 2: .paket folder) => 3: as CLI tool => as bootstrapper (4: proj Bootstrapper style, 5: BootstrapperExeDir) => 6: global path variable -->
+  <Target Name="SetPaketCommand" >
+    <!-- Test if paket is available in the standard locations. If so, that takes priority. Case 1/2 - non-windows specific -->
+    <PropertyGroup Condition=" '$(OS)' != 'Windows_NT' ">
+      <!-- no windows, try native paket as default, root => tool -->
+      <PaketExePath Condition=" '$(PaketExePath)' == '' AND Exists('$(PaketRootPath)paket') ">$(PaketRootPath)paket</PaketExePath>
+      <PaketExePath Condition=" '$(PaketExePath)' == '' AND Exists('$(PaketToolsPath)paket') ">$(PaketToolsPath)paket</PaketExePath>
+    </PropertyGroup>
+
+    <!-- Test if paket is available in the standard locations. If so, that takes priority. Case 2/2 - same across platforms -->
+    <PropertyGroup>
+      <!-- root => tool -->
+      <PaketExePath Condition=" '$(PaketExePath)' == '' AND Exists('$(PaketRootPath)paket.exe') ">$(PaketRootPath)paket.exe</PaketExePath>
+      <PaketExePath Condition=" '$(PaketExePath)' == '' AND Exists('$(PaketToolsPath)paket.exe') ">$(PaketToolsPath)paket.exe</PaketExePath>
+    </PropertyGroup>
+
+    <!-- If paket hasn't be found in standard locations, test for CLI tool usage. -->
+    <!-- First test: Is CLI configured to be used in "dotnet-tools.json"? - can result in a false negative; only a positive outcome is reliable. -->
+    <PropertyGroup Condition=" '$(PaketExePath)' == '' ">
+      <_DotnetToolsJson Condition="Exists('$(PaketRootPath)/.config/dotnet-tools.json')">$([System.IO.File]::ReadAllText("$(PaketRootPath)/.config/dotnet-tools.json"))</_DotnetToolsJson>
+      <_ConfigContainsPaket Condition=" '$(_DotnetToolsJson)' != ''">$(_DotnetToolsJson.Contains('"paket"'))</_ConfigContainsPaket>
+      <_ConfigContainsPaket Condition=" '$(_ConfigContainsPaket)' == ''">false</_ConfigContainsPaket>
+    </PropertyGroup>
+
+    <!-- Second test: Call 'dotnet paket' and see if it returns without an error. Mute all the output. Only run if previous test failed and the test has not been disabled. -->
+    <!-- WARNING: This method can lead to processes hanging forever, and should be used as little as possible. See https://github.com/fsprojects/Paket/issues/3705 for details. -->
+    <Exec Condition=" '$(PaketExePath)' == '' AND !$(PaketDisableCliTest) AND !$(_ConfigContainsPaket)" Command="dotnet paket --version" IgnoreExitCode="true" StandardOutputImportance="low" StandardErrorImportance="low" >
+      <Output TaskParameter="ExitCode" PropertyName="LocalPaketToolExitCode" />
+    </Exec>
+
+    <!-- If paket is installed as CLI use that. Again, only if paket haven't already been found in standard locations. -->
+    <PropertyGroup Condition=" '$(PaketExePath)' == '' AND ($(_ConfigContainsPaket) OR '$(LocalPaketToolExitCode)' == '0') ">
+      <_PaketCommand>dotnet paket</_PaketCommand>
+    </PropertyGroup>
+
+    <!-- If neither local files nor CLI tool can be found, final attempt is searching for boostrapper config before falling back to global path variable. -->
+    <PropertyGroup Condition=" '$(PaketExePath)' == '' AND '$(_PaketCommand)' == '' ">
+      <!-- Test for bootstrapper setup -->
+      <PaketExePath Condition=" '$(PaketExePath)' == '' AND '$(PaketBootstrapperStyle)' == 'proj' ">$(PaketToolsPath)paket</PaketExePath>
+      <PaketExePath Condition=" '$(PaketExePath)' == '' AND Exists('$(PaketBootStrapperExeDir)') ">$(PaketBootStrapperExeDir)paket</PaketExePath>
+
+      <!-- If all else fails, use global path approach. -->
+      <PaketExePath Condition=" '$(PaketExePath)' == ''">paket</PaketExePath>
+    </PropertyGroup>
+
+    <!-- If not using CLI, setup correct execution command. -->
+    <PropertyGroup Condition=" '$(_PaketCommand)' == '' ">
+      <_PaketExeExtension>$([System.IO.Path]::GetExtension("$(PaketExePath)"))</_PaketExeExtension>
+      <_PaketCommand Condition=" '$(_PaketCommand)' == '' AND '$(_PaketExeExtension)' == '.dll' ">dotnet "$(PaketExePath)"</_PaketCommand>
+      <_PaketCommand Condition=" '$(_PaketCommand)' == '' AND '$(OS)' != 'Windows_NT' AND '$(_PaketExeExtension)' == '.exe' ">$(MonoPath) --runtime=v4.0.30319 "$(PaketExePath)"</_PaketCommand>
+      <_PaketCommand Condition=" '$(_PaketCommand)' == '' ">"$(PaketExePath)"</_PaketCommand>
+    </PropertyGroup>
+
+    <!-- The way to get a property to be available outside the target is to use this task. -->
+    <CreateProperty Value="$(_PaketCommand)">
+      <Output TaskParameter="Value" PropertyName="PaketCommand"/>
+    </CreateProperty>
+
+  </Target>
+
+  <Choose> <!-- MyProject.fsproj.paket.references has the highest precedence -->
+    <When Condition="Exists('$(MSBuildProjectFullPath).paket.references')">
+      <PropertyGroup>
+        <PaketReferences>$(MSBuildProjectFullPath).paket.references</PaketReferences>
+      </PropertyGroup>
+    </When> <!-- MyProject.paket.references -->
+    <When Condition="Exists('$(MSBuildProjectDirectory)\$(MSBuildProjectName).paket.references')">
+      <PropertyGroup>
+        <PaketReferences>$(MSBuildProjectDirectory)\$(MSBuildProjectName).paket.references</PaketReferences>
+      </PropertyGroup>
+    </When> <!-- paket.references -->
+    <When Condition="Exists('$(MSBuildProjectDirectory)\paket.references')">
+      <PropertyGroup>
+        <PaketReferences>$(MSBuildProjectDirectory)\paket.references</PaketReferences>
+      </PropertyGroup>
+    </When> <!-- Set to empty if a reference file isn't found matching one of the 3 format options -->
+    <Otherwise>
+      <PropertyGroup>
+        <PaketReferences></PaketReferences>
+      </PropertyGroup>
+    </Otherwise>
+  </Choose>
+
+  <PropertyGroup>
+    <!-- We need to ensure packages are restored prior to assembly resolve -->
+    <BuildDependsOn Condition="$(RestorePackages) == 'true'">RestorePackages; $(BuildDependsOn);</BuildDependsOn>
+  </PropertyGroup>
+
+  <Target Name="RestorePackages" DependsOnTargets="SetPaketCommand">
+
+    <PropertyGroup>
+      <!-- Commands -->
+      <RestoreCommand>$(PaketCommand) restore --references-file "$(PaketReferences)"</RestoreCommand>
+      <PaketRestoreRequired>true</PaketRestoreRequired>
+    </PropertyGroup>
+
+    <PropertyGroup Condition="Exists('$(PaketRestoreCacheFile)') ">
+      <PaketRestoreCachedHash>$([System.IO.File]::ReadAllText('$(PaketRestoreCacheFile)'))</PaketRestoreCachedHash>
+      <PaketRestoreLockFileHash>$([System.IO.File]::ReadAllText('$(PaketLockFilePath)'))</PaketRestoreLockFileHash>
+      <PaketRestoreRequired>true</PaketRestoreRequired>
+      <PaketRestoreRequired Condition=" '$(PaketRestoreLockFileHash)' == '$(PaketRestoreCachedHash)' ">false</PaketRestoreRequired>
+      <PaketRestoreRequired Condition=" '$(PaketRestoreLockFileHash)' == '' ">true</PaketRestoreRequired>
+    </PropertyGroup>
+
+    <Exec Command="$(RestoreCommand)"
+          IgnoreStandardErrorWarningFormat="true"
+          WorkingDirectory="$(PaketRootPath)"
+          ContinueOnError="false"
+          Condition=" '$(PaketRestoreRequired)' == 'true' AND Exists('$(PaketReferences)') AND '$(PaketReferences)' != '' "
+    />
+  </Target>
+</Project>

+ 12 - 0
Info/Ebnfqsp.txt

@@ -0,0 +1,12 @@
+ws = " " {" "}
+"a" = "a" ws
+'a' = 'a' {" "}
+Если нечто в кавычках - то после него обязательно следует как минимум один пробел, если в апострофах - 0 или больше пробелов
+escape symbol - "\"
+
+ident = ["*" | "$"] (underscore | letter) {letter | digit | underscore}
+
+assign = ["set" | "let"] ident ['[' expr ']'] ('=' ['+'|'-'] | ('+'|'-') '=') exprNotStartWithNeg
+call = ident exprNotStartWithNeg {"," expr}
+
+commentOp = "!" { ^("'"| nl | '"') | "'" { ^"'" | "''" } "'" | '"' { ^'"' | '""' } '"' }

+ 0 - 35
QSParse.sln

@@ -1,35 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 11.00
-# Visual Studio 2010
-Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "QSParse", "QSParse\QSParse.fsproj", "{6ECF54C2-777C-4275-BC5D-E48FA61A4627}"
-	ProjectSection(ProjectDependencies) = postProject
-		{554B1E12-DFA8-4972-9E9B-F5ABE1FC272A} = {554B1E12-DFA8-4972-9E9B-F5ABE1FC272A}
-	EndProjectSection
-EndProject
-Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "QSTools", "QSTools\QSTools.fsproj", "{8E6003CD-564C-4A80-B7AC-168E6E28CAF6}"
-EndProject
-Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "RunIfChange", "RunIfChange\RunIfChange.fsproj", "{554B1E12-DFA8-4972-9E9B-F5ABE1FC272A}"
-EndProject
-Global
-	GlobalSection(SolutionConfigurationPlatforms) = preSolution
-		Debug|x86 = Debug|x86
-		Release|x86 = Release|x86
-	EndGlobalSection
-	GlobalSection(ProjectConfigurationPlatforms) = postSolution
-		{6ECF54C2-777C-4275-BC5D-E48FA61A4627}.Debug|x86.ActiveCfg = Debug|x86
-		{6ECF54C2-777C-4275-BC5D-E48FA61A4627}.Debug|x86.Build.0 = Debug|x86
-		{6ECF54C2-777C-4275-BC5D-E48FA61A4627}.Release|x86.ActiveCfg = Release|x86
-		{6ECF54C2-777C-4275-BC5D-E48FA61A4627}.Release|x86.Build.0 = Release|x86
-		{8E6003CD-564C-4A80-B7AC-168E6E28CAF6}.Debug|x86.ActiveCfg = Debug|x86
-		{8E6003CD-564C-4A80-B7AC-168E6E28CAF6}.Debug|x86.Build.0 = Debug|x86
-		{8E6003CD-564C-4A80-B7AC-168E6E28CAF6}.Release|x86.ActiveCfg = Release|x86
-		{8E6003CD-564C-4A80-B7AC-168E6E28CAF6}.Release|x86.Build.0 = Release|x86
-		{554B1E12-DFA8-4972-9E9B-F5ABE1FC272A}.Debug|x86.ActiveCfg = Debug|x86
-		{554B1E12-DFA8-4972-9E9B-F5ABE1FC272A}.Debug|x86.Build.0 = Debug|x86
-		{554B1E12-DFA8-4972-9E9B-F5ABE1FC272A}.Release|x86.ActiveCfg = Release|x86
-		{554B1E12-DFA8-4972-9E9B-F5ABE1FC272A}.Release|x86.Build.0 = Release|x86
-	EndGlobalSection
-	GlobalSection(SolutionProperties) = preSolution
-		HideSolutionNode = FALSE
-	EndGlobalSection
-EndGlobal

+ 6 - 0
QSParse/App.config

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+    <startup> 
+        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
+    </startup>
+</configuration>

+ 98 - 0
QSParse/Ast.fs

@@ -0,0 +1,98 @@
+module QSAST
+
+type Value =
+    | Int of int
+    | String of string
+
+type Op =
+    // "+" | "-"   | "*"   | "/"    | "mod"
+    | Plus | Minus | Times | Divide | Mod
+    // "=" | ">" | ">=" | "<" | "<=" | ("!" | "<>")| =< | =>
+    | Eq   | Gt  | Ge   | Lt  | Le   | Ne          | El | Eg
+    // "and" | "or"
+    | And    | Or
+[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
+[<RequireQualifiedAccess>]
+module Op =
+    [<ReflectedDefinition>]
+    let toString = function
+        | Times -> "*"
+        | Divide -> "/"
+        | Mod -> "mod"
+        | Plus -> "+"
+        | Minus -> "-"
+        | Lt -> "<"
+        | Gt -> ">"
+        | Le -> "<="
+        | Eg -> "=>"
+        | Ge -> ">="
+        | El -> "=<"
+        | Ne -> "<>"
+        | And -> "and"
+        | Or -> "or"
+        | Eq -> "="
+//            opp.AddOperator(InfixOperator("=>", ws, 4, A.Left, fun x y -> Expr(Ge, x, y)))
+//    opp.AddOperator(InfixOperator("=<", ws, 4, A.Left, fun x y -> Expr(Le, x, y)))
+    let ops = Reflect.unionCaseToList <@toString@>
+
+    let fromString = 
+        let m = Map.ofList <| List.map (fun (a,b) -> b,a) ops
+        fun x -> match Map.tryFind x m with Some x -> x | None -> failwithf "not found %A" x    
+type UnarOp = 
+    // "-" |"obj" | "no"
+    | Neg  | Obj  | No
+[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
+[<RequireQualifiedAccess>]
+module UnarOp =
+    [<ReflectedDefinition>]
+    let toString = function | Obj -> "obj" | Neg -> "-" | No -> "no"
+    let ops = Reflect.unionCaseToList <@toString@>
+    let fromString = 
+        let m = Map.ofList <| List.map (fun (a,b) -> b,a) ops
+        fun x -> match Map.tryFind x m with Some x -> x | None -> failwithf "not found %A" x
+module Precedences = 
+    type T = OpB of Op | PrefB of UnarOp
+
+    //&
+    //OR
+    //AND
+    //OBJ, NO
+    //=, <, >, !, <>, <=, >=, =<, =>
+    //+, -
+    //MOD
+    //*, /
+    //+, - (унарные)
+
+//        "=, <, >, <>, <=, >=".Split([|", "|], System.StringSplitOptions.None)
+//        |> Array.map (Op.fromString >> sprintf "OpB %A") |> join " | "
+    let prec = function
+        | OpB Or -> 1
+        | OpB And -> 2
+        | PrefB Obj | PrefB No -> 3
+        // =     | <      | >      | <>     | <=     | >=     | =>     | =<
+        | OpB Eq | OpB Lt | OpB Gt | OpB Ne | OpB Le | OpB Ge | OpB Eg | OpB El-> 4
+        | OpB Plus | OpB Minus -> 5
+        | OpB Mod -> 6
+        | OpB Times | OpB Divide -> 7
+        | PrefB Neg -> 8
+type Expr =
+    | Val of Value
+    | Var of string
+    | Func of string * Expr list
+    | Arr of string * Expr list
+    | UnarExpr of UnarOp * Expr
+    | Expr of Op * Expr * Expr
+
+type Assign = 
+    | AssignVar of string
+    | AssignArr of string * Expr
+type Statement =
+    | Assign of Assign * Expr
+    | AssingCode of Assign * Statement list
+    | CallSt of string * Expr list
+    | StarPl of Expr
+    | If of Expr * Statement list * Statement list
+    | Act of Expr list * Statement list
+    | Sign of string
+    | Comment of string
+type Location = Location of string * Statement list

+ 215 - 0
QSParse/Parsec.fs

@@ -0,0 +1,215 @@
+module QSParsec
+
+open FParsec
+open QSAST
+
+type A = Associativity
+
+
+let parsing p str =
+    match run p str with
+    | Success(result, _, _)   -> result
+    | Failure(errorMsg, _, _) -> failwithf "Failure: %s" errorMsg
+
+//let ws = spaces
+let ws = 
+    skipManySatisfy (function '\t' | ' ' -> true | _ -> false)
+    //manyChars (pchar '\t' <|> pchar ' ')
+let nl<'a> = skipMany1 newline : Parser<unit, 'a>
+let str s = pstring s
+let str_ws s = pstring s .>> ws
+let char_ws c = pchar c .>> ws
+let bet opened closed = between <| char_ws opened <| pchar closed
+let bet_ws opened closed p = bet opened closed p .>> ws
+let optList p = p <|>% []
+//ident = ["*" | "$"] (underscore | letter) {letter | digit | underscore}
+let identifier =
+    let isIdentifierFirstChar c = isLetter c || c = '_'
+    let isIdentifierChar c = isLetter c || isDigit c || c = '_' || c = '.'
+    let p = many1Satisfy2L isIdentifierFirstChar isIdentifierChar "identifier"
+
+    let keys = notFollowedByL ((choice <| List.map pstringCI ["let"; "set"; "if"; "end"; "elseif"; "else"; "act"; "no"; "obj"]) >>. (spaces1 <|> eof <|> skipChar '"' <|> skipChar ''')) "some excess"
+
+    keys >>.
+    p <|> (pstring "*" <|> pstring "$" >>= fun st -> p |>> fun x -> st + x)
+    .>> ws // skips trailing whitespace
+
+let stringLiteral =
+    let normalChar c = satisfy (fun c' -> c' <> c)
+    let p c = manyChars (normalChar c <|> attempt(pchar c >>. pchar c))
+
+    bet_ws '"' '"' (p '"') <|> bet_ws '\'' '\'' (p '\'')
+assert
+    assert
+        parsing stringLiteral "\" \"" = ""
+    assert
+        parsing stringLiteral "\"\"\"\"" = "\""
+    assert
+        parsing stringLiteral "''''" = "'"
+
+    parsing stringLiteral "''" = ""
+
+
+let pexpr =
+    let opp = new OperatorPrecedenceParser<Expr,unit,unit>()
+    let expr = opp.ExpressionParser
+    let term = 
+        let varOrCall = 
+            let pcall name = 
+                bet_ws '(' ')' (sepBy expr (pchar ',' >>. ws)) |>> fun args ->
+                Func(name, args)
+            let idx name = 
+                bet_ws '[' ']' (sepBy expr (pchar ',' >>. ws)) |>> fun args ->
+                Arr(name, args)                
+            identifier >>= fun name -> pcall name <|> idx name <|>% (Var name)
+        let pred = (stringLiteral |>> String) <|> (pint32 |>> Int) |>> Val .>> ws
+        //(pint32 .>> ws |>> (Int >> Val)) <|> varOrCall <|> bet_ws '(' ')' expr
+        pred <|> varOrCall <|> bet_ws '(' ')' expr
+    
+    opp.TermParser <- term
+
+    let addInf opT = 
+        let op = Op.toString opT
+        let prec = Precedences.prec <| Precedences.OpB opT
+        opp.AddOperator(InfixOperator(op, ws, prec, A.Left, fun x y -> Expr(opT, x, y)))
+    Reflect.createUnionCases |> List.iter addInf
+    
+//    opp.AddOperator(InfixOperator("=>", ws, 4, A.Left, fun x y -> Expr(Ge, x, y)))
+//    opp.AddOperator(InfixOperator("=<", ws, 4, A.Left, fun x y -> Expr(Le, x, y)))
+    opp.AddOperator(InfixOperator("!",   ws, 4, A.Left, fun x y -> Expr(Le, x, y)))
+    //Precedences.prec <| Precedences.OpB And
+    opp.AddOperator(InfixOperator("OR",  ws, 1, A.Left, fun x y -> Expr(Le, x, y)))
+    opp.AddOperator(InfixOperator("AND", ws, 2, A.Left, fun x y -> Expr(Le, x, y)))
+    let addPref unT = 
+        let op = UnarOp.toString unT
+        let prec = Precedences.prec <| Precedences.PrefB unT
+        opp.AddOperator(PrefixOperator(op, ws, prec, false, fun x -> UnarExpr(unT, x)))
+    
+    Reflect.createUnionCases |> List.iter addPref
+
+    expr
+
+let nlws = nl >>. spaces
+let strInsWs s = pstringCI s >>. ws
+let identOnly s = pstringCI s >>? notFollowedBy (satisfy isLetter) >>. ws
+let pstmt, pstmtRef = createParserForwardedToRef<Statement,unit>()
+let stmts = sepEndBy pstmt (nlws <|> (char_ws '&' >>% ()))
+let assign = 
+    let assdef name ass = 
+        let asscode = 
+            //let stmts = sepBy pstmt nlws
+            between (pchar '{' >>. spaces) (spaces >>. char_ws '}') stmts
+            |>> fun stmts -> AssingCode(ass, stmts)
+        let call = identifier >>=? fun name -> followedBy (identifier <|> (puint32 >>% "") <|> stringLiteral) >>. (sepBy1 pexpr (char_ws ',')) |>> fun args -> Assign(ass, Func(name, args))
+        let assexpr = call <|> (pexpr |>> fun defExpr -> Assign(ass, defExpr))
+        
+        (str_ws "-=" >>. pexpr |>> fun defExpr -> Assign(ass, Expr.Expr(Minus, Var name, defExpr)))
+        <|> (str_ws "=-" >>. pexpr |>> fun defExpr -> Assign(ass, Expr.Expr(Minus, defExpr, Var name)))
+        <|> ((str_ws "+=" <|> str_ws "=+") >>. pexpr |>> fun defExpr -> Assign(ass, Expr.Expr(Plus, Var name, defExpr)))
+        <|> (char_ws '=' >>. (assexpr <|> asscode))
+
+    let assign name = 
+        let arr = bet_ws '[' ']' pexpr |>> fun braketExpr -> AssignArr(name, braketExpr)
+        arr <|>% (AssignVar name) >>= assdef name
+    // assign = ["set" | "let"] ident ['[' expr ']'] ('=' ['+'|'-'] | ('+'|'-') '=') exprNotStartWithNeg
+    let p = identOnly "set" <|> identOnly "let" >>. identifier >>= assign
+    let all =    
+        identifier >>=? fun name ->
+        let call name = (sepBy1 pexpr (char_ws ',')) |>> fun exprs -> CallSt(name, exprs)
+        //assign name <|> (followedBy (identifier <|> (puint32 >>% "") <|> stringLiteral) >>. call name)
+        assign name <|> (followedBy (identifier <|> ((strInsWs "obj" <|> strInsWs "no") >>% "") <|> (puint32 >>% "") <|> stringLiteral) >>. call name)
+    p <|> all
+    //attempt p <|> (pexpr |>> Statement.StarPl)
+let pcomment<'a> = 
+    let stringLiteral2 c =
+        let normalCharSnippet = many1Satisfy ((<>) c)
+        let cs = string c
+        let escapedChar = pstring (cs + cs)
+        between (pchar c) (pchar c)
+                (manyStrings (normalCharSnippet <|> escapedChar)) |>> fun x -> System.String.Concat([|cs; x; cs|])
+    let brace = 
+        let normalCharSnippet = many1Satisfy ((<>) '}')
+        let escapedChar = pstring "}}"
+        between (pchar '{') (pchar '}')
+                (manyStrings (normalCharSnippet <|> escapedChar)) |>> fun x -> System.String.Concat([|"{"; x; "}"|])
+    let p = 
+        many1Satisfy (fun c -> c <> '\n' && c <> ''' && c <> '"' && c <> '{')
+        <|> stringLiteral2 '"'
+        <|> stringLiteral2 '''
+        <|> brace
+    pchar '!' >>. manyStrings p |>> Comment : Parser<Statement,'a>
+let pexprStmt = 
+    pexpr |>> function Var x -> CallSt(x, []) | Func(name, args) -> CallSt(name,args) | x -> StarPl x
+let psign = char_ws ':' >>. manySatisfy ((<>) '\n') |>> Sign
+module IfMod =
+    let ifBegin = strInsWs "if" >>. pexpr .>> char_ws ':'
+    
+    let stmtsOne, stmtsOneRef = createParserForwardedToRef<Statement list,unit>()
+
+    //ifOneBody = stmtsOne ["else" stmtsOne];
+    let ifOneBody cond =
+        stmtsOne >>= fun body -> 
+        optList (strInsWs "else" >>. stmtsOne) 
+        |>> fun elseBody -> If(cond, body, elseBody)
+    //ifOne = ifBegin ifOneBody;
+    let ifone = ifBegin >>= ifOneBody
+
+    //actBegin = "act" expr ":"
+    let actBegin = strInsWs "act" >>. sepBy1 pexpr (char_ws ',') .>> char_ws ':'
+    //actOne = actBegin stmtsOne;
+    let actOne = actBegin >>= fun exprs -> stmtsOne |>> fun body -> Act(exprs, body)
+    //stmtsOne = actOne | ifOne | assign { "&" assign } [actOne | ifOne]
+    let p = (actOne <|> ifone |>> fun x -> [x])
+    stmtsOneRef := 
+        //p <|> sepBy1 (assign <|> pexprStmt <|> pcomment) (char_ws '&') .>> (skipChar 'a' <|>% ()) .>> ws >>= fun assigns -> 
+        //p <|> sepBy1 (assign <|> pexprStmt <|> pcomment <|> actOne <|> ifone) (char_ws '&') >>= fun assigns -> 
+        sepBy1 (assign <|> pexprStmt <|> pcomment <|> actOne <|> ifone) (char_ws '&') <|> p >>= fun assigns -> 
+        optList p |>> fun x -> assigns @ x
+    
+    let smtsMulti, smtsMultiRef = createParserForwardedToRef<Statement list,unit>()
+    //stmtsMultiNl = nl smtsMulti nl {stmtsMulti nl}
+    let stmtsMultiNl = nlws >>. sepEndBy1 smtsMulti nlws |>> List.concat
+    //actMulti = actBegin (stmtsOne | stmtsMultiNl "end");
+    let actMulti = 
+        actBegin >>= fun args -> 
+        stmtsOne <|> (stmtsMultiNl .>> strInsWs "end")
+        |>> fun body -> Act(args, body)
+    let elsifbody cond elsif =
+        stmtsMultiNl >>= fun body ->
+        let en = strInsWs "end" >>% If(cond, body, [])
+        let el =
+            strInsWs "else" >>. ((elsif()|>>fun x -> [x]) <|> (stmtsMultiNl .>> strInsWs "end"))
+            |>> fun elseBody -> If(cond, body, elseBody)
+        en <|> el
+    //elif = ifBegin stmtsMultiNl ("end" | "else" (elif | stmtsMultiNl "end"));
+    let rec elsif () = ifBegin >>= fun cond -> elsifbody cond elsif
+
+    //ifMulti = ifBegin (elsifbody | ifOneBody)
+    let ifMulti =
+        ifBegin >>= fun cond ->
+        elsifbody cond elsif <|> ifOneBody cond
+    //stmtsMulti = ifMulti | actMulti | assign { "&" assign } [ifMulti | actMulti]
+    let pIf = ifMulti <|> actMulti
+    do
+        let p = 
+            sepEndBy1 (assign <|> pcomment <|> pexprStmt <|> psign) (char_ws '&') >>= fun stmts -> 
+            opt(opt(char_ws '&') >>. ifone) |>> function None -> stmts | Some x -> List.append stmts [x]
+        smtsMultiRef := 
+            //ifActMulti <|> sepBy (assign <|> pcomment <|> pexprStmt <|> psign) (char_ws '&') >>= fun assigns -> optList ifActMulti |>> fun x -> assigns @ x
+            //sepBy (assign <|> pcomment <|> pexprStmt <|> psign) (char_ws '&') <|> ifActMulti >>= fun assigns -> optList ifActMulti |>> fun x -> assigns @ x
+            p <|> (pIf |>> fun x -> [x]) <|>% []
+            
+    
+
+//let startStr = stringLiteral .>> ws .>> nlws |>> (String >> Val >> StarPl)
+
+pstmtRef := 
+    assign <|> IfMod.pIf <|> pcomment <|> (attempt pexprStmt) <|> psign
+
+let ploc = 
+    let anyExceptNl = many1Satisfy (fun c -> c <> '\n')
+    char_ws '#' >>. anyExceptNl .>> nlws >>= fun name ->
+    stmts .>> (char_ws '-') .>> (skipManySatisfy (fun c -> c<>'\n')) .>> spaces |>> fun body -> Location(name, body)
+//let plst = str_ws "begin" >>. sepEndBy ident (nl >>. ws) .>> str "end"
+//parsing plst "begin a\n end"
+

+ 0 - 69
QSParse/Program.fs

@@ -1,69 +0,0 @@
-module Program
-open System
-open System.IO
-
-let genOp () = 
-    #if INTERACTIVE
-        #r "C:\Program Files\FSharpPowerPack-2.0.0.0\\bin\FSharp.PowerPack.dll"
-        #load "QS.fs"
-        #load "QSParser.fs"
-        #load "QSLexer.fs"
-    #endif
-    let join sep (xs:string list) = System.String.Join(sep, xs)
-    QSLexer.ops |> Map.toList |> List.map (fun (s, _) -> "\"" + s + "\"") |> join " | " |> printfn "%s"
-
-let parseFile path =
-    let read = File.ReadAllText path
-    let lexbuf = Lexing.LexBuffer<_>.FromString read
-    QSParser.start QSLexer.tokenize lexbuf
-
-let parse (str:string) =
-    let stri = string str // так надо, без нее f# interactive выдает нечто непонятное
-    let lexbuf = Lexing.LexBuffer<char>.FromString str
-    QSParser.parseStatements QSLexer.tokenize lexbuf
-
-let lextest path = 
-    let read = File.ReadAllText path
-    let listTokens = System.Collections.Generic.List<(QSParser.token*int)>(10000)
-    let lexbuf = Lexing.LexBuffer<_>.FromString read
-    //let string_buff = new System.Text.StringBuilder(4000)
-
-    let rec f currIdx =
-        let exnf (e:exn) =
-            let count = 15
-            let lower = let n = currIdx - count - 1 in if n < 0 then 0 else n
-            let xs = listTokens.GetRange(lower, currIdx - lower)
-            xs |> Seq.iter (printfn "%A")
-            printfn "%s" e.Message
-            printfn "line %d" lexbuf.StartPos.Line
-            printfn "%A" lexbuf.Lexeme
-            failwithf "%A" e        
-        if not lexbuf.IsPastEndOfStream then
-            try
-                (QSLexer.tokenize lexbuf, lexbuf.StartPos.Line) |> listTokens.Add
-            with
-            | :? QSLexer.Lexical_error as e -> exnf e
-            | e -> exnf e
-            f (currIdx + 1)
-    f 0
-    printfn "lex ok"
-
-let rec y () = 
-    printfn "parse"
-    let read = File.ReadAllText("input")
-    let lexbuf = Lexing.LexBuffer<_>.FromString read
-    try
-        QSParser.start QSLexer.tokenize lexbuf
-    with | e -> 
-        printfn "%A" e.Message
-        let x = System.Console.ReadKey()
-        y()
-
-let writer = new StreamWriter("output")
-let writen t s = let s:string = sprintf t s in writer.WriteLine s
-
-QS.printLocs (y()) |> writer.Write
-writer.Close()
-
-printfn "Done!"
-Console.ReadKey () |> ignore

+ 0 - 161
QSParse/Program1.fs

@@ -1,161 +0,0 @@
-open System
-open System.IO
-open System.Text.RegularExpressions
-
-type Statement =
-    | If of string * Statement list * Statement list option 
-    | Act of string * Statement list
-    | End
-    | Other of string
-
-let test = [If ("true", [Other "dosomeshit"; Act("постучать", [Other "do"])], None); Other "do nothing"]
-
-let parseExpr str = 
-    let res = Regex.Match(str, "(.*?):")
-    if res.Success then res else failwith "kjf"
-
-let find str pattern =
-    let m = Regex.Match(str, pattern)
-    if m.Success then
-        Some(m.Value), str.[m.Length + m.Index .. str.Length - 1]
-    else
-        None, str
-
-let finds str pattern =
-    let m = Regex.Match(str, pattern, RegexOptions.Singleline)
-    if m.Success then
-        Some(m.Value), str.[m.Length + m.Index .. str.Length - 1]
-    else
-        None, str
-
-//let testFind = Regex.Match(rest, ".*end", RegexOptions.Singleline).Value
-
-printfn ""
-(*
-let rec parseStr = 
-    function
-    | "" -> []
-    | str -> 
-            match find str "(?<=\s)[\*a-zA-Z0-9_]+?(?=[\'|\(|\s|\"])" with
-            | Some(statement), rest ->
-                let parseBody () = 
-                    match find rest "(.*?):" with
-                    | Some(exprstr), rest ->
-                        match find rest "^\s*?\n" with // проверка на однострочность конструкции if
-                        | Some(bodyMatch), rest ->
-                            match finds rest ".*?(?=end)" with
-                            | Some(body), rest ->
-                                If(exprstr, parseStr body, None) :: (parseStr rest)
-                            | None, _ -> failwithf "не совпадает end! %s" rest
-                        | None, rest -> 
-                            match find rest ".*" with
-                            | Some(bodyMatch), rest -> If(exprstr, [Other(bodyMatch)], None) :: (parseStr rest)
-                            | None, rest -> failwithf ".* случилось невозможное! %s" rest
-                    | None, rest -> failwithf "(.*?): Syntax error %s" rest
-
-                if statement = "if" then
-                    parseBody ()
-                elif statement = "act" then
-                    parseBody ()
-                else
-                    match find rest ".+?\n" with
-                    | Some(args), rest -> Other(statement + args)::(parseStr rest)
-                    | None, rest -> Other(statement)::(parseStr rest)
-            | None, _ -> []
-*)
-
-let f rest = 
-    let rec parseStr2 = 
-                function
-                | [] -> None, []
-                | statement::rest ->
-                    let parseBody () = 
-                            let restend = ref rest
-                            let rec f' =
-                                    function
-                                    | None, _ -> failwithf "end not found %A" !restend
-                                    | Some( End ), rest -> restend := rest; []
-                                    | Some( state ), rest -> state :: (f' (parseStr2 rest))
-                            If ("", f'( parseStr2 rest ), None )
-                            |> Some, !restend
-
-                    match statement with
-                    | "if" -> parseBody ()
-                    //| "act" -> 
-                    | "end" -> Some(End), rest
-                    | _ -> Some(Other statement), rest
-
-    let rec f' = function
-                | None, _ -> []
-                | Some( End ), rest -> failwithf "какой-то левый end нарисовался %A" rest
-                | Some( state ), rest -> state :: (f' (parseStr2 rest))
-    in f'( parseStr2 rest )
-
-let prog = ["p1"; "p2"; "if"; "p3"; "p4"; "if"; "p5"; "p6"; "end"; "p7"; "end"; "p8"]
-
-let res = f prog
-
-//let res = parseStr2 (File.ReadAllText("tryparse.txt", Text.Encoding.Default))
-
-let progRaw = File.ReadAllText("tryparse.txt", Text.Encoding.Default)
-
-type Tokens =
-    | Word of string
-    | Other of string
-
-
-let parseWord input =
-    let tor = 
-        [("word", let word = @"[a-zA-Zа-яА-я]" in String.Format(@"(\${0}s|{0})+.*?({0}|\d*)*", word));
-        ("whitespace", @"[\s\t]");
-        ("newline", @"(\n|\r\n)");
-        ("str", @"'(?:\\.|[^'])*'");
-        ("jumpsign", @"#.*?" + @"(\n|\r\n)");
-        ("minuses", @"-{3,}");
-        ("tildes", @"~+");
-        ("defloc", @"Название локации:");
-        ("descloc", @"Описание локации:");
-        ("endloc", @"Конец локации:");]
-
-    let word = 
-        let word = @"[a-zA-Zа-яА-я]"
-        //@"(\$[a-zA-Zа-яА-я]|[a-zA-Zа-яА-я])+.*?([a-zA-Zа-яА-я]|\d*)*" //@"[[:word:]]+"
-        String.Format(@"(\${0}s|{0})+.*?({0}|\d*)*", word)
-    let whitespace = @"[\s\t]"
-    let newline = @"(\n|\r\n)"
-    let str = @"'(?:\\.|[^'])*'"
-    let jumpsign = @"#.*?" + newline
-    let minuses = @"-{3,}"
-    let tildes = @"~+"
-    let defloc = @"Название локации:"
-    let descloc = @"Описание локации:"
-    let endloc = @"Конец локации:"
-
-    let toks = [ defloc; descloc; endloc; word; whitespace; newline; str; jumpsign; minuses; tildes; ]
-               |> List.map (fun x -> "^" + x)
-    
-    let tryMatch str pattern = 
-            let m = Regex.Match(str, pattern, RegexOptions.Singleline)
-            if m.Success then
-                Some(m.Value, str.[m.Length + m.Index .. str.Length - 1])
-            else
-                None
-    
-    let rec s' = function
-        | "" -> []
-        | str ->
-            let rec f = function
-                    | [] -> (str.[0].ToString(), "unknown"), (str.[1..str.Length-1])
-                    | h::t -> match tryMatch str h with
-                              | Some(finded, rest) -> (finded, h), rest
-                              | None -> f t
-            f toks
-            |> (function h, rest -> h::s' rest)
-    s' input
-
-let res2 = parseWord progRaw
-res2
-|> List.iter (function a, b -> printfn "%s %s" a b)
-
-printf "Done!"
-Console.ReadKey() |> ignore

+ 0 - 148
QSParse/QS.fs

@@ -1,148 +0,0 @@
-module QS
-
-type value =
-    | Int of int  
-    | Float of float  
-    | String of string
-
-type Ops =
-    | Plus | Minus | Times | Divide | Mod
-    | Eq | Gt | Ge | Lt | Le | Ne   // =, >, >=, <, <=, (!, <>)
-    | And | Or
-    
-type UnarOp = Obj | No
-
-type Expr =
-    | Val of value
-    | Var of string
-    | Func of string * Expr list
-    | UnarExpr of UnarOp * Expr
-    | Expr of Ops * Expr * Expr
-//and Call = { FunName: string; Args: Expr list }
-// cond не покрывает случай когда в выражении стоит переменная типа bool или же напрямую 
-// одно из значений данного типа. К примеру: let var = true in if var then true else false
-//type If = { Cond:Expr; IfTrue:Statements list; Else: Statements list }
-//and Act = { Loc:string; ImagePath:string; Body: Statements list }
-type Statements =
-    | Assert of Expr * Expr
-    | AssertCode of Expr * Statements list
-    | ExprS of Expr // вообще, достаточно какой-нибудь функции с побочным действием.
-    | FuncS of string * Expr list
-    | StringS of string
-    | If of Expr * Statements list * Statements list
-    | Act of Expr list * Statements list
-    | Sign of string
-    | Comment of string
-    | Constr of string * Expr list * Statements list
-type Location = Location of string * Statements list
-
-let join s (xs:seq<string>) = System.String.Join(s, xs)
-let nl = "\r\n"
-let printState =
-    let brake s = "[" + s + "]"
-    let paren s = "(" + s + ")"
-    let value = function
-        | Int x -> x.ToString() | Float x -> x.ToString()
-        | String x -> "'" + x + "'"
-    let ops = function
-        | Plus -> "+" | Minus -> "-" | Times -> "*" | Divide -> "/"
-        | Eq -> "=" | Gt -> ">" | Ge -> ">=" | Lt -> "<" | Le -> "<" | Ne -> "!"   // =, >, >=, <, <=, !
-        | And -> "and" | Or -> "or" | Mod -> "mod"
-    let unar = function No -> "no" | Obj -> "obj"
-    let rec expr = function
-        | Val v -> value v
-        | Var v -> v
-        | Func("idx", (Var x)::t) -> x + (List.map expr t |> join ", " |> brake)
-        //| Func(x, [Func("idx", xs)]) -> x + (List.map expr xs |> join ", " |> brake)
-        | Func(x, xs) -> x + (List.map expr xs |> join ", " |> paren)
-        | UnarExpr(op, e) -> unar op + expr e |> paren
-        | Expr(op, e1, e2) -> expr e1 + " " + ops op + " " + expr e2 |> paren
-    
-    let tabss n = String.replicate n "\t"
-    let rec state tabs xs = 
-        let f = function [] -> "(NEWLINE)" | xs -> nl + join nl (List.map (state (tabs + 1)) xs)
-        //let f' = function [] -> "(NEWLINE)" | xs -> " " + join "&" (List.map (state 0) xs)
-        let rec f' = function
-            | Assert(e1, e2) -> expr e1 + " = " + expr e2
-            | AssertCode(e, xs) -> expr e + " = " + "{" + f xs + "}"
-            | ExprS e -> expr e
-            | Sign s -> ": " + s
-            | StringS x -> "'" + x + "'"
-            | If(e, [FuncS _ as x], []) -> "if " + expr e + ":" + " " + f' x
-            | If(e, [FuncS _ as x], [FuncS _ as y]) -> "if " + expr e + ":" + " " + f' x + " else " + f' y
-            | If(e, [Assert _ as x], []) -> "if " + expr e + ":" + " " + f' x
-            | If(e, xs, ys) -> 
-                let rec els = function
-                    | [] -> ""
-                    | [If(e, xs, ys)] -> nl + tabss tabs + "elseif " + expr e + ":" + f xs + els ys
-                    | ys -> nl + tabss tabs + "else" + f ys
-                "if " + expr e + ":" + f xs + els ys
-            | Act(es, [FuncS _ as x]) -> "act " + join ", " (List.map expr es) + ":" + " " + f' x
-            | Act(es, xs) -> "act " + join ", " (List.map expr es) + ":" + f xs
-            | Comment s -> "! " + s
-            | FuncS(name, xs) -> name + " " + (List.map expr xs |> join ", ")
-            | x -> failwithf "%A absent" x
-        tabss tabs + f' xs
-    state 0
-let printLoc (Location(name, statements)) = 
-    sprintf "# %s" name + nl +
-    join nl (List.map printState statements) + nl +
-    sprintf "--- %s ----------" name
-let printLocs xs = List.map printLoc xs |> join nl
-    
-assert
-    let sample =
-      If
-         (Var "v1",
-          [FuncS ("gs",[]);
-           If
-             (Var "v2",
-              [If
-                 (Var "v3",[Act ([Var "v4"],[FuncS ("gt",[])])],
-                  [If
-                     (Var "v5",[Act ([Var "v6"],[FuncS ("gt",[])])],
-                      [If
-                         (Var "v7",
-                          [Act
-                             ([Var "v8"],
-                              [Act ([Var "v9"],[FuncS ("gt",[])]);
-                               Act
-                                 ([Var "v10"],
-                                  [If
-                                     (Var "v",[Act ([Var "v"],[FuncS ("gt",[])])],
-                                      [If
-                                         (Var "v",
-                                          [Act ([Var "v"],[FuncS ("gt",[])])],[])])])])],
-                          [])])])],[]);
-           If
-             (Var "v",
-              [If
-                 (Var "v",
-                  [If
-                     (Var "v",
-                      [If
-                         (Var "v",
-                          [Act
-                             ([Var "v"],
-                              [FuncS ("gs",[]); Act ([Var "v"],[FuncS ("gt",[])])])],
-                          [])],
-                      [If
-                         (Var "v",
-                          [If
-                             (Var "v",
-                              [Act
-                                 ([Var "v"],
-                                  [FuncS ("gs",[]);
-                                   Act ([Var "v"],[FuncS ("gt",[])])])],[])],
-                          [If
-                             (Var "v",
-                              [If
-                                 (Var "v",
-                                  [Act
-                                     ([Var "v"],
-                                      [FuncS ("gs",[]);
-                                       Act ([Var "v"],[FuncS ("gt",[])])])],[])],
-                              [])])])],[])],[]); Act ([Var "v"],[FuncS ("gt",[])])],
-          [])
-    printState sample |> ignore
-    true

+ 0 - 225
QSParse/QSLexer.fsl

@@ -1,225 +0,0 @@
-{   
-module QSLexer
-open System
-open QSParser   
-open Microsoft.FSharp.Text.Lexing
-//
-let keywords =   
-    [
-        "end", END;
-        "and", AND;   
-        "or", OR; "else", ELSE; "elseif", ELSEIF; "if", IF; "act", ACT;
-        "set", SET; "let", LET; "no", NO; "obj", OBJ; "mod", MOD;
-    ] |> Map.ofList
-
-let ops =   
-    [
-        "+=",   EQP; "=+", EQP;
-        "-=", EQM; "=-", EQM; // x =-7 -> x = x - 7 или x = -7 ?
-        "++", INC; "--", DECR;
-        "=",    EQ;
-        "<",    LT;
-        "<=",   LE; "=<",   LE;
-        ">",    GT;
-        ">=",   GE; "=>",   GE; // точно есть
-        "!",    NEQ; "<>", NEQ;
-        "{",    LBRACE;
-        "}",    RBRACE;
-        "[",    LBRACK;
-        "]",    RBRACK;
-        "(",    LPAREN;
-        ")",    RPAREN;
-        "*",    TIMES;
-        "/",    DIVIDE;
-        "+",    PLUS;
-        "-",    MINUS;
-        
-    ] |> Map.ofList
-
-let brace_depth = ref 0
-let comment_depth = ref 0
-
-let in_pattern () = !brace_depth = 0 && !comment_depth = 0
-
-exception Lexical_error of string * string * int * int
-
-let string_buff = new System.Text.StringBuilder(256)
-
-let reset_string_buffer () = string_buff.Clear() |> ignore
-
-let store_string_char (c:char []) = string_buff.Append(c) |> ignore
-let store_string_chars (s:string) = string_buff.Append(s) |> ignore
-
-let get_stored_string () = string_buff.ToString() //Buffer.contents string_buff
-
-let char_for_backslash = function
-    | 'n' -> '\010'
-    | 'r' -> '\013'
-    | 'b' -> '\008'
-    | 't' -> '\009'
-    | c   -> c
-
-let raise_lexical_error (lexbuf:LexBuffer<_>) msg =
-    let p = lexbuf.StartPos in
-    raise (Lexical_error (msg,
-                        p.pos_fname,
-                        p.pos_lnum,
-                        p.pos_cnum - p.pos_bol + 1))
-
-let handle_lexical_error fn (lexbuf:LexBuffer<_>) =
-    let p = lexbuf.StartPos in
-    let line = p.pos_lnum
-    let column = p.pos_cnum - p.pos_bol + 1
-    let file = p.pos_fname
-    try fn lexbuf
-    with Lexical_error (msg, "", 0, 0) -> raise(Lexical_error(msg, file, line, column))
-
-let warning (lexbuf:LexBuffer<_>) msg =
-    let p = lexbuf.StartPos in
-    Printf.eprintf "ocamllex warning:\nFile \"%s\", line %d, character %d: %s.\n" p.pos_fname p.pos_lnum (p.pos_cnum - p.pos_bol + 1) msg;
-    //flush stderr
-
-let inline decimal_code  c d u =
-    100 * (int c - 48) + 10 * (int d - 48) + (int u - 48)
-
-let char_for_hexadecimal_code d u =
-    let d1 = int d in
-    let val1 = if d1 >= 97 then d1 - 87
-                else if d1 >= 65 then d1 - 55
-                else d1 - 48
-    in
-    let d2 = int u in
-    let val2 = if d2 >= 97 then d2 - 87
-                else if d2 >= 65 then d2 - 55
-                else d2 - 48
-    in
-    int (val1 * 16 + val2)
-
-let incr_loc (lexbuf:LexBuffer<_>) delta =
-    //let pos = lexbuf
-    (*
-	let incr_loc lexbuf delta =
-	  let pos = lexbuf.Lexing.lex_curr_p in
-	  lexbuf.Lexing.lex_curr_p <- { pos with
-		Lexing.pos_lnum = pos.Lexing.pos_lnum + 1;
-		Lexing.pos_bol = pos.Lexing.pos_cnum - delta;
-	  }*)
-    let pos = lexbuf.StartPos
-    printfn "curr %d" pos.pos_lnum
-    lexbuf.StartPos <- { pos with Lexing.pos_lnum = pos.pos_lnum + 1; Lexing.pos_bol = pos.pos_cnum - delta; }
-    printfn "CURR %d" lexbuf.StartPos.pos_lnum
-
-let update_loc (lexbuf:LexBuffer<_>) opt_file line =
-    let pos = lexbuf.StartPos
-    let new_file = match opt_file with
-                    | None -> pos.pos_fname
-                    | Some f -> f
-    lexbuf.StartPos <- { pos with Lexing.pos_fname = new_file; Lexing.pos_lnum = line; Lexing.pos_bol = pos.pos_cnum; }
-let decr (lexbuf:LexBuffer<_>) a =
-    let pos = lexbuf.StartPos
-    lexbuf.StartPos <- { pos with Lexing.pos_cnum = pos.pos_cnum - Array.length a; }
-
-let comment = ref true
-let newlineL (lexbuf:LexBuffer<_>) = lexbuf.EndPos <- lexbuf.EndPos.NextLine
-let newlinen (lexbuf:LexBuffer<_>) = lexbuf.Lexeme |> Array.sumBy(function '\r' | '\n' -> 1 | _ -> 0) |> fun x -> x / 2 |> fun x -> for i = 1 to x do newlineL lexbuf
-}
-
-let char        = ['a'-'z' 'A'-'Z' 'а'-'я' 'А'-'Я']
-let digit       = ['0'-'9']
-//let int         = '-'?digit+ // 1 - 1 -> [Int 1; Int -1]
-let int         = digit+
-//let float       = '-'?digit+ '.' digit+
-let float       = digit+ '.' digit+
-//let identifier  = char (char|digit|['-' '_' '.'])* // ловит "chars--"
-let identifier  = char (char|digit|['_' '.']|('-'(char|digit)+))* // ловит "chars--"
-let whitespace  = [' ' '\t']
-let newline     = "\r\n" | '\n' //"\n\r" | '\n' | '\r'
-let operator = "!" | "(" | ")" | "*" | "+" | "++" | "+=" | "-" | "--" | "-=" | "/" | "<" | "<=" | "<>" | "=" | "=+" | "=-" | "=<" | "=>" | ">" | ">=" | "[" | "]" | "{" | "}"
-let backslash_escapes = ['\\' '\'' '"' 'n' 't' 'b' 'r' ' ']
-
-
-rule tokenize = parse
-| '!'                          { if !comment then // если перед ним было ('&'|nl) {whitespace}
-                                     comment := false; reset_string_buffer(); handle_lexical_error comm lexbuf; COMMENT(get_stored_string())
-                                 else NEQ }
-| whitespace                   { tokenize lexbuf }
-| newline(newline|whitespace)* { comment := true; newlinen lexbuf; NEWLINE }
-| int                          { comment := false; INT(Int32.Parse(LexBuffer<_>.LexemeString lexbuf)) }
-| float                        { comment := false; FLOAT(Double.Parse(LexBuffer<_>.LexemeString lexbuf)) }
-//| '$'			               { comment := false; DOLLAR }
-| '&'			               { comment := true; AMP }
-| '#' [^'\r''\n']+             { comment := false;
-                                 let join sep (xs:seq<char>) = System.String.Join(sep, xs)
-                                 let r = lexbuf.Lexeme |> Seq.skip 2 |> join "" |> STARTLOC
-                                 //printfn "%A" r;
-                                 r}
-| '\''                         { comment := false; reset_string_buffer(); handle_lexical_error string lexbuf; TSTRING(get_stored_string())  }
-| '"'                          { comment := false; reset_string_buffer(); handle_lexical_error string2 lexbuf; TSTRING(get_stored_string())  }
-| ','			               { comment := false; COMMA }
-| operator                     { comment := false; ops.[LexBuffer<_>.LexemeString lexbuf] }
-| identifier                   { comment := false;
-                                 match keywords.TryFind((LexBuffer<_>.LexemeString lexbuf).ToLower()) with   
-                                 | Some(token) -> token
-                                 | None -> ID(LexBuffer<_>.LexemeString lexbuf) }
-| '$' identifier               { comment := false; ID(LexBuffer<_>.LexemeString lexbuf) }
-//| "--- " identifier " ---------------------------------" { comment := true; ENDLOC }
-| "--- " [^'\r''\n']+           { comment := true; ENDLOC }
-| ':'			               { comment := false; COLON }
-| eof                          { EOF }
-| _ 			               { failwith "tokenize error" }
-(*
-and nl = parse
-| newline { newlineL lexbuf; nl lexbuf }
-| whitespace { nl lexbuf }
-| _ { decr lexbuf [|1..10|]; () } *)
-
-and comm = parse
-| '\'' { handle_lexical_error string lexbuf; comm lexbuf  }
-| '"' { handle_lexical_error string2 lexbuf; comm lexbuf }
-| '{' { handle_lexical_error stringBrace lexbuf; comm lexbuf }
-//| newline { decr lexbuf lexbuf.Lexeme; () }
-//| eof { printfn "eof"; decr lexbuf lexbuf.Lexeme; () }
-| [^'\n''\r'] { store_string_char lexbuf.Lexeme; comm lexbuf }
-| '\r' { newlineL lexbuf; () }
-
-and stringBrace = parse
-   | '}' { () }
-   | '\\' backslash_escapes
-    { store_string_char [| char_for_backslash lexbuf.Lexeme.[1] |]; stringBrace lexbuf }
-  | eof
-    { raise(Lexical_error("unterminated string", "", 0, 0)) }
-  | newline { newlineL lexbuf; stringBrace lexbuf }
-  | _
-    { store_string_char lexbuf.Lexeme; stringBrace lexbuf }
-
-and string = parse
-   | "''" { store_string_char lexbuf.Lexeme; string lexbuf }
-   | '\'' { () }
-   | '\\' backslash_escapes
-    { store_string_char [| char_for_backslash lexbuf.Lexeme.[1] |]; string lexbuf }
-  | eof
-    { raise(Lexical_error("unterminated string", "", 0, 0)) }
-  | newline { newlineL lexbuf; string lexbuf }
-  | _
-    { store_string_char lexbuf.Lexeme; string lexbuf }
-
-and string2 = parse
-   | "\"\"" { store_string_char lexbuf.Lexeme; string2 lexbuf }
-   | '"' { () }
-   | '\\' backslash_escapes
-    { store_string_char [| char_for_backslash lexbuf.Lexeme.[1] |]; string2 lexbuf }
-  | eof
-    { raise(Lexical_error("unterminated string", "", 0, 0)) }
-  | newline { newlineL lexbuf; string2 lexbuf }
-  | _
-    { store_string_char lexbuf.Lexeme; string2 lexbuf }
-(*
-and location = parse
-	| newline { newlineL lexbuf; string lexbuf }
-	| whitespace { location lexbuf }
-	| '#' identifier { reset_string_buffer(); store_string_char lexbuf.Lexeme; handle_lexical_error locCounter lexbuf; LOCATIONRAW(get_stored_string()) }
-	| _ { failwithf "перед началом локации обнаружено это %A" lexbuf.Lexeme }
-and locCounter = parse
-	| "--- " identifier " ---------------------------------" { store_string_char lexbuf.Lexeme }
-	| eof { raise(Lexical_error("конец файла наступил раньше чем конец локации", "", 0, 0)) }
-	| _ { store_string_char lexbuf.Lexeme; locCounter lexbuf } *)

+ 9 - 63
QSParse/QSParse.fsproj

@@ -1,73 +1,19 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
-    <ProductVersion>8.0.30703</ProductVersion>
-    <SchemaVersion>2.0</SchemaVersion>
-    <ProjectGuid>{6ecf54c2-777c-4275-bc5d-e48fa61a4627}</ProjectGuid>
     <OutputType>Exe</OutputType>
-    <RootNamespace>QSParse</RootNamespace>
-    <AssemblyName>QSParse</AssemblyName>
-    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
-    <TargetFrameworkProfile>Client</TargetFrameworkProfile>
-    <Name>QSParse</Name>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>true</Optimize>
-    <Tailcalls>true</Tailcalls>
-    <OutputPath>bin\Debug\</OutputPath>
-    <DefineConstants>DEBUG;TRACE</DefineConstants>
-    <WarningLevel>3</WarningLevel>
-    <PlatformTarget>x86</PlatformTarget>
-    <DocumentationFile>bin\Debug\QSParse.XML</DocumentationFile>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
-    <DebugType>pdbonly</DebugType>
+    <TargetFramework>net461</TargetFramework>
     <Optimize>true</Optimize>
     <Tailcalls>true</Tailcalls>
-    <OutputPath>bin\Release\</OutputPath>
-    <DefineConstants>TRACE</DefineConstants>
-    <WarningLevel>3</WarningLevel>
-    <PlatformTarget>x86</PlatformTarget>
-    <DocumentationFile>bin\Release\QSParse.XML</DocumentationFile>
   </PropertyGroup>
-  <Import Project="$(MSBuildExtensionsPath32)\FSharp\1.0\Microsoft.FSharp.Targets" Condition="!Exists('$(MSBuildBinPath)\Microsoft.Build.Tasks.v4.0.dll')" />
-  <Import Project="$(MSBuildExtensionsPath32)\..\Microsoft F#\v4.0\Microsoft.FSharp.Targets" Condition=" Exists('$(MSBuildBinPath)\Microsoft.Build.Tasks.v4.0.dll')" />
   <ItemGroup>
-    <Compile Include="QS.fs" />
-    <None Include="Program1.fs" />
-    <None Include="QSParser.fsp" />
-    <None Include="QSLexer.fsl" />
-    <None Include="QSParser.fsyacc.output" />
-    <Compile Include="QSParser.fsi" />
-    <Compile Include="QSParser.fs" />
-    <Compile Include="QSLexer.fs" />
-    <Compile Include="Program.fs" />
+    <None Include="App.config" />
+    <Compile Include="Ast.fs" />
+    <Compile Include="Parser.fs" />
   </ItemGroup>
   <ItemGroup>
-    <Reference Include="FSharp.PowerPack, Version=2.0.0.0, Culture=neutral, PublicKeyToken=a19089b1c74d0809" />
-    <Reference Include="mscorlib" />
-    <Reference Include="FSharp.Core" />
-    <Reference Include="System" />
-    <Reference Include="System.Core" />
-    <Reference Include="System.Numerics" />
+    <None Include="App.config" />
+    <Reference Include="System.Runtime" />
+	<Reference Include="$(FsharpMyExtension)" />
   </ItemGroup>
-  <PropertyGroup>
-    <PreBuildEvent />
-  </PropertyGroup>
-  <PropertyGroup>
-    <PreBuildEvent>REM fslex.exe "$(ProjectDir)QSLexer.fsl" --unicode
-$(SolutionDir)RunIfChange\bin\Debug\RunIfChange.exe fslex.exe "$(ProjectDir)QSLexer.fsl" --unicode
-$(SolutionDir)RunIfChange\bin\Debug\RunIfChange.exe fsyacc.exe "$(ProjectDir)QSParser.fsp" --module QSParser -v</PreBuildEvent>
-  </PropertyGroup>
-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
-	     Other similar extension points exist, see Microsoft.Common.targets.
-	<Target Name="BeforeBuild">
-	</Target>
-	<Target Name="AfterBuild">
-	</Target>
-	-->
+  <Import Project="..\.paket\Paket.Restore.targets" />
 </Project>

+ 194 - 0
QSParse/QSParsecTest.fsx

@@ -0,0 +1,194 @@
+module QSParsecTest
+
+#if INTERACTIVE
+#r @"..\packages\FParsec.1.0.2\lib\net40-client\FParsecCS.dll"
+#r @"..\packages\FParsec.1.0.2\lib\net40-client\FParsec.dll"
+#endif
+
+#if INTERACTIVE
+#load "reflect.fs"
+#load "QSAST.fs"
+#load "show.fs"
+#endif
+#if INTERACTIVE
+#load "QSParsec.fs"
+#endif
+open FParsec
+open QSParsec
+open QSAST
+open Show
+
+let parsingP p = parsing p >> printfn "%A"
+
+parsingP pexpr "sprintchance =< nochance" // sprintchance =< (no chance)
+parsingP pstmt "a = obj 's'"
+parsingP pstmt "a =- 10"
+parsingP pstmt "a = a + 10"
+parsingP pstmt "if c:
+smt
+act arg: pl
+elseif c2:
+if a: k else pre if cond: d  elseif celif: d
+stmt2
+end"
+
+parsingP pstmt "if x:
+s = {
+s
+}
+end"
+parsingP pstmt "if a: k else pre if cond: d  elseif celif: d"
+
+parsingP pstmt "IF e:
+stmt1 & stmt
+elseif e2 : 
+    stmt2 
+    stmt3
+elseif e3 : 
+    end2
+    if e4 :
+        stmt5
+    elseif e5:
+        tm
+        elsei
+    end
+end
+"
+
+parsingP pstmt "if k:
+wear += 1
+end"
+
+//System.Text.Encoding.Default
+//System.Text.Encoding.UTF8
+parsing (many ploc) (System.IO.File.ReadAllText(@"e:\Disc D\All\It\DefaultBox\drive\C\All2\Games\GamesSourceCode\etoEdit.txt", System.Text.Encoding.UTF8))
+|> ignore
+//|> fun x -> System.IO.File.WriteAllText(@"e:\res.txt", sprintf "%A" x)
+parsing (many ploc) (System.IO.File.ReadAllText(@"e:\Disc D\All\It\DefaultBox\drive\C\All2\Games\GamesSourceCode\al.txt"))
+|> ignore
+//|> fun x -> System.IO.File.WriteAllText(@"e:\res.txt", sprintf "%A" x)
+
+
+
+
+let printState =
+    let showValue = function
+        | Int x -> shows x //| Float x -> x.ToString()
+        | String x -> bet "'" "'" (x.Replace("'", "''") |> showString)
+    let ops = Op.toString >> showString
+//    let ops = function
+//        | Plus -> "+" | Minus -> "-" | Times -> "*" | Divide -> "/"
+//        | Eq -> "=" | Gt -> ">" | Ge -> ">=" | Lt -> "<" | Le -> "<=" | Ne -> "<>"   // =, >, >=, <, <=, (<>|!)
+//        | And -> "and" | Or -> "or" | Mod -> "mod"
+    let unar = function No -> "no" | Obj -> "obj" | Neg -> "-"
+    let rec showExpr = function
+        | Val v -> showValue v
+        | Var v -> showString v
+        | Func(name, es) -> showString name << showParen true (List.map showExpr es |> joinS ", ")
+        | UnarExpr(op, e) ->
+            let space = function Obj | No -> showChar ' ' | Neg -> id
+            showString (unar op) << space op << showExpr e
+        //| Expr(op, e1, e2) -> showExpr e1 << showChar ' ' << showString(ops op) << showChar ' ' << showExpr e2
+        | Expr(op, e1, e2) -> 
+            let prec = Precedences.OpB >> Precedences.prec
+            let f = function
+                | Expr(op', _, _) -> showParen (prec op > prec op')
+                | UnarExpr _ -> showParen true | _ -> id
+            let f x = f x (showExpr x)
+            f e1 << showChar ' ' << ops op << showChar ' ' << f e2
+        | Arr(name, es) -> showString name << bet "[" "]" (List.map showExpr es |> joinS ", ")
+    let showAssign = function
+        | Assign.AssignArr(nameVar, expr) -> showString nameVar << bet "[" "]" (showExpr expr)
+        | Assign.AssignVar name -> showString name
+    
+    let (|OneStmt|_|) = function
+        | [x] -> 
+            match x with
+            | Assign _ | CallSt _ | StarPl _ | Comment _ -> Some x
+            | AssingCode _ -> None // спорно
+            | Act _ | If _ -> None
+            | Sign _ -> None // эту нечисть нужно как можно более нагляднее подчеркнуть. Да странно будет, если она окажется одна в списке инструкций.
+        | _ -> None
+    
+    //let (OneStmt x) = [ parsing pstmt "a = 1"; ]
+    let (|AssingName|) = function AssignArr(x, _) -> x | AssignVar x -> x
+    let tabss n = Show.replicate n '\t'
+    let rec state tabs xs = 
+        let f = function [] -> nl | xs -> nl << joinS "\n" (List.map (state <| tabs + 1) xs)
+
+        let indent = nl << tabss tabs : ShowS
+        let rec f' = function
+            | Assign(AssingName name' as ass, Expr((Plus|Minus) as op, Var name, e)) when name' = name -> 
+                showAssign ass << showChar ' ' << ops op << showString "= " << showExpr e
+            | Assign(AssingName name' as ass, Expr((Plus|Minus) as op, e, Var name)) when name' = name -> 
+                showAssign ass << showString " =" << ops op << showChar ' ' << showExpr e
+            | Assign(ass, e) -> showAssign ass << showString " = " << showExpr e
+            | CallSt(name, es) -> showString name << showChar ' ' << (List.map showExpr es |> joinS ", ")
+            | StarPl e -> showExpr e
+            | Sign s -> showChar ':' << showString s
+            | If(e, body, elseBody) -> 
+                let ifBegin e = showString "if " << showExpr e << showChar ':'
+                let body = 
+                    match body, elseBody with
+                    | OneStmt x, OneStmt y -> showChar ' ' << f' x << showString " else " << f' y
+                    | OneStmt x, [] -> showChar ' ' << f' x
+                    //| [CallSt _ as x], [CallSt _ as y] -> showChar ' ' << f' x << showString " else " << f' y
+                    //| [Assign _ as x], [] | [CallSt _ as x], [] | [StarPl _ as x], [] -> showChar ' ' << f' x
+                    | xs, ys -> 
+                        let rec els xs =
+                            if List.isEmpty xs then id
+                            else 
+                                let body = function [If(e, xs, ys)] -> ifBegin e << f xs << els ys | xs -> f xs
+                                indent << showString "else" << body xs
+//                            | [] -> id
+//                            | [If(e, xs, ys)] -> 
+//                                indent << showString "else" << ifBegin e << f xs << els ys
+//                            | ys -> 
+//                                indent << showString "else" << f ys
+                        f xs << els ys << indent << showString "end"
+                ifBegin e << body
+            | Act(es, body) -> 
+                let fbody = function
+                    | OneStmt x -> showChar ' ' << f' x
+                    | xs -> f xs << indent << showString "end"
+                showString "act " << joinS ", " (List.map showExpr es) << showChar ':' << fbody body
+            | Comment s -> showChar '!' << showString s
+            | AssingCode(ass, stmts) -> 
+                showAssign ass << showString " = " << showChar '{' << nl << (f stmts) << indent << showChar '}'
+        tabss tabs << f' xs
+    state 0
+let showLoc (Location(name, statements)) = 
+    showString "# " << showString name << nl
+    << joinS "\n" (List.map printState statements) << nl
+    << showString (sprintf "--- %s ----------" name)
+let printLocs xs = List.map showLoc xs |> joinS "\n\n" |> show
+
+let s = parsing pstmt "k = k + 1" //"a = a = (no a) > b"
+let s' = parsing pstmt "a = a = no (a > b)"
+let test p s =
+    let p = parsing p
+    let before = p s
+    let after = printState before |> show |> p
+    if  after <> before then failwithf "before:\n%A\nafter:\n%A" before after
+test pstmt "a = a = no -a > b"
+parsingP pstmt "asdf obj 'Персонаж'"
+parsingP pstmt "a = pstam> (pmaxstam/4)*2 and pstam <= (pmaxstam/4)*3"
+test pstmt "php -= 3*emdmg*2 - parm"
+parsing pstmt """php =+ 3*emdmg*2 - parm"""
+|> printState |> show |> printfn "%A"
+printState s |> show |> printfn "%s"
+printState s' |> show |> printfn "%s"
+
+let str = System.IO.File.ReadAllText(@"e:\Disc D\All\It\DefaultBox\drive\C\All2\Games\GamesSourceCode\destiny 0.5.txt", System.Text.Encoding.Default)
+let res = parsing (many ploc) str
+let test2 =
+    let f x = 
+        let s = printState x |> show
+        if s |> parsing pstmt = x then None
+        else Some(s)
+
+    List.choose (function Location(name, stmts) -> match List.choose f stmts with [] -> None | xs -> Some(name, xs)) res
+
+res |> fun x -> System.IO.File.WriteAllText(@"e:\res.txt", printLocs x)
+
+//System.IO.File.WriteAllLines(@"e:\res2.txt", test2)

+ 0 - 228
QSParse/QSParser.fsp

@@ -1,228 +0,0 @@
-%{   
-open QS
-
-let except str =  failwithf "%s" str
-let exceptP (p:Parsing.IParseState) str = 
-    let p = p.ParserLocalStore.["LexBuffer"] :?> Microsoft.FSharp.Text.Lexing.LexBuffer<char>
-    
-    printfn "%A" p.Lexeme
-    printfn "%A" p.StartPos
-    printfn "%A" p.EndPos
-
-    failwithf "%s" str
-
-let parse_error_rich = Some (fun (ctxt: Microsoft.FSharp.Text.Parsing.ParseErrorContext<_>) -> 
-    let p =
-        ctxt.ParseState.ParserLocalStore.["LexBuffer"] :?> Microsoft.FSharp.Text.Lexing.LexBuffer<char>
-        //|> unbox
-    printfn "%A" ctxt.CurrentToken
-    printfn "%A" p.Lexeme
-    printfn "%A" p.StartPos
-    printfn "%A" p.EndPos
-    printfn "start col: %d" p.StartPos.Column
-    printfn "%A" (p.StartPos.AbsoluteOffset, ctxt.CurrentToken))
-
-%}
-  
-%token <string> ID COMMENT TSTRING
-%token <int> INT   
-%token <float> FLOAT
-%token <string> STARTLOC
-%token ENDLOC
-//%token 
-
-%token PLUS MINUS TIMES DIVIDE
-%token EQ GT GE LT LE // =, >, >=, <, <=
-%token MOD
-%token AND OR
-%token COMMA
-%token AMP // &
-%token LBRACE RBRACE // { }
-%token LBRACK RBRACK // [ ]
-%token LPAREN RPAREN // ( )
-%token NO OBJ
-
-%token EOF
-
-%token SHARP
-%token DOLLAR
-
-%token IF ACT
-%token COLON ELSE ELSEIF
-%token NEWLINE
-%token END
-%token SET LET
-%token EQP EQM INC DECR // += -= ++ --
-%token NEQ // ! | <>
-
-// associativity and precedences
-// очередность [%left; %left; ...] влияет! Чем ниже - тем приоритетнее операция.
-
-%left OR
-%left AND
-%right NO
-%left EQ GT GE LT LE NEQ
-%right OBJ
-%left PLUS MINUS
-%left MOD
-%left TIMES DIVIDE
-%left NEWLINE
-%nonassoc RPAREN
-%nonassoc LPAREN
-%left COMMA
-%left COLON
-%left AMP
-
-//%nonassoc NEWLINE
-
-// start   
-%start start parseStatements
-%type <QS.Location list> start
-%type <QS.Statements list> parseStatements
-//%type <QS.Statements list> start
-
-%%
-start:
-    //|  {  { Location.Name = ""; Location.Statements = [] } }
-	| error { except "blah-blah" }
-	| EOF { [] }
-    | NEWLINE start { $2 }
-    | loc start { $1::$2 }
-
-parseStatements:
-    | NEWLINE parseStatements { $2 }
-	| EOF { [] }
-	| statements { $1 }
-
-loc:
-	| error { except "error in loc" }
-    | STARTLOC NEWLINE 
-          statements
-      ENDLOC { Location($1, $3) }
-    //| { exceptP parseState "начало локации не найдено" }
-
-end_:
-    | { failwithf "отсутствует end" }
-    | END { }
-
-elseif:
-    | ELSEIF expr COLON NEWLINE statements { [If($2, $5, [])] }
-    | ELSEIF expr COLON NEWLINE statements elseif { [If($2, $5, $6)] }
-	| ELSEIF expr COLON NEWLINE statements ELSE NEWLINE statements { [If($2, $5, $8)] }
-
-
-statements:
-    | { [] }
-	| error { except "statements" }
-    | states NEWLINE statements { $1@$3 }
-    | assertOp EQ LBRACE NEWLINE statements RBRACE NEWLINE statements  { AssertCode($1, $5) :: $8 }
-    | COMMENT NEWLINE statements { Comment $1::$3 }
-    | COLON ID NEWLINE statements { Sign $2::$4 }
-
-	| ACT seq_ COLON states NEWLINE statements { Act($2, $4)::$6 }
-    | ACT seq_ COLON IF expr COLON states NEWLINE statements { Act($2, [If($5, $7, [])])::$9 }
-	| ACT seq_ COLON ACT seq_ COLON states NEWLINE statements { Act($2, [Act($5, $7)])::$9 }
-	| ACT seq_ COLON NEWLINE statements END NEWLINE statements { Act($2, $5)::$8 }
-
-    | IF expr COLON states NEWLINE statements { If($2, $4, [])::$6 }
-	| IF expr COLON IF expr COLON states NEWLINE statements { If($2, [If($5, $7, [])], [])::$9 }
-	| IF expr COLON ACT seq_ COLON states NEWLINE statements { If($2, [Act($5, $7)], [])::$9 }
-    | IF expr COLON NEWLINE statements END NEWLINE statements { If($2, $5, [])::$8 }
-
-	| IF expr COLON states ELSE states NEWLINE statements { If($2, $4, $6)::$8 }
-    | IF expr COLON NEWLINE statements ELSE NEWLINE statements END NEWLINE statements { If($2, $5, $8)::$11 }
-	| IF expr COLON NEWLINE statements elseif END NEWLINE statements { If($2, $5, $6)::$9 }
-	//| ID seq_ COLON states NEWLINE statements { Constr($1, $2, $4)::$6 }
-    //| ID seq_ COLON ID seq_ COLON states NEWLINE statements { Constr($1, $2, [Constr($4, $5, $7)])::$9 }
-    //| ID seq_ COLON states ELSE states NEWLINE statements { Constr($1, $2, $4 @ $6)::$8 }
-	//| ID seq_ COLON NEWLINE statements END NEWLINE statements { Constr($1, $2, $5)::$8 }
-	//| IF expr COLON NEWLINE statements ELSEIF expr COLON NEWLINE statements END NEWLINE statements { If($2, $5, [If($7, $10, [])])::$13 }
-	//| ELSEIF expr COLON NEWLINE statements { [If($2, $5, [])] }
-    //| ID seq_ COLON NEWLINE statements ELSE NEWLINE statements END NEWLINE statements { Constr($1, $2, $5 @ $8)::$11 }
-    
-states: 
-	| state AMP ACT seq_ COLON states { $1::[Act($4, $6)] }
-    | state AMP states { $1 :: $3 }
-    | state AMP COMMENT { $1::[Comment $3] }
-    | state { [$1] }
-
-id:
-    | ID { $1 }
-    | TIMES ID { "*" + $2 }
-temp:
-	| id { Func($1, []) }
-	| id LPAREN RPAREN { Func($1, []) }
-	| id LPAREN expr COMMA seq_ RPAREN { Func($1, $3::$5) }
-	| TSTRING { Val(value.String $1) }
-
-state:
-    | assertOp EQ expr { Assert( $1, $3 ) } 
-	| assertOp EQ ID val_ { Assert( $1, Func($3, [Val $4]) ) } // st_1 = input 'Введите сумму'
-	| assertOp EQP expr { Assert( $1, Expr(Plus, $1, $3) ) }
-	| assertOp EQM expr { Assert( $1, Expr(Minus, $1, $3) ) }
-    /*
-    Общий вид вызова оператора
-        имя_оператора аргумент1, аргумент2, ...
-    или
-        имя_оператора (аргумент1, аргумент2, ...) */
-    //id f(v)
-    //id v, v2
-    //*pl 'Яблок' + яблоко
-    //*pl 'Груш' + груша
-	| temp { ExprS $1 }
-	| temp PLUS expr { ExprS( Expr(Plus, $1, $3) ) }
-	| id seq_ { FuncS($1, $2) }
-
-ass:
-	| id { Var $1 }
-    | SET id { Var $2 }
-    | LET id { Var $2 }	
-
-assertOp:
-    //| id { Var $1 }
-    //| id LBRACK seq_ RBRACK { Func("idx", (Var $1)::$3) }
-	| ass { $1 }
-	| ass LBRACK seq_ RBRACK { Func("idx", $1::$3) }
-
-seq_:
-    | expr COMMA seq_ { $1 :: $3 }
-    | expr { [$1] }
-    //| { [] }
-
-seqval:
-    | val_ COMMA seqval { (Val $1)::$3 }
-    | val_ { [Val $1] }
-    //| { [] }
-
-expr:
-    | val_ { Val $1 }
-    | ID { Var $1 }
-    | ID LPAREN RPAREN        { Func($1, []) }
-    | ID LPAREN seq_ RPAREN   { Func($1, $3) }
-    | ID LBRACK seq_ RBRACK   { Func("idx", (Var $1)::$3) }
-    
-	| NO expr { UnarExpr(No, $2) }  //if ((a+b)/c)=45+54 or (b<5 or c>45) and no obj 'лопата' and $f=$vvv+'RRRRR':p 'OK' & goto 'Next'
-	| OBJ expr { UnarExpr(Obj, $2) }
-
-    | LPAREN expr RPAREN      { $2 }
-    
-    | expr PLUS expr          { Expr.Expr(Plus, $1, $3) } 
-    | expr MINUS expr         { Expr.Expr(Minus, $1, $3) } 
-    | MINUS INT %prec MINUS   { Val(Int -$2) }
-    | expr TIMES expr         { Expr.Expr(Times, $1, $3) } 
-    | expr DIVIDE expr        { Expr.Expr(Divide, $1, $3) }
-    | expr EQ expr            { Expr.Expr(Eq, $1, $3) }
-    | expr GT expr            { Expr.Expr(Gt, $1, $3) }
-    | expr GE expr            { Expr.Expr(Ge, $1, $3) }
-    | expr LT expr            { Expr.Expr(Lt, $1, $3) }
-    | expr LE expr            { Expr.Expr(Le, $1, $3) }
-    | expr NEQ expr           { Expr.Expr(Ne, $1, $3) }
-    | expr AND expr           { Expr.Expr(And, $1, $3) }
-    | expr OR expr            { Expr.Expr(Or, $1, $3) }
-	| expr MOD expr           { Expr(Mod, $1, $3) }
-
-val_:
-    | INT { Int $1 }
-    | FLOAT { Float $1 }
-    | TSTRING { value.String $1 }
-%%

+ 2 - 0
QSParse/paket.references

@@ -0,0 +1,2 @@
+FSharp.Core
+FuChu

+ 0 - 62
QSTools/Program.fs

@@ -1,62 +0,0 @@
-module Program
-#if INTERACTIVE
-#r @"..\..\bin\Debug\QSParse.exe"
-#endif
-open QS
-
-module codeTools = 
-    let filter func statemetns =
-        let rec f acc = function
-            | [] -> acc |> List.rev
-            | h::t ->
-                if func h then f (h::acc) t
-                else
-                    match h with
-                    | Act(x, xs) ->
-                        match f [] xs with
-                        | [] -> f acc t
-                        | xs -> f (Act(x, xs)::acc) t
-                    | AssertCode(e, xs) ->
-                        match f [] xs with
-                        | [] -> f acc t
-                        | xs -> f (AssertCode(e, xs)::acc) t
-                    | If(x, xs, ys) ->
-                        let xs = f [] xs
-                        let ys = f [] ys
-                        if List.isEmpty xs && List.isEmpty ys then f acc t
-                        else f (If(x, xs, ys)::acc) t
-                    | _ -> f acc t
-        f [] statemetns    
-    let filterSimple func statemetns =
-        let rec f acc = function
-            | [] -> acc |> List.rev
-            | h::t ->
-                match func h with
-                | Some x -> f (x::acc) t
-                | None ->
-                    match h with
-                    | Act(x, xs) -> f (f acc xs) t
-                    | AssertCode(e, xs) -> f (f acc xs) t
-                    | If(x, xs, ys) -> f (f (f acc xs) ys) t
-                    | _ -> f acc t
-        f [] statemetns
-
-let p = Program.parseFile @"game.txt"
-let filter f = 
-    let f = codeTools.filter f
-    let res = 
-        List.choose (function Location(name, xs) -> 
-                              match f xs with [] -> None | xs -> Location(name, f xs) |> QS.printLoc |> Some) p
-    System.IO.File.WriteAllLines(@"c:\All\Project\Parsers\QSParse\QSParse\bin\Debug\output.txt", res)
-
-filter (function FuncS(name, _) -> Set.contains name (set["gt"; "goto"; "xgt"; "xgoto"; "gs"; "gosub"]) | _ -> false)
-filter (function FuncS("gt",Val (String "office")::_) -> true | _ -> false)
-filter (function Assert(_, _) -> true | _ -> false)
-
-Program.parse "'some text' + var + 'some text2'\r\n"
-let res2 f = List.choose (function Location(name, xs) -> match codeTools.filterSimple f xs with [] -> None | xs -> Some xs) p
-
-res2 (function StringS _ as x -> Some x | ExprS _ as x -> Some x | _ -> None)
-res2 (function AssertCode(name, _) -> AssertCode(name, []) |> Some | _ -> None) |> List.concat
-|> Seq.groupBy id
-|> Seq.map (fun (key, v) -> key, Seq.length v) |> List.ofSeq |> List.filter (snd >> ((<)2))

+ 0 - 63
QSTools/QSTools.fsproj

@@ -1,63 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
-    <ProductVersion>8.0.30703</ProductVersion>
-    <SchemaVersion>2.0</SchemaVersion>
-    <ProjectGuid>{8e6003cd-564c-4a80-b7ac-168e6e28caf6}</ProjectGuid>
-    <OutputType>Exe</OutputType>
-    <RootNamespace>QSTools</RootNamespace>
-    <AssemblyName>QSTools</AssemblyName>
-    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
-    <TargetFrameworkProfile>Client</TargetFrameworkProfile>
-    <Name>QSTools</Name>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <Tailcalls>false</Tailcalls>
-    <OutputPath>bin\Debug\</OutputPath>
-    <DefineConstants>DEBUG;TRACE</DefineConstants>
-    <WarningLevel>3</WarningLevel>
-    <PlatformTarget>x86</PlatformTarget>
-    <DocumentationFile>bin\Debug\QSTools.XML</DocumentationFile>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <Tailcalls>true</Tailcalls>
-    <OutputPath>bin\Release\</OutputPath>
-    <DefineConstants>TRACE</DefineConstants>
-    <WarningLevel>3</WarningLevel>
-    <PlatformTarget>x86</PlatformTarget>
-    <DocumentationFile>bin\Release\QSTools.XML</DocumentationFile>
-  </PropertyGroup>
-  <ItemGroup>
-    <Reference Include="mscorlib" />
-    <Reference Include="FSharp.Core" />
-    <Reference Include="System" />
-    <Reference Include="System.Core" />
-    <Reference Include="System.Numerics" />
-  </ItemGroup>
-  <ItemGroup>
-    <Compile Include="Program.fs" />
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="..\QSParse\QSParse.fsproj">
-      <Name>QSParse</Name>
-      <Project>{6ecf54c2-777c-4275-bc5d-e48fa61a4627}</Project>
-      <Private>True</Private>
-    </ProjectReference>
-  </ItemGroup>
-  <Import Project="$(MSBuildExtensionsPath32)\FSharp\1.0\Microsoft.FSharp.Targets" Condition="!Exists('$(MSBuildBinPath)\Microsoft.Build.Tasks.v4.0.dll')" />
-  <Import Project="$(MSBuildExtensionsPath32)\..\Microsoft F#\v4.0\Microsoft.FSharp.Targets" Condition=" Exists('$(MSBuildBinPath)\Microsoft.Build.Tasks.v4.0.dll')" />
-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
-	     Other similar extension points exist, see Microsoft.Common.targets.
-	<Target Name="BeforeBuild">
-	</Target>
-	<Target Name="AfterBuild">
-	</Target>
-	-->
-</Project>

+ 1 - 1
README.md

@@ -1 +1 @@
-Parser языка QSP при помощи технологии Lex/YACC на языке F#, который строит abstract syntax tree(AST) для разных нужд — например, для вычленения string исходного кода, чтобы перевести на другой язык; для переименования переменных; для интерпретации и выполнения QSP.
+Parser языка [QSP](http://wiki.qsp.su/).

+ 0 - 64
RunIfChange/Program.fs

@@ -1,64 +0,0 @@
-open System.Text
-open System.Diagnostics
-/// Запускаем новый процесс. Получаем кортеж (код_завершения, stdout)
-let shellExecute program arguments =
-    let startInfo = new ProcessStartInfo()
-    startInfo.FileName  <- program
-    startInfo.Arguments <- arguments
-    startInfo.UseShellExecute        <- false
-    startInfo.RedirectStandardOutput <- true
-    let proc = new Process()
-    proc.EnableRaisingEvents <- true
-    // Добавить обработчик события ‘OutputDataRecieved’, чтобы можно было
-    // сохранить поток STDOUT процесса.
-    let driverOutput = new StringBuilder()
-    proc.OutputDataReceived.AddHandler(
-        DataReceivedEventHandler(
-            (fun sender args -> driverOutput.AppendLine(args.Data) |> ignore)
-        )
-    )
-    proc.StartInfo <- startInfo
-    proc.Start() |> ignore
-
-    proc.BeginOutputReadLine()
-    proc.WaitForExit()
-    (proc.ExitCode, driverOutput.ToString())
-
-open System.IO
-let dirwork = 
-    let d = Path.Combine(System.Environment.CurrentDirectory, "temp")
-    if not <| Directory.Exists d then Directory.CreateDirectory d |> ignore
-    d
-
-[<EntryPoint>]
-let main args = 
-    ///<summary>Сравнивает два файла</summary>
-    let compare path1 path2 = File.ReadAllBytes path1 = File.ReadAllBytes path2
-    let f prog path args =
-        let run () = 
-            let args = System.String.Join(" ", path::args)
-            shellExecute prog args
-        if not <| File.Exists path then (0, sprintf "%s not exist" path)
-        else
-            let file' = Path.GetFileNameWithoutExtension path + ".fs"
-            let dir = Path.GetDirectoryName path
-            let path' = Path.Combine(dir, file')
-            let file = Path.Combine(dirwork, Path.GetFileName path)
-            (*
-            let f cond else' then' = if cond() then then' () else else'(); File.Copy(path, file, true); run()
-            f (fun () -> File.Exists path') (fun () -> printfn "not exist compile file") (fun () ->
-            f (fun () -> File.Exists file)  (fun () -> printfn "not cache %s" file) (fun () ->
-            f (fun () -> compare file path) (fun () -> printfn "changed") (fun () -> (0, sprintf "not change %s" file)))) *)
-            let f func = File.Copy(path, file, true); run()
-            if File.Exists path' then
-                if File.Exists file  then
-                    if compare file path then (0, sprintf "not change %s" file)
-                    else printfn "changed"; f()
-                else printfn "not cache %s" file; f()
-            else printfn "not exist compile file"; f()
-
-    match args |> List.ofArray with
-    | "fslex.exe" as prog::path::args -> f prog path args
-    | "fsyacc.exe" as prog::path::args -> f prog path args
-    | _ -> 1, sprintf "cmd error"
-    |> function code, stdout -> printfn "%s" stdout; code

+ 0 - 2
RunIfChange/README.md

@@ -1,2 +0,0 @@
-А ведь идея-то неплохая — запустить фоном программу, она бы отслеживала состояние нужных файлов, и если они изменились, то сделать всё необходимое. Эх, не додумался в свое время, а жаль. Может, попробовать снова Lex/YACC? Да ну, FParsec меня полностью устраивает, и так пока что сойдет.
-Черт, как же чешутся руки ее написать...

+ 0 - 56
RunIfChange/RunIfChange.fsproj

@@ -1,56 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
-    <ProductVersion>8.0.30703</ProductVersion>
-    <SchemaVersion>2.0</SchemaVersion>
-    <ProjectGuid>{554b1e12-dfa8-4972-9e9b-f5abe1fc272a}</ProjectGuid>
-    <OutputType>Exe</OutputType>
-    <RootNamespace>RunIfChange</RootNamespace>
-    <AssemblyName>RunIfChange</AssemblyName>
-    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
-    <TargetFrameworkProfile>Client</TargetFrameworkProfile>
-    <Name>RunIfChange</Name>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <Tailcalls>false</Tailcalls>
-    <OutputPath>bin\Debug\</OutputPath>
-    <DefineConstants>DEBUG;TRACE</DefineConstants>
-    <WarningLevel>3</WarningLevel>
-    <PlatformTarget>x86</PlatformTarget>
-    <DocumentationFile>bin\Debug\RunIfChange.XML</DocumentationFile>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <Tailcalls>true</Tailcalls>
-    <OutputPath>bin\Release\</OutputPath>
-    <DefineConstants>TRACE</DefineConstants>
-    <WarningLevel>3</WarningLevel>
-    <PlatformTarget>x86</PlatformTarget>
-    <DocumentationFile>bin\Release\RunIfChange.XML</DocumentationFile>
-  </PropertyGroup>
-  <ItemGroup>
-    <Reference Include="mscorlib" />
-    <Reference Include="FSharp.Core" />
-    <Reference Include="System" />
-    <Reference Include="System.Core" />
-    <Reference Include="System.Numerics" />
-  </ItemGroup>
-  <ItemGroup>
-    <Compile Include="Program.fs" />
-  </ItemGroup>
-  <Import Project="$(MSBuildExtensionsPath32)\FSharp\1.0\Microsoft.FSharp.Targets" Condition="!Exists('$(MSBuildBinPath)\Microsoft.Build.Tasks.v4.0.dll')" />
-  <Import Project="$(MSBuildExtensionsPath32)\..\Microsoft F#\v4.0\Microsoft.FSharp.Targets" Condition=" Exists('$(MSBuildBinPath)\Microsoft.Build.Tasks.v4.0.dll')" />
-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
-	     Other similar extension points exist, see Microsoft.Common.targets.
-	<Target Name="BeforeBuild">
-	</Target>
-	<Target Name="AfterBuild">
-	</Target>
-	-->
-</Project>

+ 6 - 0
Test/App.config

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+    <startup> 
+        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
+    </startup>
+</configuration>

+ 36 - 0
Test/Test.fs

@@ -0,0 +1,36 @@
+open Fuchu
+open FsharpMyExtension
+
+[<Tests>]
+let simpleTest =
+    testCase "simpleTest" (fun _ ->
+        let exp = "a"
+        let act = "a"
+        Assert.Equal("msg", exp, act)
+    )
+// run simpleTest // <- если нужно запустить тест вручную
+
+[<Tests>]
+let simpleTestList =
+    testList "testListName" [
+        testCase "testCase1" (fun _ ->
+            let exp = true
+            let act = true
+            Assert.Equal("msg1", exp, act)
+        )
+        testCase "testCase2" (fun _ ->
+            let exp = 1
+            let act = 1
+            Assert.Equal("msg2", exp, act)
+        )
+        testCase "testCase3" (fun _ ->
+            let exp = ()
+            let act = ()
+            Assert.Equal("msg3", exp, act)
+        )
+    ]
+// run simpleTestList
+
+[<EntryPoint;System.STAThread>]
+let main arg =
+    defaultMainThisAssembly arg

+ 22 - 0
Test/Test.fsproj

@@ -0,0 +1,22 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>net461</TargetFramework>
+    <Optimize>true</Optimize>
+    <Tailcalls>true</Tailcalls>
+  </PropertyGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\QSParse\QSParse.fsproj">
+      <Name>QSParse.fsproj</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Test.fs" />
+    <None Include="App.config" />
+  </ItemGroup>
+  <ItemGroup>
+    <Reference Include="System.Runtime" />
+	<Reference Include="$(FsharpMyExtension)" />
+  </ItemGroup>
+  <Import Project="..\.paket\Paket.Restore.targets" />
+</Project>

+ 2 - 0
Test/paket.references

@@ -0,0 +1,2 @@
+FSharp.Core
+FuChu

+ 17 - 0
build.cmd

@@ -0,0 +1,17 @@
+@echo off
+cls
+
+IF EXIST ".paket\paket.exe" (
+  REM Do one thing
+) ELSE (
+  .paket\paket.bootstrapper.exe
+)
+.paket\paket.exe restore
+if errorlevel 1 (
+  exit /b %errorlevel%
+)
+
+packages\build\FAKE\tools\FAKE.exe build.fsx %*
+if errorlevel 1 (
+  REM pause
+)

+ 91 - 0
build.fsx

@@ -0,0 +1,91 @@
+// --------------------------------------------------------------------------------------
+// FAKE build script
+// --------------------------------------------------------------------------------------
+#r "./packages/build/FAKE/tools/FakeLib.dll"
+open Fake.IO.Globbing.Operators
+open Fake.Core
+// --------------------------------------------------------------------------------------
+// Build variables
+// --------------------------------------------------------------------------------------
+let f projName =
+    let pattern = sprintf @"**\%s.fsproj" projName
+    let xs = !! pattern
+    xs
+    |> Seq.tryExactlyOne
+    |> Option.defaultWith (fun () ->
+        xs
+        |> List.ofSeq
+        |> failwithf "'%s' expected exactly one but:\n%A" pattern
+    )
+let testProjName = "Test"
+let testProjPath = f testProjName
+let mainProjName = "QSParse"
+let mainProjPath = f mainProjName
+// --------------------------------------------------------------------------------------
+// Helpers
+// --------------------------------------------------------------------------------------
+open Fake.DotNet
+let buildConf = DotNet.BuildConfiguration.Debug
+let dotnetSdk = lazy DotNet.install DotNet.Versions.FromGlobalJson
+let inline dtntSmpl arg = DotNet.Options.lift dotnetSdk.Value arg
+// --------------------------------------------------------------------------------------
+// Targets
+// --------------------------------------------------------------------------------------
+Target.create "BuildTest" (fun _ ->
+    testProjPath
+    |> Fake.IO.Path.getDirectory
+    |> DotNet.build (fun x ->
+        { x with Configuration = buildConf }
+        |> dtntSmpl)
+)
+
+let run projName projPath =
+    let dir = Fake.IO.Path.getDirectory projPath
+    let localpath = sprintf "bin/%A/net461/%s.exe" buildConf projName
+    let path = Fake.IO.Path.combine dir localpath
+    if not <| Fake.IO.File.exists path then
+        failwithf "not found %s" path
+
+    Command.RawCommand(path, Arguments.Empty)
+    |> CreateProcess.fromCommand
+    |> CreateProcess.withWorkingDirectory (Fake.IO.Path.getDirectory path)
+    |> Proc.run
+
+Target.create "RunTest" (fun _ ->
+    let x = run testProjName testProjPath
+    if x.ExitCode <> 0 then
+        raise <| Fake.Testing.Common.FailedTestsException "test error"
+)
+
+Target.create "RunMainProj" (fun _ ->
+    run mainProjName mainProjPath |> ignore
+)
+
+Target.create "TrimTrailingWhitespace" (fun _ ->
+    // по-хорошему, нужно использовать .gitignore, но и так пока сойдет
+    let files =
+        !! "**/*.fs"
+        ++ "**/*.fsx"
+        ++ "**/*.fsproj"
+        ++ "**/*.cs"
+        ++ "**/*.csproj"
+        -- "**/obj/**"
+        -- "**/paket-files/**"
+        -- "**/packages/**"
+    files
+    |> Seq.iter (fun path ->
+        System.IO.File.ReadAllLines path
+        |> Array.map (fun x -> x.TrimEnd())
+        |> fun content -> System.IO.File.WriteAllLines(path, content)
+    )
+)
+
+// --------------------------------------------------------------------------------------
+// Build order
+// --------------------------------------------------------------------------------------
+open Fake.Core.TargetOperators
+
+"BuildTest"
+  ==> "RunTest"
+  ==> "RunMainProj"
+Target.runOrDefault "RunMainProj"

+ 5 - 0
global.json

@@ -0,0 +1,5 @@
+{
+    "sdk": {
+        "version": "3.1.301"
+    }
+}

+ 13 - 0
paket.dependencies

@@ -0,0 +1,13 @@
+storage: none
+source https://www.nuget.org/api/v2
+
+framework: >= net461
+nuget FAKE
+nuget FSharp.Core
+nuget Fuchu
+nuget FParsec
+
+group Build
+  source https://nuget.org/api/v2
+
+  nuget FAKE

+ 17 - 0
paket.lock

@@ -0,0 +1,17 @@
+STORAGE: NONE
+RESTRICTION: >= net461
+NUGET
+  remote: https://www.nuget.org/api/v2
+    FAKE (5.16)
+    FParsec (1.1.1)
+      FSharp.Core (>= 4.3.4)
+      System.ValueTuple (>= 4.4)
+    FSharp.Core (4.7.2)
+    Fuchu (1.1)
+      FSharp.Core (>= 4.3.4)
+    System.ValueTuple (4.5)
+
+GROUP Build
+NUGET
+  remote: https://www.nuget.org/api/v2
+    FAKE (5.16)