CEL-GO 实践 - 练习

Hello World

本文测试基于Google的CEL-GP CodeLab课程,按照所有语言的入门规则,先从一个"hello world"开始。

配置环境

func exercise1() {
	fmt.Println("=== Exercise 1: Hello World ===\n")

	env, err := cel.NewEnv()

	if err != nil {

				glog.Exitf("Error creating CEL environment: %v", err)
	}

}

CEL应用程序根据环境来评估表达式,使用env,err := cel.NewEnv()来配置标准环境。
可以通过cel.EnvOption来订制环境,这些选项能够禁用宏、声明自定义变量和函数等。
一个标注的CEl环境支持语言规范[^1] 当中定义的所有类型、运算符、函数和宏。

解析并检查表达式

当配置好环境之后,就可以解析和检查表达式。

// Compile, eval, profit!
func exercise1() {
	fmt.Println("=== Exercise 1: Hello World ===\n")

	// 创建标准环境
	env, err := cel.NewEnv()

	if err != nil {

				glog.Exitf("Error creating CEL environment: %v", err)
	}

	// 检查表达式是否编译,返回AST、Issues (Issues定义用于检查解析和检查调用的错误详细信息的方法。)
	ast,iss := env.Parse(`"Hello, World!"`)

	// 是否存在语法错误
	if iss.Err() != nil {

		glog.Exitf("Error parsing expression: %v", iss.Err())
	}

	// 检查表达式的正确性
	checked,iss := env.Check(ast)

	// 检查是否存在语法错误
	if iss.Err() != nil {

		glog.Exitf("Error checking expression: %v", iss.Err())
	}

	// 检查表达式结果类型是否为String
	if !proto.Equal(checked.ResultType(),decls.String) {

		glog.Exitf("Error: expected result type to be string, got %v", checked.ResultType())
	}

	// TODO
}

env.Parseenv.Check返回的iss对象的值可能是错误的问题列表,如果iss.Err()不为nil,那说明表达式的语法或者语义有错误,程序无法继续运行。当表达式格式良好时,这两个调用的结果是一个可执行的cel.Ast
在这个codelab中解析和检查阶段被打包到当前文件的compile()方法中,它可以用于协助练习其余部分。

// compile将根据给定的表达式expr进行解析和检查
// ‘env’确定表达式执行的环境
// ‘exprType’ 匹配输入表达式结果的ResultType
func compile(env *cel.Env, expr string, exprType *exprpb.Type) *cel.Ast {
	ast, iss := env.Compile(expr)
	if iss.Err() != nil {
		glog.Exit(iss.Err())
	}
	if !proto.Equal(ast.ResultType(), exprType) {
		glog.Exitf(
			"Got %v, wanted %v result type", ast.ResultType(), exprType)
	}
	fmt.Printf("%s\n\n", strings.ReplaceAll(expr, "\t", " "))
	return ast
}

对表达式求值

一单表达式被解析并检查通过返回一个cel.Ast,代表它可以转换成一个可以求值的表达式程序,其参数绑定和求值模式可以使用cel.ProgramOption选项进行自定义。请注意,也可以使用cel.CheckedExprToAstcelParsedExprToAst函数从proto中读取cel.Ast

一旦设计好了cel.Program,就可以通过调用Eval对表达式进行求值,求值结果将包含结果、求值详情、错误状态等信息。

func exercise1() {
	fmt.Println("=== Exercise 1: Hello World ===\n")

	// 创建标准环境
	env, err := cel.NewEnv()

	if err != nil {

				glog.Exitf("Error creating CEL environment: %v", err)
	}

	// 检查表达式是否编译,返回AST、Issues (Issues定义用于检查解析和检查调用的错误详细信息的方法。)
	ast,iss := env.Parse(`"Hello, World!"`)

	// 是否存在语法错误
	if iss.Err() != nil {

		glog.Exitf("Error parsing expression: %v", iss.Err())
	}

	// 检查表达式的正确性
	checked,iss := env.Check(ast)

	// 检查是否存在语法错误
	if iss.Err() != nil {

		glog.Exitf("Error checking expression: %v", iss.Err())
	}

	// 检查表达式结果类型是否为String
	if !proto.Equal(checked.ResultType(),decls.String) {

		glog.Exitf("Error: expected result type to be string, got %v", checked.ResultType())
	}

	// 程序生成一个AST的可计算实例
	program, err := env.Program(checked)

	if err != nil {

		glog.Exitf("Error creating program: %v", err)
	}

	// 在没有任何附加参数的情况下执行程序
	out,_,err := eval(program, cel.NoVars())

	if err != nil {

		glog.Exitf("Error evaluating expression: %v", err)
	}

	// 打印结果
	fmt.Printf("Result: %v\n", out)
}

运行这段代码

run it.

输出:

=== Exercise 1: Hello World ===

------ input ------
(interpreter.emptyActivation)

------ result ------
value: Hello, World! (types.String)

Result: Hello, World!

在函数中使用变量

大多数CEL应用程序会声明可以在表达式中引用的变量。变量的声明指定了名称和类型。变量的类型可以是CEL内置的类型、协议缓冲区的知名类型,或者任何protobuf消息类型,只要它的描述符也被提供给CEL。

在下面的例子当中,compileevalhelpers方法被作为evn.Parse()/env.Check()/program.Eval()的替身而包含。这些辅助函数是用来打印练习的输入和输出的。

添加功能

在此开始使用exercise2的代码

注解

[^1]语言规范: https://github.com/google/cel-spec/blob/master/doc/langdef.md

posted @ 2022-06-05 21:55  鑄劍師  阅读(650)  评论(0编辑  收藏  举报