lisp-interpreter 0.3.5 → 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
  SHA1:
3
- metadata.gz: 31b5afb412627509393e82cd31613a47029d6de8
4
- data.tar.gz: 5fb55aedca3ff30a6a41f9a808379a9483feb03c
3
+ metadata.gz: 0f2eed4083aad91446e2fd71b4b7ad1181e7c4d4
4
+ data.tar.gz: 553180b55363be657880ebeeefc78a46f410e95b
5
5
  SHA512:
6
- metadata.gz: 1c1101cea234ab1711fc5208d344199fc492032c214448442c23eaba3c7940b0cb9792f374845e52b92f5e00d5525bb49e938b8091a7d4450bed56347831e64f
7
- data.tar.gz: 15b95c4869df5dd227fbd243a0d6a53fe4ce008bc94ac6e58b09bcf99206d465f10e9821146f2438fd57e5698cf32fbe559c0d84e3ac71bb32f12e476b1dd7c6
6
+ metadata.gz: 67963dab535ddc3f856fb7dbe0b286eae6f0ac1d4a2d728d144374fe805639f489ecf57b50928d51ee47710e50d105e7b4cc3cb411406c72a4232efe587d82b5
7
+ data.tar.gz: 78bcaad6f467ad69d83af2afedc9d9f4c9631b9383f2a769dc56efc787e917a2cd98591eb5bd7ce6b74562f82ad4c4fd4839d61e47bc742d453dcb91506fa042
@@ -1,39 +1,38 @@
1
1
  # Check if variable is specific type
2
2
  module SchemeChecker
3
3
  def check_for_bool(token)
4
- return true if ['#t', '#f'].include? token
4
+ return true if token.boolean?
5
5
  is_instance_var = check_instance_var token
6
- return true if is_instance_var && (check_for_bool get_var token)
6
+ return (check_for_bool get_var token) if is_instance_var
7
7
  false
8
8
  end
9
9
 
10
10
  def check_for_string(token)
11
11
  return true if token.string?
12
12
  is_instance_var = check_instance_var token
13
- return true if is_instance_var && (check_for_string get_var token)
13
+ return (check_for_string get_var token) if is_instance_var
14
14
  false
15
15
  end
16
16
 
17
- def check_for_number(token)
17
+ def check_for_num(token)
18
18
  return true if token.to_s.number?
19
19
  is_instance_var = check_instance_var token
20
- return true if is_instance_var && (check_for_number get_var token)
20
+ return (check_for_num get_var token) if is_instance_var
21
21
  false
22
22
  end
23
23
 
24
24
  def check_for_quote(token)
25
25
  return true if token[0].quote?
26
26
  is_instance_var = check_instance_var token
27
- return true if is_instance_var && (check_for_number get_var token)
27
+ return (check_for_num get_var token) if is_instance_var
28
28
  false
29
29
  end
30
30
 
31
31
  def check_for_symbol(var)
32
32
  var = var.join('') if var.is_a? Array
33
- return true if var == '#\space'
34
33
  return true if var.character?
35
34
  is_instance_var = check_instance_var var
36
- return true if is_instance_var && (check_for_character get_var var)
35
+ return (check_for_character get_var var) if is_instance_var
37
36
  false
38
37
  end
39
38
 
@@ -29,7 +29,8 @@ module SchemeBooleans
29
29
 
30
30
  def not(other)
31
31
  raise arg_err_build 1, other.size if other.size != 1
32
- raise 'Invalid data type' unless check_for_bool other[0]
32
+ valid = check_for_bool other[0]
33
+ raise data_type_err '<boolean>', other[0].type unless valid
33
34
  other[0] == '#t' ? '#f' : '#t'
34
35
  end
35
36
 
@@ -11,6 +11,18 @@ module ErrorMessages
11
11
  def arg_err_build(exp, got)
12
12
  'Incorrect number of arguments, expected ' + exp.to_s + ' got ' + got.to_s
13
13
  end
14
+
15
+ def no_procedure_build(name)
16
+ 'No procedure found ' + name.to_s
17
+ end
18
+
19
+ def unbound_symbol_err(symbol)
20
+ 'Unbound symbol ' + symbol.to_s
21
+ end
22
+
23
+ def data_type_err(exp, got)
24
+ 'Invalid data type, expected ' + exp.to_s + ' got ' + got.to_s
25
+ end
14
26
  end
15
27
 
16
28
  class SchemeException < RuntimeError
@@ -91,6 +91,12 @@ module Optimize
91
91
  expr = build_compose_expr funcs
92
92
  proc_lambda expr
93
93
  end
94
+
95
+ def define_var_stl(var, values)
96
+ valid_stl = methods.include? values.to_s[2..-3].to_sym
97
+ return set_var var, values.to_s[2..-3].to_sym if valid_stl
98
+ set_var var, values[0]
99
+ end
94
100
  end
95
101
 
96
102
  # FunctionalScheme helper
@@ -163,7 +169,7 @@ module FunctionalSchemeHelper
163
169
  def define_var(var, values)
164
170
  raise arg_err_build 1, values.size if values.size != 1
165
171
  raise 'Invalid variable name' unless valid_var_name var
166
- set_var var, values[0]
172
+ define_var_stl var, values
167
173
  end
168
174
 
169
175
  def set_values_define(other, params, args)
@@ -76,7 +76,7 @@ module SchemeListsHelper
76
76
 
77
77
  def find_list_function_value(other)
78
78
  raise arg_err_build 1, other.size if other.size != 1
79
- raise 'Invalid data type' unless other[0].list?
79
+ raise data_type_err '<list>', other[0].type unless other[0].list?
80
80
  split_list_as_string other[0].to_s
81
81
  end
82
82
 
@@ -2,7 +2,7 @@
2
2
  module SchemeNumbersHelper
3
3
  def get_one_arg_function(other)
4
4
  raise arg_err_build 1, other.size if other.size != 1
5
- raise 'Invalid data type' unless check_for_number other[0]
5
+ raise data_type_err '<number>', other[0].type unless check_for_num other[0]
6
6
  other[0].to_num
7
7
  end
8
8
 
@@ -24,7 +24,7 @@ module SchemeNumbersHelper
24
24
 
25
25
  def get_num_denom(other)
26
26
  num, other = find_next_value other
27
- raise 'Invalid data type' unless check_for_number num
27
+ raise data_type_err '<number>', num.type unless check_for_num num
28
28
  return [num, 1] if other.empty?
29
29
  denom, other = find_next_value other
30
30
  raise arg_err_build 1, other.size unless other.empty?
@@ -40,7 +40,7 @@ module SchemeNumbersHelper
40
40
 
41
41
  def convert_to_num(other)
42
42
  other.each do |t|
43
- raise 'Invalid data type' unless check_for_number t
43
+ raise data_type_err '<number>', t.type unless check_for_num t
44
44
  end
45
45
  other.map(&:to_num)
46
46
  end
@@ -124,7 +124,7 @@ module SchemeNumbers
124
124
  raise arg_err_build 1, 0 if other.empty?
125
125
  other = num_denom_helper other
126
126
  result = (get_num_denom other)[0]
127
- raise 'Invalid data type' unless check_for_number result
127
+ raise data_type_err '<number>', result.type unless check_for_num result
128
128
  result.to_num
129
129
  end
130
130
 
@@ -132,7 +132,7 @@ module SchemeNumbers
132
132
  raise arg_err_build 1, 0 if other.empty?
133
133
  other = num_denom_helper other
134
134
  result = (get_num_denom other)[1]
135
- raise 'Invalid data type' unless check_for_number result
135
+ raise data_type_err '<number>', result.type unless check_for_num result
136
136
  result.to_num
137
137
  end
138
138
 
