package main

import (
	"fmt"
	"gopl.io/ch7/eval"
	"log"
	"math"
	"strconv"
)

type Expr interface {
	// Eval 接口定义的方法
	Eval(env Env) float64
	String() string
}

// Var 变量
type Var string

// literal 常量
type literal float64

// 实现 常量和变量的Eval方法

func (v Var) Eval(env Env) float64 {
	return env[v]
}
func (l literal) Eval(Env) float64 {
	return float64(l)
}
func (v Var) String() string {
	return "变量:" + string(v)
}
func (l literal) String() string {
	return "常量:" + strconv.FormatFloat(float64(l), 'f', -1, 64)

}

// 一元符号
type unary struct {
	op rune
	x  Expr
}

// 二元符号
type binary struct {
	op   rune
	x, y Expr
}

// 实现对运算符的操作

func (u unary) Eval(env Env) float64 {
	switch u.op {
	case '+':
		return +u.x.Eval(env)
	case '-':
		return -u.x.Eval(env)
	}
	panic(fmt.Sprintf("没有支持的运算符，%q", u.op))
}
func (u unary) String() string {
	return "(操作符号:" + strconv.QuoteRuneToASCII(u.op) + " | " +
		u.x.String() + ")"

}

func (b binary) Eval(env Env) float64 {
	switch b.op {
	case '+':
		return b.x.Eval(env) + b.y.Eval(env)
	case '-':
		return b.x.Eval(env) - b.y.Eval(env)
	case '*':
		return b.x.Eval(env) * b.y.Eval(env)
	case '/':
		return b.x.Eval(env) / b.y.Eval(env)
	}
	panic(fmt.Sprintf("没有支持的运算符，%q", b.op))
}
func (b binary) String() string {
	return "(" + b.x.String() + " | 操作符号:" +
		strconv.QuoteRuneToASCII(b.op) + " | " + b.y.String() + ")"

}

// 函数调用表达式
type call struct {
	fn   string
	args []Expr
}

// 实现对函数的调用

func (c call) Eval(env Env) float64 {
	switch c.fn {
	case "pow":
		return math.Pow(c.args[0].Eval(env), c.args[1].Eval(env))
	case "sin":
		return math.Sin(c.args[0].Eval(env))
	case "sqrt":
		return math.Sqrt(c.args[0].Eval(env))
	}
	panic(fmt.Sprintf("没有支持的函数，%q", c.fn))

}
func (c call) String() string {
	var args string
	for i, v := range c.args {
		args += v.String()
		if i < len(c.args)-1 {
			args += ", "
		}
	}
	//fmt.Println(args)
	return "函数:" + c.fn + "(" + args + ")"

}

// Env 映射对应的变量值
type Env map[Var]float64

func main() {
	env := Env{"x": 3, "y": 4}
	xy := unary{
		op: '-',
		x:  Var("y"),
	}

	add := binary{
		op: '+',
		x:  Var("x"),
		y:  Var("y"),
	}

	// 乘
	mul := binary{
		op: '*',
		x:  Var("x"),
		y:  Var("y"),
	}

	// pow
	pow := call{
		fn:   "pow",
		args: []Expr{Var("x"), Var("y")},
	}

	fmt.Println("xy:", add.Eval(env))
	fmt.Println(xy.Eval(env))
	fmt.Println(mul.Eval(env))
	fmt.Println(pow.Eval(env))

	var val Expr = Var("x")
	fmt.Println(val)
	val = literal(234.323233)
	fmt.Println(val)
	fmt.Println(xy)
	fmt.Println(add)
	fmt.Println(mul)
	fmt.Println(pow)

	wawa := Env{"q": 1, "w": 2, "e": 3, "x": 3, "y": 4}
	fmt.Println("变量列表：", wawa)
	taowa := call{
		fn: "pow",
		args: []Expr{
			add,
			call{
				fn: "sqrt",
				args: []Expr{
					binary{
						op: '+',
						x:  Var("e"),
						y:  Var("q"),
					},
				},
			},
		},
	}
	fmt.Println(taowa)            // 函数:pow((变量:x | 操作符号:'+' | 变量:y), 函数:sqrt((变量:e | 操作符号:'+' | 变量:q)))
	fmt.Println(taowa.Eval(wawa)) // 49
	ss, err := eval.Parse("1+3+4")
	if err != nil {
		log.Fatalln(err)
	}
	print(ss.Eval(nil))
}
