diff --git a/.github/workflows/cs.yml b/.github/workflows/cs.yml index 3e0ccdb..e442aef 100644 --- a/.github/workflows/cs.yml +++ b/.github/workflows/cs.yml @@ -8,13 +8,8 @@ jobs: fail-fast: false matrix: include: - - { dotnet: 2.1.x, framework: netcoreapp2.1 } - - { dotnet: 2.2.x, framework: netcoreapp2.2 } - - { dotnet: 3.0.x, framework: netcoreapp3.0 } - - { dotnet: 3.1.x, framework: netcoreapp3.1 } - - { dotnet: 5.0.x, framework: net5.0 } - { dotnet: 6.0.x, framework: net6.0 } - - { dotnet: 7.0.x, framework: net7.0 } + - { dotnet: 8.0.x, framework: net8.0 } name: ${{ matrix.dotnet }} runs-on: ubuntu-latest steps: diff --git a/.gitignore b/.gitignore index 71d3e7c..a17b90f 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,5 @@ test/cs/obj test/java/target .jekyll-cache + +.vscode diff --git a/Makefile b/Makefile index dfda6b4..81052f0 100644 --- a/Makefile +++ b/Makefile @@ -53,7 +53,7 @@ test-all: test-java test-js test-python test-ruby test-java: $(test_grammars:%.peg=%/Grammar.java) cd test/java && mvn clean test -DOTNET_SDK?=netcoreapp3.1 +DOTNET_SDK?=net6.0 test-cs: $(test_grammars:%.peg=%/Grammar.cs) cd test/cs && dotnet test --framework ${DOTNET_SDK} diff --git a/README.md b/README.md index 9f43d3d..8e96292 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Canopy -Canopy is a parser compiler targeting Java, JavaScript, Python and Ruby. It +Canopy is a parser compiler targeting C#, Java, JavaScript, Python and Ruby. It takes a file describing a [parsing expression grammar][1] and compiles it into a parser module in the target language. The generated parsers have no runtime dependency on Canopy itself. diff --git a/src/builders/cs.js b/src/builders/cs.js index 4c1175f..c2c48af 100644 --- a/src/builders/cs.js +++ b/src/builders/cs.js @@ -5,7 +5,7 @@ const Base = require('./base') const TYPES = { address: 'TreeNode', - chunk: 'String', + chunk: 'string', elements: 'List', index: 'int', max: 'int' @@ -54,37 +54,36 @@ class Builder extends Base { package_ (name, actions, block) { this._grammarName = name - this._newBuffer('cs', 'Actions') - this._template('cs', 'Actions.cs', { actions, namespace: this._namespace }) + let bufferName = name.replace(/\./g, '') + this._newBuffer('cs', bufferName) - this._newBuffer('cs', 'CacheRecord') - this._template('cs', 'CacheRecord.cs', { namespace: this._namespace }) + // some pragmas to kill warnings + this.pragma("warning disable CS1717") + + this._line('using System') + this._line('using System.Collections') + this._line('using System.Collections.Generic') + this._line('using System.Text.RegularExpressions') + this._newline() + + this._line(`namespace ${this._namespace} {`, false) + + this._template('cs', 'Actions.cs', { actions }) + this._template('cs', 'CacheRecord.cs') block() + + this._line('}', false) } syntaxNodeClass_ () { let name = 'TreeNode' - - this._newBuffer('cs', name) - this._template('cs', 'TreeNode.cs', { name, namespace: this._namespace }) + this._template('cs', 'TreeNode.cs', { name }) return name } grammarModule_ (block) { - this._newBuffer('cs', 'Grammar') - - // some pragmas to kill warnings - this.pragma("warning disable CS1717") - - this._line('using System') - this._line('using System.Collections') - this._line('using System.Collections.Generic') - this._line('using System.Text.RegularExpressions') - this._newline() - - this._line('namespace ' + this._namespace + ' {', false) this._indent(() => { this._line('public abstract class Grammar {', false) this._indent(() => { @@ -112,8 +111,8 @@ class Builder extends Base { this._newline() block() }) + this._line('}',false) }) - this._line('}}', false) } compileRegex_ (charClass, name) { @@ -125,29 +124,23 @@ class Builder extends Base { } parserClass_ (root) { - this._newBuffer('cs', 'ParseError') - this._template('cs', 'ParseError.cs', { namespace: this._namespace }) - let grammar = this._quote(this._grammarName) let name = this._grammarName.replace(/\./g, '') - this._newBuffer('cs', name) - this._template('cs', 'Parser.cs', { grammar, root, name, namespace: this._namespace }) - let labels = [...this._labels].sort() + this._template('cs', 'Parser.cs', { grammar, root, name }) + this._template('cs', 'ParseError.cs') - this._newBuffer('cs', 'Label') - this._template('cs', 'Label.cs', { labels, namespace: this._namespace }) + let labels = [...this._labels].sort() + this._template('cs', 'Label.cs', { labels }) } class_ (name, parent, block) { this._newline() - this._line('namespace ' + this._namespace + ' {', false) this._indent(() => { this._line('class ' + name + ' : ' + parent + ' {', false) this._scope(block, name) this._line('}', false) }) - this._line('}', false) } constructor_ (args, block) { diff --git a/src/canopy.js b/src/canopy.js index ba57742..2f97064 100644 --- a/src/canopy.js +++ b/src/canopy.js @@ -4,8 +4,8 @@ const Compiler = require('./compiler') module.exports = { builders: { + cs: require('./builders/cs'), java: require('./builders/java'), - cs: require('./builders/cs'), javascript: require('./builders/javascript'), python: require('./builders/python'), ruby: require('./builders/ruby') diff --git a/templates/cs/Actions.cs b/templates/cs/Actions.cs index db318e4..73bc2ee 100644 --- a/templates/cs/Actions.cs +++ b/templates/cs/Actions.cs @@ -1,10 +1,6 @@ -using System.Collections.Generic; -using System; - -namespace {{namespace}} { public interface Actions { {{#each actions}} - public TreeNode {{this}}(String input, int start, int end, List elements); + public TreeNode {{this}}(string input, int start, int end, List elements); {{/each}} } -} + diff --git a/templates/cs/CacheRecord.cs b/templates/cs/CacheRecord.cs index 8c93a5b..4737c12 100644 --- a/templates/cs/CacheRecord.cs +++ b/templates/cs/CacheRecord.cs @@ -1,5 +1,3 @@ -namespace {{namespace}} { - public class CacheRecord { public TreeNode node; public int tail; @@ -9,4 +7,3 @@ public CacheRecord(TreeNode node, int tail) { this.tail = tail; } } -} diff --git a/templates/cs/Label.cs b/templates/cs/Label.cs index b13f0b1..ce0a935 100644 --- a/templates/cs/Label.cs +++ b/templates/cs/Label.cs @@ -1,7 +1,6 @@ -namespace {{namespace}} { public enum Label { {{#each labels}} {{this}}{{#unless @last}},{{/unless}} {{/each}} } -} + diff --git a/templates/cs/ParseError.cs b/templates/cs/ParseError.cs index fea9ac5..1161c61 100644 --- a/templates/cs/ParseError.cs +++ b/templates/cs/ParseError.cs @@ -1,8 +1,5 @@ -using System; - -namespace {{namespace}} { public class ParseError : Exception { - public ParseError(String message) : base(message) { + public ParseError(string message) : base(message) { } } -} + diff --git a/templates/cs/Parser.cs b/templates/cs/Parser.cs index e1cc2de..b456939 100644 --- a/templates/cs/Parser.cs +++ b/templates/cs/Parser.cs @@ -1,30 +1,25 @@ -using System.Collections.Generic; -using System.Collections; -using System; - -namespace {{namespace}} { public class {{name}} : Grammar { - public {{name}}(String input, Actions actions) { + public {{name}}(string input, Actions actions) { this.input = input; this.inputSize = input.Length; this.actions = actions; this.offset = 0; this.cache = new Dictionary>(); this.failure = 0; - this.expected = new List(); + this.expected = new List(); } - public static TreeNode parse(String input, Actions actions) { + public static TreeNode parse(string input, Actions actions) { {{name}} parser = new {{name}}(input, actions); return parser.parse(); } - public static TreeNode parse(String input){ + public static TreeNode parse(string input){ return parse(input, null); } - private static String formatError(String input, int offset, List expected) { - String[] lines = input.Split('\n'); + private static string formatError(string input, int offset, List expected) { + string[] lines = input.Split('\n'); int lineNo = 0, position = 0; while (position <= offset) { @@ -32,14 +27,14 @@ private static String formatError(String input, int offset, List expec lineNo += 1; } - String line = lines[lineNo - 1]; - String message = "Line " + lineNo + ": expected one of:\n\n"; + string line = lines[lineNo - 1]; + string message = "Line " + lineNo + ": expected one of:\n\n"; - foreach (String[] pair in expected) { + foreach (string[] pair in expected) { message += " - " + pair[1] + " from " + pair[0] + "\n"; } - String number = "" + lineNo; + string number = "" + lineNo; while (number.Length < 6) number = " " + number; message += "\n" + number + " | " + line + "\n"; @@ -59,9 +54,8 @@ private TreeNode parse(){ } if (expected.Count <= 0) { failure = offset; - expected.Add(new String[] { {{{grammar}}}, "" }); + expected.Add(new string[] { {{{grammar}}}, "" }); } throw new ParseError(formatError(input, failure, expected)); } } -} diff --git a/templates/cs/TreeNode.cs b/templates/cs/TreeNode.cs index c607798..5fea5b2 100644 --- a/templates/cs/TreeNode.cs +++ b/templates/cs/TreeNode.cs @@ -1,10 +1,5 @@ -using System.Collections.Generic; -using System.Collections; -using System; - -namespace {{namespace}} { public class {{name}} : IEnumerable<{{name}}> { - public String text; + public string text; public int offset; public List<{{name}}> elements; @@ -12,7 +7,7 @@ public class {{name}} : IEnumerable<{{name}}> { public {{name}}() : this("", -1, new List<{{name}}>(0)) {} - public {{name}}(String text, int offset, List<{{name}}> elements) { + public {{name}}(string text, int offset, List<{{name}}> elements) { this.text = text; this.offset = offset; this.elements = elements; @@ -41,4 +36,3 @@ IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } -} diff --git a/test/cs/canopy.csproj b/test/cs/canopy.csproj index 0c92ef8..5f7268d 100644 --- a/test/cs/canopy.csproj +++ b/test/cs/canopy.csproj @@ -1,6 +1,6 @@ - net45;netcoreapp2.1;netcoreapp2.2;netcoreapp3.0;netcoreapp3.1;netstandard2.1;net5.0;net6.0;net7.0 + net6.0;net8.0 8.0 false false @@ -12,52 +12,11 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -