shen-ruby 0.1.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.
Files changed (117) hide show
  1. data/.gitignore +4 -0
  2. data/.rspec +0 -0
  3. data/Gemfile +6 -0
  4. data/Gemfile.lock +20 -0
  5. data/MIT_LICENSE.txt +26 -0
  6. data/README.md +94 -0
  7. data/bin/shen_test_suite.rb +9 -0
  8. data/bin/srrepl +23 -0
  9. data/lib/kl.rb +7 -0
  10. data/lib/kl/absvector.rb +12 -0
  11. data/lib/kl/compiler.rb +253 -0
  12. data/lib/kl/cons.rb +51 -0
  13. data/lib/kl/empty_list.rb +12 -0
  14. data/lib/kl/environment.rb +123 -0
  15. data/lib/kl/error.rb +4 -0
  16. data/lib/kl/internal_error.rb +7 -0
  17. data/lib/kl/lexer.rb +186 -0
  18. data/lib/kl/primitives/arithmetic.rb +60 -0
  19. data/lib/kl/primitives/assignments.rb +18 -0
  20. data/lib/kl/primitives/booleans.rb +17 -0
  21. data/lib/kl/primitives/error_handling.rb +13 -0
  22. data/lib/kl/primitives/generic_functions.rb +22 -0
  23. data/lib/kl/primitives/lists.rb +21 -0
  24. data/lib/kl/primitives/streams.rb +38 -0
  25. data/lib/kl/primitives/strings.rb +55 -0
  26. data/lib/kl/primitives/symbols.rb +17 -0
  27. data/lib/kl/primitives/time.rb +17 -0
  28. data/lib/kl/primitives/vectors.rb +30 -0
  29. data/lib/kl/reader.rb +40 -0
  30. data/lib/kl/trampoline.rb +14 -0
  31. data/lib/shen_ruby.rb +7 -0
  32. data/lib/shen_ruby/version.rb +3 -0
  33. data/shen-ruby.gemspec +26 -0
  34. data/shen/README.txt +17 -0
  35. data/shen/lib/shen_ruby/shen.rb +124 -0
  36. data/shen/license.txt +34 -0
  37. data/shen/release/benchmarks/N_queens.shen +45 -0
  38. data/shen/release/benchmarks/README.shen +14 -0
  39. data/shen/release/benchmarks/benchmarks.shen +56 -0
  40. data/shen/release/benchmarks/bigprog +2173 -0
  41. data/shen/release/benchmarks/br.shen +13 -0
  42. data/shen/release/benchmarks/einstein.shen +33 -0
  43. data/shen/release/benchmarks/heatwave.gif +0 -0
  44. data/shen/release/benchmarks/interpreter.shen +219 -0
  45. data/shen/release/benchmarks/picture.jpg +0 -0
  46. data/shen/release/benchmarks/plato.jpg +0 -0
  47. data/shen/release/benchmarks/powerset.shen +10 -0
  48. data/shen/release/benchmarks/prime.shen +10 -0
  49. data/shen/release/benchmarks/short.shen +129 -0
  50. data/shen/release/benchmarks/text.txt +68 -0
  51. data/shen/release/k_lambda/core.kl +1002 -0
  52. data/shen/release/k_lambda/declarations.kl +1021 -0
  53. data/shen/release/k_lambda/load.kl +94 -0
  54. data/shen/release/k_lambda/macros.kl +479 -0
  55. data/shen/release/k_lambda/prolog.kl +1309 -0
  56. data/shen/release/k_lambda/reader.kl +1058 -0
  57. data/shen/release/k_lambda/sequent.kl +556 -0
  58. data/shen/release/k_lambda/sys.kl +582 -0
  59. data/shen/release/k_lambda/t-star.kl +3493 -0
  60. data/shen/release/k_lambda/toplevel.kl +223 -0
  61. data/shen/release/k_lambda/track.kl +208 -0
  62. data/shen/release/k_lambda/types.kl +455 -0
  63. data/shen/release/k_lambda/writer.kl +108 -0
  64. data/shen/release/k_lambda/yacc.kl +280 -0
  65. data/shen/release/test_programs/Chap13/problems.txt +26 -0
  66. data/shen/release/test_programs/README.shen +53 -0
  67. data/shen/release/test_programs/TinyLispFunctions.txt +16 -0
  68. data/shen/release/test_programs/TinyTypes.shen +55 -0
  69. data/shen/release/test_programs/binary.shen +24 -0
  70. data/shen/release/test_programs/bubble_version_1.shen +28 -0
  71. data/shen/release/test_programs/bubble_version_2.shen +22 -0
  72. data/shen/release/test_programs/calculator.shen +21 -0
  73. data/shen/release/test_programs/cartprod.shen +23 -0
  74. data/shen/release/test_programs/change.shen +25 -0
  75. data/shen/release/test_programs/classes-defaults.shen +94 -0
  76. data/shen/release/test_programs/classes-inheritance.shen +100 -0
  77. data/shen/release/test_programs/classes-typed.shen +74 -0
  78. data/shen/release/test_programs/classes-untyped.shen +46 -0
  79. data/shen/release/test_programs/depth_.shen +14 -0
  80. data/shen/release/test_programs/einstein.shen +33 -0
  81. data/shen/release/test_programs/fruit_machine.shen +46 -0
  82. data/shen/release/test_programs/interpreter.shen +219 -0
  83. data/shen/release/test_programs/metaprog.shen +85 -0
  84. data/shen/release/test_programs/minim.shen +193 -0
  85. data/shen/release/test_programs/mutual.shen +11 -0
  86. data/shen/release/test_programs/n_queens.shen +45 -0
  87. data/shen/release/test_programs/newton_version_1.shen +33 -0
  88. data/shen/release/test_programs/newton_version_2.shen +24 -0
  89. data/shen/release/test_programs/parse.prl +14 -0
  90. data/shen/release/test_programs/parser.shen +52 -0
  91. data/shen/release/test_programs/powerset.shen +10 -0
  92. data/shen/release/test_programs/prime.shen +10 -0
  93. data/shen/release/test_programs/proof_assistant.shen +81 -0
  94. data/shen/release/test_programs/proplog_version_1.shen +25 -0
  95. data/shen/release/test_programs/proplog_version_2.shen +27 -0
  96. data/shen/release/test_programs/qmachine.shen +67 -0
  97. data/shen/release/test_programs/red-black.shen +55 -0
  98. data/shen/release/test_programs/search.shen +56 -0
  99. data/shen/release/test_programs/semantic_net.shen +44 -0
  100. data/shen/release/test_programs/spreadsheet.shen +35 -0
  101. data/shen/release/test_programs/stack.shen +27 -0
  102. data/shen/release/test_programs/streams.shen +20 -0
  103. data/shen/release/test_programs/strings.shen +59 -0
  104. data/shen/release/test_programs/structures-typed.shen +71 -0
  105. data/shen/release/test_programs/structures-untyped.shen +42 -0
  106. data/shen/release/test_programs/tests.shen +294 -0
  107. data/shen/release/test_programs/types.shen +11 -0
  108. data/shen/release/test_programs/whist.shen +240 -0
  109. data/shen/release/test_programs/yacc.shen +136 -0
  110. data/spec/kl/cons_spec.rb +12 -0
  111. data/spec/kl/environment_spec.rb +306 -0
  112. data/spec/kl/lexer_spec.rb +149 -0
  113. data/spec/kl/primitives/generic_functions_spec.rb +29 -0
  114. data/spec/kl/primitives/symbols_spec.rb +21 -0
  115. data/spec/kl/reader_spec.rb +36 -0
  116. data/spec/spec_helper.rb +2 -0
  117. metadata +189 -0
