2013-06-22 17 views
2

我想使用PetitParserDart来解析dart字符串中的嵌入表达式。如何使用PetitParser匹配飞镖字符串中的表达式?

准备一些对象:

class User { 
    String name; 
} 
var user1 = new User()..name="Mike"; 
var user2 = new User()..name="Jeff"; 
var user3 = new User()..name="John}}}"; 
var users = [user1, user2, user3]; 

长字符串:

var s = """ 
Hello, this is an embed dart expression below: 
    ${ 
    users.where((u)=>u.name!='Jeff}}}}}}}}') 
      .where((u) { return u.name!='{{{John'}) 
      .map((u)=>u.name).toList() 
    } 
It's very complex. 
""" 

你可以看到有字符串内使用${},其内容是很复杂的。

我尝试使用这种petitparser代码:

def("expr_in_string", string('${').ref('expr').char('}')); 
def("expr", ????); 

但我不知道如何定义expr规则。它可能包含{},所以我不能简单地使用anyIn('{}').neg()

现在我该怎么办?我觉得这将是一个非常复杂的规则。

回答

1

我不认为你可以正确解析所有可能的字符串,而没有或多或少的完整的飞镖表达语法。你可以写一个近似值(就像你在答案中做的那样),或者尝试使用示例中附带的Dart语法的表达式生成。无论哪种情况,结果语法都很复杂,因为你试图匹配的东西很复杂。

+0

谢谢你,卢卡斯。你能给我一个例子,说明我的解决方案无法正确处理吗? – Freewind

+0

我认为包含注释的表达式处理不正确。 –

0

在src/dart/grammar.dart中有一个针对Dart的语法,它似乎可以解析它。

+0

我看过那个演示,但它太复杂了。 – Freewind

+0

取决于你想要完成什么,你可能想看看analyzer_experimental作为替代。 –

0

我找到了一个解决方案:确定${}内的字符串,首先匹配它们。然后匹配所有{}

代码:

// whole `${...}` 
def("expr", string(r"$") & ref("block_brace")); 
// strings 
def("dart_str_single", char("'") & (string(r"\'") | char("'").neg()).star() & char("'")); 
def("dart_str_double", char('"') & (string(r'\"') | char('"').neg()).star() & char('"')); 
def("dart_str_triple_single", string("'''") & string("'''").neg().star() & string("'''")); 
def("dart_str_triple_double", string('"""') & string('"""').neg().star() & string('"""')); 
// (...) 
def("block_parenthesis", char('(') & (
    ref("dart_str_triple_single") 
    | ref("dart_str_triple_double") 
    | ref("dart_str_single") 
    | ref("dart_str_double") 
    | ref("block_parenthesis") 
    | ref("block_brace") 
    | char(')').neg() 
).star() & char(')')); 
// {...} 
def("block_brace", char('{') & (
    ref("dart_str_triple_single") 
    | ref("dart_str_triple_double") 
    | ref("dart_str_single") 
    | ref("dart_str_double") 
    | ref("block_parenthesis") 
    | ref("block_brace") 
    | char('}').neg() 
).star() & char('}')); 

测试代码:

var x4 = grammar["expr"]; 
    var yyy4 = x4.parse(r"""${ 
    users.where((u) => u.name != 'Jeff}}}}}}}}') 
    .where((u) { 
    return u.name != '{{{John'; 
    }) 
    .map((u) => u.name).toList() 
    }"""); 
    print(yyy4.value); 

它打印:

[$, [{, [ 
, , , , , , , u, s, e, r, s, ., w, h, e, r, e, 
[(, [[(, [u],)], , =, >, , u, ., n, a, m, e, , !, =, , 
[', [J, e, f, f, }, }, }, }, }, }, }, }], ']],)], 
, , , , , , , ., w, h, e, r, e, [(, [[(, [u],)], , [{, 
[, , , , , , , , , r, e, t, u, r, n, , u, ., n, a, m, e, , !, =, , 
[', [{, {, {, J, o, h, n], '], ;, , , , , , , ], }]],)], 
, , , , , , , ., m, a, p, [(, [[(, [u],)], , =, >, , u, ., n, a, m, e],)], 
., t, o, L, i, s, t, [(, [],)], 
, , , , , , ], }]] 

我认为这是正确的,但我仍然在寻找一个简单的解决方案。


更新:

它不能处理这种复杂的代码:

"""${ 
    users.where((u) => u.name != 'Jeff}}}}}}}}') 
    .where((u) { 
    return u.name != '{{{John${ 
    users.where((u) => u.name != 'Jeff}}}}}}}}') 
    .where((u) { 
    return u.name != '{{{John'; 
    }) 
    .map((u) => u.name).toList() 
    }'; 
    }) 
    .map((u) => u.name).toList() 
    }""" 

也就是说${}一个字符串,它内部的${}内。除此之外还有其他情况吗?