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 +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 +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fabbce316a5c08423208383985c44621b20e0032499072ada99fe46aa24b7f9a
|
4
|
+
data.tar.gz: d1861c145f2647640cf5192fd376177a2565915e979a15cb46a34a7e340d6171
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
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
@@ -300,12 +300,16 @@ module RplLang
|
|
300
300
|
|
301
301
|
# end )
|
302
302
|
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
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
|
-
|
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',
|
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.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-
|
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.
|
57
|
+
rubygems_version: 3.2.32
|
58
58
|
signing_key:
|
59
59
|
specification_version: 4
|
60
60
|
summary: Functional Stack Language
|