从简单的树顶解析器获取日期部分:错误的参数类型 Class(预期模块)
Getting date parts from a simple treetop parser: wrong argument type Class (expected Module)
对于以下树顶语法,在解析 '3/14/01' 时(通过 irb 中的 t = Parser.parse('3/14/01')
),我得到 "TypeError: wrong argument type Class (expected Module)".
grammar SimpleDate
rule dateMDY
whitespace? month_part ( '/' / '-') day_part ( ('/' / '-') year_part)? whitespace? <DateMDY>
end
rule month_part
( ( '1' [0-2] ) / ( '0'? [1-9] ) ) <MonthLiteral>
end
rule day_part
( ( [12] [0-9] ) / ( '3' [0-1] ) / ( '0'? [1-9] ) ) <DayLiteral>
end
rule year_part
( ( '1' '9' ) / ( '2' [01] ) )? [0-9] [0-9] <YearLiteral> # 1900 through 2199 (4 digit)
end
rule whitespace
[\s]+
end
end
第一,
如果我注释掉 <MonthLiteral>
和 <DayLiteral>
class 引用,一切都很好。注释掉 <DateMDY>
,但保留那些 Literal 对象,也会发出错误。注释掉 <YearLiteral>
似乎并不重要(不管它是否有效)——这似乎表明因为前两个是非终结符,所以我无法为它们生成元素。
对于 Ruby(或 treetop)如何实例化这些 classes 或关于解释所发生情况的 AST 生成,显然有一些我不满意的地方。你能解释一下或指出一些可以帮助我理解为什么 <MonthLiteral>
或 <DayLiteral>
不能生成对象的东西吗?
第二个,
这可能是一座太过分的桥梁,但我真正想要的是获得一个具有三个属性(月、日和年)的 DateMDY
对象,这样我就可以轻松生成 Ruby Time
来自 DateMDY
方法 to_time
的对象,但现在我只想将组成部分作为对象生成。
所以我尝试将 <DateMDY>
作为对象并注释掉对 <MonthLiteral>
、<DayLiteral>
和 <YearLiteral>
的引用。我看到从 .parse
(在我的原始示例中为 t
)返回的结果 AST 对象有两个 public 方法——:day_part
和 :month_part
但那些似乎当我调用那些(例如,puts t.day_part
)并且没有 :year_part
方法时为零,所以这似乎没有帮助我。
是否有可能以某种方式让 DateMDY
最终访问其组成部分?
仅供参考,我使用的 Parser
代码本身是树顶教程中非常标准的东西,定义对象 classes 的 node_extensions.rb
也很简单,但我post 如果你需要看那些也可以。
谢谢!
理查德
错误消息准确地告诉了您做错了什么。只有一组有限的地方可以用这种方式使用 Class。如果允许,Class 必须是 SyntaxNode 的子class。但是通常你应该使用一个模块,它被扩展()到由内部规则创建的 SyntaxNode 中。 YearLiteral 的不同之处在于它不像 Month 和 Day 文字那样包装带括号的序列。这个带括号的序列 returns 一个现有的 SyntaxNode,不能用另一个 Class 扩展(),只能用一个模块,所以你得到 TypeError。
关于你的第二个问题,你想要的 DateMDY 对象几乎肯定不是 SyntaxNode - 因为所有 SyntaxNode 都保留对其所有子 SyntaxNode 和输入字符串的引用 - 这就是我们正在谈论的解析器内部结构.您真的要将解析器内部的一些细节暴露给外界吗?
相反,您应该安排在解析完成后访问适当的语法节点,方法是调用一个函数,returns您的域对象类型使用这些解析器对象识别和保存的子字符串构造。最好添加这些函数以从最顶层规则向下遍历,而不是尝试遍历解析树 "from the outside".
您可以通过在您的最高规则中添加一个块来做到这一点,就像这样(假设您有一个合适的 DateMDY class)。当你有一个成功的解析树时,通过调用 "tree.result":
来获取你的 DateMDY
rule dateMDY
whitespace? month_part ( '/' / '-') day_part y:( ('/' / '-') year_part)? whitespace?
{
def result
DateMDY.new(y.empty? ? nil : y.year_part.text_value.to_i,
month_part.text_value.to_i,
day_part.text_value.to_i)
end
}
end
当然,为 year_part、month_part 和 day_part 添加单独的结果方法会更清晰;这只是对如何添加这些方法的介绍。
对于以下树顶语法,在解析 '3/14/01' 时(通过 irb 中的 t = Parser.parse('3/14/01')
),我得到 "TypeError: wrong argument type Class (expected Module)".
grammar SimpleDate
rule dateMDY
whitespace? month_part ( '/' / '-') day_part ( ('/' / '-') year_part)? whitespace? <DateMDY>
end
rule month_part
( ( '1' [0-2] ) / ( '0'? [1-9] ) ) <MonthLiteral>
end
rule day_part
( ( [12] [0-9] ) / ( '3' [0-1] ) / ( '0'? [1-9] ) ) <DayLiteral>
end
rule year_part
( ( '1' '9' ) / ( '2' [01] ) )? [0-9] [0-9] <YearLiteral> # 1900 through 2199 (4 digit)
end
rule whitespace
[\s]+
end
end
第一,
如果我注释掉 <MonthLiteral>
和 <DayLiteral>
class 引用,一切都很好。注释掉 <DateMDY>
,但保留那些 Literal 对象,也会发出错误。注释掉 <YearLiteral>
似乎并不重要(不管它是否有效)——这似乎表明因为前两个是非终结符,所以我无法为它们生成元素。
对于 Ruby(或 treetop)如何实例化这些 classes 或关于解释所发生情况的 AST 生成,显然有一些我不满意的地方。你能解释一下或指出一些可以帮助我理解为什么 <MonthLiteral>
或 <DayLiteral>
不能生成对象的东西吗?
第二个,
这可能是一座太过分的桥梁,但我真正想要的是获得一个具有三个属性(月、日和年)的 DateMDY
对象,这样我就可以轻松生成 Ruby Time
来自 DateMDY
方法 to_time
的对象,但现在我只想将组成部分作为对象生成。
所以我尝试将 <DateMDY>
作为对象并注释掉对 <MonthLiteral>
、<DayLiteral>
和 <YearLiteral>
的引用。我看到从 .parse
(在我的原始示例中为 t
)返回的结果 AST 对象有两个 public 方法——:day_part
和 :month_part
但那些似乎当我调用那些(例如,puts t.day_part
)并且没有 :year_part
方法时为零,所以这似乎没有帮助我。
是否有可能以某种方式让 DateMDY
最终访问其组成部分?
仅供参考,我使用的 Parser
代码本身是树顶教程中非常标准的东西,定义对象 classes 的 node_extensions.rb
也很简单,但我post 如果你需要看那些也可以。
谢谢! 理查德
错误消息准确地告诉了您做错了什么。只有一组有限的地方可以用这种方式使用 Class。如果允许,Class 必须是 SyntaxNode 的子class。但是通常你应该使用一个模块,它被扩展()到由内部规则创建的 SyntaxNode 中。 YearLiteral 的不同之处在于它不像 Month 和 Day 文字那样包装带括号的序列。这个带括号的序列 returns 一个现有的 SyntaxNode,不能用另一个 Class 扩展(),只能用一个模块,所以你得到 TypeError。
关于你的第二个问题,你想要的 DateMDY 对象几乎肯定不是 SyntaxNode - 因为所有 SyntaxNode 都保留对其所有子 SyntaxNode 和输入字符串的引用 - 这就是我们正在谈论的解析器内部结构.您真的要将解析器内部的一些细节暴露给外界吗?
相反,您应该安排在解析完成后访问适当的语法节点,方法是调用一个函数,returns您的域对象类型使用这些解析器对象识别和保存的子字符串构造。最好添加这些函数以从最顶层规则向下遍历,而不是尝试遍历解析树 "from the outside".
您可以通过在您的最高规则中添加一个块来做到这一点,就像这样(假设您有一个合适的 DateMDY class)。当你有一个成功的解析树时,通过调用 "tree.result":
来获取你的 DateMDYrule dateMDY
whitespace? month_part ( '/' / '-') day_part y:( ('/' / '-') year_part)? whitespace?
{
def result
DateMDY.new(y.empty? ? nil : y.year_part.text_value.to_i,
month_part.text_value.to_i,
day_part.text_value.to_i)
end
}
end
当然,为 year_part、month_part 和 day_part 添加单独的结果方法会更清晰;这只是对如何添加这些方法的介绍。