rpl 0.1.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b8843f4b55d77c8d3ec6c92cbe565ecb883361ba8cb47628097425b4b6f73da2
4
- data.tar.gz: 430db66a68a4eeead6b16091e75aa9022a6a734004006067a38fb5283c3ec261
3
+ metadata.gz: fabbce316a5c08423208383985c44621b20e0032499072ada99fe46aa24b7f9a
4
+ data.tar.gz: d1861c145f2647640cf5192fd376177a2565915e979a15cb46a34a7e340d6171
5
5
  SHA512:
6
- metadata.gz: 7eff83ebc75b43ba473b913513590b82286932dd8b9628f9ae8970bb8d352ddd60a057e648d31fad7a5fefab974d2ddbcd9a03b18094c8c977e709bf1d910f56
7
- data.tar.gz: 5fcd3aa9b3c9d918876fc5f69e3025a2f0339a4e0da8c2bc66432db11821ded06a149b3dcfe88d2d3d955c90ca42c86d0f2a4dc1257612bc5804380cf0638a4a
6
+ metadata.gz: 2150ec4f68a633e83e1e17ce6508ad706e8e3a5cfe9e3683322f9e257d59ac6d37303d2ea87072f4479fe2b42189231748e3d294028a2fdfa6952ad8ae528aa3
7
+ data.tar.gz: 9e4b5766997db3b9825bd9d713e90a0494d3a007f3f4882bfe7f5eb5aed2e5b47281ee9d077e96915697f884e4a362aed3f652ce647e71b92cee1c4689e4212e
data/bin/rpl CHANGED
@@ -1,16 +1,21 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
+ require 'English'
5
+ require 'optparse'
4
6
  require 'readline'
5
7
 
6
8
  require 'rpl'
7
9
 
8
10
  class RplRepl
9
- def initialize
10
- @interpreter = Rpl.new
11
+ def initialize( interpreter )
12
+ interpreter ||= Rpl.new
13
+ @interpreter = interpreter
11
14
  end
12
15
 
13
16
  def run
17
+ print_stack unless @interpreter.stack.empty?
18
+
14
19
  Readline.completion_proc = proc do |s|
