refactoring: split interpreter

This commit is contained in:
Gwenhael Le Moine 2022-02-10 14:50:59 +01:00
parent 3ebec3e4b0
commit b8724a4a1c
No known key found for this signature in database
GPG key ID: FDFE3669426707A7
31 changed files with 1716 additions and 1733 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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
View 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

View file

@ -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
View 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

View file

@ -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

View file

@ -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 [],

View file

@ -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

View file

@ -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

View file

@ -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 },

View file

@ -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 },

View file

@ -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

View file

@ -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 },

View file

@ -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 }],

View file

@ -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?

View file

@ -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_dr
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_rd
interpreter = Rpl::Interpreter.new
interpreter = Rpl.new
interpreter.run 'pi r→d'
assert_equal [{ value: 180, type: :numeric, base: 10 }],
interpreter.stack

View file

@ -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 },