Flutter表达式计算插件fast_expressions的使用
Flutter表达式计算插件fast_expressions的使用
Fast Expressions 是一个用于解析和评估表达式的库。它在解析表达式时具有高性能,通过使用非常快速的解析器来实现。解析后的表达式会被包装成函数调用。在评估表达式时,通过不使用任何类并直接执行表达式函数来提高性能。
关于这个软件
Fast Expressions 是一个用于解析和评估表达式的库。高效率的解析性能通过使用非常快速的解析器实现。解析后的表达式被封装为函数调用。在评估表达式时,通过不使用任何类并直接执行表达式函数来实现高效率。
示例
以下是一些使用 fast_expressions
库的例子:
import 'dart:math';
import 'package:fast_expressions/fast_expressions.dart';
void main(List<String> args) {
// 示例 1: 使用三元运算符
{
const e = '1.isEven ? "Yes, 1 is even" : "No, 1 is odd"';
final r = parseExpression(
e,
resolve: _resolve,
);
print(r()); // 输出: No, 1 is odd
}
// 示例 2: 简单算术表达式
{
const e = '1 + 2 * 3';
final r = parseExpression(e);
print(r()); // 输出: 7
}
// 示例 3: 使用变量
{
const e = '1 + 2 * x';
final r = parseExpression(
e,
context: {
'x': 3,
},
);
print(r()); // 输出: 7
}
// 示例 4: 数组访问
{
const e = '1 + 2 * x[y]';
final r = parseExpression(
e,
context: {
'x': [1, 2, 3],
'y': 2,
},
);
print(r()); // 输出: 7
}
// 示例 5: 自定义函数
{
const e = '1 + 2 * add(1, 2)';
final r = parseExpression(
e,
context: {
'add': (num x, num y) => x + y,
},
);
print(r()); // 输出: 7
}
// 示例 6: 带有命名参数的自定义函数
{
const e = '1 + 2 * sub(x: 7, y: 4)';
final r = parseExpression(
e,
context: {
'sub': ({required num x, required num y}) => x - y,
},
);
print(r()); // 输出: 5
}
// 示例 7: 调用对象的方法
{
const e = '1 + 2 * foo.add(1, 2)';
final r = parseExpression(
e,
context: {
'foo': Foo(),
},
resolve: _resolve,
);
print(r()); // 输出: 7
}
// 示例 8: 复杂表达式
{
const e = '1 + 2 * foo.list()[foo.add(1, 1)]';
final r = parseExpression(
e,
context: {
'foo': Foo(),
},
resolve: _resolve,
);
print(r()); // 输出: 4
}
// 示例 9: 字符串拼接
{
const e = '''
"Hello, " + friends[random()].name
''';
final friends = [
Person('Jack'),
Person('Jerry'),
Person('John'),
];
final r = parseExpression(
e,
context: {
'friends': friends,
'random': () => Random().nextInt(friends.length - 1),
},
resolve: _resolve,
);
print(r()); // 输出随机名字,例如: Hello, Jack
}
}
// 解析对象成员的函数
dynamic _resolve(dynamic object, String member) {
Never error() {
throw StateError("Invalid member '$member', object is $object");
}
if (object is Foo) {
switch (member) {
case 'add':
return object.add;
case 'list':
return object.list;
}
}
if (object is Person) {
switch (member) {
case 'name':
return object.name;
}
}
if (object is int) {
switch (member) {
case 'isEven':
return object.isEven;
}
}
error();
}
// 示例类
class Foo {
num add(num x, num y) => x + y;
List<num> list() => [1, 2, 3];
}
// 示例类
class Person {
final String name;
Person(this.name);
}
关于解析器的实现
解析器是通过 PEG 语法生成的。用于生成解析器的软件可以通过以下链接获取: PEG
以下是语法源代码:
%{
typedef Expression = dynamic Function();
String _escape(int charCode) {
switch (charCode) {
case 0x22:
return '"';
case 0x2f:
return '/';
case 0x5c:
return '\\';
case 0x62:
return '\b';
case 0x66:
return '\f';
case 0x6e:
return '\n';
case 0x72:
return '\r';
case 0x74:
return '\t';
default:
throw StateError('Unable to escape charCode: $charCode');
}
}
}%
%%
final Map<String, dynamic> context;
final dynamic Function(dynamic object, String member)? resolve;
ExpressionParser({
this.context = const {},
this.resolve,
});
Expression _binary(Expression? left, ({String op, Expression expr}) next) {
final op = next.op;
final right = next.expr;
final l = left!;
switch (op) {
case '+':
return () => l() + right();
case '-':
return () => l() - right();
case '/':
return () => l() / right();
case '*':
return () => l() * right();
case '%':
return () => l() % right();
case '~/':
return () => l() ~/ right();
case '<<':
return () => l() << right();
case '>>':
return () => l() >> right();
case '>>>':
return () => l() >>> right();
case '&':
return () => l() & right();
case '^':
return () => l() ^ right();
case '|':
return () => l() | right();
case '>':
return () => l() > right();
case '>=':
return () => l() >= right();
case '<':
return () => l() < right();
case '<=':
return () => l() <= right();
case '||':
return () => l() as bool || right() as bool;
case '&&':
return () => l() as bool && right() as bool;
case '??':
return () => l() ?? right();
case '==':
return () => l() == right();
case '!=':
return () => l() != right();
default:
throw StateError('Unknown operator: $op');
}
}
Expression _prefix(String? operator, Expression operand) {
if (operator == null) {
return operand;
}
switch (operator) {
case '-':
return () => -operand();
case '!':
return () => !(operand() as bool);
case '~':
return () => ~operand();
default:
throw StateError('Unknown operator: $operator');
}
}
Expression _postfix(
Expression object, List<({String kind, dynamic arguments})> selectors) {
for (final selector in selectors) {
final kind = selector.kind;
final arguments = selector.arguments;
switch (kind) {
case '.':
final member = arguments as String;
final object2 = object;
object = () {
final object3 = object2();
if (resolve case final resolve?) {
return resolve(object3, member);
} else {
throw StateError(
"Unable to resolve member '$member' for $object3");
}
};
break;
case '[':
final index = arguments as dynamic Function();
final object2 = object;
object = () {
final object3 = object2();
final index2 = index();
return object3[index2];
};
break;
case '(':
final object2 = object;
final arguments2 =
arguments as List<({String name, Expression expr})>;
object = () {
final object3 = object2() as Function;
final positionalArguments = <dynamic>[];
final namedArguments = <Symbol, dynamic>{};
for (final element in arguments2) {
final name = element.name;
final expr = element.expr;
if (name.isEmpty) {
positionalArguments.add(expr());
} else {
if (namedArguments.containsKey(name)) {
throw StateError('Duplicate named argument: $name');
}
final key = Symbol(name);
namedArguments[key] = expr();
}
}
return Function.apply(object3, positionalArguments, namedArguments);
};
break;
default:
throw StateError('Unknown selector: $kind');
}
}
return object;
}
%%
Start = Spaces v:Expression Eof ;
Expression = Conditional ;
Expression
Conditional =
e1:IfNull Question e2:Expression Colon e3:Expression { $$ = () => e1() as bool ? e2() : e3(); }
/ IfNull ;
Expression
IfNull = h:LogicalOr t:(op:IfNullOp ↑ expr:LogicalOr)* { $$ = t.isEmpty ? h : t.fold(h, _binary); } ;
IfNullOp = v:'??' Spaces ;
Expression
LogicalOr = h:LogicalAnd t:(op:LogicalOrOp ↑ expr:LogicalAnd)* { $$ = t.isEmpty ? h : t.fold(h, _binary); } ;
LogicalOrOp = v:'||' Spaces ;
Expression
LogicalAnd = h:Equality t:(op:LogicalAndOp ↑ expr:Equality)* { $$ = t.isEmpty ? h : t.fold(h, _binary); } ;
LogicalAndOp = v:'&&' Spaces ;
Expression
Equality = h:Relational t:(op:EqualityOp ↑ expr:Relational)* { $$ = t.isEmpty ? h : t.fold(h, _binary); } ;
EqualityOp = v:('==' / '!=') Spaces ;
Expression
Relational = h:BitwiseOr t:(op:RelationalOp ↑ expr:BitwiseOr)* { $$ = t.isEmpty ? h : t.fold(h, _binary); } ;
RelationalOp = v:('>=' / '>' / '<=' / '<') Spaces ;
Expression
BitwiseOr = h:BitwiseXor t:(op:BitwiseOrOp ↑ expr:BitwiseXor)* { $$ = t.isEmpty ? h : t.fold(h, _binary); } ;
BitwiseOrOp = !'||' v:'|' Spaces ;
Expression
BitwiseXor = h:BitwiseAnd t:(op:BitwiseXorOp ↑ expr:BitwiseAnd)* { $$ = t.isEmpty ? h : t.fold(h, _binary); } ;
BitwiseXorOp = v:'^' Spaces ;
Expression
BitwiseAnd = h:Shift t:(op:BitwiseAndOp ↑ expr:Shift)* { $$ = t.isEmpty ? h : t.fold(h, _binary); } ;
BitwiseAndOp = !'&&' v:'&' Spaces ;
Expression
Shift = h:Additive t:(op:ShiftOp ↑ expr:Additive)* { $$ = t.isEmpty ? h : t.fold(h, _binary); } ;
ShiftOp = v:('<<' / '>>>' / '>>') Spaces ;
Expression
Additive = h:Multiplicative t:(op:AdditiveOp ↑ expr:Multiplicative)* { $$ = t.isEmpty ? h : t.fold(h, _binary); } ;
AdditiveOp = v:('-' / '+') Spaces ;
Expression
Multiplicative = h:UnaryPrefix t:(op:MultiplicativeOp ↑ expr:UnaryPrefix)* { $$ = t.isEmpty ? h : t.fold(h, _binary); } ;
MultiplicativeOp = v:('/' / '*' / '%' / '~/') Spaces ;
UnaryPrefix = [@expected](/user/expected)('expression', UnaryPrefix_) ;
[@inline](/user/inline)
Expression
UnaryPrefix_ = op:UnaryPrefixOp? expr:UnaryPostfix { $$ = _prefix(op, expr); } ;
UnaryPrefixOp = v:('-' / '!' / '~') Spaces ;
Expression
UnaryPostfix = object:Primary selectors:Selector* { $$ = _postfix(object, selectors); } ;
({String kind, dynamic arguments})
Selector =
kind:Dot arguments:Identifier_
/ kind:OpenBracket arguments:Expression CloseBracket
/ kind:OpenParenthesis arguments:Arguments CloseParenthesis ;
Arguments = [@list](/user/list)(NamedArgument / PositionalArgument, Comma ↑ v:(NamedArgument / PositionalArgument)) ;
NamedArgument = name:Identifier_ Colon expr:Expression ;
PositionalArgument = name:'' expr:Expression ;
Primary =
Number
/ Boolean
/ String
/ Null
/ Identifier
/ OpenParenthesis v:Expression CloseParenthesis ;
Expression
Null = 'null' Spaces { $$ = () => null; } ;
Expression
Boolean =
'true' Spaces { $$ = () => true; }
/ 'false' Spaces { $$ = () => false; } ;
Expression
Number = v:$(
[-]?
([0] / [1-9][0-9]*)
([.] [0-9]+)?
([eE] ↑ [-+]? [0-9]+)?
) Spaces {
final n = num.parse(v);
$$ = () => n;
} ;
[@inline](/user/inline)
String
EscapeChar = c:["/bfnrt\\] { $$ = _escape(c); } ;
[@inline](/user/inline)
String
EscapeHex = 'u' v:HexNumber { $$ = String.fromCharCode(v); } ;
HexNumber = [@indicate](/user/indicate)('Expected 4 digit hex number', HexNumber_) ;
[@inline](/user/inline)
int
HexNumber_ = v:$([0-9A-Za-z]{4}) { $$ = int.parse(v, radix: 16); } ;
String
StringChars =
$[\u{20}-\u{21}\u{23}-\u{5b}\u{5d}-\u{10ffff}]+
/ '\\' v:(EscapeChar / EscapeHex) ;
String
StringRaw = '"' v:StringChars* DoubleQuote { $$ = v.join(); } ;
Expression
String = v:StringRaw { $$ = () => v; } ;
[@inline](/user/inline)
String
Identifier_ = v:[@expected](/user/expected)('identifier', $([a-zA-Z_$] [a-zA-Z_$0-9]*)) Spaces ;
Expression
Identifier = v:Identifier_ {
$$ = () {
if (!context.containsKey(v)) {
throw StateError("Variable '$v' not found");
}
return context[v];
};
} ;
Eof = !. ;
CloseBracket = v:']' Spaces ;
CloseParenthesis = v:')' Spaces ;
Colon = v:':' Spaces ;
Comma = v:',' Spaces ;
Dot = v:'.' Spaces ;
DoubleQuote = v:'"' Spaces ;
OpenBracket = v:'[' Spaces ;
OpenParenthesis = v:'(' Spaces ;
Question = v:'?' Spaces ;
Spaces = [ \n\r\t]* ;
更多关于Flutter表达式计算插件fast_expressions的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter表达式计算插件fast_expressions的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,下面是一个关于如何使用Flutter表达式计算插件fast_expressions
的代码示例。这个插件允许你解析和计算数学表达式。
首先,你需要在你的pubspec.yaml
文件中添加fast_expressions
依赖:
dependencies:
flutter:
sdk: flutter
fast_expressions: ^x.y.z # 请替换为最新版本号
然后运行flutter pub get
来获取依赖。
接下来,你可以在你的Flutter应用中使用fast_expressions
来计算表达式。以下是一个简单的示例,展示如何在Flutter应用中实现这一功能:
import 'package:flutter/material.dart';
import 'package:fast_expressions/fast_expressions.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Expression Calculator',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: CalculatorScreen(),
);
}
}
class CalculatorScreen extends StatefulWidget {
@override
_CalculatorScreenState createState() => _CalculatorScreenState();
}
class _CalculatorScreenState extends State<CalculatorScreen> {
final TextEditingController _controller = TextEditingController();
String _result = '';
void _calculate() {
try {
final expression = _controller.text;
final parser = ExpressionParser();
final compiled = parser.parse(expression);
final context = ExpressionContext();
final result = compiled.evaluate(context);
setState(() {
_result = result.toString();
});
} catch (e) {
setState(() {
_result = 'Error: $e';
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter Expression Calculator'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextField(
controller: _controller,
decoration: InputDecoration(
labelText: 'Enter Expression',
border: OutlineInputBorder(),
),
keyboardType: TextInputType.multiline,
maxLines: null,
),
SizedBox(height: 16.0),
ElevatedButton(
onPressed: _calculate,
child: Text('Calculate'),
),
SizedBox(height: 16.0),
Text(
_result,
style: TextStyle(fontSize: 24.0, color: Colors.blue),
),
],
),
),
);
}
}
在这个示例中,我们创建了一个简单的Flutter应用,包含一个文本字段用于输入数学表达式,一个按钮用于触发计算,以及一个文本组件用于显示计算结果。
- 依赖添加:在
pubspec.yaml
中添加fast_expressions
依赖。 - UI布局:使用
Scaffold
、TextField
、ElevatedButton
和Text
组件构建UI。 - 表达式计算:在
_calculate
方法中,我们使用ExpressionParser
解析表达式,然后使用ExpressionContext
评估表达式并获取结果。
请注意,ExpressionParser
和ExpressionContext
是fast_expressions
插件提供的类,用于解析和评估数学表达式。
确保你已经安装了最新版本的fast_expressions
插件,并根据需要调整代码以适应你的应用逻辑。