// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com). // All rights reserved. // operator-prod.go package expr import ( "strings" "git.portale-stac.it/go-pkg/expr/kern" ) //-------- multiply term func newMultiplyTerm(tk *Token) (inst *term) { return &term{ tk: *tk, children: make([]*term, 0, 2), position: posInfix, priority: priProduct, evalFunc: evalMultiply, } } func mulValues(opTerm *term, leftValue, rightValue any) (v any, err error) { if kern.IsString(leftValue) && kern.IsInteger(rightValue) { s, _ := leftValue.(string) n, _ := rightValue.(int64) v = strings.Repeat(s, int(n)) } else if kern.IsNumOrFract(leftValue) && kern.IsNumOrFract(rightValue) { if kern.IsFloat(leftValue) || kern.IsFloat(rightValue) { v = kern.NumAsFloat(leftValue) * kern.NumAsFloat(rightValue) } else if kern.IsFraction(leftValue) || kern.IsFraction(rightValue) { v, err = kern.MulAnyFract(leftValue, rightValue) } else { leftInt, _ := leftValue.(int64) rightInt, _ := rightValue.(int64) v = leftInt * rightInt } } else { err = opTerm.errIncompatibleTypes(leftValue, rightValue) } return } func evalMultiply(ctx kern.ExprContext, prodTerm *term) (v any, err error) { var leftValue, rightValue any if leftValue, rightValue, err = prodTerm.evalInfix(ctx); err != nil { return } return mulValues(prodTerm, leftValue, rightValue) } //-------- divide term func newDivideTerm(tk *Token) (inst *term) { return &term{ tk: *tk, children: make([]*term, 0, 2), position: posInfix, priority: priProduct, evalFunc: evalDivide, } } func divValues(opTerm *term, leftValue, rightValue any) (v any, err error) { if kern.IsNumOrFract(leftValue) && kern.IsNumOrFract(rightValue) { if kern.IsFloat(leftValue) || kern.IsFloat(rightValue) { d := kern.NumAsFloat(rightValue) if d == 0.0 { err = opTerm.errDivisionByZero() } else { v = kern.NumAsFloat(leftValue) / d } } else if kern.IsFraction(leftValue) || kern.IsFraction(rightValue) { v, err = kern.DivAnyFract(leftValue, rightValue) } else { leftInt, _ := leftValue.(int64) if rightInt, _ := rightValue.(int64); rightInt == 0 { err = opTerm.errDivisionByZero() } else { v = leftInt / rightInt } } } else if kern.IsString(leftValue) && kern.IsString(rightValue) { source := leftValue.(string) sep := rightValue.(string) v = kern.ListFromStrings(strings.Split(source, sep)) } else if kern.IsString(leftValue) && kern.IsInteger(rightValue) { source := leftValue.(string) partSize := int(rightValue.(int64)) if partSize == 0 { err = opTerm.errDivisionByZero() } else { partCount := len(source) / partSize remainder := len(source) % partSize listSize := partCount if remainder > 0 { listSize++ } parts := make([]any, 0, listSize) for i := 0; i < partCount; i++ { parts = append(parts, source[i*partSize:(i+1)*partSize]) } if remainder > 0 { parts = append(parts, source[len(source)-remainder:]) } v = kern.NewList(parts) } } else { err = opTerm.errIncompatibleTypes(leftValue, rightValue) } return } func evalDivide(ctx kern.ExprContext, opTerm *term) (v any, err error) { var leftValue, rightValue any if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil { return } return divValues(opTerm, leftValue, rightValue) } //-------- 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 kern.ExprContext, floatDivTerm *term) (v any, err error) { var leftValue, rightValue any if leftValue, rightValue, err = floatDivTerm.evalInfix(ctx); err != nil { return } if kern.IsNumOrFract(leftValue) && kern.IsNumOrFract(rightValue) { d := kern.NumAsFloat(rightValue) if d == 0.0 { err = floatDivTerm.errDivisionByZero() } else { v = kern.NumAsFloat(leftValue) / d } } else { err = floatDivTerm.errIncompatibleTypes(leftValue, rightValue) } return } //-------- reminder term func newRemainderTerm(tk *Token) (inst *term) { return &term{ tk: *tk, children: make([]*term, 0, 2), position: posInfix, priority: priProduct, evalFunc: evalRemainder, } } func remainderValues(opTerm *term, leftValue, rightValue any) (v any, err error) { if kern.IsInteger(leftValue) && kern.IsInteger(rightValue) { rightInt, _ := rightValue.(int64) if rightInt == 0 { err = opTerm.errDivisionByZero() } else { leftInt, _ := leftValue.(int64) v = leftInt % rightInt } } else { err = opTerm.errIncompatibleTypes(leftValue, rightValue) } return } func evalRemainder(ctx kern.ExprContext, remainderTerm *term) (v any, err error) { var leftValue, rightValue any if leftValue, rightValue, err = remainderTerm.evalInfix(ctx); err != nil { return } return remainderValues(remainderTerm, leftValue, rightValue) } // init func init() { registerTermConstructor(SymStar, newMultiplyTerm) registerTermConstructor(SymSlash, newDivideTerm) registerTermConstructor(SymDotSlash, newDivideAsFloatTerm) registerTermConstructor(SymPercent, newRemainderTerm) }