@@ -0,0 +1,66 @@
1
+ # redefine method in Object class
2
+ class Object
3
+ def number?
4
+ to_f.to_s == to_s || to_i.to_s == to_s
5
+ end
6
+
7
+ def to_num
8
+ return to_f if to_f.to_s == to_s
9
+ return to_i if to_i.to_s == to_s
10
+ end
11
+
12
+ def character?
13
+ return true if self == '#\space'
14
+ (start_with? '#\\') && (('a'..'z').to_a.include? self[2]) && size == 3
15
+ end
16
+
17
+ def string?
18
+ return false unless self.class == String
19
+ (start_with? '"') && (end_with? '"') && (size != 1)
20
+ end
21
+
22
+ def list?
23
+ return false if size < 3
24
+ check_for_list
25
+ end
26
+
27
+ def pair?
28
+ res = object_split if is_a? String
29
+ res = to_a if is_a? Array
30
+ return true if res[-3] == '.'
31
+ list? && !res[2..-2].empty?
32
+ end
33
+
34
+ def quote?
35
+ return true if start_with? '\''
36
+ false
37
+ end
38
+
39
+ def boolean?
40
+ ['#t', '#f'].include? self
41
+ end
42
+
43
+ def type
44
+ return '<list>' if list?
45
+ return '<pair>' if pair?
46
+ return '<string>' if string?
47
+ return '<number>' if number?
48
+ return '<character>' if character?
49
+ return '<boolean>' if boolean?
50
+ '<quote>'
51
+ end
52
+
53
+ private
54
+
55
+ def object_split
56
+ result = to_s.split(/(\(|\)|\.)|\ /)
57
+ result.delete('')
58
+ result
59
+ end
60
+
61
+ def check_for_list
62
+ res = to_a if is_a? Array
63
+ res = object_split if is_a? String
64
+ res[0..1].join == '\'(' && res[-1] == ')' && res[-3] != '.'
65
+ end
66
+ end
@@ -0,0 +1,140 @@
1
+ # Helper functions for SchemeStrings
2
+ module SchemeStringsHelper
3
+ def substring_builder(str, from, to)
4
+ result = (str[1..-2])[from..(to.nil? ? -1 : to - 1)]
5
+ return '""' if result.nil?
6
+ '"' + result + '"'
7
+ end
8
+
9
+ def find_delimeter(other)
10
+ return ' ' if other.nil?
11
+ other[1..-2]
12
+ end
13
+
14
+ def build_as_string_helper(other, idx)
15
+ value = other[0..idx].join(' ').gsub('( ', '(').gsub(' )', ')')
16
+ [value, other[idx + 1..-1]]
17
+ end
18
+
19
+ def build_next_value_as_string(other)
20
+ idx = find_idx_for_list other
21
+ if other[0] == '('
22
+ build_as_string_helper other, idx
23
+ elsif other[0..1].join == '\'('
24
+ [(get_raw_value other[0..idx]), other[idx + 1..-1]]
25
+ else
26
+ [other[0], other[1..-1]]
27
+ end
28
+ end
29
+
30
+ def build_character(char)
31
+ '#\\' + (char == ' ' ? 'space' : char)
32
+ end
33
+
34
+ def remove_carriage(str)
35
+ str = str[1..-2]
36
+ str.gsub('\n', '').gsub('\r', '').gsub('\t', '').strip.squeeze(' ')
37
+ end
38
+
39
+ def arg_function_validator(other, vars = 1)
40
+ raise arg_err_build other.size, vars if other.size != vars
41
+ res = other[0..vars - 1].reject { |v| check_for_string v }
42
+ raise data_type_err '<string>', res[0].type unless res.empty?
43
+ res
44
+ end
45
+
46
+ def string_join_helper(other, dilimeter)
47
+ values = split_list_as_string other.to_s
48
+ delim_result = find_delimeter dilimeter
49
+ '"' + (values.join delim_result) + '"'
50
+ end
51
+
52
+ def strjoin_validate(other)
53
+ raise arg_err_build '[1, 2]', other.size unless other.size.between? 1, 2
54
+ raise data_type_err '<list>', other[0].type unless other[0].to_s.list?
55
+ end
56
+
57
+ def substring_validator(from, to)
58
+ valid = (check_for_num from) && (to.nil? || (check_for_num to))
59
+ type = [from, to].first { |t| t.type if t.type != 'number' }
60
+ raise data_type_err '<number>', type unless valid
61
+ end
62
+ end
63
+
64
+ # Scheme numbers module
65
+ module SchemeStrings
66
+ include SchemeStringsHelper
67
+ def substring(other)
68
+ raise arg_err_build '[2, 3]', other.size unless other.size.between? 2, 3
69
+ str, from, to = other
70
+ arg_function_validator [str]
71
+ substring_validator from, to
72
+ substring_builder str, from.to_num, to.to_num
73
+ end
74
+
75
+ def string?(other)
76
+ raise arg_err_build 1, other.size if other.size != 1
77
+ result = check_for_string other[0].to_s
78
+ result ? '#t' : '#f'
79
+ end
80
+
81
+ def strlen(other)
82
+ arg_function_validator other
83
+ other[0][1..-2].length
84
+ end
85
+
86
+ def strupcase(other)
87
+ arg_function_validator other
88
+ other[0].upcase
89
+ end
90
+
91
+ def strdowncase(other)
92
+ arg_function_validator other
93
+ other[0].downcase
94
+ end
95
+
96
+ def strcontains(other)
97
+ arg_function_validator other, 2
98
+ result = other[0][1..-2].include? other[1][1..-2]
99
+ result ? '#t' : '#f'
100
+ end
101
+
102
+ def strsplit(other)
103
+ arg_function_validator other
104
+ str = remove_carriage other[0]
105
+ result = str.split(' ').map { |s| '"' + s + '"' }
106
+ build_list result
107
+ end
108
+
109
+ def strlist(other)
110
+ arg_function_validator other
111
+ result = other[0][1..-2].chars.map { |c| build_character c }
112
+ build_list result
113
+ end
114
+
115
+ def strreplace(other)
116
+ arg_function_validator other, 3
117
+ str, to_replace, replace_with = other.map { |t| t[1..-2] }
118
+ '"' + (str.gsub to_replace, replace_with) + '"'
119
+ end
120
+
121
+ def strprefix(other)
122
+ arg_function_validator other, 2
123
+ str, to_check = other.map { |t| t[1..-2] }
124
+ result = str.start_with? to_check
125
+ result ? '#t' : '#f'
126
+ end
127
+
128
+ def strsufix(other)
129
+ arg_function_validator other, 2
130
+ str, to_check = other.map { |t| t[1..-2] }
131
+ result = str.end_with? to_check
132
+ result ? '#t' : '#f'
133
+ end
134
+
135
+ def strjoin(other)
136
+ strjoin_validate other
137
+ arg_function_validator [other[1]] if other.size == 2
138
+ string_join_helper other[0], other[1]
139
+ end
140
+ end
@@ -10,6 +10,7 @@ class Object
10
10
  end
