我想在Isabelle的cartouches中实现一个特定于域的语言(带有自己的解析器)。例如,我希望术语(MY ‹123›, 3)
为子串123
调用我自己的解析器,但通常将其余的解析为术语。
关注HOL/ex/Cartouche_Examples.thy
,我了解如何为MY ‹...›
形式的子项安装我自己的解析翻译,以及如何将广告素材的内容设为string*Position.T
或{{ 1}}。
我也理解如何使用Isabelle的解析器组合器来编写Symbol_Pos.T list
类型的解析器。
但我无法找到如何将解析器应用于字符串(或term parser
)。
换句话说,我仍然缺少的是一个功能
Symbol_Pos.T list
将fun parse_cartouche ctx (cartouche:string) (pos:Position.T) : term = ???
类型的解析器应用于字符串term parser
(并正确地将解析错误报告给顶层)。
澄清:
我想利用Isabelle的现有基础架构来跟踪/报告解析位置。例如,如果存在解析错误,我希望Isabelle / jEdit中的代码为红色,如果在我自己的语言中,我会调用像Args.parse_term这样的解析器,我希望Isabelle / jEdit颜色变量正确,并通过控制悬停获取类型信息。
我不想重新实现我自己的解析器来处理像int这样的常见事情,但是如果我至少得到前面的要点那么可以这样做。 (但是,将我的语言的子字符串解析为术语,我将不得不使用一些现有的解析函数,因为我不能自己重新实现Isabelle语法。
以下是我目前的完整代码(带有cartouche
的虚拟实现。)
parse_cartouche
答案 0 :(得分:1)
因为这是一个相对罕见的用例,我不确定"规范"解决方案已经出现了。但我至少可以从我自己的代码中给出两个例子来帮助说明一般方法。
在给定函数eval_term : string -> term
的情况下,以下解析翻译从一个cartouche中提取一些ML源,将其评估为term
,然后将其用作解析翻译的结果。
fun term_translation ctxt args =
let
fun err () = raise TERM ("Splice.term_translation", args)
fun input s pos =
let
val content = Symbol_Pos.cartouche_content (Symbol_Pos.explode (s, pos))
val (text, range) = Symbol_Pos.implode_range (Symbol_Pos.range content) content
in
Input.source true text range
end
in
case args of
[(c as Const (@{syntax_const "_constrain"}, _)) $ Free (s, _) $ p] =>
(case Term_Position.decode_position p of
SOME (pos, _) => c $ eval_term (input s pos) ctxt $ p
| NONE => err ())
| _ => err ()
end
这个允许我将XML文字嵌入到术语中,然后将其解释为术语。
syntax "_cartouche_xml" :: "cartouche_position \<Rightarrow> 'a" ("XML _")
parse_translation\<open>
let
fun translation args =
let
fun err () = raise TERM ("Common._cartouche_xml", args)
fun input s pos = Symbol_Pos.implode (Symbol_Pos.cartouche_content (Symbol_Pos.explode (s, pos)))
val eval = Codec.the_decode Codec.term o XML.parse
in
case args of
[(c as Const (@{syntax_const "_constrain"}, _)) $ Free (s, _) $ p] =>
(case Term_Position.decode_position p of
SOME (pos, _) => c $ eval (input s pos) $ p
| NONE => err ())
| _ => err ()
end
in
[(@{syntax_const "_cartouche_xml"}, K translation)]
end
\<close>
以下代码应该允许您将Input.source
转换为解析器组合器可消化的内容,包括完整的位置信息:
ML ‹
val input = ‹term"3 + 4"›;
(* a bit more complicated than just Input.pos_of because otherwise the position includes the
outer cartouche brackets, which manifests as an off-by-one-error in the markup *)
val pos = Input.source_explode input |> Symbol_Pos.range |> Position.range_position;
val str = Input.source_content input;
val toks = Token.explode Keyword.empty_keywords pos str;
val parser = Args.$$$ "term" |-- Args.embedded_inner_syntax;
parser toks |> fst |> Syntax.read_term @{context}
›
答案 1 :(得分:1)
基于@ larsrh&#39; answer和自己的实验,我想出了以下答案。
Symbol_Pos.T list
转换为Symbol_Pos.cartouche_content o Symbol_Pos.explode
。 (这在Cartouche_Examples.thy的例子中有所涉及,由Isabelle提供。)Symbol_Pos.T list
可以使用Source.source
转换为包含Symbol_Pos.T
的{{1}}。Source.of_list
的{{1}}可以使用Source.source
转换为包含Symbol_Pos.T
的{{1}}。Source.source
从此来源删除空白徽标。Token.T
将结果转换为Token.source'
。Token.source_proper
类型的解析器可以应用于此类Token.T list
。 (或者,如果我们有Source.exhaust
,那么我们还需要提供一个上下文。)需要完成一些额外的工作:向'a parser
添加EOF以允许解析器检测输入的结束。处理解析器中的错误(以获得很好的错误消息)。
下面的代码是一个完整的评论工作示例(对于Isabelle 2016-1),也可以找到来源here。
Token.T list