rubylisp 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,116 @@
1
+ module Lisp
2
+
3
+ class EnvironmentFrame
4
+
5
+ attr_accessor :frame
6
+
7
+ def self.global
8
+ @@global_frame ||= EnvironmentFrame.new(nil)
9
+ @@global_frame
10
+ end
11
+
12
+ def self.extending(parent, f=nil)
13
+ f ||= parent.frame if parent && parent.has_frame?
14
+ self.new(parent, f)
15
+ end
16
+
17
+ def initialize(parent, f=nil)
18
+ @bindings = []
19
+ @parent = parent
20
+ @frame = f
21
+ end
22
+
23
+ def has_frame?
24
+ !@frame.nil?
25
+ end
26
+
27
+ # Bindings following parent env frame pointer
28
+
29
+ def is_name_bound?(str)
30
+ if !@frame && @frame.has_slot?(Lisp:Symbol.named("#{str}:", true))
31
+ return true
32
+ end
33
+
34
+ binding = @bindings.detect {|b| b.symbol.name == str}
35
+ return true unless binding.nil?
36
+ return false if @parent.nil?
37
+ return @parent.is_name_bound?(str)
38
+ end
39
+
40
+ def binding_for(symbol)
41
+ binding = @bindings.detect {|b| b.symbol.name == symbol.name}
42
+ return binding unless binding.nil?
43
+ return @parent.binding_for(symbol) unless @parent.nil?
44
+ nil
45
+ end
46
+
47
+ def bind(symbol, value)
48
+ b = self.binding_for(symbol)
49
+ if b.nil?
50
+ @bindings << Lisp::Binding.new(symbol, value)
51
+ else
52
+ b.value = value
53
+ end
54
+ end
55
+
56
+ def set(symbol, value)
57
+ naked_symbol = symbol.to_naked
58
+ if @frame && @frame.has_slot?(naked_symbol)
59
+ return @frame.at_put(naked_symbol, value)
60
+ end
61
+
62
+ b = self.binding_for(symbol)
63
+ if b.nil?
64
+ raise "#{symbol} is undefined."
65
+ else
66
+ b.value = value
67
+ end
68
+ end
69
+
70
+ # Bindings local to this env frame only
71
+
72
+ def local_binding_for(symbol)
73
+ @bindings.detect {|b| b.symbol.name == symbol.name}
74
+ end
75
+
76
+ def bind_locally(symbol, value)
77
+ b = self.local_binding_for(symbol)
78
+ if b.nil?
79
+ @bindings << Lisp::Binding.new(symbol, value)
80
+ else
81
+ b.value = value
82
+ end
83
+ end
84
+
85
+ # Look up a symbol
86
+
87
+ def value_of(symbol)
88
+ b = local_binding_for(symbol)
89
+ return b.value unless b.nil?
90
+
91
+ naked_symbol = symbol.to_naked
92
+ if @frame && @frame.has_slot?(naked_symbol)
93
+ return @frame.get(naked_symbol)
94
+ end
95
+
96
+ b = binding_for(symbol)
97
+ return b.value unless b.nil?
98
+ nil
99
+ end
100
+
101
+
102
+ def quick_value_of(symbol_name)
103
+ b = binding_for(Symbol.new(symbol_name))
104
+ b.nil? ? nil : b.value
105
+ end
106
+
107
+
108
+ def dump
109
+ @bindings.each do |b|
110
+ puts b.to_s
111
+ end
112
+ end
113
+
114
+ end
115
+
116
+ end
@@ -0,0 +1,118 @@
1
+ module Lisp
2
+
3
+ class Equivalence
4
+
5
+ def self.register
6
+ Primitive.register("=", "(= number number)\n\nReturns whether the first numeric argument is equal to the second numeric argument.") do |args, env|
7
+ Lisp::Equivalence::num_eq_impl(args, env)
8
+ end
9
+
10
+ Primitive.register("==", "(== number number)\n\nReturns whether the first numeric argument is equal to the second numeric argument.") do |args, env|
11
+ Lisp::Equivalence::num_eq_impl(args, env)
12
+ end
13
+
14
+ Primitive.register("!=", "(!= number number)\n\nReturns whether the first numeric argument is not equal to the second numeric argument.") do |args, env|
15
+ Lisp::Equivalence::num_neq_impl(args, env)
16
+ end
17
+
18
+ Primitive.register("/=", "(/= number number)\n\nReturns whether the first numeric argument is not equal to the second numeric argument.") do |args, env|
19
+ Lisp::Equivalence::num_neq_impl(args, env)
20
+ end
21
+
22
+ Primitive.register("eq?", "(eq? sexpr sexpr)\n\nReturns whether the first argument is the same type as the second argument, and the same object, except in the case of numbers where the values are compared.") do |args, env|
23
+ Lisp::Equivalence::eq_impl(args, env)
24
+ end
25
+
26
+ Primitive.register("eqv?", "(eqv? sexpr sexpr)\n\nReturns whether the first argument is the same type as the second argument, and the same object, except in the case of numbers where the values are compared.") do |args, env|
27
+ Lisp::Equivalence::eqv_impl(args, env)
28
+ end
29
+
30
+ Primitive.register("equal?", "(equal? sexpr sexpr)\n\nReturns whether the first argument is the same type as the second argument, and are lists containing the same elements, are identical strings, are frames with matching slots, are numbers with the same value, or are the same object (if none of the above).") do |args, env|
31
+ Lisp::Equivalence::equal_impl(args, env)
32
+ end
33
+
34
+ end
35
+
36
+ # == - Check two integers for equivalence
37
+
38
+ def self.num_eq_impl(args, env)
39
+ raise "= and == need 2 arguments, received #{args.length}" if args.length != 2
40
+ c1 = args.car.evaluate(env)
41
+ c2 = args.cadr.evaluate(env)
42
+ return Lisp::FALSE unless c1.integer? && c2.integer?
43
+ Lisp::Boolean.with_value(c1.value == c2.value)
44
+ end
45
+
46
+ def self.num_neq_impl(args, env)
47
+ raise "!= and /= needs 2 arguments, received #{args.length}" if args.length != 2
48
+ c1 = args.car.evaluate(env)
49
+ c2 = args.cadr.evaluate(env)
50
+ return Lisp::TRUE unless c1.integer? && c2.integer?
51
+ Lisp::Boolean.with_value(c1.value != c2.value)
52
+ end
53
+
54
+
55
+ # eq? - identity, typically used for symbols
56
+
57
+ def self.eq_check(o1, o2)
58
+ return Lisp::FALSE unless o1.type == o2.type
59
+ Lisp::Boolean.with_value(case o1.type
60
+ when :number
61
+ (o1.integer? == o2.integer?) && (o1.value == o2.value)
62
+ else
63
+ o1.equal?(o2)
64
+ end)
65
+ end
66
+
67
+
68
+ def self.eq_impl(args, env)
69
+ raise "eq? needs 2 arguments, received #{args.length}" if args.length != 2
70
+ o1 = args.car.evaluate(env)
71
+ o2 = args.cadr.evaluate(env)
72
+ eq_check(o1, o2)
73
+ end
74
+
75
+
76
+ # eqv? - same as eq?
77
+
78
+ def self.eqv_check(o1, o2)
79
+ eq_check(o1, o2)
80
+ end
81
+
82
+
83
+ def self.eqv_impl(args, env)
84
+ raise "eq? needs 2 arguments, received #{args.length}" if args.length != 2
85
+ o1 = args.car.evaluate(env)
86
+ o2 = args.cadr.evaluate(env)
87
+ eqv_check(o1, o2)
88
+ end
89
+
90
+
91
+ # equal? - object equality: same value
92
+
93
+ def self.equal_check(o1, o2)
94
+ return Lisp::FALSE unless o1.type == o2.type
95
+ Lisp::Boolean.with_value(case o1.type
96
+ when :pair
97
+ o1.eq?(o2)
98
+ when :string
99
+ o1.value.eql?(o2.value)
100
+ when :frame
101
+ o1.eq?(o2)
102
+ when :number
103
+ (o1.integer? == o2.integer?) && (o1.value == o2.value)
104
+ else
105
+ o1.equal?(o2)
106
+ end)
107
+ end
108
+
109
+
110
+ def self.equal_impl(args, env)
111
+ raise "equal? needs 2 arguments, received #{args.length}" if args.length != 2
112
+ o1 = args.car.evaluate(env)
113
+ o2 = args.cadr.evaluate(env)
114
+ self.equal_check(o1, o2)
115
+ end
116
+ end
117
+
118
+ end
@@ -0,0 +1,98 @@
1
+ module Lisp
2
+
3
+ class Exception
4
+
5
+ def self.register
6
+ Primitive.register("raise") {|args, env| Lisp::Exception::raise_impl(args, env) }
7
+ Primitive.register("reraise") {|args, env| Lisp::Exception::reraise_impl(args, env) }
8
+ Primitive.register("try") {|args, env| Lisp::Exception::try_impl(args, env) }
9
+ Primitive.register("reraise") {|args, env| Lisp::Exception::reraise_impl(args, env) }
10
+ Primitive.register("resume") {|args, env| Lisp::Exception::resume_impl(args, env) }
11
+ Primitive.register("restart") {|args, env| Lisp::Exception::restart_impl(args, env) }
12
+ end
13
+
14
+
15
+ def handler_or_nil(handlers, exception_name)
16
+ handlers.each do |handler_pair|
17
+ exceptions = handler_pair.car
18
+ if exceptions.eq(exception_name) || (exceptions.pair? && exceptions.include?(exception_name))
19
+ handler_pair.cdr
20
+ else
21
+ nil
22
+ end
23
+ end
24
+ end
25
+
26
+ def self.do_exception(name, with_message, args, env)
27
+ frame = env
28
+ while !frame.nil?
29
+ handlers = frame.value_of(Symbol.named("__handlers__"))
30
+ unless handlers.nil?
31
+ handler = handler_or_nil(handlers, for: name)
32
+ unless handler.nil?
33
+ handler.apply_to_without_evaluating(args, in: frame)
34
+ break
35
+ end
36
+ end
37
+ frame = frame.parent
38
+ if frame.nil?
39
+ exception_message = message.empty? ? "" : ": #{message}"
40
+ raise "Unhandled Exception: #{exception_name}#{exception_message}"
41
+ end
42
+ end
43
+ end
44
+
45
+ def self.raise_impl(args, env)
46
+ raise "'raise' requires at least one argument." unless args.length > 0
47
+ exception_name = args.car.evaluate(env)
48
+ raise "'raise' requires an exception name as it's first argument." unless exception_name.string? || class_name.symbol?
49
+
50
+ message = ""
51
+ if args.length > 1
52
+ message = args.cadr.evaluate(env)
53
+ raise "The message parameter to 'raise' must be a string." unless message.string?
54
+ end
55
+
56
+ handler_args = args.length > 2 ? Lisp::ConsCell.array_to_list(args.cdr.to_a.collect {|a| a.evaluate(env)}) : Lisp::ConsCell.new
57
+ end
58
+
59
+
60
+ def self.try_impl(args, env)
61
+ raw_handlers = args.car
62
+ body = args.cdr
63
+
64
+ raise "Exception handlers must be a list." unless raw_handlers.list?
65
+ raise "Exception handlers must be a list of pairs." unless raw_handlers.all? {|h| h.list?}
66
+ raise "Exception clause must be a symbol/string or a list of symbol/string." unless raw_handlers.all? do |h|
67
+ ex = h.car
68
+ ex.symbol? || ex.string? || (ex.list? && ex.all? {|h2| h2.symbol? || h2.string?})
69
+ end
70
+
71
+ array_of_handlers = raw_handlers.to_a.collect do |h|
72
+ ex = h.car
73
+ f = h.cadr.evaluate(env)
74
+ raise "Exception handler has to be a function." unless f.function?
75
+ Lisp::ConsCell.cons(ex, f)
76
+ end
77
+ handlers = Lisp::ConsCell.array_to_list(array_of_handlers)
78
+ env.bind_locally(Symbol.named("__handlers__"), handlers)
79
+
80
+ body.evaluate_each(env)
81
+ end
82
+
83
+
84
+ def self.reraise_impl(args, env)
85
+ end
86
+
87
+
88
+ def self.resume_impl(args, env)
89
+ end
90
+
91
+
92
+ def self.restart_impl(args, env)
93
+ end
94
+
95
+
96
+ end
97
+ end
98
+
@@ -0,0 +1,122 @@
1
+ class NilClass
2
+
3
+ def true?
4
+ false
5
+ end
6
+
7
+ def false?
8
+ true
9
+ end
10
+
11
+ def to_s
12
+ "()"
13
+ end
14
+
15
+ def eq?(other)
16
+ other.nil?
17
+ end
18
+
19
+ def print_string
20
+ self.to_s
21
+ end
22
+
23
+ def evaluate(env)
24
+ nil
25
+ end
26
+
27
+ def evaluate_each(env)
28
+ nil
29
+ end
30
+
31
+ def car
32
+ nil
33
+ end
34
+
35
+ def cdr
36
+ nil
37
+ end
38
+
39
+ def set_car!(s)
40
+ nil
41
+ end
42
+
43
+ def set_cdr!(s)
44
+ nil
45
+ end
46
+
47
+ def quoted
48
+ nil
49
+ end
50
+
51
+ def empty?
52
+ true
53
+ end
54
+
55
+ def length
56
+ 0
57
+ end
58
+
59
+ def value
60
+ nil
61
+ end
62
+
63
+ def string?
64
+ false
65
+ end
66
+
67
+ def number?
68
+ false
69
+ end
70
+
71
+ def symbol?
72
+ false
73
+ end
74
+
75
+ def pair?
76
+ false
77
+ end
78
+
79
+ def list?
80
+ true
81
+ end
82
+
83
+ def method_missing(name, *args, &block)
84
+ if name[0] == ?c && name[-1] == ?r && (name[1..-2].chars.all? {|e| "ad".include?(e)})
85
+ nil
86
+ else
87
+ super
88
+ end
89
+ end
90
+
91
+ def primitive?
92
+ false
93
+ end
94
+
95
+ def function?
96
+ false
97
+ end
98
+
99
+ def object?
100
+ false
101
+ end
102
+
103
+ def type
104
+ :nil
105
+ end
106
+
107
+ def lisp_object?
108
+ true
109
+ end
110
+
111
+
112
+
113
+ end
114
+
115
+
116
+ class Object
117
+
118
+ def lisp_onject?
119
+ false
120
+ end
121
+
122
+ end
@@ -0,0 +1,162 @@
1
+ # -*- coding: utf-8 -*-
2
+ module Lisp
3
+
4
+ class ClassObject < Atom
5
+
6
+ def self.register
7
+ Primitive.register("extend", "(extend parent child)\n\nCreates a new class named child that extends (i.e. inherits from) the class parent. The names (parent and child can be either stirngs or symbols). The new class is accessible by name and is returned.") do |args, env|
8
+ Lisp::ClassObject::extend_impl(args, env)
9
+ end
10
+
11
+ Primitive.register("add-method", "(add-method class selector function)\n\nAdd a method named selector to the class named class using function as it’s body. function can be a reference to a named function or, more likely, a lambda expression.") do |args, env|
12
+ Lisp::ClassObject::add_method_impl(args, env)
13
+ end
14
+
15
+ Primitive.register("add-static-method", "Not Implemented.") do |args, env|
16
+ Lisp::ClassObject::add_static_method_impl(args, env)
17
+ end
18
+
19
+ Primitive.register("super", "Not implemented.") do |args, env|
20
+ Lisp::ClassObject::super_impl(args, env)
21
+ end
22
+
23
+ end
24
+
25
+
26
+ def self.extend_impl(args, env)
27
+ raise "'extend' requires 2 arguments." if args.length != 2
28
+
29
+ class_name = args.car.evaluate(env)
30
+ raise "'extend' requires a name as it's first argument." unless class_name.string? || class_name.symbol?
31
+ super_class = Object.const_get(class_name.to_s)
32
+ raise "'extend' requires the name of an existing class as it's first argument." if super_class.nil?
33
+
34
+ new_class_name = args.cadr.evaluate(env)
35
+ raise "'extend' requires a name as it's second argument." unless new_class_name.string? || new_class_name.symbol?
36
+ new_class = Class.new(super_class)
37
+ raise "'extend' requires the name of a new (i.e. nonexistant) class as it's second argument." if Object.const_defined?(new_class_name.to_s)
38
+
39
+ Object.const_set(new_class_name.to_s, new_class)
40
+ ClassObject.with_class(new_class)
41
+ end
42
+
43
+
44
+ def self.convert_to_lisp(value)
45
+ case value.class.name
46
+ when "Fixnum", "Float"
47
+ Lisp::Number.with_value(value)
48
+ when "TrueClass"
49
+ Lisp::Boolean.TRUE
50
+ when "FalseClass"
51
+ Lisp::Boolean.FALSE
52
+ when "String"
53
+ Lisp::String.with_value(value)
54
+ when "Symbol"
55
+ Lisp::Symbol.named(value)
56
+ when "Array"
57
+ Lisp::ConsCell.array_to_list(value.map {|a| convert_to_lisp(a)})
58
+ else
59
+ value.lisp_object? ? value : Lisp::NativeObject.with_value(value)
60
+ end
61
+ end
62
+
63
+
64
+ def self.convert_to_ruby(a, env)
65
+ if a.nil?
66
+ nil
67
+ elsif a.function?
68
+ proc do
69
+ a.apply_to(Lisp::ConsCell.new, env)
70
+ end
71
+ elsif a.list?
72
+ a.to_a.map {|i| convert_to_ruby(i, env)}
73
+ else
74
+ a.value
75
+ end
76
+ end
77
+
78
+
79
+ def self.add_method_impl(args, env)
80
+ raise "'add-method' requires 3 arguments." if args.length != 3
81
+ class_name = args.car.evaluate(env)
82
+ raise "'add-method' requires a class name as it's first argument." unless class_name.string? || class_name.symbol?
83
+ target_class = Object.const_get(class_name.to_s)
84
+ raise "'add-method' requires the name of an existing class." if target_class.nil?
85
+
86
+ method_name = args.cadr.evaluate(env)
87
+ raise "'add-method' requires a method name as it's second argument." unless class_name.string? || class_name.symbol?
88
+
89
+ body = args.caddr.evaluate(env)
90
+ raise "'add-method' requires a function as it's third argument." unless body.function?
91
+
92
+ target_class.send(:define_method, method_name.to_s) do |*args|
93
+ local_env = Lisp::EnvironmentFrame.extending(env)
94
+ local_env.bind_locally(Symbol.named("self"), Lisp::NativeObject.with_value(self))
95
+ processed_args = args.map {|a| Lisp::ClassObject.convert_to_lisp(a)}
96
+ Lisp::ClassObject.convert_to_ruby(body.apply_to(Lisp::ConsCell.array_to_list(processed_args), in: local_env), in: local_env)
97
+ end
98
+ Lisp::String.with_value("OK")
99
+ end
100
+
101
+
102
+ def self.super_impl(args, env)
103
+ Lisp::String.with_value("NOT IMPLEMENTED")
104
+ end
105
+
106
+
107
+ def self.add_static_method_impl(args, env)
108
+ Lisp::String.with_value("NOT IMPLEMENTED")
109
+ end
110
+
111
+
112
+ def self.new_instance
113
+ self.new(@value.alloc.init)
114
+ end
115
+
116
+
117
+ def self.with_class(c)
118
+ self.new(c)
119
+ end
120
+
121
+
122
+ def initialize(c)
123
+ @value = c
124
+ end
125
+
126
+
127
+ def with_value(&block)
128
+ block.call(@value)
129
+ end
130
+
131
+
132
+ def class?
133
+ true
134
+ end
135
+
136
+
137
+ def type
138
+ :class
139
+ end
140
+
141
+
142
+ def native_type
143
+ @value.class
144
+ end
145
+
146
+
147
+ def to_s
148
+ "<a class: #{@value.name}>"
149
+ end
150
+
151
+
152
+ def true?
153
+ @value != nil
154
+ end
155
+
156
+
157
+ def false?
158
+ @value == nil
159
+ end
160
+
161
+ end
162
+ end
@@ -0,0 +1,32 @@
1
+ module Lisp
2
+
3
+ class FfiNew < Atom
4
+
5
+ def initialize(name)
6
+ @value = name
7
+ @klass = Object.const_get(name)
8
+ end
9
+
10
+ def apply_to(args, env)
11
+ NativeObject.with_value(@klass.new)
12
+ end
13
+
14
+ def apply_to_without_evaluating(args, env)
15
+ NativeObject.with_value(@klass.new)
16
+ end
17
+
18
+ def to_s
19
+ "#{@value}."
20
+ end
21
+
22
+ def primitive?
23
+ true
24
+ end
25
+
26
+ def type
27
+ :primitive
28
+ end
29
+
30
+ end
31
+
32
+ end