github.com/richardwilkes/toolbox@v1.121.0/eval/operator.go (about)

     1  // Copyright (c) 2016-2024 by Richard A. Wilkes. All rights reserved.
     2  //
     3  // This Source Code Form is subject to the terms of the Mozilla Public
     4  // License, version 2.0. If a copy of the MPL was not distributed with
     5  // this file, You can obtain one at http://mozilla.org/MPL/2.0/.
     6  //
     7  // This Source Code Form is "Incompatible With Secondary Licenses", as
     8  // defined by the Mozilla Public License, version 2.0.
     9  
    10  package eval
    11  
    12  import (
    13  	"unicode"
    14  	"unicode/utf8"
    15  )
    16  
    17  // OpFunc provides a signature for an Operator's Evaluate function.
    18  type OpFunc func(left, right any) (any, error)
    19  
    20  // UnaryOpFunc provides a signature for an Operator's EvaluateUnary function.
    21  type UnaryOpFunc func(arg any) (any, error)
    22  
    23  // Operator provides an operator implementation for the Evaluator.
    24  type Operator struct {
    25  	Evaluate      OpFunc
    26  	EvaluateUnary UnaryOpFunc
    27  	Symbol        string
    28  	Precedence    int
    29  }
    30  
    31  func (o *Operator) match(expression string, start, maximum int) bool {
    32  	if maximum-start < len(o.Symbol) {
    33  		return false
    34  	}
    35  	matches := o.Symbol == expression[start:start+len(o.Symbol)]
    36  	// Hack to allow negative exponents on floating point numbers (i.e. 1.2e-2)
    37  	if matches && len(o.Symbol) == 1 && o.Symbol == "-" && start > 1 && expression[start-1:start] == "e" {
    38  		ch, _ := utf8.DecodeRuneInString(expression[start-2 : start-1])
    39  		if unicode.IsDigit(ch) {
    40  			return false
    41  		}
    42  	}
    43  	return matches
    44  }
    45  
    46  // OpenParen (
    47  func OpenParen() *Operator {
    48  	return &Operator{Symbol: "("}
    49  }
    50  
    51  // CloseParen )
    52  func CloseParen() *Operator {
    53  	return &Operator{Symbol: ")"}
    54  }
    55  
    56  // Not !
    57  func Not(f UnaryOpFunc) *Operator {
    58  	return &Operator{
    59  		Symbol:        "!",
    60  		EvaluateUnary: f,
    61  	}
    62  }
    63  
    64  // LogicalOr ||
    65  func LogicalOr(f OpFunc) *Operator {
    66  	return &Operator{
    67  		Symbol:     "||",
    68  		Precedence: 10,
    69  		Evaluate:   f,
    70  	}
    71  }
    72  
    73  // LogicalAnd &&
    74  func LogicalAnd(f OpFunc) *Operator {
    75  	return &Operator{
    76  		Symbol:     "&&",
    77  		Precedence: 20,
    78  		Evaluate:   f,
    79  	}
    80  }
    81  
    82  // Equal ==
    83  func Equal(f OpFunc) *Operator {
    84  	return &Operator{
    85  		Symbol:     "==",
    86  		Precedence: 30,
    87  		Evaluate:   f,
    88  	}
    89  }
    90  
    91  // NotEqual !=
    92  func NotEqual(f OpFunc) *Operator {
    93  	return &Operator{
    94  		Symbol:     "!=",
    95  		Precedence: 30,
    96  		Evaluate:   f,
    97  	}
    98  }
    99  
   100  // GreaterThan >
   101  func GreaterThan(f OpFunc) *Operator {
   102  	return &Operator{
   103  		Symbol:     ">",
   104  		Precedence: 40,
   105  		Evaluate:   f,
   106  	}
   107  }
   108  
   109  // GreaterThanOrEqual >=
   110  func GreaterThanOrEqual(f OpFunc) *Operator {
   111  	return &Operator{
   112  		Symbol:     ">=",
   113  		Precedence: 40,
   114  		Evaluate:   f,
   115  	}
   116  }
   117  
   118  // LessThan <
   119  func LessThan(f OpFunc) *Operator {
   120  	return &Operator{
   121  		Symbol:     "<",
   122  		Precedence: 40,
   123  		Evaluate:   f,
   124  	}
   125  }
   126  
   127  // LessThanOrEqual <=
   128  func LessThanOrEqual(f OpFunc) *Operator {
   129  	return &Operator{
   130  		Symbol:     "<=",
   131  		Precedence: 40,
   132  		Evaluate:   f,
   133  	}
   134  }
   135  
   136  // Add +
   137  func Add(f OpFunc, unary UnaryOpFunc) *Operator {
   138  	return &Operator{
   139  		Symbol:        "+",
   140  		Precedence:    50,
   141  		Evaluate:      f,
   142  		EvaluateUnary: unary,
   143  	}
   144  }
   145  
   146  // Subtract -
   147  func Subtract(f OpFunc, unary UnaryOpFunc) *Operator {
   148  	return &Operator{
   149  		Symbol:        "-",
   150  		Precedence:    50,
   151  		Evaluate:      f,
   152  		EvaluateUnary: unary,
   153  	}
   154  }
   155  
   156  // Multiply *
   157  func Multiply(f OpFunc) *Operator {
   158  	return &Operator{
   159  		Symbol:     "*",
   160  		Precedence: 60,
   161  		Evaluate:   f,
   162  	}
   163  }
   164  
   165  // Divide /
   166  func Divide(f OpFunc) *Operator {
   167  	return &Operator{
   168  		Symbol:     "/",
   169  		Precedence: 60,
   170  		Evaluate:   f,
   171  	}
   172  }
   173  
   174  // Modulo %
   175  func Modulo(f OpFunc) *Operator {
   176  	return &Operator{
   177  		Symbol:     "%",
   178  		Precedence: 60,
   179  		Evaluate:   f,
   180  	}
   181  }
   182  
   183  // Power ^
   184  func Power(f OpFunc) *Operator {
   185  	return &Operator{
   186  		Symbol:     "^",
   187  		Precedence: 70,
   188  		Evaluate:   f,
   189  	}
   190  }