11
11
 
12
12
  def character?
13
+ return true if self == '#\space'
13
14
  (start_with? '#\\') && (('a'..'z').to_a.include? self[2]) && size == 3
14
15
  end
15
16
 
@@ -35,6 +36,20 @@ class Object
35
36
  false
36
37
  end
37
38
 
39
+ def boolean?
40
+ ['#t', '#f'].include? self
41
+ end
42
+
43
+ def type
44
+ return 'list' if list?
45
+ return 'pair' if pair?
46
+ return 'string' if string?
47
+ return 'number' if number?
48
+ return 'character' if character?
49
+ return 'boolean' if boolean?
50
+ 'quote'
51
+ end
52
+
38
53
  private
39
54
 
40
55
  def object_split
@@ -1,4 +1,4 @@
1
- require_relative 'errors'
1
+ require_relative 'core/errors'
2
2
  require_relative 'validator'
3
3
  require_relative 'tokenizer'
4
4
 
@@ -62,7 +62,7 @@ module SchemeStrings
62
62
  raise arg_err_build '[2, 3]', other.size unless other.size.between? 2, 3
63
63
  str, from, to = other
64
64
  arg_function_validator [str]
65
- valid = (check_for_number from) && (to.nil? || (check_for_number to))
65
+ valid = (check_for_num from) && (to.nil? || (check_for_num to))
66
66
  raise 'Incorrect parameter type' unless valid
