# frozen_string_literal: true module Rpl module Lang module Core module_function # addition def add( stack, dictionary ) addable = %i[numeric string name] stack, args = Rpl::Lang::Core.stack_extract( stack, [addable, addable] ) result = { type: case args[1][:type] when :name :name when :string :string when :numeric if args[0][:type] == :numeric :numeric else :string end end } args.each do |elt| elt[:value] = elt[:value][1..-2] unless elt[:type] == :numeric end result[:value] = case result[:type] when :name "'#{args[1][:value]}#{args[0][:value]}'" when :string "\"#{args[1][:value]}#{args[0][:value]}\"" when :numeric args[1][:value] + args[0][:value] end result[:base] = 10 if result[:type] == :numeric # TODO: what if operands have other bases ? stack << result [stack, dictionary] end # substraction def subtract( stack, dictionary ) stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric], %i[numeric]] ) stack << { type: :numeric, base: 10, value: args[1][:value] - args[0][:value] } [stack, dictionary] end # multiplication def multiply( stack, dictionary ) stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric], %i[numeric]] ) stack << { type: :numeric, base: 10, value: args[1][:value] * args[0][:value] } [stack, dictionary] end # division def divide( stack, dictionary ) stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric], %i[numeric]] ) stack << { type: :numeric, base: 10, value: args[1][:value] / args[0][:value] } [stack, dictionary] end # power def power( stack, dictionary ) stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric], %i[numeric]] ) stack << { type: :numeric, base: 10, value: args[1][:value]**args[0][:value] } [stack, dictionary] end # rpn_square root def sqrt( stack, dictionary ) stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric]] ) stack << { type: :numeric, base: 10, value: BigMath.sqrt( BigDecimal( args[0][:value] ), Rpl::Lang::Core.precision ) } [stack, dictionary] end # rpn_square def sq( stack, dictionary ) stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric]] ) stack << { type: :numeric, base: 10, value: args[0][:value] * args[0][:value] } [stack, dictionary] end # absolute value def abs( stack, dictionary ) stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric]] ) stack << { type: :numeric, base: 10, value: args[0][:value].abs } [stack, dictionary] end # arbitrary base representation def base( stack, dictionary ) stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric], %i[numeric]] ) args[1][:base] = args[0][:value] stack << args[1] [stack, dictionary] end # 1 if number at stack level 1 is > 0, 0 if == 0, -1 if <= 0 def sign( stack, dictionary ) stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric]] ) value = if args[0][:value].positive? 1 elsif args[0][:value].negative? -1 else 0 end stack << { type: :numeric, base: 10, value: value } [stack, dictionary] end # OPERATIONS ON REALS # percent def percent( stack, dictionary ) stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric], %i[numeric]] ) stack << { type: :numeric, base: 10, value: args[0][:value] * ( args[1][:value] / 100.0 ) } [stack, dictionary] end # inverse percent def inverse_percent( stack, dictionary ) stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric], %i[numeric]] ) stack << { type: :numeric, base: 10, value: 100.0 * ( args[0][:value] / args[1][:value] ) } [stack, dictionary] end # modulo def mod( stack, dictionary ) stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric], %i[numeric]] ) stack << { type: :numeric, base: 10, value: args[1][:value] % args[0][:value] } [stack, dictionary] end # n! for integer n or Gamma(x+1) for fractional x def fact( stack, dictionary ) stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric]] ) stack << { type: :numeric, base: 10, value: Math.gamma( args[0][:value] ) } [stack, dictionary] end # largest number <= def floor( stack, dictionary ) stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric]] ) stack << { type: :numeric, base: 10, value: args[0][:value].floor } [stack, dictionary] end # smallest number >= def ceil( stack, dictionary ) stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric]] ) stack << { type: :numeric, base: 10, value: args[0][:value].ceil } [stack, dictionary] end # min of 2 real numbers def min( stack, dictionary ) stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric], %i[numeric]] ) stack << ( args[0][:value] < args[1][:value] ? args[0] : args[1] ) [stack, dictionary] end # max of 2 real numbers def max( stack, dictionary ) stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric], %i[numeric]] ) stack << ( args[0][:value] > args[1][:value] ? args[0] : args[1] ) [stack, dictionary] end # implemented in Rpl # negation def negate( stack, dictionary ) stack << { value: '« -1 * »', type: :program } Rpl::Lang::Core.eval( stack, dictionary ) end # inverse def inverse( stack, dictionary ) stack << { value: '« 1.0 swap / »', type: :program } Rpl::Lang::Core.eval( stack, dictionary ) end # decimal representation def dec( stack, dictionary ) stack << { value: '« 10 base »', type: :program } Rpl::Lang::Core.eval( stack, dictionary ) end # hexadecimal representation def hex( stack, dictionary ) stack << { value: '« 16 base »', type: :program } Rpl::Lang::Core.eval( stack, dictionary ) end # binary representation def bin( stack, dictionary ) stack << { value: '« 2 base »', type: :program } Rpl::Lang::Core.eval( stack, dictionary ) end end end end