rus3 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dfda189d1f2499f00d441efe70f0e8db49ecc443a8c414ec7b4f9282caf28fe2
4
- data.tar.gz: 1a0c858ec768aec68e79b66815fd8b5cdd2c6eef2f4e688e55f90fbcd1fde558
3
+ metadata.gz: e00bc6347634a3d6fd3ee9da17b18334e49373bab389c9c0126e5ee983504b56
4
+ data.tar.gz: 369f1e8627bdcb5c8ece22d0ba4971b417fa4924fa67ca31da3665bebb6a3aa8
5
5
  SHA512:
6
- metadata.gz: cb42c290cdcea8dacd9ae0b024ce0c2b266ae912ddc4178c40c5134fda5a79507d420ab959fc10a9860dd8bf3d805e16347a9cd791c4e90ddffaf1e7afd29932
7
- data.tar.gz: 16450eb77a484889dc5572a62fd48670b278fac5f4845111d6b192dbf8820bac54854a150a628004b9461b995a166f1957876d72636b732b11cf7c6db3dbc6c6
6
+ metadata.gz: 4eac508d23d36f6f1f7f6b60879bfbb80921c16ed669ed2d60e5d4d8926a62189269c8cef2373e6489d3dae3b47af01ee888116ecd8a85070f84ce3c8493e57a
7
+ data.tar.gz: ac9f76be872b9a5d70822f4bf0d4fab3da83d931002fd2f7b749648f704e65b7063487f9e9d095630a8c5bb8e9dd2f3e3b24fef3f24338d83e49cc73404a603c
data/CHANGELOG.md CHANGED
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
7
7
  ## [Unreleased]
8
8
  - (nothing to record)
9
9
 
10
+ ## [0.1.2] - 2021-04-23
11
+ ### Added
12
+ - Add `char`:
13
+ - add Rus3::Char class,
14
+ - modify Rus3::Parser::Lexer to accept a character literal,
15
+ - modify Rus3::Parser::SchemeParser to parse and translate a
16
+ character literal,
17
+ - Add new error classes (CharRequiredError),
18
+ - Add tests around `char`.
19
+
10
20
  ## [0.1.1] - 2021-04-22
11
21
  ### Added
12
22
  - Add `vector`:
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rus3 (0.1.1)
4
+ rus3 (0.1.2)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -54,6 +54,11 @@ Rus3(scheme)> 3+4i
54
54
  ==> (3+4i)
55
55
  Rus3(scheme)> #(1 2 3)
56
56
  ==> #<Rus3::Vector:0x00007facf12d9fb0 @content=[1, 2, 3]>
