使用Ffltter的PetiteParser创建FHIRPath [英] Using Flutter's PetiteParser to create FHIRPath

查看:21
本文介绍了使用Ffltter的PetiteParser创建FHIRPath的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想寻求一些使用mini tparser的指导(我正在更新这个问题)。我正尝试在DART中重新创建一个名为FHIRPath的基于json的语法。我对这样的语法还不熟悉,所以我花了一些时间来理解我想要它做什么(或者我认为我想要它做什么)。我已经设法让它解析json路径和一般函数,它看起来如下所示:

class FhirPathGrammar extends GrammarDefinition {
  Parser start() => ref0(value).end();

  Parser value() => (ref0(parens) | ref0(dotString) | ref0(path)).star();

  Parser parens() =>
      (char('(') & ref0(value) & char(')')).map((value) => value);

  Parser dotString() =>
      (anyOf('-_') | letter() | digit() | range(0x80, 0x10FFF))
          .plus()
          .flatten();
          
  Parser path() => (char('.') & ref0(dotString)).map((value) => value);
}

如果我运行此函数:

void main() {
  var pathString = 'Patient.name.exists()';
  var definition = FhirPathGrammar();
  final parser = definition.build();
  print(parser.parse(pathString));
}

这是结果:

[Patient, [., name], [., exists], [(, [], )]]

到目前为止一切顺利。但现在,如果我更改了语法类,并添加了一个相同的解析器:

class FhirPathGrammar extends GrammarDefinition {
  Parser start() => ref0(value).end();

  Parser value() =>
      (ref0(parens) | ref0(dotString) | ref0(path) | ref0(equal)).star();

  Parser equal() =>
      (ref0(value) & string(' = ') & ref0(value)).map((value) => value);

  Parser parens() =>
      (char('(') & ref0(value) & char(')')).map((value) => value);

  Parser dotString() =>
      (anyOf('-_') | letter() | digit() | range(0x80, 0x10FFF))
          .plus()
          .flatten();

  Parser path() => (char('.') & ref0(dotString)).map((value) => value);
}

我收到错误:

Unhandled exception:
Stack Overflow
#0      ChoiceParser.parseOn  package:petitparser/…/combinator/choice.dart:71
#1      PossessiveRepeatingParser.parseOn  package:petitparser/…/repeater/possessive.dart:59
#2      FlattenParser.parseOn  package:petitparser/…/action/flatten.dart:31
// Then these 4 lines repeat
#3      ChoiceParser.parseOn  package:petitparser/…/combinator/choice.dart:69
#4      PossessiveRepeatingParser.parseOn  package:petitparser/…/repeater/possessive.dart:67
#5      SequenceParser.parseOn  package:petitparser/…/combinator/sequence.dart:39
#6      MapParser.parseOn  package:petitparser/…/action/map.dart:38
// until it gets here
#9491   ChoiceParser.parseOn  package:petitparser/…/combinator/choice.dart:69
#9492   PossessiveRepeatingParser.parseOn  package:petitparser/…/repeater/possessive.dart:67
#9493   SequenceParser.parseOn  package:petitparser/…/combinator/sequence.dart:39
#9494   PickParser.parseOn  package:petitparser/…/action/pick.dart:26
#9495   CastParser.parseOn  package:petitparser/…/action/cast.dart:17
#9496   Parser.parse  package:petitparser/…/core/parser.dart:51
#9497   main  fhir_path/also_main.dart:7
#9498   _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:283:19)
#9499   _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)

正如@Lukas-Renggli指出的那样,它似乎进入了一个无限循环。因此,至少我认为这就是正在发生的事情。但我不认为我理解它是如何匹配的,这导致了无限循环。

推荐答案

如果没有一个最小的、可重复的示例,我很难判断发生了什么。然而,我怀疑星运算符中的选择中的一个解析器总是在不消耗任何东西的情况下成功(ref0(empty)看起来可疑)。这将导致无限循环。

例如,下面的解析器显示这样的行为:

epsilon().star().parse('');   // loops forever

更新问题的答案:您的语法left-recursiveequals生产中。一个类似的、稍微简单一点的例子是:

// Loops forever: expression is recursively called without consuming anything.
Parser expression() => (ref0(expression) & char('+') & ref0(expression)) 
    | digit();`

// Fixes the infinite loop by forcing the grammar to consume something 
// at each step.
Parser expression() => digit().separatedBy(char('+'));

有多种方法可以修复您的示例,具体取决于您想要的行为。最简单的选项是重写语法,使等号作为其他选项之间的分隔符:

Parser value() => (ref0(parens) | ref0(dotString) | ref0(path))
    .separatedBy(string(" = "));
我建议您查看Expression Builder。它可以简化表达式解析器的构建并避免常见陷阱。

这篇关于使用Ffltter的PetiteParser创建FHIRPath的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