[bug] fix variable overwriting bug

This commit is contained in:
Gwenhael Le Moine 2022-08-30 14:34:15 +02:00
parent 703c659f83
commit db0d8cb5a9
No known key found for this signature in database
GPG key ID: FDFE3669426707A7
6 changed files with 200 additions and 105 deletions

View file

@ -7,7 +7,6 @@ To run REPL locally: `rake run`
To run the test suite: `rake test` To run the test suite: `rake test`
# BUGs # BUGs
* var1 var2 +|-|*|\ ===> result in on stack (normal) AND stored in var1 (_bug_)
# TODO-list # TODO-list
* pseudo filesystem: subdir/namespace for variables * pseudo filesystem: subdir/namespace for variables

View file

@ -1,5 +1,13 @@
# frozen_string_literal: true # frozen_string_literal: true
class RplTypeError < StandardError
attr_reader :reason
def initialize( reason = "-undefined-" )
@reason = reason
end
end
class Parser class Parser
include Types include Types
@ -68,7 +76,7 @@ class Parser
end end
# 2. parse # 2. parse
regrouped_input.map do |element| parsed_input = regrouped_input.map do |element|
if RplBoolean.can_parse?( element ) if RplBoolean.can_parse?( element )
Types.new_object( RplBoolean, element ) Types.new_object( RplBoolean, element )
elsif RplNumeric.can_parse?( element ) elsif RplNumeric.can_parse?( element )
@ -83,5 +91,7 @@ class Parser
Types.new_object( RplName, element ) Types.new_object( RplName, element )
end end
end end
parsed_input
end end
end end

View file

@ -1,5 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
require 'rpl/parser'
module Types module Types
class RplString class RplString
attr_accessor :value attr_accessor :value

View file

