我想知道如何在没有针对每种可能的排列的具体模式匹配的情况下处理多个选项。
以下是我遇到的问题的简化示例:
lexical Int = [0-9]+;
syntax Bool = "True" | "False";
syntax Period = "Day" | "Month" | "Quarter" | "Year";
layout Standard = [\ \t\n\f\r]*;
syntax Optionals = Int? i Bool? b Period? p;
str printOptionals(Optionals opt){
str res = "";
if(!isEmpty("<opt.i>")) { // opt has i is always true (same for opt.i?)
res += printInt(opt.i);
}
if(!isEmpty("<opt.b>")){
res += printBool(opt.b);
}
if(!isEmpty("<opt.p>")) {
res += printPeriod(opt.period);
}
return res;
}
str printInt(Int i) = "<i>";
str printBool(Bool b) = "<b>";
str printPeriod(Period p) = "<p>";
然而,这会给出错误消息:
The called signature: printInt(opt(lex("Int"))), does not match the declared signature: str printInt(sort("Int"));
当我知道它在那里时,如何摆脱选择部分?
答案 0 :(得分:1)
我不确定这是多么理想,但你现在可以这样做:
if (/Int i := opt.i) {
res += printInt(i);
}
这将从Int
中提取opt.i
(如果有),但如果Int
未作为其中一个选项提供,则匹配将失败。
答案 1 :(得分:0)
无类型解决方案是从解析树中突出显示元素:
rascal>opt.i.args[0];
Tree: `1`
Tree: appl(prod(lex("Int"),[iter(\char-class([range(48,57)]))],{}),[appl(regular(iter(\char-class([range(48,57)]))),[char(49)])[@loc=|file://-|(0,1,<1,0>,<1,1>)]])[@loc=|file://-|(0,1,<1,0>,<1,1>)]
但是,然后将其转回Int
,您必须进行模式匹配,如下所示:
rascal>if (Int i := opt.i.args[0]) { printInt(i); }
str: "1"
可以编写一个通用的强制转换函数来帮助:
rascal>&T cast(type[&T] t, value v) { if (&T a := v) return a; throw "cast exception"; }
ok
rascal>printInt(cast(#Int, opt.i.args[0]))
str: "1"
不过,我相信Rascal在这里缺少一个功能。这样的事情将是一个很好的功能要求:
rascal>Int j = opt.i.value;
rascal>opt.i has value
bool: true
答案 2 :(得分:0)
github上的当前master具有以下功能来处理选项:它们可以被迭代。
例如:
if (Int i <- opt.i) {
res += printInt(i);
}
如果缺少可选值,<-
将立即生成false
,否则循环一次并绑定模式中存在的值。