2

I want to use PetitParserDart to parse the embed expression inside a dart string.

Prepare some objects:

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];

The long string:

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.
"""

You can see there is a ${} inside the string, and its content is very complex.

I'm try to use such petitparser code:

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

But I don't know how to define the expr rule. It may contain { or }, so I can't simply use anyIn('{}').neg().

What do I do now? I feel it will be a very complicated rule.

Freewind
  • 193,756
  • 157
  • 432
  • 708

3 Answers3

1

I don't think you can correctly parse all possible strings without having a more or less complete Dart expression grammar. You can either write an approximation (as you did in your answer) or try to use the expression production of the Dart grammar that comes with the examples. In either case the resulting grammar is complicated, because the thing you try to match is complicated.

Lukas Renggli
  • 8,754
  • 23
  • 46
0

There is a grammar for Dart in src/dart/grammar.dart, that seems like it would be able to parse that.

Alan Knight
  • 2,759
  • 1
  • 15
  • 13
0

I've found a solution: Determine the strings inside ${}, match them first. Then match all {}.

Code:

// 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('}'));

Test code:

  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);

It prints:

[$, [{, [
,  ,  ,  ,  ,  ,  , 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, [(, [], )], 
,  ,  ,  ,  ,  ,  ], }]]

Which I think is correct, but I still looking for an simpler solution.


Update:

It can't handle such complex code:

"""${
  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()
  }"""

That is ${} inside a string which inside a ${}. Is there any other case except this?

Freewind
  • 193,756
  • 157
  • 432
  • 708