Module: RubyLLM::Toolbox::SafeMath
- Defined in:
- lib/ruby_llm/toolbox/safe_math.rb
Overview
A safe arithmetic evaluator. Parses and evaluates a math expression with a hand-written recursive-descent parser — it never calls eval, so a malicious expression can’t execute Ruby. Supports + - * / % **, unary minus, parentheses, a small set of functions, and the constants pi and e.
Defined Under Namespace
Constant Summary collapse
- FUNCTIONS =
{ "sqrt" => ->(x) { Math.sqrt(x) }, "abs" => ->(x) { x.abs }, "sin" => ->(x) { Math.sin(x) }, "cos" => ->(x) { Math.cos(x) }, "tan" => ->(x) { Math.tan(x) }, "ln" => ->(x) { Math.log(x) }, "log10" => ->(x) { Math.log10(x) }, "exp" => ->(x) { Math.exp(x) }, "floor" => ->(x) { x.floor }, "ceil" => ->(x) { x.ceil }, "round" => ->(x) { x.round } }.freeze
- CONSTANTS =
{ "pi" => Math::PI, "e" => Math::E }.freeze
Class Method Summary collapse
Class Method Details
.evaluate(expression) ⇒ Object
30 31 32 33 34 35 36 37 |
# File 'lib/ruby_llm/toolbox/safe_math.rb', line 30 def evaluate(expression) tokens = tokenize(expression.to_s) parser = Parser.new(tokens) value = parser.expression raise Error, "unexpected token: #{parser.current.inspect}" unless parser.done? value end |
.tokenize(str) ⇒ Object
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/ruby_llm/toolbox/safe_math.rb', line 39 def tokenize(str) tokens = [] scanner = str.dup until scanner.empty? case scanner when /\A\s+/ then scanner = scanner[Regexp.last_match(0).length..] when /\A(\d+\.\d+|\.\d+|\d+)([eE][+-]?\d+)?/ tokens << [:num, Regexp.last_match(0).to_f] scanner = scanner[Regexp.last_match(0).length..] when /\A[A-Za-z_]\w*/ tokens << [:ident, Regexp.last_match(0)] scanner = scanner[Regexp.last_match(0).length..] when /\A\*\*/ then tokens << [:op, "**"]; scanner = scanner[2..] when %r{\A[-+*/%(),]} then tokens << [:op, Regexp.last_match(0)]; scanner = scanner[1..] else raise Error, "unexpected character: #{scanner[0].inspect}" end end tokens end |