Update grammar, expand CRC32 function #2

Merged
dominic merged 4 commits from grammar into master 2026-04-25 10:26:06 +00:00
5 changed files with 80 additions and 21 deletions
Showing only changes of commit a05903df4d - Show all commits

View File

@ -199,11 +199,13 @@ namespace XNeedle.Parser
from ws1 in Parse.WhiteSpace.Many().Optional() from ws1 in Parse.WhiteSpace.Many().Optional()
from open in Parse.Char('{') from open in Parse.Char('{')
from ws2 in Parse.WhiteSpace.Many().Optional() from ws2 in Parse.WhiteSpace.Many().Optional()
from expressions in Parse.Ref(() => BangObject) from expressions in (
.Or(Parse.Ref(() => RuleObject)) from expr in Parse.Ref(() => BangObject)
.Or(ExprPart(ctx).Select(e => (Part)e)) .Or(Parse.Ref(() => RuleObject))
.DelimitedBy(Parse.Char(';').Token()) .Or(ExprPart(ctx).Select(e => (Part)e))
from tailingsemi in Parse.Char(';').Optional() from semi in Parse.Char(';').Token()
select expr
).Many()
from ws3 in Parse.WhiteSpace.Many().Optional() from ws3 in Parse.WhiteSpace.Many().Optional()
from close in Parse.Char('}') from close in Parse.Char('}')
select new Bang{Name = new string([.. name]), Arguments = arguments, Body = expressions}; select new Bang{Name = new string([.. name]), Arguments = arguments, Body = expressions};
@ -214,15 +216,23 @@ namespace XNeedle.Parser
from ws1 in Parse.WhiteSpace.Many().Optional() from ws1 in Parse.WhiteSpace.Many().Optional()
from open in Parse.Char('{') from open in Parse.Char('{')
from ws2 in Parse.WhiteSpace.Many().Optional() from ws2 in Parse.WhiteSpace.Many().Optional()
from expressions in Parse.Ref(() => BangObject) from expressions in (
.Or(Parse.Ref(() => RuleObject)) from expr in Parse.Ref(() => BangObject)
.Or(ExprPart(ctx).Select(e => (Part)e)) .Or(Parse.Ref(() => RuleObject))
.DelimitedBy(Parse.Char(';').Token()) .Or(ExprPart(ctx).Select(e => (Part)e))
from tailingsemi in Parse.Char(';').Optional() from semi in Parse.Char(';').Token()
select expr
).Many()
from ws3 in Parse.WhiteSpace.Many().Optional() from ws3 in Parse.WhiteSpace.Many().Optional()
from close in Parse.Char('}') from close in Parse.Char('}')
select new Rule{XPathSelector = selector, Body = expressions}; select new Rule{XPathSelector = selector, Body = expressions};
public static readonly Parser<IEnumerable<Part>> Rules =
(from rule in RuleObject.Token()
from semi in Parse.Char(';').Token()
select rule)
.Many()
.End();
static public string StripComments(string source) static public string StripComments(string source)
{ {

View File

@ -40,10 +40,10 @@ namespace XNeedle
var rawSource = File.ReadAllText(opts.XnDefinition); var rawSource = File.ReadAllText(opts.XnDefinition);
var xnSource = XnParser.StripComments(rawSource); var xnSource = XnParser.StripComments(rawSource);
Rule masterRule; IEnumerable<Part> rules;
try try
{ {
masterRule = (Rule)XnParser.RuleObject.Parse(xnSource); rules = XnParser.Rules.Parse(xnSource);
} }
catch (ParseException ex) catch (ParseException ex)
{ {
@ -54,11 +54,19 @@ namespace XNeedle
if (showPosition) if (showPosition)
{ {
Console.Error.WriteLine($"{opts.XnDefinition}({line},{col}): parse error: {ex.Message}"); var msg = ex.Message;
var hint = (msg.Contains("expected }") && !msg.Contains("expected ';'"))
? "Hint: a missing ';' terminator may be located just after this position"
: "";
Console.Error.WriteLine($"{opts.XnDefinition}({line},{col}): parse error: {msg}");
var srcLine = line <= lines.Length ? lines[line - 1].TrimEnd() : ""; var srcLine = line <= lines.Length ? lines[line - 1].TrimEnd() : "";
var pointer = new string(' ', Math.Max(0, col - 1)) + "^"; var pointer = new string(' ', Math.Max(0, col - 1)) + "^";
Console.Error.WriteLine($" {srcLine}"); Console.Error.WriteLine($" {srcLine}");
Console.Error.WriteLine($" {pointer}"); Console.Error.WriteLine($" {pointer}");
if (!string.IsNullOrEmpty(hint))
{
Console.Error.WriteLine($"\n{hint}");
}
} }
else else
{ {
@ -69,7 +77,16 @@ namespace XNeedle
var doc = XDocument.Load(opts.Input, LoadOptions.PreserveWhitespace); var doc = XDocument.Load(opts.Input, LoadOptions.PreserveWhitespace);
var encoding = XmlRoundtripWriter.DetectEncoding(File.ReadAllBytes(opts.Input)); var encoding = XmlRoundtripWriter.DetectEncoding(File.ReadAllBytes(opts.Input));
var sloc = new SourceLocation(opts.Input, encoding); var sloc = new SourceLocation(opts.Input, encoding);
masterRule.Transform(doc, sloc); try
{
foreach (var rule in rules.OfType<Rule>())
rule.Transform(doc, sloc);
}
catch (RequireException ex)
{
Console.Error.WriteLine($"{ex.SLoc.FilePath}({ex.SLoc.LineNumber}): require error: {ex.UserMessage}");
return;
}
using var writer = XmlRoundtripWriter.Create(opts.Input, opts.Output); using var writer = XmlRoundtripWriter.Create(opts.Input, opts.Output);
doc.WriteTo(writer); doc.WriteTo(writer);
Console.WriteLine($"Applied \"{opts.XnDefinition}\" to \"{opts.Input}\" and saved result to \"{opts.Output}\""); Console.WriteLine($"Applied \"{opts.XnDefinition}\" to \"{opts.Input}\" and saved result to \"{opts.Output}\"");

View File

@ -187,5 +187,18 @@ namespace XNeedle.Transformation
} }
return ""; return "";
} }
public static string require(Context ctx, string message = "Required node not present")
{
if (ctx.Node == null)
{
throw new RequireException{SLoc=ctx.SLoc, UserMessage=message};
}
else
{
Console.WriteLine(ctx.Node.ToString());
}
return "";
}
} }
} }

View File

@ -0,0 +1,15 @@
using System.Collections.Generic;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;
using XNeedle;
using XNeedle.Parser.Elements;
namespace XNeedle.Transformation
{
public class RequireException : Exception
{
public SourceLocation SLoc { get; set; }
public required string UserMessage { get; set; }
}
}

View File

@ -22,15 +22,19 @@ namespace XNeedle.Transformation
public override void Operate(Context ctx) public override void Operate(Context ctx)
{ {
if(ctx.Node is null) var nodes = ctx.Node?.XPathSelectElements(XPathSelector);
{ if(nodes is null || nodes.Count() == 0)
return;
}
var nodes = ctx.Node.XPathSelectElements(XPathSelector);
if(nodes is null)
{ {
var nullCtx = ctx.Clone();
nullCtx.Node = null;
nullCtx.SLoc = ctx.SLoc.WithLineNumber(-1);
foreach (var b in Body)
{
b.Operate(nullCtx);
}
return; return;
} }
foreach (XElement n in nodes) foreach (XElement n in nodes)
{ {
var loopCtx = ctx.Clone(); var loopCtx = ctx.Clone();