15
20
  ( @interpreter.dictionary.words.keys + @interpreter.dictionary.vars.keys ).grep(/^#{Regexp.escape(s)}/)
16
21
  end
@@ -48,4 +53,34 @@ class RplRepl
48
53
  end
49
54
  end
50
55
 
51
- RplRepl.new.run
56
+ interpreter = Rpl.new
57
+
58
+ options = { run_REPL: ARGV.empty?,
59
+ files: [],
60
+ programs: [] }
61
+
62
+ OptionParser.new do |opts|
63
+ opts.on('-c', '--code "program"', ' ') do |program|
64
+ options[:programs] << program
65
+ end
66
+
67
+ opts.on('-f', '--file program.rpl', 'load program.rpl') do |filename|
68
+ options[:files] << filename
69
+ end
70
+
71
+ opts.on('-i', '--interactive', 'launch interactive REPL') do
72
+ options[:run_REPL] = true
73
+ end
74
+ end.parse!
75
+
76
+ options[:files].each do |filename|
77
+ interpreter.run "\"#{filename}\" feval"
78
+ end
79
+
80
+ options[:programs].each do |program|
81
+ interpreter.run program
82
+ end
83
+
84
+ RplRepl.new( interpreter ).run if options[:run_REPL]
85
+
86
+ pp interpreter.stack.map { |elt| interpreter.stringify( elt ) }.join(' ')
@@ -300,12 +300,16 @@ module RplLang
300
300
 
301
301
  # end )
302
302
 
303
- # @dictionary.add_word( ['xpon'],
304
- # 'Operations on reals',
305
- # 'exponant of a real number',
306
- # proc do
303
+ @dictionary.add_word( ['xpon'],
304
+ 'Operations on reals',
305
+ 'exponant of a real number',
306
+ proc do
307
+ args = stack_extract( [%i[numeric]] )
307
308
 
308
- # end )
309
+ @stack << { type: :numeric,
310
+ base: infer_resulting_base( args ),
311
+ value: args[0][:value].exponent }
312
+ end )
309
313
 
310
314
  @dictionary.add_word( ['ip'],
311
315
  'Operations on reals',
@@ -12,7 +12,11 @@ module RplLang
12
12
  proc do
13
13
  args = stack_extract( [:any] )
14
14
 
15
- run( args[0][:value].to_s )
15
+ if %i[list numeric boolean].include?( args[0][:type] )
16
+ @stack << args[0] # these types evaluate to themselves
17
+ else
18
+ run( args[0][:value].to_s )
19
+ end
16
20
  end )
17
21
  end
18
22
  end
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'bigdecimal'
3
4
  require 'bigdecimal/math'
5
+ require 'bigdecimal/util'
4
6
 
5
7
  require 'rpl/dictionary'
6
8
 
@@ -41,12 +43,31 @@ class Interpreter
41
43
  end
42
44
  end
43
45
 
46
+ unless input.index("\n").nil?
47
+ input = input
48
+ .split("\n")
49
+ .map do |line|
50
+ comment_begin_index = line.index('#')
51
+
52
+ if comment_begin_index.nil?
53
+ line
54
+ elsif comment_begin_index == 0
55
+ ''
56
+ else
57
+ line[0..(comment_begin_index - 1)]
58
+ end
59
+ end
60
+ .join(' ')
61
+ end
62
+
44
63
  splitted_input = input.split(' ')
45
64
 
46
65
  # 2-passes:
47
66
  # 1. regroup strings and programs
48
67
  opened_programs = 0
49
68
  closed_programs = 0
69
+ opened_lists = 0
70
+ closed_lists = 0
50
71
  string_delimiters = 0
51
72
  name_delimiters = 0
52
73
  regrouping = false
@@ -56,22 +77,33 @@ class Interpreter
56
77
  if elt[0] == '«'
57
78
  opened_programs += 1
58
79
  elt.gsub!( '«', '« ') if elt.length > 1 && elt[1] != ' '
80
+ elsif elt[0] == '{'
81
+ opened_lists += 1
82
+ elt.gsub!( '{', '{ ') if elt.length > 1 && elt[1] != ' '
83
+ elsif elt[0] == '"' && elt.length > 1
84
+ string_delimiters += 1
85
+ elsif elt[0] == "'" && elt.length > 1
86
+ name_delimiters += 1
59
87
  end
60
- string_delimiters += 1 if elt[0] == '"' && elt.length > 1
61
- name_delimiters += 1 if elt[0] == "'" && elt.length > 1
62
88
 
63
89
  elt = "#{regrouped_input.pop} #{elt}".strip if regrouping
64
90
 
65
91
  regrouped_input << elt
66
92
 
67
- if elt[-1] == '»'
93
+ case elt[-1]
94
+ when '»'
68
95
  closed_programs += 1
69
96
  elt.gsub!( '»', ' »') if elt.length > 1 && elt[-2] != ' '
97
+ when '}'
98
+ closed_lists += 1
99
+ elt.gsub!( '}', ' }') if elt.length > 1 && elt[-2] != ' '
100
+ when '"'
101
+ string_delimiters += 1
102
+ when "'"
103
+ name_delimiters += 1
70
104
  end
71
- string_delimiters += 1 if elt[-1] == '"'
72
- name_delimiters += 1 if elt[-1] == "'"
73
105
 
74
- regrouping = string_delimiters.odd? || name_delimiters.odd? || (opened_programs > closed_programs )
106
+ regrouping = string_delimiters.odd? || name_delimiters.odd? || (opened_programs > closed_programs ) || (opened_lists > closed_lists )
75
107
  end
76
108
 
77
109
  # 2. parse
@@ -83,6 +115,8 @@ class Interpreter
83
115
  parsed_entry[:type] = case elt[0]
84
116
  when '«'
85
117
  :program
118
+ when '{'
119
+ :list
86
120
  when '"'
87
121
  :string
88
122
  when "'"
@@ -97,18 +131,30 @@ class Interpreter
97
131
 
98
132
  if %I[string name].include?( parsed_entry[:type] )
99
133
  parsed_entry[:value] = parsed_entry[:value][1..-2]
100
- elsif parsed_entry[:type] == :program
134
+ elsif %I[program].include?( parsed_entry[:type] )
101
135
  parsed_entry[:value] = parsed_entry[:value][2..-3]
102
- elsif parsed_entry[:type] == :numeric
103
- parsed_entry[:base] = 10 # TODO: parse others possible bases 0x...
104
-
105
- begin
106
- parsed_entry[:value] = Float( parsed_entry[:value] )
107
- parsed_entry[:value] = parsed_entry[:value].to_i if (parsed_entry[:value] % 1).zero? && elt.index('.').nil?
108
- rescue ArgumentError
109
- parsed_entry[:value] = Integer( parsed_entry[:value] )
136
+ elsif %I[list].include?( parsed_entry[:type] )
137
+ parsed_entry[:value] = parse( parsed_entry[:value][2..-3] )
138
+ elsif %I[numeric].include?( parsed_entry[:type] )
139
+ underscore_position = parsed_entry[:value].index('_')
140
+
141
+ if parsed_entry[:value][0] == '0' && ( ['b', 'o', 'x'].include?( parsed_entry[:value][1] ) || !underscore_position.nil? )
142
+ if parsed_entry[:value][1] == 'x'
143
+ parsed_entry[:base] = 16
144
+ elsif parsed_entry[:value][1] == 'b'
145
+ parsed_entry[:base] = 2
146
+ elsif parsed_entry[:value][1] == 'o'
147
+ parsed_entry[:base] = 8
148
+ parsed_entry[:value] = parsed_entry[:value][2..]
149
+ elsif !underscore_position.nil?
150
+ parsed_entry[:base] = parsed_entry[:value][1..(underscore_position - 1)].to_i
151
+ parsed_entry[:value] = parsed_entry[:value][(underscore_position + 1)..]
152
+ end
153
+ else
154
+ parsed_entry[:base] = 10
110
155
  end
111
156
 
157
+ parsed_entry[:value] = parsed_entry[:value].to_i( parsed_entry[:base] ) unless parsed_entry[:base] == 10
112
158
  parsed_entry[:value] = BigDecimal( parsed_entry[:value], @precision )
113
159
  end
114
160
 
@@ -197,7 +243,7 @@ class Interpreter
197
243
 
198
244
  "#{prefix}#{suffix}"
199
245
  when :list
200
- "[#{elt[:value].map { |e| stringify( e ) }.join(', ')}]"
246
+ "{ #{elt[:value].map { |e| stringify( e ) }.join(' ')} }"
201
247
  when :program
202
248
  "« #{elt[:value]} »"
203
249
  when :string
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rpl
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gwenhael Le Moine
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-02-15 00:00:00.000000000 Z
11
+ date: 2022-02-22 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A language inspired by HP's RPL and https://github.com/louisrubet/rpn/
14
14
  email: gwenhael@le-moine.org
@@ -45,7 +45,7 @@ require_paths:
45
45
  - lib
46
46
  required_ruby_version: !ruby/object:Gem::Requirement
47
47
  requirements:
48
- - - "~>"
48
+ - - ">"
49
49
  - !ruby/object:Gem::Version
50
50
  version: '2.7'
51
51
  required_rubygems_version: !ruby/object:Gem::Requirement
@@ -54,7 +54,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
54
54
  - !ruby/object:Gem::Version
55
55
  version: '0'
56
56
  requirements: []
57
- rubygems_version: 3.0.3.1
57
+ rubygems_version: 3.2.32
58
58
  signing_key:
59
59
  specification_version: 4
60
60
  summary: Functional Stack Language