@ -25,56 +25,50 @@ module RplLang
args.reverse! args.reverse!
result = if args[0].instance_of?( RplList ) result = if args[0].instance_of?( RplList )
if args[1].instance_of?( RplList ) new_list = if args[1].instance_of?( RplList )
args[0].value.concat( args[1].value ) RplList.new( args[0].to_s ).value.concat( args[1].value )
else else
args[0].value << args[1] RplList.new( args[0].to_s ).value.concat( [ args[1] ] )
end end
args[0]
RplList.new( "{ #{new_list.join(' ')} }" )
elsif args[1].instance_of?( RplList ) elsif args[1].instance_of?( RplList )
if args[0].instance_of?( RplList ) new_list = if args[0].instance_of?( RplList )
args[0].value.concat( args[1].value ) RplList.new( args[0].to_s ).value.concat( args[1].value )
args[0] else
else RplList.new( "{ #{args[0]} }" ).value.concat( args[1].value )
args[1].value.unshift( args[0] ) end
args[1]
end RplList.new( "{ #{new_list.join(' ')} }" )
elsif args[0].instance_of?( RplString ) 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[1].instance_of?( RplName )
"#{args[0].value}#{args[1].value}" "\"#{args[0].value}#{args[1].value}\""
else else
"#{args[0].value}#{args[1]}" "\"#{args[0].value}#{args[1]}\""
end end )
args[0]
elsif args[0].instance_of?( RplName ) elsif args[0].instance_of?( RplName )
if args[1].instance_of?( RplName ) if args[1].instance_of?( RplName )
args[0].value = "#{args[0].value}#{args[1].value}" RplName.new( "'#{args[0].value}#{args[1].value}'" )
args[0] 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 else
if args[1].instance_of?( RplString ) Types.new_object( RplString, "\"#{args[0]}#{args[1]}\"" )
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
end end
elsif args[0].instance_of?( RplNumeric ) elsif args[0].instance_of?( RplNumeric )
if args[1].instance_of?( RplNumeric ) if args[1].instance_of?( RplNumeric )
args[0].value += args[1].value RplNumeric.new( args[0].value + args[1].value, args[0].base )
args[0] elsif args[1].instance_of?( RplString )
RplString.new( "\"#{args[0]}#{args[1].value}\"" )
elsif args[1].instance_of?( RplString ) || elsif args[1].instance_of?( RplName )
args[1].instance_of?( RplName ) RplName.new( "'#{args[0]}#{args[1].value}'" )
args[1].value = "#{args[0]}#{args[1].value}"
args[1]
end end
end end
@ -87,9 +81,7 @@ module RplLang
proc do proc do
args = stack_extract( [[RplNumeric], [RplNumeric]] ) args = stack_extract( [[RplNumeric], [RplNumeric]] )
args[1].value = args[1].value - args[0].value @stack << RplNumeric.new( args[1].value - args[0].value, args[1].base )
@stack << args[1]
end ) end )
@dictionary.add_word( ['chs'], @dictionary.add_word( ['chs'],
@ -105,9 +97,7 @@ module RplLang
proc do proc do
args = stack_extract( [[RplNumeric], [RplNumeric]] ) args = stack_extract( [[RplNumeric], [RplNumeric]] )
args[1].value = args[1].value * args[0].value @stack << RplNumeric.new( args[1].value * args[0].value, args[1].base )
@stack << args[1]
end ) end )
@dictionary.add_word( ['÷', '/'], @dictionary.add_word( ['÷', '/'],
@ -116,9 +106,7 @@ module RplLang
proc do proc do
args = stack_extract( [[RplNumeric], [RplNumeric]] ) args = stack_extract( [[RplNumeric], [RplNumeric]] )
args[1].value = args[1].value / args[0].value @stack << RplNumeric.new( args[1].value / args[0].value, args[1].base )
@stack << args[1]
end ) end )
@dictionary.add_word( ['inv'], @dictionary.add_word( ['inv'],
@ -134,9 +122,7 @@ module RplLang
proc do proc do
args = stack_extract( [[RplNumeric], [RplNumeric]] ) args = stack_extract( [[RplNumeric], [RplNumeric]] )
args[1].value = args[1].value**args[0].value @stack << RplNumeric.new( args[1].value**args[0].value, args[1].base )
@stack << args[1]
end ) end )
@dictionary.add_word( ['√', 'sqrt'], @dictionary.add_word( ['√', 'sqrt'],
@ -145,9 +131,7 @@ module RplLang
proc do proc do
args = stack_extract( [[RplNumeric]] ) args = stack_extract( [[RplNumeric]] )
args[0].value = BigMath.sqrt( args[0].value, RplNumeric.precision ) @stack << RplNumeric.new( BigMath.sqrt( args[0].value, RplNumeric.precision ), args[0].base )
@stack << args[0]
end ) end )
@dictionary.add_word( ['²', 'sq'], @dictionary.add_word( ['²', 'sq'],
@ -163,9 +147,7 @@ module RplLang
proc do proc do
args = stack_extract( [[RplNumeric]] ) args = stack_extract( [[RplNumeric]] )
args[0].value = args[0].value.abs @stack << RplNumeric.new( args[0].value.abs, args[0].base )
@stack << args[0]
end ) end )
@dictionary.add_word( ['dec'], @dictionary.add_word( ['dec'],
@ -195,9 +177,7 @@ module RplLang
proc do proc do
args = stack_extract( [[RplNumeric], [RplNumeric]] ) args = stack_extract( [[RplNumeric], [RplNumeric]] )
args[1].base = args[0].value @stack << RplNumeric.new( args[1].value, args[0].value )
@stack << args[1]
end ) end )
@dictionary.add_word( ['sign'], @dictionary.add_word( ['sign'],
@ -205,15 +185,14 @@ module RplLang
'( a -- b ) sign of element', '( a -- b ) sign of element',
proc do proc do
args = stack_extract( [[RplNumeric]] ) 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 ) end )
# Operations on reals # Operations on reals
@ -223,9 +202,7 @@ module RplLang
proc do proc do
args = stack_extract( [[RplNumeric], [RplNumeric]] ) args = stack_extract( [[RplNumeric], [RplNumeric]] )
args[1].value = args[0].value * ( args[1].value / 100.0 ) @stack << RplNumeric.new( args[0].value * ( args[1].value / 100.0 ), args[1].base )
@stack << args[1]
end ) end )
@dictionary.add_word( ['%CH'], @dictionary.add_word( ['%CH'],
@ -234,9 +211,7 @@ module RplLang
proc do proc do
args = stack_extract( [[RplNumeric], [RplNumeric]] ) args = stack_extract( [[RplNumeric], [RplNumeric]] )
args[1].value = 100.0 * ( args[0].value / args[1].value ) @stack << RplNumeric.new( 100.0 * ( args[0].value / args[1].value ), args[1].base )
@stack << args[1]
end ) end )
@dictionary.add_word( ['mod'], @dictionary.add_word( ['mod'],
@ -245,9 +220,7 @@ module RplLang
proc do proc do
args = stack_extract( [[RplNumeric], [RplNumeric]] ) args = stack_extract( [[RplNumeric], [RplNumeric]] )
args[1].value = args[1].value % args[0].value @stack << RplNumeric.new( args[1].value % args[0].value, args[1].base )
@stack << args[1]
end ) end )
@dictionary.add_word( ['!', 'fact'], @dictionary.add_word( ['!', 'fact'],
@ -256,9 +229,7 @@ module RplLang
proc do proc do
args = stack_extract( [[RplNumeric]] ) args = stack_extract( [[RplNumeric]] )
args[0].value = Math.gamma( args[0].value ) @stack << RplNumeric.new( Math.gamma( args[0].value ), args[0].base )
@stack << args[0]
end ) end )
@dictionary.add_word( ['floor'], @dictionary.add_word( ['floor'],
@ -267,9 +238,7 @@ module RplLang
proc do proc do
args = stack_extract( [[RplNumeric]] ) args = stack_extract( [[RplNumeric]] )
args[0].value = args[0].value.floor @stack << RplNumeric.new( args[0].value.floor, args[0].base )
@stack << args[0]
end ) end )
@dictionary.add_word( ['ceil'], @dictionary.add_word( ['ceil'],
@ -278,9 +247,7 @@ module RplLang
proc do proc do
args = stack_extract( [[RplNumeric]] ) args = stack_extract( [[RplNumeric]] )
args[0].value = args[0].value.ceil @stack << RplNumeric.new( args[0].value.ceil, args[0].base )
@stack << args[0]
end ) end )
@dictionary.add_word( ['min'], @dictionary.add_word( ['min'],
@ -316,9 +283,7 @@ module RplLang
proc do proc do
args = stack_extract( [[RplNumeric]] ) args = stack_extract( [[RplNumeric]] )
args[0].value = args[0].value.exponent @stack << RplNumeric.new( args[0].value.exponent, args[0].base )
@stack << args[0]
end ) end )
@dictionary.add_word( ['ip'], @dictionary.add_word( ['ip'],
@ -334,9 +299,7 @@ module RplLang
proc do proc do
args = stack_extract( [[RplNumeric]] ) args = stack_extract( [[RplNumeric]] )
args[0].value = args[0].value.frac @stack << RplNumeric.new( args[0].value.frac, args[0].base )
@stack << args[0]
end ) end )
# Operations on complexes # Operations on complexes

