rpl 0.1.1 → 0.5.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 +4 -4
- data/bin/rpl +38 -3
- data/lib/rpl/core/operations.rb +9 -5
- data/lib/rpl/core/program.rb +5 -1
- data/lib/rpl/interpreter.rb +62 -16
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: db2185e41b8f4562c26b03d1b71ae420661697cb7dfbe3fe27763bc13146427b
|
4
|
+
data.tar.gz: 7130c10e23d621b08d2a71840b48afc5adbd49d8ed2e8f4fc80e507f07cc5dd3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9a45f40c4fd25cf9eb5471d02cbcd74e2512744e81495aeaeee2f90e278298f09e6f8168caf10f97f93da56c2beadb992c0d927c5bf27a337a21f5ef07fcc6d8
|
7
|
+
data.tar.gz: 44a18620e90a806ebc24488e133e9250dab50165ec27508d5f0d867b7b32e9fee6bb6aa311cfacfe2ccb796e3a8ac408caf1b5e5f4938a81b2ff9aaba21a1603
|
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
|
-
|
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
|
-
|
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(' ')
|
data/lib/rpl/core/operations.rb
CHANGED
@@ -293,12 +293,16 @@ module RplLang
|
|
293
293
|
@stack << ( args[0][:value] > args[1][:value] ? args[0] : args[1] )
|
294
294
|
end )
|
295
295
|
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
296
|
+
@dictionary.add_word( ['mant'],
|
297
|
+
'Operations on reals',
|
298
|
+
'mantissa of a real number',
|
299
|
+
proc do
|
300
|
+
args = stack_extract( [%i[numeric]] )
|
300
301
|
|
301
|
-
|
302
|
+
@stack << { type: :numeric,
|
303
|
+
base: infer_resulting_base( args ),
|
304
|
+
value: BigDecimal( args[0][:value].to_s.split('e').first.to_f.abs, @precision ) }
|
305
|
+
end )
|
302
306
|
|
303
307
|
@dictionary.add_word( ['xpon'],
|
304
308
|
'Operations on reals',
|
data/lib/rpl/core/program.rb
CHANGED
@@ -12,7 +12,11 @@ module RplLang
|
|
12
12
|
proc do
|
13
13
|
args = stack_extract( [:any] )
|
14
14
|
|
15
|
-
|
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
|
data/lib/rpl/interpreter.rb
CHANGED
@@ -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
|
-
|
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]
|
134
|
+
elsif %I[program].include?( parsed_entry[:type] )
|
101
135
|
parsed_entry[:value] = parsed_entry[:value][2..-3]
|
102
|
-
elsif parsed_entry[:type]
|
103
|
-
parsed_entry[:
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
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
|
-
"
|
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.
|
4
|
+
version: 0.5.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-
|
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
|