{"id":20111948,"url":"https://github.com/mezoni/fast_expressions","last_synced_at":"2026-05-24T16:32:15.973Z","repository":{"id":196255558,"uuid":"695650213","full_name":"mezoni/fast_expressions","owner":"mezoni","description":"Fast Expressions is an expression parser and evaluation library.","archived":false,"fork":false,"pushed_at":"2023-10-28T13:11:26.000Z","size":84,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-02T18:50:44.105Z","etag":null,"topics":["dart","dart3","dartlang","expression-evaluator","expression-parser","expressions"],"latest_commit_sha":null,"homepage":"","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mezoni.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2023-09-23T20:02:19.000Z","updated_at":"2024-11-13T06:52:39.000Z","dependencies_parsed_at":"2023-09-26T19:09:38.294Z","dependency_job_id":"407b7103-0b06-4441-a06e-00cf844f4549","html_url":"https://github.com/mezoni/fast_expressions","commit_stats":null,"previous_names":["mezoni/fast_expressions"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/mezoni/fast_expressions","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mezoni%2Ffast_expressions","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mezoni%2Ffast_expressions/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mezoni%2Ffast_expressions/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mezoni%2Ffast_expressions/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mezoni","download_url":"https://codeload.github.com/mezoni/fast_expressions/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mezoni%2Ffast_expressions/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33442523,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-24T13:13:05.286Z","status":"ssl_error","status_checked_at":"2026-05-24T13:13:03.728Z","response_time":57,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dart","dart3","dartlang","expression-evaluator","expression-parser","expressions"],"created_at":"2024-11-13T18:18:17.731Z","updated_at":"2026-05-24T16:32:15.937Z","avatar_url":"https://github.com/mezoni.png","language":"Dart","funding_links":[],"categories":[],"sub_categories":[],"readme":"# fast_expressions\n\nFast Expressions is an expression parser and evaluation library.\n\nVersion: 0.1.7\n\n[![Pub Package](https://img.shields.io/pub/v/fast_expressions.svg)](https://pub.dev/packages/fast_expressions)\n[![GitHub Issues](https://img.shields.io/github/issues/mezoni/fast_expressions.svg)](https://github.com/mezoni/fast_expressions/issues)\n[![GitHub Forks](https://img.shields.io/github/forks/mezoni/fast_expressions.svg)](https://github.com/mezoni/fast_expressions/forks)\n[![GitHub Stars](https://img.shields.io/github/stars/mezoni/fast_expressions.svg)](https://github.com/mezoni/fast_expressions/stargazers)\n[![GitHub License](https://img.shields.io/badge/License-BSD_3--Clause-blue.svg)](https://raw.githubusercontent.com/mezoni/fast_expressions/main/LICENSE)\n\n## About this software\n\nFast Expressions is an expression parser and evaluation library.  \nHigh performance when parsing parser expressions is achieved by using a very fast parser.  \nParsed expressions are wrapped into function calls.  \nHigh performance when evaluating expressions is achieved by not using any classes and using expression function execution  directly.\n\n## Example\n\n```dart\nimport 'dart:math';\n\nimport 'package:fast_expressions/fast_expressions.dart';\n\nvoid main(List\u003cString\u003e args) {\n  {\n    const e = '1.isEven ? \"Yes, 1 is even\" : \"No, 1 is odd\"';\n    final r = parseExpression(\n      e,\n      resolve: _resolve,\n    );\n    print(r());\n  }\n\n  {\n    const e = '1 + 2 * 3';\n    final r = parseExpression(e);\n    print(r());\n  }\n\n  {\n    const e = '1 + 2 * x';\n    final r = parseExpression(\n      e,\n      context: {\n        'x': 3,\n      },\n    );\n    print(r());\n  }\n\n  {\n    const e = '1 + 2 * x[y]';\n    final r = parseExpression(\n      e,\n      context: {\n        'x': [1, 2, 3],\n        'y': 2,\n      },\n    );\n    print(r());\n  }\n\n  {\n    const e = '1 + 2 * add(1, 2)';\n    final r = parseExpression(\n      e,\n      context: {\n        'add': (num x, num y) =\u003e x + y,\n      },\n    );\n    print(r());\n  }\n\n  {\n    const e = '1 + 2 * sub(x: 7, y: 4)';\n    final r = parseExpression(\n      e,\n      context: {\n        'sub': ({required num x, required num y}) =\u003e x - y,\n      },\n    );\n    print(r());\n  }\n\n  {\n    const e = '1 + 2 * foo.add(1, 2)';\n    final r = parseExpression(\n      e,\n      context: {\n        'foo': Foo(),\n      },\n      resolve: _resolve,\n    );\n    print(r());\n  }\n\n  {\n    const e = '1 + 2 * foo.list()[foo.add(1, 1)]';\n    final r = parseExpression(\n      e,\n      context: {\n        'foo': Foo(),\n      },\n      resolve: _resolve,\n    );\n    print(r());\n  }\n\n  {\n    const e = '''\n\"Hello, \" + friends[random()].name\n''';\n    final friends = [\n      Person('Jack'),\n      Person('Jerry'),\n      Person('John'),\n    ];\n    final r = parseExpression(\n      e,\n      context: {\n        'friends': friends,\n        'random': () =\u003e Random().nextInt(friends.length - 1),\n      },\n      resolve: _resolve,\n    );\n    print(r());\n  }\n}\n\ndynamic _resolve(dynamic object, String member) {\n  Never error() {\n    throw StateError(\"Invalid member '$member', object is $object\");\n  }\n\n  if (object is Foo) {\n    switch (member) {\n      case 'add':\n        return object.add;\n      case 'list':\n        return object.list;\n    }\n  }\n\n  if (object is Person) {\n    switch (member) {\n      case 'name':\n        return object.name;\n    }\n  }\n\n  if (object is int) {\n    switch (member) {\n      case 'isEven':\n        return object.isEven;\n    }\n  }\n\n  error();\n}\n\nclass Foo {\n  num add(num x, num y) =\u003e x + y;\n\n  List\u003cnum\u003e list() =\u003e [1, 2, 3];\n}\n\nclass Person {\n  final String name;\n\n  Person(this.name);\n}\n\n```\n\n## About the implementation of parsers\n\nParser are generated from PEG grammar.  \nSoftware used to generate parsers [![Pub Package](https://img.shields.io/pub/v/peg.svg)](https://pub.dev/packages/peg)  \nBelow is the source code of the grammar.\n\n```\n%{\n\ntypedef Expression = dynamic Function();\n\nString _escape(int charCode) {\n    switch (charCode) {\n      case 0x22:\n        return '\"';\n      case 0x2f:\n        return '/';\n      case 0x5c:\n        return '\\\\';\n      case 0x62:\n        return '\\b';\n      case 0x66:\n        return '\\f';\n      case 0x6e:\n        return '\\n';\n      case 0x72:\n        return '\\r';\n      case 0x74:\n        return '\\t';\n      default:\n        throw StateError('Unable to escape charCode: $charCode');\n    }\n  }\n\n}%\n\n%%\n  final Map\u003cString, dynamic\u003e context;\n\n  final dynamic Function(dynamic object, String member)? resolve;\n\n  ExpressionParser({\n    this.context = const {},\n    this.resolve,\n  });\n\n  Expression _binary(Expression? left, ({String op, Expression expr}) next) {\n    final op = next.op;\n    final right = next.expr;\n    final l = left!;\n    switch (op) {\n      case '+':\n        return () =\u003e l() + right();\n      case '-':\n        return () =\u003e l() - right();\n      case '/':\n        return () =\u003e l() / right();\n      case '*':\n        return () =\u003e l() * right();\n      case '%':\n        return () =\u003e l() % right();\n      case '~/':\n        return () =\u003e l() ~/ right();\n      case '\u003c\u003c':\n        return () =\u003e l() \u003c\u003c right();\n      case '\u003e\u003e':\n        return () =\u003e l() \u003e\u003e right();\n      case '\u003e\u003e\u003e':\n        return () =\u003e l() \u003e\u003e\u003e right();\n      case '\u0026':\n        return () =\u003e l() \u0026 right();\n      case '^':\n        return () =\u003e l() ^ right();\n      case '|':\n        return () =\u003e l() | right();\n      case '\u003e':\n        return () =\u003e l() \u003e right();\n      case '\u003e=':\n        return () =\u003e l() \u003e= right();\n      case '\u003c':\n        return () =\u003e l() \u003c right();\n      case '\u003c=':\n        return () =\u003e l() \u003c= right();\n      case '||':\n        return () =\u003e l() as bool || right() as bool;\n      case '\u0026\u0026':\n        return () =\u003e l() as bool \u0026\u0026 right() as bool;\n      case '??':\n        return () =\u003e l() ?? right();\n      case '==':\n        return () =\u003e l() == right();\n      case '!=':\n        return () =\u003e l() != right();\n      default:\n        throw StateError('Unknown operator: $op');\n    }\n  }\n\n  Expression _prefix(String? operator, Expression operand) {\n    if (operator == null) {\n      return operand;\n    }\n\n    switch (operator) {\n      case '-':\n        return () =\u003e -operand();\n      case '!':\n        return () =\u003e !(operand() as bool);\n      case '~':\n        return () =\u003e ~operand();\n      default:\n        throw StateError('Unknown operator: $operator');\n    }\n  }\n\n  Expression _postfix(\n      Expression object, List\u003c({String kind, dynamic arguments})\u003e selectors) {\n    for (final selector in selectors) {\n      final kind = selector.kind;\n      final arguments = selector.arguments;\n      switch (kind) {\n        case '.':\n          final member = arguments as String;\n          final object2 = object;\n          object = () {\n            final object3 = object2();\n            if (resolve case final resolve?) {\n              return resolve(object3, member);\n            } else {\n              throw StateError(\n                  \"Unable to resolve member '$member' for $object3\");\n            }\n          };\n          break;\n        case '[':\n          final index = arguments as dynamic Function();\n          final object2 = object;\n          object = () {\n            final object3 = object2();\n            final index2 = index();\n            return object3[index2];\n          };\n          break;\n        case '(':\n          final object2 = object;\n          final arguments2 =\n              arguments as List\u003c({String name, Expression expr})\u003e;\n          object = () {\n            final object3 = object2() as Function;\n            final positionalArguments = \u003cdynamic\u003e[];\n            final namedArguments = \u003cSymbol, dynamic\u003e{};\n            for (final element in arguments2) {\n              final name = element.name;\n              final expr = element.expr;\n              if (name.isEmpty) {\n                positionalArguments.add(expr());\n              } else {\n                if (namedArguments.containsKey(name)) {\n                  throw StateError('Duplicate named argument: $name');\n                }\n\n                final key = Symbol(name);\n                namedArguments[key] = expr();\n              }\n            }\n\n            return Function.apply(object3, positionalArguments, namedArguments);\n          };\n          break;\n        default:\n          throw StateError('Unknown selector: $kind');\n      }\n    }\n\n    return object;\n  }\n%%\n\nStart = Spaces v:Expression Eof ;\n\nExpression = Conditional ;\n\nExpression\nConditional =\n    e1:IfNull Question e2:Expression Colon e3:Expression { $$ = () =\u003e e1() as bool ? e2() : e3(); }\n  / IfNull ;\n\nExpression\nIfNull = h:LogicalOr t:(op:IfNullOp ↑ expr:LogicalOr)* { $$ = t.isEmpty ? h : t.fold(h, _binary); } ;\n\nIfNullOp = v:'??' Spaces ;\n\nExpression\nLogicalOr = h:LogicalAnd t:(op:LogicalOrOp ↑ expr:LogicalAnd)* { $$ = t.isEmpty ? h : t.fold(h, _binary); } ;\n\nLogicalOrOp = v:'||' Spaces ;\n\nExpression\nLogicalAnd = h:Equality t:(op:LogicalAndOp ↑ expr:Equality)* { $$ = t.isEmpty ? h : t.fold(h, _binary); } ;\n\nLogicalAndOp = v:'\u0026\u0026' Spaces ;\n\nExpression\nEquality = h:Relational t:(op:EqualityOp ↑ expr:Relational)* { $$ = t.isEmpty ? h : t.fold(h, _binary); } ;\n\nEqualityOp = v:('==' / '!=') Spaces ;\n\nExpression\nRelational = h:BitwiseOr t:(op:RelationalOp ↑ expr:BitwiseOr)* { $$ = t.isEmpty ? h : t.fold(h, _binary); } ;\n\nRelationalOp = v:('\u003e=' / '\u003e' / '\u003c=' / '\u003c') Spaces ;\n\nExpression\nBitwiseOr = h:BitwiseXor t:(op:BitwiseOrOp ↑ expr:BitwiseXor)* { $$ = t.isEmpty ? h : t.fold(h, _binary); } ;\n\nBitwiseOrOp = !'||' v:'|' Spaces ;\n\nExpression\nBitwiseXor = h:BitwiseAnd t:(op:BitwiseXorOp ↑ expr:BitwiseAnd)* { $$ = t.isEmpty ? h : t.fold(h, _binary); } ;\n\nBitwiseXorOp = v:'^' Spaces ;\n\nExpression\nBitwiseAnd = h:Shift t:(op:BitwiseAndOp ↑ expr:Shift)* { $$ = t.isEmpty ? h : t.fold(h, _binary); } ;\n\nBitwiseAndOp = !'\u0026\u0026' v:'\u0026' Spaces ;\n\nExpression\nShift = h:Additive t:(op:ShiftOp ↑ expr:Additive)* { $$ = t.isEmpty ? h : t.fold(h, _binary); } ;\n\nShiftOp = v:('\u003c\u003c' / '\u003e\u003e\u003e' / '\u003e\u003e') Spaces ;\n\nExpression\nAdditive = h:Multiplicative t:(op:AdditiveOp ↑ expr:Multiplicative)* { $$ = t.isEmpty ? h : t.fold(h, _binary); } ;\n\nAdditiveOp = v:('-' / '+') Spaces ;\n\nExpression\nMultiplicative = h:UnaryPrefix t:(op:MultiplicativeOp ↑ expr:UnaryPrefix)* { $$ = t.isEmpty ? h : t.fold(h, _binary); } ;\n\nMultiplicativeOp = v:('/' / '*' / '%' / '~/') Spaces ;\n\nUnaryPrefix = @expected('expression', UnaryPrefix_) ;\n\n@inline\nExpression\nUnaryPrefix_ = op:UnaryPrefixOp? expr:UnaryPostfix { $$ = _prefix(op, expr); } ;\n\nUnaryPrefixOp = v:('-' / '!' / '~') Spaces ;\n\nExpression\nUnaryPostfix = object:Primary selectors:Selector* { $$ = _postfix(object, selectors); } ;\n\n({String kind, dynamic arguments})\nSelector =\n    kind:Dot arguments:Identifier_\n  / kind:OpenBracket arguments:Expression CloseBracket\n  / kind:OpenParenthesis arguments:Arguments CloseParenthesis ;\n\nArguments = @list(NamedArgument / PositionalArgument, Comma ↑ v:(NamedArgument / PositionalArgument)) ;\n\nNamedArgument = name:Identifier_ Colon expr:Expression ;\n\nPositionalArgument = name:'' expr:Expression ;\n\nPrimary =\n    Number\n  / Boolean\n  / String\n  / Null\n  / Identifier\n  / OpenParenthesis v:Expression CloseParenthesis ;\n\nExpression\nNull = 'null' Spaces { $$ = () =\u003e null; } ;\n\nExpression\nBoolean =\n    'true' Spaces { $$ = () =\u003e true; }\n  / 'false' Spaces { $$ = () =\u003e false; } ;\n\nExpression\nNumber = v:$(\n  [-]?\n  ([0] / [1-9][0-9]*)\n  ([.] [0-9]+)?\n  ([eE] ↑ [-+]? [0-9]+)?\n  ) Spaces {\n    final n = num.parse(v);\n    $$ = () =\u003e n;\n  } ;\n\n@inline\nString\nEscapeChar = c:[\"/bfnrt\\\\] { $$ = _escape(c); } ;\n\n@inline\nString\nEscapeHex = 'u' v:HexNumber { $$ = String.fromCharCode(v); } ;\n\nHexNumber = @indicate('Expected 4 digit hex number', HexNumber_) ;\n\n@inline\nint\nHexNumber_ = v:$([0-9A-Za-z]{4}) { $$ = int.parse(v, radix: 16); } ;\n\nString\nStringChars =\n    $[\\u{20}-\\u{21}\\u{23}-\\u{5b}\\u{5d}-\\u{10ffff}]+\n  / '\\\\' v:(EscapeChar / EscapeHex) ;\n\nString\nStringRaw = '\"' v:StringChars* DoubleQuote { $$ = v.join(); } ;\n\nExpression\nString = v:StringRaw { $$ = () =\u003e v; } ;\n\n@inline\nString\nIdentifier_ = v:@expected('identifier', $([a-zA-Z_$] [a-zA-Z_$0-9]*)) Spaces ;\n\nExpression\nIdentifier = v:Identifier_ {\n    $$ = () {\n      if (!context.containsKey(v)) {\n        throw StateError(\"Variable '$v' not found\");\n      }\n      return context[v];\n    };\n  } ;\n\nEof = !. ;\n\nCloseBracket = v:']' Spaces ;\n\nCloseParenthesis = v:')' Spaces ;\n\nColon = v:':' Spaces ;\n\nComma = v:',' Spaces ;\n\nDot = v:'.' Spaces ;\n\nDoubleQuote = v:'\"' Spaces ;\n\nOpenBracket = v:'[' Spaces ;\n\nOpenParenthesis = v:'(' Spaces ;\n\nQuestion = v:'?' Spaces ;\n\nSpaces = [ \\n\\r\\t]* ;\n\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmezoni%2Ffast_expressions","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmezoni%2Ffast_expressions","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmezoni%2Ffast_expressions/lists"}