From cfcbcc7ce5268e435327a01438eac3413e7df395 Mon Sep 17 00:00:00 2001 From: Gwenhael Le Moine Date: Tue, 7 Dec 2021 15:50:58 +0100 Subject: [PATCH] =?UTF-8?q?Rpl::=20=E2=86=92=20Rpl::Lang::?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/core.rb | 54 +++--- lib/dictionary.rb | 306 ++++++++++++++++--------------- lib/language/branch.rb | 24 +-- lib/language/general.rb | 12 +- lib/language/mode.rb | 42 +++-- lib/language/operations.rb | 240 ++++++++++++------------ lib/language/program.rb | 24 +-- lib/language/stack.rb | 206 ++++++++++----------- lib/language/string.rb | 94 +++++----- lib/language/test.rb | 168 ++++++++--------- lib/language/time-date.rb | 40 ++-- lib/parser.rb | 144 ++++++++------- lib/runner.rb | 30 +-- repl.rb | 15 +- spec/core_spec.rb | 12 +- spec/language_branch_spec.rb | 16 +- spec/language_operations_spec.rb | 88 ++++----- spec/language_program_spec.rb | 17 +- spec/language_stack_spec.rb | 94 +++++----- spec/language_string_spec.rb | 22 +-- spec/language_time-date_spec.rb | 6 +- spec/parser_spec.rb | 36 ++-- 22 files changed, 868 insertions(+), 822 deletions(-) diff --git a/lib/core.rb b/lib/core.rb index bed21b5..0fdf6e0 100644 --- a/lib/core.rb +++ b/lib/core.rb @@ -11,37 +11,39 @@ require_relative './language/test' require_relative './language/time-date' module Rpl - module Core - module_function + module Lang + module Core + module_function - include BigMath + include BigMath - def precision - @precision or 12 - end - - def precision=( value ) - @precision = value - end - - def stack_extract( stack, needs ) - raise 'Not enough elements' if stack.size < needs.size - - args = [] - needs.each do |need| - elt = stack.pop - - raise "Type Error, needed #{need} got #{elt[:type]}" if need != :any && !need.include?( elt[:type] ) - - args << elt + def precision + @precision or 12 end - [stack, args] - end + def precision=( value ) + @precision = value + end - def __todo( stack ) - puts '__NOT IMPLEMENTED__' - stack + def stack_extract( stack, needs ) + raise 'Not enough elements' if stack.size < needs.size + + args = [] + needs.each do |need| + elt = stack.pop + + raise "Type Error, needed #{need} got #{elt[:type]}" if need != :any && !need.include?( elt[:type] ) + + args << elt + end + + [stack, args] + end + + def __todo( stack ) + puts '__NOT IMPLEMENTED__' + stack + end end end end diff --git a/lib/dictionary.rb b/lib/dictionary.rb index 52914cc..004bfbd 100644 --- a/lib/dictionary.rb +++ b/lib/dictionary.rb @@ -1,190 +1,191 @@ # coding: utf-8 module Rpl + module Lang class Dictionary def initialize @parser = Parser.new @words = {} # GENERAL - add( 'nop', proc { |stack| Rpl::Core.nop( stack ) } ) - add( 'help', proc { |stack| Rpl::Core.__todo( stack ) } ) # this help message - add( 'quit', proc { |stack| Rpl::Core.__todo( stack ) } ) # quit software - add( 'version', proc { |stack| Rpl::Core.__todo( stack ) } ) # show rpn version - add( 'uname', proc { |stack| Rpl::Core.__todo( stack ) } ) # show rpn complete identification string - add( 'history', proc { |stack| Rpl::Core.__todo( stack ) } ) # see commands history + add( 'nop', proc { |stack| Rpl::Lang::Core.nop( stack ) } ) + add( 'help', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # this help message + add( 'quit', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # quit software + add( 'version', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # show rpn version + add( 'uname', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # show rpn complete identification string + add( 'history', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # see commands history # STACK - add( 'swap', proc { |stack| Rpl::Core.swap( stack ) } ) - add( 'drop', proc { |stack| Rpl::Core.drop( stack ) } ) - add( 'drop2', proc { |stack| Rpl::Core.drop2( stack ) } ) - add( 'dropn', proc { |stack| Rpl::Core.dropn( stack ) } ) - add( 'del', proc { |stack| Rpl::Core.del( stack ) } ) - add( 'rot', proc { |stack| Rpl::Core.rot( stack ) } ) - add( 'dup', proc { |stack| Rpl::Core.dup( stack ) } ) - add( 'dup2', proc { |stack| Rpl::Core.dup2( stack ) } ) - add( 'dupn', proc { |stack| Rpl::Core.dupn( stack ) } ) - add( 'pick', proc { |stack| Rpl::Core.pick( stack ) } ) - add( 'depth', proc { |stack| Rpl::Core.depth( stack ) } ) - add( 'roll', proc { |stack| Rpl::Core.roll( stack ) } ) - add( 'rolld', proc { |stack| Rpl::Core.rolld( stack ) } ) - add( 'over', proc { |stack| Rpl::Core.over( stack ) } ) + add( 'swap', proc { |stack| Rpl::Lang::Core.swap( stack ) } ) + add( 'drop', proc { |stack| Rpl::Lang::Core.drop( stack ) } ) + add( 'drop2', proc { |stack| Rpl::Lang::Core.drop2( stack ) } ) + add( 'dropn', proc { |stack| Rpl::Lang::Core.dropn( stack ) } ) + add( 'del', proc { |stack| Rpl::Lang::Core.del( stack ) } ) + add( 'rot', proc { |stack| Rpl::Lang::Core.rot( stack ) } ) + add( 'dup', proc { |stack| Rpl::Lang::Core.dup( stack ) } ) + add( 'dup2', proc { |stack| Rpl::Lang::Core.dup2( stack ) } ) + add( 'dupn', proc { |stack| Rpl::Lang::Core.dupn( stack ) } ) + add( 'pick', proc { |stack| Rpl::Lang::Core.pick( stack ) } ) + add( 'depth', proc { |stack| Rpl::Lang::Core.depth( stack ) } ) + add( 'roll', proc { |stack| Rpl::Lang::Core.roll( stack ) } ) + add( 'rolld', proc { |stack| Rpl::Lang::Core.rolld( stack ) } ) + add( 'over', proc { |stack| Rpl::Lang::Core.over( stack ) } ) # USUAL OPERATIONS ON REALS AND COMPLEXES - add( '+', proc { |stack| Rpl::Core.add( stack ) } ) - add( '-', proc { |stack| Rpl::Core.subtract( stack ) } ) - add( 'chs', proc { |stack| Rpl::Core.negate( stack ) } ) - add( '*', proc { |stack| Rpl::Core.multiply( stack ) } ) - add( '×', proc { |stack| Rpl::Core.multiply( stack ) } ) # alias - add( '/', proc { |stack| Rpl::Core.divide( stack ) } ) - add( '÷', proc { |stack| Rpl::Core.divide( stack ) } ) # alias - add( 'inv', proc { |stack| Rpl::Core.inverse( stack ) } ) - add( '^', proc { |stack| Rpl::Core.power( stack ) } ) - add( 'sqrt', proc { |stack| Rpl::Core.sqrt( stack ) } ) - add( 'sq', proc { |stack| Rpl::Core.sq( stack ) } ) - add( 'abs', proc { |stack| Rpl::Core.abs( stack ) } ) - add( 'dec', proc { |stack| Rpl::Core.dec( stack ) } ) - add( 'hex', proc { |stack| Rpl::Core.hex( stack ) } ) - add( 'bin', proc { |stack| Rpl::Core.bin( stack ) } ) - add( 'base', proc { |stack| Rpl::Core.base( stack ) } ) - add( 'sign', proc { |stack| Rpl::Core.sign( stack ) } ) + add( '+', proc { |stack| Rpl::Lang::Core.add( stack ) } ) + add( '-', proc { |stack| Rpl::Lang::Core.subtract( stack ) } ) + add( 'chs', proc { |stack| Rpl::Lang::Core.negate( stack ) } ) + add( '*', proc { |stack| Rpl::Lang::Core.multiply( stack ) } ) + add( '×', proc { |stack| Rpl::Lang::Core.multiply( stack ) } ) # alias + add( '/', proc { |stack| Rpl::Lang::Core.divide( stack ) } ) + add( '÷', proc { |stack| Rpl::Lang::Core.divide( stack ) } ) # alias + add( 'inv', proc { |stack| Rpl::Lang::Core.inverse( stack ) } ) + add( '^', proc { |stack| Rpl::Lang::Core.power( stack ) } ) + add( 'sqrt', proc { |stack| Rpl::Lang::Core.sqrt( stack ) } ) + add( 'sq', proc { |stack| Rpl::Lang::Core.sq( stack ) } ) + add( 'abs', proc { |stack| Rpl::Lang::Core.abs( stack ) } ) + add( 'dec', proc { |stack| Rpl::Lang::Core.dec( stack ) } ) + add( 'hex', proc { |stack| Rpl::Lang::Core.hex( stack ) } ) + add( 'bin', proc { |stack| Rpl::Lang::Core.bin( stack ) } ) + add( 'base', proc { |stack| Rpl::Lang::Core.base( stack ) } ) + add( 'sign', proc { |stack| Rpl::Lang::Core.sign( stack ) } ) # OPERATIONS ON REALS - add( '%', proc { |stack| Rpl::Core.__todo( stack ) } ) # percent - add( '%CH', proc { |stack| Rpl::Core.__todo( stack ) } ) # inverse percent - add( 'mod', proc { |stack| Rpl::Core.__todo( stack ) } ) # modulo - add( 'fact', proc { |stack| Rpl::Core.__todo( stack ) } ) # n! for integer n or Gamma(x+1) for fractional x - add( 'mant', proc { |stack| Rpl::Core.__todo( stack ) } ) # mantissa of a real number - add( 'xpon', proc { |stack| Rpl::Core.__todo( stack ) } ) # exponant of a real number - add( 'floor', proc { |stack| Rpl::Core.__todo( stack ) } ) # largest number <= - add( 'ceil', proc { |stack| Rpl::Core.__todo( stack ) } ) # smallest number >= - add( 'ip', proc { |stack| Rpl::Core.__todo( stack ) } ) # integer part - add( 'fp', proc { |stack| Rpl::Core.__todo( stack ) } ) # fractional part - add( 'min', proc { |stack| Rpl::Core.__todo( stack ) } ) # min of 2 real numbers - add( 'max', proc { |stack| Rpl::Core.__todo( stack ) } ) # max of 2 real numbers + add( '%', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # percent + add( '%CH', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # inverse percent + add( 'mod', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # modulo + add( 'fact', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # n! for integer n or Gamma(x+1) for fractional x + add( 'mant', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # mantissa of a real number + add( 'xpon', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # exponant of a real number + add( 'floor', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # largest number <= + add( 'ceil', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # smallest number >= + add( 'ip', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # integer part + add( 'fp', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # fractional part + add( 'min', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # min of 2 real numbers + add( 'max', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # max of 2 real numbers # OPERATIONS ON COMPLEXES - add( 're', proc { |stack| Rpl::Core.__todo( stack ) } ) # complex real part - add( 'im', proc { |stack| Rpl::Core.__todo( stack ) } ) # complex imaginary part - add( 'conj', proc { |stack| Rpl::Core.__todo( stack ) } ) # complex conjugate - add( 'arg', proc { |stack| Rpl::Core.__todo( stack ) } ) # complex argument in radians - add( 'c->r', proc { |stack| Rpl::Core.__todo( stack ) } ) # transform a complex in 2 reals - add( 'c→r', proc { |stack| Rpl::Core.__todo( stack ) } ) # alias - add( 'r->c', proc { |stack| Rpl::Core.__todo( stack ) } ) # transform 2 reals in a complex - add( 'r→c', proc { |stack| Rpl::Core.__todo( stack ) } ) # alias - add( 'p->r', proc { |stack| Rpl::Core.__todo( stack ) } ) # cartesian to polar - add( 'p→r', proc { |stack| Rpl::Core.__todo( stack ) } ) # alias - add( 'r->p', proc { |stack| Rpl::Core.__todo( stack ) } ) # polar to cartesian - add( 'r→p', proc { |stack| Rpl::Core.__todo( stack ) } ) # alias + add( 're', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # complex real part + add( 'im', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # complex imaginary part + add( 'conj', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # complex conjugate + add( 'arg', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # complex argument in radians + add( 'c->r', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # transform a complex in 2 reals + add( 'c→r', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # alias + add( 'r->c', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # transform 2 reals in a complex + add( 'r→c', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # alias + add( 'p->r', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # cartesian to polar + add( 'p→r', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # alias + add( 'r->p', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # polar to cartesian + add( 'r→p', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # alias # MODE - add( 'std', proc { |stack| Rpl::Core.__todo( stack ) } ) # standard floating numbers representation. ex: std - add( 'fix', proc { |stack| Rpl::Core.__todo( stack ) } ) # fixed point representation. ex: 6 fix - add( 'sci', proc { |stack| Rpl::Core.__todo( stack ) } ) # scientific floating point representation. ex: 20 sci - add( 'prec', proc { |stack| Rpl::Core.prec( stack ) } ) - add( 'round', proc { |stack| Rpl::Core.__todo( stack ) } ) # set float rounding mode. ex: ["nearest", "toward zero", "toward +inf", "toward -inf", "away from zero"] round - add( 'default', proc { |stack| Rpl::Core.default( stack ) } ) - add( 'type', proc { |stack| Rpl::Core.type( stack ) } ) + add( 'std', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # standard floating numbers representation. ex: std + add( 'fix', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # fixed point representation. ex: 6 fix + add( 'sci', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # scientific floating point representation. ex: 20 sci + add( 'prec', proc { |stack| Rpl::Lang::Core.prec( stack ) } ) + add( 'round', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # set float rounding mode. ex: ["nearest", "toward zero", "toward +inf", "toward -inf", "away from zero"] round + add( 'default', proc { |stack| Rpl::Lang::Core.default( stack ) } ) + add( 'type', proc { |stack| Rpl::Lang::Core.type( stack ) } ) # TEST - add( '>', proc { |stack| Rpl::Core.greater_than( stack ) } ) - add( '>=', proc { |stack| Rpl::Core.greater_or_equal_than( stack ) } ) - add( '≥', proc { |stack| Rpl::Core.greater_or_equal_than( stack ) } ) # alias - add( '<', proc { |stack| Rpl::Core.less_than( stack ) } ) - add( '<=', proc { |stack| Rpl::Core.less_or_equal_than( stack ) } ) - add( '≤', proc { |stack| Rpl::Core.less_or_equal_than( stack ) } ) # alias - add( '!=', proc { |stack| Rpl::Core.different( stack ) } ) - add( '≠', proc { |stack| Rpl::Core.different( stack ) } ) # alias - add( '==', proc { |stack| Rpl::Core.same( stack ) } ) # alias - add( 'and', proc { |stack| Rpl::Core.and( stack ) } ) - add( 'or', proc { |stack| Rpl::Core.or( stack ) } ) - add( 'xor', proc { |stack| Rpl::Core.xor( stack ) } ) - add( 'not', proc { |stack| Rpl::Core.not( stack ) } ) - add( 'same', proc { |stack| Rpl::Core.same( stack ) } ) - add( 'true', proc { |stack| Rpl::Core.true( stack ) } ) # specific - add( 'false', proc { |stack| Rpl::Core.false( stack ) } ) # specific + add( '>', proc { |stack| Rpl::Lang::Core.greater_than( stack ) } ) + add( '>=', proc { |stack| Rpl::Lang::Core.greater_or_equal_than( stack ) } ) + add( '≥', proc { |stack| Rpl::Lang::Core.greater_or_equal_than( stack ) } ) # alias + add( '<', proc { |stack| Rpl::Lang::Core.less_than( stack ) } ) + add( '<=', proc { |stack| Rpl::Lang::Core.less_or_equal_than( stack ) } ) + add( '≤', proc { |stack| Rpl::Lang::Core.less_or_equal_than( stack ) } ) # alias + add( '!=', proc { |stack| Rpl::Lang::Core.different( stack ) } ) + add( '≠', proc { |stack| Rpl::Lang::Core.different( stack ) } ) # alias + add( '==', proc { |stack| Rpl::Lang::Core.same( stack ) } ) # alias + add( 'and', proc { |stack| Rpl::Lang::Core.and( stack ) } ) + add( 'or', proc { |stack| Rpl::Lang::Core.or( stack ) } ) + add( 'xor', proc { |stack| Rpl::Lang::Core.xor( stack ) } ) + add( 'not', proc { |stack| Rpl::Lang::Core.not( stack ) } ) + add( 'same', proc { |stack| Rpl::Lang::Core.same( stack ) } ) + add( 'true', proc { |stack| Rpl::Lang::Core.true( stack ) } ) # specific + add( 'false', proc { |stack| Rpl::Lang::Core.false( stack ) } ) # specific # STRING - add( '->str', proc { |stack| Rpl::Core.to_string( stack ) } ) - add( '→str', proc { |stack| Rpl::Core.to_string( stack ) } ) # alias - add( 'str->', proc { |stack| Rpl::Core.from_string( stack ) } ) - add( 'str→', proc { |stack| Rpl::Core.from_string( stack ) } ) # alias - add( 'chr', proc { |stack| Rpl::Core.chr( stack ) } ) - add( 'num', proc { |stack| Rpl::Core.num( stack ) } ) - add( 'size', proc { |stack| Rpl::Core.size( stack ) } ) - add( 'pos', proc { |stack| Rpl::Core.pos( stack ) } ) - add( 'sub', proc { |stack| Rpl::Core.sub( stack ) } ) + add( '->str', proc { |stack| Rpl::Lang::Core.to_string( stack ) } ) + add( '→str', proc { |stack| Rpl::Lang::Core.to_string( stack ) } ) # alias + add( 'str->', proc { |stack| Rpl::Lang::Core.from_string( stack ) } ) + add( 'str→', proc { |stack| Rpl::Lang::Core.from_string( stack ) } ) # alias + add( 'chr', proc { |stack| Rpl::Lang::Core.chr( stack ) } ) + add( 'num', proc { |stack| Rpl::Lang::Core.num( stack ) } ) + add( 'size', proc { |stack| Rpl::Lang::Core.size( stack ) } ) + add( 'pos', proc { |stack| Rpl::Lang::Core.pos( stack ) } ) + add( 'sub', proc { |stack| Rpl::Lang::Core.sub( stack ) } ) # BRANCH - add( 'if', proc { |stack| Rpl::Core.__todo( stack ) } ) # if then else end - add( 'then', proc { |stack| Rpl::Core.__todo( stack ) } ) # used with if - add( 'else', proc { |stack| Rpl::Core.__todo( stack ) } ) # used with if - add( 'end', proc { |stack| Rpl::Core.__todo( stack ) } ) # used with various branch instructions - add( 'start', proc { |stack| Rpl::Core.__todo( stack ) } ) # start next| step - add( 'for', proc { |stack| Rpl::Core.__todo( stack ) } ) # for next| step - add( 'next', proc { |stack| Rpl::Core.__todo( stack ) } ) # used with start and for - add( 'step', proc { |stack| Rpl::Core.__todo( stack ) } ) # used with start and for - add( 'ift', proc { |stack| Rpl::Core.ift( stack, self ) } ) - add( 'ifte', proc { |stack| Rpl::Core.ifte( stack, self ) } ) - add( 'do', proc { |stack| Rpl::Core.__todo( stack ) } ) # do until end - add( 'until', proc { |stack| Rpl::Core.__todo( stack ) } ) # used with do - add( 'while', proc { |stack| Rpl::Core.__todo( stack ) } ) # while repeat end - add( 'repeat', proc { |stack| Rpl::Core.__todo( stack ) } ) # used with while + add( 'if', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # if then else end + add( 'then', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # used with if + add( 'else', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # used with if + add( 'end', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # used with various branch instructions + add( 'start', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # start next| step + add( 'for', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # for next| step + add( 'next', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # used with start and for + add( 'step', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # used with start and for + add( 'ift', proc { |stack| Rpl::Lang::Core.ift( stack, self ) } ) + add( 'ifte', proc { |stack| Rpl::Lang::Core.ifte( stack, self ) } ) + add( 'do', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # do until end + add( 'until', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # used with do + add( 'while', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # while repeat end + add( 'repeat', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # used with while # STORE - add( 'sto', proc { |stack| Rpl::Core.__todo( stack ) } ) # store a variable. ex: 1 'name' sto - add( '▶', proc { |stack| Rpl::Core.__todo( stack ) } ) # alias - add( 'rcl', proc { |stack| Rpl::Core.__todo( stack ) } ) # recall a variable. ex: 'name' rcl - add( 'purge', proc { |stack| Rpl::Core.__todo( stack ) } ) # delete a variable. ex: 'name' purge - add( 'vars', proc { |stack| Rpl::Core.__todo( stack ) } ) # list all variables - add( 'clusr', proc { |stack| Rpl::Core.__todo( stack ) } ) # erase all variables - add( 'edit', proc { |stack| Rpl::Core.__todo( stack ) } ) # edit a variable content - add( 'sto+', proc { |stack| Rpl::Core.__todo( stack ) } ) # add to a stored variable. ex: 1 'name' sto+ 'name' 2 sto+ - add( 'sto-', proc { |stack| Rpl::Core.__todo( stack ) } ) # substract to a stored variable. ex: 1 'name' sto- 'name' 2 sto- - add( 'sto*', proc { |stack| Rpl::Core.__todo( stack ) } ) # multiply a stored variable. ex: 3 'name' sto* 'name' 2 sto* - add( 'sto/', proc { |stack| Rpl::Core.__todo( stack ) } ) # divide a stored variable. ex: 3 'name' sto/ 'name' 2 sto/ - add( 'sneg', proc { |stack| Rpl::Core.__todo( stack ) } ) # negate a variable. ex: 'name' sneg - add( 'sinv', proc { |stack| Rpl::Core.__todo( stack ) } ) # inverse a variable. ex: 1 'name' sinv + add( 'sto', proc { |stack| Rpl::Lang::Core.sto( stack ) } ) # store a variable. ex: 1 'name' sto + add( '▶', proc { |stack| Rpl::Lang::Core.sto( stack ) } ) # alias + add( 'rcl', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # recall a variable. ex: 'name' rcl + add( 'purge', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # delete a variable. ex: 'name' purge + add( 'vars', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # list all variables + add( 'clusr', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # erase all variables + add( 'edit', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # edit a variable content + add( 'sto+', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # add to a stored variable. ex: 1 'name' sto+ 'name' 2 sto+ + add( 'sto-', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # substract to a stored variable. ex: 1 'name' sto- 'name' 2 sto- + add( 'sto*', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # multiply a stored variable. ex: 3 'name' sto* 'name' 2 sto* + add( 'sto/', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # divide a stored variable. ex: 3 'name' sto/ 'name' 2 sto/ + add( 'sneg', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # negate a variable. ex: 'name' sneg + add( 'sinv', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # inverse a variable. ex: 1 'name' sinv # PROGRAM - add( 'eval', proc { |stack| Rpl::Core.eval( stack, self ) } ) - add( '->', proc { |stack| Rpl::Core.__todo( stack ) } ) # load program local variables. ex: << -> n m << 0 n m for i i + next >> >> - add( '→', proc { |stack| Rpl::Core.__todo( stack ) } ) # alias + add( 'eval', proc { |stack| Rpl::Lang::Core.eval( stack, self ) } ) + add( '->', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # load program local variables. ex: << -> n m << 0 n m for i i + next >> >> + add( '→', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # alias # TRIG ON REALS AND COMPLEXES - add( 'pi', proc { |stack| Rpl::Core.__todo( stack ) } ) # pi constant - add( 'sin', proc { |stack| Rpl::Core.__todo( stack ) } ) # sinus - add( 'asin', proc { |stack| Rpl::Core.__todo( stack ) } ) # arg sinus - add( 'cos', proc { |stack| Rpl::Core.__todo( stack ) } ) # cosinus - add( 'acos', proc { |stack| Rpl::Core.__todo( stack ) } ) # arg cosinus - add( 'tan', proc { |stack| Rpl::Core.__todo( stack ) } ) # tangent - add( 'atan', proc { |stack| Rpl::Core.__todo( stack ) } ) # arg tangent - add( 'd->r', proc { |stack| Rpl::Core.__todo( stack ) } ) # convert degrees to radians - add( 'd→r', proc { |stack| Rpl::Core.__todo( stack ) } ) # alias - add( 'r->d', proc { |stack| Rpl::Core.__todo( stack ) } ) # convert radians to degrees - add( 'r→d', proc { |stack| Rpl::Core.__todo( stack ) } ) # alias + add( 'pi', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # pi constant + add( 'sin', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # sinus + add( 'asin', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # arg sinus + add( 'cos', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # cosinus + add( 'acos', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # arg cosinus + add( 'tan', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # tangent + add( 'atan', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # arg tangent + add( 'd->r', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # convert degrees to radians + add( 'd→r', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # alias + add( 'r->d', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # convert radians to degrees + add( 'r→d', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # alias # LOGS ON REALS AND COMPLEXES - add( 'e', proc { |stack| Rpl::Core.__todo( stack ) } ) # Euler constant - add( 'ln', proc { |stack| Rpl::Core.__todo( stack ) } ) # logarithm base e - add( 'lnp1', proc { |stack| Rpl::Core.__todo( stack ) } ) # ln(1+x) which is useful when x is close to 0 - add( 'exp', proc { |stack| Rpl::Core.__todo( stack ) } ) # exponential - add( 'expm', proc { |stack| Rpl::Core.__todo( stack ) } ) # exp(x)-1 which is useful when x is close to 0 - add( 'log10', proc { |stack| Rpl::Core.__todo( stack ) } ) # logarithm base 10 - add( 'alog10', proc { |stack| Rpl::Core.__todo( stack ) } ) # exponential base 10 - add( 'log2', proc { |stack| Rpl::Core.__todo( stack ) } ) # logarithm base 2 - add( 'alog2', proc { |stack| Rpl::Core.__todo( stack ) } ) # exponential base 2 - add( 'sinh', proc { |stack| Rpl::Core.__todo( stack ) } ) # hyperbolic sine - add( 'asinh', proc { |stack| Rpl::Core.__todo( stack ) } ) # inverse hyperbolic sine - add( 'cosh', proc { |stack| Rpl::Core.__todo( stack ) } ) # hyperbolic cosine - add( 'acosh', proc { |stack| Rpl::Core.__todo( stack ) } ) # inverse hyperbolic cosine - add( 'tanh', proc { |stack| Rpl::Core.__todo( stack ) } ) # hyperbolic tangent - add( 'atanh', proc { |stack| Rpl::Core.__todo( stack ) } ) # inverse hyperbolic tangent + add( 'e', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # Euler constant + add( 'ln', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # logarithm base e + add( 'lnp1', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # ln(1+x) which is useful when x is close to 0 + add( 'exp', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # exponential + add( 'expm', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # exp(x)-1 which is useful when x is close to 0 + add( 'log10', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # logarithm base 10 + add( 'alog10', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # exponential base 10 + add( 'log2', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # logarithm base 2 + add( 'alog2', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # exponential base 2 + add( 'sinh', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # hyperbolic sine + add( 'asinh', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # inverse hyperbolic sine + add( 'cosh', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # hyperbolic cosine + add( 'acosh', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # inverse hyperbolic cosine + add( 'tanh', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # hyperbolic tangent + add( 'atanh', proc { |stack| Rpl::Lang::Core.__todo( stack ) } ) # inverse hyperbolic tangent # TIME AND DATE - add( 'time', proc { |stack| Rpl::Core.time( stack ) } ) - add( 'date', proc { |stack| Rpl::Core.date( stack ) } ) - add( 'ticks', proc { |stack| Rpl::Core.ticks( stack ) } ) + add( 'time', proc { |stack| Rpl::Lang::Core.time( stack ) } ) + add( 'date', proc { |stack| Rpl::Lang::Core.date( stack ) } ) + add( 'ticks', proc { |stack| Rpl::Lang::Core.ticks( stack ) } ) end def add( name, implementation ) @@ -198,3 +199,4 @@ module Rpl # TODO: alias end end +end diff --git a/lib/language/branch.rb b/lib/language/branch.rb index 1278eb4..6d87004 100644 --- a/lib/language/branch.rb +++ b/lib/language/branch.rb @@ -1,19 +1,21 @@ module Rpl - module Core - module_function + module Lang + module Core + module_function - # similar to if-then-end, ift - def ift( stack, dictionary ) - ifte( stack << { type: :word, value: 'nop' }, dictionary ) - end + # similar to if-then-end, ift + def ift( stack, dictionary ) + ifte( stack << { type: :word, value: 'nop' }, dictionary ) + end - # similar to if-then-else-end, ifte - def ifte( stack, dictionary ) - stack, args = Rpl::Core.stack_extract( stack, [%i[program word], %i[program word], %i[boolean]] ) + # similar to if-then-else-end, ifte + def ifte( stack, dictionary ) + stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[program word], %i[program word], %i[boolean]] ) - stack << args[ args[2][:value] ? 1 : 0 ] + stack << args[ args[2][:value] ? 1 : 0 ] - Rpl::Core.eval( stack, dictionary ) + Rpl::Lang::Core.eval( stack, dictionary ) + end end end end diff --git a/lib/language/general.rb b/lib/language/general.rb index 8088cb6..a9fb831 100644 --- a/lib/language/general.rb +++ b/lib/language/general.rb @@ -1,10 +1,12 @@ module Rpl - module Core - module_function + module Lang + module Core + module_function - # no operation - def nop( stack ) - stack + # no operation + def nop( stack ) + stack + end end end end diff --git a/lib/language/mode.rb b/lib/language/mode.rb index 36f647c..7f2f08c 100644 --- a/lib/language/mode.rb +++ b/lib/language/mode.rb @@ -1,31 +1,33 @@ module Rpl - module Core - module_function + module Lang + module Core + module_function - # set float precision in bits. ex: 256 prec - def prec( stack ) - stack, args = Rpl::Core.stack_extract( stack, [%i[numeric]] ) + # set float precision in bits. ex: 256 prec + def prec( stack ) + stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric]] ) - Rpl::Core.precision = args[0][:value] + Rpl::Lang::Core.precision = args[0][:value] - stack - end + stack + end - # set float representation and precision to default - def default( stack ) - Rpl::Core.precision = 12 + # set float representation and precision to default + def default( stack ) + Rpl::Lang::Core.precision = 12 - stack - end + stack + end - # show type of stack first entry - def type( stack ) - stack, args = Rpl::Core.stack_extract( stack, [:any] ) + # show type of stack first entry + def type( stack ) + stack, args = Rpl::Lang::Core.stack_extract( stack, [:any] ) - stack << args[0] - stack << { type: :string, - value: args[0][:type].to_s } - stack + stack << args[0] + stack << { type: :string, + value: args[0][:type].to_s } + stack + end end end end diff --git a/lib/language/operations.rb b/lib/language/operations.rb index b67ef72..4a30572 100644 --- a/lib/language/operations.rb +++ b/lib/language/operations.rb @@ -1,156 +1,158 @@ module Rpl - module Core - module_function + module Lang + module Core + module_function - # addition - def add( stack ) - addable = %i[numeric string name] - stack, args = Rpl::Core.stack_extract( stack, [addable, addable] ) + # addition + def add( stack ) + addable = %i[numeric string name] + stack, args = Rpl::Lang::Core.stack_extract( stack, [addable, addable] ) - result = { type: case args[1][:type] - when :name - :name - when :string - :string - when :numeric - if args[0][:type] == :numeric - :numeric - else + result = { type: case args[1][:type] + when :name + :name + when :string :string - end - end } + when :numeric + if args[0][:type] == :numeric + :numeric + else + :string + end + end } - args.each do |elt| - elt[:value] = elt[:value][1..-2] unless elt[:type] == :numeric + args.each do |elt| + elt[:value] = elt[:value][1..-2] unless elt[:type] == :numeric + end + + result[:value] = case result[:type] + when :name + "'#{args[1][:value]}#{args[0][:value]}'" + when :string + "\"#{args[1][:value]}#{args[0][:value]}\"" + when :numeric + args[1][:value] + args[0][:value] + end + + result[:base] = 10 if result[:type] == :numeric # TODO: what if operands have other bases ? + + stack << result end - result[:value] = case result[:type] - when :name - "'#{args[1][:value]}#{args[0][:value]}'" - when :string - "\"#{args[1][:value]}#{args[0][:value]}\"" - when :numeric - args[1][:value] + args[0][:value] - end + # substraction + def subtract( stack ) + stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric], %i[numeric]] ) - result[:base] = 10 if result[:type] == :numeric # TODO: what if operands have other bases ? + stack << { type: :numeric, base: 10, + value: args[1][:value] - args[0][:value] } + end - stack << result - end + # negation + def negate( stack ) + stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric]] ) - # substraction - def subtract( stack ) - stack, args = Rpl::Core.stack_extract( stack, [%i[numeric], %i[numeric]] ) + stack << { type: :numeric, base: 10, + value: args[0][:value] * -1 } + end - stack << { type: :numeric, base: 10, - value: args[1][:value] - args[0][:value] } - end + # multiplication + def multiply( stack ) + stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric], %i[numeric]] ) - # negation - def negate( stack ) - stack, args = Rpl::Core.stack_extract( stack, [%i[numeric]] ) + stack << { type: :numeric, base: 10, + value: args[1][:value] * args[0][:value] } + end - stack << { type: :numeric, base: 10, - value: args[0][:value] * -1 } - end + # division + def divide( stack ) + stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric], %i[numeric]] ) - # multiplication - def multiply( stack ) - stack, args = Rpl::Core.stack_extract( stack, [%i[numeric], %i[numeric]] ) + raise 'Division by 0' if args[0][:value].zero? - stack << { type: :numeric, base: 10, - value: args[1][:value] * args[0][:value] } - end + stack << { type: :numeric, base: 10, + value: args[1][:value] / args[0][:value] } + end - # division - def divide( stack ) - stack, args = Rpl::Core.stack_extract( stack, [%i[numeric], %i[numeric]] ) + # inverse + def inverse( stack ) + stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric]] ) - raise 'Division by 0' if args[0][:value].zero? + raise 'Division by 0' if args[0][:value].zero? - stack << { type: :numeric, base: 10, - value: args[1][:value] / args[0][:value] } - end + stack << { type: :numeric, base: 10, + value: 1.0 / args[0][:value] } + end - # inverse - def inverse( stack ) - stack, args = Rpl::Core.stack_extract( stack, [%i[numeric]] ) + # power + def power( stack ) + stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric], %i[numeric]] ) - raise 'Division by 0' if args[0][:value].zero? + stack << { type: :numeric, base: 10, + value: args[1][:value]**args[0][:value] } + end - stack << { type: :numeric, base: 10, - value: 1.0 / args[0][:value] } - end + # rpn_square root + def sqrt( stack ) + stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric]] ) - # power - def power( stack ) - stack, args = Rpl::Core.stack_extract( stack, [%i[numeric], %i[numeric]] ) + stack << { type: :numeric, base: 10, + value: BigMath.sqrt( BigDecimal( args[0][:value] ), Rpl::Lang::Core.precision ) } + end - stack << { type: :numeric, base: 10, - value: args[1][:value]**args[0][:value] } - end + # rpn_square + def sq( stack ) + stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric]] ) - # rpn_square root - def sqrt( stack ) - stack, args = Rpl::Core.stack_extract( stack, [%i[numeric]] ) + stack << { type: :numeric, base: 10, + value: args[0][:value] * args[0][:value] } + end - stack << { type: :numeric, base: 10, - value: BigMath.sqrt( BigDecimal( args[0][:value] ), Rpl::Core.precision ) } - end + # absolute value + def abs( stack ) + stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric]] ) - # rpn_square - def sq( stack ) - stack, args = Rpl::Core.stack_extract( stack, [%i[numeric]] ) + stack << { type: :numeric, base: 10, + value: args[0][:value].abs } + end - stack << { type: :numeric, base: 10, - value: args[0][:value] * args[0][:value] } - end + # decimal representation + def dec( stack ) + base( stack << { type: :numeric, base: 10, value: 10 } ) + end - # absolute value - def abs( stack ) - stack, args = Rpl::Core.stack_extract( stack, [%i[numeric]] ) + # hexadecimal representation + def hex( stack ) + base( stack << { type: :numeric, base: 10, value: 16 } ) + end - stack << { type: :numeric, base: 10, - value: args[0][:value].abs } - end + # binary representation + def bin( stack ) + base( stack << { type: :numeric, base: 10, value: 2 } ) + end - # decimal representation - def dec( stack ) - base( stack << { type: :numeric, base: 10, value: 10 } ) - end + # arbitrary base representation + def base( stack ) + stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric], %i[numeric]] ) - # hexadecimal representation - def hex( stack ) - base( stack << { type: :numeric, base: 10, value: 16 } ) - end + args[1][:base] = args[0][:value] - # binary representation - def bin( stack ) - base( stack << { type: :numeric, base: 10, value: 2 } ) - end + stack << args[1] + end - # arbitrary base representation - def base( stack ) - stack, args = Rpl::Core.stack_extract( stack, [%i[numeric], %i[numeric]] ) + # 1 if number at stack level 1 is > 0, 0 if == 0, -1 if <= 0 + def sign( stack ) + stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric]] ) + value = if args[0][:value].positive? + 1 + elsif args[0][:value].negative? + -1 + else + 0 + end - args[1][:base] = args[0][:value] - - stack << args[1] - end - - # 1 if number at stack level 1 is > 0, 0 if == 0, -1 if <= 0 - def sign( stack ) - stack, args = Rpl::Core.stack_extract( stack, [%i[numeric]] ) - value = if args[0][:value].positive? - 1 - elsif args[0][:value].negative? - -1 - else - 0 - end - - stack << { type: :numeric, base: 10, - value: value } + stack << { type: :numeric, base: 10, + value: value } + end end end end diff --git a/lib/language/program.rb b/lib/language/program.rb index 2d6e67d..1aeeed9 100644 --- a/lib/language/program.rb +++ b/lib/language/program.rb @@ -1,19 +1,21 @@ module Rpl - module Core - module_function + module Lang + module Core + module_function - # evaluate (run) a program, or recall a variable. ex: 'my_prog' eval - def eval( stack, dictionary ) - stack, args = Rpl::Core.stack_extract( stack, [%i[program word name]] ) + # evaluate (run) a program, or recall a variable. ex: 'my_prog' eval + def eval( stack, dictionary ) + stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[program word name]] ) - # we trim enclosing «» - preparsed_input = args[0][:type] == :word ? args[0][:value] : args[0][:value][1..-2] - parsed_input = Rpl::Parser.new.parse_input( preparsed_input ) + # we trim enclosing «» + preparsed_input = args[0][:type] == :word ? args[0][:value] : args[0][:value][1..-2] + parsed_input = Rpl::Lang::Parser.new.parse_input( preparsed_input ) - stack, _dictionary = Rpl::Runner.new.run_input( stack, dictionary, parsed_input ) - # TODO: check that STO actually updates dictionary + stack, _dictionary = Rpl::Lang::Runner.new.run_input( stack, dictionary, parsed_input ) + # TODO: check that STO actually updates dictionary - stack + stack + end end end end diff --git a/lib/language/stack.rb b/lib/language/stack.rb index e912c39..e8f2d5c 100644 --- a/lib/language/stack.rb +++ b/lib/language/stack.rb @@ -1,128 +1,130 @@ module Rpl - module Core - module_function + module Lang + module Core + module_function - # swap 2 first stack entries - def swap( stack ) - stack, args = Rpl::Core.stack_extract( stack, %i[any any] ) + # swap 2 first stack entries + def swap( stack ) + stack, args = Rpl::Lang::Core.stack_extract( stack, %i[any any] ) - stack << args[0] << args[1] - end + stack << args[0] << args[1] + end - # drop first stack entry - def drop( stack ) - dropn( stack << { type: :numeric, base: 10, value: 1 } ) - end + # drop first stack entry + def drop( stack ) + dropn( stack << { type: :numeric, base: 10, value: 1 } ) + end - # drop 2 first stack entries - def drop2( stack ) - dropn( stack << { type: :numeric, base: 10, value: 2 } ) - end + # drop 2 first stack entries + def drop2( stack ) + dropn( stack << { type: :numeric, base: 10, value: 2 } ) + end - # drop n first stack entries - def dropn( stack ) - stack, args = Rpl::Core.stack_extract( stack, [%i[numeric]] ) - stack, _args = Rpl::Core.stack_extract( stack, %i[any] * args[0][:value] ) + # drop n first stack entries + def dropn( stack ) + stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric]] ) + stack, _args = Rpl::Lang::Core.stack_extract( stack, %i[any] * args[0][:value] ) - stack - end + stack + end - # drop all stack entries - def del( _stack ) - [] - end + # drop all stack entries + def del( _stack ) + [] + end - # rotate 3 first stack entries - def rot( stack ) - stack, args = Rpl::Core.stack_extract( stack, %i[any any any] ) + # rotate 3 first stack entries + def rot( stack ) + stack, args = Rpl::Lang::Core.stack_extract( stack, %i[any any any] ) - stack << args[1] << args[0] << args[2] - end + stack << args[1] << args[0] << args[2] + end - # duplicate first stack entry - def dup( stack ) - dupn( stack << { type: :numeric, base: 10, value: 1 } ) - end + # duplicate first stack entry + def dup( stack ) + dupn( stack << { type: :numeric, base: 10, value: 1 } ) + end - # duplicate 2 first stack entries - def dup2( stack ) - dupn( stack << { type: :numeric, base: 10, value: 2 } ) - end + # duplicate 2 first stack entries + def dup2( stack ) + dupn( stack << { type: :numeric, base: 10, value: 2 } ) + end - # duplicate n first stack entries - def dupn( stack ) - stack, args = Rpl::Core.stack_extract( stack, [%i[numeric]] ) - n = args[0][:value] - stack, args = Rpl::Core.stack_extract( stack, %i[any] * args[0][:value] ) + # duplicate n first stack entries + def dupn( stack ) + stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric]] ) + n = args[0][:value] + stack, args = Rpl::Lang::Core.stack_extract( stack, %i[any] * args[0][:value] ) - args.reverse! + args.reverse! + + 2.times do + n.times.each do |i| + stack << args[ i ] + end + end + + stack + end + + # push a copy of the given stack level onto the stack + def pick( stack ) + stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric]] ) + n = args[0][:value] + stack, args = Rpl::Lang::Core.stack_extract( stack, %i[any] * args[0][:value] ) + + args.reverse! - 2.times do n.times.each do |i| stack << args[ i ] end + stack << args[0] + + stack end - stack - end - - # push a copy of the given stack level onto the stack - def pick( stack ) - stack, args = Rpl::Core.stack_extract( stack, [%i[numeric]] ) - n = args[0][:value] - stack, args = Rpl::Core.stack_extract( stack, %i[any] * args[0][:value] ) - - args.reverse! - - n.times.each do |i| - stack << args[ i ] - end - stack << args[0] - - stack - end - - # give stack depth - def depth( stack ) - stack << { type: :numeric, base: 10, value: stack.size } - end - - # move a stack entry to the top of the stack - def roll( stack ) - stack, args = Rpl::Core.stack_extract( stack, [%i[numeric]] ) - n = args[0][:value] - stack, args = Rpl::Core.stack_extract( stack, %i[any] * args[0][:value] ) - - args.reverse! - - (1..(n - 1)).each do |i| - stack << args[ i ] - end - stack << args[0] - - stack - end - - # move the element on top of the stack to a higher stack position - def rolld( stack ) - stack, args = Rpl::Core.stack_extract( stack, [%i[numeric]] ) - n = args[0][:value] - stack, args = Rpl::Core.stack_extract( stack, %i[any] * args[0][:value] ) - - args.reverse! - - stack << args[n - 1] - - (0..(n - 2)).each do |i| - stack << args[ i ] + # give stack depth + def depth( stack ) + stack << { type: :numeric, base: 10, value: stack.size } end - stack - end + # move a stack entry to the top of the stack + def roll( stack ) + stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric]] ) + n = args[0][:value] + stack, args = Rpl::Lang::Core.stack_extract( stack, %i[any] * args[0][:value] ) - # push a copy of the element in stack level 2 onto the stack - def over( stack ) - pick( stack << { type: :numeric, base: 10, value: 2 } ) + args.reverse! + + (1..(n - 1)).each do |i| + stack << args[ i ] + end + stack << args[0] + + stack + end + + # move the element on top of the stack to a higher stack position + def rolld( stack ) + stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric]] ) + n = args[0][:value] + stack, args = Rpl::Lang::Core.stack_extract( stack, %i[any] * args[0][:value] ) + + args.reverse! + + stack << args[n - 1] + + (0..(n - 2)).each do |i| + stack << args[ i ] + end + + stack + end + + # push a copy of the element in stack level 2 onto the stack + def over( stack ) + pick( stack << { type: :numeric, base: 10, value: 2 } ) + end end end end diff --git a/lib/language/string.rb b/lib/language/string.rb index 350267d..00bfee4 100644 --- a/lib/language/string.rb +++ b/lib/language/string.rb @@ -1,65 +1,67 @@ module Rpl - module Core - module_function + module Lang + module Core + module_function - # convert an object into a string - def to_string( stack ) - stack, args = Rpl::Core.stack_extract( stack, [:any] ) + # convert an object into a string + def to_string( stack ) + stack, args = Rpl::Lang::Core.stack_extract( stack, [:any] ) - stack << { type: :string, - value: args[0][:value].to_s } - end + stack << { type: :string, + value: args[0][:value].to_s } + end - # convert a string into an object - def from_string( stack ) - stack, args = Rpl::Core.stack_extract( stack, [%i[string]] ) + # convert a string into an object + def from_string( stack ) + stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[string]] ) - parsed_input = Rpl::Parser.new.parse_input( args[0][:value] ) + parsed_input = Rpl::Lang::Parser.new.parse_input( args[0][:value] ) - stack + parsed_input - end + stack + parsed_input + end - # convert ASCII character code in stack level 1 into a string - def chr( stack ) - stack, args = Rpl::Core.stack_extract( stack, [%i[numeric]] ) + # convert ASCII character code in stack level 1 into a string + def chr( stack ) + stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric]] ) - stack << { type: :string, - value: args[0][:value].chr } - end + stack << { type: :string, + value: args[0][:value].chr } + end - # return ASCII code of the first character of the string in stack level 1 as a real number - def num( stack ) - stack, args = Rpl::Core.stack_extract( stack, [%i[string]] ) + # return ASCII code of the first character of the string in stack level 1 as a real number + def num( stack ) + stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[string]] ) - stack << { type: :numeric, - base: 10, - value: args[0][:value].ord } - end + stack << { type: :numeric, + base: 10, + value: args[0][:value].ord } + end - # return the length of the string - def size( stack ) - stack, args = Rpl::Core.stack_extract( stack, [%i[string]] ) + # return the length of the string + def size( stack ) + stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[string]] ) - stack << { type: :numeric, - base: 10, - value: args[0][:value].length } - end + 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( stack ) - stack, args = Rpl::Core.stack_extract( stack, [%i[string], %i[string]] ) + # search for the string in level 1 within the string in level 2 + def pos( stack ) + stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[string], %i[string]] ) - stack << { type: :numeric, - base: 10, - value: args[1][:value].index( args[0][:value] ) } - end + 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( stack ) - stack, args = Rpl::Core.stack_extract( stack, [%i[numeric], %i[numeric], %i[string]] ) + # return a substring of the string in level 3 + def sub( stack ) + stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric], %i[numeric], %i[string]] ) - stack << { type: :string, - value: args[2][:value][args[1][:value]..args[0][:value]] } + stack << { type: :string, + value: args[2][:value][args[1][:value]..args[0][:value]] } + end end end end diff --git a/lib/language/test.rb b/lib/language/test.rb index 2c74a77..30bee2e 100644 --- a/lib/language/test.rb +++ b/lib/language/test.rb @@ -1,109 +1,111 @@ module Rpl - module Core - module_function + module Lang + module Core + module_function - # binary operator > - def greater_than( stack ) - stack, args = Rpl::Core.stack_extract( stack, %i[any any] ) + # binary operator > + def greater_than( stack ) + stack, args = Rpl::Lang::Core.stack_extract( stack, %i[any any] ) - stack << { type: :boolean, - value: args[1][:value] > args[0][:value] } - stack - end + stack << { type: :boolean, + value: args[1][:value] > args[0][:value] } + stack + end - # binary operator >= - def greater_or_equal_than( stack ) - stack, args = Rpl::Core.stack_extract( stack, %i[any any] ) + # binary operator >= + def greater_or_equal_than( stack ) + stack, args = Rpl::Lang::Core.stack_extract( stack, %i[any any] ) - stack << { type: :boolean, - value: args[1][:value] >= args[0][:value] } - stack - end + stack << { type: :boolean, + value: args[1][:value] >= args[0][:value] } + stack + end - # binary operator < - def less_than( stack ) - stack, args = Rpl::Core.stack_extract( stack, %i[any any] ) + # binary operator < + def less_than( stack ) + stack, args = Rpl::Lang::Core.stack_extract( stack, %i[any any] ) - stack << { type: :boolean, - value: args[1][:value] < args[0][:value] } - stack - end + stack << { type: :boolean, + value: args[1][:value] < args[0][:value] } + stack + end - # binary operator <= - def less_or_equal_than( stack ) - stack, args = Rpl::Core.stack_extract( stack, %i[any any] ) + # binary operator <= + def less_or_equal_than( stack ) + stack, args = Rpl::Lang::Core.stack_extract( stack, %i[any any] ) - stack << { type: :boolean, - value: args[1][:value] <= args[0][:value] } - stack - end + stack << { type: :boolean, + value: args[1][:value] <= args[0][:value] } + stack + end - # boolean operator != (different) - def different( stack ) - stack, args = Rpl::Core.stack_extract( stack, %i[any any] ) + # boolean operator != (different) + def different( stack ) + stack, args = Rpl::Lang::Core.stack_extract( stack, %i[any any] ) - stack << { type: :boolean, - value: args[1][:value] != args[0][:value] } - stack - end + stack << { type: :boolean, + value: args[1][:value] != args[0][:value] } + stack + end - # boolean operator and - def and( stack ) - stack, args = Rpl::Core.stack_extract( stack, [%i[boolean], %i[boolean]] ) + # boolean operator and + def and( stack ) + stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[boolean], %i[boolean]] ) - stack << { type: :boolean, - value: args[1][:value] && args[0][:value] } - stack - end + stack << { type: :boolean, + value: args[1][:value] && args[0][:value] } + stack + end - # boolean operator or - def or( stack ) - stack, args = Rpl::Core.stack_extract( stack, [%i[boolean], %i[boolean]] ) + # boolean operator or + def or( stack ) + stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[boolean], %i[boolean]] ) - stack << { type: :boolean, - value: args[1][:value] || args[0][:value] } - stack - end + stack << { type: :boolean, + value: args[1][:value] || args[0][:value] } + stack + end - # boolean operator xor - def xor( stack ) - stack, args = Rpl::Core.stack_extract( stack, [%i[boolean], %i[boolean]] ) + # boolean operator xor + def xor( stack ) + stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[boolean], %i[boolean]] ) - stack << { type: :boolean, - value: args[1][:value] ^ args[0][:value] } - stack - end + stack << { type: :boolean, + value: args[1][:value] ^ args[0][:value] } + stack + end - # boolean operator not - def not( stack ) - stack, args = Rpl::Core.stack_extract( stack, [%i[boolean]] ) + # boolean operator not + def not( stack ) + stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[boolean]] ) - stack << { type: :boolean, - value: !args[0][:value] } - stack - end + stack << { type: :boolean, + value: !args[0][:value] } + stack + end - # boolean operator same (equal) - def same( stack ) - stack, args = Rpl::Core.stack_extract( stack, %i[any any] ) + # boolean operator same (equal) + def same( stack ) + stack, args = Rpl::Lang::Core.stack_extract( stack, %i[any any] ) - stack << { type: :boolean, - value: args[1][:value] == args[0][:value] } - stack - end + stack << { type: :boolean, + value: args[1][:value] == args[0][:value] } + stack + end - # true boolean - def true( stack ) - stack << { type: :boolean, - value: true } - stack - end + # true boolean + def true( stack ) + stack << { type: :boolean, + value: true } + stack + end - # false boolean - def false( stack ) - stack << { type: :boolean, - value: false } - stack + # false boolean + def false( stack ) + stack << { type: :boolean, + value: false } + stack + end end end end diff --git a/lib/language/time-date.rb b/lib/language/time-date.rb index 27ebb61..e5db42b 100644 --- a/lib/language/time-date.rb +++ b/lib/language/time-date.rb @@ -1,28 +1,30 @@ require 'date' module Rpl - module Core - module_function + module Lang + module Core + module_function - # time in local format - def time( stack ) - stack << { type: :string, - value: Time.now.to_s } - end + # time in local format + def time( stack ) + stack << { type: :string, + value: Time.now.to_s } + end - # date in local format - def date( stack ) - stack << { type: :string, - value: Date.today.to_s } - end + # date in local format + def date( stack ) + stack << { type: :string, + value: Date.today.to_s } + end - # system tick in µs - def ticks( stack ) - 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 } + # system tick in µs + def ticks( stack ) + 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 end diff --git a/lib/parser.rb b/lib/parser.rb index c0c880f..07ef6a5 100644 --- a/lib/parser.rb +++ b/lib/parser.rb @@ -1,88 +1,90 @@ # coding: utf-8 module Rpl - class Parser - def initialize; end + module Lang + class Parser + def initialize; end - def numeric?( elt ) - !Float(elt).nil? - rescue ArgumentError - begin - !Integer(elt).nil? + def numeric?( elt ) + !Float(elt).nil? rescue ArgumentError - false - end - end - - def parse_input( input ) - splitted_input = input.split(' ') - - # 2-passes: - # 1. regroup strings and programs - opened_programs = 0 - closed_programs = 0 - string_delimiters = 0 - regrouping = false - - regrouped_input = [] - splitted_input.each do |elt| - # TODO: handle buried-in-elt « and » (surround by ' ' and re-split) - if elt[0] == '«' - opened_programs += 1 - elt.gsub!( '«', '« ') if elt.length > 1 && elt[1] != ' ' + begin + !Integer(elt).nil? + rescue ArgumentError + false end - string_delimiters += 1 if elt[0] == '"' - - 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.length > 1 && elt[-1] == '"' - - regrouping = string_delimiters.odd? || (opened_programs > closed_programs ) end - # 2. parse - parsed_tree = [] - regrouped_input.each do |elt| - parsed_entry = { value: elt } + def parse_input( input ) + splitted_input = input.split(' ') - opened_programs += 1 if elt[0] == '«' - string_delimiters += 1 if elt[0] == '"' + # 2-passes: + # 1. regroup strings and programs + opened_programs = 0 + closed_programs = 0 + string_delimiters = 0 + regrouping = false - parsed_entry[:type] = case elt[0] - when '«' - :program - when '"' - :string - when "'" - :name # TODO: check for forbidden space - else - if numeric?( elt ) - :numeric - else - :word - end - end - - if parsed_entry[:type] == :numeric - parsed_entry[:base] = 10 # TODO: parse others possible bases 0x... - - begin - parsed_entry[:value] = Float( parsed_entry[:value] ) - rescue ArgumentError - parsed_entry[:value] = Integer( parsed_entry[:value] ) + regrouped_input = [] + splitted_input.each do |elt| + # TODO: handle buried-in-elt « and » (surround by ' ' and re-split) + if elt[0] == '«' + opened_programs += 1 + elt.gsub!( '«', '« ') if elt.length > 1 && elt[1] != ' ' end + string_delimiters += 1 if elt[0] == '"' + + 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.length > 1 && elt[-1] == '"' + + regrouping = string_delimiters.odd? || (opened_programs > closed_programs ) end - parsed_tree << parsed_entry - end + # 2. parse + parsed_tree = [] + regrouped_input.each do |elt| + parsed_entry = { value: elt } - parsed_tree + opened_programs += 1 if elt[0] == '«' + string_delimiters += 1 if elt[0] == '"' + + parsed_entry[:type] = case elt[0] + when '«' + :program + when '"' + :string + when "'" + :name # TODO: check for forbidden space + else + if numeric?( elt ) + :numeric + else + :word + end + end + + if parsed_entry[:type] == :numeric + parsed_entry[:base] = 10 # TODO: parse others possible bases 0x... + + begin + parsed_entry[:value] = Float( parsed_entry[:value] ) + rescue ArgumentError + parsed_entry[:value] = Integer( parsed_entry[:value] ) + end + end + + parsed_tree << parsed_entry + end + + parsed_tree + end end end end diff --git a/lib/runner.rb b/lib/runner.rb index fa96ad2..775931d 100644 --- a/lib/runner.rb +++ b/lib/runner.rb @@ -1,26 +1,28 @@ # coding: utf-8 module Rpl - class Runner - def initialize; end + module Lang + class Runner + def initialize; end - def run_input( stack, dictionary, input ) - input.each do |elt| - case elt[:type] - when :word - command = dictionary.lookup( elt[:value] ) + def run_input( stack, dictionary, input ) + input.each do |elt| + case elt[:type] + when :word + command = dictionary.lookup( elt[:value] ) - if command.nil? - stack << { type: :name, value: "'#{elt[:value]}'" } + if command.nil? + stack << { type: :name, value: "'#{elt[:value]}'" } + else + stack = command.call( stack ) + end else - stack = command.call( stack ) + stack << elt end - else - stack << elt end - end - [stack, dictionary] + [stack, dictionary] + end end end end diff --git a/repl.rb b/repl.rb index 632c854..81a35ea 100644 --- a/repl.rb +++ b/repl.rb @@ -9,7 +9,9 @@ require './lib/parser' require './lib/runner' module Rpl - class Repl + class Language + attr_reader :stack + def initialize @stack = [] @dictionary = Dictionary.new @@ -17,6 +19,17 @@ module Rpl @runner = Runner.new end + def run( input ) + @stack, @dictionary = @runner.run_input( @stack, @dictionary, + @parser.parse_input( input ) ) + end + end + + class Repl + def initialize + @lang = Rpl::Language.new + end + def run Readline.completion_proc = proc do |s| Readline::HISTORY.grep(/^#{Regexp.escape(s)}/) diff --git a/spec/core_spec.rb b/spec/core_spec.rb index 9fc9904..2107a6f 100644 --- a/spec/core_spec.rb +++ b/spec/core_spec.rb @@ -7,17 +7,17 @@ require_relative '../lib/core' class TestParser < Test::Unit::TestCase def test_stack_extract - stack, args = Rpl::Core.stack_extract [{ value: 1, type: :numeric }, - { value: 2, type: :numeric }], - [:any] + stack, args = Rpl::Lang::Core.stack_extract [{ value: 1, type: :numeric }, + { value: 2, type: :numeric }], + [:any] assert_equal [{ value: 1, type: :numeric }], stack assert_equal [{ value: 2, type: :numeric }], args - stack, args = Rpl::Core.stack_extract [{ value: 'test', type: :string }, - { value: 2, type: :numeric }], - [[:numeric], :any] + stack, args = Rpl::Lang::Core.stack_extract [{ value: 'test', type: :string }, + { value: 2, type: :numeric }], + [[:numeric], :any] assert_equal [], stack assert_equal [{ value: 2, type: :numeric }, diff --git a/spec/language_branch_spec.rb b/spec/language_branch_spec.rb index ae2e9fa..6e8df95 100644 --- a/spec/language_branch_spec.rb +++ b/spec/language_branch_spec.rb @@ -10,18 +10,18 @@ require_relative '../lib/runner' class TestLanguageBranch < Test::Unit::TestCase def test_ifte - stack = Rpl::Core.ifte( [{ type: :boolean, value: true }, - { type: :program, value: '« 2 3 + »' }, - { type: :program, value: '« 2 3 - »' }], - Rpl::Dictionary.new ) + stack = Rpl::Lang::Core.ifte( [{ type: :boolean, value: true }, + { type: :program, value: '« 2 3 + »' }, + { type: :program, value: '« 2 3 - »' }], + Rpl::Lang::Dictionary.new ) assert_equal [{ value: 5, type: :numeric, base: 10 }], stack - stack = Rpl::Core.ifte( [{ type: :boolean, value: false }, - { type: :program, value: '« 2 3 + »' }, - { type: :program, value: '« 2 3 - »' }], - Rpl::Dictionary.new ) + stack = Rpl::Lang::Core.ifte( [{ type: :boolean, value: false }, + { type: :program, value: '« 2 3 + »' }, + { type: :program, value: '« 2 3 - »' }], + Rpl::Lang::Dictionary.new ) assert_equal [{ value: -1, type: :numeric, base: 10 }], stack diff --git a/spec/language_operations_spec.rb b/spec/language_operations_spec.rb index 0f2eeb5..4fb1017 100644 --- a/spec/language_operations_spec.rb +++ b/spec/language_operations_spec.rb @@ -7,172 +7,172 @@ require_relative '../lib/core' class TesttLanguageOperations < Test::Unit::TestCase def test_add - stack = Rpl::Core.add [{ value: 1, type: :numeric, base: 10 }, - { value: 2, type: :numeric, base: 10 }] + stack = Rpl::Lang::Core.add [{ value: 1, type: :numeric, base: 10 }, + { value: 2, type: :numeric, base: 10 }] assert_equal [{ value: 3, type: :numeric, base: 10 }], stack - stack = Rpl::Core.add [{ value: 1, type: :numeric, base: 10 }, - { value: '"a"', type: :string }] + stack = Rpl::Lang::Core.add [{ value: 1, type: :numeric, base: 10 }, + { value: '"a"', type: :string }] assert_equal [{ value: '"1a"', type: :string }], stack - stack = Rpl::Core.add [{ value: 1, type: :numeric, base: 10 }, - { value: "'a'", type: :name }] + stack = Rpl::Lang::Core.add [{ value: 1, type: :numeric, base: 10 }, + { value: "'a'", type: :name }] assert_equal [{ value: '"1a"', type: :string }], stack - stack = Rpl::Core.add [{ value: "'a'", type: :name }, - { value: 1, type: :numeric, base: 10 }] + stack = Rpl::Lang::Core.add [{ value: "'a'", type: :name }, + { value: 1, type: :numeric, base: 10 }] assert_equal [{ value: "'a1'", type: :name }], stack - stack = Rpl::Core.add [{ value: "'a'", type: :name }, - { value: '"b"', type: :string }] + stack = Rpl::Lang::Core.add [{ value: "'a'", type: :name }, + { value: '"b"', type: :string }] assert_equal [{ value: "'ab'", type: :name }], stack - stack = Rpl::Core.add [{ value: "'a'", type: :name }, - { value: "'b'", type: :name }] + stack = Rpl::Lang::Core.add [{ value: "'a'", type: :name }, + { value: "'b'", type: :name }] assert_equal [{ value: "'ab'", type: :name }], stack - stack = Rpl::Core.add [{ value: '"a"', type: :string }, - { value: '"b"', type: :string }] + stack = Rpl::Lang::Core.add [{ value: '"a"', type: :string }, + { value: '"b"', type: :string }] assert_equal [{ value: '"ab"', type: :string }], stack - stack = Rpl::Core.add [{ value: '"a"', type: :string }, - { value: "'b'", type: :name }] + stack = Rpl::Lang::Core.add [{ value: '"a"', type: :string }, + { value: "'b'", type: :name }] assert_equal [{ value: '"ab"', type: :string }], stack - stack = Rpl::Core.add [{ value: '"a"', type: :string }, - { value: 1, type: :numeric, base: 10 }] + stack = Rpl::Lang::Core.add [{ value: '"a"', type: :string }, + { value: 1, type: :numeric, base: 10 }] assert_equal [{ value: '"a1"', type: :string }], stack end def test_subtract - stack = Rpl::Core.subtract [{ value: 1, type: :numeric, base: 10 }, - { value: 2, type: :numeric, base: 10 }] + stack = Rpl::Lang::Core.subtract [{ value: 1, type: :numeric, base: 10 }, + { value: 2, type: :numeric, base: 10 }] assert_equal [{ value: -1, type: :numeric, base: 10 }], stack - stack = Rpl::Core.subtract [{ value: 2, type: :numeric, base: 10 }, - { value: 1, type: :numeric, base: 10 }] + stack = Rpl::Lang::Core.subtract [{ value: 2, type: :numeric, base: 10 }, + { value: 1, type: :numeric, base: 10 }] assert_equal [{ value: 1, type: :numeric, base: 10 }], stack end def test_negate - stack = Rpl::Core.negate [{ value: -1, type: :numeric, base: 10 }] + stack = Rpl::Lang::Core.negate [{ value: -1, type: :numeric, base: 10 }] assert_equal [{ value: 1, type: :numeric, base: 10 }], stack - stack = Rpl::Core.negate [{ value: 1, type: :numeric, base: 10 }] + stack = Rpl::Lang::Core.negate [{ value: 1, type: :numeric, base: 10 }] assert_equal [{ value: -1, type: :numeric, base: 10 }], stack end def test_multiply - stack = Rpl::Core.multiply [{ value: 3, type: :numeric, base: 10 }, - { value: 4, type: :numeric, base: 10 }] + stack = Rpl::Lang::Core.multiply [{ value: 3, type: :numeric, base: 10 }, + { value: 4, type: :numeric, base: 10 }] assert_equal [{ value: 12, type: :numeric, base: 10 }], stack end def test_divide - stack = Rpl::Core.divide [{ value: 3.0, type: :numeric, base: 10 }, - { value: 4, type: :numeric, base: 10 }] + stack = Rpl::Lang::Core.divide [{ value: 3.0, type: :numeric, base: 10 }, + { value: 4, type: :numeric, base: 10 }] assert_equal [{ value: 0.75, type: :numeric, base: 10 }], stack - # stack = Rpl::Core.divide [{ value: 3, type: :numeric, base: 10 }, + # stack = Rpl::Lang::Core.divide [{ value: 3, type: :numeric, base: 10 }, # { value: 4, type: :numeric, base: 10 }] # assert_equal [{ value: 0.75, type: :numeric, base: 10 }], # stack end def test_inverse - stack = Rpl::Core.inverse [{ value: 4, type: :numeric, base: 10 }] + stack = Rpl::Lang::Core.inverse [{ value: 4, type: :numeric, base: 10 }] assert_equal [{ value: 0.25, type: :numeric, base: 10 }], stack end def test_power - stack = Rpl::Core.power [{ value: 3, type: :numeric, base: 10 }, - { value: 4, type: :numeric, base: 10 }] + stack = Rpl::Lang::Core.power [{ value: 3, type: :numeric, base: 10 }, + { value: 4, type: :numeric, base: 10 }] assert_equal [{ value: 81, type: :numeric, base: 10 }], stack end def test_sqrt - stack = Rpl::Core.sqrt [{ value: 16, type: :numeric, base: 10 }] + stack = Rpl::Lang::Core.sqrt [{ value: 16, type: :numeric, base: 10 }] assert_equal [{ value: 4, type: :numeric, base: 10 }], stack end def test_sq - stack = Rpl::Core.sq [{ value: 4, type: :numeric, base: 10 }] + stack = Rpl::Lang::Core.sq [{ value: 4, type: :numeric, base: 10 }] assert_equal [{ value: 16, type: :numeric, base: 10 }], stack end def test_abs - stack = Rpl::Core.abs [{ value: -1, type: :numeric, base: 10 }] + stack = Rpl::Lang::Core.abs [{ value: -1, type: :numeric, base: 10 }] assert_equal [{ value: 1, type: :numeric, base: 10 }], stack - stack = Rpl::Core.abs [{ value: 1, type: :numeric, base: 10 }] + stack = Rpl::Lang::Core.abs [{ value: 1, type: :numeric, base: 10 }] assert_equal [{ value: 1, type: :numeric, base: 10 }], stack end def test_dec - stack = Rpl::Core.dec [{ value: 1, type: :numeric, base: 16 }] + stack = Rpl::Lang::Core.dec [{ value: 1, type: :numeric, base: 16 }] assert_equal [{ value: 1, type: :numeric, base: 10 }], stack end def test_hex - stack = Rpl::Core.hex [{ value: 1, type: :numeric, base: 10 }] + stack = Rpl::Lang::Core.hex [{ value: 1, type: :numeric, base: 10 }] assert_equal [{ value: 1, type: :numeric, base: 16 }], stack end def test_bin - stack = Rpl::Core.bin [{ value: 1, type: :numeric, base: 10 }] + stack = Rpl::Lang::Core.bin [{ value: 1, type: :numeric, base: 10 }] assert_equal [{ value: 1, type: :numeric, base: 2 }], stack end def test_base - stack = Rpl::Core.base [{ value: 1, type: :numeric, base: 10 }, - { value: 31, type: :numeric, base: 10 }] + stack = Rpl::Lang::Core.base [{ value: 1, type: :numeric, base: 10 }, + { value: 31, type: :numeric, base: 10 }] assert_equal [{ value: 1, type: :numeric, base: 31 }], stack end def test_sign - stack = Rpl::Core.sign [{ value: -10, type: :numeric, base: 10 }] + stack = Rpl::Lang::Core.sign [{ value: -10, type: :numeric, base: 10 }] assert_equal [{ value: -1, type: :numeric, base: 10 }], stack - stack = Rpl::Core.sign [{ value: 10, type: :numeric, base: 10 }] + stack = Rpl::Lang::Core.sign [{ value: 10, type: :numeric, base: 10 }] assert_equal [{ value: 1, type: :numeric, base: 10 }], stack - stack = Rpl::Core.sign [{ value: 0, type: :numeric, base: 10 }] + stack = Rpl::Lang::Core.sign [{ value: 0, type: :numeric, base: 10 }] assert_equal [{ value: 0, type: :numeric, base: 10 }], stack diff --git a/spec/language_program_spec.rb b/spec/language_program_spec.rb index 5a6ecef..9cefad3 100644 --- a/spec/language_program_spec.rb +++ b/spec/language_program_spec.rb @@ -10,24 +10,31 @@ require_relative '../lib/runner' class TestLanguageProgram < Test::Unit::TestCase def test_eval - stack = Rpl::Core.eval( [{ value: '« 2 dup * dup »', type: :program }], Rpl::Dictionary.new ) + stack = Rpl::Lang::Core.eval( [{ value: '« 2 dup * dup »', type: :program }], Rpl::Lang::Dictionary.new ) assert_equal [{ value: 4, type: :numeric, base: 10 }, { value: 4, type: :numeric, base: 10 }], stack - stack = Rpl::Core.eval( [{ value: 4, type: :numeric, base: 10 }, - { value: "'dup'", type: :name }], Rpl::Dictionary.new ) + stack = Rpl::Lang::Core.eval( [{ value: 4, type: :numeric, base: 10 }, + { value: "'dup'", type: :name }], Rpl::Lang::Dictionary.new ) assert_equal [{ value: 4, type: :numeric, base: 10 }, { value: 4, type: :numeric, base: 10 }], stack - stack = Rpl::Core.eval( [{ value: 4, type: :numeric, base: 10 }, - { value: 'dup', type: :word }], Rpl::Dictionary.new ) + stack = Rpl::Lang::Core.eval( [{ value: 4, type: :numeric, base: 10 }, + { value: 'dup', type: :word }], Rpl::Lang::Dictionary.new ) assert_equal [{ value: 4, type: :numeric, base: 10 }, { value: 4, type: :numeric, base: 10 }], stack end + + def test_sto + stack = Rpl::Lang::Core.sto( [{ value: '« 2 dup »', type: :program }, + { value: "'quatre'", type: :name }], Rpl::Lang::Dictionary.new ) + + assert_equal [], stack + end end diff --git a/spec/language_stack_spec.rb b/spec/language_stack_spec.rb index 7defa79..4431706 100644 --- a/spec/language_stack_spec.rb +++ b/spec/language_stack_spec.rb @@ -7,48 +7,48 @@ require_relative '../lib/core' class TestLanguageStack < Test::Unit::TestCase def test_swap - stack = Rpl::Core.swap [{ value: 1, type: :numeric, base: 10 }, - { value: 2, type: :numeric, base: 10 }] + stack = Rpl::Lang::Core.swap [{ value: 1, type: :numeric, base: 10 }, + { value: 2, type: :numeric, base: 10 }] assert_equal [{ value: 2, type: :numeric, base: 10 }, { value: 1, type: :numeric, base: 10 }], stack end def test_drop - stack = Rpl::Core.drop [{ value: 1, type: :numeric, base: 10 }, - { value: 2, type: :numeric, base: 10 }] + stack = Rpl::Lang::Core.drop [{ value: 1, type: :numeric, base: 10 }, + { value: 2, type: :numeric, base: 10 }] assert_equal [{ value: 1, type: :numeric, base: 10 }], stack end def test_drop2 - stack = Rpl::Core.drop2 [{ value: 1, type: :numeric, base: 10 }, - { value: 2, type: :numeric, base: 10 }] + stack = Rpl::Lang::Core.drop2 [{ value: 1, type: :numeric, base: 10 }, + { value: 2, type: :numeric, base: 10 }] assert_equal [], stack end def test_dropn - stack = Rpl::Core.dropn [{ value: 1, type: :numeric, base: 10 }, - { value: 2, type: :numeric, base: 10 }, - { value: 3, type: :numeric, base: 10 }, - { value: 4, type: :numeric, base: 10 }, - { value: 3, type: :numeric, base: 10 }] + stack = Rpl::Lang::Core.dropn [{ value: 1, type: :numeric, base: 10 }, + { value: 2, type: :numeric, base: 10 }, + { value: 3, type: :numeric, base: 10 }, + { value: 4, type: :numeric, base: 10 }, + { value: 3, type: :numeric, base: 10 }] assert_equal [{ value: 1, type: :numeric, base: 10 }], stack end def test_del - stack = Rpl::Core.del [{ value: 1, type: :numeric, base: 10 }, - { value: 2, type: :numeric, base: 10 }] + stack = Rpl::Lang::Core.del [{ value: 1, type: :numeric, base: 10 }, + { value: 2, type: :numeric, base: 10 }] assert_equal [], stack end def test_rot - stack = Rpl::Core.rot [{ value: 1, type: :numeric, base: 10 }, - { value: 2, type: :numeric, base: 10 }, - { value: 3, type: :numeric, base: 10 }] + stack = Rpl::Lang::Core.rot [{ value: 1, type: :numeric, base: 10 }, + { value: 2, type: :numeric, base: 10 }, + { value: 3, type: :numeric, base: 10 }] assert_equal [{ value: 2, type: :numeric, base: 10 }, { value: 3, type: :numeric, base: 10 }, { value: 1, type: :numeric, base: 10 }], @@ -56,8 +56,8 @@ class TestLanguageStack < Test::Unit::TestCase end def test_dup - stack = Rpl::Core.dup [{ value: 1, type: :numeric, base: 10 }, - { value: 2, type: :numeric, base: 10 }] + stack = Rpl::Lang::Core.dup [{ value: 1, type: :numeric, base: 10 }, + { value: 2, type: :numeric, base: 10 }] assert_equal [{ value: 1, type: :numeric, base: 10 }, { value: 2, type: :numeric, base: 10 }, { value: 2, type: :numeric, base: 10 }], @@ -65,8 +65,8 @@ class TestLanguageStack < Test::Unit::TestCase end def test_dup2 - stack = Rpl::Core.dup2 [{ value: 1, type: :numeric, base: 10 }, - { value: 2, type: :numeric, base: 10 }] + stack = Rpl::Lang::Core.dup2 [{ value: 1, type: :numeric, base: 10 }, + { value: 2, type: :numeric, base: 10 }] assert_equal [{ value: 1, type: :numeric, base: 10 }, { value: 2, type: :numeric, base: 10 }, { value: 1, type: :numeric, base: 10 }, @@ -75,11 +75,11 @@ class TestLanguageStack < Test::Unit::TestCase end def test_dupn - stack = Rpl::Core.dupn [{ value: 1, type: :numeric, base: 10 }, - { value: 2, type: :numeric, base: 10 }, - { value: 3, type: :numeric, base: 10 }, - { value: 4, type: :numeric, base: 10 }, - { value: 3, type: :numeric, base: 10 }] + stack = Rpl::Lang::Core.dupn [{ value: 1, type: :numeric, base: 10 }, + { value: 2, type: :numeric, base: 10 }, + { value: 3, type: :numeric, base: 10 }, + { value: 4, type: :numeric, base: 10 }, + { value: 3, type: :numeric, base: 10 }] assert_equal [{ value: 1, type: :numeric, base: 10 }, { value: 2, type: :numeric, base: 10 }, { value: 3, type: :numeric, base: 10 }, @@ -91,11 +91,11 @@ class TestLanguageStack < Test::Unit::TestCase end def test_pick - stack = Rpl::Core.pick [{ value: 1, type: :numeric, base: 10 }, - { value: 2, type: :numeric, base: 10 }, - { value: 3, type: :numeric, base: 10 }, - { value: 4, type: :numeric, base: 10 }, - { value: 3, type: :numeric, base: 10 }] + stack = Rpl::Lang::Core.pick [{ value: 1, type: :numeric, base: 10 }, + { value: 2, type: :numeric, base: 10 }, + { value: 3, type: :numeric, base: 10 }, + { value: 4, type: :numeric, base: 10 }, + { value: 3, type: :numeric, base: 10 }] assert_equal [{ value: 1, type: :numeric, base: 10 }, { value: 2, type: :numeric, base: 10 }, { value: 3, type: :numeric, base: 10 }, @@ -105,12 +105,12 @@ class TestLanguageStack < Test::Unit::TestCase end def test_depth - stack = Rpl::Core.depth [] + stack = Rpl::Lang::Core.depth [] assert_equal [{ value: 0, type: :numeric, base: 10 }], stack - stack = Rpl::Core.depth [{ value: 1, type: :numeric, base: 10 }, - { value: 2, type: :numeric, base: 10 }] + stack = Rpl::Lang::Core.depth [{ value: 1, type: :numeric, base: 10 }, + { value: 2, type: :numeric, base: 10 }] assert_equal [{ value: 1, type: :numeric, base: 10 }, { value: 2, type: :numeric, base: 10 }, { value: 2, type: :numeric, base: 10 }], @@ -118,11 +118,11 @@ class TestLanguageStack < Test::Unit::TestCase end def test_roll - stack = Rpl::Core.roll [{ value: 1, type: :numeric, base: 10 }, - { value: 2, type: :numeric, base: 10 }, - { value: 3, type: :numeric, base: 10 }, - { value: 4, type: :numeric, base: 10 }, - { value: 3, type: :numeric, base: 10 }] + stack = Rpl::Lang::Core.roll [{ value: 1, type: :numeric, base: 10 }, + { value: 2, type: :numeric, base: 10 }, + { value: 3, type: :numeric, base: 10 }, + { value: 4, type: :numeric, base: 10 }, + { value: 3, type: :numeric, base: 10 }] assert_equal [{ value: 1, type: :numeric, base: 10 }, { value: 3, type: :numeric, base: 10 }, { value: 4, type: :numeric, base: 10 }, @@ -131,11 +131,11 @@ class TestLanguageStack < Test::Unit::TestCase end def test_rolld - stack = Rpl::Core.rolld [{ value: 1, type: :numeric, base: 10 }, - { value: 2, type: :numeric, base: 10 }, - { value: 4, type: :numeric, base: 10 }, - { value: 3, type: :numeric, base: 10 }, - { value: 2, type: :numeric, base: 10 }] + stack = Rpl::Lang::Core.rolld [{ value: 1, type: :numeric, base: 10 }, + { value: 2, type: :numeric, base: 10 }, + { value: 4, type: :numeric, base: 10 }, + { value: 3, type: :numeric, base: 10 }, + { value: 2, type: :numeric, base: 10 }] assert_equal [{ value: 1, type: :numeric, base: 10 }, { value: 2, type: :numeric, base: 10 }, { value: 3, type: :numeric, base: 10 }, @@ -144,10 +144,10 @@ class TestLanguageStack < Test::Unit::TestCase end def test_over - stack = Rpl::Core.over [{ value: 1, type: :numeric, base: 10 }, - { value: 2, type: :numeric, base: 10 }, - { value: 3, type: :numeric, base: 10 }, - { value: 4, type: :numeric, base: 10 }] + stack = Rpl::Lang::Core.over [{ value: 1, type: :numeric, base: 10 }, + { value: 2, type: :numeric, base: 10 }, + { value: 3, type: :numeric, base: 10 }, + { value: 4, type: :numeric, base: 10 }] assert_equal [{ value: 1, type: :numeric, base: 10 }, { value: 2, type: :numeric, base: 10 }, { value: 3, type: :numeric, base: 10 }, diff --git a/spec/language_string_spec.rb b/spec/language_string_spec.rb index 7e14060..2b712e9 100644 --- a/spec/language_string_spec.rb +++ b/spec/language_string_spec.rb @@ -8,19 +8,19 @@ require_relative '../lib/parser' class TestLanguageString < Test::Unit::TestCase def test_to_string - stack = Rpl::Core.to_string( [{ value: 2, type: :numeric, base: 10 }] ) + stack = Rpl::Lang::Core.to_string( [{ value: 2, type: :numeric, base: 10 }] ) assert_equal [{ value: '2', type: :string }], stack end def test_from_string - stack = Rpl::Core.from_string( [{ value: '2', type: :string }] ) + stack = Rpl::Lang::Core.from_string( [{ value: '2', type: :string }] ) assert_equal [{ value: 2, type: :numeric, base: 10 }], stack - stack = Rpl::Core.from_string( [{ value: "« 2 dup * » 'carré' sto", type: :string }] ) + stack = Rpl::Lang::Core.from_string( [{ value: "« 2 dup * » 'carré' sto", type: :string }] ) assert_equal [{ value: '« 2 dup * »', type: :program }, { value: "'carré'", type: :name }, @@ -29,38 +29,38 @@ class TestLanguageString < Test::Unit::TestCase end def test_chr - stack = Rpl::Core.chr( [{ value: 71, type: :numeric, base: 10 }] ) + stack = Rpl::Lang::Core.chr( [{ value: 71, type: :numeric, base: 10 }] ) assert_equal [{ value: 'G', type: :string }], stack end def test_num - stack = Rpl::Core.num( [{ value: 'G', type: :string }] ) + stack = Rpl::Lang::Core.num( [{ value: 'G', type: :string }] ) assert_equal [{ value: 71, type: :numeric, base: 10 }], stack end def test_size - stack = Rpl::Core.size( [{ value: 'test', type: :string }] ) + stack = Rpl::Lang::Core.size( [{ value: 'test', type: :string }] ) assert_equal [{ value: 4, type: :numeric, base: 10 }], stack end def test_pos - stack = Rpl::Core.pos( [{ value: 'test of POS', type: :string }, - { value: 'of', type: :string }] ) + stack = Rpl::Lang::Core.pos( [{ value: 'test of POS', type: :string }, + { value: 'of', type: :string }] ) assert_equal [{ value: 5, type: :numeric, base: 10 }], stack end def test_sub - stack = Rpl::Core.sub( [{ value: 'test', type: :string }, - { value: 1, type: :numeric, base: 10 }, - { value: 2, type: :numeric, base: 10 }] ) + stack = Rpl::Lang::Core.sub( [{ value: 'test', type: :string }, + { value: 1, type: :numeric, base: 10 }, + { value: 2, type: :numeric, base: 10 }] ) assert_equal [{ value: 'es', type: :string }], stack diff --git a/spec/language_time-date_spec.rb b/spec/language_time-date_spec.rb index 2f1aba9..660dcba 100644 --- a/spec/language_time-date_spec.rb +++ b/spec/language_time-date_spec.rb @@ -8,7 +8,7 @@ require_relative '../lib/core' class TestLanguageTimeDate < Test::Unit::TestCase def test_time now = Time.now.to_s - stack = Rpl::Core.time( [] ) + stack = Rpl::Lang::Core.time( [] ) assert_equal [{ value: now, type: :string }], stack @@ -16,14 +16,14 @@ class TestLanguageTimeDate < Test::Unit::TestCase def test_date now = Date.today.to_s - stack = Rpl::Core.date( [] ) + stack = Rpl::Lang::Core.date( [] ) assert_equal [{ value: now, type: :string }], stack end def test_ticks - stack = Rpl::Core.ticks( [] ) + stack = Rpl::Lang::Core.ticks( [] ) # TODO: better test, but how? assert_equal :numeric, diff --git a/spec/parser_spec.rb b/spec/parser_spec.rb index e8d5deb..a69ba67 100644 --- a/spec/parser_spec.rb +++ b/spec/parser_spec.rb @@ -7,76 +7,76 @@ require_relative '../lib/parser' class TestParser < Test::Unit::TestCase def test_number - result = Rpl::Parser.new.parse_input( '1' ) + result = Rpl::Lang::Parser.new.parse_input( '1' ) assert_equal [{ value: 1, type: :numeric, base: 10 }], result end def test_word - result = Rpl::Parser.new.parse_input( 'dup' ) + result = Rpl::Lang::Parser.new.parse_input( 'dup' ) assert_equal [{ value: 'dup', type: :word }], result end def test_string - result = Rpl::Parser.new.parse_input( '"test"' ) + result = Rpl::Lang::Parser.new.parse_input( '"test"' ) assert_equal [{ value: '"test"', type: :string }], result - result = Rpl::Parser.new.parse_input( '" test"' ) + result = Rpl::Lang::Parser.new.parse_input( '" test"' ) assert_equal [{ value: '" test"', type: :string }], result - result = Rpl::Parser.new.parse_input( '"test "' ) + result = Rpl::Lang::Parser.new.parse_input( '"test "' ) assert_equal [{ value: '"test "', type: :string }], result - result = Rpl::Parser.new.parse_input( '" test "' ) + result = Rpl::Lang::Parser.new.parse_input( '" test "' ) assert_equal [{ value: '" test "', type: :string }], result end def test_name - result = Rpl::Parser.new.parse_input( "'test'" ) + result = Rpl::Lang::Parser.new.parse_input( "'test'" ) assert_equal [{ value: "'test'", type: :name }], result end def test_program - result = Rpl::Parser.new.parse_input( '« test »' ) + result = Rpl::Lang::Parser.new.parse_input( '« test »' ) assert_equal [{ value: '« test »', type: :program }], result - result = Rpl::Parser.new.parse_input( '«test »' ) + result = Rpl::Lang::Parser.new.parse_input( '«test »' ) assert_equal [{ value: '« test »', type: :program }], result - result = Rpl::Parser.new.parse_input( '« test»' ) + result = Rpl::Lang::Parser.new.parse_input( '« test»' ) assert_equal [{ value: '« test »', type: :program }], result - result = Rpl::Parser.new.parse_input( '«test»' ) + result = Rpl::Lang::Parser.new.parse_input( '«test»' ) assert_equal [{ value: '« test »', type: :program }], result - result = Rpl::Parser.new.parse_input( '« test test »' ) + result = Rpl::Lang::Parser.new.parse_input( '« test test »' ) assert_equal [{ value: '« test test »', type: :program }], result - result = Rpl::Parser.new.parse_input( '« test « test » »' ) + result = Rpl::Lang::Parser.new.parse_input( '« test « test » »' ) assert_equal [{ value: '« test « test » »', type: :program }], result - result = Rpl::Parser.new.parse_input( '« test "test" test »' ) + result = Rpl::Lang::Parser.new.parse_input( '« test "test" test »' ) assert_equal [{ value: '« test "test" test »', type: :program }], result end def test_number_number - result = Rpl::Parser.new.parse_input( '2 3' ) + result = Rpl::Lang::Parser.new.parse_input( '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::Parser.new.parse_input( '2 3 +' ) + result = Rpl::Lang::Parser.new.parse_input( '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::Parser.new.parse_input( '4 "test"' ) + result = Rpl::Lang::Parser.new.parse_input( '4 "test"' ) assert_equal [{ value: 4, type: :numeric, base: 10 }, { value: '"test"', type: :string }], result end def test_program_name - result = Rpl::Parser.new.parse_input( "« 2 dup * » 'carré' sto" ) + result = Rpl::Lang::Parser.new.parse_input( "« 2 dup * » 'carré' sto" ) assert_equal [{ value: '« 2 dup * »', type: :program }, { value: "'carré'", type: :name },