Arch: firstly, ast node need to change, use payload instead of token
This commit is contained in:
@@ -16,8 +16,9 @@ using System.Text;
|
||||
|
||||
namespace StgSharp.RegularAnalysis.Abstraction
|
||||
{
|
||||
public interface ITrinitySyntaxNode<TNode, TLabel> : ISyntaxNode<TNode, TLabel>
|
||||
where TNode : ISyntaxNode<TNode, TLabel>
|
||||
public interface ITrinitySyntaxNode<TNode, TPayload, TLabel> : ISyntaxNode<TNode, TPayload, TLabel>
|
||||
where TNode : ISyntaxNode<TNode, TPayload, TLabel>
|
||||
where TPayload : ISyntaxPayload<TPayload, TNode, TLabel>
|
||||
where TLabel : unmanaged
|
||||
{
|
||||
|
||||
@@ -25,7 +26,9 @@ namespace StgSharp.RegularAnalysis.Abstraction
|
||||
|
||||
}
|
||||
|
||||
public interface ISyntaxNode<TNode, TLabel> where TNode : ISyntaxNode<TNode, TLabel>
|
||||
public interface ISyntaxNode<TNode, TPayload, TLabel>
|
||||
where TNode : ISyntaxNode<TNode, TPayload, TLabel>
|
||||
where TPayload : ISyntaxPayload<TPayload, TNode, TLabel>
|
||||
where TLabel : unmanaged
|
||||
{
|
||||
|
||||
@@ -45,7 +48,7 @@ namespace StgSharp.RegularAnalysis.Abstraction
|
||||
|
||||
static abstract TNode Empty { get; }
|
||||
|
||||
Token<TLabel> Source { get; }
|
||||
TPayload Source { get; }
|
||||
|
||||
protected internal int EnumState { get; set; }
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
// file="ISyntaxPayload"
|
||||
// Project: StgSharp
|
||||
// Copyright (c) Nitload.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace StgSharp.RegularAnalysis.Abstraction
|
||||
{
|
||||
// TODO 不对劲,TCarrier是个昏招,还是去掉吧
|
||||
public interface ISyntaxPayload<TSelf, TCarrier, TLabel>
|
||||
where TSelf : ISyntaxPayload<TSelf, TCarrier, TLabel>
|
||||
where TCarrier : ISyntaxNode<TCarrier, TSelf, TLabel>
|
||||
where TLabel : unmanaged
|
||||
{
|
||||
|
||||
int Column { get; set; }
|
||||
|
||||
int Row { get; set; }
|
||||
|
||||
string Source { get; set; }
|
||||
|
||||
TLabel Flag { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -27,13 +27,37 @@ IR 层代码因此归档而非删除:将来做 stepping 解释器时是字节
|
||||
|
||||
## 需要在 AST 上补什么
|
||||
|
||||
### 节点重设计(先于一切)
|
||||
|
||||
`RegexAstNode` 不再挂载 `Token<RegexElementLabel>`:token 在 AST 构建时被**消费掉**,
|
||||
转换为结构化载荷。节点只剩三样东西:`Label`(原 `Source.Flag`)、`IPayload`、拓扑。
|
||||
这把 IR 层真正有价值的部分(类型化语义)请了回来,线性形态留在 `.old` 里。
|
||||
|
||||
| Label | Payload | 转换时机 |
|
||||
| --- | --- | --- |
|
||||
| `UNIT` / `UNIT_SPAN` | `LiteralPayload(Text)`,**转义已消解** | AST 构建 |
|
||||
| `UNIT_SET` | `CharSetPayload(Set)` | AST 构建 |
|
||||
| `COUNT` | `CountPayload(Min, Max, IsGreedy)`,即 `{m,n}` 的唯一解析点 | AST 构建 |
|
||||
| `GROUP_BEGIN` | `GroupPayload(Name, Index)` | AST 构建 |
|
||||
| `CONCAT` / `ALT` | 无(null) | — |
|
||||
| `FIND`(新) | `FindPayload(Anchor, IsNearest)` | phase 6 融合 pass |
|
||||
|
||||
规则:
|
||||
|
||||
1. 载荷全部是不可变 record,深拷贝共享引用不复制
|
||||
2. `ReplaceBy` / `RemoveAndAsChild` 搬运 `Label + Payload`,不再拷 Source
|
||||
3. mask 决断载荷类型,取用走 `PayloadAs<T>()`,类型不符当场抛
|
||||
4. pass 局部属性(`FirstAtom`/`LastAtom`)不住这个槽,放融合 pass 的 side table
|
||||
|
||||
改造点:`ASTGenerate` 构造处(token→payload 转换)、`ASTOptimize` 里读
|
||||
`Value`/`Source` 的消费点、两个变形 API、`EmptyRegexAstNode`(Label=NONE)。
|
||||
|
||||
### 基础件(不存在,先补)
|
||||
|
||||
1. **子树深拷贝**——`(ab){2,3}` 展开需要克隆 body;配合破坏性移动可省一份
|
||||
2. **合成节点工厂**——展开要凭空造 CONCAT/COUNT 节点,
|
||||
需要 `Token<RegexElementLabel>` 的合成构造入口(如 `Token.Synthetic(flag, value)`)
|
||||
3. **FIND 节点标签**——`RegexElementLabel` 新增 `FIND`,语义为"搜索连接"
|
||||
(替代 IR 的 `FIND_COMPLEX`,见下)
|
||||
1. **子树深拷贝**——`(ab){2,3}` 展开需要克隆 body;配合破坏性移动可省一份;载荷共享不拷
|
||||
2. **FIND 节点标签**——`RegexElementLabel` 新增 `FIND`,语义为"搜索连接"
|
||||
(替代 IR 的 `FIND_COMPLEX`,见下);合成节点直接 `new(label, payload)`,
|
||||
无需伪造 token
|
||||
|
||||
### 树上规范化 pass(`OptimizeTree` 扩到六阶段)
|
||||
|
||||
@@ -81,7 +105,9 @@ GROUP 的捕获终点落在锚起点**之前**。
|
||||
| 文件 | 错误原因 | 处置 |
|
||||
| --- | --- | --- |
|
||||
| `RegexAnalyzer.cs` | `TextRegexSource` 记录携带 `List<RegexIR>` 字段,`Analyze` 调 `GenerateIR`/`ScanAndOptimizeIR`/`EmitPrefix` | 砍掉 IR 字段与三个调用,管线止于 `OptimizeTree` |
|
||||
| `TextRegexSourceGen.GenClass.cs` | `GenerateSource` 读 `source.IRs`,`GenerateBlock`/`GenerateRegion`/`MeasureRegionExtents`/`FindRegionEnd` 全是 IR 机器 | 重写为读 `source.Ast` 的节点递归;保留 `FormatStringLiteral`/`FormatCharLiteral`/charset 解析 |
|
||||
| `TextRegexSourceGen.GenClass.cs` | `GenerateSource` 读 `source.IRs`,`GenerateBlock`/`GenerateRegion`/`MeasureRegionExtents`/`FindRegionEnd` 全是 IR 机器 | 重写为读 `source.Ast` 的节点递归;保留 `FormatStringLiteral`/`FormatCharLiteral`;charset 解析迁入 `CharSetPayload` 转换 |
|
||||
|
||||
节点重设计落地时,`ASTGenerate`/`ASTOptimize` 会新增一批预期内错误(`Source`/`Value` 消费点),同批修复。
|
||||
|
||||
## `.old` 文件清单与参考价值
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<IsRoslynComponent>true</IsRoslynComponent>
|
||||
@@ -34,6 +34,16 @@
|
||||
<None Include="$(OutputPath)StgSharp.Common.dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" Condition="Exists('$(OutputPath)StgSharp.Common.dll')" />
|
||||
<None Remove="bin\x64\Debug\net8.0\StgSharp.Common.pdb" />
|
||||
<None Include="$(OutputPath)StgSharp.Common.pdb" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" Condition="Exists('$(OutputPath)StgSharp.Common.pdb')" />
|
||||
<None Include=".discard\RegexAnalyzer.IRGenerate.cs.old" />
|
||||
<None Include=".discard\RegexAnalyzer.IROptimize.cs.old" />
|
||||
<None Include=".discard\RegexAnalyzer.PrefixEmit.cs.old" />
|
||||
<None Include=".discard\RegexIR.Abstraction.cs.old" />
|
||||
<None Include=".discard\RegexIR.cs.old" />
|
||||
<None Include=".discard\RegexIR.Prefix.cs.old" />
|
||||
<None Include=".discard\RegexIRGenerator.cs.old" />
|
||||
<None Include=".discard\TextRegexSourceGen.GenClass.MultiIR.cs.old" />
|
||||
<None Include=".discard\TextRegexSourceGen.GenClass.Prefix.cs.old" />
|
||||
<None Include=".discard\TextRegexSourceGen.GenClass.SingleIR.cs.old" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
// file="RegexAnalyzer.ASTNodeOptimize"
|
||||
// Project: StgSharp
|
||||
// Copyright (c) Nitload.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
using StgSharp.RegularAnalysis.Abstraction;
|
||||
using System;
|
||||
|
||||
namespace StgSharp.RegularAnalysis.Text
|
||||
{
|
||||
internal partial class RegexAnalyzer
|
||||
{
|
||||
|
||||
private static bool TryFlattenCount(
|
||||
RegexAstNode node
|
||||
)
|
||||
{
|
||||
// flatten count node if it matches raw string pattern
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -44,10 +44,11 @@ namespace StgSharp.RegularAnalysis.Text
|
||||
public string Pattern { get; }
|
||||
|
||||
internal AbstractSyntaxTree<RegexAstNode, RegexElementLabel> Ast { get; }
|
||||
|
||||
/*
|
||||
internal List<RegexIR> BaseIR { get; }
|
||||
|
||||
internal List<RegexIR> IRs { get; }
|
||||
/**/
|
||||
|
||||
internal RegexInfo Info { get; }
|
||||
|
||||
@@ -76,10 +77,11 @@ namespace StgSharp.RegularAnalysis.Text
|
||||
{
|
||||
return new TextRegexSource(regex, null, null, null, info, ex);
|
||||
}
|
||||
List<RegexIR> base_ir;
|
||||
/*
|
||||
// List<RegexIR> base_ir;
|
||||
try
|
||||
{
|
||||
base_ir = GenerateIR(tree, ref info);
|
||||
// base_ir = GenerateIR(tree, ref info);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -87,8 +89,8 @@ namespace StgSharp.RegularAnalysis.Text
|
||||
}
|
||||
try
|
||||
{
|
||||
ScanAndOptimizeIR(base_ir, out List<RegexIR> opt_ir);
|
||||
List<RegexIR> prefix_ir = EmitPrefix(opt_ir, ref info);
|
||||
// ScanAndOptimizeIR(base_ir, out List<RegexIR> opt_ir);
|
||||
// List<RegexIR> prefix_ir = EmitPrefix(opt_ir, ref info);
|
||||
return new TextRegexSource(regex, require_ast ? tree : null!,
|
||||
require_origin_ir ? base_ir : null!, prefix_ir, info);
|
||||
}
|
||||
@@ -97,6 +99,7 @@ namespace StgSharp.RegularAnalysis.Text
|
||||
return new TextRegexSource(regex, require_ast ? tree : null!,
|
||||
require_origin_ir ? base_ir : null!, null!, info, ex);
|
||||
}
|
||||
/**/
|
||||
#pragma warning restore CA1031
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
// file="RegexAstNode.AdditionalPayload"
|
||||
// Project: StgSharp
|
||||
// Copyright (c) Nitload.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
using StgSharp.RegularAnalysis.Abstraction;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace StgSharp.RegularAnalysis.Text
|
||||
{
|
||||
public class RegexCountPayload : ISyntaxPayload<RegexCountPayload, RegexAstNode, RegexElementLabel>
|
||||
{
|
||||
|
||||
public int Min { get; set; }
|
||||
|
||||
public int Max { get; set; }
|
||||
|
||||
public string Source { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class RegexCommonPayload : IRegexAstNodeAdditionalPayload
|
||||
{
|
||||
|
||||
public string Source { get; set; } = string.Empty;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,8 @@ using System.Runtime.CompilerServices;
|
||||
|
||||
namespace StgSharp.RegularAnalysis.Text
|
||||
{
|
||||
// TODO 现在存在的问题是,AstNode过于依赖NodeFlag表达其内部语义,这导致进行精细优化时识别节点语义复杂,
|
||||
// TODO 当前Ast的类型差异过小,不利于保存特征数据,应当争取进一步细化,或者说这是AstNode一开始为了简化架构设计引入的妥协
|
||||
internal class RegexAstNode : ISyntaxNode<RegexAstNode, RegexElementLabel>
|
||||
{
|
||||
|
||||
|
||||
Reference in New Issue
Block a user