refactoring: split interpreter
This commit is contained in:
parent
3ebec3e4b0
commit
b8724a4a1c
31 changed files with 1716 additions and 1733 deletions
757
interpreter.rb
757
interpreter.rb
|
@ -1,757 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'bigdecimal/math'
|
||||
|
||||
require_relative './lib/dictionary'
|
||||
|
||||
require_relative './lib/core/branch'
|
||||
require_relative './lib/core/general'
|
||||
require_relative './lib/core/mode'
|
||||
require_relative './lib/core/operations'
|
||||
require_relative './lib/core/program'
|
||||
require_relative './lib/core/stack'
|
||||
require_relative './lib/core/store'
|
||||
require_relative './lib/core/string'
|
||||
require_relative './lib/core/test'
|
||||
require_relative './lib/core/time-date'
|
||||
require_relative './lib/core/trig'
|
||||
require_relative './lib/core/logs'
|
||||
require_relative './lib/core/filesystem'
|
||||
require_relative './lib/core/list'
|
||||
|
||||
module Rpl
|
||||
class Interpreter
|
||||
include BigMath
|
||||
|
||||
include Rpl::Lang::Core
|
||||
|
||||
attr_reader :stack,
|
||||
:dictionary,
|
||||
:version
|
||||
|
||||
attr_accessor :precision
|
||||
|
||||
def initialize( stack = [], dictionary = Rpl::Lang::Dictionary.new )
|
||||
@version = 0.1
|
||||
|
||||
@precision = default_precision
|
||||
|
||||
@dictionary = dictionary
|
||||
@stack = stack
|
||||
|
||||
populate_dictionary if @dictionary.words.empty?
|
||||
end
|
||||
|
||||
def default_precision
|
||||
12
|
||||
end
|
||||
|
||||
def parse( input )
|
||||
is_numeric = lambda do |elt|
|
||||
begin
|
||||
!Float(elt).nil?
|
||||
rescue ArgumentError
|
||||
begin
|
||||
!Integer(elt).nil?
|
||||
rescue ArgumentError
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
splitted_input = input.split(' ')
|
||||
|
||||
# 2-passes:
|
||||
# 1. regroup strings and programs
|
||||
opened_programs = 0
|
||||
closed_programs = 0
|
||||
string_delimiters = 0
|
||||
name_delimiters = 0
|
||||
regrouping = false
|
||||
|
||||
regrouped_input = []
|
||||
splitted_input.each do |elt|
|
||||
if elt[0] == '«'
|
||||
opened_programs += 1
|
||||
elt.gsub!( '«', '« ') if elt.length > 1 && elt[1] != ' '
|
||||
end
|
||||
string_delimiters += 1 if elt[0] == '"' && elt.length > 1
|
||||
name_delimiters += 1 if elt[0] == "'" && elt.length > 1
|
||||
|
||||
elt = "#{regrouped_input.pop} #{elt}".strip if regrouping
|
||||
|
||||
regrouped_input << elt
|
||||
|
||||
if elt[-1] == '»'
|
||||
closed_programs += 1
|
||||
elt.gsub!( '»', ' »') if elt.length > 1 && elt[-2] != ' '
|
||||
end
|
||||
string_delimiters += 1 if elt[-1] == '"'
|
||||
name_delimiters += 1 if elt[-1] == "'"
|
||||
|
||||
regrouping = string_delimiters.odd? || name_delimiters.odd? || (opened_programs > closed_programs )
|
||||
end
|
||||
|
||||
# 2. parse
|
||||
# TODO: parse ∞, <NaN> as numerics
|
||||
parsed_tree = []
|
||||
regrouped_input.each do |elt|
|
||||
parsed_entry = { value: elt }
|
||||
|
||||
parsed_entry[:type] = case elt[0]
|
||||
when '«'
|
||||
:program
|
||||
when '"'
|
||||
:string
|
||||
when "'"
|
||||
:name # TODO: check for forbidden space
|
||||
else
|
||||
if is_numeric.call( elt )
|
||||
:numeric
|
||||
else
|
||||
:word
|
||||
end
|
||||
end
|
||||
|
||||
if %I[string name].include?( parsed_entry[:type] )
|
||||
parsed_entry[:value] = parsed_entry[:value][1..-2]
|
||||
elsif parsed_entry[:type] == :program
|
||||
parsed_entry[:value] = parsed_entry[:value][2..-3]
|
||||
elsif parsed_entry[:type] == :numeric
|
||||
parsed_entry[:base] = 10 # TODO: parse others possible bases 0x...
|
||||
|
||||
begin
|
||||
parsed_entry[:value] = Float( parsed_entry[:value] )
|
||||
parsed_entry[:value] = parsed_entry[:value].to_i if (parsed_entry[:value] % 1).zero? && elt.index('.').nil?
|
||||
rescue ArgumentError
|
||||
parsed_entry[:value] = Integer( parsed_entry[:value] )
|
||||
end
|
||||
|
||||
parsed_entry[:value] = BigDecimal( parsed_entry[:value], @precision )
|
||||
end
|
||||
|
||||
parsed_tree << parsed_entry
|
||||
end
|
||||
|
||||
parsed_tree
|
||||
end
|
||||
|
||||
def run( input )
|
||||
@dictionary.add_local_vars_layer
|
||||
|
||||
parse( input.to_s ).each do |elt|
|
||||
case elt[:type]
|
||||
when :word
|
||||
break if %w[break quit exit].include?( elt[:value] )
|
||||
|
||||
command = @dictionary.lookup( elt[:value] )
|
||||
|
||||
if command.nil?
|
||||
# if there isn't a command by that name then it's a name
|
||||
elt[:type] = :name
|
||||
|
||||
@stack << elt
|
||||
elsif command.is_a?( Proc )
|
||||
command.call
|
||||
else
|
||||
run( command[:value] )
|
||||
end
|
||||
else
|
||||
@stack << elt
|
||||
end
|
||||
end
|
||||
|
||||
@dictionary.remove_local_vars_layer
|
||||
|
||||
# superfluous but feels nice
|
||||
@stack
|
||||
end
|
||||
|
||||
def stack_extract( needs )
|
||||
raise ArgumentError, 'Not enough elements' if @stack.size < needs.size
|
||||
|
||||
args = []
|
||||
needs.each do |need|
|
||||
raise ArgumentError, "Type Error, needed #{need} got #{elt[:type]}" unless need == :any || need.include?( @stack.last[:type] )
|
||||
|
||||
args << @stack.pop
|
||||
end
|
||||
|
||||
args
|
||||
end
|
||||
|
||||
def stringify( elt )
|
||||
case elt[:type]
|
||||
when :numeric
|
||||
prefix = case elt[:base]
|
||||
when 2
|
||||
'0b'
|
||||
when 8
|
||||
'0o'
|
||||
when 10
|
||||
''
|
||||
when 16
|
||||
'0x'
|
||||
else
|
||||
"0#{elt[:base]}_"
|
||||
end
|
||||
|
||||
if elt[:value].infinite?
|
||||
suffix = elt[:value].infinite?.positive? ? '∞' : '-∞'
|
||||
elsif elt[:value].nan?
|
||||
suffix = '<NaN>'
|
||||
else
|
||||
suffix = if elt[:value].to_i == elt[:value]
|
||||
elt[:value].to_i
|
||||
else
|
||||
elt[:value].to_s('F')
|
||||
end
|
||||
suffix = elt[:value].to_s( elt[:base] ) unless elt[:base] == 10
|
||||
end
|
||||
|
||||
"#{prefix}#{suffix}"
|
||||
when :list
|
||||
"[#{elt[:value].map { |e| stringify( e ) }.join(', ')}]"
|
||||
when :program
|
||||
"« #{elt[:value]} »"
|
||||
when :string
|
||||
"\"#{elt[:value]}\""
|
||||
when :name
|
||||
"'#{elt[:value]}'"
|
||||
else
|
||||
elt[:value]
|
||||
end
|
||||
end
|
||||
|
||||
def infer_resulting_base( numerics )
|
||||
10 if numerics.length.zero?
|
||||
|
||||
numerics.last[:base]
|
||||
end
|
||||
|
||||
def populate_dictionary
|
||||
# GENERAL
|
||||
@dictionary.add_word( ['nop'],
|
||||
'General',
|
||||
'( -- ) no operation',
|
||||
proc { nop } )
|
||||
@dictionary.add_word( ['help'],
|
||||
'General',
|
||||
'( w -- s ) pop help string of the given word',
|
||||
proc { help } )
|
||||
@dictionary.add_word( ['quit'],
|
||||
'General',
|
||||
'( -- ) Stop and quit interpreter',
|
||||
proc {} )
|
||||
@dictionary.add_word( ['version'],
|
||||
'General',
|
||||
'( -- n ) Pop the interpreter\'s version number',
|
||||
proc { version } )
|
||||
@dictionary.add_word( ['uname'],
|
||||
'General',
|
||||
'( -- s ) Pop the interpreter\'s complete indentification string',
|
||||
proc { uname } )
|
||||
@dictionary.add_word( ['history'],
|
||||
'REPL',
|
||||
'',
|
||||
proc {} )
|
||||
@dictionary.add_word( ['.s'],
|
||||
'REPL',
|
||||
'DEBUG',
|
||||
proc { pp @stack } )
|
||||
|
||||
# STACK
|
||||
@dictionary.add_word( ['swap'],
|
||||
'Stack',
|
||||
'( a b -- b a ) swap 2 first stack elements',
|
||||
proc { swap } )
|
||||
@dictionary.add_word( ['drop'],
|
||||
'Stack',
|
||||
'( a -- ) drop first stack element',
|
||||
proc { drop } )
|
||||
@dictionary.add_word( ['drop2'],
|
||||
'Stack',
|
||||
'( a b -- ) drop first two stack elements',
|
||||
proc { drop2 } )
|
||||
@dictionary.add_word( ['dropn'],
|
||||
'Stack',
|
||||
'( a b … n -- ) drop first n stack elements',
|
||||
proc { dropn } )
|
||||
@dictionary.add_word( ['del'],
|
||||
'Stack',
|
||||
'( a b … -- ) drop all stack elements',
|
||||
proc { del } )
|
||||
@dictionary.add_word( ['rot'],
|
||||
'Stack',
|
||||
'( a b c -- b c a ) rotate 3 first stack elements',
|
||||
proc { rot } )
|
||||
@dictionary.add_word( ['dup'],
|
||||
'Stack',
|
||||
'( a -- a a ) duplicate first stack element',
|
||||
proc { dup } )
|
||||
@dictionary.add_word( ['dup2'],
|
||||
'Stack',
|
||||
'( a b -- a b a b ) duplicate first two stack elements',
|
||||
proc { dup2 } )
|
||||
@dictionary.add_word( ['dupn'],
|
||||
'Stack',
|
||||
'( a b … n -- a b … a b … ) duplicate first n stack elements',
|
||||
proc { dupn } )
|
||||
@dictionary.add_word( ['pick'],
|
||||
'Stack',
|
||||
'( … b … n -- … b … b ) push a copy of the given stack level onto the stack',
|
||||
proc { pick } )
|
||||
@dictionary.add_word( ['depth'],
|
||||
'Stack',
|
||||
'( … -- … n ) push stack depth onto the stack',
|
||||
proc { depth } )
|
||||
@dictionary.add_word( ['roll'],
|
||||
'Stack',
|
||||
'( … a -- a … ) move a stack element to the top of the stack',
|
||||
proc { roll } )
|
||||
@dictionary.add_word( ['rolld'],
|
||||
'Stack',
|
||||
'( a … -- … a ) move the element on top of the stack to a higher stack position',
|
||||
proc { rolld } )
|
||||
@dictionary.add_word( ['over'],
|
||||
'Stack',
|
||||
'( a b -- a b a ) push a copy of the element in stack level 2 onto the stack',
|
||||
proc { over } )
|
||||
|
||||
# Usual operations on reals and complexes
|
||||
@dictionary.add_word( ['+'],
|
||||
'Usual operations on reals and complexes',
|
||||
'( a b -- c ) addition',
|
||||
proc { add } )
|
||||
@dictionary.add_word( ['-'],
|
||||
'Usual operations on reals and complexes',
|
||||
'( a b -- c ) subtraction',
|
||||
proc { subtract } )
|
||||
@dictionary.add_word( ['chs'],
|
||||
'Usual operations on reals and complexes',
|
||||
'( a -- b ) negate',
|
||||
proc { negate } )
|
||||
@dictionary.add_word( ['×', '*'],
|
||||
'Usual operations on reals and complexes',
|
||||
'( a b -- c ) multiplication',
|
||||
proc { multiply } ) # alias
|
||||
@dictionary.add_word( ['÷', '/'],
|
||||
'Usual operations on reals and complexes',
|
||||
'( a b -- c ) division',
|
||||
proc { divide } ) # alias
|
||||
@dictionary.add_word( ['inv'],
|
||||
'Usual operations on reals and complexes',
|
||||
'( a -- b ) invert numeric',
|
||||
proc { inverse } )
|
||||
@dictionary.add_word( ['^'],
|
||||
'Usual operations on reals and complexes',
|
||||
'( a b -- c ) a to the power of b',
|
||||
proc { power } )
|
||||
@dictionary.add_word( ['√', 'sqrt'],
|
||||
'Usual operations on reals and complexes',
|
||||
'( a -- b ) square root',
|
||||
proc { sqrt } ) # alias
|
||||
@dictionary.add_word( ['²', 'sq'],
|
||||
'Usual operations on reals and complexes',
|
||||
'( a -- b ) square',
|
||||
proc { sq } )
|
||||
@dictionary.add_word( ['abs'],
|
||||
'Usual operations on reals and complexes',
|
||||
'( a -- b ) absolute value',
|
||||
proc { abs } )
|
||||
@dictionary.add_word( ['dec'],
|
||||
'Usual operations on reals and complexes',
|
||||
'( a -- a ) set numeric\'s base to 10',
|
||||
proc { dec } )
|
||||
@dictionary.add_word( ['hex'],
|
||||
'Usual operations on reals and complexes',
|
||||
'( a -- a ) set numeric\'s base to 16',
|
||||
proc { hex } )
|
||||
@dictionary.add_word( ['bin'],
|
||||
'Usual operations on reals and complexes',
|
||||
'( a -- a ) set numeric\'s base to 2',
|
||||
proc { bin } )
|
||||
@dictionary.add_word( ['base'],
|
||||
'Usual operations on reals and complexes',
|
||||
'( a b -- a ) set numeric\'s base to b',
|
||||
proc { base } )
|
||||
@dictionary.add_word( ['sign'],
|
||||
'Usual operations on reals and complexes',
|
||||
'( a -- b ) sign of element',
|
||||
proc { sign } )
|
||||
|
||||
# Operations on reals
|
||||
@dictionary.add_word( ['%'],
|
||||
'Operations on reals',
|
||||
'( a b -- c ) b% of a',
|
||||
proc { percent } )
|
||||
@dictionary.add_word( ['%CH'],
|
||||
'Operations on reals',
|
||||
'( a b -- c ) b is c% of a',
|
||||
proc { inverse_percent } )
|
||||
@dictionary.add_word( ['mod'],
|
||||
'Operations on reals',
|
||||
'( a b -- c ) modulo',
|
||||
proc { mod } )
|
||||
@dictionary.add_word( ['!', 'fact'],
|
||||
'Operations on reals',
|
||||
'( a -- b ) factorial',
|
||||
proc { fact } )
|
||||
@dictionary.add_word( ['floor'],
|
||||
'Operations on reals',
|
||||
'( a -- b ) highest integer under a',
|
||||
proc { floor } )
|
||||
@dictionary.add_word( ['ceil'],
|
||||
'Operations on reals',
|
||||
'( a -- b ) highest integer over a',
|
||||
proc { ceil } )
|
||||
@dictionary.add_word( ['min'],
|
||||
'Operations on reals',
|
||||
'( a b -- a/b ) leave lowest of a or b',
|
||||
proc { min } )
|
||||
@dictionary.add_word( ['max'],
|
||||
'Operations on reals',
|
||||
'( a b -- a/b ) leave highest of a or b',
|
||||
proc { max } )
|
||||
# @dictionary.add_word( ['mant'],
|
||||
# 'Operations on reals',
|
||||
# '',
|
||||
# proc { __todo } ) # mantissa of a real number
|
||||
# @dictionary.add_word( ['xpon'],
|
||||
# 'Operations on reals',
|
||||
# '',
|
||||
# proc { __todo } ) # exponant of a real number
|
||||
# @dictionary.add_word( ['ip'],
|
||||
# 'Operations on reals',
|
||||
# '',
|
||||
# proc { __todo } ) # integer part
|
||||
# @dictionary.add_word( ['fp'],
|
||||
# 'Operations on reals',
|
||||
# '',
|
||||
# proc { __todo } ) # fractional part
|
||||
|
||||
# OPERATIONS ON COMPLEXES
|
||||
# @dictionary.add_word( ['re'],
|
||||
# proc { __todo } ) # complex real part
|
||||
# @dictionary.add_word( 'im',
|
||||
# proc { __todo } ) # complex imaginary part
|
||||
# @dictionary.add_word( ['conj'],
|
||||
# proc { __todo } ) # complex conjugate
|
||||
# @dictionary.add_word( 'arg',
|
||||
# proc { __todo } ) # complex argument in radians
|
||||
# @dictionary.add_word( ['c->r'],
|
||||
# proc { __todo } ) # transform a complex in 2 reals
|
||||
# @dictionary.add_word( 'c→r',
|
||||
# proc { __todo } ) # alias
|
||||
# @dictionary.add_word( ['r->c'],
|
||||
# proc { __todo } ) # transform 2 reals in a complex
|
||||
# @dictionary.add_word( 'r→c',
|
||||
# proc { __todo } ) # alias
|
||||
# @dictionary.add_word( ['p->r'],
|
||||
# proc { __todo } ) # cartesian to polar
|
||||
# @dictionary.add_word( 'p→r',
|
||||
# proc { __todo } ) # alias
|
||||
# @dictionary.add_word( ['r->p'],
|
||||
# proc { __todo } ) # polar to cartesian
|
||||
# @dictionary.add_word( 'r→p',
|
||||
# proc { __todo } ) # alias
|
||||
|
||||
# Mode
|
||||
@dictionary.add_word( ['prec'],
|
||||
'Mode',
|
||||
'( a -- ) set precision to a',
|
||||
proc { prec } )
|
||||
@dictionary.add_word( ['default'],
|
||||
'Mode',
|
||||
'( -- ) set default precision',
|
||||
proc { default } )
|
||||
@dictionary.add_word( ['type'],
|
||||
'Mode',
|
||||
'( a -- s ) type of a as a string',
|
||||
proc { type } )
|
||||
# @dictionary.add_word( ['std'],
|
||||
# proc { __todo } ) # standard floating numbers representation. ex: std
|
||||
# @dictionary.add_word( ['fix'],
|
||||
# proc { __todo } ) # fixed point representation. ex: 6 fix
|
||||
# @dictionary.add_word( ['sci'],
|
||||
# proc { __todo } ) # scientific floating point representation. ex: 20 sci
|
||||
# @dictionary.add_word( ['round'],
|
||||
# proc { __todo } ) # set float rounding mode. ex: ["nearest", "toward zero", "toward +inf", "toward -inf", "away from zero"] round
|
||||
|
||||
# Test
|
||||
@dictionary.add_word( ['>'],
|
||||
'Test',
|
||||
'( a b -- t ) is a greater than b?',
|
||||
proc { greater_than } )
|
||||
@dictionary.add_word( ['≥', '>='],
|
||||
'Test',
|
||||
'( a b -- t ) is a greater than or equal to b?',
|
||||
proc { greater_than_or_equal } ) # alias
|
||||
@dictionary.add_word( ['<'],
|
||||
'Test',
|
||||
'( a b -- t ) is a less than b?',
|
||||
proc { less_than } )
|
||||
@dictionary.add_word( ['≤', '<='],
|
||||
'Test',
|
||||
'( a b -- t ) is a less than or equal to b?',
|
||||
proc { less_than_or_equal } ) # alias
|
||||
@dictionary.add_word( ['≠', '!='],
|
||||
'Test',
|
||||
'( a b -- t ) is a not equal to b',
|
||||
proc { different } ) # alias
|
||||
@dictionary.add_word( ['==', 'same'],
|
||||
'Test',
|
||||
'( a b -- t ) is a equal to b',
|
||||
proc { same } )
|
||||
@dictionary.add_word( ['and'],
|
||||
'Test',
|
||||
'( a b -- t ) boolean and',
|
||||
proc { boolean_and } )
|
||||
@dictionary.add_word( ['or'],
|
||||
'Test',
|
||||
'( a b -- t ) boolean or',
|
||||
proc { boolean_or } )
|
||||
@dictionary.add_word( ['xor'],
|
||||
'Test',
|
||||
'( a b -- t ) boolean xor',
|
||||
proc { xor } )
|
||||
@dictionary.add_word( ['not'],
|
||||
'Test',
|
||||
'( a -- t ) invert boolean value',
|
||||
proc { boolean_not } )
|
||||
@dictionary.add_word( ['true'],
|
||||
'Test',
|
||||
'( -- t ) push true onto stack',
|
||||
proc { boolean_true } ) # specific
|
||||
@dictionary.add_word( ['false'],
|
||||
'Test',
|
||||
'( -- t ) push false onto stack',
|
||||
proc { boolean_false } ) # specific
|
||||
|
||||
# String
|
||||
@dictionary.add_word( ['→str', '->str'],
|
||||
'String',
|
||||
'( a -- s ) convert element to string',
|
||||
proc { to_string } ) # alias
|
||||
@dictionary.add_word( ['str→', 'str->'],
|
||||
'String',
|
||||
'( s -- a ) convert string to element',
|
||||
proc { from_string } )
|
||||
@dictionary.add_word( ['chr'],
|
||||
'String',
|
||||
'( n -- c ) convert ASCII character code in stack level 1 into a string',
|
||||
proc { chr } )
|
||||
@dictionary.add_word( ['num'],
|
||||
'String',
|
||||
'( s -- n ) return ASCII code of the first character of the string in stack level 1 as a real number',
|
||||
proc { num } )
|
||||
@dictionary.add_word( ['size'],
|
||||
'String',
|
||||
'( s -- n ) return the length of the string',
|
||||
proc { size } )
|
||||
@dictionary.add_word( ['pos'],
|
||||
'String',
|
||||
'( s s -- n ) search for the string in level 1 within the string in level 2',
|
||||
proc { pos } )
|
||||
@dictionary.add_word( ['sub'],
|
||||
'String',
|
||||
'( s n n -- s ) return a substring of the string in level 3',
|
||||
proc { sub } )
|
||||
@dictionary.add_word( ['rev'],
|
||||
'String',
|
||||
'( s -- s ) reverse string',
|
||||
proc { rev } ) # specific
|
||||
@dictionary.add_word( ['split'],
|
||||
'String',
|
||||
'( s c -- … ) split string s on character c',
|
||||
proc { split } ) # specific
|
||||
|
||||
# Branch
|
||||
@dictionary.add_word( ['ift'],
|
||||
'Branch',
|
||||
'( t pt -- … ) eval pt or not based on the value of boolean t',
|
||||
proc { ift } )
|
||||
@dictionary.add_word( ['ifte'],
|
||||
'Branch',
|
||||
'( t pt pf -- … ) eval pt or pf based on the value of boolean t',
|
||||
proc { ifte } )
|
||||
@dictionary.add_word( ['times'],
|
||||
'Branch',
|
||||
'( n p -- … ) eval p n times while pushing counter on stack before',
|
||||
proc { times } ) # specific
|
||||
@dictionary.add_word( ['loop'],
|
||||
'Branch',
|
||||
'( n1 n2 p -- … ) eval p looping from n1 to n2 while pushing counter on stack before',
|
||||
proc { loop } ) # specific
|
||||
|
||||
# Store
|
||||
@dictionary.add_word( ['▶', 'sto'],
|
||||
'Store',
|
||||
'( content name -- ) store to variable',
|
||||
proc { sto } )
|
||||
@dictionary.add_word( ['rcl'],
|
||||
'Store',
|
||||
'( name -- … ) push content of variable name onto stack',
|
||||
proc { rcl } )
|
||||
@dictionary.add_word( ['purge'],
|
||||
'Store',
|
||||
'( name -- ) delete variable',
|
||||
proc { purge } )
|
||||
@dictionary.add_word( ['vars'],
|
||||
'Store',
|
||||
'( -- […] ) list variables',
|
||||
proc { vars } )
|
||||
@dictionary.add_word( ['clusr'],
|
||||
'Store',
|
||||
'( -- ) delete all variables',
|
||||
proc { clusr } )
|
||||
@dictionary.add_word( ['sto+'],
|
||||
'Store',
|
||||
'( a n -- ) add content to variable\'s value',
|
||||
proc { sto_add } )
|
||||
@dictionary.add_word( ['sto-'],
|
||||
'Store',
|
||||
'( a n -- ) subtract content to variable\'s value',
|
||||
proc { sto_subtract } )
|
||||
@dictionary.add_word( ['sto×', 'sto*'],
|
||||
'Store',
|
||||
'( a n -- ) multiply content of variable\'s value',
|
||||
proc { sto_multiply } ) # alias
|
||||
@dictionary.add_word( ['sto÷', 'sto/'],
|
||||
'Store',
|
||||
'( a n -- ) divide content of variable\'s value',
|
||||
proc { sto_divide } ) # alias
|
||||
@dictionary.add_word( ['sneg'],
|
||||
'Store',
|
||||
'( a n -- ) negate content of variable\'s value',
|
||||
proc { sto_negate } )
|
||||
@dictionary.add_word( ['sinv'],
|
||||
'Store',
|
||||
'( a n -- ) invert content of variable\'s value',
|
||||
proc { sto_inverse } )
|
||||
@dictionary.add_word( ['↴', 'lsto'],
|
||||
'Program',
|
||||
'( content name -- ) store to local variable',
|
||||
proc { lsto } )
|
||||
|
||||
# Program
|
||||
@dictionary.add_word( ['eval'],
|
||||
'Program',
|
||||
'( a -- … ) interpret',
|
||||
proc { eval } )
|
||||
|
||||
# Trig on reals and complexes
|
||||
@dictionary.add_word( ['𝛑', 'pi'],
|
||||
'Trig on reals and complexes',
|
||||
'( … -- 𝛑 ) push 𝛑',
|
||||
proc { pi } )
|
||||
@dictionary.add_word( ['sin'],
|
||||
'Trig on reals and complexes',
|
||||
'( n -- m ) compute sinus of n',
|
||||
proc { sinus } ) # sinus
|
||||
@dictionary.add_word( ['asin'],
|
||||
'Trig on reals and complexes',
|
||||
'( n -- m ) compute arg-sinus of n',
|
||||
proc { arg_sinus } ) # arg sinus
|
||||
@dictionary.add_word( ['cos'],
|
||||
'Trig on reals and complexes',
|
||||
'( n -- m ) compute cosinus of n',
|
||||
proc { cosinus } ) # cosinus
|
||||
@dictionary.add_word( ['acos'],
|
||||
'Trig on reals and complexes',
|
||||
'( n -- m ) compute arg-cosinus of n',
|
||||
proc { arg_cosinus } ) # arg cosinus
|
||||
@dictionary.add_word( ['tan'],
|
||||
'Trig on reals and complexes',
|
||||
'( n -- m ) compute tangent of n',
|
||||
proc { tangent } ) # tangent
|
||||
@dictionary.add_word( ['atan'],
|
||||
'Trig on reals and complexes',
|
||||
'( n -- m ) compute arc-tangent of n',
|
||||
proc { arg_tangent } ) # arg tangent
|
||||
@dictionary.add_word( ['d→r', 'd->r'],
|
||||
'Trig on reals and complexes',
|
||||
'( n -- m ) convert degree to radian',
|
||||
proc { degrees_to_radians } ) # convert degrees to radians
|
||||
@dictionary.add_word( ['r→d', 'r->d'],
|
||||
'Trig on reals and complexes',
|
||||
'( n -- m ) convert radian to degree',
|
||||
proc { radians_to_degrees } ) # convert radians to degrees
|
||||
|
||||
# Logs on reals and complexes
|
||||
@dictionary.add_word( ['ℇ', 'e'],
|
||||
'Logs on reals and complexes',
|
||||
'( … -- ℇ ) push ℇ',
|
||||
proc { e } ) # alias
|
||||
# @dictionary.add_word( 'ln',
|
||||
# proc { __todo } ) # logarithm base e
|
||||
# @dictionary.add_word( 'lnp1',
|
||||
# proc { __todo } ) # ln(1+x) which is useful when x is close to 0
|
||||
# @dictionary.add_word( 'exp',
|
||||
# proc { __todo } ) # exponential
|
||||
# @dictionary.add_word( 'expm',
|
||||
# proc { __todo } ) # exp(x)-1 which is useful when x is close to 0
|
||||
# @dictionary.add_word( 'log10',
|
||||
# proc { __todo } ) # logarithm base 10
|
||||
# @dictionary.add_word( 'alog10',
|
||||
# proc { __todo } ) # exponential base 10
|
||||
# @dictionary.add_word( 'log2',
|
||||
# proc { __todo } ) # logarithm base 2
|
||||
# @dictionary.add_word( 'alog2',
|
||||
# proc { __todo } ) # exponential base 2
|
||||
# @dictionary.add_word( 'sinh',
|
||||
# proc { __todo } ) # hyperbolic sine
|
||||
# @dictionary.add_word( 'asinh',
|
||||
# proc { __todo } ) # inverse hyperbolic sine
|
||||
# @dictionary.add_word( 'cosh',
|
||||
# proc { __todo } ) # hyperbolic cosine
|
||||
# @dictionary.add_word( 'acosh',
|
||||
# proc { __todo } ) # inverse hyperbolic cosine
|
||||
# @dictionary.add_word( 'tanh',
|
||||
# proc { __todo } ) # hyperbolic tangent
|
||||
# @dictionary.add_word( 'atanh',
|
||||
# proc { __todo } ) # inverse hyperbolic tangent
|
||||
|
||||
# Time and date
|
||||
@dictionary.add_word( ['time'],
|
||||
'Time and date',
|
||||
'( -- t ) push current time',
|
||||
proc { time } )
|
||||
@dictionary.add_word( ['date'],
|
||||
'Time and date',
|
||||
'( -- d ) push current date',
|
||||
proc { date } )
|
||||
@dictionary.add_word( ['ticks'],
|
||||
'Time and date',
|
||||
'( -- t ) push datetime as ticks',
|
||||
proc { ticks } )
|
||||
|
||||
# Rpl.rb specifics
|
||||
# Lists
|
||||
@dictionary.add_word( ['→list', '->list'],
|
||||
'Lists',
|
||||
'( … x -- […] ) pack x stacks levels into a list',
|
||||
proc { to_list } )
|
||||
@dictionary.add_word( ['list→', 'list->'],
|
||||
'Lists',
|
||||
'( […] -- … ) unpack list on stack',
|
||||
proc { unpack_list } )
|
||||
|
||||
# Filesystem
|
||||
@dictionary.add_word( ['fread'],
|
||||
'Filesystem',
|
||||
'( filename -- content ) read file and put content on stack as string',
|
||||
proc { fread } )
|
||||
@dictionary.add_word( ['feval'],
|
||||
'Filesystem',
|
||||
'( filename -- … ) read and run file',
|
||||
proc { feval } )
|
||||
@dictionary.add_word( ['fwrite'],
|
||||
'Filesystem',
|
||||
'( content filename -- ) write content into filename',
|
||||
proc { fwrite } )
|
||||
|
||||
# Graphics
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,44 +1,42 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Rpl
|
||||
module Lang
|
||||
module Core
|
||||
# ( x prg -- … ) run PRG X times putting i(counter) on the stack before each run
|
||||
def times
|
||||
args = stack_extract( [:any, %i[numeric]] )
|
||||
module Lang
|
||||
module Core
|
||||
# ( x prg -- … ) run PRG X times putting i(counter) on the stack before each run
|
||||
def times
|
||||
args = stack_extract( [:any, %i[numeric]] )
|
||||
|
||||
args[1][:value].to_i.times do |i|
|
||||
counter = { value: BigDecimal( i, @precision ), type: :numeric, base: 10 }
|
||||
@stack << counter
|
||||
args[1][:value].to_i.times do |i|
|
||||
counter = { value: BigDecimal( i, @precision ), type: :numeric, base: 10 }
|
||||
@stack << counter
|
||||
|
||||
run( args[0][:value] )
|
||||
end
|
||||
run( args[0][:value] )
|
||||
end
|
||||
end
|
||||
|
||||
# ( x y prg -- … ) run PRG (Y - X) times putting i(counter) on the stack before each run
|
||||
def loop
|
||||
args = stack_extract( [:any, %i[numeric], %i[numeric]] )
|
||||
# ( x y prg -- … ) run PRG (Y - X) times putting i(counter) on the stack before each run
|
||||
def loop
|
||||
args = stack_extract( [:any, %i[numeric], %i[numeric]] )
|
||||
|
||||
((args[2][:value].to_i)..(args[1][:value].to_i)).each do |i|
|
||||
counter = { value: BigDecimal( i, @precision ), type: :numeric, base: 10 }
|
||||
@stack << counter
|
||||
((args[2][:value].to_i)..(args[1][:value].to_i)).each do |i|
|
||||
counter = { value: BigDecimal( i, @precision ), type: :numeric, base: 10 }
|
||||
@stack << counter
|
||||
|
||||
run( args[0][:value] )
|
||||
end
|
||||
run( args[0][:value] )
|
||||
end
|
||||
end
|
||||
|
||||
# similar to if-then-else-end, <test-instruction> <true-instruction> <false-instruction> ifte
|
||||
def ifte
|
||||
args = stack_extract( [:any, :any, %i[boolean]] )
|
||||
# similar to if-then-else-end, <test-instruction> <true-instruction> <false-instruction> ifte
|
||||
def ifte
|
||||
args = stack_extract( [:any, :any, %i[boolean]] )
|
||||
|
||||
run( args[ args[2][:value] ? 1 : 0 ][:value] )
|
||||
end
|
||||
run( args[ args[2][:value] ? 1 : 0 ][:value] )
|
||||
end
|
||||
|
||||
# Implemented in Rpl
|
||||
# similar to if-then-end, <test-instruction> <true-instruction> ift
|
||||
def ift
|
||||
run( '« nop » ifte' )
|
||||
end
|
||||
# Implemented in Rpl
|
||||
# similar to if-then-end, <test-instruction> <true-instruction> ift
|
||||
def ift
|
||||
run( '« nop » ifte' )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,30 +1,30 @@
|
|||
module Rpl
|
||||
module Lang
|
||||
module Core
|
||||
module_function
|
||||
# frozen_string_literal: true
|
||||
|
||||
# ( filename -- content ) read file and put content on stack as string
|
||||
def fread
|
||||
args = stack_extract( [%i[string]] )
|
||||
module Lang
|
||||
module Core
|
||||
module_function
|
||||
|
||||
path = File.absolute_path( args[0][:value] )
|
||||
# ( filename -- content ) read file and put content on stack as string
|
||||
def fread
|
||||
args = stack_extract( [%i[string]] )
|
||||
|
||||
@stack << { type: :string,
|
||||
value: File.read( path ) }
|
||||
end
|
||||
path = File.absolute_path( args[0][:value] )
|
||||
|
||||
# ( filename -- … ) read and run file
|
||||
def feval
|
||||
run 'fread eval'
|
||||
end
|
||||
@stack << { type: :string,
|
||||
value: File.read( path ) }
|
||||
end
|
||||
|
||||
# ( content filename -- ) write content into filename
|
||||
def fwrite
|
||||
args = stack_extract( [%i[string], :any] )
|
||||
# ( filename -- … ) read and run file
|
||||
def feval
|
||||
run 'fread eval'
|
||||
end
|
||||
|
||||
File.write( File.absolute_path( args[0][:value] ),
|
||||
args[1][:value] )
|
||||
end
|
||||
# ( content filename -- ) write content into filename
|
||||
def fwrite
|
||||
args = stack_extract( [%i[string], :any] )
|
||||
|
||||
File.write( File.absolute_path( args[0][:value] ),
|
||||
args[1][:value] )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,31 +1,29 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Rpl
|
||||
module Lang
|
||||
module Core
|
||||
module_function
|
||||
module Lang
|
||||
module Core
|
||||
module_function
|
||||
|
||||
# no operation
|
||||
def nop; end
|
||||
# no operation
|
||||
def nop; end
|
||||
|
||||
# show version
|
||||
def version
|
||||
@stack += parse( @version.to_s )
|
||||
end
|
||||
# show version
|
||||
def version
|
||||
@stack += parse( @version.to_s )
|
||||
end
|
||||
|
||||
# show complete identification string
|
||||
def uname
|
||||
@stack += parse( "\"Rpl Interpreter version #{@version}\"" )
|
||||
end
|
||||
# show complete identification string
|
||||
def uname
|
||||
@stack += parse( "\"Rpl Interpreter version #{@version}\"" )
|
||||
end
|
||||
|
||||
def help
|
||||
args = stack_extract( [%i[name]] )
|
||||
def help
|
||||
args = stack_extract( [%i[name]] )
|
||||
|
||||
word = @dictionary.words[ args[0][:value] ]
|
||||
word = @dictionary.words[ args[0][:value] ]
|
||||
|
||||
@stack << { type: :string,
|
||||
value: "#{args[0][:value]}: #{word.nil? ? 'not a core word' : word[:help]}" }
|
||||
end
|
||||
@stack << { type: :string,
|
||||
value: "#{args[0][:value]}: #{word.nil? ? 'not a core word' : word[:help]}" }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,26 +1,24 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Rpl
|
||||
module Lang
|
||||
module Core
|
||||
module_function
|
||||
module Lang
|
||||
module Core
|
||||
module_function
|
||||
|
||||
# ( … x -- […] ) pack x stacks levels into a list
|
||||
def to_list
|
||||
args = stack_extract( [%i[numeric]] )
|
||||
args = stack_extract( %i[any] * args[0][:value] )
|
||||
# ( … x -- […] ) pack x stacks levels into a list
|
||||
def to_list
|
||||
args = stack_extract( [%i[numeric]] )
|
||||
args = stack_extract( %i[any] * args[0][:value] )
|
||||
|
||||
@stack << { type: :list,
|
||||
value: args.reverse }
|
||||
end
|
||||
@stack << { type: :list,
|
||||
value: args.reverse }
|
||||
end
|
||||
|
||||
# ( […] -- … ) unpack list on stack
|
||||
def unpack_list
|
||||
args = stack_extract( [%i[list]] )
|
||||
# ( […] -- … ) unpack list on stack
|
||||
def unpack_list
|
||||
args = stack_extract( [%i[list]] )
|
||||
|
||||
args[0][:value].each do |elt|
|
||||
@stack << elt
|
||||
end
|
||||
args[0][:value].each do |elt|
|
||||
@stack << elt
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
module Rpl
|
||||
module Lang
|
||||
module Core
|
||||
module_function
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Euler constant
|
||||
def e
|
||||
@stack << { type: :numeric,
|
||||
base: 10,
|
||||
value: BigMath.E( @precision ) }
|
||||
end
|
||||
module Lang
|
||||
module Core
|
||||
module_function
|
||||
|
||||
# Euler constant
|
||||
def e
|
||||
@stack << { type: :numeric,
|
||||
base: 10,
|
||||
value: BigMath.E( @precision ) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,29 +1,27 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Rpl
|
||||
module Lang
|
||||
module Core
|
||||
module_function
|
||||
module Lang
|
||||
module Core
|
||||
module_function
|
||||
|
||||
# set float precision in bits. ex: 256 prec
|
||||
def prec
|
||||
args = stack_extract( [%i[numeric]] )
|
||||
# set float precision in bits. ex: 256 prec
|
||||
def prec
|
||||
args = stack_extract( [%i[numeric]] )
|
||||
|
||||
@precision = args[0][:value]
|
||||
end
|
||||
@precision = args[0][:value]
|
||||
end
|
||||
|
||||
# set float representation and precision to default
|
||||
def default
|
||||
@precision = default_precision
|
||||
end
|
||||
# set float representation and precision to default
|
||||
def default
|
||||
@precision = default_precision
|
||||
end
|
||||
|
||||
# show type of stack first entry
|
||||
def type
|
||||
args = stack_extract( [:any] )
|
||||
# show type of stack first entry
|
||||
def type
|
||||
args = stack_extract( [:any] )
|
||||
|
||||
@stack << { type: :string,
|
||||
value: args[0][:type].to_s }
|
||||
end
|
||||
@stack << { type: :string,
|
||||
value: args[0][:type].to_s }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,258 +1,256 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Rpl
|
||||
module Lang
|
||||
module Core
|
||||
module_function
|
||||
module Lang
|
||||
module Core
|
||||
module_function
|
||||
|
||||
# addition
|
||||
def add
|
||||
addable = %i[numeric string name list]
|
||||
args = stack_extract( [addable, addable] )
|
||||
# | + | 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 |
|
||||
# addition
|
||||
def add
|
||||
addable = %i[numeric string name list]
|
||||
args = stack_extract( [addable, addable] )
|
||||
# | + | 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 |
|
||||
|
||||
result = { type: case args[0][:type]
|
||||
when :numeric
|
||||
args[1][:type]
|
||||
|
||||
when :string
|
||||
case args[1][:type]
|
||||
when :list
|
||||
:list
|
||||
else
|
||||
:string
|
||||
end
|
||||
|
||||
when :name
|
||||
case args[1][:type]
|
||||
when :name
|
||||
:name
|
||||
when :list
|
||||
:list
|
||||
else
|
||||
:string
|
||||
end
|
||||
result = { type: case args[0][:type]
|
||||
when :numeric
|
||||
args[1][:type]
|
||||
|
||||
when :string
|
||||
case args[1][:type]
|
||||
when :list
|
||||
:list
|
||||
|
||||
else
|
||||
args[0][:type]
|
||||
end }
|
||||
|
||||
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
|
||||
end
|
||||
|
||||
value_to_string = lambda do |e|
|
||||
if e[:type] == :numeric
|
||||
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
|
||||
args[1][:value] + args[0][:value]
|
||||
:string
|
||||
end
|
||||
|
||||
result[:base] = args[0][:base] if result[:type] == :numeric
|
||||
when :name
|
||||
case args[1][:type]
|
||||
when :name
|
||||
:name
|
||||
when :list
|
||||
:list
|
||||
else
|
||||
:string
|
||||
end
|
||||
|
||||
@stack << result
|
||||
when :list
|
||||
:list
|
||||
|
||||
else
|
||||
args[0][:type]
|
||||
end }
|
||||
|
||||
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
|
||||
end
|
||||
|
||||
# substraction
|
||||
def subtract
|
||||
args = stack_extract( [%i[numeric], %i[numeric]] )
|
||||
|
||||
@stack << { type: :numeric, base: infer_resulting_base( args ),
|
||||
value: args[1][:value] - args[0][:value] }
|
||||
|
||||
[stack, dictionary]
|
||||
value_to_string = lambda do |e|
|
||||
if e[:type] == :numeric
|
||||
stringify( e )
|
||||
else
|
||||
e[:value].to_s
|
||||
end
|
||||
end
|
||||
|
||||
# multiplication
|
||||
def multiply
|
||||
args = stack_extract( [%i[numeric], %i[numeric]] )
|
||||
result[:value] = if %i[name string].include?( result[:type] )
|
||||
"#{value_to_string.call( args[1] )}#{value_to_string.call( args[0] )}"
|
||||
else
|
||||
args[1][:value] + args[0][:value]
|
||||
end
|
||||
|
||||
@stack << { type: :numeric, base: infer_resulting_base( args ),
|
||||
value: args[1][:value] * args[0][:value] }
|
||||
result[:base] = args[0][:base] if result[:type] == :numeric
|
||||
|
||||
[stack, dictionary]
|
||||
end
|
||||
@stack << result
|
||||
end
|
||||
|
||||
# division
|
||||
def divide
|
||||
args = stack_extract( [%i[numeric], %i[numeric]] )
|
||||
# substraction
|
||||
def subtract
|
||||
args = stack_extract( [%i[numeric], %i[numeric]] )
|
||||
|
||||
@stack << { type: :numeric, base: infer_resulting_base( args ),
|
||||
value: args[1][:value] / args[0][:value] }
|
||||
end
|
||||
@stack << { type: :numeric, base: infer_resulting_base( args ),
|
||||
value: args[1][:value] - args[0][:value] }
|
||||
|
||||
# power
|
||||
def power
|
||||
args = stack_extract( [%i[numeric], %i[numeric]] )
|
||||
[stack, dictionary]
|
||||
end
|
||||
|
||||
@stack << { type: :numeric, base: infer_resulting_base( args ),
|
||||
value: args[1][:value]**args[0][:value] }
|
||||
end
|
||||
# multiplication
|
||||
def multiply
|
||||
args = stack_extract( [%i[numeric], %i[numeric]] )
|
||||
|
||||
# rpn_square root
|
||||
def sqrt
|
||||
args = stack_extract( [%i[numeric]] )
|
||||
@stack << { type: :numeric, base: infer_resulting_base( args ),
|
||||
value: args[1][:value] * args[0][:value] }
|
||||
|
||||
@stack << { type: :numeric, base: infer_resulting_base( args ),
|
||||
value: BigMath.sqrt( BigDecimal( args[0][:value], precision ), precision ) }
|
||||
end
|
||||
[stack, dictionary]
|
||||
end
|
||||
|
||||
# rpn_square
|
||||
def sq
|
||||
args = stack_extract( [%i[numeric]] )
|
||||
# division
|
||||
def divide
|
||||
args = stack_extract( [%i[numeric], %i[numeric]] )
|
||||
|
||||
@stack << { type: :numeric, base: infer_resulting_base( args ),
|
||||
value: args[0][:value] * args[0][:value] }
|
||||
end
|
||||
@stack << { type: :numeric, base: infer_resulting_base( args ),
|
||||
value: args[1][:value] / args[0][:value] }
|
||||
end
|
||||
|
||||
# absolute value
|
||||
def abs
|
||||
args = stack_extract( [%i[numeric]] )
|
||||
# power
|
||||
def power
|
||||
args = stack_extract( [%i[numeric], %i[numeric]] )
|
||||
|
||||
@stack << { type: :numeric, base: infer_resulting_base( args ),
|
||||
value: args[0][:value].abs }
|
||||
end
|
||||
@stack << { type: :numeric, base: infer_resulting_base( args ),
|
||||
value: args[1][:value]**args[0][:value] }
|
||||
end
|
||||
|
||||
# arbitrary base representation
|
||||
def base
|
||||
args = stack_extract( [%i[numeric], %i[numeric]] )
|
||||
# rpn_square root
|
||||
def sqrt
|
||||
args = stack_extract( [%i[numeric]] )
|
||||
|
||||
args[1][:base] = args[0][:value]
|
||||
@stack << { type: :numeric, base: infer_resulting_base( args ),
|
||||
value: BigMath.sqrt( BigDecimal( args[0][:value], precision ), precision ) }
|
||||
end
|
||||
|
||||
@stack << args[1]
|
||||
end
|
||||
# rpn_square
|
||||
def sq
|
||||
args = stack_extract( [%i[numeric]] )
|
||||
|
||||
# 1 if number at stack level 1 is > 0, 0 if == 0, -1 if <= 0
|
||||
def sign
|
||||
args = stack_extract( [%i[numeric]] )
|
||||
value = if args[0][:value].positive?
|
||||
1
|
||||
elsif args[0][:value].negative?
|
||||
-1
|
||||
else
|
||||
0
|
||||
end
|
||||
@stack << { type: :numeric, base: infer_resulting_base( args ),
|
||||
value: args[0][:value] * args[0][:value] }
|
||||
end
|
||||
|
||||
@stack << { type: :numeric, base: infer_resulting_base( args ),
|
||||
value: value }
|
||||
end
|
||||
# absolute value
|
||||
def abs
|
||||
args = stack_extract( [%i[numeric]] )
|
||||
|
||||
# OPERATIONS ON REALS
|
||||
@stack << { type: :numeric, base: infer_resulting_base( args ),
|
||||
value: args[0][:value].abs }
|
||||
end
|
||||
|
||||
# percent
|
||||
def percent
|
||||
args = stack_extract( [%i[numeric], %i[numeric]] )
|
||||
# arbitrary base representation
|
||||
def base
|
||||
args = stack_extract( [%i[numeric], %i[numeric]] )
|
||||
|
||||
@stack << { type: :numeric,
|
||||
base: infer_resulting_base( args ),
|
||||
value: args[0][:value] * ( args[1][:value] / 100.0 ) }
|
||||
end
|
||||
args[1][:base] = args[0][:value]
|
||||
|
||||
# inverse percent
|
||||
def inverse_percent
|
||||
args = stack_extract( [%i[numeric], %i[numeric]] )
|
||||
@stack << args[1]
|
||||
end
|
||||
|
||||
@stack << { type: :numeric,
|
||||
base: infer_resulting_base( args ),
|
||||
value: 100.0 * ( args[0][:value] / args[1][:value] ) }
|
||||
end
|
||||
# 1 if number at stack level 1 is > 0, 0 if == 0, -1 if <= 0
|
||||
def sign
|
||||
args = stack_extract( [%i[numeric]] )
|
||||
value = if args[0][:value].positive?
|
||||
1
|
||||
elsif args[0][:value].negative?
|
||||
-1
|
||||
else
|
||||
0
|
||||
end
|
||||
|
||||
# modulo
|
||||
def mod
|
||||
args = stack_extract( [%i[numeric], %i[numeric]] )
|
||||
@stack << { type: :numeric, base: infer_resulting_base( args ),
|
||||
value: value }
|
||||
end
|
||||
|
||||
@stack << { type: :numeric,
|
||||
base: infer_resulting_base( args ),
|
||||
value: args[1][:value] % args[0][:value] }
|
||||
end
|
||||
# OPERATIONS ON REALS
|
||||
|
||||
# n! for integer n or Gamma(x+1) for fractional x
|
||||
def fact
|
||||
args = stack_extract( [%i[numeric]] )
|
||||
# percent
|
||||
def percent
|
||||
args = stack_extract( [%i[numeric], %i[numeric]] )
|
||||
|
||||
@stack << { type: :numeric,
|
||||
base: infer_resulting_base( args ),
|
||||
value: Math.gamma( args[0][:value] ) }
|
||||
end
|
||||
@stack << { type: :numeric,
|
||||
base: infer_resulting_base( args ),
|
||||
value: args[0][:value] * ( args[1][:value] / 100.0 ) }
|
||||
end
|
||||
|
||||
# largest number <=
|
||||
def floor
|
||||
args = stack_extract( [%i[numeric]] )
|
||||
# inverse percent
|
||||
def inverse_percent
|
||||
args = stack_extract( [%i[numeric], %i[numeric]] )
|
||||
|
||||
@stack << { type: :numeric,
|
||||
base: infer_resulting_base( args ),
|
||||
value: args[0][:value].floor }
|
||||
end
|
||||
@stack << { type: :numeric,
|
||||
base: infer_resulting_base( args ),
|
||||
value: 100.0 * ( args[0][:value] / args[1][:value] ) }
|
||||
end
|
||||
|
||||
# smallest number >=
|
||||
def ceil
|
||||
args = stack_extract( [%i[numeric]] )
|
||||
# modulo
|
||||
def mod
|
||||
args = stack_extract( [%i[numeric], %i[numeric]] )
|
||||
|
||||
@stack << { type: :numeric,
|
||||
base: infer_resulting_base( args ),
|
||||
value: args[0][:value].ceil }
|
||||
end
|
||||
@stack << { type: :numeric,
|
||||
base: infer_resulting_base( args ),
|
||||
value: args[1][:value] % args[0][:value] }
|
||||
end
|
||||
|
||||
# min of 2 real numbers
|
||||
def min
|
||||
args = stack_extract( [%i[numeric], %i[numeric]] )
|
||||
# n! for integer n or Gamma(x+1) for fractional x
|
||||
def fact
|
||||
args = stack_extract( [%i[numeric]] )
|
||||
|
||||
@stack << ( args[0][:value] < args[1][:value] ? args[0] : args[1] )
|
||||
end
|
||||
@stack << { type: :numeric,
|
||||
base: infer_resulting_base( args ),
|
||||
value: Math.gamma( args[0][:value] ) }
|
||||
end
|
||||
|
||||
# max of 2 real numbers
|
||||
def max
|
||||
args = stack_extract( [%i[numeric], %i[numeric]] )
|
||||
# largest number <=
|
||||
def floor
|
||||
args = stack_extract( [%i[numeric]] )
|
||||
|
||||
@stack << ( args[0][:value] > args[1][:value] ? args[0] : args[1] )
|
||||
end
|
||||
@stack << { type: :numeric,
|
||||
base: infer_resulting_base( args ),
|
||||
value: args[0][:value].floor }
|
||||
end
|
||||
|
||||
# implemented in Rpl
|
||||
# negation
|
||||
def negate
|
||||
run( '-1 *' )
|
||||
end
|
||||
# smallest number >=
|
||||
def ceil
|
||||
args = stack_extract( [%i[numeric]] )
|
||||
|
||||
# inverse
|
||||
def inverse
|
||||
run( '1.0 swap /' )
|
||||
end
|
||||
@stack << { type: :numeric,
|
||||
base: infer_resulting_base( args ),
|
||||
value: args[0][:value].ceil }
|
||||
end
|
||||
|
||||
# decimal representation
|
||||
def dec
|
||||
run( '10 base' )
|
||||
end
|
||||
# min of 2 real numbers
|
||||
def min
|
||||
args = stack_extract( [%i[numeric], %i[numeric]] )
|
||||
|
||||
# hexadecimal representation
|
||||
def hex
|
||||
run( '16 base' )
|
||||
end
|
||||
@stack << ( args[0][:value] < args[1][:value] ? args[0] : args[1] )
|
||||
end
|
||||
|
||||
# binary representation
|
||||
def bin
|
||||
run( '2 base' )
|
||||
end
|
||||
# max of 2 real numbers
|
||||
def max
|
||||
args = stack_extract( [%i[numeric], %i[numeric]] )
|
||||
|
||||
@stack << ( args[0][:value] > args[1][:value] ? args[0] : args[1] )
|
||||
end
|
||||
|
||||
# implemented in Rpl
|
||||
# negation
|
||||
def negate
|
||||
run( '-1 *' )
|
||||
end
|
||||
|
||||
# inverse
|
||||
def inverse
|
||||
run( '1.0 swap /' )
|
||||
end
|
||||
|
||||
# decimal representation
|
||||
def dec
|
||||
run( '10 base' )
|
||||
end
|
||||
|
||||
# hexadecimal representation
|
||||
def hex
|
||||
run( '16 base' )
|
||||
end
|
||||
|
||||
# binary representation
|
||||
def bin
|
||||
run( '2 base' )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Rpl
|
||||
module Lang
|
||||
module Core
|
||||
module_function
|
||||
module Lang
|
||||
module Core
|
||||
module_function
|
||||
|
||||
# evaluate (run) a program, or recall a variable. ex: 'my_prog' eval
|
||||
def eval
|
||||
args = stack_extract( [:any] )
|
||||
# evaluate (run) a program, or recall a variable. ex: 'my_prog' eval
|
||||
def eval
|
||||
args = stack_extract( [:any] )
|
||||
|
||||
run( args[0][:value].to_s )
|
||||
end
|
||||
run( args[0][:value].to_s )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,126 +1,124 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Rpl
|
||||
module Lang
|
||||
module Core
|
||||
module_function
|
||||
module Lang
|
||||
module Core
|
||||
module_function
|
||||
|
||||
# swap 2 first stack entries
|
||||
def swap
|
||||
args = stack_extract( %i[any any] )
|
||||
# swap 2 first stack entries
|
||||
def swap
|
||||
args = stack_extract( %i[any any] )
|
||||
|
||||
@stack << args[0] << args[1]
|
||||
end
|
||||
@stack << args[0] << args[1]
|
||||
end
|
||||
|
||||
# drop n first stack entries
|
||||
def dropn
|
||||
args = stack_extract( [%i[numeric]] )
|
||||
# drop n first stack entries
|
||||
def dropn
|
||||
args = stack_extract( [%i[numeric]] )
|
||||
|
||||
_args = stack_extract( %i[any] * args[0][:value] )
|
||||
end
|
||||
_args = stack_extract( %i[any] * args[0][:value] )
|
||||
end
|
||||
|
||||
# drop all stack entries
|
||||
def del
|
||||
@stack = []
|
||||
end
|
||||
# drop all stack entries
|
||||
def del
|
||||
@stack = []
|
||||
end
|
||||
|
||||
# rotate 3 first stack entries
|
||||
def rot
|
||||
args = stack_extract( %i[any any any] )
|
||||
# rotate 3 first stack entries
|
||||
def rot
|
||||
args = stack_extract( %i[any any any] )
|
||||
|
||||
@stack << args[1] << args[0] << args[2]
|
||||
end
|
||||
@stack << args[1] << args[0] << args[2]
|
||||
end
|
||||
|
||||
# duplicate n first stack entries
|
||||
def dupn
|
||||
args = stack_extract( [%i[numeric]] )
|
||||
n = args[0][:value].to_i
|
||||
args = stack_extract( %i[any] * args[0][:value] )
|
||||
# duplicate n first stack entries
|
||||
def dupn
|
||||
args = stack_extract( [%i[numeric]] )
|
||||
n = args[0][:value].to_i
|
||||
args = stack_extract( %i[any] * args[0][:value] )
|
||||
|
||||
args.reverse!
|
||||
|
||||
2.times do
|
||||
n.times.each do |i|
|
||||
@stack << Marshal.load(Marshal.dump( args[i] ))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# push a copy of the given stack level onto the stack
|
||||
def pick
|
||||
args = stack_extract( [%i[numeric]] )
|
||||
n = args[0][:value].to_i
|
||||
args = stack_extract( %i[any] * args[0][:value] )
|
||||
|
||||
args.reverse!
|
||||
args.reverse!
|
||||
|
||||
2.times do
|
||||
n.times.each do |i|
|
||||
@stack << args[ i ]
|
||||
end
|
||||
|
||||
@stack << args[0]
|
||||
end
|
||||
|
||||
# give stack depth
|
||||
def depth
|
||||
@stack << { type: :numeric, base: 10, value: stack.size }
|
||||
end
|
||||
|
||||
# move a stack entry to the top of the stack
|
||||
def roll
|
||||
args = stack_extract( [%i[numeric]] )
|
||||
n = args[0][:value]
|
||||
args = stack_extract( %i[any] * args[0][:value] )
|
||||
|
||||
args.reverse!
|
||||
|
||||
(1..(n - 1)).each do |i|
|
||||
@stack << args[ i ]
|
||||
end
|
||||
|
||||
@stack << args[0]
|
||||
end
|
||||
|
||||
# move the element on top of the stack to a higher stack position
|
||||
def rolld
|
||||
args = stack_extract( [%i[numeric]] )
|
||||
n = args[0][:value]
|
||||
args = stack_extract( %i[any] * args[0][:value] )
|
||||
|
||||
args.reverse!
|
||||
|
||||
@stack << args[n - 1]
|
||||
|
||||
(0..(n - 2)).each do |i|
|
||||
@stack << args[ i ]
|
||||
@stack << Marshal.load(Marshal.dump( args[i] ))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# implemented in Rpl
|
||||
# push a copy of the element in stack level 2 onto the stack
|
||||
def over
|
||||
run( '2 pick' )
|
||||
# push a copy of the given stack level onto the stack
|
||||
def pick
|
||||
args = stack_extract( [%i[numeric]] )
|
||||
n = args[0][:value].to_i
|
||||
args = stack_extract( %i[any] * args[0][:value] )
|
||||
|
||||
args.reverse!
|
||||
|
||||
n.times.each do |i|
|
||||
@stack << args[ i ]
|
||||
end
|
||||
|
||||
# drop first stack entry
|
||||
def drop
|
||||
run( '1 dropn' )
|
||||
@stack << args[0]
|
||||
end
|
||||
|
||||
# give stack depth
|
||||
def depth
|
||||
@stack << { type: :numeric, base: 10, value: stack.size }
|
||||
end
|
||||
|
||||
# move a stack entry to the top of the stack
|
||||
def roll
|
||||
args = stack_extract( [%i[numeric]] )
|
||||
n = args[0][:value]
|
||||
args = stack_extract( %i[any] * args[0][:value] )
|
||||
|
||||
args.reverse!
|
||||
|
||||
(1..(n - 1)).each do |i|
|
||||
@stack << args[ i ]
|
||||
end
|
||||
|
||||
# drop 2 first stack entries
|
||||
def drop2
|
||||
run( '2 dropn' )
|
||||
end
|
||||
@stack << args[0]
|
||||
end
|
||||
|
||||
# duplicate first stack entry
|
||||
def dup
|
||||
run( '1 dupn' )
|
||||
end
|
||||
# move the element on top of the stack to a higher stack position
|
||||
def rolld
|
||||
args = stack_extract( [%i[numeric]] )
|
||||
n = args[0][:value]
|
||||
args = stack_extract( %i[any] * args[0][:value] )
|
||||
|
||||
# duplicate 2 first stack entries
|
||||
def dup2
|
||||
run( '2 dupn' )
|
||||
args.reverse!
|
||||
|
||||
@stack << args[n - 1]
|
||||
|
||||
(0..(n - 2)).each do |i|
|
||||
@stack << args[ i ]
|
||||
end
|
||||
end
|
||||
|
||||
# implemented in Rpl
|
||||
# push a copy of the element in stack level 2 onto the stack
|
||||
def over
|
||||
run( '2 pick' )
|
||||
end
|
||||
|
||||
# drop first stack entry
|
||||
def drop
|
||||
run( '1 dropn' )
|
||||
end
|
||||
|
||||
# drop 2 first stack entries
|
||||
def drop2
|
||||
run( '2 dropn' )
|
||||
end
|
||||
|
||||
# duplicate first stack entry
|
||||
def dup
|
||||
run( '1 dupn' )
|
||||
end
|
||||
|
||||
# duplicate 2 first stack entries
|
||||
def dup2
|
||||
run( '2 dupn' )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,98 +1,96 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Rpl
|
||||
module Lang
|
||||
module Core
|
||||
module_function
|
||||
module Lang
|
||||
module Core
|
||||
module_function
|
||||
|
||||
# store a variable. ex: 1 'name' sto
|
||||
def sto
|
||||
args = stack_extract( [%i[name], :any] )
|
||||
# store a variable. ex: 1 'name' sto
|
||||
def sto
|
||||
args = stack_extract( [%i[name], :any] )
|
||||
|
||||
@dictionary.add_var( args[0][:value],
|
||||
args[1] )
|
||||
end
|
||||
@dictionary.add_var( args[0][:value],
|
||||
args[1] )
|
||||
end
|
||||
|
||||
# store a local variable
|
||||
def lsto
|
||||
args = stack_extract( [%i[name], :any] )
|
||||
# store a local variable
|
||||
def lsto
|
||||
args = stack_extract( [%i[name], :any] )
|
||||
|
||||
@dictionary.add_local_var( args[0][:value],
|
||||
args[1] )
|
||||
end
|
||||
@dictionary.add_local_var( args[0][:value],
|
||||
args[1] )
|
||||
end
|
||||
|
||||
# recall a variable. ex: 'name' rcl
|
||||
def rcl
|
||||
args = stack_extract( [%i[name]] )
|
||||
# recall a variable. ex: 'name' rcl
|
||||
def rcl
|
||||
args = stack_extract( [%i[name]] )
|
||||
|
||||
content = @dictionary.lookup( args[0][:value] )
|
||||
content = @dictionary.lookup( args[0][:value] )
|
||||
|
||||
@stack << content unless content.nil?
|
||||
end
|
||||
@stack << content unless content.nil?
|
||||
end
|
||||
|
||||
# delete a variable. ex: 'name' purge
|
||||
def purge
|
||||
args = stack_extract( [%i[name]] )
|
||||
# delete a variable. ex: 'name' purge
|
||||
def purge
|
||||
args = stack_extract( [%i[name]] )
|
||||
|
||||
@dictionary.remove_var( args[0][:value] )
|
||||
end
|
||||
@dictionary.remove_var( args[0][:value] )
|
||||
end
|
||||
|
||||
# list all variables
|
||||
def vars
|
||||
@stack << { type: :list,
|
||||
value: (@dictionary.vars.keys + @dictionary.local_vars_layers.reduce([]) { |memo, layer| memo + layer.keys }).map { |name| { type: :name, value: name } } }
|
||||
end
|
||||
# list all variables
|
||||
def vars
|
||||
@stack << { type: :list,
|
||||
value: (@dictionary.vars.keys + @dictionary.local_vars_layers.reduce([]) { |memo, layer| memo + layer.keys }).map { |name| { type: :name, value: name } } }
|
||||
end
|
||||
|
||||
# erase all variables
|
||||
def clusr
|
||||
@dictionary.remove_all_vars
|
||||
end
|
||||
# erase all variables
|
||||
def clusr
|
||||
@dictionary.remove_all_vars
|
||||
end
|
||||
|
||||
# add to a stored variable. ex: 1 'name' sto+ 'name' 2 sto+
|
||||
def sto_add
|
||||
run( '
|
||||
# add to a stored variable. ex: 1 'name' sto+ 'name' 2 sto+
|
||||
def sto_add
|
||||
run( '
|
||||
dup type "name" ==
|
||||
« swap »
|
||||
ift
|
||||
over rcl + swap sto' )
|
||||
end
|
||||
end
|
||||
|
||||
# substract to a stored variable. ex: 1 'name' sto- 'name' 2 sto-
|
||||
def sto_subtract
|
||||
run( '
|
||||
# substract to a stored variable. ex: 1 'name' sto- 'name' 2 sto-
|
||||
def sto_subtract
|
||||
run( '
|
||||
dup type "name" ==
|
||||
« swap »
|
||||
ift
|
||||
over rcl swap - swap sto' )
|
||||
end
|
||||
end
|
||||
|
||||
# multiply a stored variable. ex: 3 'name' sto* 'name' 2 sto*
|
||||
def sto_multiply
|
||||
run( '
|
||||
# multiply a stored variable. ex: 3 'name' sto* 'name' 2 sto*
|
||||
def sto_multiply
|
||||
run( '
|
||||
dup type "name" ==
|
||||
« swap »
|
||||
ift
|
||||
over rcl * swap sto' )
|
||||
end
|
||||
end
|
||||
|
||||
# divide a stored variable. ex: 3 'name' sto/ 'name' 2 sto/
|
||||
def sto_divide
|
||||
run( '
|
||||
# divide a stored variable. ex: 3 'name' sto/ 'name' 2 sto/
|
||||
def sto_divide
|
||||
run( '
|
||||
dup type "name" ==
|
||||
« swap »
|
||||
ift
|
||||
over rcl swap / swap sto' )
|
||||
end
|
||||
end
|
||||
|
||||
# negate a variable. ex: 'name' sneg
|
||||
def sto_negate
|
||||
run( 'dup rcl chs swap sto' )
|
||||
end
|
||||
# negate a variable. ex: 'name' sneg
|
||||
def sto_negate
|
||||
run( 'dup rcl chs swap sto' )
|
||||
end
|
||||
|
||||
# inverse a variable. ex: 1 'name' sinv
|
||||
def sto_inverse
|
||||
run( 'dup rcl inv swap sto' )
|
||||
end
|
||||
# inverse a variable. ex: 1 'name' sinv
|
||||
def sto_inverse
|
||||
run( 'dup rcl inv swap sto' )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,93 +1,91 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Rpl
|
||||
module Lang
|
||||
module Core
|
||||
module_function
|
||||
module Lang
|
||||
module Core
|
||||
module_function
|
||||
|
||||
# convert an object into a string
|
||||
def to_string
|
||||
args = stack_extract( [:any] )
|
||||
# convert an object into a string
|
||||
def to_string
|
||||
args = stack_extract( [:any] )
|
||||
|
||||
@stack << { type: :string,
|
||||
value: stringify( args[0] ) }
|
||||
end
|
||||
|
||||
# convert a string into an object
|
||||
def from_string
|
||||
args = stack_extract( [%i[string]] )
|
||||
|
||||
@stack += parse( args[0][:value] )
|
||||
end
|
||||
|
||||
# convert ASCII character code in stack level 1 into a string
|
||||
def chr
|
||||
args = stack_extract( [%i[numeric]] )
|
||||
|
||||
@stack << { type: :string,
|
||||
value: args[0][:value].to_i.chr }
|
||||
end
|
||||
|
||||
# return ASCII code of the first character of the string in stack level 1 as a real number
|
||||
def num
|
||||
args = stack_extract( [%i[string]] )
|
||||
|
||||
@stack << { type: :numeric,
|
||||
base: 10,
|
||||
value: args[0][:value].ord }
|
||||
end
|
||||
|
||||
# return the length of the string
|
||||
def size
|
||||
args = stack_extract( [%i[string]] )
|
||||
|
||||
@stack << { type: :numeric,
|
||||
base: 10,
|
||||
value: args[0][:value].length }
|
||||
end
|
||||
|
||||
# search for the string in level 1 within the string in level 2
|
||||
def pos
|
||||
args = stack_extract( [%i[string], %i[string]] )
|
||||
|
||||
@stack << { type: :numeric,
|
||||
base: 10,
|
||||
value: args[1][:value].index( args[0][:value] ) }
|
||||
end
|
||||
|
||||
# return a substring of the string in level 3
|
||||
def sub
|
||||
args = stack_extract( [%i[numeric], %i[numeric], %i[string]] )
|
||||
|
||||
@stack << { type: :string,
|
||||
value: args[2][:value][ (args[1][:value] - 1)..(args[0][:value] - 1) ] }
|
||||
end
|
||||
|
||||
# reverse string or list
|
||||
def rev
|
||||
args = stack_extract( [%i[string list]] )
|
||||
|
||||
result = args[0]
|
||||
|
||||
case args[0][:type]
|
||||
when :string
|
||||
result = { type: :string,
|
||||
value: args[0][:value].reverse }
|
||||
when :list
|
||||
result[:value].reverse!
|
||||
end
|
||||
|
||||
@stack << result
|
||||
end
|
||||
|
||||
# split string
|
||||
def split
|
||||
args = stack_extract( [%i[string], %i[string]] )
|
||||
|
||||
args[1][:value].split( args[0][:value] ).each do |elt|
|
||||
@stack << { type: :string,
|
||||
value: stringify( args[0] ) }
|
||||
end
|
||||
|
||||
# convert a string into an object
|
||||
def from_string
|
||||
args = stack_extract( [%i[string]] )
|
||||
|
||||
@stack += parse( args[0][:value] )
|
||||
end
|
||||
|
||||
# convert ASCII character code in stack level 1 into a string
|
||||
def chr
|
||||
args = stack_extract( [%i[numeric]] )
|
||||
|
||||
@stack << { type: :string,
|
||||
value: args[0][:value].to_i.chr }
|
||||
end
|
||||
|
||||
# return ASCII code of the first character of the string in stack level 1 as a real number
|
||||
def num
|
||||
args = stack_extract( [%i[string]] )
|
||||
|
||||
@stack << { type: :numeric,
|
||||
base: 10,
|
||||
value: args[0][:value].ord }
|
||||
end
|
||||
|
||||
# return the length of the string
|
||||
def size
|
||||
args = stack_extract( [%i[string]] )
|
||||
|
||||
@stack << { type: :numeric,
|
||||
base: 10,
|
||||
value: args[0][:value].length }
|
||||
end
|
||||
|
||||
# search for the string in level 1 within the string in level 2
|
||||
def pos
|
||||
args = stack_extract( [%i[string], %i[string]] )
|
||||
|
||||
@stack << { type: :numeric,
|
||||
base: 10,
|
||||
value: args[1][:value].index( args[0][:value] ) }
|
||||
end
|
||||
|
||||
# return a substring of the string in level 3
|
||||
def sub
|
||||
args = stack_extract( [%i[numeric], %i[numeric], %i[string]] )
|
||||
|
||||
@stack << { type: :string,
|
||||
value: args[2][:value][ (args[1][:value] - 1)..(args[0][:value] - 1) ] }
|
||||
end
|
||||
|
||||
# reverse string or list
|
||||
def rev
|
||||
args = stack_extract( [%i[string list]] )
|
||||
|
||||
result = args[0]
|
||||
|
||||
case args[0][:type]
|
||||
when :string
|
||||
result = { type: :string,
|
||||
value: args[0][:value].reverse }
|
||||
when :list
|
||||
result[:value].reverse!
|
||||
end
|
||||
|
||||
@stack << result
|
||||
end
|
||||
|
||||
# split string
|
||||
def split
|
||||
args = stack_extract( [%i[string], %i[string]] )
|
||||
|
||||
args[1][:value].split( args[0][:value] ).each do |elt|
|
||||
@stack << { type: :string,
|
||||
value: elt }
|
||||
end
|
||||
value: elt }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
144
lib/core/test.rb
144
lib/core/test.rb
|
@ -1,99 +1,97 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Rpl
|
||||
module Lang
|
||||
module Core
|
||||
# binary operator >
|
||||
def greater_than
|
||||
args = stack_extract( %i[any any] )
|
||||
module Lang
|
||||
module Core
|
||||
# binary operator >
|
||||
def greater_than
|
||||
args = stack_extract( %i[any any] )
|
||||
|
||||
@stack << { type: :boolean,
|
||||
value: args[1][:value] > args[0][:value] }
|
||||
end
|
||||
@stack << { type: :boolean,
|
||||
value: args[1][:value] > args[0][:value] }
|
||||
end
|
||||
|
||||
# binary operator >=
|
||||
def greater_than_or_equal
|
||||
args = stack_extract( %i[any any] )
|
||||
# binary operator >=
|
||||
def greater_than_or_equal
|
||||
args = stack_extract( %i[any any] )
|
||||
|
||||
@stack << { type: :boolean,
|
||||
value: args[1][:value] >= args[0][:value] }
|
||||
end
|
||||
@stack << { type: :boolean,
|
||||
value: args[1][:value] >= args[0][:value] }
|
||||
end
|
||||
|
||||
# binary operator <
|
||||
def less_than
|
||||
args = stack_extract( %i[any any] )
|
||||
# binary operator <
|
||||
def less_than
|
||||
args = stack_extract( %i[any any] )
|
||||
|
||||
@stack << { type: :boolean,
|
||||
value: args[1][:value] < args[0][:value] }
|
||||
end
|
||||
@stack << { type: :boolean,
|
||||
value: args[1][:value] < args[0][:value] }
|
||||
end
|
||||
|
||||
# binary operator <=
|
||||
def less_than_or_equal
|
||||
args = stack_extract( %i[any any] )
|
||||
# binary operator <=
|
||||
def less_than_or_equal
|
||||
args = stack_extract( %i[any any] )
|
||||
|
||||
@stack << { type: :boolean,
|
||||
value: args[1][:value] <= args[0][:value] }
|
||||
end
|
||||
@stack << { type: :boolean,
|
||||
value: args[1][:value] <= args[0][:value] }
|
||||
end
|
||||
|
||||
# boolean operator != (different)
|
||||
def different
|
||||
args = stack_extract( %i[any any] )
|
||||
# boolean operator != (different)
|
||||
def different
|
||||
args = stack_extract( %i[any any] )
|
||||
|
||||
@stack << { type: :boolean,
|
||||
value: args[1][:value] != args[0][:value] }
|
||||
end
|
||||
@stack << { type: :boolean,
|
||||
value: args[1][:value] != args[0][:value] }
|
||||
end
|
||||
|
||||
# boolean operator and
|
||||
def boolean_and
|
||||
args = stack_extract( [%i[boolean], %i[boolean]] )
|
||||
# boolean operator and
|
||||
def boolean_and
|
||||
args = stack_extract( [%i[boolean], %i[boolean]] )
|
||||
|
||||
@stack << { type: :boolean,
|
||||
value: args[1][:value] && args[0][:value] }
|
||||
end
|
||||
@stack << { type: :boolean,
|
||||
value: args[1][:value] && args[0][:value] }
|
||||
end
|
||||
|
||||
# boolean operator or
|
||||
def boolean_or
|
||||
args = stack_extract( [%i[boolean], %i[boolean]] )
|
||||
# boolean operator or
|
||||
def boolean_or
|
||||
args = stack_extract( [%i[boolean], %i[boolean]] )
|
||||
|
||||
@stack << { type: :boolean,
|
||||
value: args[1][:value] || args[0][:value] }
|
||||
end
|
||||
@stack << { type: :boolean,
|
||||
value: args[1][:value] || args[0][:value] }
|
||||
end
|
||||
|
||||
# boolean operator xor
|
||||
def xor
|
||||
args = stack_extract( [%i[boolean], %i[boolean]] )
|
||||
# boolean operator xor
|
||||
def xor
|
||||
args = stack_extract( [%i[boolean], %i[boolean]] )
|
||||
|
||||
@stack << { type: :boolean,
|
||||
value: args[1][:value] ^ args[0][:value] }
|
||||
end
|
||||
@stack << { type: :boolean,
|
||||
value: args[1][:value] ^ args[0][:value] }
|
||||
end
|
||||
|
||||
# boolean operator not
|
||||
def boolean_not
|
||||
args = stack_extract( [%i[boolean]] )
|
||||
# boolean operator not
|
||||
def boolean_not
|
||||
args = stack_extract( [%i[boolean]] )
|
||||
|
||||
@stack << { type: :boolean,
|
||||
value: !args[0][:value] }
|
||||
end
|
||||
@stack << { type: :boolean,
|
||||
value: !args[0][:value] }
|
||||
end
|
||||
|
||||
# boolean operator same (equal)
|
||||
def same
|
||||
args = stack_extract( %i[any any] )
|
||||
# boolean operator same (equal)
|
||||
def same
|
||||
args = stack_extract( %i[any any] )
|
||||
|
||||
@stack << { type: :boolean,
|
||||
value: args[1][:value] == args[0][:value] }
|
||||
end
|
||||
@stack << { type: :boolean,
|
||||
value: args[1][:value] == args[0][:value] }
|
||||
end
|
||||
|
||||
# true boolean
|
||||
def boolean_true
|
||||
@stack << { type: :boolean,
|
||||
value: true }
|
||||
end
|
||||
# true boolean
|
||||
def boolean_true
|
||||
@stack << { type: :boolean,
|
||||
value: true }
|
||||
end
|
||||
|
||||
# false boolean
|
||||
def boolean_false
|
||||
@stack << { type: :boolean,
|
||||
value: false }
|
||||
end
|
||||
# false boolean
|
||||
def boolean_false
|
||||
@stack << { type: :boolean,
|
||||
value: false }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,31 +2,29 @@
|
|||
|
||||
require 'date'
|
||||
|
||||
module Rpl
|
||||
module Lang
|
||||
module Core
|
||||
module_function
|
||||
module Lang
|
||||
module Core
|
||||
module_function
|
||||
|
||||
# time in local format
|
||||
def time
|
||||
@stack << { type: :string,
|
||||
value: Time.now.to_s }
|
||||
end
|
||||
# time in local format
|
||||
def time
|
||||
@stack << { type: :string,
|
||||
value: Time.now.to_s }
|
||||
end
|
||||
|
||||
# date in local format
|
||||
def date
|
||||
@stack << { type: :string,
|
||||
value: Date.today.to_s }
|
||||
end
|
||||
# date in local format
|
||||
def date
|
||||
@stack << { type: :string,
|
||||
value: Date.today.to_s }
|
||||
end
|
||||
|
||||
# system tick in µs
|
||||
def ticks
|
||||
ticks_since_epoch = Time.utc( 1, 1, 1 ).to_i * 10_000_000
|
||||
now = Time.now
|
||||
@stack << { type: :numeric,
|
||||
base: 10,
|
||||
value: now.to_i * 10_000_000 + now.nsec / 100 - ticks_since_epoch }
|
||||
end
|
||||
# system tick in µs
|
||||
def ticks
|
||||
ticks_since_epoch = Time.utc( 1, 1, 1 ).to_i * 10_000_000
|
||||
now = Time.now
|
||||
@stack << { type: :numeric,
|
||||
base: 10,
|
||||
value: now.to_i * 10_000_000 + now.nsec / 100 - ticks_since_epoch }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
104
lib/core/trig.rb
104
lib/core/trig.rb
|
@ -1,46 +1,47 @@
|
|||
module Rpl
|
||||
module Lang
|
||||
module Core
|
||||
module_function
|
||||
# frozen_string_literal: true
|
||||
|
||||
# pi constant
|
||||
def pi
|
||||
@stack << { type: :numeric,
|
||||
base: 10,
|
||||
value: BigMath.PI( precision ) }
|
||||
end
|
||||
module Lang
|
||||
module Core
|
||||
module_function
|
||||
|
||||
# sinus
|
||||
def sinus
|
||||
args = stack_extract( [%i[numeric]] )
|
||||
# pi constant
|
||||
def pi
|
||||
@stack << { type: :numeric,
|
||||
base: 10,
|
||||
value: BigMath.PI( precision ) }
|
||||
end
|
||||
|
||||
@stack << { type: :numeric,
|
||||
base: infer_resulting_base( args ),
|
||||
value: BigMath.sin( BigDecimal( args[0][:value], precision ), precision ) }
|
||||
end
|
||||
# sinus
|
||||
def sinus
|
||||
args = stack_extract( [%i[numeric]] )
|
||||
|
||||
# https://rosettacode.org/wiki/Trigonometric_functions#Ruby
|
||||
# arg sinus
|
||||
def arg_sinus
|
||||
run( '
|
||||
@stack << { type: :numeric,
|
||||
base: infer_resulting_base( args ),
|
||||
value: BigMath.sin( BigDecimal( args[0][:value], precision ), precision ) }
|
||||
end
|
||||
|
||||
# https://rosettacode.org/wiki/Trigonometric_functions#Ruby
|
||||
# arg sinus
|
||||
def arg_sinus
|
||||
run( '
|
||||
dup abs 1 ==
|
||||
« 𝛑 2 / * »
|
||||
« dup sq 1 swap - sqrt / atan »
|
||||
ifte' )
|
||||
end
|
||||
end
|
||||
|
||||
# cosinus
|
||||
def cosinus
|
||||
args = stack_extract( [%i[numeric]] )
|
||||
# cosinus
|
||||
def cosinus
|
||||
args = stack_extract( [%i[numeric]] )
|
||||
|
||||
@stack << { type: :numeric,
|
||||
base: infer_resulting_base( args ),
|
||||
value: BigMath.cos( BigDecimal( args[0][:value], precision ), precision ) }
|
||||
end
|
||||
@stack << { type: :numeric,
|
||||
base: infer_resulting_base( args ),
|
||||
value: BigMath.cos( BigDecimal( args[0][:value], precision ), precision ) }
|
||||
end
|
||||
|
||||
# arg cosinus
|
||||
def arg_cosinus
|
||||
run( '
|
||||
# arg cosinus
|
||||
def arg_cosinus
|
||||
run( '
|
||||
dup 0 ==
|
||||
« drop 𝛑 2 / »
|
||||
«
|
||||
|
@ -50,31 +51,30 @@ module Rpl
|
|||
ift
|
||||
»
|
||||
ifte' )
|
||||
end
|
||||
end
|
||||
|
||||
# tangent
|
||||
def tangent
|
||||
run( 'dup sin swap cos /' )
|
||||
end
|
||||
# tangent
|
||||
def tangent
|
||||
run( 'dup sin swap cos /' )
|
||||
end
|
||||
|
||||
# arg tangent
|
||||
def arg_tangent
|
||||
args = stack_extract( [%i[numeric]] )
|
||||
# arg tangent
|
||||
def arg_tangent
|
||||
args = stack_extract( [%i[numeric]] )
|
||||
|
||||
@stack << { type: :numeric,
|
||||
base: infer_resulting_base( args ),
|
||||
value: BigMath.atan( BigDecimal( args[0][:value], precision ), precision ) }
|
||||
end
|
||||
@stack << { type: :numeric,
|
||||
base: infer_resulting_base( args ),
|
||||
value: BigMath.atan( BigDecimal( args[0][:value], precision ), precision ) }
|
||||
end
|
||||
|
||||
# convert degrees to radians
|
||||
def degrees_to_radians
|
||||
run( '180 / 𝛑 *' )
|
||||
end
|
||||
# convert degrees to radians
|
||||
def degrees_to_radians
|
||||
run( '180 / 𝛑 *' )
|
||||
end
|
||||
|
||||
# convert radians to degrees
|
||||
def radians_to_degrees
|
||||
run( '𝛑 180 / /' )
|
||||
end
|
||||
# convert radians to degrees
|
||||
def radians_to_degrees
|
||||
run( '𝛑 180 / /' )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,79 +1,75 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Rpl
|
||||
module Lang
|
||||
class Dictionary
|
||||
attr_reader :words,
|
||||
:vars,
|
||||
:local_vars_layers
|
||||
class Dictionary
|
||||
attr_reader :words,
|
||||
:vars,
|
||||
:local_vars_layers
|
||||
|
||||
def initialize
|
||||
@words = {}
|
||||
@vars = {}
|
||||
@local_vars_layers = []
|
||||
end
|
||||
def initialize
|
||||
@words = {}
|
||||
@vars = {}
|
||||
@local_vars_layers = []
|
||||
end
|
||||
|
||||
def add_word( names, category, help, implementation )
|
||||
names.each do |name|
|
||||
@words[ name ] = { category: category,
|
||||
help: help,
|
||||
implementation: implementation }
|
||||
end
|
||||
end
|
||||
|
||||
def add_var( name, implementation )
|
||||
@vars[ name ] = implementation
|
||||
end
|
||||
|
||||
def remove_vars( names )
|
||||
names.each do |name|
|
||||
@vars.delete( name )
|
||||
end
|
||||
end
|
||||
|
||||
def remove_var( name )
|
||||
remove_vars( [name] )
|
||||
end
|
||||
|
||||
def remove_all_vars
|
||||
@vars = {}
|
||||
end
|
||||
|
||||
def add_local_vars_layer
|
||||
@local_vars_layers << {}
|
||||
end
|
||||
|
||||
def add_local_var( name, implementation )
|
||||
@local_vars_layers.last[ name ] = implementation
|
||||
end
|
||||
|
||||
def remove_local_vars( names )
|
||||
names.each do |name|
|
||||
@local_vars_layers.last.delete( name )
|
||||
end
|
||||
end
|
||||
|
||||
def remove_local_var( name )
|
||||
remove_local_vars( [name] )
|
||||
end
|
||||
|
||||
def remove_local_vars_layer
|
||||
@local_vars_layers.pop
|
||||
end
|
||||
|
||||
def lookup( name )
|
||||
# look in local variables from the deepest layer up
|
||||
local_vars_layer = @local_vars_layers.reverse.find { |layer| layer[ name ] }
|
||||
word = local_vars_layer.nil? ? nil : local_vars_layer[ name ]
|
||||
|
||||
# otherwise look in (global) variables
|
||||
word ||= @vars[ name ]
|
||||
|
||||
# or is it a core word
|
||||
word ||= @words[ name ].nil? ? nil : @words[ name ][:implementation]
|
||||
|
||||
word
|
||||
end
|
||||
def add_word( names, category, help, implementation )
|
||||
names.each do |name|
|
||||
@words[ name ] = { category: category,
|
||||
help: help,
|
||||
implementation: implementation }
|
||||
end
|
||||
end
|
||||
|
||||
def add_var( name, implementation )
|
||||
@vars[ name ] = implementation
|
||||
end
|
||||
|
||||
def remove_vars( names )
|
||||
names.each do |name|
|
||||
@vars.delete( name )
|
||||
end
|
||||
end
|
||||
|
||||
def remove_var( name )
|
||||
remove_vars( [name] )
|
||||
end
|
||||
|
||||
def remove_all_vars
|
||||
@vars = {}
|
||||
end
|
||||
|
||||
def add_local_vars_layer
|
||||
@local_vars_layers << {}
|
||||
end
|
||||
|
||||
def add_local_var( name, implementation )
|
||||
@local_vars_layers.last[ name ] = implementation
|
||||
end
|
||||
|
||||
def remove_local_vars( names )
|
||||
names.each do |name|
|
||||
@local_vars_layers.last.delete( name )
|
||||
end
|
||||
end
|
||||
|
||||
def remove_local_var( name )
|
||||
remove_local_vars( [name] )
|
||||
end
|
||||
|
||||
def remove_local_vars_layer
|
||||
@local_vars_layers.pop
|
||||
end
|
||||
|
||||
def lookup( name )
|
||||
# look in local variables from the deepest layer up
|
||||
local_vars_layer = @local_vars_layers.reverse.find { |layer| layer[ name ] }
|
||||
word = local_vars_layer.nil? ? nil : local_vars_layer[ name ]
|
||||
|
||||
# otherwise look in (global) variables
|
||||
word ||= @vars[ name ]
|
||||
|
||||
# or is it a core word
|
||||
word ||= @words[ name ].nil? ? nil : @words[ name ][:implementation]
|
||||
|
||||
word
|
||||
end
|
||||
end
|
||||
|
|
213
lib/interpreter.rb
Normal file
213
lib/interpreter.rb
Normal file
|
@ -0,0 +1,213 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'bigdecimal/math'
|
||||
|
||||
require_relative './dictionary'
|
||||
|
||||
class Interpreter
|
||||
include BigMath
|
||||
|
||||
attr_reader :stack,
|
||||
:dictionary,
|
||||
:version
|
||||
|
||||
attr_accessor :precision
|
||||
|
||||
def initialize( stack = [], dictionary = Rpl::Lang::Dictionary.new )
|
||||
@version = 0.1
|
||||
|
||||
@precision = default_precision
|
||||
|
||||
@dictionary = dictionary
|
||||
@stack = stack
|
||||
|
||||
populate_dictionary if @dictionary.words.empty?
|
||||
end
|
||||
|
||||
def default_precision
|
||||
12
|
||||
end
|
||||
|
||||
def parse( input )
|
||||
is_numeric = lambda do |elt|
|
||||
begin
|
||||
!Float(elt).nil?
|
||||
rescue ArgumentError
|
||||
begin
|
||||
!Integer(elt).nil?
|
||||
rescue ArgumentError
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
splitted_input = input.split(' ')
|
||||
|
||||
# 2-passes:
|
||||
# 1. regroup strings and programs
|
||||
opened_programs = 0
|
||||
closed_programs = 0
|
||||
string_delimiters = 0
|
||||
name_delimiters = 0
|
||||
regrouping = false
|
||||
|
||||
regrouped_input = []
|
||||
splitted_input.each do |elt|
|
||||
if elt[0] == '«'
|
||||
opened_programs += 1
|
||||
elt.gsub!( '«', '« ') if elt.length > 1 && elt[1] != ' '
|
||||
end
|
||||
string_delimiters += 1 if elt[0] == '"' && elt.length > 1
|
||||
name_delimiters += 1 if elt[0] == "'" && elt.length > 1
|
||||
|
||||
elt = "#{regrouped_input.pop} #{elt}".strip if regrouping
|
||||
|
||||
regrouped_input << elt
|
||||
|
||||
if elt[-1] == '»'
|
||||
closed_programs += 1
|
||||
elt.gsub!( '»', ' »') if elt.length > 1 && elt[-2] != ' '
|
||||
end
|
||||
string_delimiters += 1 if elt[-1] == '"'
|
||||
name_delimiters += 1 if elt[-1] == "'"
|
||||
|
||||
regrouping = string_delimiters.odd? || name_delimiters.odd? || (opened_programs > closed_programs )
|
||||
end
|
||||
|
||||
# 2. parse
|
||||
# TODO: parse ∞, <NaN> as numerics
|
||||
parsed_tree = []
|
||||
regrouped_input.each do |elt|
|
||||
parsed_entry = { value: elt }
|
||||
|
||||
parsed_entry[:type] = case elt[0]
|
||||
when '«'
|
||||
:program
|
||||
when '"'
|
||||
:string
|
||||
when "'"
|
||||
:name # TODO: check for forbidden space
|
||||
else
|
||||
if is_numeric.call( elt )
|
||||
:numeric
|
||||
else
|
||||
:word
|
||||
end
|
||||
end
|
||||
|
||||
if %I[string name].include?( parsed_entry[:type] )
|
||||
parsed_entry[:value] = parsed_entry[:value][1..-2]
|
||||
elsif parsed_entry[:type] == :program
|
||||
parsed_entry[:value] = parsed_entry[:value][2..-3]
|
||||
elsif parsed_entry[:type] == :numeric
|
||||
parsed_entry[:base] = 10 # TODO: parse others possible bases 0x...
|
||||
|
||||
begin
|
||||
parsed_entry[:value] = Float( parsed_entry[:value] )
|
||||
parsed_entry[:value] = parsed_entry[:value].to_i if (parsed_entry[:value] % 1).zero? && elt.index('.').nil?
|
||||
rescue ArgumentError
|
||||
parsed_entry[:value] = Integer( parsed_entry[:value] )
|
||||
end
|
||||
|
||||
parsed_entry[:value] = BigDecimal( parsed_entry[:value], @precision )
|
||||
end
|
||||
|
||||
parsed_tree << parsed_entry
|
||||
end
|
||||
|
||||
parsed_tree
|
||||
end
|
||||
|
||||
def run( input )
|
||||
@dictionary.add_local_vars_layer
|
||||
|
||||
parse( input.to_s ).each do |elt|
|
||||
case elt[:type]
|
||||
when :word
|
||||
break if %w[break quit exit].include?( elt[:value] )
|
||||
|
||||
command = @dictionary.lookup( elt[:value] )
|
||||
|
||||
if command.nil?
|
||||
# if there isn't a command by that name then it's a name
|
||||
elt[:type] = :name
|
||||
|
||||
@stack << elt
|
||||
elsif command.is_a?( Proc )
|
||||
command.call
|
||||
else
|
||||
run( command[:value] )
|
||||
end
|
||||
else
|
||||
@stack << elt
|
||||
end
|
||||
end
|
||||
|
||||
@dictionary.remove_local_vars_layer
|
||||
|
||||
# superfluous but feels nice
|
||||
@stack
|
||||
end
|
||||
|
||||
def stack_extract( needs )
|
||||
raise ArgumentError, 'Not enough elements' if @stack.size < needs.size
|
||||
|
||||
args = []
|
||||
needs.each do |need|
|
||||
raise ArgumentError, "Type Error, needed #{need} got #{elt[:type]}" unless need == :any || need.include?( @stack.last[:type] )
|
||||
|
||||
args << @stack.pop
|
||||
end
|
||||
|
||||
args
|
||||
end
|
||||
|
||||
def stringify( elt )
|
||||
case elt[:type]
|
||||
when :numeric
|
||||
prefix = case elt[:base]
|
||||
when 2
|
||||
'0b'
|
||||
when 8
|
||||
'0o'
|
||||
when 10
|
||||
''
|
||||
when 16
|
||||
'0x'
|
||||
else
|
||||
"0#{elt[:base]}_"
|
||||
end
|
||||
|
||||
if elt[:value].infinite?
|
||||
suffix = elt[:value].infinite?.positive? ? '∞' : '-∞'
|
||||
elsif elt[:value].nan?
|
||||
suffix = '<NaN>'
|
||||
else
|
||||
suffix = if elt[:value].to_i == elt[:value]
|
||||
elt[:value].to_i
|
||||
else
|
||||
elt[:value].to_s('F')
|
||||
end
|
||||
suffix = elt[:value].to_s( elt[:base] ) unless elt[:base] == 10
|
||||
end
|
||||
|
||||
"#{prefix}#{suffix}"
|
||||
when :list
|
||||
"[#{elt[:value].map { |e| stringify( e ) }.join(', ')}]"
|
||||
when :program
|
||||
"« #{elt[:value]} »"
|
||||
when :string
|
||||
"\"#{elt[:value]}\""
|
||||
when :name
|
||||
"'#{elt[:value]}'"
|
||||
else
|
||||
elt[:value]
|
||||
end
|
||||
end
|
||||
|
||||
def infer_resulting_base( numerics )
|
||||
10 if numerics.length.zero?
|
||||
|
||||
numerics.last[:base]
|
||||
end
|
||||
end
|
4
repl.rb
4
repl.rb
|
@ -2,11 +2,11 @@
|
|||
|
||||
require 'readline'
|
||||
|
||||
require './interpreter'
|
||||
require './rpl'
|
||||
|
||||
class RplRepl
|
||||
def initialize
|
||||
@interpreter = Rpl::Interpreter.new
|
||||
@interpreter = Rpl.new
|
||||
end
|
||||
|
||||
def run
|
||||
|
|
553
rpl.rb
Normal file
553
rpl.rb
Normal file
|
@ -0,0 +1,553 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_relative './lib/interpreter'
|
||||
|
||||
require_relative './lib/core/branch'
|
||||
require_relative './lib/core/general'
|
||||
require_relative './lib/core/mode'
|
||||
require_relative './lib/core/operations'
|
||||
require_relative './lib/core/program'
|
||||
require_relative './lib/core/stack'
|
||||
require_relative './lib/core/store'
|
||||
require_relative './lib/core/string'
|
||||
require_relative './lib/core/test'
|
||||
require_relative './lib/core/time-date'
|
||||
require_relative './lib/core/trig'
|
||||
require_relative './lib/core/logs'
|
||||
require_relative './lib/core/filesystem'
|
||||
require_relative './lib/core/list'
|
||||
|
||||
class Rpl < Interpreter
|
||||
def initialize( stack = [], dictionary = Dictionary.new )
|
||||
super
|
||||
|
||||
populate_dictionary if @dictionary.words.empty?
|
||||
end
|
||||
|
||||
include Lang::Core
|
||||
|
||||
def populate_dictionary
|
||||
# GENERAL
|
||||
@dictionary.add_word( ['nop'],
|
||||
'General',
|
||||
'( -- ) no operation',
|
||||
proc { nop } )
|
||||
@dictionary.add_word( ['help'],
|
||||
'General',
|
||||
'( w -- s ) pop help string of the given word',
|
||||
proc { help } )
|
||||
@dictionary.add_word( ['quit'],
|
||||
'General',
|
||||
'( -- ) Stop and quit interpreter',
|
||||
proc {} )
|
||||
@dictionary.add_word( ['version'],
|
||||
'General',
|
||||
'( -- n ) Pop the interpreter\'s version number',
|
||||
proc { version } )
|
||||
@dictionary.add_word( ['uname'],
|
||||
'General',
|
||||
'( -- s ) Pop the interpreter\'s complete indentification string',
|
||||
proc { uname } )
|
||||
@dictionary.add_word( ['history'],
|
||||
'REPL',
|
||||
'',
|
||||
proc {} )
|
||||
@dictionary.add_word( ['.s'],
|
||||
'REPL',
|
||||
'DEBUG',
|
||||
proc { pp @stack } )
|
||||
|
||||
# STACK
|
||||
@dictionary.add_word( ['swap'],
|
||||
'Stack',
|
||||
'( a b -- b a ) swap 2 first stack elements',
|
||||
proc { swap } )
|
||||
@dictionary.add_word( ['drop'],
|
||||
'Stack',
|
||||
'( a -- ) drop first stack element',
|
||||
proc { drop } )
|
||||
@dictionary.add_word( ['drop2'],
|
||||
'Stack',
|
||||
'( a b -- ) drop first two stack elements',
|
||||
proc { drop2 } )
|
||||
@dictionary.add_word( ['dropn'],
|
||||
'Stack',
|
||||
'( a b … n -- ) drop first n stack elements',
|
||||
proc { dropn } )
|
||||
@dictionary.add_word( ['del'],
|
||||
'Stack',
|
||||
'( a b … -- ) drop all stack elements',
|
||||
proc { del } )
|
||||
@dictionary.add_word( ['rot'],
|
||||
'Stack',
|
||||
'( a b c -- b c a ) rotate 3 first stack elements',
|
||||
proc { rot } )
|
||||
@dictionary.add_word( ['dup'],
|
||||
'Stack',
|
||||
'( a -- a a ) duplicate first stack element',
|
||||
proc { dup } )
|
||||
@dictionary.add_word( ['dup2'],
|
||||
'Stack',
|
||||
'( a b -- a b a b ) duplicate first two stack elements',
|
||||
proc { dup2 } )
|
||||
@dictionary.add_word( ['dupn'],
|
||||
'Stack',
|
||||
'( a b … n -- a b … a b … ) duplicate first n stack elements',
|
||||
proc { dupn } )
|
||||
@dictionary.add_word( ['pick'],
|
||||
'Stack',
|
||||
'( … b … n -- … b … b ) push a copy of the given stack level onto the stack',
|
||||
proc { pick } )
|
||||
@dictionary.add_word( ['depth'],
|
||||
'Stack',
|
||||
'( … -- … n ) push stack depth onto the stack',
|
||||
proc { depth } )
|
||||
@dictionary.add_word( ['roll'],
|
||||
'Stack',
|
||||
'( … a -- a … ) move a stack element to the top of the stack',
|
||||
proc { roll } )
|
||||
@dictionary.add_word( ['rolld'],
|
||||
'Stack',
|
||||
'( a … -- … a ) move the element on top of the stack to a higher stack position',
|
||||
proc { rolld } )
|
||||
@dictionary.add_word( ['over'],
|
||||
'Stack',
|
||||
'( a b -- a b a ) push a copy of the element in stack level 2 onto the stack',
|
||||
proc { over } )
|
||||
|
||||
# Usual operations on reals and complexes
|
||||
@dictionary.add_word( ['+'],
|
||||
'Usual operations on reals and complexes',
|
||||
'( a b -- c ) addition',
|
||||
proc { add } )
|
||||
@dictionary.add_word( ['-'],
|
||||
'Usual operations on reals and complexes',
|
||||
'( a b -- c ) subtraction',
|
||||
proc { subtract } )
|
||||
@dictionary.add_word( ['chs'],
|
||||
'Usual operations on reals and complexes',
|
||||
'( a -- b ) negate',
|
||||
proc { negate } )
|
||||
@dictionary.add_word( ['×', '*'],
|
||||
'Usual operations on reals and complexes',
|
||||
'( a b -- c ) multiplication',
|
||||
proc { multiply } ) # alias
|
||||
@dictionary.add_word( ['÷', '/'],
|
||||
'Usual operations on reals and complexes',
|
||||
'( a b -- c ) division',
|
||||
proc { divide } ) # alias
|
||||
@dictionary.add_word( ['inv'],
|
||||
'Usual operations on reals and complexes',
|
||||
'( a -- b ) invert numeric',
|
||||
proc { inverse } )
|
||||
@dictionary.add_word( ['^'],
|
||||
'Usual operations on reals and complexes',
|
||||
'( a b -- c ) a to the power of b',
|
||||
proc { power } )
|
||||
@dictionary.add_word( ['√', 'sqrt'],
|
||||
'Usual operations on reals and complexes',
|
||||
'( a -- b ) square root',
|
||||
proc { sqrt } ) # alias
|
||||
@dictionary.add_word( ['²', 'sq'],
|
||||
'Usual operations on reals and complexes',
|
||||
'( a -- b ) square',
|
||||
proc { sq } )
|
||||
@dictionary.add_word( ['abs'],
|
||||
'Usual operations on reals and complexes',
|
||||
'( a -- b ) absolute value',
|
||||
proc { abs } )
|
||||
@dictionary.add_word( ['dec'],
|
||||
'Usual operations on reals and complexes',
|
||||
'( a -- a ) set numeric\'s base to 10',
|
||||
proc { dec } )
|
||||
@dictionary.add_word( ['hex'],
|
||||
'Usual operations on reals and complexes',
|
||||
'( a -- a ) set numeric\'s base to 16',
|
||||
proc { hex } )
|
||||
@dictionary.add_word( ['bin'],
|
||||
'Usual operations on reals and complexes',
|
||||
'( a -- a ) set numeric\'s base to 2',
|
||||
proc { bin } )
|
||||
@dictionary.add_word( ['base'],
|
||||
'Usual operations on reals and complexes',
|
||||
'( a b -- a ) set numeric\'s base to b',
|
||||
proc { base } )
|
||||
@dictionary.add_word( ['sign'],
|
||||
'Usual operations on reals and complexes',
|
||||
'( a -- b ) sign of element',
|
||||
proc { sign } )
|
||||
|
||||
# Operations on reals
|
||||
@dictionary.add_word( ['%'],
|
||||
'Operations on reals',
|
||||
'( a b -- c ) b% of a',
|
||||
proc { percent } )
|
||||
@dictionary.add_word( ['%CH'],
|
||||
'Operations on reals',
|
||||
'( a b -- c ) b is c% of a',
|
||||
proc { inverse_percent } )
|
||||
@dictionary.add_word( ['mod'],
|
||||
'Operations on reals',
|
||||
'( a b -- c ) modulo',
|
||||
proc { mod } )
|
||||
@dictionary.add_word( ['!', 'fact'],
|
||||
'Operations on reals',
|
||||
'( a -- b ) factorial',
|
||||
proc { fact } )
|
||||
@dictionary.add_word( ['floor'],
|
||||
'Operations on reals',
|
||||
'( a -- b ) highest integer under a',
|
||||
proc { floor } )
|
||||
@dictionary.add_word( ['ceil'],
|
||||
'Operations on reals',
|
||||
'( a -- b ) highest integer over a',
|
||||
proc { ceil } )
|
||||
@dictionary.add_word( ['min'],
|
||||
'Operations on reals',
|
||||
'( a b -- a/b ) leave lowest of a or b',
|
||||
proc { min } )
|
||||
@dictionary.add_word( ['max'],
|
||||
'Operations on reals',
|
||||
'( a b -- a/b ) leave highest of a or b',
|
||||
proc { max } )
|
||||
# @dictionary.add_word( ['mant'],
|
||||
# 'Operations on reals',
|
||||
# '',
|
||||
# proc { __todo } ) # mantissa of a real number
|
||||
# @dictionary.add_word( ['xpon'],
|
||||
# 'Operations on reals',
|
||||
# '',
|
||||
# proc { __todo } ) # exponant of a real number
|
||||
# @dictionary.add_word( ['ip'],
|
||||
# 'Operations on reals',
|
||||
# '',
|
||||
# proc { __todo } ) # integer part
|
||||
# @dictionary.add_word( ['fp'],
|
||||
# 'Operations on reals',
|
||||
# '',
|
||||
# proc { __todo } ) # fractional part
|
||||
|
||||
# OPERATIONS ON COMPLEXES
|
||||
# @dictionary.add_word( ['re'],
|
||||
# proc { __todo } ) # complex real part
|
||||
# @dictionary.add_word( 'im',
|
||||
# proc { __todo } ) # complex imaginary part
|
||||
# @dictionary.add_word( ['conj'],
|
||||
# proc { __todo } ) # complex conjugate
|
||||
# @dictionary.add_word( 'arg',
|
||||
# proc { __todo } ) # complex argument in radians
|
||||
# @dictionary.add_word( ['c->r'],
|
||||
# proc { __todo } ) # transform a complex in 2 reals
|
||||
# @dictionary.add_word( 'c→r',
|
||||
# proc { __todo } ) # alias
|
||||
# @dictionary.add_word( ['r->c'],
|
||||
# proc { __todo } ) # transform 2 reals in a complex
|
||||
# @dictionary.add_word( 'r→c',
|
||||
# proc { __todo } ) # alias
|
||||
# @dictionary.add_word( ['p->r'],
|
||||
# proc { __todo } ) # cartesian to polar
|
||||
# @dictionary.add_word( 'p→r',
|
||||
# proc { __todo } ) # alias
|
||||
# @dictionary.add_word( ['r->p'],
|
||||
# proc { __todo } ) # polar to cartesian
|
||||
# @dictionary.add_word( 'r→p',
|
||||
# proc { __todo } ) # alias
|
||||
|
||||
# Mode
|
||||
@dictionary.add_word( ['prec'],
|
||||
'Mode',
|
||||
'( a -- ) set precision to a',
|
||||
proc { prec } )
|
||||
@dictionary.add_word( ['default'],
|
||||
'Mode',
|
||||
'( -- ) set default precision',
|
||||
proc { default } )
|
||||
@dictionary.add_word( ['type'],
|
||||
'Mode',
|
||||
'( a -- s ) type of a as a string',
|
||||
proc { type } )
|
||||
# @dictionary.add_word( ['std'],
|
||||
# proc { __todo } ) # standard floating numbers representation. ex: std
|
||||
# @dictionary.add_word( ['fix'],
|
||||
# proc { __todo } ) # fixed point representation. ex: 6 fix
|
||||
# @dictionary.add_word( ['sci'],
|
||||
# proc { __todo } ) # scientific floating point representation. ex: 20 sci
|
||||
# @dictionary.add_word( ['round'],
|
||||
# proc { __todo } ) # set float rounding mode. ex: ["nearest", "toward zero", "toward +inf", "toward -inf", "away from zero"] round
|
||||
|
||||
# Test
|
||||
@dictionary.add_word( ['>'],
|
||||
'Test',
|
||||
'( a b -- t ) is a greater than b?',
|
||||
proc { greater_than } )
|
||||
@dictionary.add_word( ['≥', '>='],
|
||||
'Test',
|
||||
'( a b -- t ) is a greater than or equal to b?',
|
||||
proc { greater_than_or_equal } ) # alias
|
||||
@dictionary.add_word( ['<'],
|
||||
'Test',
|
||||
'( a b -- t ) is a less than b?',
|
||||
proc { less_than } )
|
||||
@dictionary.add_word( ['≤', '<='],
|
||||
'Test',
|
||||
'( a b -- t ) is a less than or equal to b?',
|
||||
proc { less_than_or_equal } ) # alias
|
||||
@dictionary.add_word( ['≠', '!='],
|
||||
'Test',
|
||||
'( a b -- t ) is a not equal to b',
|
||||
proc { different } ) # alias
|
||||
@dictionary.add_word( ['==', 'same'],
|
||||
'Test',
|
||||
'( a b -- t ) is a equal to b',
|
||||
proc { same } )
|
||||
@dictionary.add_word( ['and'],
|
||||
'Test',
|
||||
'( a b -- t ) boolean and',
|
||||
proc { boolean_and } )
|
||||
@dictionary.add_word( ['or'],
|
||||
'Test',
|
||||
'( a b -- t ) boolean or',
|
||||
proc { boolean_or } )
|
||||
@dictionary.add_word( ['xor'],
|
||||
'Test',
|
||||
'( a b -- t ) boolean xor',
|
||||
proc { xor } )
|
||||
@dictionary.add_word( ['not'],
|
||||
'Test',
|
||||
'( a -- t ) invert boolean value',
|
||||
proc { boolean_not } )
|
||||
@dictionary.add_word( ['true'],
|
||||
'Test',
|
||||
'( -- t ) push true onto stack',
|
||||
proc { boolean_true } ) # specific
|
||||
@dictionary.add_word( ['false'],
|
||||
'Test',
|
||||
'( -- t ) push false onto stack',
|
||||
proc { boolean_false } ) # specific
|
||||
|
||||
# String
|
||||
@dictionary.add_word( ['→str', '->str'],
|
||||
'String',
|
||||
'( a -- s ) convert element to string',
|
||||
proc { to_string } ) # alias
|
||||
@dictionary.add_word( ['str→', 'str->'],
|
||||
'String',
|
||||
'( s -- a ) convert string to element',
|
||||
proc { from_string } )
|
||||
@dictionary.add_word( ['chr'],
|
||||
'String',
|
||||
'( n -- c ) convert ASCII character code in stack level 1 into a string',
|
||||
proc { chr } )
|
||||
@dictionary.add_word( ['num'],
|
||||
'String',
|
||||
'( s -- n ) return ASCII code of the first character of the string in stack level 1 as a real number',
|
||||
proc { num } )
|
||||
@dictionary.add_word( ['size'],
|
||||
'String',
|
||||
'( s -- n ) return the length of the string',
|
||||
proc { size } )
|
||||
@dictionary.add_word( ['pos'],
|
||||
'String',
|
||||
'( s s -- n ) search for the string in level 1 within the string in level 2',
|
||||
proc { pos } )
|
||||
@dictionary.add_word( ['sub'],
|
||||
'String',
|
||||
'( s n n -- s ) return a substring of the string in level 3',
|
||||
proc { sub } )
|
||||
@dictionary.add_word( ['rev'],
|
||||
'String',
|
||||
'( s -- s ) reverse string',
|
||||
proc { rev } ) # specific
|
||||
@dictionary.add_word( ['split'],
|
||||
'String',
|
||||
'( s c -- … ) split string s on character c',
|
||||
proc { split } ) # specific
|
||||
|
||||
# Branch
|
||||
@dictionary.add_word( ['ift'],
|
||||
'Branch',
|
||||
'( t pt -- … ) eval pt or not based on the value of boolean t',
|
||||
proc { ift } )
|
||||
@dictionary.add_word( ['ifte'],
|
||||
'Branch',
|
||||
'( t pt pf -- … ) eval pt or pf based on the value of boolean t',
|
||||
proc { ifte } )
|
||||
@dictionary.add_word( ['times'],
|
||||
'Branch',
|
||||
'( n p -- … ) eval p n times while pushing counter on stack before',
|
||||
proc { times } ) # specific
|
||||
@dictionary.add_word( ['loop'],
|
||||
'Branch',
|
||||
'( n1 n2 p -- … ) eval p looping from n1 to n2 while pushing counter on stack before',
|
||||
proc { loop } ) # specific
|
||||
|
||||
# Store
|
||||
@dictionary.add_word( ['▶', 'sto'],
|
||||
'Store',
|
||||
'( content name -- ) store to variable',
|
||||
proc { sto } )
|
||||
@dictionary.add_word( ['rcl'],
|
||||
'Store',
|
||||
'( name -- … ) push content of variable name onto stack',
|
||||
proc { rcl } )
|
||||
@dictionary.add_word( ['purge'],
|
||||
'Store',
|
||||
'( name -- ) delete variable',
|
||||
proc { purge } )
|
||||
@dictionary.add_word( ['vars'],
|
||||
'Store',
|
||||
'( -- […] ) list variables',
|
||||
proc { vars } )
|
||||
@dictionary.add_word( ['clusr'],
|
||||
'Store',
|
||||
'( -- ) delete all variables',
|
||||
proc { clusr } )
|
||||
@dictionary.add_word( ['sto+'],
|
||||
'Store',
|
||||
'( a n -- ) add content to variable\'s value',
|
||||
proc { sto_add } )
|
||||
@dictionary.add_word( ['sto-'],
|
||||
'Store',
|
||||
'( a n -- ) subtract content to variable\'s value',
|
||||
proc { sto_subtract } )
|
||||
@dictionary.add_word( ['sto×', 'sto*'],
|
||||
'Store',
|
||||
'( a n -- ) multiply content of variable\'s value',
|
||||
proc { sto_multiply } ) # alias
|
||||
@dictionary.add_word( ['sto÷', 'sto/'],
|
||||
'Store',
|
||||
'( a n -- ) divide content of variable\'s value',
|
||||
proc { sto_divide } ) # alias
|
||||
@dictionary.add_word( ['sneg'],
|
||||
'Store',
|
||||
'( a n -- ) negate content of variable\'s value',
|
||||
proc { sto_negate } )
|
||||
@dictionary.add_word( ['sinv'],
|
||||
'Store',
|
||||
'( a n -- ) invert content of variable\'s value',
|
||||
proc { sto_inverse } )
|
||||
@dictionary.add_word( ['↴', 'lsto'],
|
||||
'Program',
|
||||
'( content name -- ) store to local variable',
|
||||
proc { lsto } )
|
||||
|
||||
# Program
|
||||
@dictionary.add_word( ['eval'],
|
||||
'Program',
|
||||
'( a -- … ) interpret',
|
||||
proc { eval } )
|
||||
|
||||
# Trig on reals and complexes
|
||||
@dictionary.add_word( ['𝛑', 'pi'],
|
||||
'Trig on reals and complexes',
|
||||
'( … -- 𝛑 ) push 𝛑',
|
||||
proc { pi } )
|
||||
@dictionary.add_word( ['sin'],
|
||||
'Trig on reals and complexes',
|
||||
'( n -- m ) compute sinus of n',
|
||||
proc { sinus } ) # sinus
|
||||
@dictionary.add_word( ['asin'],
|
||||
'Trig on reals and complexes',
|
||||
'( n -- m ) compute arg-sinus of n',
|
||||
proc { arg_sinus } ) # arg sinus
|
||||
@dictionary.add_word( ['cos'],
|
||||
'Trig on reals and complexes',
|
||||
'( n -- m ) compute cosinus of n',
|
||||
proc { cosinus } ) # cosinus
|
||||
@dictionary.add_word( ['acos'],
|
||||
'Trig on reals and complexes',
|
||||
'( n -- m ) compute arg-cosinus of n',
|
||||
proc { arg_cosinus } ) # arg cosinus
|
||||
@dictionary.add_word( ['tan'],
|
||||
'Trig on reals and complexes',
|
||||
'( n -- m ) compute tangent of n',
|
||||
proc { tangent } ) # tangent
|
||||
@dictionary.add_word( ['atan'],
|
||||
'Trig on reals and complexes',
|
||||
'( n -- m ) compute arc-tangent of n',
|
||||
proc { arg_tangent } ) # arg tangent
|
||||
@dictionary.add_word( ['d→r', 'd->r'],
|
||||
'Trig on reals and complexes',
|
||||
'( n -- m ) convert degree to radian',
|
||||
proc { degrees_to_radians } ) # convert degrees to radians
|
||||
@dictionary.add_word( ['r→d', 'r->d'],
|
||||
'Trig on reals and complexes',
|
||||
'( n -- m ) convert radian to degree',
|
||||
proc { radians_to_degrees } ) # convert radians to degrees
|
||||
|
||||
# Logs on reals and complexes
|
||||
@dictionary.add_word( ['ℇ', 'e'],
|
||||
'Logs on reals and complexes',
|
||||
'( … -- ℇ ) push ℇ',
|
||||
proc { e } ) # alias
|
||||
# @dictionary.add_word( 'ln',
|
||||
# proc { __todo } ) # logarithm base e
|
||||
# @dictionary.add_word( 'lnp1',
|
||||
# proc { __todo } ) # ln(1+x) which is useful when x is close to 0
|
||||
# @dictionary.add_word( 'exp',
|
||||
# proc { __todo } ) # exponential
|
||||
# @dictionary.add_word( 'expm',
|
||||
# proc { __todo } ) # exp(x)-1 which is useful when x is close to 0
|
||||
# @dictionary.add_word( 'log10',
|
||||
# proc { __todo } ) # logarithm base 10
|
||||
# @dictionary.add_word( 'alog10',
|
||||
# proc { __todo } ) # exponential base 10
|
||||
# @dictionary.add_word( 'log2',
|
||||
# proc { __todo } ) # logarithm base 2
|
||||
# @dictionary.add_word( 'alog2',
|
||||
# proc { __todo } ) # exponential base 2
|
||||
# @dictionary.add_word( 'sinh',
|
||||
# proc { __todo } ) # hyperbolic sine
|
||||
# @dictionary.add_word( 'asinh',
|
||||
# proc { __todo } ) # inverse hyperbolic sine
|
||||
# @dictionary.add_word( 'cosh',
|
||||
# proc { __todo } ) # hyperbolic cosine
|
||||
# @dictionary.add_word( 'acosh',
|
||||
# proc { __todo } ) # inverse hyperbolic cosine
|
||||
# @dictionary.add_word( 'tanh',
|
||||
# proc { __todo } ) # hyperbolic tangent
|
||||
# @dictionary.add_word( 'atanh',
|
||||
# proc { __todo } ) # inverse hyperbolic tangent
|
||||
|
||||
# Time and date
|
||||
@dictionary.add_word( ['time'],
|
||||
'Time and date',
|
||||
'( -- t ) push current time',
|
||||
proc { time } )
|
||||
@dictionary.add_word( ['date'],
|
||||
'Time and date',
|
||||
'( -- d ) push current date',
|
||||
proc { date } )
|
||||
@dictionary.add_word( ['ticks'],
|
||||
'Time and date',
|
||||
'( -- t ) push datetime as ticks',
|
||||
proc { ticks } )
|
||||
|
||||
# Rpl.rb specifics
|
||||
# Lists
|
||||
@dictionary.add_word( ['→list', '->list'],
|
||||
'Lists',
|
||||
'( … x -- […] ) pack x stacks levels into a list',
|
||||
proc { to_list } )
|
||||
@dictionary.add_word( ['list→', 'list->'],
|
||||
'Lists',
|
||||
'( […] -- … ) unpack list on stack',
|
||||
proc { unpack_list } )
|
||||
|
||||
# Filesystem
|
||||
@dictionary.add_word( ['fread'],
|
||||
'Filesystem',
|
||||
'( filename -- content ) read file and put content on stack as string',
|
||||
proc { fread } )
|
||||
@dictionary.add_word( ['feval'],
|
||||
'Filesystem',
|
||||
'( filename -- … ) read and run file',
|
||||
proc { feval } )
|
||||
@dictionary.add_word( ['fwrite'],
|
||||
'Filesystem',
|
||||
'( content filename -- ) write content into filename',
|
||||
proc { fwrite } )
|
||||
|
||||
# Graphics
|
||||
end
|
||||
end
|
|
@ -2,20 +2,20 @@
|
|||
|
||||
require 'test/unit'
|
||||
|
||||
require_relative '../interpreter'
|
||||
require_relative '../rpl'
|
||||
|
||||
class TestParser < Test::Unit::TestCase
|
||||
def test_stack_extract
|
||||
interpreter = Rpl::Interpreter.new( [{ value: 1, type: :numeric },
|
||||
{ value: 2, type: :numeric }] )
|
||||
interpreter = Rpl.new( [{ value: 1, type: :numeric },
|
||||
{ value: 2, type: :numeric }] )
|
||||
args = interpreter.stack_extract [:any]
|
||||
assert_equal [{ value: 1, type: :numeric }],
|
||||
interpreter.stack
|
||||
assert_equal [{ value: 2, type: :numeric }],
|
||||
args
|
||||
|
||||
interpreter = Rpl::Interpreter.new( [{ value: 'test', type: :string },
|
||||
{ value: 2, type: :numeric }] )
|
||||
interpreter = Rpl.new( [{ value: 'test', type: :string },
|
||||
{ value: 2, type: :numeric }] )
|
||||
args = interpreter.stack_extract [[:numeric], :any]
|
||||
assert_equal [],
|
||||
interpreter.stack
|
||||
|
@ -26,8 +26,8 @@ class TestParser < Test::Unit::TestCase
|
|||
|
||||
def test_stringify
|
||||
assert_equal '∞',
|
||||
Rpl::Interpreter.new.stringify( { value: Float::INFINITY,
|
||||
base: 10,
|
||||
type: :numeric } )
|
||||
Rpl.new.stringify( { value: Float::INFINITY,
|
||||
base: 10,
|
||||
type: :numeric } )
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
|
||||
require 'test/unit'
|
||||
|
||||
require_relative '../interpreter'
|
||||
require_relative '../rpl'
|
||||
|
||||
class TestLanguageBranch < Test::Unit::TestCase
|
||||
def test_loop
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '11 16 « "hello no." swap + » loop'
|
||||
|
||||
assert_equal [{ value: 'hello no.11', type: :string },
|
||||
|
@ -20,7 +20,7 @@ class TestLanguageBranch < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_times
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '5 « "hello no." swap + » times'
|
||||
|
||||
assert_equal [{ value: 'hello no.0', type: :string },
|
||||
|
@ -32,13 +32,13 @@ class TestLanguageBranch < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_ifte
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run 'true « 2 3 + » « 2 3 - » ifte'
|
||||
|
||||
assert_equal [{ value: 5, type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run 'false « 2 3 + » « 2 3 - » ifte'
|
||||
|
||||
assert_equal [{ value: -1, type: :numeric, base: 10 }],
|
||||
|
@ -46,13 +46,13 @@ class TestLanguageBranch < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_ift
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run 'true « 2 3 + » ift'
|
||||
|
||||
assert_equal [{ value: 5, type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run 'false « 2 3 + » ift'
|
||||
|
||||
assert_equal [],
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
|
||||
require 'test/unit'
|
||||
|
||||
require_relative '../interpreter'
|
||||
require_relative '../rpl'
|
||||
|
||||
class TestLanguageFileSystem < Test::Unit::TestCase
|
||||
def test_fread
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '"spec/test.rpl" fread'
|
||||
|
||||
assert_equal [{ value: "1 2 +
|
||||
|
@ -26,7 +26,7 @@ trrr
|
|||
end
|
||||
|
||||
def test_feval
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '"spec/test.rpl" feval vars'
|
||||
assert_equal [{ value: 27, base: 10, type: :numeric },
|
||||
{ value: [{ type: :name, value: 'trrr' }], type: :list }],
|
||||
|
@ -34,7 +34,7 @@ trrr
|
|||
end
|
||||
|
||||
def test_fwrite
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '"Ceci est un test de fwrite" "spec/test_fwrite.txt" fwrite'
|
||||
assert_equal [],
|
||||
interpreter.stack
|
||||
|
|
|
@ -3,77 +3,77 @@
|
|||
|
||||
require 'test/unit'
|
||||
|
||||
require_relative '../interpreter'
|
||||
require_relative '../rpl'
|
||||
|
||||
class TesttLanguageOperations < Test::Unit::TestCase
|
||||
def test_add
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '1 2 +'
|
||||
assert_equal [{ value: 3, type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '1 "a" +'
|
||||
assert_equal [{ value: '1a', type: :string }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '1 \'a\' +'
|
||||
assert_equal [{ value: '1a', type: :string }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '1 dup dup →list +'
|
||||
assert_equal [{ value: [{ value: 1, type: :numeric, base: 10 },
|
||||
{ value: 1, type: :numeric, base: 10 }],
|
||||
type: :list }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '"a" "b" +'
|
||||
assert_equal [{ value: 'ab', type: :string }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '"a" \'b\' +'
|
||||
assert_equal [{ value: 'ab', type: :string }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '"a" 1 +'
|
||||
assert_equal [{ value: 'a1', type: :string }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '"a" 1 dup →list +'
|
||||
assert_equal [{ value: [{ value: 'a', type: :string },
|
||||
{ value: 1, type: :numeric, base: 10 }],
|
||||
type: :list }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '\'a\' 1 +'
|
||||
assert_equal [{ value: 'a1', type: :name }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '\'a\' "b" +'
|
||||
assert_equal [{ value: 'ab', type: :string }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '\'a\' \'b\' +'
|
||||
assert_equal [{ value: 'ab', type: :name }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '\'a\' 1 dup →list +'
|
||||
assert_equal [{ value: [{ value: 'a', type: :name },
|
||||
{ value: 1, type: :numeric, base: 10 }],
|
||||
type: :list }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '1 a "test" 3 →list dup rev +'
|
||||
assert_equal [{ type: :list,
|
||||
value: [{ value: 1, type: :numeric, base: 10 },
|
||||
|
@ -84,7 +84,7 @@ class TesttLanguageOperations < Test::Unit::TestCase
|
|||
{ value: 1, type: :numeric, base: 10 }] }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '1 a "test" 3 →list 9 +'
|
||||
assert_equal [{ type: :list,
|
||||
value: [{ value: 1, type: :numeric, base: 10 },
|
||||
|
@ -95,189 +95,189 @@ class TesttLanguageOperations < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_subtract
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '1 2 -'
|
||||
assert_equal [{ value: -1, type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '2 1 -'
|
||||
assert_equal [{ value: 1, type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
end
|
||||
|
||||
def test_negate
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '-1 chs'
|
||||
assert_equal [{ value: 1, type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '1 chs'
|
||||
assert_equal [{ value: -1, type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
end
|
||||
|
||||
def test_multiply
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '3 4 *'
|
||||
assert_equal [{ value: 12, type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
end
|
||||
|
||||
def test_divide
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '3.0 4 /'
|
||||
assert_equal [{ value: 0.75, type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
end
|
||||
|
||||
def test_inverse
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '4 inv'
|
||||
assert_equal [{ value: 0.25, type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
end
|
||||
|
||||
def test_power
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '3 4 ^'
|
||||
assert_equal [{ value: 81, type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
end
|
||||
|
||||
def test_sqrt
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '16 √'
|
||||
assert_equal [{ value: 4, type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
end
|
||||
|
||||
def test_sq
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '4 sq'
|
||||
assert_equal [{ value: 16, type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
end
|
||||
|
||||
def test_abs
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '-1 abs'
|
||||
assert_equal [{ value: 1, type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '1 abs'
|
||||
assert_equal [{ value: 1, type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
end
|
||||
|
||||
def test_dec
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '0x1 dec'
|
||||
assert_equal [{ value: 1, type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
end
|
||||
|
||||
def test_hex
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '1 hex'
|
||||
assert_equal [{ value: 1, type: :numeric, base: 16 }],
|
||||
interpreter.stack
|
||||
end
|
||||
|
||||
def test_bin
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '1 bin'
|
||||
assert_equal [{ value: 1, type: :numeric, base: 2 }],
|
||||
interpreter.stack
|
||||
end
|
||||
|
||||
def test_base
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '1 31 base'
|
||||
assert_equal [{ value: 1, type: :numeric, base: 31 }],
|
||||
interpreter.stack
|
||||
end
|
||||
|
||||
def test_sign
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '-10 sign'
|
||||
assert_equal [{ value: -1, type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '10 sign'
|
||||
assert_equal [{ value: 1, type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '0 sign'
|
||||
assert_equal [{ value: 0, type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
end
|
||||
|
||||
def test_percent
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '2 33 %'
|
||||
assert_equal [{ value: 0.66, type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
end
|
||||
|
||||
def test_inverse_percent
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '2 0.66 %CH'
|
||||
assert_equal [{ value: 33, type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
end
|
||||
|
||||
def test_mod
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '9 4 mod'
|
||||
assert_equal [{ value: 1, type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
end
|
||||
|
||||
def test_fact
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '5 !'
|
||||
assert_equal [{ value: 24, type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
end
|
||||
|
||||
def test_floor
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '5.23 floor'
|
||||
assert_equal [{ value: 5, type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
end
|
||||
|
||||
def test_ceil
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '5.23 ceil'
|
||||
assert_equal [{ value: 6, type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
end
|
||||
|
||||
def test_min
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '1 2 min'
|
||||
assert_equal [{ value: 1, type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '2 1 min'
|
||||
assert_equal [{ value: 1, type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
end
|
||||
|
||||
def test_max
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '1 2 max'
|
||||
assert_equal [{ value: 2, type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '2 1 max'
|
||||
assert_equal [{ value: 2, type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
|
|
|
@ -2,18 +2,18 @@
|
|||
|
||||
require 'test/unit'
|
||||
|
||||
require_relative '../interpreter'
|
||||
require_relative '../rpl'
|
||||
|
||||
class TestLanguageProgram < Test::Unit::TestCase
|
||||
def test_eval
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '« 2 dup * dup » eval'
|
||||
|
||||
assert_equal [{ value: 4, type: :numeric, base: 10 },
|
||||
{ value: 4, type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '4 \'dup\' eval'
|
||||
|
||||
assert_equal [{ value: 4, type: :numeric, base: 10 },
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
|
||||
require 'test/unit'
|
||||
|
||||
require_relative '../interpreter'
|
||||
require_relative '../rpl'
|
||||
|
||||
class TestLanguageStack < Test::Unit::TestCase
|
||||
def test_swap
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '1 2 swap'
|
||||
|
||||
assert_equal [{ value: 2, type: :numeric, base: 10 },
|
||||
|
@ -16,7 +16,7 @@ class TestLanguageStack < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_drop
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '1 2 drop'
|
||||
|
||||
assert_equal [{ value: 1, type: :numeric, base: 10 }],
|
||||
|
@ -24,7 +24,7 @@ class TestLanguageStack < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_drop2
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '1 2 drop2'
|
||||
|
||||
assert_equal [],
|
||||
|
@ -32,7 +32,7 @@ class TestLanguageStack < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_dropn
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '1 2 3 4 3 dropn'
|
||||
|
||||
assert_equal [{ value: 1, type: :numeric, base: 10 }],
|
||||
|
@ -40,14 +40,14 @@ class TestLanguageStack < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_del
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '1 2 del'
|
||||
|
||||
assert_empty interpreter.stack
|
||||
end
|
||||
|
||||
def test_rot
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '1 2 3 rot'
|
||||
|
||||
assert_equal [{ value: 2, type: :numeric, base: 10 },
|
||||
|
@ -57,7 +57,7 @@ class TestLanguageStack < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_dup
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '1 2 dup'
|
||||
|
||||
assert_equal [{ value: 1, type: :numeric, base: 10 },
|
||||
|
@ -67,7 +67,7 @@ class TestLanguageStack < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_dup2
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '1 2 dup2'
|
||||
|
||||
assert_equal [{ value: 1, type: :numeric, base: 10 },
|
||||
|
@ -78,7 +78,7 @@ class TestLanguageStack < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_dupn
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '1 2 3 4 3 dupn'
|
||||
|
||||
assert_equal [{ value: 1, type: :numeric, base: 10 },
|
||||
|
@ -92,7 +92,7 @@ class TestLanguageStack < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_pick
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '1 2 3 4 3 pick'
|
||||
|
||||
assert_equal [{ value: 1, type: :numeric, base: 10 },
|
||||
|
@ -104,13 +104,13 @@ class TestLanguageStack < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_depth
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run 'depth'
|
||||
|
||||
assert_equal [{ value: 0, type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '1 2 depth'
|
||||
|
||||
assert_equal [{ value: 1, type: :numeric, base: 10 },
|
||||
|
@ -120,7 +120,7 @@ class TestLanguageStack < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_roll
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '1 2 3 4 3 roll'
|
||||
|
||||
assert_equal [{ value: 1, type: :numeric, base: 10 },
|
||||
|
@ -131,7 +131,7 @@ class TestLanguageStack < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_rolld
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '1 2 4 3 2 rolld'
|
||||
|
||||
assert_equal [{ value: 1, type: :numeric, base: 10 },
|
||||
|
@ -142,7 +142,7 @@ class TestLanguageStack < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_over
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '1 2 3 4 over'
|
||||
|
||||
assert_equal [{ value: 1, type: :numeric, base: 10 },
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
|
||||
require 'test/unit'
|
||||
|
||||
require_relative '../interpreter'
|
||||
require_relative '../rpl'
|
||||
|
||||
class TestLanguageProgram < Test::Unit::TestCase
|
||||
def test_sto
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '« 2 dup * » \'quatre\' sto'
|
||||
assert_empty interpreter.stack
|
||||
|
||||
|
@ -16,14 +16,14 @@ class TestLanguageProgram < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_lsto
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run "« 2 'deux' lsto deux dup * » eval 'deux' rcl"
|
||||
|
||||
assert_empty interpreter.dictionary.local_vars_layers
|
||||
assert_equal [{ value: 4, type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run "« 2 'deux' lsto « 3 'trois' lsto trois drop » eval deux dup * » eval 'deux' rcl 'trois' rcl"
|
||||
|
||||
assert_empty interpreter.dictionary.local_vars_layers
|
||||
|
@ -32,20 +32,20 @@ class TestLanguageProgram < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_rcl
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '« 2 dup * » \'quatre\' sto \'quatre\' rcl'
|
||||
assert_equal [{ value: '2 dup *', type: :program }],
|
||||
interpreter.stack
|
||||
end
|
||||
|
||||
def test_purge
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '« 2 dup * » \'quatre\' sto \'quatre\' purge'
|
||||
assert_nil interpreter.dictionary.lookup( 'quatre' )
|
||||
end
|
||||
|
||||
def test_vars
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '« 2 dup * » \'quatre\' sto 1 \'un\' sto vars'
|
||||
assert_equal [{ value: [{ type: :name, value: 'quatre' },
|
||||
{ type: :name, value: 'un' }], type: :list }],
|
||||
|
@ -53,68 +53,68 @@ class TestLanguageProgram < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_clusr
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '« 2 dup * » \'quatre\' sto 1 \'un\' sto clusr'
|
||||
assert_empty interpreter.dictionary.vars
|
||||
end
|
||||
|
||||
def test_sto_add
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '1 \'test\' sto \'test\' 3 sto+ \'test\' rcl'
|
||||
assert_equal [{ value: 4, type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '1 \'test\' sto 3 \'test\' sto+ \'test\' rcl'
|
||||
assert_equal [{ value: 4, type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
end
|
||||
|
||||
def test_sto_subtract
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '1 \'test\' sto \'test\' 3 sto- \'test\' rcl'
|
||||
assert_equal [{ value: -2, type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '1 \'test\' sto 3 \'test\' sto- \'test\' rcl'
|
||||
assert_equal [{ value: -2, type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
end
|
||||
|
||||
def test_sto_multiply
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '2 \'test\' sto \'test\' 3 sto* \'test\' rcl'
|
||||
assert_equal [{ value: 6, type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '2 \'test\' sto 3 \'test\' sto* \'test\' rcl'
|
||||
assert_equal [{ value: 6, type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
end
|
||||
|
||||
def test_sto_divide
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '3 \'test\' sto \'test\' 2.0 sto÷ \'test\' rcl'
|
||||
assert_equal [{ value: 1.5, type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '3 \'test\' sto 2.0 \'test\' sto÷ \'test\' rcl'
|
||||
assert_equal [{ value: 1.5, type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
end
|
||||
|
||||
def test_sto_negate
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '3 \'test\' sto \'test\' sneg \'test\' rcl'
|
||||
assert_equal [{ value: -3, type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
end
|
||||
|
||||
def test_sto_inverse
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '2 \'test\' sto \'test\' sinv \'test\' rcl'
|
||||
assert_equal [{ value: 0.5, type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
|
||||
require 'test/unit'
|
||||
|
||||
require_relative '../interpreter'
|
||||
require_relative '../rpl'
|
||||
|
||||
class TestLanguageString < Test::Unit::TestCase
|
||||
def test_to_string
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '2 →str'
|
||||
|
||||
assert_equal [{ value: '2', type: :string }],
|
||||
|
@ -15,13 +15,13 @@ class TestLanguageString < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_from_string
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '"2" str→'
|
||||
|
||||
assert_equal [{ value: 2, type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '"« dup * » \'carré\' sto" str→'
|
||||
|
||||
assert_equal [{ value: 'dup *', type: :program },
|
||||
|
@ -31,7 +31,7 @@ class TestLanguageString < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_chr
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '71 chr'
|
||||
|
||||
assert_equal [{ value: 'G', type: :string }],
|
||||
|
@ -39,7 +39,7 @@ class TestLanguageString < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_num
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '"G" num'
|
||||
|
||||
assert_equal [{ value: 71, type: :numeric, base: 10 }],
|
||||
|
@ -47,7 +47,7 @@ class TestLanguageString < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_size
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '"test" size'
|
||||
|
||||
assert_equal [{ value: 4, type: :numeric, base: 10 }],
|
||||
|
@ -55,7 +55,7 @@ class TestLanguageString < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_pos
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '"test of POS" "of" pos'
|
||||
|
||||
assert_equal [{ value: 5, type: :numeric, base: 10 }],
|
||||
|
@ -63,7 +63,7 @@ class TestLanguageString < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_sub
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '"my string to sub" 4 6 sub'
|
||||
|
||||
assert_equal [{ value: 'str', type: :string }],
|
||||
|
@ -71,7 +71,7 @@ class TestLanguageString < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_rev
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '"my string to sub" rev'
|
||||
|
||||
assert_equal [{ value: 'my string to sub'.reverse, type: :string }],
|
||||
|
@ -79,7 +79,7 @@ class TestLanguageString < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_split
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '"my string to sub" " " split'
|
||||
|
||||
assert_equal [{ value: 'my', type: :string },
|
||||
|
@ -88,7 +88,7 @@ class TestLanguageString < Test::Unit::TestCase
|
|||
{ value: 'sub', type: :string }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '"my,string,to sub" "," split'
|
||||
|
||||
assert_equal [{ value: 'my', type: :string },
|
||||
|
|
|
@ -3,23 +3,23 @@
|
|||
|
||||
require 'test/unit'
|
||||
|
||||
require_relative '../interpreter'
|
||||
require_relative '../rpl'
|
||||
|
||||
class TestLanguageTest < Test::Unit::TestCase
|
||||
def test_greater_than
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '0 0.1 >'
|
||||
|
||||
assert_equal [{ value: false, type: :boolean }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '0.1 0 >'
|
||||
|
||||
assert_equal [{ value: true, type: :boolean }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '1 1 >'
|
||||
|
||||
assert_equal [{ value: false, type: :boolean }],
|
||||
|
@ -27,19 +27,19 @@ class TestLanguageTest < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_greater_than_or_equal
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '0 0.1 >='
|
||||
|
||||
assert_equal [{ value: false, type: :boolean }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '0.1 0 ≥'
|
||||
|
||||
assert_equal [{ value: true, type: :boolean }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '1 1 ≥'
|
||||
|
||||
assert_equal [{ value: true, type: :boolean }],
|
||||
|
@ -47,19 +47,19 @@ class TestLanguageTest < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_less_than
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '0 0.1 <'
|
||||
|
||||
assert_equal [{ value: true, type: :boolean }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '0.1 0 <'
|
||||
|
||||
assert_equal [{ value: false, type: :boolean }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '1 1 <'
|
||||
|
||||
assert_equal [{ value: false, type: :boolean }],
|
||||
|
@ -67,19 +67,19 @@ class TestLanguageTest < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_less_than_or_equal
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '0 0.1 <='
|
||||
|
||||
assert_equal [{ value: true, type: :boolean }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '0.1 0 ≤'
|
||||
|
||||
assert_equal [{ value: false, type: :boolean }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '1 1 ≤'
|
||||
|
||||
assert_equal [{ value: true, type: :boolean }],
|
||||
|
@ -87,13 +87,13 @@ class TestLanguageTest < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_different
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '1 1 !='
|
||||
|
||||
assert_equal [{ value: false, type: :boolean }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '1 2 ≠'
|
||||
|
||||
assert_equal [{ value: true, type: :boolean }],
|
||||
|
@ -101,25 +101,25 @@ class TestLanguageTest < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_and
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run 'true true and'
|
||||
|
||||
assert_equal [{ value: true, type: :boolean }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run 'false false and'
|
||||
|
||||
assert_equal [{ value: false, type: :boolean }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run 'true false and'
|
||||
|
||||
assert_equal [{ value: false, type: :boolean }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run 'false true and'
|
||||
|
||||
assert_equal [{ value: false, type: :boolean }],
|
||||
|
@ -127,25 +127,25 @@ class TestLanguageTest < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_or
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run 'true true or'
|
||||
|
||||
assert_equal [{ value: true, type: :boolean }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run 'false false or'
|
||||
|
||||
assert_equal [{ value: false, type: :boolean }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run 'true false or'
|
||||
|
||||
assert_equal [{ value: true, type: :boolean }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run 'false true or'
|
||||
|
||||
assert_equal [{ value: true, type: :boolean }],
|
||||
|
@ -153,25 +153,25 @@ class TestLanguageTest < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_xor
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run 'true true xor'
|
||||
|
||||
assert_equal [{ value: false, type: :boolean }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run 'false false xor'
|
||||
|
||||
assert_equal [{ value: false, type: :boolean }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run 'true false xor'
|
||||
|
||||
assert_equal [{ value: true, type: :boolean }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run 'false true xor'
|
||||
|
||||
assert_equal [{ value: true, type: :boolean }],
|
||||
|
@ -179,13 +179,13 @@ class TestLanguageTest < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_not
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run 'true not'
|
||||
|
||||
assert_equal [{ value: false, type: :boolean }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run 'false not'
|
||||
|
||||
assert_equal [{ value: true, type: :boolean }],
|
||||
|
@ -193,13 +193,13 @@ class TestLanguageTest < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_same
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '1 1 same'
|
||||
|
||||
assert_equal [{ value: true, type: :boolean }],
|
||||
interpreter.stack
|
||||
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '1 2 =='
|
||||
|
||||
assert_equal [{ value: false, type: :boolean }],
|
||||
|
@ -207,7 +207,7 @@ class TestLanguageTest < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_true
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run 'true'
|
||||
|
||||
assert_equal [{ value: true, type: :boolean }],
|
||||
|
@ -215,7 +215,7 @@ class TestLanguageTest < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_false
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run 'false'
|
||||
|
||||
assert_equal [{ value: false, type: :boolean }],
|
||||
|
|
|
@ -3,12 +3,12 @@
|
|||
|
||||
require 'test/unit'
|
||||
|
||||
require_relative '../interpreter'
|
||||
require_relative '../rpl'
|
||||
|
||||
class TestLanguageTimeDate < Test::Unit::TestCase
|
||||
def test_time
|
||||
now = Time.now.to_s
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run 'time'
|
||||
|
||||
assert_equal [{ value: now, type: :string }],
|
||||
|
@ -17,7 +17,7 @@ class TestLanguageTimeDate < Test::Unit::TestCase
|
|||
|
||||
def test_date
|
||||
now = Date.today.to_s
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run 'date'
|
||||
|
||||
assert_equal [{ value: now, type: :string }],
|
||||
|
@ -25,7 +25,7 @@ class TestLanguageTimeDate < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_ticks
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run 'ticks'
|
||||
|
||||
# TODO: better test, but how?
|
||||
|
|
|
@ -3,60 +3,60 @@
|
|||
|
||||
require 'test/unit'
|
||||
|
||||
require_relative '../interpreter'
|
||||
require_relative '../rpl'
|
||||
|
||||
class TesttLanguageOperations < Test::Unit::TestCase
|
||||
def test_pi
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run 'pi'
|
||||
assert_equal [{ value: BigMath.PI( interpreter.precision ), type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
end
|
||||
|
||||
def test_sin
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '3 sin'
|
||||
assert_equal [{ value: BigMath.sin( BigDecimal( 3 ), interpreter.precision ), type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
end
|
||||
|
||||
def test_asin
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '1 asin pi 2 / =='
|
||||
assert_equal [{ value: true, type: :boolean }],
|
||||
interpreter.stack
|
||||
end
|
||||
|
||||
def test_cos
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '3 cos'
|
||||
assert_equal [{ value: BigMath.cos( BigDecimal( 3 ), interpreter.precision ), type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
end
|
||||
|
||||
def test_acos
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '0 acos pi 2 / =='
|
||||
assert_equal [{ value: true, type: :boolean }],
|
||||
interpreter.stack
|
||||
end
|
||||
|
||||
def test_tan
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '0 tan 0 =='
|
||||
assert_equal [{ value: true, type: :boolean }],
|
||||
interpreter.stack
|
||||
end
|
||||
|
||||
def test_atan
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '1 atan'
|
||||
assert_equal [{ value: BigMath.atan( BigDecimal( 1 ), interpreter.precision ), type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
end
|
||||
|
||||
def test_d→r
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run '90 d→r'
|
||||
assert_equal [{ value: BigMath.PI( interpreter.precision ) / 2,
|
||||
type: :numeric, base: 10 }],
|
||||
|
@ -64,7 +64,7 @@ class TesttLanguageOperations < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_r→d
|
||||
interpreter = Rpl::Interpreter.new
|
||||
interpreter = Rpl.new
|
||||
interpreter.run 'pi r→d'
|
||||
assert_equal [{ value: 180, type: :numeric, base: 10 }],
|
||||
interpreter.stack
|
||||
|
|
|
@ -3,116 +3,116 @@
|
|||
|
||||
require 'test/unit'
|
||||
|
||||
require_relative '../interpreter'
|
||||
require_relative '../rpl'
|
||||
|
||||
class TestParser < Test::Unit::TestCase
|
||||
def test_number
|
||||
result = Rpl::Interpreter.new.parse( '1' )
|
||||
result = Rpl.new.parse( '1' )
|
||||
assert_equal [{ value: 1, type: :numeric, base: 10 }], result
|
||||
end
|
||||
|
||||
def test_word
|
||||
result = Rpl::Interpreter.new.parse( 'dup' )
|
||||
result = Rpl.new.parse( 'dup' )
|
||||
assert_equal [{ value: 'dup', type: :word }], result
|
||||
end
|
||||
|
||||
def test_string
|
||||
result = Rpl::Interpreter.new.parse( '"test"' )
|
||||
result = Rpl.new.parse( '"test"' )
|
||||
assert_equal [{ value: 'test', type: :string }], result
|
||||
|
||||
result = Rpl::Interpreter.new.parse( '" test"' )
|
||||
result = Rpl.new.parse( '" test"' )
|
||||
assert_equal [{ value: ' test', type: :string }], result
|
||||
|
||||
result = Rpl::Interpreter.new.parse( '"test "' )
|
||||
result = Rpl.new.parse( '"test "' )
|
||||
assert_equal [{ value: 'test ', type: :string }], result
|
||||
|
||||
result = Rpl::Interpreter.new.parse( '" test "' )
|
||||
result = Rpl.new.parse( '" test "' )
|
||||
assert_equal [{ value: ' test ', type: :string }], result
|
||||
|
||||
result = Rpl::Interpreter.new.parse( '" « test » "' )
|
||||
result = Rpl.new.parse( '" « test » "' )
|
||||
assert_equal [{ value: ' « test » ', type: :string }], result
|
||||
end
|
||||
|
||||
def test_name
|
||||
result = Rpl::Interpreter.new.parse( "'test'" )
|
||||
result = Rpl.new.parse( "'test'" )
|
||||
assert_equal [{ value: 'test', type: :name }], result
|
||||
end
|
||||
|
||||
def test_program
|
||||
result = Rpl::Interpreter.new.parse( '« test »' )
|
||||
result = Rpl.new.parse( '« test »' )
|
||||
assert_equal [{ value: 'test', type: :program }], result
|
||||
|
||||
result = Rpl::Interpreter.new.parse( '«test »' )
|
||||
result = Rpl.new.parse( '«test »' )
|
||||
assert_equal [{ value: 'test', type: :program }], result
|
||||
|
||||
result = Rpl::Interpreter.new.parse( '« test»' )
|
||||
result = Rpl.new.parse( '« test»' )
|
||||
assert_equal [{ value: 'test', type: :program }], result
|
||||
|
||||
result = Rpl::Interpreter.new.parse( '«test»' )
|
||||
result = Rpl.new.parse( '«test»' )
|
||||
assert_equal [{ value: 'test', type: :program }], result
|
||||
|
||||
result = Rpl::Interpreter.new.parse( '« test test »' )
|
||||
result = Rpl.new.parse( '« test test »' )
|
||||
assert_equal [{ value: 'test test', type: :program }], result
|
||||
|
||||
result = Rpl::Interpreter.new.parse( '« test « test » »' )
|
||||
result = Rpl.new.parse( '« test « test » »' )
|
||||
assert_equal [{ value: 'test « test »', type: :program }], result
|
||||
|
||||
result = Rpl::Interpreter.new.parse( '« test "test" test »' )
|
||||
result = Rpl.new.parse( '« test "test" test »' )
|
||||
assert_equal [{ value: 'test "test" test', type: :program }], result
|
||||
end
|
||||
|
||||
def test_number_number
|
||||
result = Rpl::Interpreter.new.parse( '2 3' )
|
||||
result = Rpl.new.parse( '2 3' )
|
||||
assert_equal [{ value: 2, type: :numeric, base: 10 }, { value: 3, type: :numeric, base: 10 }], result
|
||||
end
|
||||
|
||||
def test_number_number_word
|
||||
result = Rpl::Interpreter.new.parse( '2 3 +' )
|
||||
result = Rpl.new.parse( '2 3 +' )
|
||||
assert_equal [{ value: 2, type: :numeric, base: 10 },
|
||||
{ value: 3, type: :numeric, base: 10 },
|
||||
{ value: '+', type: :word }], result
|
||||
end
|
||||
|
||||
def test_number_string
|
||||
result = Rpl::Interpreter.new.parse( '4 "test"' )
|
||||
result = Rpl.new.parse( '4 "test"' )
|
||||
assert_equal [{ value: 4, type: :numeric, base: 10 }, { value: 'test', type: :string }], result
|
||||
end
|
||||
|
||||
def test_emptystring
|
||||
result = Rpl::Interpreter.new.parse( '""' )
|
||||
result = Rpl.new.parse( '""' )
|
||||
|
||||
assert_equal [{ value: '', type: :string }], result
|
||||
end
|
||||
|
||||
def test_spacestring
|
||||
result = Rpl::Interpreter.new.parse( '" "' )
|
||||
result = Rpl.new.parse( '" "' )
|
||||
|
||||
assert_equal [{ value: ' ', type: :string }], result
|
||||
end
|
||||
|
||||
def test_string_spacestring
|
||||
result = Rpl::Interpreter.new.parse( '"test string" " "' )
|
||||
result = Rpl.new.parse( '"test string" " "' )
|
||||
|
||||
assert_equal [{ value: 'test string', type: :string },
|
||||
{ value: ' ', type: :string }], result
|
||||
end
|
||||
|
||||
def test_string_word
|
||||
result = Rpl::Interpreter.new.parse( '"test string" split' )
|
||||
result = Rpl.new.parse( '"test string" split' )
|
||||
|
||||
assert_equal [{ value: 'test string', type: :string },
|
||||
{ value: 'split', type: :word }], result
|
||||
end
|
||||
|
||||
def test_spacestring_word
|
||||
result = Rpl::Interpreter.new.parse( '" " split' )
|
||||
result = Rpl.new.parse( '" " split' )
|
||||
|
||||
assert_equal [{ value: ' ', type: :string },
|
||||
{ value: 'split', type: :word }], result
|
||||
end
|
||||
|
||||
def test_program_name
|
||||
result = Rpl::Interpreter.new.parse( "« 2 dup * » 'carré' sto" )
|
||||
result = Rpl.new.parse( "« 2 dup * » 'carré' sto" )
|
||||
|
||||
assert_equal [{ value: '2 dup *', type: :program },
|
||||
{ value: 'carré', type: :name },
|
||||
|
|
Loading…
Reference in a new issue