// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com). // All rights reserved. // operator-prod.go package expr import ( "errors" "strings" ) //-------- multiply term func newMultiplyTerm(tk *Token) (inst *term) { return &term{ tk: *tk, // class: classOperator, // kind: kindUnknown, children: make([]*term, 0, 2), position: posInfix, priority: priProduct, evalFunc: evalMultiply, } } func evalMultiply(ctx ExprContext, self *term) (v any, err error) { var leftValue, rightValue any if leftValue, rightValue, err = self.evalInfix(ctx); err != nil { return } if isString(leftValue) && isInteger(rightValue) { s, _ := leftValue.(string) n, _ := rightValue.(int64) v = strings.Repeat(s, int(n)) } else if isNumber(leftValue) && isNumber(rightValue) { if isFloat(leftValue) || isFloat(rightValue) { v = numAsFloat(leftValue) * numAsFloat(rightValue) } else { leftInt, _ := leftValue.(int64) rightInt, _ := rightValue.(int64) v = leftInt * rightInt } } else if isFraction(leftValue) || isFraction(rightValue) { v, err = mulAnyFract(leftValue, rightValue) } else { err = self.errIncompatibleTypes(leftValue, rightValue) } return } //-------- divide term func newDivideTerm(tk *Token) (inst *term) { return &term{ tk: *tk, // class: classOperator, // kind: kindUnknown, children: make([]*term, 0, 2), position: posInfix, priority: priProduct, evalFunc: evalDivide, } } func evalDivide(ctx ExprContext, self *term) (v any, err error) { var leftValue, rightValue any if leftValue, rightValue, err = self.evalInfix(ctx); err != nil { return } if isNumber(leftValue) && isNumber(rightValue) { if isFloat(leftValue) || isFloat(rightValue) { d := numAsFloat(rightValue) if d == 0.0 { err = errors.New("division by zero") } else { v = numAsFloat(leftValue) / d } } else { leftInt, _ := leftValue.(int64) if rightInt, _ := rightValue.(int64); rightInt == 0 { err = errors.New("division by zero") } else { v = leftInt / rightInt } } } else if isFraction(leftValue) || isFraction(rightValue) { v, err = divAnyFract(leftValue, rightValue) } else { err = self.errIncompatibleTypes(leftValue, rightValue) } return } //-------- divide as float term func newDivideAsFloatTerm(tk *Token) (inst *term) { return &term{ tk: *tk, children: make([]*term, 0, 2), position: posInfix, priority: priProduct, evalFunc: evalDivideAsFloat, } } func evalDivideAsFloat(ctx ExprContext, self *term) (v any, err error) { var leftValue, rightValue any if leftValue, rightValue, err = self.evalInfix(ctx); err != nil { return } if isNumber(leftValue) && isNumber(rightValue) { d := numAsFloat(rightValue) if d == 0.0 { err = errors.New("division by zero") } else { v = numAsFloat(leftValue) / d } } else { err = self.errIncompatibleTypes(leftValue, rightValue) } return } //-------- reminder term func newReminderTerm(tk *Token) (inst *term) { return &term{ tk: *tk, // class: classOperator, // kind: kindUnknown, children: make([]*term, 0, 2), position: posInfix, priority: priProduct, evalFunc: evalReminder, } } func evalReminder(ctx ExprContext, self *term) (v any, err error) { var leftValue, rightValue any if leftValue, rightValue, err = self.evalInfix(ctx); err != nil { return } if isInteger(leftValue) && isInteger(rightValue) { rightInt, _ := rightValue.(int64) if rightInt == 0 { err = errors.New("division by zero") } else { leftInt, _ := leftValue.(int64) v = leftInt % rightInt } } else { err = self.errIncompatibleTypes(leftValue, rightValue) } return } // init func init() { registerTermConstructor(SymStar, newMultiplyTerm) registerTermConstructor(SymSlash, newDivideTerm) registerTermConstructor(SymDotSlash, newDivideAsFloatTerm) registerTermConstructor(SymPercent, newReminderTerm) }