diff --git a/README.md b/README.md index 0e497eb..7eba5a8 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,6 @@ To run REPL locally: `rake run` To run the test suite: `rake test` # BUGs - * var1 var2 +|-|*|\ ===> result in on stack (normal) AND stored in var1 (_bug_) # TODO-list * pseudo filesystem: subdir/namespace for variables diff --git a/lib/rpl/parser.rb b/lib/rpl/parser.rb index 5c38919..ce919ed 100644 --- a/lib/rpl/parser.rb +++ b/lib/rpl/parser.rb @@ -1,5 +1,13 @@ # frozen_string_literal: true +class RplTypeError < StandardError + attr_reader :reason + + def initialize( reason = "-undefined-" ) + @reason = reason + end +end + class Parser include Types @@ -68,7 +76,7 @@ class Parser end # 2. parse - regrouped_input.map do |element| + parsed_input = regrouped_input.map do |element| if RplBoolean.can_parse?( element ) Types.new_object( RplBoolean, element ) elsif RplNumeric.can_parse?( element ) @@ -83,5 +91,7 @@ class Parser Types.new_object( RplName, element ) end end + + parsed_input end end diff --git a/lib/rpl/types/string.rb b/lib/rpl/types/string.rb index 3d1d649..9318765 100644 --- a/lib/rpl/types/string.rb +++ b/lib/rpl/types/string.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +require 'rpl/parser' + module Types class RplString attr_accessor :value diff --git a/lib/rpl/words/operations.rb b/lib/rpl/words/operations.rb index 39310b9..e639aff 100644 --- a/lib/rpl/words/operations.rb +++ b/lib/rpl/words/operations.rb @@ -25,56 +25,50 @@ module RplLang args.reverse! result = if args[0].instance_of?( RplList ) - if args[1].instance_of?( RplList ) - args[0].value.concat( args[1].value ) - else - args[0].value << args[1] - end - args[0] + new_list = if args[1].instance_of?( RplList ) + RplList.new( args[0].to_s ).value.concat( args[1].value ) + else + RplList.new( args[0].to_s ).value.concat( [ args[1] ] ) + end + + RplList.new( "{ #{new_list.join(' ')} }" ) elsif args[1].instance_of?( RplList ) - if args[0].instance_of?( RplList ) - args[0].value.concat( args[1].value ) - args[0] - else - args[1].value.unshift( args[0] ) - args[1] - end + new_list = if args[0].instance_of?( RplList ) + RplList.new( args[0].to_s ).value.concat( args[1].value ) + else + RplList.new( "{ #{args[0]} }" ).value.concat( args[1].value ) + end + + RplList.new( "{ #{new_list.join(' ')} }" ) elsif args[0].instance_of?( RplString ) - args[0].value = if args[1].instance_of?( RplString ) || + RplString.new( if args[1].instance_of?( RplString ) || args[1].instance_of?( RplName ) - "#{args[0].value}#{args[1].value}" - else - "#{args[0].value}#{args[1]}" - end - args[0] + "\"#{args[0].value}#{args[1].value}\"" + else + "\"#{args[0].value}#{args[1]}\"" + end ) elsif args[0].instance_of?( RplName ) if args[1].instance_of?( RplName ) - args[0].value = "#{args[0].value}#{args[1].value}" - args[0] + RplName.new( "'#{args[0].value}#{args[1].value}'" ) + elsif args[1].instance_of?( RplString ) + Types.new_object( RplString, "\"#{args[0].value}#{args[1].value}\"" ) + elsif args[1].instance_of?( RplNumeric ) + RplName.new( "'#{args[0].value}#{args[1]}'" ) else - if args[1].instance_of?( RplString ) - Types.new_object( RplString, "\"#{args[0].value}#{args[1].value}\"" ) - elsif args[1].instance_of?( RplNumeric ) - args[0].value = "#{args[0].value}#{args[1]}" - args[0] - else - Types.new_object( RplString, "\"#{args[0]}#{args[1]}\"" ) - end + Types.new_object( RplString, "\"#{args[0]}#{args[1]}\"" ) end elsif args[0].instance_of?( RplNumeric ) if args[1].instance_of?( RplNumeric ) - args[0].value += args[1].value - args[0] - - elsif args[1].instance_of?( RplString ) || - args[1].instance_of?( RplName ) - args[1].value = "#{args[0]}#{args[1].value}" - args[1] + RplNumeric.new( args[0].value + args[1].value, args[0].base ) + elsif args[1].instance_of?( RplString ) + RplString.new( "\"#{args[0]}#{args[1].value}\"" ) + elsif args[1].instance_of?( RplName ) + RplName.new( "'#{args[0]}#{args[1].value}'" ) end end @@ -87,9 +81,7 @@ module RplLang proc do args = stack_extract( [[RplNumeric], [RplNumeric]] ) - args[1].value = args[1].value - args[0].value - - @stack << args[1] + @stack << RplNumeric.new( args[1].value - args[0].value, args[1].base ) end ) @dictionary.add_word( ['chs'], @@ -105,9 +97,7 @@ module RplLang proc do args = stack_extract( [[RplNumeric], [RplNumeric]] ) - args[1].value = args[1].value * args[0].value - - @stack << args[1] + @stack << RplNumeric.new( args[1].value * args[0].value, args[1].base ) end ) @dictionary.add_word( ['÷', '/'], @@ -116,9 +106,7 @@ module RplLang proc do args = stack_extract( [[RplNumeric], [RplNumeric]] ) - args[1].value = args[1].value / args[0].value - - @stack << args[1] + @stack << RplNumeric.new( args[1].value / args[0].value, args[1].base ) end ) @dictionary.add_word( ['inv'], @@ -134,9 +122,7 @@ module RplLang proc do args = stack_extract( [[RplNumeric], [RplNumeric]] ) - args[1].value = args[1].value**args[0].value - - @stack << args[1] + @stack << RplNumeric.new( args[1].value**args[0].value, args[1].base ) end ) @dictionary.add_word( ['√', 'sqrt'], @@ -145,9 +131,7 @@ module RplLang proc do args = stack_extract( [[RplNumeric]] ) - args[0].value = BigMath.sqrt( args[0].value, RplNumeric.precision ) - - @stack << args[0] + @stack << RplNumeric.new( BigMath.sqrt( args[0].value, RplNumeric.precision ), args[0].base ) end ) @dictionary.add_word( ['²', 'sq'], @@ -163,9 +147,7 @@ module RplLang proc do args = stack_extract( [[RplNumeric]] ) - args[0].value = args[0].value.abs - - @stack << args[0] + @stack << RplNumeric.new( args[0].value.abs, args[0].base ) end ) @dictionary.add_word( ['dec'], @@ -195,9 +177,7 @@ module RplLang proc do args = stack_extract( [[RplNumeric], [RplNumeric]] ) - args[1].base = args[0].value - - @stack << args[1] + @stack << RplNumeric.new( args[1].value, args[0].value ) end ) @dictionary.add_word( ['sign'], @@ -205,15 +185,14 @@ module RplLang '( a -- b ) sign of element', proc do args = stack_extract( [[RplNumeric]] ) - args[0].value = if args[0].value.positive? - 1 - elsif args[0].value.negative? - -1 - else - 0 - end - @stack << args[0] + @stack << RplNumeric.new( if args[0].value.positive? + 1 + elsif args[0].value.negative? + -1 + else + 0 + end ) end ) # Operations on reals @@ -223,9 +202,7 @@ module RplLang proc do args = stack_extract( [[RplNumeric], [RplNumeric]] ) - args[1].value = args[0].value * ( args[1].value / 100.0 ) - - @stack << args[1] + @stack << RplNumeric.new( args[0].value * ( args[1].value / 100.0 ), args[1].base ) end ) @dictionary.add_word( ['%CH'], @@ -234,9 +211,7 @@ module RplLang proc do args = stack_extract( [[RplNumeric], [RplNumeric]] ) - args[1].value = 100.0 * ( args[0].value / args[1].value ) - - @stack << args[1] + @stack << RplNumeric.new( 100.0 * ( args[0].value / args[1].value ), args[1].base ) end ) @dictionary.add_word( ['mod'], @@ -245,9 +220,7 @@ module RplLang proc do args = stack_extract( [[RplNumeric], [RplNumeric]] ) - args[1].value = args[1].value % args[0].value - - @stack << args[1] + @stack << RplNumeric.new( args[1].value % args[0].value, args[1].base ) end ) @dictionary.add_word( ['!', 'fact'], @@ -256,9 +229,7 @@ module RplLang proc do args = stack_extract( [[RplNumeric]] ) - args[0].value = Math.gamma( args[0].value ) - - @stack << args[0] + @stack << RplNumeric.new( Math.gamma( args[0].value ), args[0].base ) end ) @dictionary.add_word( ['floor'], @@ -267,9 +238,7 @@ module RplLang proc do args = stack_extract( [[RplNumeric]] ) - args[0].value = args[0].value.floor - - @stack << args[0] + @stack << RplNumeric.new( args[0].value.floor, args[0].base ) end ) @dictionary.add_word( ['ceil'], @@ -278,9 +247,7 @@ module RplLang proc do args = stack_extract( [[RplNumeric]] ) - args[0].value = args[0].value.ceil - - @stack << args[0] + @stack << RplNumeric.new( args[0].value.ceil, args[0].base ) end ) @dictionary.add_word( ['min'], @@ -316,9 +283,7 @@ module RplLang proc do args = stack_extract( [[RplNumeric]] ) - args[0].value = args[0].value.exponent - - @stack << args[0] + @stack << RplNumeric.new( args[0].value.exponent, args[0].base ) end ) @dictionary.add_word( ['ip'], @@ -334,9 +299,7 @@ module RplLang proc do args = stack_extract( [[RplNumeric]] ) - args[0].value = args[0].value.frac - - @stack << args[0] + @stack << RplNumeric.new( args[0].value.frac, args[0].base ) end ) # Operations on complexes diff --git a/lib/rpl/words/string-list.rb b/lib/rpl/words/string-list.rb index 6c99d8a..3d70298 100644 --- a/lib/rpl/words/string-list.rb +++ b/lib/rpl/words/string-list.rb @@ -98,9 +98,11 @@ module RplLang proc do args = stack_extract( [[RplString, RplList]] ) - args[0].value.reverse! - - @stack << args[0] + if args[0].is_a?( RplString ) + @stack << args[0].class.new( "\"#{args[0].value.reverse}\"" ) + else + @stack << args[0].class.new( "{ #{args[0].value.reverse.join(' ')} }" ) + end end ) @dictionary.add_word( ['split'], diff --git a/spec/language_operations_spec.rb b/spec/language_operations_spec.rb index e04754f..153d935 100644 --- a/spec/language_operations_spec.rb +++ b/spec/language_operations_spec.rb @@ -27,7 +27,7 @@ class TesttLanguageOperations < MiniTest::Test interpreter = Rpl.new interpreter.run '1 dup dup →list +' assert_equal [Types.new_object( RplList, [Types.new_object( RplNumeric, 1 ), - Types.new_object( RplNumeric, 1 )] )], + Types.new_object( RplNumeric, 1 )] )], interpreter.stack interpreter = Rpl.new @@ -48,7 +48,7 @@ class TesttLanguageOperations < MiniTest::Test interpreter = Rpl.new interpreter.run '"a" 1 dup →list +' assert_equal [Types.new_object( RplList, [Types.new_object( RplString, '"a"' ), - Types.new_object( RplNumeric, 1 )] )], + Types.new_object( RplNumeric, 1 )] )], interpreter.stack interpreter = Rpl.new @@ -69,25 +69,144 @@ class TesttLanguageOperations < MiniTest::Test interpreter = Rpl.new interpreter.run '\'a\' 1 dup →list +' assert_equal [Types.new_object( RplList, [Types.new_object( RplName, 'a' ), - Types.new_object( RplNumeric, 1 )] )], + Types.new_object( RplNumeric, 1 )] )], interpreter.stack interpreter = Rpl.new interpreter.run '1 a "test" 3 →list dup rev +' assert_equal [Types.new_object( RplList, [Types.new_object( RplNumeric, 1 ), - Types.new_object( RplName, 'a' ), - Types.new_object( RplString, '"test"' ), - Types.new_object( RplString, '"test"' ), - Types.new_object( RplName, 'a' ), - Types.new_object( RplNumeric, 1 )] )], + Types.new_object( RplName, 'a' ), + Types.new_object( RplString, '"test"' ), + Types.new_object( RplString, '"test"' ), + Types.new_object( RplName, 'a' ), + Types.new_object( RplNumeric, 1 )] )], interpreter.stack interpreter = Rpl.new interpreter.run '1 a "test" 3 →list 9 +' assert_equal [Types.new_object( RplList, [Types.new_object( RplNumeric, 1 ), - Types.new_object( RplName, 'a' ), - Types.new_object( RplString, '"test"' ), - Types.new_object( RplNumeric, 9 )] )], + Types.new_object( RplName, 'a' ), + Types.new_object( RplString, '"test"' ), + Types.new_object( RplNumeric, 9 )] )], + interpreter.stack + + ################# + # now with vars # + ################# + + interpreter = Rpl.new + interpreter.run '1 \'a\' sto 2 \'b\' sto a b + a b' + assert_equal [Types.new_object( RplNumeric, 3 ), + Types.new_object( RplNumeric, 1 ), + Types.new_object( RplNumeric, 2 )], + interpreter.stack + + interpreter = Rpl.new + interpreter.run '1 \'a\' sto "a" \'b\' sto a b + a b' + assert_equal [Types.new_object( RplString, '"1a"' ), + Types.new_object( RplNumeric, 1 ), + Types.new_object( RplString, '"a"' )], + interpreter.stack + + interpreter = Rpl.new + interpreter.run '1 \'a\' sto \'z\' \'b\' sto a b + a b' + assert_equal [Types.new_object( RplName, "'1z'" ), + Types.new_object( RplNumeric, 1 ), + Types.new_object( RplName, "'z'" )], + interpreter.stack + + interpreter = Rpl.new + interpreter.run '1 \'a\' sto a dup →list \'b\' sto a b + a b' + assert_equal [Types.new_object( RplList, [Types.new_object( RplNumeric, 1 ), + Types.new_object( RplNumeric, 1 )] ), + Types.new_object( RplNumeric, 1 ), + Types.new_object( RplList, [Types.new_object( RplNumeric, 1 )] )], + interpreter.stack + + interpreter = Rpl.new + interpreter.run '"a" \'a\' sto "b" \'b\' sto a b + a b' + assert_equal [Types.new_object( RplString, '"ab"' ), + Types.new_object( RplString, '"a"' ), + Types.new_object( RplString, '"b"' )], + interpreter.stack + + interpreter = Rpl.new + interpreter.run '"a" \'a\' sto \'z\' \'b\' sto a b + a b' + assert_equal [Types.new_object( RplString, '"az"' ), + Types.new_object( RplString, '"a"' ), + Types.new_object( RplName, "'z'" )], + interpreter.stack + + interpreter = Rpl.new + interpreter.run '"a" \'a\' sto 1 \'b\' sto a b + a b' + assert_equal [Types.new_object( RplString, '"a1"' ), + Types.new_object( RplString, '"a"' ), + Types.new_object( RplNumeric, 1 )], + interpreter.stack + + interpreter = Rpl.new + interpreter.run '"a" \'a\' sto 1 dup →list \'b\' sto a b + a b' + assert_equal [Types.new_object( RplList, [Types.new_object( RplString, '"a"' ), + Types.new_object( RplNumeric, 1 )] ), + Types.new_object( RplString, '"a"' ), + Types.new_object( RplList, [Types.new_object( RplNumeric, 1 )] )], + interpreter.stack + + interpreter = Rpl.new + interpreter.run '\'z\' \'a\' sto 1 \'b\' sto a b + a b' + assert_equal [Types.new_object( RplName, 'z1' ), + Types.new_object( RplName, 'z' ), + Types.new_object( RplNumeric, 1 )], + interpreter.stack + + interpreter = Rpl.new + interpreter.run '\'z\' \'a\' sto "b" \'b\' sto a b + a b' + assert_equal [Types.new_object( RplString, '"zb"' ), + Types.new_object( RplName, "'z'" ), + Types.new_object( RplString, '"b"' )], + interpreter.stack + + interpreter = Rpl.new + interpreter.run '\'z\' \'a\' sto \'y\' \'b\' sto a b + a b' + assert_equal [Types.new_object( RplName, "'zy'" ), + Types.new_object( RplName, "'z'" ), + Types.new_object( RplName, "'y'" )], + interpreter.stack + + interpreter = Rpl.new + interpreter.run '\'z\' \'a\' sto 1 dup →list \'b\' sto a b + a b' + assert_equal [Types.new_object( RplList, [Types.new_object( RplName, "'z'" ), + Types.new_object( RplNumeric, 1 )] ), + Types.new_object( RplName, "'z'" ), + Types.new_object( RplList, [Types.new_object( RplNumeric, 1 )] )], + interpreter.stack + + interpreter = Rpl.new + interpreter.run '1 z "test" 3 →list \'a\' sto a rev \'b\' sto a b + a b' + assert_equal [Types.new_object( RplList, [Types.new_object( RplNumeric, 1 ), + Types.new_object( RplName, 'z' ), + Types.new_object( RplString, '"test"' ), + Types.new_object( RplString, '"test"' ), + Types.new_object( RplName, 'z' ), + Types.new_object( RplNumeric, 1 )] ), + Types.new_object( RplList, [Types.new_object( RplNumeric, 1 ), + Types.new_object( RplName, 'z' ), + Types.new_object( RplString, '"test"' )] ), + Types.new_object( RplList, [Types.new_object( RplString, '"test"' ), + Types.new_object( RplName, 'z' ), + Types.new_object( RplNumeric, 1 )] )], + interpreter.stack + + interpreter = Rpl.new + interpreter.run '1 a "test" 3 →list \'a\' sto 9 \'b\' sto a b + a b' + assert_equal [Types.new_object( RplList, [Types.new_object( RplNumeric, 1 ), + Types.new_object( RplName, 'a' ), + Types.new_object( RplString, '"test"' ), + Types.new_object( RplNumeric, 9 )] ), + Types.new_object( RplList, [Types.new_object( RplNumeric, 1 ), + Types.new_object( RplName, 'a' ), + Types.new_object( RplString, '"test"' )] ), + Types.new_object( RplNumeric, 9 )], interpreter.stack end