data/lib/kl/cons.rb ADDED
@@ -0,0 +1,51 @@
1
+ require 'kl/empty_list'
2
+
3
+ module Kl
4
+ class Cons
5
+ include Enumerable
6
+
7
+ attr_reader :hd, :tl
8
+
9
+ def initialize(hd, tl)
10
+ @hd = hd
11
+ @tl = tl
12
+ end
13
+
14
+ def ==(other)
15
+ other.kind_of?(Kl::Cons) && hd == other.hd && tl == other.tl
16
+ end
17
+
18
+ def each
19
+ cell = self
20
+ while !cell.kind_of? Kl::EmptyList
21
+ yield cell.hd
22
+ cell = cell.tl
23
+ end
24
+ end
25
+
26
+ class << self
27
+ def list(array)
28
+ if array.empty?
29
+ Kl::EmptyList.instance
30
+ else
31
+ index = array.size - 1
32
+ head = new(array[index], Kl::EmptyList.instance)
33
+ index = index - 1
34
+ while index >= 0
35
+ head = new(array[index], head)
36
+ index = index - 1
37
+ end
38
+ head
39
+ end
40
+ end
41
+
42
+ def list_to_string(f)
43
+ if f.kind_of? Kl::Cons
44
+ '(' + f.map {|x| list_to_string(x)}.join(' ') + ')'
45
+ else
46
+ f.to_s
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,12 @@
1
+ require 'singleton'
2
+
3
+ module Kl
4
+ class EmptyList
5
+ include Singleton
6
+ include Enumerable
7
+
8
+ def each
9
+ # no-op
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,123 @@
1
+ require 'kl/compiler'
2
+ require 'kl/primitives/booleans'
3
+ require 'kl/primitives/symbols'
4
+ require 'kl/primitives/strings'
5
+ require 'kl/primitives/assignments'
6
+ require 'kl/primitives/error_handling'
7
+ require 'kl/primitives/lists'
8
+ require 'kl/primitives/generic_functions'
9
+ require 'kl/primitives/vectors'
10
+ require 'kl/primitives/streams'
11
+ require 'kl/primitives/time'
12
+ require 'kl/primitives/arithmetic'
13
+
14
+ module Kl
15
+ class Environment
16
+ include ::Kl::Primitives::Booleans
17
+ include ::Kl::Primitives::Symbols
18
+ include ::Kl::Primitives::Strings
19
+ include ::Kl::Primitives::Assignments
20
+ include ::Kl::Primitives::ErrorHandling
21
+ include ::Kl::Primitives::Lists
22
+ include ::Kl::Primitives::GenericFunctions
23
+ include ::Kl::Primitives::Vectors
24
+ include ::Kl::Primitives::Streams
25
+ include ::Kl::Primitives::Time
26
+ include ::Kl::Primitives::Arithmetic
27
+
28
+ def initialize
29
+ @dump_code = false
30
+ @tramp_fn = @tramp_args = nil
31
+ @variables = {}
32
+ @eigenklass = class << self; self; end
33
+ @arity_cache = Hash.new { |h, k| h[k] = method(k).arity }
34
+ end
35
+
36
+ # Trampoline-aware function application
37
+ def __apply(fn, args)
38
+ while fn
39
+ @tramp_fn = nil
40
+ if fn.kind_of? Symbol
41
+ if respond_to? fn
42
+ arity = @arity_cache[fn]
43
+ if arity == args.size || arity == -1
44
+ result = send(fn, *args)
45
+ elsif arity > args.size
46
+ # Partial application
47
+ result = method(fn).to_proc.curry.call(*args)
48
+ else
49
+ # Uncurrying. Apply fn to its expected number of arguments
50
+ # and hope that the result is a function that can be applied
51
+ # to the remainder.
52
+ fn = __apply(fn, args[0, arity])
53
+ args = args[arity..-1]
54
+ next
55
+ end
56
+ else
57
+ raise Kl::Error, "The function #{fn} is undefined"
58
+ end
59
+ else
60
+ arity = fn.arity
61
+ if arity == args.size || arity == -1
62
+ result = fn.call(*args)
63
+ elsif arity > args.size
64
+ result = fn.curry.call(*args)
65
+ else
66
+ # Uncurrying. Apply fn to its expected number of arguments
67
+ # and hope that the result is a function that can be applied
68
+ # to the remainder.
69
+ fn = __apply(fn, args[0, arity])
70
+ args = args[arity..-1]
71
+ next
72
+ end
73
+ end
74
+
75
+ if fn = @tramp_fn
76
+ # Bounce on the trampoline
77
+ args = @tramp_args
78
+ @tramp_args = nil
79
+ end
80
+ end
81
+ result
82
+ rescue SystemStackError
83
+ raise ::Kl::Error, 'maximum stack depth exceeded'
84
+ end
85
+
86
+ def __eval(form)
87
+ if @dump_code
88
+ puts "=" * 70
89
+ puts "Compiling:"
90
+ puts Kl::Cons.list_to_string(form)
91
+ puts '-----'
92
+ end
93
+ code = ::Kl::Compiler.compile(form, {}, true)
94
+ if @dump_code
95
+ puts code
96
+ puts "=" * 70
97
+ end
98
+ @tramp_fn = nil
99
+ result = instance_eval(code)
100
+ # Handle top-level trampolines
101
+ if @tramp_fn
102
+ fn = @tramp_fn
103
+ args = @tramp_args
104
+ @tramp_fn = nil
105
+ @tramp_args = nil
106
+ __apply(fn, args)
107
+ else
108
+ result
109
+ end
110
+ end
111
+
112
+ class << self
113
+ def load_file(env, path)
114
+ File.open(path, 'r') do |file|
115
+ reader = Kl::Reader.new(file)
116
+ while form = reader.next
117
+ env.__eval(form)
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
data/lib/kl/error.rb ADDED
@@ -0,0 +1,4 @@
1
+ module Kl
2
+ class Error < StandardError
3
+ end
4
+ end
@@ -0,0 +1,7 @@
1
+ module Kl
2
+ # Internal errors represent inconsistent state within the compiler
3
+ # or runtime environment. They are not catchable by application-level
4
+ # code.
5
+ class InternalError < StandardError
6
+ end
7
+ end
data/lib/kl/lexer.rb ADDED
@@ -0,0 +1,186 @@
1
+ require 'singleton'
2
+ require 'kl/error'
3
+
4
+ module Kl
5
+ class Lexer
6
+ SYMBOL_CHARS = /[-=*\/+_?$!\@~><&%'#`;:{}a-zA-Z0-9.]/
7
+
8
+ # Syntax tokens
9
+ class OpenParen
10
+ include Singleton
11
+ end
12
+ class CloseParen
13
+ include Singleton
14
+ end
15
+
16
+ def initialize(stream)
17
+ @stream = stream
18
+ @buffer = []
19
+ end
20
+
21
+ def eof?
22
+ @buffer.empty? && @stream.eof?
23
+ end
24
+
25
+ def getc
26
+ if @buffer.empty?
27
+ @stream.getc
28
+ else
29
+ @buffer.pop
30
+ end
31
+ end
32
+
33
+ def ungetc(c)
34
+ @buffer.push(c)
35
+ end
36
+
37
+ def next
38
+ drain_whitespace
39
+ unless eof?
40
+ c = getc
41
+ case c
42
+ when '('
43
+ OpenParen.instance
44
+ when ')'
45
+ CloseParen.instance
46
+ when '"'
47
+ consume_string
48
+ when SYMBOL_CHARS
49
+ ungetc(c)
50
+ consume_number_or_symbol
51
+ else
52
+ raise Error, "illegal character: #{c}"
53
+ end
54
+ end
55
+ end
56
+
57
+ private
58
+ def drain_whitespace
59
+ until eof?
60
+ c = getc
61
+ if c =~ /\S/
62
+ ungetc(c)
63
+ break
64
+ end
65
+ end
66
+ end
67
+
68
+ def consume_string
69
+ chars = []
70
+ loop do
71
+ raise Error, "unterminated string" if eof?
72
+ c = getc
73
+ break if c == '"'
74
+ chars << c
75
+ end
76
+ chars.join
77
+ end
78
+
79
+ def consume_number
80
+ # Shen allows multiple leading plusses and minuses. The plusses
81
+ # are ignored and an even number of minuses cancel each other.
82
+ # Thus '------+-7' is read as 7.
83
+ #
84
+ # The Shen reader parses "7." as the integer 7 and the symbol '.'
85
+ decimal_seen = false
86
+ negative = false
87
+ past_sign = false
88
+ chars = []
89
+ loop do
90
+ break if eof?
91
+ c = getc
92
+ if c =~ /\d/
93
+ past_sign = true
94
+ chars << c
95
+ elsif c == '.' && !decimal_seen
96
+ past_sign = true
97
+ decimal_seen = true
98
+ chars << c
99
+ elsif c == '+' && !past_sign
100
+ # ignore
101
+ elsif c == '-' && !past_sign
102
+ negative = !negative
103
+ else
104
+ ungetc c
105
+ break
106
+ end
107
+ end
108
+ chars.unshift('-') if negative
109
+ if chars.last == '.'
110
+ # A trailing decimal point is treated as part of the next
111
+ # token. Forget we saw it.
112
+ ungetc(chars.pop)
113
+ decimal_seen = false
114
+ end
115
+ str = chars.join
116
+ decimal_seen ? str.to_f : str.to_i
117
+ end
118
+
119
+ def consume_symbol
120
+ chars = []
121
+ loop do
122
+ break if eof?
123
+ c = getc
124
+ unless c =~ SYMBOL_CHARS
125
+ ungetc c
126
+ break
127
+ end
128
+ chars << c
129
+ end
130
+ str = chars.join
131
+
132
+ case str
133
+ when 'true'
134
+ true
135
+ when 'false'
136
+ false
137
+ else
138
+ str.to_sym
139
+ end
140
+ end
141
+
142
+ def consume_number_or_symbol
143
+ # First drain optional leading signs
144
+ # Then drain optional decimal point
145
+ # If there is another character and it is a digit, then it
146
+ # is a number. Otherwise it is a symbol.
147
+ chars = []
148
+ loop do
149
+ break if eof?
150
+ c = getc
151
+ unless c =~ /[-+]/
152
+ ungetc c
153
+ break
154
+ end
155
+ chars << c
156
+ end
157
+ if eof?
158
+ chars.reverse.each {|x| ungetc x}
159
+ return consume_symbol
160
+ end
161
+
162
+ c = getc
163
+ chars << c
164
+ if c == '.'
165
+ if eof?
166
+ chars.reverse.each {|x| ungetc x}
167
+ return consume_symbol
168
+ end
169
+ c = getc
170
+ chars << c
171
+ chars.reverse.each {|x| ungetc x}
172
+ if c =~ /\d/
173
+ return consume_number
174
+ else
175
+ return consume_symbol
176
+ end
177
+ elsif c =~ /\d/
178
+ chars.reverse.each {|x| ungetc x}
179
+ return consume_number
180
+ else
181
+ chars.reverse.each {|x| ungetc x}
182
+ return consume_symbol
183
+ end
184
+ end
185
+ end
186
+ end
@@ -0,0 +1,60 @@
1
+ module Kl
2
+ module Primitives
3
+ module Arithmetic
4
+ def +(a, b)
5
+ raise ::Kl::Error, "#{a} is not a number" unless a.kind_of? Numeric
6
+ raise ::Kl::Error, "#{b} is not a number" unless b.kind_of? Numeric
7
+ a + b
8
+ end
9
+
10
+ def -(a, b)
11
+ raise ::Kl::Error, "#{a} is not a number" unless a.kind_of? Numeric
12
+ raise ::Kl::Error, "#{b} is not a number" unless b.kind_of? Numeric
13
+ a - b
14
+ end
15
+
16
+ def *(a, b)
17
+ raise ::Kl::Error, "#{a} is not a number" unless a.kind_of? Numeric
18
+ raise ::Kl::Error, "#{b} is not a number" unless b.kind_of? Numeric
19
+ a * b
20
+ end
21
+
22
+ def /(a, b)
23
+ raise ::Kl::Error, "#{a} is not a number" unless a.kind_of? Numeric
24
+ raise ::Kl::Error, "#{b} is not a number" unless b.kind_of? Numeric
25
+ if a.kind_of?(Fixnum) && b.kind_of?(Fixnum) && a % b != 0
26
+ a = a.to_f
27
+ end
28
+ a / b
29
+ end
30
+
31
+ def >(a, b)
32
+ raise ::Kl::Error, "#{a} is not a number" unless a.kind_of? Numeric
33
+ raise ::Kl::Error, "#{b} is not a number" unless b.kind_of? Numeric
34
+ a > b
35
+ end
36
+
37
+ def <(a, b)
38
+ raise ::Kl::Error, "#{a} is not a number" unless a.kind_of? Numeric
39
+ raise ::Kl::Error, "#{b} is not a number" unless b.kind_of? Numeric
40
+ a < b
41
+ end
42
+
43
+ def >=(a, b)
44
+ raise ::Kl::Error, "#{a} is not a number" unless a.kind_of? Numeric
45
+ raise ::Kl::Error, "#{b} is not a number" unless b.kind_of? Numeric
46
+ a >= b
47
+ end
48
+
49
+ def <=(a, b)
50
+ raise ::Kl::Error, "#{a} is not a number" unless a.kind_of? Numeric
51
+ raise ::Kl::Error, "#{b} is not a number" unless b.kind_of? Numeric
52
+ a <= b
53
+ end
54
+
55
+ def number?(a)
56
+ a.kind_of?(Numeric)
57
+ end
58
+ end
59
+ end
60
+ end