View file

@ -98,9 +98,11 @@ module RplLang
proc do proc do
args = stack_extract( [[RplString, RplList]] ) args = stack_extract( [[RplString, RplList]] )
args[0].value.reverse! if args[0].is_a?( RplString )
@stack << args[0].class.new( "\"#{args[0].value.reverse}\"" )
@stack << args[0] else
@stack << args[0].class.new( "{ #{args[0].value.reverse.join(' ')} }" )
end
end ) end )
@dictionary.add_word( ['split'], @dictionary.add_word( ['split'],

View file

@ -27,7 +27,7 @@ class TesttLanguageOperations < MiniTest::Test
interpreter = Rpl.new interpreter = Rpl.new
interpreter.run '1 dup dup →list +' interpreter.run '1 dup dup →list +'
assert_equal [Types.new_object( RplList, [Types.new_object( RplNumeric, 1 ), assert_equal [Types.new_object( RplList, [Types.new_object( RplNumeric, 1 ),
Types.new_object( RplNumeric, 1 )] )], Types.new_object( RplNumeric, 1 )] )],
interpreter.stack interpreter.stack
interpreter = Rpl.new interpreter = Rpl.new
@ -48,7 +48,7 @@ class TesttLanguageOperations < MiniTest::Test
interpreter = Rpl.new interpreter = Rpl.new
interpreter.run '"a" 1 dup →list +' interpreter.run '"a" 1 dup →list +'
assert_equal [Types.new_object( RplList, [Types.new_object( RplString, '"a"' ), assert_equal [Types.new_object( RplList, [Types.new_object( RplString, '"a"' ),
Types.new_object( RplNumeric, 1 )] )], Types.new_object( RplNumeric, 1 )] )],
interpreter.stack interpreter.stack
interpreter = Rpl.new interpreter = Rpl.new
@ -69,25 +69,144 @@ class TesttLanguageOperations < MiniTest::Test
interpreter = Rpl.new interpreter = Rpl.new
interpreter.run '\'a\' 1 dup →list +' interpreter.run '\'a\' 1 dup →list +'
assert_equal [Types.new_object( RplList, [Types.new_object( RplName, 'a' ), assert_equal [Types.new_object( RplList, [Types.new_object( RplName, 'a' ),
Types.new_object( RplNumeric, 1 )] )], Types.new_object( RplNumeric, 1 )] )],
interpreter.stack interpreter.stack
interpreter = Rpl.new interpreter = Rpl.new
interpreter.run '1 a "test" 3 →list dup rev +' interpreter.run '1 a "test" 3 →list dup rev +'
assert_equal [Types.new_object( RplList, [Types.new_object( RplNumeric, 1 ), assert_equal [Types.new_object( RplList, [Types.new_object( RplNumeric, 1 ),
Types.new_object( RplName, 'a' ), Types.new_object( RplName, 'a' ),
Types.new_object( RplString, '"test"' ), Types.new_object( RplString, '"test"' ),
Types.new_object( RplString, '"test"' ), Types.new_object( RplString, '"test"' ),
Types.new_object( RplName, 'a' ), Types.new_object( RplName, 'a' ),
Types.new_object( RplNumeric, 1 )] )], Types.new_object( RplNumeric, 1 )] )],
interpreter.stack interpreter.stack
interpreter = Rpl.new interpreter = Rpl.new
interpreter.run '1 a "test" 3 →list 9 +' interpreter.run '1 a "test" 3 →list 9 +'
assert_equal [Types.new_object( RplList, [Types.new_object( RplNumeric, 1 ), assert_equal [Types.new_object( RplList, [Types.new_object( RplNumeric, 1 ),
Types.new_object( RplName, 'a' ), Types.new_object( RplName, 'a' ),
Types.new_object( RplString, '"test"' ), Types.new_object( RplString, '"test"' ),
Types.new_object( RplNumeric, 9 )] )], 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 interpreter.stack
end end