Update grammar, expand CRC32 function #2
@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
25
Program.cs
25
Program.cs
@ -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}\"");
|
||||||
|
|||||||
@ -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 "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
15
Transformation/RequireException.cs
Normal file
15
Transformation/RequireException.cs
Normal 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; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user