57
+ Rus3(scheme)> #\a
58
+ ==> #<Rus3::Char:0x00007fc41f1059d8
59
+ @char="a",
60
+ @codepoint=97,
61
+ @encoding=#<Encoding:UTF-8>>
57
62
  ```
58
63
 
59
64
  ### Procedure call
@@ -117,14 +122,18 @@ Following procedures described in the spec is available.
117
122
  - Predicates:
118
123
  - null?, list?
119
124
  - eqv?, eq?
120
- - boolean?, pair?, symbol?, number?, string?, vector?
121
- - char? and port? are defined but it always returns `false`.
125
+ - boolean?, pair?, symbol?, number?, string?, vector?, char?
126
+ - port? are defined but it always returns `false`.
122
127
  - complex?, real?, rational?, integer?
123
128
  - zero?, positive?, negative?, odd?, even?
124
129
  - string-eq?, string-ci-eq?, string-lt?, string-gt?, string-le?,
125
130
  string-ge?, string-ci-lt?, string-ci-gt?, string-ci-le?, string-ci-ge?
126
- - some predicates for `char` and `port` are defined but it always
127
- returns `false`.
131
+ - char-eq?, char-lt?, char-gt?, char-le?, char-ge?,
132
+ char-ci-eq?, char-ci-lt?, char-ci-gt?, char-ci-le?, char-ci-ge?,
133
+ char-alphabetic?, char-numeric?, char-whitespace?,
134
+ char-upper-case?, char-lower-case?
135
+ - some predicates for `port` are defined but it always returns
136
+ `false`.
128
137
 
129
138
  - List operations
130
139
  - cons, car, cdr, set-car!, set-cdr!, cxxr (caar and so on)
@@ -134,6 +143,9 @@ Following procedures described in the spec is available.
134
143
  - make-vector, vector, vector-length, vector-ref, vector-set!,
135
144
  vector->list, list->vector, vector-fill!
136
145
 
146
+ - Char operations
147
+ - char->integer, integer->char, char-upcase, char-downcase
148
+
137
149
  - Write values
138
150
  - write
139
151
  - display
@@ -169,6 +181,7 @@ deviations from the Scheme specification (R5RS or R7RS-small).
169
181
  identifier in Ruby. So, it is possible that some collision of
170
182
  identifiers.
171
183
  - Nested definition of procedure can use outside.
184
+ - All characters and strings are treated as encoded in UTF-8.
172
185
 
173
186
  Some of these may be disappeared in the future version, or may not be.
174
187
 
data/lib/rus3.rb CHANGED
@@ -43,6 +43,7 @@ module Rus3
43
43
 
44
44
  require_relative "rus3/procedure/utils"
45
45
  require_relative "rus3/procedure/predicate"
46
+ require_relative "rus3/procedure/char"
46
47
  require_relative "rus3/procedure/list"
47
48
  require_relative "rus3/procedure/vector"
48
49
  require_relative "rus3/procedure/control"
data/lib/rus3/char.rb CHANGED
@@ -1,6 +1,102 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rus3
4
+
4
5
  class Char
6
+ include Comparable
7
+
8
+ class << self
9
+
10
+ def alphabetic?(char)
11
+ raise CharRequiredError, char unless char.instance_of?(Char)
12
+ /[A-Za-z]/ === char.to_s
13
+ end
14
+
15
+ def numeric?(char)
16
+ raise CharRequiredError, char unless char.instance_of?(Char)
17
+ /[0-9]/ === char.to_s
18
+ end
19
+
20
+ def whitespace?(char)
21
+ raise CharRequiredError, char unless char.instance_of?(Char)
22
+ /[\s]/ === char.to_s
23
+ end
24
+
25
+ def upper_case?(char)
26
+ raise CharRequiredError, char unless char.instance_of?(Char)
27
+ /[A-Z]/ === char.to_s
28
+ end
29
+
30
+ def lower_case?(char)
31
+ raise CharRequiredError, char unless char.instance_of?(Char)
32
+ /[a-z]/ === char.to_s
33
+ end
34
+
35
+ def char_to_integer(char)
36
+ raise CharRequiredError, char unless char.instance_of?(Char)
37
+ char.codepoint
38
+ end
39
+
40
+ def integer_to_char(n, encoding: Encoding::UTF_8)
41
+ self.new(n.chr(encoding))
42
+ end
43
+
44
+ def upcase(char)
45
+ raise CharRequiredError, char unless char.instance_of?(Char)
46
+ self.new(char.to_s.upcase)
47
+ end
48
+
49
+ def downcase(char)
50
+ raise CharRequiredError, char unless char.instance_of?(Char)
51
+ self.new(char.to_s.downcase)
52
+ end
53
+
54
+ def compare_chars(char1, char2, comp_op, ignore_case: false)
55
+ if !char1.instance_of?(self)
56
+ raise CharRequiredError, char1
57
+ elsif !char2.instance_of?(self)
58
+ raise CharRequiredError, char2
59
+ end
60
+
61
+ if ignore_case
62
+ char1 = downcase(char1)
63
+ char2 = downcase(char2)
64
+ end
65
+ char1.send(comp_op, char2)
66
+ end
67
+
68
+ end
69
+
70
+ LITERAL_PREFIX = "#\\"
71
+ LITERAL_SPACE = "#\\space"
72
+ LITERAL_NEWLINE = "#\\newline"
73
+
74
+ attr_reader :codepoint
75
+ attr_reader :encoding
76
+
77
+ def initialize(str)
78
+ @char = str[0].dup.freeze
79
+ @encoding = str.encoding
80
+ @codepoint = @char.ord
81
+ end
82
+
83
+ def ==(other)
84
+ other.instance_of?(Char) and to_s == other.to_s
85
+ end
86
+
87
+ def <=>(other)
88
+ raise CharRequiredError, other unless other.instance_of?(Char)
89
+ @codepoint <=> other.codepoint
90
+ end
91
+
92
+ def to_literal
93
+ LITERAL_PREFIX + @char
94
+ end
95
+
96
+ def to_s
97
+ @char
98
+ end
99
+
5
100
  end
101
+
6
102
  end
data/lib/rus3/error.rb CHANGED
@@ -30,95 +30,96 @@ module Rus3
30
30
  # :stopdoc:
31
31
 
32
32
  EMSG = {
33
+ :number_required => "number required: got=%s",
34
+ :integer_required => "integer required: got=%s",
35
+ :real_number_required => "real number required: got=%s",
36
+ :char_required => "char required: got=%s",
37
+ :string_required => "string required: got=%s",
38
+ :vector_required => "vector required: got=%s",
33
39
  :pair_required => "pair required: got=%s",
34
40
  :list_required => "proper list required: got=%s",
35
41
  :pair_or_list_required => "pair or proper list required: got=%s",
36
- :vector_required => "vector required: got=%s",
37
42
  :out_of_range => "argument out of range: got=%s",
38
43
  :exceed_upper_limit => "argument exceeds its upper limit (%d): got=%d",
39
- :unsupported_method => "specified method does not work now.",
40
44
  :wrong_type => "wrong type argument: got=%s, wants=%s",
41
- :integer_required => "integer required: got=%s",
42
- :real_number_required => "real number required: got=%s",
43
- :number_required => "number required: got=%s",
44
- :string_required => "string required: got=%s",
45
45
  :scheme_syntax_error => "syntax error as Scheme: got=%s",
46
+ :unsupported_method => "specified method does not work now.",
47
+ :unsupported_feature => "specified feature (`%s`) does not support for %s",
46
48
  :cannot_find_file => "cannot find %s",
47
- :unsupported_feature => "specified feature (`%s`) does not support for %s"
48
49
  }
49
50
 
50
51
  # :startdoc:
51
52
 
52
- class PairRequiredError < Error
53
+ class NumberRequiredError < Error
53
54
  def initialize(obj)
54
- super(EMSG[:pair_required] % smart_error_value(obj))
55
+ super(EMSG[:number_required] % smart_error_value(obj))
55
56
  end
56
57
  end
57
58
 
58
- class ListRequiredError < Error
59
+ class IntegerRequiredError < Error
59
60
  def initialize(obj)
60
- super(EMSG[:list_required] % smart_error_value(obj))
61
+ super(EMSG[:integer_required] % smart_error_value(obj))
61
62
  end
62
63
  end
63
64
 
64
- class PairOrListRequiredError < Error
65
+ class RealNumberRequiredError < Error
65
66
  def initialize(obj)
66
- super(EMSG[:pair_or_list_required] % smart_error_value(obj))
67
+ super(EMSG[:real_number_required] % smart_error_value(obj))
67
68
  end
68
69
  end
69
70
 
70
- class VectorRequiredError < Error
71
+ class CharRequiredError < Error
71
72
  def initialize(obj)
72
- super(EMSG[:vector_required] % smart_error_value(obj))
73
+ super(EMSG[:char_required] % smart_error_value(obj))
73
74
  end
74
75
  end
75
76
 
76
- class OutOfRangeError < Error
77
+ class StringRequiredError < Error
77
78
  def initialize(obj)
78
- super(EMSG[:out_of_range] % smart_error_value(obj))
79
+ super(EMSG[:string_required] % smart_error_value(obj))
79
80
  end
80
81
  end
81
82
 
82
- class ExceedUpperLimitError < Error
83
- def initialize(value, limit)
84
- super(EMSG[:exceed_upper_limit] % [limit, value])
83
+ class VectorRequiredError < Error
84
+ def initialize(obj)
85
+ super(EMSG[:vector_required] % smart_error_value(obj))
85
86
  end
86
87
  end
87
88
 
88
- class UnsupportedMethodError < Error
89
- def initialize
90
- super(EMSG[:unsupported_method])
89
+ class PairRequiredError < Error
90
+ def initialize(obj)
91
+ super(EMSG[:pair_required] % smart_error_value(obj))
91
92
  end
92
93
  end
93
94
 
94
- class WrongTypeError < Error
95
- def initialize(obj, expected)
96
- emsg = EMSG[:wrong_type] % [obj, expected]
97
- super(emsg)
95
+ class ListRequiredError < Error
96
+ def initialize(obj)
97
+ super(EMSG[:list_required] % smart_error_value(obj))
98
98
  end
99
99
  end
100
100
 
101
- class IntegerRequiredError < Error
101
+ class PairOrListRequiredError < Error
102
102
  def initialize(obj)
103
- super(EMSG[:integer_required] % smart_error_value(obj))
103
+ super(EMSG[:pair_or_list_required] % smart_error_value(obj))
104
104
  end
105
105
  end
106
106
 
107
- class RealNumberRequiredError < Error
107
+ class OutOfRangeError < Error
108
108
  def initialize(obj)
109
- super(EMSG[:real_number_required] % smart_error_value(obj))
109
+ super(EMSG[:out_of_range] % smart_error_value(obj))
110
110
  end
111
111
  end
112
112
 
113
- class NumberRequiredError < Error
114
- def initialize(obj)
115
- super(EMSG[:number_required] % smart_error_value(obj))
113
+ class ExceedUpperLimitError < Error
114
+ def initialize(value, limit)
115
+ super(EMSG[:exceed_upper_limit] % [limit, value])
116
116
  end
117
117
  end
118
118
 
119
- class StringRequiredError < Error
120
- def initialize(obj)
121
- super(EMSG[:string_required] % smart_error_value(obj))
119
+ class WrongTypeError < Error
120
+ def initialize(obj, expected)
121
+ emsg = EMSG[:wrong_type] % [obj, expected]
122
+ super(emsg)
122
123
  end
123
124
  end
124
125
 
@@ -128,9 +129,9 @@ module Rus3
128
129
  end
129
130
  end
130
131
 
131
- class CannotFindFileError < Error
132
- def initialize(obj)
133
- super(EMSG[:cannot_find_file] % smart_error_value(obj))
132
+ class UnsupportedMethodError < Error
133
+ def initialize
134
+ super(EMSG[:unsupported_method])
134
135
  end
135
136
  end
136
137
 
@@ -140,4 +141,10 @@ module Rus3
140
141
  end
141
142
  end
142
143
 
144
+ class CannotFindFileError < Error
145
+ def initialize(obj)
146
+ super(EMSG[:cannot_find_file] % smart_error_value(obj))
147
+ end
148
+ end
149
+
143
150
  end
@@ -16,6 +16,7 @@ module Rus3
16
16
  include Rus3::Procedure::Write
17
17
  include Rus3::Procedure::Vector
18
18
  include Rus3::Procedure::List
19
+ include Rus3::Procedure::Char
19
20
  include Rus3::Procedure::Predicate
20
21
  include Rus3::EmptyList
21
22
 
@@ -17,6 +17,7 @@ module Rus3::Parser
17
17
  # value types
18
18
  :boolean,
19
19
  :ident,
20
+ :char,
20
21
  :string,
21
22
  :number,
22
23
  # operators
@@ -55,6 +56,15 @@ module Rus3::Parser
55
56
  COMPLEX = Regexp.new("\\A[+-]?#{COMP_PAT}\\Z")
56
57
  PURE_IMAG = Regexp.new("\\A[+-](#{C_IMAG_PAT})?i\\Z")
57
58
 
59
+ # char
60
+ SINGLE_CHAR_PAT = "."
61
+ SPACE_PAT = "space"
62
+ NEWLINE_PAT = "newline"
63
+
64
+ CHAR_PREFIX = "\#\\\\"
65
+ CHAR_PAT = "(#{SINGLE_CHAR_PAT}|#{SPACE_PAT}|#{NEWLINE_PAT})"
66
+ CHAR = Regexp.new("\\A#{CHAR_PREFIX}#{CHAR_PAT}\\Z")
67
+
58
68
  KEYWORDS = {
59
69
  "LAMBDA" => :lambda,
60
70
  "IF" => :if,
@@ -102,6 +112,8 @@ module Rus3::Parser
102
112
  else
103
113
  Token.new(:ident, literal.gsub(EXTENDED_REGEXP, EXTENDED_MAP))
104
114
  end
115
+ when CHAR
116
+ Token.new(:char, literal)
105
117
  when STRING
106
118
  Token.new(:string, literal)
107
119
  when "="
@@ -155,7 +155,7 @@ module Rus3::Parser
155
155
  r_exp = translate_ident(token.literal)
156
156
  when :string
157
157
  r_exp = token.literal
158
- when :ident, :boolean, :number, :op_proc
158
+ when :ident, :boolean, :char, :number, :op_proc
159
159
  trans_method_name = "translate_#{token.type}".intern
160
160
  r_exp = self.send(trans_method_name, token.literal)
161
161
  else
@@ -213,6 +213,17 @@ module Rus3::Parser
213
213
  (s_exp_literal[1] == "f") ? "false" : "true"
214
214
  end
215
215
 
216
+ def translate_char(s_exp_literal)
217
+ c = s_exp_literal[2..-1]
218
+ case c
219
+ when "space"
220
+ c = " "
221
+ when "newline"
222
+ c = "\n"
223
+ end
224
+ "Char.new(\"#{c}\")"
225
+ end
226
+
216
227
  def translate_number(s_exp_literal)
217
228
  if s_exp_literal.include?("/") # rational?
218
229
  denominator, numerator = s_exp_literal.split("/").map{|s| Kernel.eval(s)}
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rus3::Procedure
4
+ module Char
5
+
6
+ # - procedure (R5RS): (char->integer char)
7
+
8
+ def char_to_integer(char)
9
+ Rus3::Char.char_to_integer(char)
10
+ end
11
+
12
+ # - procedure (R5RS): (integer->char n)
13
+
14
+ def integer_to_char(n)
15
+ Rus3::Char.integer_to_char(n)
16
+ end
17
+
18
+ # - library procedure (R5RS): (char-upcase char)
19
+
20
+ def char_upcase(char)
21
+ Rus3::Char.upcase(char)
22
+ end
23
+
24
+ # - library procedure (R5RS): (char-downcase char)
25
+
26
+ def char_downcase(char)
27
+ Rus3::Char.downcase(char)
28
+ end
29
+
30
+ end
31
+ end
@@ -72,7 +72,7 @@ module Rus3::Procedure
72
72
  end
73
73
 
74
74
  def char?(obj)
75
- false
75
+ obj.instance_of?(Rus3::Char)
76
76
  end
77
77
 
78
78
  def string?(obj)
@@ -163,69 +163,67 @@ module Rus3::Procedure
163
163
  # :stopdoc:
164
164
 
165
165
  # Characters:
166
- #
167
- # ...
168
166
 
169
167
  # :startdoc:
170
168
 
171
169
  def char_eq?(char1, char2)
172
- false
170
+ Rus3::Char.compare_chars(char1, char2, :==)
173
171
  end
174
172
 
175
173
  def char_lt?(char1, char2)
176
- false
174
+ Rus3::Char.compare_chars(char1, char2, :<)
177
175
  end
178
176
 
179
177
  def char_gt?(char1, char2)
180
- false
178
+ Rus3::Char.compare_chars(char1, char2, :>)
181
179
  end
182
180
 
183
181
  def char_le?(char1, char2)
184
- false
182
+ Rus3::Char.compare_chars(char1, char2, :<=)
185
183
  end
186
184
 
187
185
  def char_ge?(char1, char2)
188
- false
186
+ Rus3::Char.compare_chars(char1, char2, :>=)
189
187
  end
190
188
 
191
189
  def char_ci_eq?(char1, char2)
192
- false
190
+ Rus3::Char.compare_chars(char1, char2, :==, ignore_case: true)
193
191
  end
194
192
 
195
193
  def char_ci_lt?(char1, char2)
196
- false
194
+ Rus3::Char.compare_chars(char1, char2, :<, ignore_case: true)
197
195
  end
198
196
 
199
197
  def char_ci_gt?(char1, char2)
200
- false
198
+ Rus3::Char.compare_chars(char1, char2, :>, ignore_case: true)
201
199
  end
202
200
 
203
201
  def char_ci_le?(char1, char2)
204
- false
202
+ Rus3::Char.compare_chars(char1, char2, :<=, ignore_case: true)
205
203
  end
206
204
 
207
205
  def char_ci_ge?(char1, char2)
208
- false
206
+ Rus3::Char.compare_chars(char1, char2, :>=, ignore_case: true)
209
207
  end
210
208
 
211
209
  def char_alphabetic?(char)
212
- false
210
+ Rus3::Char.alphabetic?(char)
213
211
  end
214
212
 
215
213
  def char_numeric?(char)
216
- false
214
+ Rus3::Char.numeric?(char)
217
215
  end
218
216
 
219
217
  def char_whitespace?(char)
220
- false
218
+ Rus3::Char.whitespace?(char)
221
219
  end
222
220
 
223
221
  def char_upper_case?(letter)
224
- false
222
+ Rus3::Char.upper_case?(letter)
225
223
  end
226
224
 
227
225
  def char_lower_case?(letter)
228
- false
226
+ Rus3::Char.lower_case?(letter)
229
227
  end
230
228
 
231
229
  # :stopdoc:
data/lib/rus3/repl.rb CHANGED
@@ -75,7 +75,7 @@ module Rus3
75
75
  begin
76
76
  exp = @parser.read(STDIN) # READ
77
77
  rescue SchemeSyntaxError => e
78
- puts "ERROR: %s" % e
78
+ puts "ERROR" + (@verbose ? "(READ)" : "") + ": %s" % e
79
79
  next
80
80
  end
81
81
  break FAREWELL_MESSAGE if exp.nil?
@@ -83,7 +83,7 @@ module Rus3
83
83
  begin
84
84
  value = @evaluator.eval(exp) # EVAL
85
85
  rescue SyntaxError, StandardError => e
86
- puts "ERROR: %s" % e
86
+ puts "ERROR" + (@verbose ? "(EVAL)" : "") + ": %s" % e
87
87
  next
88
88
  end
89
89
 
data/lib/rus3/version.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rus3
4
- VERSION = "0.1.1"
5
- RELEASE = "2021-04-22"
4
+ VERSION = "0.1.2"
5
+ RELEASE = "2021-04-23"
6
6
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rus3
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - mnbi
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-04-22 00:00:00.000000000 Z
11
+ date: 2021-04-23 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Ruby with Syntax Sugar of Scheme
14
14
  email:
@@ -42,6 +42,7 @@ files:
42
42
  - lib/rus3/parser/scheme_parser.rb
43
43
  - lib/rus3/port.rb
44
44
  - lib/rus3/printer.rb
45
+ - lib/rus3/procedure/char.rb
45
46
  - lib/rus3/procedure/control.rb
46
47
  - lib/rus3/procedure/list.rb
47
48
  - lib/rus3/procedure/predicate.rb