In my opinion, the Interpreter Design Pattern is simply to create a parser to execute syntax beyond the rules of the language and get results.
We have the following text to process:
1 + 1 = ?
(1 + 1) * 5 / 2 = ?
6.43 * 7 = ?
These are very simple mathematical expressions.
We only use Golang to write a simple program to calculate the result.
But if the mathematical expressions are complex or there are many different mathematical expressions, do we need to write a program for each expression?
So the interpreter design pattern solves this problem. We set a specified syntax input for this expression, then write an interpreter to interpret and calculate the input, and then return the result, that is, only write once, but all different expressions can be run
There is no javascript evel() function in golang. Therefore, we can using goja to use the javascript engine to call the eval() function:
github.com/dop251/goja
We using eval() function to write a Interpreter:
interpreter.go
package designpattern
import (
"fmt"
"github.com/dop251/goja"
)
type Context struct {
expression Expression
}
func NewContext() *Context {
return &Context{expression: &JavaScriptExpression{}}
}
func (context *Context) Eval(expr string) float64 {
return context.expression.interpret(expr)
}
type Expression interface {
interpret(expr string) float64
}
type JavaScriptExpression struct {
}
func (expression *JavaScriptExpression) interpret(expr string) float64 {
javascript := fmt.Sprintf("eval(%s).toFixed(6)", expr)
vm := goja.New()
v, err := vm.RunString(javascript)
if err != nil {
panic("Javascript eval expression exception")
}
return v.ToFloat()
}
interpreter_test.go
package designpattern_test
import (
designpattern "ptarmigan-golang-design-pattern/src"
"testing"
)
func TestInterpreter(t *testing.T) {
ctx := designpattern.NewContext()
f1 := ctx.Eval("1 + 1")
if f1 != 2 {
t.Error("The result must equals 2")
}
f2 := ctx.Eval("12 + 7 * 3")
if f2 != 33 {
t.Error("The result must equals 33")
}
f3 := ctx.Eval("(1 + 1) * 5 / 2")
if f3 != 5 {
t.Error("The result must equals 5")
}
f4 := ctx.Eval("13 % 2")
if f4 != 1 {
t.Error("The result must equals 1")
}
f5 := ctx.Eval("Math.cos(Math.PI / 3) * 2")
if f5 != 1 {
t.Error("The result must equals 1")
}
f6 := ctx.Eval("6.43 * 7")
if f6 != 45.01 {
t.Error("The result must equals 45.01")
}
}