67
67
  substring_builder str, from.to_num, to.to_num
68
68
  end
@@ -1,13 +1,13 @@
1
- require_relative 'object'
2
- require_relative 'errors'
1
+ require_relative 'core/object'
2
+ require_relative 'core/errors'
3
+ require_relative 'core/numbers'
4
+ require_relative 'core/strings'
5
+ require_relative 'core/boolean'
6
+ require_relative 'core/list'
7
+ require_relative 'core/functional'
3
8
  require_relative 'value_finder'
4
9
  require_relative 'checker'
5
10
  require_relative 'validator'
6
- require_relative 'numbers'
7
- require_relative 'strings'
8
- require_relative 'boolean'
9
- require_relative 'list'
10
- require_relative 'functional'
11
11
 
12
12
  # Tokenizer helper
13
13
  module TokenizerHelper
@@ -66,9 +66,8 @@ module TokenizerHelper
66
66
  end
67
67
 
68
68
  def set_var(var, value)
69
- raise 'Cannot predefine reserved keyword' if @reserved.key? var.to_s
70
69
  valid = (valid_var value.to_s) || (value.is_a? Proc)
71
- raise 'Invalid parameter' unless valid
70
+ raise 'Invalid parameter' unless valid || (value.is_a? Symbol)
72
71
  @procs[var] = value
73
72
  end
74
73
 
@@ -78,7 +77,7 @@ module TokenizerHelper
78
77
  val = (predefined_method_caller [var])
79
78
  return val unless val.nil?
80
79
  valid = valid_var var
81
- valid ? var : (raise 'Unbound symbol "' + var + '"')
80
+ valid ? var : (raise unbound_symbol_err var)
82
81
  end
83
82
 
84
83
  def syntax_methods
@@ -124,12 +123,17 @@ class Tokenizer
124
123
  call_predefined_method m_name, arr
125
124
  end
126
125
 
126
+ def check_for_stl_function(arr)
127
+ idx = find_bracket_idx arr, 1
128
+ func, = valid_function arr[1..idx]
129
+ values = find_all_values arr[idx + 1..-2]
130
+ return func.call(*values) if func.is_a? Proc
131
+ calc_input_val ['(', func, *values, ')']
132
+ end
133
+
127
134
  def special_check_proc(m_name, arr)
128
135
  if arr[0..1].join == '(('
129
- idx = find_bracket_idx arr, 1
130
- func, = valid_function arr[1..idx]
131
- values = find_all_values arr[idx + 1..-2]
132
- func.call(*values)
136
+ check_for_stl_function arr
133
137
  else
134
138
  m_name.call(*arr[2..-2])
135
139
  end
@@ -27,20 +27,20 @@ module Validator
27
27
 
28
28
  def valid_function(fn)
29
29
  idx = fn[0] == '(' ? (find_bracket_idx fn, 0) : 0
30
- func =
30
+ f =
31
31
  if idx.zero?
32
32
  predefined_method_caller [fn[idx]]
33
33
  else
34
34
  calc_input_val fn[0..idx]
35
35
  end
36
- raise 'No such procedure' if func.nil? && (!func.is_a? Proc)
37
- [func, fn[idx + 1..-1]]
36
+ valid_function? f, fn, idx
37
+ [f, fn[idx + 1..-1]]
38
38
  end
39
39
 
40
40
  private
41
41
 
42
42
  def valid_literals(var)
43
- number = check_for_number var
43
+ number = check_for_num var
44
44
  string = check_for_string var
45
45
  boolean = check_for_bool var
46
46
  symbol = check_for_symbol var
@@ -51,4 +51,9 @@ module Validator
51
51
  def valid_objects(var)
52
52
  var.list? || var.pair?
53
53
  end
54
+
55
+ def valid_function?(f, fn, idx)
56
+ idx = find_bracket_idx fn, 1 if fn[idx] == '\''
57
+ raise no_procedure_build fn[0..idx].join if f.nil? && (!f.is_a? Proc)
58
+ end
54
59
  end
