Prexonite, a .NET hosted scripting language with a focus on meta-programming and embedded DSLs
0

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #177 from chklauser/agent/pxcoco-source-generator

Replace PxCoco tool with source generator

authored by

Christian Klauser and committed by
GitHub
(Jul 11, 2026, 12:31 AM +0200) fa189f4a a4a8b106

+433 -1018
-4
.github/workflows/PrxCi.yml
··· 8 8 tags-ignore: 9 9 - '**' 10 10 paths-ignore: 11 - - PxCoco/** 12 - - .github/workflows/PxCoco* 13 11 - .github/workflows/PrxRelease* 14 12 pull_request: 15 13 paths-ignore: 16 - - PxCoco/** 17 - - .github/workflows/PxCoco* 18 14 - .github/workflows/PrxRelease* 19 15 20 16 jobs:
-36
.github/workflows/PxCocoCi.yml
··· 1 - name: PxCoco CI 2 - 3 - on: 4 - push: 5 - branches: 6 - - main 7 - - master 8 - tags-ignore: 9 - - '**' 10 - paths: 11 - - PxCoco/** 12 - - .github/workflows/PxCocoCi.yml 13 - pull_request: 14 - paths: 15 - - PxCoco/** 16 - 17 - jobs: 18 - build: 19 - name: Build PxCoco (CI) 20 - runs-on: windows-2022 21 - 22 - steps: 23 - - uses: actions/checkout@v4 24 - - name: Setup .NET SDK 25 - uses: actions/setup-dotnet@v4 26 - env: 27 - NUGET_AUTH_TOKEN: '${{secrets.GITHUB_TOKEN}}' 28 - with: 29 - global-json-file: global.json 30 - source-url: 'https://nuget.pkg.github.com/chklauser/index.json' 31 - - name: Install dependencies (Win) 32 - run: dotnet restore PxCoco/PxCoco.csproj 33 - - name: Build (Win) 34 - run: dotnet build --configuration Release --no-restore PxCoco/PxCoco.csproj 35 - - name: Pack (Win) 36 - run: dotnet pack --no-restore --no-build --configuration Release PxCoco/PxCoco.csproj
-48
.github/workflows/PxCocoRelease.yml
··· 1 - name: PxCoco Release 2 - 3 - on: 4 - push: 5 - paths: 6 - - PxCoco/** 7 - - .github/workflows/PxCocoRelease.yml 8 - tags: 9 - - pxcoco/v.* 10 - 11 - jobs: 12 - release: 13 - name: Build and Release PxCoco 14 - runs-on: windows-2022 15 - permissions: 16 - packages: write 17 - contents: read 18 - steps: 19 - - name: 'Update version to Tag' 20 - id: update-version 21 - shell: powershell 22 - env: 23 - BUILD_SOURCEBRANCH: ${{ github.ref }} 24 - run: | 25 - # Remove /refs/tags (10 chars) and pxcoco/v. (9 chars) from checkout string 26 - Write-Host Source branch: $env:BUILD_SOURCEBRANCH 27 - $ver = $env:BUILD_SOURCEBRANCH.remove(0,19) 28 - Write-Host "::set-output name=version::$ver" 29 - Write-Host Version: $ver 30 - - uses: actions/checkout@v4 31 - - name: Setup .NET SDK 32 - uses: actions/setup-dotnet@v4 33 - env: 34 - # Use a personal access token (publishing with the GITHUB_TOKEN is somehow not possible) 35 - NUGET_AUTH_TOKEN: '${{secrets.CICD_PAT}}' 36 - with: 37 - global-json-file: global.json 38 - source-url: 'https://nuget.pkg.github.com/chklauser/index.json' 39 - - name: Install dependencies (Win) 40 - run: dotnet restore PxCoco/PxCoco.csproj 41 - - name: Build (Win) 42 - run: dotnet build --configuration Release --no-restore PxCoco/PxCoco.csproj -p:Version=${{steps.update-version.outputs.version}} 43 - - name: Pack (Win) 44 - run: dotnet pack --no-restore --no-build --configuration Release PxCoco/PxCoco.csproj -p:Version=${{steps.update-version.outputs.version}} 45 - - name: Push Package (Win) 46 - run: dotnet nuget push PxCoco/bin/Release/PxCoco.${{steps.update-version.outputs.version}}.nupkg 47 - - name: Push Symbols Package (Win) 48 - run: dotnet nuget push PxCoco/bin/Release/PxCoco.${{steps.update-version.outputs.version}}.snupkg
+2 -11
.gitignore
··· 86 86 # Ignore merge by-products 87 87 *.orig 88 88 89 - # Ignore unused scanner/parser output (generated on each build) 90 - Prexonite/Compiler/Parser.cs 91 - Prexonite/Internal/Parser.cs 92 - Prexonite/Internal/Scanner.cs 93 - # TODO: implement cross-platform CSFlex (Prexonite\Compiler\Lexer.xs) 94 - Prexonite/Compiler/Scanner.cs 95 - Prexonite/Prexonite__gen.atg 96 - Prexonite/Parser.cs 97 - Prexonite/Parser.cs.old 98 - Prexonite/Scanner.cs 99 - Prexonite/Scanner.cs.old 89 + # Ignore generated files 90 + # TODO: implement cross-platform CSFlex (Prexonite\Compiler\Lexer.cs) 100 91 PrexoniteTests/OldPrexoniteTests.csproj.xml 101 92 Prexonite/Properties/Resources.Designer.cs 102 93
+5 -5
CLAUDE.md
··· 24 24 - **Prexonite**: Core language library (VM, compiler, type system, standard library) 25 25 - **PrexoniteTests**: NUnit test suite with .pxs integration tests 26 26 - **Prx**: Command-line REPL and script runner 27 - - **PxCoco**: Modified Coco/R parser generator (build-time tool) 27 + - **PxCoco**: Modified Coco/R incremental source generator 28 28 29 29 # High-Level Architecture 30 30 31 31 ## Compilation Pipeline 32 32 33 33 1. **Lexical Analysis** (`Compiler/Lexer.cs`) - Generated from `Prexonite.lex` via CSFlex 34 - 2. **Parsing** (`Compiler/Parser.cs`) - Generated from merged `.atg` grammar fragments via PxCoco 34 + 2. **Parsing** - Generated from `.atg` `AdditionalFiles` by the PxCoco source generator 35 35 3. **AST Construction** (`Compiler/AST/`) - 50+ node types representing language constructs 36 36 4. **Macro Expansion** (`Compiler/Macro/`) - Compile-time AST transformation (macros run during compilation) 37 37 5. **Symbol Resolution** (`Compiler/Symbolic/`) - Namespace imports and qualified name resolution ··· 117 117 118 118 # Build-Time Code Generation 119 119 120 - - **Grammar Assembly**: `.atg` fragments merged via MSBuild into `Prexonite__gen.atg` 121 - - **Parser Generation**: PxCoco generates `Parser.cs` from grammar 120 + - **Grammar Assembly**: `.atg` fragments are ordered and merged in memory by the PxCoco source generator 121 + - **Parser Generation**: PxCoco emits parser/scanner sources directly into the Roslyn compilation 122 122 - **Lexer Generation**: CSFlex generates `Lexer.cs` from `Prexonite.lex` 123 123 - **Test fixture generation**: `PrexoniteTests.Generators` generates NUnit fixtures from the JSON test configurations 124 124 ··· 160 160 161 161 ## Modify Grammar 162 162 1. Edit `.atg` fragments in `Compiler/Grammar/` 163 - 2. Rebuild to regenerate parser via PxCoco 163 + 2. Rebuild; the PxCoco incremental generator observes the grammar through `AdditionalFiles`
-5
Directory.Packages.props
··· 5 5 </PropertyGroup> 6 6 7 7 <ItemGroup> 8 - <!-- Build tools --> 9 - <PackageVersion Include="Microsoft.Build.Framework" Version="17.10.4" /> 10 - <PackageVersion Include="Microsoft.Build.Utilities.Core" Version="17.10.4" /> 11 - <PackageVersion Include="PxCoco" Version="1.98.0" /> 12 - 13 8 <!-- Runtime dependencies --> 14 9 <PackageVersion Include="Microsoft.Extensions.ObjectPool" Version="9.0.0" /> 15 10
+1 -9
NuGet.Config
··· 1 1 <?xml version="1.0" encoding="utf-8"?> 2 2 <configuration> 3 3 <packageSources> 4 + <clear /> 4 5 <add key="nuget" value="https://api.nuget.org/v3/index.json" /> 5 - <add key="chklauser" value="https://nuget.pkg.github.com/chklauser/index.json" /> 6 6 </packageSources> 7 - <packageSourceMapping> 8 - <packageSource key="nuget"> 9 - <package pattern="*" /> 10 - </packageSource> 11 - <packageSource key="chklauser"> 12 - <package pattern="PxCoco" /> 13 - </packageSource> 14 - </packageSourceMapping> 15 7 </configuration>
+5 -5
Prexonite/Compiler/Grammar/Grammar.Readme.txt
··· 1 - This folder contains the complete Prexonite Script File grammar, divided into several files. 2 - Since PxCoco (the compiler-compiler) cannot work on multiple files, these grammar fragments 3 - are assembled into a file called \Prexonite\Prexonite__gen.atg which is then passed to PxCoco. 4 - So if you want to modify the grammar, do so in the original files here and not the generated one. 1 + This folder contains the complete Prexonite Script File grammar, divided into several files. 2 + The files are supplied to the PxCoco incremental source generator as AdditionalFiles. PxCoco 3 + orders and merges the fragments in memory, then adds the generated parser directly to the 4 + compilation. To change the grammar, edit the fragments in this folder and rebuild. 5 5 6 - The generated parser has a code-behind file called Compiler\Parser.Code.cs. 6 + The generated parser has a code-behind file called Compiler\Parser.Code.cs.
+10 -79
Prexonite/Prexonite.csproj
··· 17 17 <PropertyGroup> 18 18 <!--<UseHostCompilerIfAvailable>False</UseHostCompilerIfAvailable> --> 19 19 <BuildDependsOn> 20 - ExpressionParser; 21 20 PrexoniteScanner; 22 - PrexoniteParser; 23 21 $(BuildDependsOn); 24 22 </BuildDependsOn> 25 23 <ToolsDirectory>$(ProjectDir)../Tools</ToolsDirectory> 26 - <FramesDirectory>$(ToolsDirectory)</FramesDirectory> 27 24 <PrexoniteScannerDefinition>Prexonite.lex</PrexoniteScannerDefinition> 28 - <PrexoniteGrammarDefinition>Prexonite__gen.atg</PrexoniteGrammarDefinition> 29 - <PTypeExpressionGrammarDefinition>PTypeExpression.atg</PTypeExpressionGrammarDefinition> 30 - <PrexoniteParserOutputFiles>Parser.cs</PrexoniteParserOutputFiles> 31 - <PTypeExpressionParserOutputFiles>Parser.cs;Scanner.cs</PTypeExpressionParserOutputFiles> 32 - <PrexoniteParserFiles>$(PxCocoOutputFiles)</PrexoniteParserFiles> 33 - <PTypeExpressionParserFiles>$(PxCocoOutputFiles)</PTypeExpressionParserFiles> 34 - <DirectDebug>False</DirectDebug> 35 25 </PropertyGroup> 36 26 <ItemGroup> 37 - <GrammarFragment Include="Compiler\Grammar\Header.atg" /> 38 - <GrammarFragment Include="Compiler\Grammar\Scanner.atg" /> 39 - <GrammarFragment Include="Compiler\Grammar\Parser*.atg" /> 40 - <Compile Remove="Parser.cs" /> 41 - <Compile Remove="Scanner.cs" /> 27 + <AdditionalFiles Include="Compiler\Grammar\Header.atg" PxCocoGrammar="Prexonite" PxCocoOrder="10" /> 28 + <AdditionalFiles Include="Compiler\Grammar\Scanner.atg" PxCocoGrammar="Prexonite" PxCocoOrder="20" /> 29 + <AdditionalFiles Include="Compiler\Grammar\Parser*.atg" PxCocoGrammar="Prexonite" PxCocoOrder="30" /> 30 + <AdditionalFiles Include="Compiler\Grammar\Footer.atg" PxCocoGrammar="Prexonite" PxCocoOrder="40" /> 31 + <AdditionalFiles Include="PTypeExpression.atg" PxCocoGrammar="PTypeExpression" PxCocoOrder="10" /> 32 + <CompilerVisibleItemMetadata Include="AdditionalFiles" MetadataName="PxCocoGrammar" /> 33 + <CompilerVisibleItemMetadata Include="AdditionalFiles" MetadataName="PxCocoOrder" /> 42 34 <None Remove="prxlib\legacy_symbols.pxs" /> 43 35 <None Remove="prxlib\prx.core.pxs" /> 44 36 <None Remove="prxlib\prx.prim.pxs" /> ··· 49 41 <EmbeddedResource Include="prxlib\prx.v1.prelude.pxs" /> 50 42 <EmbeddedResource Include="prxlib\prx.v2.prelude.pxs" /> 51 43 <EmbeddedResource Include="prxlib\sys.pxs" /> 52 - <GrammarFragment Include="Compiler\Grammar\Footer.atg" /> 53 - <!-- Generated files (tracked manually because they might only appear in the middle of the build process and, 54 - in that case, would not be discovered automaticaly. --> 55 - <Compile Remove="$(ProjectDir)\Compiler\Parser.cs" /> 56 - <Compile Remove="$(ProjectDir)\Internal\Parser.cs" /> 57 - <Compile Remove="$(ProjectDir)\Internal\Scanner.cs" /> 58 - <Compile Include="$(ProjectDir)\Compiler\Parser.cs" /> 59 - <Compile Include="$(ProjectDir)\Internal\Parser.cs" /> 60 - <Compile Include="$(ProjectDir)\Internal\Scanner.cs" /> 61 44 <None Remove="Compiler\Lexer.cs~" /> 62 45 </ItemGroup> 63 - <ItemGroup> 64 - <Grammar Include="PTypeExpression.atg" /> 65 - </ItemGroup> 66 - 67 - <!-- These defitions are not used in a normal build. They can be useful for debugging PxCoco in the context of Prexonite. --> 68 - <!-- <PropertyGroup> 69 - <PxCocoDebugTaskExt Condition=" '$(MSBuildRuntimeType)' == 'Core' ">net5.0\PxCoco.dll</PxCocoDebugTaskExt> 70 - <PxCocoDebugTaskExt Condition=" '$(MSBuildRuntimeType)' != 'Core' ">net48\PxCoco.exe</PxCocoDebugTaskExt> 71 - <PxCocoTaskAssembly>$(MSBuildThisFileDirectory)..\PxCoco\bin\Debug\$(PxCocoDebugTaskExt)</PxCocoTaskAssembly> 72 - </PropertyGroup> 73 - <UsingTask TaskName="PxCoco" AssemblyFile="$(PxCocoTaskAssembly)" /> 74 - <UsingTask TaskName="Merge" AssemblyFile="$(PxCocoTaskAssembly)" /> --> 75 - 76 - <!-- PType Expression Parser Target --> 77 - <Target Name="PTypeExpressionParser" BeforeTargets="BeforeBuild"> 78 - <Message Text="Building type expression parser." /> 79 - <PxCoco Grammar="$(PTypeExpressionGrammarDefinition)" Namespace="Prexonite.Internal" FramesDirectory="$(FramesDirectory)" DirectDebug="$(DirectDebug)" RelativePathRoot="$(ProjectDir)\Internal"> 80 - <Output TaskParameter="OutputFiles" ItemName="PTypeExpressionParserFiles" /> 81 - </PxCoco> 82 - <Copy SourceFiles="$(ProjectDir)Parser.cs;$(ProjectDir)Scanner.cs" DestinationFolder="$(ProjectDir)Internal" /> 83 - <Delete Files="$(PTypeExpressionParserFiles)" DeletedFiles="$(ProjectDir)Parser.cs;$(ProjectDir)Scanner.cs" /> 84 - </Target> 85 - 86 - <!-- Prexonite Parser Target --> 87 - <Target Name="PrexoniteParser" DependsOnTargets="PrexoniteGrammar" BeforeTargets="BeforeBuild"> 88 - <Message Text="Building prexonite parser." /> 89 - <PxCoco Grammar="$(PrexoniteGrammarDefinition)" Namespace="Prexonite.Compiler" FramesDirectory="$(FramesDirectory)" DirectDebug="$(DirectDebug)" RelativePathRoot="$(ProjectDir)\Compiler"> 90 - <Output TaskParameter="OutputFiles" ItemName="PrexoniteParserFiles" /> 91 - </PxCoco> 92 - <!-- We use the CSFlex-generated scanner instead. --> 93 - <Copy SourceFiles="$(ProjectDir)/Parser.cs" DestinationFolder="$(ProjectDir)/Compiler" /> 94 - <Delete Files="$(PrexoniteParserFiles)" DeletedFiles="$(ProjectDir)/Parser.cs" /> 95 - </Target> 96 - 97 - <!-- Prexonite Grammar Merging Target --> 98 - <Target Name="PrexoniteGrammar" Outputs="$(ProjectDir)Prexonite__gen.atg" Inputs="@(GrammarFragment->'%(FullPath)')"> 99 - <Message Text="Merging Prexonite Grammar fragments." /> 100 - <Merge InputFiles="@(GrammarFragment->'%(FullPath)')" OutputFile="$(ProjectDir)Prexonite__gen.atg" RelativePathRoot="$(ProjectDir)\Compiler"> 101 - </Merge> 102 - <Message Text="$(PrexoniteGrammarDefinition) is now ready." /> 103 - </Target> 104 46 <Target Name="PrexoniteScanner" Outputs="$(ProjectDir)/Compiler/Lexer.cs" Inputs="$(ProjectDir)/Compiler/$(PrexoniteScannerDefinition)"> 105 47 <Exec Command="&quot;../$(ToolsDirectory)/csflex.exe&quot; --csharp --nested-default-skeleton --nobak $(PrexoniteScannerDefinition)" WorkingDirectory="$(ProjectDir)/Compiler" /> 106 48 </Target> 107 49 108 - <Target Name="PrexoniteParserClean" AfterTargets="Clean"> 109 - <Delete Files="$(ProjectDir)\Compiler\Parser.cs" /> 110 - </Target> 111 - 112 - <Target Name="PTypeExpressionParserClean" AfterTargets="Clean"> 113 - <Delete Files="$(ProjectDir)\Internal\Parser.cs;$(ProjectDir)\Internal\Scanner.cs" /> 114 - </Target> 115 - 116 - <Target Name="PrexoniteGrammerClean" AfterTargets="Clean"> 117 - <!-- On Windows, deletion will fail because some build process retains a handle to this file. --> 118 - <!-- <Delete Files="$(PrexoniteGrammarDefinition)" /> --> 119 - </Target> 120 - 121 50 <ItemGroup> 122 51 <!-- Generate the Properties/Resources.Designer.cs file from the default translations in Resources.resx --> 123 52 <EmbeddedResource Update="Properties/Resources.resx"> ··· 133 62 134 63 <!-- NUGET References --> 135 64 <ItemGroup> 136 - <PackageReference Include="PxCoco" /> 65 + <ProjectReference Include="..\PxCoco\PxCoco.csproj" 66 + OutputItemType="Analyzer" 67 + ReferenceOutputAssembly="false" /> 137 68 <PackageReference Include="Microsoft.Extensions.ObjectPool" /> 138 69 </ItemGroup> 139 70 </Project>
+62 -147
PxCoco/Coco.cs
··· 4 4 extended by M. Loeberbauer & A. Woess, Univ. of Linz 5 5 with improvements by Pat Terry, Rhodes University 6 6 7 - This program is free software; you can redistribute it and/or modify it 8 - under the terms of the GNU General Public License as published by the 9 - Free Software Foundation; either version 2, or (at your option) any 7 + This program is free software; you can redistribute it and/or modify it 8 + under the terms of the GNU General Public License as published by the 9 + Free Software Foundation; either version 2, or (at your option) any 10 10 later version. 11 11 12 - This program is distributed in the hope that it will be useful, but 13 - WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 - for more details. 16 - 17 - You should have received a copy of the GNU General Public License along 18 - with this program; if not, write to the Free Software Foundation, Inc., 19 - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 20 - 21 12 As an exception, it is allowed to write an extension of Coco/R that is 22 13 used as a plugin in non-free software. 23 14 24 - If not otherwise stated, any source code generated by Coco/R (other than 15 + If not otherwise stated, any source code generated by Coco/R (other than 25 16 Coco/R itself) does not fall under the GNU General Public License. 26 17 -------------------------------------------------------------------------*/ 27 18 28 - /* 29 - * THIS IS A MODIFIED VERSION! 30 - * I, Christian "SealedSun" Klauser <sealedsun AT gmail DOT com>, have modified 31 - * CoCo/R to better fit my needs. The code generator now uses the symbolic 32 - * constants whenever possible. 33 - * 34 - * To distinguish CoCo/R and from my version, I called my executable PxCoco.exe 35 - */ 36 - 37 - /*------------------------------------------------------------------------- 38 - Trace output options 39 - 0 | A: prints the states of the scanner automaton 40 - 1 | F: prints the First and Follow sets of all nonterminals 41 - 2 | G: prints the syntax graph of the productions 42 - 3 | I: traces the computation of the First sets 43 - 4 | J: prints the sets associated with ANYs and synchronisation sets 44 - 6 | S: prints the symbol table (terminals, nonterminals, pragmas) 45 - 7 | X: prints a cross reference list of all syntax symbols 46 - 8 | P: prints statistics about the Coco run 47 - 48 - Trace output can be switched on by the pragma 49 - $ { digit | letter } 50 - in the attributed grammar or as a command-line option 51 - -------------------------------------------------------------------------*/ 52 - 53 19 using System; 54 20 using System.IO; 21 + using System.Text; 55 22 56 - // ReSharper disable CheckNamespace 57 - namespace at.jku.ssw.Coco { 58 - public static partial class Coco { 59 - 60 - public static bool Generate(GeneratorOptions generatorOptions) 23 + namespace at.jku.ssw.Coco 24 + { 25 + public static partial class Coco 61 26 { 62 - try 27 + public static GenerationResult Generate(GeneratorOptions options) 63 28 { 64 - var pos = generatorOptions.SrcName.LastIndexOf('/'); 65 - if (pos < 0) pos = generatorOptions.SrcName.LastIndexOf('\\'); 66 - var file = generatorOptions.SrcName; 67 - var srcDir = generatorOptions.SrcName.Substring(0, pos + 1); 29 + if (options == null) throw new ArgumentNullException(nameof(options)); 30 + if (options.Grammar == null) throw new ArgumentException("The grammar is required.", nameof(options)); 31 + if (options.ParserFrame == null) throw new ArgumentException("The parser frame is required.", nameof(options)); 32 + if (options.GenerateScanner && options.ScannerFrame == null) 33 + throw new ArgumentException("The scanner frame is required when scanner generation is enabled.", nameof(options)); 68 34 69 - var scanner = new Scanner(file); 70 - var parser = new Parser(scanner); 71 - 72 - var traceFileName = srcDir + "trace.txt"; 73 - parser.trace = new StreamWriter(new FileStream(traceFileName, FileMode.Create)); 74 - parser.tab = new Tab(parser); 75 - parser.dfa = new DFA(parser); 76 - parser.pgen = new ParserGen(parser) 35 + var trace = new StringWriter(); 36 + try 77 37 { 78 - DirectDebug = generatorOptions.DirectDebug, 79 - RelativePathRoot = generatorOptions.RelativePathRoot 80 - }; 38 + using var grammar = new MemoryStream(Encoding.UTF8.GetBytes(options.Grammar)); 39 + var scanner = new Scanner(grammar); 40 + var parser = new Parser(scanner) 41 + { 42 + trace = trace 43 + }; 81 44 82 - parser.tab.srcName = generatorOptions.SrcName; 83 - parser.tab.srcDir = srcDir; 84 - parser.tab.nsName = generatorOptions.Namespace; 85 - parser.tab.frameDir = generatorOptions.FrameDirectoryPath; 86 - if (generatorOptions.DirectDebugTrace != null) parser.tab.SetDDT(generatorOptions.DirectDebugTrace); 45 + parser.tab = new Tab(parser) 46 + { 47 + srcName = options.SourceName ?? "grammar.atg", 48 + srcDir = "", 49 + nsName = options.Namespace 50 + }; 51 + parser.dfa = new DFA(parser) 52 + { 53 + Frame = options.ScannerFrame, 54 + FrameName = "Scanner.frame" 55 + }; 56 + parser.pgen = new ParserGen(parser) 57 + { 58 + DirectDebug = options.DirectDebug, 59 + Frame = options.ParserFrame, 60 + FrameName = options.ParserFrameName ?? "Parser.frame" 61 + }; 87 62 88 - parser.errors.WriteMessage = generatorOptions.WriteMessage; 89 - parser.errors.WriteError = generatorOptions.WriteError; 63 + if (options.DirectDebugTrace != null) 64 + parser.tab.SetDDT(options.DirectDebugTrace); 90 65 91 - parser.errors.realFile = generatorOptions.SrcName; 92 - 93 - parser.Parse(); 94 - 95 - parser.trace.Close(); 96 - var f = new FileInfo(traceFileName); 97 - if (f.Length == 0) f.Delete(); 98 - else generatorOptions.WriteMessage("trace output is in " + traceFileName); 99 - generatorOptions.WriteMessage($"{parser.errors.count} errors detected"); 100 - return parser.errors.count <= 0; 101 - } 102 - catch (IOException ex) 103 - { 104 - generatorOptions.WriteError(ex.Message); 105 - return false; 106 - } 107 - catch (FatalError ex) 108 - { 109 - generatorOptions.WriteError(ex.Message); 110 - return false; 111 - } 112 - } 113 - 114 - public static void Main (string[] arg) { 115 - Console.WriteLine("PxCoco/R (Jun 30, 2019), based on Coco/R (Sep 19, 2006)"); 66 + parser.errors.WriteMessage = options.WriteMessage; 67 + parser.errors.WriteError = options.WriteError; 68 + parser.errors.realFile = options.SourceName ?? "grammar.atg"; 116 69 117 - if (arg.Length > 0 && arg[0] == "-merge") 118 - { 119 - MergeCommandLine(arg); 120 - return; 121 - } 70 + parser.Parse(); 122 71 123 - var opts = new GeneratorOptions(Console.WriteLine, ex => Console.WriteLine("-- " + ex)); 124 - 125 - for (var i = 0; i < arg.Length; i++) 126 - { 127 - switch (arg[i]) 72 + options.WriteMessage($"{parser.errors.count} errors detected"); 73 + return new GenerationResult( 74 + parser.errors.count == 0, 75 + parser.pgen.GeneratedSource, 76 + options.GenerateScanner ? parser.dfa.GeneratedSource : null, 77 + trace.ToString()); 78 + } 79 + catch (IOException ex) 128 80 { 129 - case "-namespace" when i < arg.Length - 1: 130 - opts.Namespace = arg[++i]; 131 - break; 132 - case "-frames" when i < arg.Length - 1: 133 - opts.FrameDirectoryPath = arg[++i]; 134 - break; 135 - case "-trace" when i < arg.Length - 1: 136 - opts.DirectDebugTrace = arg[++i]; 137 - break; 138 - case "-relative" when i < arg.Length - 1: 139 - opts.RelativePathRoot = arg[++i]; 140 - break; 141 - case "-d": 142 - opts.DirectDebug = true; 143 - break; 144 - default: 145 - opts.SrcName = arg[i]; 146 - break; 81 + options.WriteError(ex.Message); 147 82 } 148 - } 149 - if (arg.Length > 0 && opts.SrcName != null) { 150 - Generate(opts); 151 - } else { 152 - //No arguments supplied -> display help message 153 - Console.WriteLine("Usage: {0}\t- PxCoco Grammar.ATG {{Option}}{0}\t- PxCoco -merge {{grammar.atg}} output.atg{0}" + 154 - "Options:{0}" + 155 - " -namespace <namespaceName>{0}" + 156 - " -frames <frameFilesDirectory>{0}" + 157 - " -trace <traceString>{0}" + 158 - " -relative <pathRoot>{0}" + 159 - "Valid characters in the trace string:{0}" + 160 - " A trace automaton{0}" + 161 - " F list first/follow sets{0}" + 162 - " G print syntax graph{0}" + 163 - " I trace computation of first sets{0}" + 164 - " J list ANY and SYNC sets{0}" + 165 - " P print statistics{0}" + 166 - " S list symbol table{0}" + 167 - " X list cross reference table{0}" + 168 - "Scanner.frame and Parser.frame files needed in ATG directory{0}" + 169 - "or in a directory specified in the -frames option.", 170 - Environment.NewLine); 171 - } 172 - } 173 - 174 - } // end Coco 83 + catch (FatalError ex) 84 + { 85 + options.WriteError(ex.Message); 86 + } 175 87 176 - } // end namespace 88 + return new GenerationResult(false, null, null, trace.ToString()); 89 + } 90 + } 91 + }
+17 -25
PxCoco/DFA.cs
··· 29 29 using System.IO; 30 30 using System.Text; 31 31 using System.Collections; 32 + using System.Globalization; 32 33 33 34 namespace at.jku.ssw.Coco { 34 35 ··· 292 293 public State firstState; 293 294 public State lastState; // last allocated state 294 295 public int lastSimState; // last non melted state 295 - public FileStream fram; // scanner frame input 296 - public StreamWriter gen; // generated scanner file 296 + public TextReader fram; // scanner frame input 297 + public TextWriter gen; // generated scanner source 297 298 public Symbol curSy; // current token to be recognized (in FindTrans) 298 299 public Node curGraph; // start of graph for current token (in FindTrans) 299 300 public bool ignoreCase; // true if input should be treated case-insensitively ··· 304 305 Tab tab; 305 306 Errors errors; 306 307 TextWriter trace; 308 + StringBuilder generatedSource; 309 + 310 + public string Frame { get; set; } 311 + public string FrameName { get; set; } = "Scanner.frame"; 312 + public string GeneratedSource => generatedSource?.ToString(); 307 313 308 314 //---------- Output primitives 309 315 private string Ch(int ch) { ··· 770 776 void CopyFramePart(string stop) { 771 777 char startCh = stop[0]; 772 778 int endOfStopString = stop.Length-1; 773 - int ch = fram.ReadByte(); 779 + int ch = fram.Read(); 774 780 while (ch != EOF) 775 781 if (ch == startCh) { 776 782 int i = 0; 777 783 do { 778 784 if (i == endOfStopString) return; // stop[0..i] found 779 - ch = fram.ReadByte(); i++; 785 + ch = fram.Read(); i++; 780 786 } while (ch == stop[i]); 781 787 // stop[0..i-1] found; continue with last read character 782 788 gen.Write(stop.Substring(0, i)); 783 789 } else { 784 - gen.Write((char)ch); ch = fram.ReadByte(); 790 + gen.Write((char)ch); ch = fram.Read(); 785 791 } 786 792 throw new FatalError("incomplete or corrupt scanner frame file"); 787 793 } ··· 868 874 } 869 875 870 876 void OpenGen(bool backUp) { /* pdt */ 871 - try { 872 - string fn = tab.srcDir + "Scanner.cs"; /* pdt */ 873 - if (File.Exists(fn) && backUp) File.Copy(fn, fn + ".old", true); 874 - gen = new StreamWriter(new FileStream(fn, FileMode.Create)); /* pdt */ 875 - } catch (IOException) { 876 - throw new FatalError("Cannot generate scanner file"); 877 - } 877 + generatedSource = new StringBuilder(); 878 + gen = new StringWriter(generatedSource, CultureInfo.InvariantCulture); 878 879 } 879 880 880 881 public void WriteScanner() { 881 882 int i; 882 - string fr = tab.srcDir + "Scanner.frame"; /* pdt */ 883 - if (!File.Exists(fr)) { 884 - if (tab.frameDir != null) 885 - fr = tab.frameDir.Trim() + Path.DirectorySeparatorChar + "Scanner.frame"; 886 - if (!File.Exists(fr)) throw new FatalError("Cannot find Scanner.frame"); 887 - } 888 - try { 889 - fram = new FileStream(fr, FileMode.Open, FileAccess.Read, FileShare.Read); 890 - } catch (FileNotFoundException) { 891 - throw new FatalError("Cannot open Scanner.frame."); 892 - } 883 + if (Frame == null) throw new FatalError("Cannot find Scanner.frame"); 884 + fram = new StringReader(Frame); 893 885 OpenGen(true); /* pdt */ 894 886 if (dirtyDFA) MakeDeterministic(); 895 887 CopyFramePart("-->begin"); ··· 945 937 WriteState(state); 946 938 CopyFramePart("$$$"); 947 939 if (tab.nsName != null && tab.nsName.Length > 0) gen.Write("}"); 948 - gen.Close(); 940 + gen.Flush(); 949 941 } 950 942 951 943 public DFA (Parser parser) { ··· 963 955 964 956 } // end DFA 965 957 966 - } // end namespace 958 + } // end namespace
-11
PxCoco/GenerateParser.proj
··· 1 - <Project DefaultTargets="CocoParser" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 2 - <PropertyGroup> 3 - <PxCoco>$(ProjectDir)..\Tools\PxCoco.exe</PxCoco> 4 - </PropertyGroup> 5 - <UsingTask AssemblyFile="$(PxCoco)" TaskName="Merge" /> 6 - <UsingTask AssemblyFile="$(PxCoco)" TaskName="PxCoco" /> 7 - <Target Name="CocoParser"> 8 - <PxCoco Grammar="Coco.atg" Namespace="at.jku.ssw.Coco" FramesDirectory="$(ProjectDirectory)"> 9 - </PxCoco> 10 - </Target> 11 - </Project>
+28 -46
PxCoco/GeneratorOptions.cs
··· 2 2 3 3 namespace at.jku.ssw.Coco 4 4 { 5 - public class GeneratorOptions 5 + public sealed class GeneratorOptions 6 6 { 7 7 public GeneratorOptions(Action<string> writeMessage, Action<string> writeError) 8 8 { 9 - WriteMessage = writeMessage; 10 - WriteError = writeError; 9 + WriteMessage = writeMessage ?? throw new ArgumentNullException(nameof(writeMessage)); 10 + WriteError = writeError ?? throw new ArgumentNullException(nameof(writeError)); 11 11 } 12 12 13 - public string SrcName { get; set; } 14 - 15 - /// <summary> 16 - /// <list type="table"> 17 - /// <item> 18 - /// <term>F</term> 19 - /// <description>list first/follow sets</description> 20 - /// </item> 21 - /// <item> 22 - /// <term>G</term> 23 - /// <description>print syntax graph</description> 24 - /// </item> 25 - /// <item> 26 - /// <term>I</term> 27 - /// <description>trace computation of first sets</description> 28 - /// </item> 29 - /// <item> 30 - /// <term>J</term> 31 - /// <description>list ANY and SYNC sets</description> 32 - /// </item> 33 - /// <item> 34 - /// <term>P</term> 35 - /// <description>print statistics</description> 36 - /// </item> 37 - /// <item> 38 - /// <term>S</term> 39 - /// <description>list symbol table</description> 40 - /// </item> 41 - /// <item> 42 - /// <term>X</term> 43 - /// <description>list cross reference table</description> 44 - /// </item> 45 - /// </list> 46 - /// </summary> 47 - public string DirectDebugTrace { get; set; } 48 - public string FrameDirectoryPath { get; set; } 13 + public string Grammar { get; set; } 14 + public string SourceName { get; set; } 15 + public string ParserFrame { get; set; } 16 + public string ParserFrameName { get; set; } 17 + public string ScannerFrame { get; set; } 49 18 public string Namespace { get; set; } 19 + public bool GenerateScanner { get; set; } = true; 50 20 public bool DirectDebug { get; set; } 21 + public string DirectDebugTrace { get; set; } 22 + public Action<string> WriteMessage { get; } 23 + public Action<string> WriteError { get; } 24 + } 51 25 52 - /// <summary> 53 - /// Optional. The path to use as the root for relative file names in <c>#line</c> directives. 54 - /// </summary> 55 - public string RelativePathRoot { get; set; } 56 - public Action<string> WriteMessage { get; set; } 57 - public Action<string> WriteError { get; set; } 26 + public sealed class GenerationResult 27 + { 28 + public GenerationResult(bool success, string parser, string scanner, string trace) 29 + { 30 + Success = success; 31 + Parser = parser; 32 + Scanner = scanner; 33 + Trace = trace; 34 + } 35 + 36 + public bool Success { get; } 37 + public string Parser { get; } 38 + public string Scanner { get; } 39 + public string Trace { get; } 58 40 } 59 - } 41 + }
-106
PxCoco/Merge.cs
··· 1 - using System; 2 - using System.Collections.Generic; 3 - using System.ComponentModel; 4 - using System.IO; 5 - using System.Runtime.CompilerServices; 6 - using PxCoco.Msbuild; 7 - 8 - // ReSharper disable CheckNamespace 9 - // ReSharper disable MemberCanBePrivate.Global 10 - 11 - namespace at.jku.ssw.Coco 12 - { 13 - public static partial class Coco 14 - { 15 - public static void Merge(string targetPath, string[] sourcePaths, Action<string> logMessage, string relativePathRoot = null) 16 - { 17 - string relativePath(string path) => 18 - relativePathRoot == null ? path : Platform.GetRelativePath(relativePathRoot, path); 19 - 20 - const int bufferSize = 512; 21 - var buffer = new byte[bufferSize]; 22 - //Use a target stream 23 - using (var ts = new FileStream(targetPath, FileMode.Create, FileAccess.Write, FileShare.None)) 24 - using (var sw = new StreamWriter(ts)) 25 - { 26 - sw.WriteLine("//-- GENERATED BY PxCoco -merge --//"); 27 - sw.WriteLine("//-- make sure to modify the source files instead of this one! --//"); 28 - sw.WriteLine("//-- file paths are relative to: {0} --//", relativePathRoot); 29 - foreach (var sourcePath in sourcePaths) 30 - { 31 - if (!File.Exists(sourcePath)) 32 - { 33 - logMessage("Source file " + sourcePath + " does not exist."); 34 - continue; 35 - } 36 - var sourceName = Path.GetFileName(sourcePath); 37 - logMessage.Invoke($"Adding {sourceName} to {Path.GetFileName(targetPath)}."); 38 - //Use a source stream 39 - using (var ss = new FileStream(sourcePath, FileMode.Open, FileAccess.Read, FileShare.Read)) 40 - { 41 - sw.WriteLine("\n#file:" + relativePath(sourcePath) + "#"); 42 - sw.Flush(); 43 - int bytesRead; 44 - while((bytesRead = ss.Read(buffer, 0, bufferSize)) > 0) 45 - ts.Write(buffer, 0, bytesRead); 46 - } 47 - 48 - } 49 - //Switch line processing back to normal, in case the user wants to add stuff here 50 - sw.WriteLine("#file:default#"); 51 - sw.Flush(); 52 - } 53 - } 54 - 55 - public static void MergeCommandLine(string[] args) 56 - { 57 - if (args.Length < 3) 58 - { 59 - Console.WriteLine("Usage: PxCoco -merge {grammarParts.atg} output.atg"); 60 - return; 61 - } 62 - 63 - string relativePath = null; 64 - var sourcePaths = new List<string>(); 65 - 66 - var argv = new Queue<string>(args); 67 - 68 - bool next(out string arg) 69 - { 70 - // Queue.TryDequeue is not present in .NET Framework 4.8 71 - if (argv.Count > 0) 72 - { 73 - arg = argv.Dequeue(); 74 - return true; 75 - } 76 - else 77 - { 78 - arg = null; 79 - return false; 80 - } 81 - } 82 - 83 - while (next(out var arg)) 84 - { 85 - switch (arg) 86 - { 87 - case "-relative" when next(out relativePath): 88 - break; 89 - default: 90 - sourcePaths.Add(arg); 91 - break; 92 - } 93 - } 94 - 95 - // The last source path is actually the target path 96 - if (sourcePaths.Count < 2) 97 - { 98 - throw new ArgumentException("At least two paths are required (source, target)."); 99 - } 100 - var targetPath = sourcePaths[sourcePaths.Count - 1]; 101 - sourcePaths.RemoveAt(sourcePaths.Count - 1); 102 - 103 - Merge(targetPath, sourcePaths.ToArray(), Console.WriteLine, relativePath); 104 - } 105 - } 106 - }
-65
PxCoco/Msbuild/MergeTask.cs
··· 1 - using System; 2 - using System.Collections.Generic; 3 - using System.Text; 4 - using Microsoft.Build.Framework; 5 - 6 - namespace PxCoco.Msbuild 7 - { 8 - public class Merge : Microsoft.Build.Utilities.Task 9 - { 10 - 11 - private ITaskItem _outputFile; 12 - 13 - [Output, Required] 14 - public ITaskItem OutputFile 15 - { 16 - get { return _outputFile; } 17 - set { _outputFile = value; } 18 - } 19 - 20 - private ITaskItem[] _inputFiles; 21 - 22 - [Required] 23 - public ITaskItem[] InputFiles 24 - { 25 - get { return _inputFiles; } 26 - set { _inputFiles = value; } 27 - } 28 - public string RelativePathRoot { get; set; } 29 - 30 - public override bool Execute() 31 - { 32 - if (_outputFile == null) 33 - { 34 - Log.LogError("No output file provided for PxCoco/R -merge"); 35 - return false; 36 - } 37 - 38 - if (_inputFiles == null || _inputFiles.Length <= 0) 39 - { 40 - Log.LogError("No input files defined for PxCoco/R -merge"); 41 - return false; 42 - } 43 - 44 - string[] inputPaths = new string[_inputFiles.Length]; 45 - for (int i = 0; i < _inputFiles.Length; i++) 46 - inputPaths[i] = _inputFiles[i].ItemSpec; 47 - 48 - try 49 - { 50 - at.jku.ssw.Coco.Coco.Merge( 51 - _outputFile.ItemSpec, 52 - inputPaths, 53 - text => Log.LogMessageFromText(text, MessageImportance.Normal), 54 - RelativePathRoot); 55 - } 56 - catch (Exception ex) 57 - { 58 - Log.LogErrorFromException(ex); 59 - return false; 60 - } 61 - 62 - return true; 63 - } 64 - } 65 - }
-60
PxCoco/Msbuild/Platform.cs
··· 1 - using System; 2 - using System.IO; 3 - using System.Runtime.InteropServices; 4 - using System.Text; 5 - 6 - namespace PxCoco.Msbuild 7 - { 8 - public static class Platform 9 - { 10 - #if NETFRAMEWORK 11 - private static string _platformGetRelativePath(string relativeTo, string path) 12 - { 13 - var fromAttr = getPathAttribute(relativeTo); 14 - var toAttr = getPathAttribute(path); 15 - 16 - var relativePath = new StringBuilder(260); // MAX_PATH 17 - if(PathRelativePathTo( 18 - relativePath, 19 - relativeTo, 20 - fromAttr, 21 - path, 22 - toAttr) == 0) 23 - { 24 - throw new ArgumentException("Paths must have a common prefix"); 25 - } 26 - return relativePath.ToString(); 27 - } 28 - 29 - private static int getPathAttribute(string path) 30 - { 31 - var di = new DirectoryInfo(path); 32 - if (di.Exists) 33 - { 34 - return FILE_ATTRIBUTE_DIRECTORY; 35 - } 36 - 37 - var fi = new FileInfo(path); 38 - if(fi.Exists) 39 - { 40 - return FILE_ATTRIBUTE_NORMAL; 41 - } 42 - 43 - throw new FileNotFoundException(); 44 - } 45 - 46 - private const int FILE_ATTRIBUTE_DIRECTORY = 0x10; 47 - private const int FILE_ATTRIBUTE_NORMAL = 0x80; 48 - 49 - [DllImport("shlwapi.dll", SetLastError = true)] 50 - private static extern int PathRelativePathTo(StringBuilder pszPath, string pszFrom, int dwAttrFrom, string pszTo, int dwAttrTo); 51 - 52 - #else 53 - private static string _platformGetRelativePath(string relativeTo, string path) 54 - { 55 - return Path.GetRelativePath(relativeTo, path); 56 - } 57 - #endif 58 - public static string GetRelativePath(string relativeTo, string path) => _platformGetRelativePath(relativeTo, path); 59 - } 60 - }
-77
PxCoco/Msbuild/PxCocoTask.cs
··· 1 - using System; 2 - using System.Diagnostics.CodeAnalysis; 3 - using at.jku.ssw.Coco; 4 - using Microsoft.Build.Framework; 5 - using Microsoft.Build.Utilities; 6 - 7 - namespace PxCoco.Msbuild 8 - { 9 - [SuppressMessage("ReSharper", "AutoPropertyCanBeMadeGetOnly.Global")] 10 - [SuppressMessage("ReSharper", "UnusedMember.Global")] 11 - [SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Global")] 12 - [SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] 13 - public class PxCoco : Task 14 - { 15 - [Required] 16 - public ITaskItem Grammar { get; set; } 17 - 18 - [Output] 19 - public ITaskItem[] OutputFiles { get; private set; } 20 - 21 - public string Namespace { get; set; } = null; 22 - 23 - public string FramesDirectory { get; set; } = null; 24 - 25 - public bool DirectDebug { get; set; } = false; 26 - 27 - public string RelativePathRoot { get; set; } 28 - 29 - public override bool Execute() 30 - { 31 - if (Grammar == null) 32 - { 33 - Log.LogError("PxCoco requires a grammar file."); 34 - return false; 35 - } 36 - 37 - if (!System.IO.File.Exists(Grammar.ItemSpec)) 38 - { 39 - Log.LogError("The grammar file {0} does not exist", Grammar.ItemSpec); 40 - return false; 41 - } 42 - 43 - OutputFiles = new ITaskItem[2]; 44 - OutputFiles[0] = new TaskItem("Parser.cs"); 45 - OutputFiles[1] = new TaskItem("Scanner.cs"); 46 - 47 - return Coco.Generate(//Continue here: extract line number and column to forward them to the IDE 48 - new GeneratorOptions(text => Log.LogMessageFromText(text, MessageImportance.High), _msBuildError) 49 - { 50 - SrcName = Grammar.ItemSpec, 51 - DirectDebugTrace = null, 52 - DirectDebug = DirectDebug, 53 - FrameDirectoryPath = FramesDirectory, 54 - Namespace = Namespace, 55 - RelativePathRoot = RelativePathRoot 56 - }); 57 - } 58 - 59 - private void _msBuildError(string ex) 60 - { 61 - int idxComma, idxClosing; 62 - if (ex.StartsWith("(") && (idxComma = ex.IndexOf(',')) > 0 && (idxClosing = ex.IndexOf(')')) > 0 && idxClosing > idxComma) 63 - { 64 - var line = int.Parse(ex.Substring(1, idxComma - 1)); 65 - var column = int.Parse(ex.Substring(idxComma + 1, idxClosing - idxComma - 1)); 66 - var idxEndFile = ex.IndexOf("::", StringComparison.InvariantCulture); 67 - var errorFile = ex.Substring(idxClosing + 1, idxEndFile - idxClosing - 2); 68 - var errorMessage = ex.Substring(idxEndFile + 2); 69 - Log.LogMessageFromText( 70 - $"line={line}\ncolumn={column}\nerrorFile={errorFile}\nerrorMessage={errorMessage}", MessageImportance.High); 71 - Log.LogError("grammar", "", "Coco/R", errorFile, line, column, line, column, errorMessage); 72 - } 73 - else 74 - Log.LogError(ex); 75 - } 76 - } 77 - }
+21 -28
PxCoco/ParserGen.cs
··· 40 40 using System.Collections; 41 41 using System.Text; 42 42 using System.Collections.Generic; 43 - using System.Runtime.InteropServices; 44 - using PxCoco.Msbuild; 43 + using System.Globalization; 45 44 46 45 namespace at.jku.ssw.Coco { 47 46 ··· 68 67 69 68 int errorNr; // highest parser error number 70 69 Symbol curSy; // symbol whose production is currently generated 71 - FileStream fram; // parser frame file 70 + TextReader fram; // parser frame 72 71 int frameLineNumber = 1; 73 - StreamWriter gen; // generated parser source file 72 + TextWriter gen; // generated parser source 74 73 StringWriter err; // generated parser error messages 75 74 ArrayList symSet = new ArrayList(); 76 75 ··· 79 78 Errors errors; 80 79 Buffer buffer; 81 80 private string _relativePathRoot; 81 + private StringBuilder _generatedSource; 82 + 83 + public string Frame { get; set; } 84 + 85 + public string FrameName { get; set; } = "Parser.frame"; 86 + 87 + public string GeneratedSource => _generatedSource?.ToString(); 82 88 83 89 void Indent (int n) { 84 90 for (int i = 1; i <= n; i++) gen.Write('\t'); ··· 121 127 return path; 122 128 } 123 129 124 - return Platform.GetRelativePath(RelativePathRoot, path); 130 + return Path.GetRelativePath(RelativePathRoot, path); 125 131 } 126 132 127 133 128 134 void CopyFramePart (string stop) { 129 135 char startCh = stop[0]; 130 136 int endOfStopString = stop.Length-1; 131 - int ch = fram.ReadByte(); 137 + int ch = fram.Read(); 132 138 if ((!DirectDebug) && ch != EOF) 133 - gen.WriteLine("\n#line {0} \"{1}\" //FRAME", frameLineNumber, _pathForLineDirective(fram.Name)); 139 + gen.WriteLine("\n#line {0} \"{1}\" //FRAME", frameLineNumber, _pathForLineDirective(FrameName)); 134 140 while (ch != EOF) 135 141 if (ch == startCh) { 136 142 int i = 0; ··· 144 150 frameLineNumber++; 145 151 return; // stop[0..i] found 146 152 } 147 - ch = fram.ReadByte(); i++; 153 + ch = fram.Read(); i++; 148 154 } while (ch == stop[i]); 149 155 // stop[0..i-1] found; continue with last read character 150 156 gen.Write(stop.Substring(0, i)); 151 157 } else { 152 - gen.Write((char)ch); ch = fram.ReadByte(); 158 + gen.Write((char)ch); ch = fram.Read(); 153 159 if (ch == (byte)ParserGen.LF) 154 160 frameLineNumber++; 155 161 } ··· 468 474 } 469 475 470 476 void OpenGen(bool backUp) { /* pdt */ 471 - try { 472 - string fn = tab.srcDir + "Parser.cs"; /* pdt */ 473 - if (File.Exists(fn) && backUp) File.Copy(fn, fn + ".old", true); 474 - gen = new StreamWriter(new FileStream(fn, FileMode.Create)); /* pdt */ 475 - } catch (IOException) { 476 - throw new FatalError("Cannot generate parser file"); 477 - } 477 + _generatedSource = new StringBuilder(); 478 + gen = new StringWriter(_generatedSource, CultureInfo.InvariantCulture); 478 479 } 479 480 480 481 public void WriteParser () { 481 482 int oldPos = buffer.Pos; // Pos is modified by CopySourcePart 482 483 symSet.Add(tab.allSyncSets); 483 - string fr = tab.srcDir + "Parser.frame"; 484 - if (!File.Exists(fr)) { 485 - if (tab.frameDir != null) fr = tab.frameDir.Trim() + Path.DirectorySeparatorChar + "Parser.frame"; 486 - if (!File.Exists(fr)) throw new FatalError("Cannot find Parser.frame"); 487 - } 488 - try { 489 - fram = new FileStream(fr, FileMode.Open, FileAccess.Read, FileShare.Read); 490 - } catch (IOException) { 491 - throw new FatalError("Cannot open Parser.frame."); 492 - } 484 + if (Frame == null) throw new FatalError("Cannot find Parser.frame"); 485 + fram = new StringReader(Frame); 493 486 OpenGen(true); /* pdt */ 494 487 err = new StringWriter(); 495 488 foreach (Symbol sym in tab.terminals) GenErrorMsg(tErr, sym); ··· 518 511 CopyFramePart("$$$"); 519 512 /* AW 2002-12-20 close namespace, if it exists */ 520 513 if (tab.nsName != null && tab.nsName.Length > 0) gen.Write("}"); 521 - gen.Close(); 514 + gen.Flush(); 522 515 buffer.Pos = oldPos; 523 516 } 524 517 ··· 541 534 542 535 } // end ParserGen 543 536 544 - } // end namespace 537 + } // end namespace
+15 -35
PxCoco/PxCoco.csproj
··· 1 1 <Project Sdk="Microsoft.NET.Sdk"> 2 2 3 3 <PropertyGroup> 4 - <OutputType>Exe</OutputType> 5 - <!-- Override defaults from Directory.Build.props for legacy project --> 6 - <TargetFramework /> 7 - <TargetFrameworks>net6.0;net48</TargetFrameworks> 8 - <LangVersion>7.3</LangVersion> 4 + <TargetFramework>net10.0</TargetFramework> 5 + <IsPackable>false</IsPackable> 6 + <IsRoslynComponent>true</IsRoslynComponent> 9 7 <Nullable>disable</Nullable> 10 - <ImplicitUsings>disable</ImplicitUsings> 11 - </PropertyGroup> 12 - 13 - <PropertyGroup> 14 - <IsPackable>true</IsPackable> 15 - <IsTool>true</IsTool> 16 - <Title>Prexonite Coco/R</Title> 17 - <PackageDescription>Coco/R is a compiler generator, which takes an attributed grammar of a source language and generates a scanner and a parser for this language. The scanner works as a deterministic finite automaton. The parser uses recursive descent. LL(1) conflicts can be resolved by a multi-symbol lookahead or by semantic checks. Thus the class of accepted grammars is LL(k) for an arbitrary k. The 'Prexonite' version is slightly modified and extended with MSBuild tasks.</PackageDescription> 18 - <Description>$(PackageDescription)</Description> 19 - <Copyright>Copyright (c) 1990, 2005 Hanspeter Moessenboeck, University of Linz 20 - extended by M. Loeberbauer &amp; A. Woess, Univ. of Linz 21 - with improvements by Pat Terry, Rhodes University. Prexonite extensions by Christian Klauser</Copyright> 22 - 23 - <!-- Suppresses the warnings about the package not having assemblies in lib/*/.dll.--> 24 - <NoPackageAnalysis>true</NoPackageAnalysis> 25 - <!-- Change the default location where NuGet will put the build output --> 26 - <BuildOutputTargetFolder>tasks</BuildOutputTargetFolder> 27 8 </PropertyGroup> 28 9 29 - <PropertyGroup> 30 - <PackageLicenseFile>LICENSE.txt</PackageLicenseFile> 31 - </PropertyGroup> 32 - 33 - <ItemGroup> 34 - <None Include="licenses\LICENSE.txt" Pack="true" PackagePath="" /> 35 - <Content Include="build\PxCoco.props" PackagePath="build\" /> 36 - <Content Include="buildMultiTargeting\PxCoco.props" PackagePath="buildMultiTargeting\" /> 37 - </ItemGroup> 10 + <ItemGroup> 11 + <Reference Include="Microsoft.CodeAnalysis"> 12 + <HintPath>$(MSBuildSDKsPath)/../Roslyn/bincore/Microsoft.CodeAnalysis.dll</HintPath> 13 + <Private>false</Private> 14 + </Reference> 15 + <Reference Include="Microsoft.CodeAnalysis.CSharp"> 16 + <HintPath>$(MSBuildSDKsPath)/../Roslyn/bincore/Microsoft.CodeAnalysis.CSharp.dll</HintPath> 17 + <Private>false</Private> 18 + </Reference> 19 + </ItemGroup> 38 20 39 21 <ItemGroup> 40 - <PackageReference Include="Microsoft.Build.Framework" /> 41 - <PackageReference Include="Microsoft.Build.Utilities.Core" /> 42 - <!-- marks all packages as 'local only' so they don't end up in the nuspec --> 43 - <PackageReference Update="@(PackageReference)" PrivateAssets="All" /> 22 + <EmbeddedResource Include="../Tools/Parser.frame" LogicalName="PxCoco.Parser.frame" /> 23 + <EmbeddedResource Include="../Tools/Scanner.frame" LogicalName="PxCoco.Scanner.frame" /> 44 24 </ItemGroup> 45 25 46 26 </Project>
-37
PxCoco/PxCoco.sln
··· 1 -  2 - Microsoft Visual Studio Solution File, Format Version 12.00 3 - # Visual Studio Version 16 4 - VisualStudioVersion = 16.0.29020.237 5 - MinimumVisualStudioVersion = 15.0.26124.0 6 - Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PxCoco", "PxCoco.csproj", "{A9AD8B78-FA8D-44A9-95D4-ADE80030DB0A}" 7 - EndProject 8 - Global 9 - GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 - Debug|Any CPU = Debug|Any CPU 11 - Debug|x64 = Debug|x64 12 - Debug|x86 = Debug|x86 13 - Release|Any CPU = Release|Any CPU 14 - Release|x64 = Release|x64 15 - Release|x86 = Release|x86 16 - EndGlobalSection 17 - GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 - {A9AD8B78-FA8D-44A9-95D4-ADE80030DB0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 - {A9AD8B78-FA8D-44A9-95D4-ADE80030DB0A}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 - {A9AD8B78-FA8D-44A9-95D4-ADE80030DB0A}.Debug|x64.ActiveCfg = Debug|Any CPU 21 - {A9AD8B78-FA8D-44A9-95D4-ADE80030DB0A}.Debug|x64.Build.0 = Debug|Any CPU 22 - {A9AD8B78-FA8D-44A9-95D4-ADE80030DB0A}.Debug|x86.ActiveCfg = Debug|Any CPU 23 - {A9AD8B78-FA8D-44A9-95D4-ADE80030DB0A}.Debug|x86.Build.0 = Debug|Any CPU 24 - {A9AD8B78-FA8D-44A9-95D4-ADE80030DB0A}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 - {A9AD8B78-FA8D-44A9-95D4-ADE80030DB0A}.Release|Any CPU.Build.0 = Release|Any CPU 26 - {A9AD8B78-FA8D-44A9-95D4-ADE80030DB0A}.Release|x64.ActiveCfg = Release|Any CPU 27 - {A9AD8B78-FA8D-44A9-95D4-ADE80030DB0A}.Release|x64.Build.0 = Release|Any CPU 28 - {A9AD8B78-FA8D-44A9-95D4-ADE80030DB0A}.Release|x86.ActiveCfg = Release|Any CPU 29 - {A9AD8B78-FA8D-44A9-95D4-ADE80030DB0A}.Release|x86.Build.0 = Release|Any CPU 30 - EndGlobalSection 31 - GlobalSection(SolutionProperties) = preSolution 32 - HideSolutionNode = FALSE 33 - EndGlobalSection 34 - GlobalSection(ExtensibilityGlobals) = postSolution 35 - SolutionGuid = {3A5543EE-73FF-4D54-9B74-1C2270B63FDE} 36 - EndGlobalSection 37 - EndGlobal
+266
PxCoco/PxCocoGenerator.cs
··· 1 + using System.Collections.Immutable; 2 + using System.Globalization; 3 + using System.Reflection; 4 + using System.Text; 5 + using Microsoft.CodeAnalysis; 6 + using Microsoft.CodeAnalysis.Diagnostics; 7 + using Microsoft.CodeAnalysis.Text; 8 + 9 + namespace PxCoco.Generators; 10 + 11 + [Generator] 12 + public sealed class PxCocoGenerator : IIncrementalGenerator 13 + { 14 + const string GrammarMetadata = "build_metadata.AdditionalFiles.PxCocoGrammar"; 15 + const string OrderMetadata = "build_metadata.AdditionalFiles.PxCocoOrder"; 16 + 17 + static readonly DiagnosticDescriptor InvalidInput = new( 18 + "PRXCOCO001", 19 + "Invalid PxCoco input", 20 + "{0}", 21 + "PxCoco", 22 + DiagnosticSeverity.Error, 23 + isEnabledByDefault: true); 24 + 25 + static readonly DiagnosticDescriptor InvalidGrammar = new( 26 + "PRXCOCO002", 27 + "Invalid PxCoco grammar", 28 + "{0}", 29 + "PxCoco", 30 + DiagnosticSeverity.Error, 31 + isEnabledByDefault: true); 32 + 33 + static readonly DiagnosticDescriptor GenerationFailure = new( 34 + "PRXCOCO003", 35 + "PxCoco generation failed", 36 + "{0}", 37 + "PxCoco", 38 + DiagnosticSeverity.Error, 39 + isEnabledByDefault: true); 40 + 41 + public void Initialize(IncrementalGeneratorInitializationContext context) 42 + { 43 + var files = context.AdditionalTextsProvider 44 + .Combine(context.AnalyzerConfigOptionsProvider) 45 + .Select(static (pair, cancellationToken) => ReadFile(pair.Left, pair.Right, cancellationToken)) 46 + .Where(static file => file is not null) 47 + .Collect(); 48 + 49 + context.RegisterSourceOutput(files, Generate); 50 + } 51 + 52 + static GrammarFile ReadFile( 53 + AdditionalText file, 54 + AnalyzerConfigOptionsProvider optionsProvider, 55 + CancellationToken cancellationToken) 56 + { 57 + var options = optionsProvider.GetOptions(file); 58 + if (!options.TryGetValue(GrammarMetadata, out var grammar) || string.IsNullOrWhiteSpace(grammar)) 59 + return null; 60 + 61 + var order = 0; 62 + if (options.TryGetValue(OrderMetadata, out var orderText) && 63 + !int.TryParse(orderText, NumberStyles.Integer, CultureInfo.InvariantCulture, out order)) 64 + order = int.MinValue; 65 + 66 + var text = file.GetText(cancellationToken); 67 + return text is null ? null : new GrammarFile(file.Path, grammar, order, text); 68 + } 69 + 70 + static void Generate(SourceProductionContext context, ImmutableArray<GrammarFile> files) 71 + { 72 + GenerateGrammar( 73 + context, 74 + files, 75 + grammarName: "Prexonite", 76 + targetNamespace: "Prexonite.Compiler", 77 + generateScanner: false, 78 + parserHintName: "Prexonite.Compiler.Parser.g.cs", 79 + scannerHintName: null); 80 + 81 + GenerateGrammar( 82 + context, 83 + files, 84 + grammarName: "PTypeExpression", 85 + targetNamespace: "Prexonite.Internal", 86 + generateScanner: true, 87 + parserHintName: "Prexonite.Internal.Parser.g.cs", 88 + scannerHintName: "Prexonite.Internal.Scanner.g.cs"); 89 + } 90 + 91 + static void GenerateGrammar( 92 + SourceProductionContext context, 93 + ImmutableArray<GrammarFile> allFiles, 94 + string grammarName, 95 + string targetNamespace, 96 + bool generateScanner, 97 + string parserHintName, 98 + string scannerHintName) 99 + { 100 + var files = allFiles 101 + .Where(file => string.Equals(file.Grammar, grammarName, StringComparison.Ordinal)) 102 + .OrderBy(file => file.Order) 103 + .ThenBy(file => file.Path, StringComparer.Ordinal) 104 + .ToArray(); 105 + 106 + if (files.Length == 0) 107 + { 108 + context.ReportDiagnostic(Diagnostic.Create( 109 + InvalidInput, 110 + Location.None, 111 + $"No AdditionalFiles were supplied for the '{grammarName}' grammar.")); 112 + return; 113 + } 114 + 115 + if (files.Any(file => file.Order == int.MinValue)) 116 + { 117 + context.ReportDiagnostic(Diagnostic.Create( 118 + InvalidInput, 119 + Location.None, 120 + $"Grammar '{grammarName}' has a file with a non-integer PxCocoOrder.")); 121 + return; 122 + } 123 + 124 + try 125 + { 126 + var errors = new List<string>(); 127 + var grammar = files.Length == 1 ? files[0].Text.ToString() : Merge(files); 128 + var result = at.jku.ssw.Coco.Coco.Generate(new at.jku.ssw.Coco.GeneratorOptions( 129 + writeMessage: static _ => { }, 130 + writeError: errors.Add) 131 + { 132 + Grammar = grammar, 133 + SourceName = files.Length == 1 ? files[0].Path : grammarName + ".atg", 134 + ParserFrame = ReadResource("PxCoco.Parser.frame"), 135 + ParserFrameName = "../../Tools/Parser.frame", 136 + ScannerFrame = ReadResource("PxCoco.Scanner.frame"), 137 + Namespace = targetNamespace, 138 + GenerateScanner = generateScanner 139 + }); 140 + 141 + foreach (var error in errors) 142 + ReportGrammarError(context, files, error); 143 + 144 + if (!result.Success || result.Parser is null) 145 + return; 146 + 147 + context.AddSource( 148 + parserHintName, 149 + SourceText.From("#nullable enable\n" + result.Parser, Encoding.UTF8)); 150 + if (generateScanner) 151 + { 152 + if (result.Scanner is null) 153 + { 154 + context.ReportDiagnostic(Diagnostic.Create( 155 + GenerationFailure, 156 + Location.None, 157 + $"Grammar '{grammarName}' did not produce a scanner.")); 158 + return; 159 + } 160 + 161 + context.AddSource(scannerHintName, SourceText.From(result.Scanner, Encoding.UTF8)); 162 + } 163 + } 164 + catch (Exception exception) 165 + { 166 + context.ReportDiagnostic(Diagnostic.Create( 167 + GenerationFailure, 168 + Location.None, 169 + $"Grammar '{grammarName}': {exception.Message}")); 170 + } 171 + } 172 + 173 + static string Merge(IEnumerable<GrammarFile> files) 174 + { 175 + var result = new StringBuilder(); 176 + result.AppendLine("//-- GENERATED INTERNALLY BY PxCoco --//"); 177 + foreach (var file in files) 178 + { 179 + result.AppendLine(); 180 + result.Append("#file:").Append(file.Path).AppendLine("#"); 181 + result.Append(file.Text.ToString()); 182 + } 183 + result.AppendLine("#file:default#"); 184 + return result.ToString(); 185 + } 186 + 187 + static string ReadResource(string name) 188 + { 189 + using var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(name) 190 + ?? throw new InvalidOperationException($"Embedded resource '{name}' is missing."); 191 + using var reader = new StreamReader(stream, Encoding.UTF8, detectEncodingFromByteOrderMarks: true); 192 + return reader.ReadToEnd(); 193 + } 194 + 195 + static void ReportGrammarError( 196 + SourceProductionContext context, 197 + IReadOnlyCollection<GrammarFile> files, 198 + string error) 199 + { 200 + if (!TryParseError(error, out var path, out var line, out var column, out var message)) 201 + { 202 + context.ReportDiagnostic(Diagnostic.Create(InvalidGrammar, Location.None, error)); 203 + return; 204 + } 205 + 206 + var file = files.FirstOrDefault(candidate => PathsEqual(candidate.Path, path)); 207 + var location = file is null ? Location.None : CreateLocation(file, line, column); 208 + context.ReportDiagnostic(Diagnostic.Create(InvalidGrammar, location, message)); 209 + } 210 + 211 + static bool TryParseError( 212 + string error, 213 + out string path, 214 + out int line, 215 + out int column, 216 + out string message) 217 + { 218 + path = ""; 219 + line = 0; 220 + column = 0; 221 + message = error; 222 + if (string.IsNullOrEmpty(error) || error[0] != '(') 223 + return false; 224 + 225 + var comma = error.IndexOf(','); 226 + var closing = error.IndexOf(')'); 227 + var separator = error.IndexOf("::", StringComparison.Ordinal); 228 + if (comma < 2 || closing < comma || separator < closing) 229 + return false; 230 + 231 + if (!int.TryParse(error.AsSpan(1, comma - 1), NumberStyles.Integer, CultureInfo.InvariantCulture, out line) || 232 + !int.TryParse(error.AsSpan(comma + 1, closing - comma - 1), NumberStyles.Integer, CultureInfo.InvariantCulture, out column)) 233 + return false; 234 + 235 + path = error.Substring(closing + 1, separator - closing - 1); 236 + message = error[(separator + 2)..]; 237 + return true; 238 + } 239 + 240 + static bool PathsEqual(string left, string right) 241 + { 242 + try 243 + { 244 + return string.Equals(Path.GetFullPath(left), Path.GetFullPath(right), StringComparison.OrdinalIgnoreCase); 245 + } 246 + catch (Exception) 247 + { 248 + return string.Equals(left, right, StringComparison.OrdinalIgnoreCase); 249 + } 250 + } 251 + 252 + static Location CreateLocation(GrammarFile file, int line, int column) 253 + { 254 + var lineIndex = Math.Clamp(line - 1, 0, file.Text.Lines.Count - 1); 255 + var textLine = file.Text.Lines[lineIndex]; 256 + var columnIndex = Math.Clamp(column - 1, 0, textLine.Span.Length); 257 + var position = textLine.Start + columnIndex; 258 + var point = new LinePosition(lineIndex, columnIndex); 259 + return Location.Create( 260 + file.Path, 261 + new TextSpan(position, 0), 262 + new LinePositionSpan(point, point)); 263 + } 264 + 265 + sealed record GrammarFile(string Path, string Grammar, int Order, SourceText Text); 266 + }
-11
PxCoco/SecureGenerateParser.proj
··· 1 - <Project DefaultTargets="CocoParser" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 2 - <PropertyGroup> 3 - <PxCoco>$(ProjectDir)..\Tools\PxCoco0.exe</PxCoco> 4 - </PropertyGroup> 5 - <UsingTask AssemblyFile="$(PxCoco)" TaskName="Merge" /> 6 - <UsingTask AssemblyFile="$(PxCoco)" TaskName="PxCoco" /> 7 - <Target Name="CocoParser"> 8 - <PxCoco Grammar="Coco.atg" Namespace="at.jku.ssw.Coco" FramesDirectory="$(ProjectDirectory)"> 9 - </PxCoco> 10 - </Target> 11 - </Project>
-19
PxCoco/build/PxCoco.props
··· 1 - <Project TreatAsLocalProperty="TaskExt;TaskAssembly"> 2 - 3 - <!-- This property file gets loaded into projects that install this NuGet package. --> 4 - 5 - <PropertyGroup> 6 - <TaskExt Condition=" '$(MSBuildRuntimeType)' == 'Core' ">dll</TaskExt> 7 - <TaskExt Condition=" '$(MSBuildRuntimeType)' != 'Core' ">exe</TaskExt> 8 - <!-- For cross-platform compatibiliy, .NET Core 'executable' are packaged as a 'dll'. 9 - Shipping the naked assembly is portable, shipping a Windows PE-file with 10 - Windows-specific framework initialization code would not be portable. 11 - 12 - This tool can be run via `dotnet PxCoco.dll` (on all platforms) 13 - --> 14 - <TaskAssembly>$(MSBuildThisFileDirectory)..\tasks\PxCoco.$(TaskExt)</TaskAssembly> 15 - </PropertyGroup> 16 - 17 - <UsingTask TaskName="Merge" AssemblyFile="$(TaskAssembly)" /> 18 - <UsingTask TaskName="PxCoco" AssemblyFile="$(TaskAssembly)" /> 19 - </Project>
-4
PxCoco/buildMultiTargeting/PxCoco.props
··· 1 - <Project> 2 - <!-- The ordinary build\PxCoco.props is already multi-targeting-aware. --> 3 - <Import Project="..\build\PxCoco.props" /> 4 - </Project>
-24
PxCoco/licenses/LICENSE.txt
··· 1 - Compiler Generator Coco/R, 2 - Copyright (c) 1990, 2005 Hanspeter Moessenboeck, University of Linz 3 - extended by M. Loeberbauer & A. Woess, Univ. of Linz 4 - with improvements by Pat Terry, Rhodes University 5 - 6 - This program is free software; you can redistribute it and/or modify it 7 - under the terms of the GNU General Public License as published by the 8 - Free Software Foundation; either version 2, or (at your option) any 9 - later version. 10 - 11 - This program is distributed in the hope that it will be useful, but 12 - WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 13 - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 - for more details. 15 - 16 - You should have received a copy of the GNU General Public License along 17 - with this program; if not, write to the Free Software Foundation, Inc., 18 - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 - 20 - As an exception, it is allowed to write an extension of Coco/R that is 21 - used as a plugin in non-free software. 22 - 23 - If not otherwise stated, any source code generated by Coco/R (other than 24 - Coco/R itself) does not fall under the GNU General Public License.
-49
PxCoco/pxcoco-azure-ci-pipeline.yaml
··· 1 - # .NET Desktop 2 - # Build and run tests for .NET Desktop or Windows classic desktop solutions. 3 - # Add steps that publish symbols, save build artifacts, and more: 4 - # https://docs.microsoft.com/azure/devops/pipelines/apps/windows/dot-net 5 - 6 - trigger: 7 - batch: true 8 - branches: 9 - include: 10 - - '*' 11 - paths: 12 - include: 13 - - PxCoco/* 14 - 15 - pr: none 16 - 17 - pool: 18 - vmImage: 'windows-2019' 19 - 20 - variables: 21 - buildConfiguration: 'Release' 22 - 23 - steps: 24 - - task: UseDotNet@2 25 - inputs: 26 - version: '5.0.x' 27 - 28 - - task: DotNetCoreCLI@2 29 - displayName: Restore (Win) 30 - inputs: 31 - command: restore 32 - projects: 'PxCoco/PxCoco.sln' 33 - 34 - - task: DotNetCoreCLI@2 35 - displayName: Build (Win) 36 - inputs: 37 - command: build 38 - projects: 'PxCoco/PxCoco.sln' 39 - arguments: /p:Configuration=$(BuildConfiguration) 40 - 41 - # There are no automated tests for PxCoco. 42 - 43 - - task: DotNetCoreCLI@2 44 - displayName: Pack (Win) 45 - inputs: 46 - command: pack 47 - searchPatternPack: 'PxCoco/PxCoco.csproj' 48 - nobuild: true 49 - configurationToPack: '$(BuildConfiguration)'
-65
PxCoco/pxcoco-azure-release-pipeline.yaml
··· 1 - # .NET Desktop 2 - # Build and run tests for .NET Desktop or Windows classic desktop solutions. 3 - # Add steps that publish symbols, save build artifacts, and more: 4 - # https://docs.microsoft.com/azure/devops/pipelines/apps/windows/dot-net 5 - 6 - trigger: 7 - tags: 8 - include: 9 - - 'pxcoco/v.*' 10 - pr: none 11 - 12 - pool: 13 - vmImage: 'windows-2019' 14 - 15 - variables: 16 - buildConfiguration: 'Release' 17 - Version: '$(Build.BuildNumber)' 18 - 19 - steps: 20 - - task: UseDotNet@2 21 - inputs: 22 - version: '5.0.x' 23 - 24 - - powershell: | 25 - # Remove /refs/tags (10 chars) and pxcoco/v. (9 chars) from checkout string 26 - $ver = $env:BUILD_SOURCEBRANCH.remove(0, 19) 27 - Write-Host "##vso[task.setvariable variable=Version]$ver" 28 - displayName: 'Update version to Tag' 29 - condition: and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/')) 30 - 31 - - task: DotNetCoreCLI@2 32 - displayName: Restore (Win) 33 - inputs: 34 - command: restore 35 - projects: 'PxCoco/PxCoco.sln' 36 - 37 - - task: DotNetCoreCLI@2 38 - displayName: Build (Win) 39 - inputs: 40 - command: build 41 - projects: 'PxCoco/PxCoco.sln' 42 - arguments: /p:Version=$(Version);Configuration=$(BuildConfiguration) 43 - 44 - # There are no automated tests for PxCoco. 45 - 46 - - task: DotNetCoreCLI@2 47 - displayName: Pack (Win) 48 - inputs: 49 - command: pack 50 - searchPatternPack: 'PxCoco/PxCoco.csproj' 51 - nobuild: true 52 - configurationToPack: $(BuildConfiguration) 53 - buildProperties: Version=$(Version) 54 - 55 - - task: PublishPipelineArtifact@0 56 - displayName: Publish (pipeline, Win) 57 - inputs: 58 - artifactName: 'binaries' 59 - targetPath: '$(Build.ArtifactStagingDirectory)' 60 - 61 - - task: DotNetCoreCLI@2 62 - displayName: Publish (NuGet, Win) 63 - inputs: 64 - command: push 65 - publishVstsFeed: 'edge'
Tools/PxCoco.exe

This is a binary file and will not be displayed.

Tools/PxCoco0.exe

This is a binary file and will not be displayed.

-4
azure-pipelines.yml
··· 4 4 branches: 5 5 include: 6 6 - '*' 7 - paths: 8 - exclude: 9 - - PxCoco/* 10 - 11 7 pr: none 12 8 13 9 stages:
-3
azure-release-pipelines.yml
··· 1 1 2 2 trigger: 3 - paths: 4 - exclude: 5 - - PxCoco/* 6 3 tags: 7 4 include: 8 5 - 'v.*'
+1
prx.slnx
··· 3 3 <Project Path="PrexoniteTests/PrexoniteTests.csproj" /> 4 4 <Project Path="PrexoniteTests.Generators/PrexoniteTests.Generators.csproj" /> 5 5 <Project Path="Prx/Prx.csproj" /> 6 + <Project Path="PxCoco/PxCoco.csproj" /> 6 7 </Solution>