rpl.rb/lib/core/operations.rb

259 lines
7 KiB
Ruby
Raw Normal View History

2021-12-07 16:09:17 +01:00
# frozen_string_literal: true
module Rpl
2021-12-07 15:50:58 +01:00
module Lang
module Core
module_function
# addition
2022-02-10 14:33:09 +01:00
def add
2021-12-16 16:34:59 +01:00
addable = %i[numeric string name list]
2022-02-10 14:33:09 +01:00
args = stack_extract( [addable, addable] )
2021-12-16 16:34:59 +01:00
# | + | 1 numeric | 1 string | 1 name | 1 list |
# |-----------+-----------+----------+--------+--------|
# | 0 numeric | numeric | string | name | list |
# | 0 string | string | string | string | list |
# | 0 name | string | string | name | list |
# | 0 list | list | list | list | list |
2021-12-07 15:50:58 +01:00
2021-12-16 16:34:59 +01:00
result = { type: case args[0][:type]
2021-12-07 15:50:58 +01:00
when :numeric
2021-12-16 16:34:59 +01:00
args[1][:type]
when :string
case args[1][:type]
when :list
:list
2021-12-07 15:50:58 +01:00
else
:string
end
2021-12-16 16:34:59 +01:00
when :name
case args[1][:type]
when :name
:name
when :list
:list
2021-12-07 15:50:58 +01:00
else
:string
end
2021-12-16 16:34:59 +01:00
when :list
:list
else
2021-12-16 16:34:59 +01:00
args[0][:type]
2021-12-07 15:50:58 +01:00
end }
2021-12-16 16:34:59 +01:00
if result[:type] == :list
args.each do |elt|
next unless elt[:type] != :list
elt_copy = Marshal.load(Marshal.dump( elt ))
elt[:type] = :list
elt[:value] = [elt_copy]
end
2021-12-07 15:50:58 +01:00
end
value_to_string = lambda do |e|
if e[:type] == :numeric
2022-02-10 14:33:09 +01:00
stringify( e )
else
e[:value].to_s
end
end
result[:value] = if %i[name string].include?( result[:type] )
"#{value_to_string.call( args[1] )}#{value_to_string.call( args[0] )}"
else
2021-12-07 15:50:58 +01:00
args[1][:value] + args[0][:value]
end
result[:base] = args[0][:base] if result[:type] == :numeric
2022-02-10 14:33:09 +01:00
@stack << result
2021-12-07 15:50:58 +01:00
end
2021-12-07 15:50:58 +01:00
# substraction
2022-02-10 14:33:09 +01:00
def subtract
args = stack_extract( [%i[numeric], %i[numeric]] )
2022-02-10 14:33:09 +01:00
@stack << { type: :numeric, base: infer_resulting_base( args ),
value: args[1][:value] - args[0][:value] }
[stack, dictionary]
2021-12-07 15:50:58 +01:00
end
2021-12-07 15:50:58 +01:00
# multiplication
2022-02-10 14:33:09 +01:00
def multiply
args = stack_extract( [%i[numeric], %i[numeric]] )
2022-02-10 14:33:09 +01:00
@stack << { type: :numeric, base: infer_resulting_base( args ),
value: args[1][:value] * args[0][:value] }
[stack, dictionary]
2021-12-07 15:50:58 +01:00
end
2021-12-07 15:50:58 +01:00
# division
2022-02-10 14:33:09 +01:00
def divide
args = stack_extract( [%i[numeric], %i[numeric]] )
2022-02-10 14:33:09 +01:00
@stack << { type: :numeric, base: infer_resulting_base( args ),
value: args[1][:value] / args[0][:value] }
2021-12-07 15:50:58 +01:00
end
2021-12-07 15:50:58 +01:00
# power
2022-02-10 14:33:09 +01:00
def power
args = stack_extract( [%i[numeric], %i[numeric]] )
2022-02-10 14:33:09 +01:00
@stack << { type: :numeric, base: infer_resulting_base( args ),
value: args[1][:value]**args[0][:value] }
2021-12-07 15:50:58 +01:00
end
2021-11-18 15:58:59 +01:00
2021-12-07 15:50:58 +01:00
# rpn_square root
2022-02-10 14:33:09 +01:00
def sqrt
args = stack_extract( [%i[numeric]] )
2021-11-18 15:58:59 +01:00
2022-02-10 14:33:09 +01:00
@stack << { type: :numeric, base: infer_resulting_base( args ),
value: BigMath.sqrt( BigDecimal( args[0][:value], precision ), precision ) }
2021-12-07 15:50:58 +01:00
end
2021-11-18 15:58:59 +01:00
2021-12-07 15:50:58 +01:00
# rpn_square
2022-02-10 14:33:09 +01:00
def sq
args = stack_extract( [%i[numeric]] )
2021-11-18 15:58:59 +01:00
2022-02-10 14:33:09 +01:00
@stack << { type: :numeric, base: infer_resulting_base( args ),
value: args[0][:value] * args[0][:value] }
2021-12-07 15:50:58 +01:00
end
2021-11-18 15:58:59 +01:00
2021-12-07 15:50:58 +01:00
# absolute value
2022-02-10 14:33:09 +01:00
def abs
args = stack_extract( [%i[numeric]] )
2022-02-10 14:33:09 +01:00
@stack << { type: :numeric, base: infer_resulting_base( args ),
value: args[0][:value].abs }
2021-12-07 15:50:58 +01:00
end
2021-12-07 15:50:58 +01:00
# arbitrary base representation
2022-02-10 14:33:09 +01:00
def base
args = stack_extract( [%i[numeric], %i[numeric]] )
2021-12-07 15:50:58 +01:00
args[1][:base] = args[0][:value]
2022-02-10 14:33:09 +01:00
@stack << args[1]
2021-12-07 15:50:58 +01:00
end
2021-12-07 15:50:58 +01:00
# 1 if number at stack level 1 is > 0, 0 if == 0, -1 if <= 0
2022-02-10 14:33:09 +01:00
def sign
args = stack_extract( [%i[numeric]] )
2021-12-07 15:50:58 +01:00
value = if args[0][:value].positive?
1
elsif args[0][:value].negative?
-1
else
0
end
2022-02-10 14:33:09 +01:00
@stack << { type: :numeric, base: infer_resulting_base( args ),
value: value }
2021-12-07 15:50:58 +01:00
end
# OPERATIONS ON REALS
# percent
2022-02-10 14:33:09 +01:00
def percent
args = stack_extract( [%i[numeric], %i[numeric]] )
2022-02-10 14:33:09 +01:00
@stack << { type: :numeric,
base: infer_resulting_base( args ),
value: args[0][:value] * ( args[1][:value] / 100.0 ) }
end
# inverse percent
2022-02-10 14:33:09 +01:00
def inverse_percent
args = stack_extract( [%i[numeric], %i[numeric]] )
2022-02-10 14:33:09 +01:00
@stack << { type: :numeric,
base: infer_resulting_base( args ),
value: 100.0 * ( args[0][:value] / args[1][:value] ) }
end
# modulo
2022-02-10 14:33:09 +01:00
def mod
args = stack_extract( [%i[numeric], %i[numeric]] )
2022-02-10 14:33:09 +01:00
@stack << { type: :numeric,
base: infer_resulting_base( args ),
value: args[1][:value] % args[0][:value] }
end
# n! for integer n or Gamma(x+1) for fractional x
2022-02-10 14:33:09 +01:00
def fact
args = stack_extract( [%i[numeric]] )
2022-02-10 14:33:09 +01:00
@stack << { type: :numeric,
base: infer_resulting_base( args ),
value: Math.gamma( args[0][:value] ) }
end
# largest number <=
2022-02-10 14:33:09 +01:00
def floor
args = stack_extract( [%i[numeric]] )
2022-02-10 14:33:09 +01:00
@stack << { type: :numeric,
base: infer_resulting_base( args ),
value: args[0][:value].floor }
end
# smallest number >=
2022-02-10 14:33:09 +01:00
def ceil
args = stack_extract( [%i[numeric]] )
2022-02-10 14:33:09 +01:00
@stack << { type: :numeric,
base: infer_resulting_base( args ),
value: args[0][:value].ceil }
end
# min of 2 real numbers
2022-02-10 14:33:09 +01:00
def min
args = stack_extract( [%i[numeric], %i[numeric]] )
2022-02-10 14:33:09 +01:00
@stack << ( args[0][:value] < args[1][:value] ? args[0] : args[1] )
end
# max of 2 real numbers
2022-02-10 14:33:09 +01:00
def max
args = stack_extract( [%i[numeric], %i[numeric]] )
2022-02-10 14:33:09 +01:00
@stack << ( args[0][:value] > args[1][:value] ? args[0] : args[1] )
end
2021-12-08 13:46:06 +01:00
# implemented in Rpl
# negation
2022-02-10 14:33:09 +01:00
def negate
run( '-1 *' )
2021-12-08 13:46:06 +01:00
end
# inverse
2022-02-10 14:33:09 +01:00
def inverse
run( '1.0 swap /' )
2021-12-08 13:46:06 +01:00
end
# decimal representation
2022-02-10 14:33:09 +01:00
def dec
run( '10 base' )
2021-12-08 13:46:06 +01:00
end
# hexadecimal representation
2022-02-10 14:33:09 +01:00
def hex
run( '16 base' )
2021-12-08 13:46:06 +01:00
end
# binary representation
2022-02-10 14:33:09 +01:00
def bin
run( '2 base' )
2021-12-08 13:46:06 +01:00
end
end
end
end