@@ -1,5 +1,5 @@
1
1
  module Lisp
2
2
  module Interpreter
3
- VERSION = '0.3.5'.freeze
3
+ VERSION = '0.4.0'.freeze
4
4
  end
5
5
  end
Binary file
@@ -1,6 +1,8 @@
1
1
  require 'spec_helper'
2
+ require_relative '../../lib/lisp/interpreter/core/errors'
2
3
 
3
4
  RSpec.describe Lisp::Interpreter do
5
+ include ErrorMessages
4
6
  before do
5
7
  @p = Parser.new
6
8
  @p.parse('(define x 5)')
@@ -19,14 +21,6 @@ RSpec.describe Lisp::Interpreter do
19
21
  '(' + arr.join(' ') + ')'
20
22
  end
21
23
 
22
- def arg_err_build(e, g)
23
- 'Incorrect number of arguments, expected ' + e.to_s + ' got ' + g.to_s
24
- end
25
-
26
- def unbound_symbol(sym)
27
- 'Unbound symbol "' + sym.to_s + '"'
28
- end
29
-
30
24
  @p.parse('(define xl (lambda (x) (* 2 x)))')
31
25
  @p.parse('(define yl (lambda () 5))')
32
26
  @p.parse('(define zl (lambda ()))')
@@ -68,7 +62,7 @@ RSpec.describe Lisp::Interpreter do
68
62
 
69
63
  describe 'literals' do
70
64
  it 'throws invalid variable error when the data is invalid' do
71
- expect(@p.parse('#\invalid')).to eq unbound_symbol '#\invalid'
65
+ expect(@p.parse('#\invalid')).to eq unbound_symbol_err '#\invalid'
72
66
  end
73
67
 
74
68
  it 'can parse integers' do
@@ -1002,7 +996,7 @@ RSpec.describe Lisp::Interpreter do
1002
996
  expr1 = '(define prodfive (lambda (x)(define yy 5)(* x yy)))'
1003
997
  expect(@p.parse(expr1)).to be_instance_of(Proc)
1004
998
  expect(@p.parse('(prodfive 6)')).to eq 30
1005
- expect(@p.parse('yy')).to eq unbound_symbol 'yy'
999
+ expect(@p.parse('yy')).to eq unbound_symbol_err 'yy'
1006
1000
  end
1007
1001
  end
1008
1002
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lisp-interpreter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.5
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Zaki Petrov
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-08-07 00:00:00.000000000 Z
11
+ date: 2017-08-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -71,12 +71,14 @@ files:
71
71
  - bin/start.rb
72
72
  - bin/zakichan.bat
73
73
  - lib/lisp/interpreter.rb
74
- - lib/lisp/interpreter/boolean.rb
75
74
  - lib/lisp/interpreter/checker.rb
76
- - lib/lisp/interpreter/errors.rb
77
- - lib/lisp/interpreter/functional.rb
78
- - lib/lisp/interpreter/list.rb
79
- - lib/lisp/interpreter/numbers.rb
75
+ - lib/lisp/interpreter/core/boolean.rb
76
+ - lib/lisp/interpreter/core/errors.rb
77
+ - lib/lisp/interpreter/core/functional.rb
78
+ - lib/lisp/interpreter/core/list.rb
79
+ - lib/lisp/interpreter/core/numbers.rb
80
+ - lib/lisp/interpreter/core/object.rb
81
+ - lib/lisp/interpreter/core/strings.rb
80
82
  - lib/lisp/interpreter/object.rb
81
83
  - lib/lisp/interpreter/parser.rb
82
84
  - lib/lisp/interpreter/run.rb
@@ -85,6 +87,7 @@ files:
85
87
  - lib/lisp/interpreter/validator.rb
86
88
  - lib/lisp/interpreter/value_finder.rb
87
89
  - lib/lisp/interpreter/version.rb
90
+ - lisp-interpreter-0.3.5.gem
88
91
  - lisp-interpreter.gemspec
89
92
  - spec/lisp/interpreter_spec.rb
90
93
  - spec/lisp/test.scm