shen-ruby 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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