p-lang 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,209 @@
1
+ module PLang
2
+ module VM
3
+ class Interpreter
4
+ include PFunctions
5
+
6
+ def initialize(ast)
7
+ @ast = ast
8
+ end
9
+
10
+ def execute!
11
+ result = nil
12
+ env = load_basic_environment
13
+ @ast.each do |ast|
14
+ result = execute(ast, env)
15
+ end
16
+ result
17
+ end
18
+
19
+ private
20
+
21
+ def load_basic_environment
22
+ @env = Environment.new
23
+ libraries = methods.grep /^add_to_interpreter/
24
+ libraries.each do |library|
25
+ send(library)
26
+ end
27
+ @env
28
+ end
29
+
30
+ def execute(ast, env)
31
+ if ast.class == PLang::Parser::Node
32
+ case ast.type
33
+ when :integer, :decimal, :string, :char, :boolean
34
+ execute_literal(ast.type, ast.value, env)
35
+ when :object
36
+ execute_object(ast.id, ast.params, env)
37
+ when :list
38
+ execute_list(ast.elements, env)
39
+ when :if
40
+ execute_if(ast.condition, ast.true_expr, ast.false_expr, env)
41
+ when :lambda
42
+ execute_lambda(ast.params, ast.body, ast.where, ast.next_lambda, env)
43
+ when :call
44
+ execute_call(ast.lambda, ast.params, env)
45
+ when :object_message
46
+ execute_object_message(ast.object, ast.message, env)
47
+ when :let
48
+ execute_let(ast.lhs, ast.rhs, env)
49
+ when :id
50
+ execute_id(ast.value, env)
51
+ when :begin
52
+ execute_begin(ast.expressions, env)
53
+ when :add, :sub, :mul, :div, :equal, :diff, :major, :major_equal, :minor, :minor_equal
54
+ execute_binop(ast.type, ast.lhs, ast.rhs, env)
55
+ when :and, :or
56
+ execute_binop("_#{ast.type}".to_sym, ast.lhs, ast.rhs, env)
57
+ when :not
58
+ execute_unop("_#{ast.type}".to_sym, ast.lhs, env)
59
+ end
60
+ else
61
+ ast
62
+ end
63
+ end
64
+
65
+ def execute_if(cond, true_expr, false_expr, env)
66
+ cond = execute(cond, env)
67
+ if cond.id == :boolean
68
+ if cond.params[0] == :true
69
+ execute(true_expr, env)
70
+ else
71
+ execute(false_expr, env)
72
+ end
73
+ else
74
+ raise "IfError"
75
+ end
76
+ end
77
+
78
+ def execute_binop(type, lhs, rhs, env)
79
+ execute_call(execute_object_message(lhs,PLang::Parser::Node.new(:id, {:value => type}), env), [rhs], env)
80
+ end
81
+
82
+ def execute_unop(type, lhs, env)
83
+ execute_call(execute_object_message(lhs,PLang::Parser::Node.new(:id, {:value => type}), env), [], env)
84
+ end
85
+
86
+ def execute_literal(type, value, env)
87
+ PObject.new(type, [value])
88
+ end
89
+
90
+ def execute_object(id, params, env)
91
+ object_params = []
92
+ params.each do |param|
93
+ object_params << execute(param, env)
94
+ end
95
+ case id.value
96
+ when :integer, :decimal, :string, :char, :boolean
97
+ if object_params.length == 1 and object_params[0].id == id.value
98
+ PObject.new(id.value, object_params[0].params)
99
+ end
100
+ else
101
+ PObject.new(id.value, object_params)
102
+ end
103
+ end
104
+
105
+ def execute_lambda(params, body, where, next_lambda, env)
106
+ lambda = []
107
+ lambda << PLambda.new do |values|
108
+ new_env = Environment.new
109
+ new_env.parent = env
110
+ values.each_with_index do |value, i|
111
+ case params[i].type
112
+ when :id
113
+ unless params[i].value == :_
114
+ new_env.set_var(params[i].value, value)
115
+ end
116
+ when :object
117
+ new_env.set_object_var(params[i], value)
118
+ end
119
+ end
120
+ where.each do |w|
121
+ execute(w, new_env)
122
+ end
123
+ execute(body, new_env)
124
+ end
125
+ params.each do |param|
126
+ case param.type
127
+ when :id
128
+ lambda[0].form << nil
129
+ else
130
+ lambda[0].form << param
131
+ end
132
+ end
133
+ if next_lambda
134
+ lambda |= execute(next_lambda, env).params
135
+ end
136
+ PObject.new(:lambda, lambda)
137
+ end
138
+
139
+ def execute_call(lambda, params, env)
140
+ values = []
141
+ params.each do |param|
142
+ values << execute(param, env)
143
+ end
144
+ lambda = execute(lambda, env)
145
+ lambda.params.each do |lamb|
146
+ return lamb.call(values) if lamb.call?(values)
147
+ end
148
+ raise "CallError"
149
+ end
150
+
151
+ def execute_let(lhs, rhs, env)
152
+ case lhs.type
153
+ when :id
154
+ if lhs.value == :_
155
+ raise "WildCardError"
156
+ else
157
+ begin
158
+ env.set_var(lhs.value, execute(rhs, env))
159
+ rescue Exception => e
160
+ var = env.get_var(lhs.value)
161
+ if var.id == :lambda
162
+ env.add_lambda(lhs.value, execute(rhs, env))
163
+ else
164
+ raise e
165
+ end
166
+ end
167
+ end
168
+ when :object
169
+ env.set_object_var(lhs, execute(rhs, env))
170
+ when :object_message
171
+ params = [lhs.object, PLang::Parser::Node.new(:object, {:id => PLang::Parser::Node.new(:id, {:value => lhs.message.value}), :params => []})]
172
+ lamb = execute_lambda(params, rhs, [], nil, env)
173
+ begin
174
+ env.set_var(:get_object_message, lamb)
175
+ rescue
176
+ env.add_lambda(:get_object_message, lamb)
177
+ end
178
+ end
179
+ end
180
+
181
+ def execute_id(id, env)
182
+ env.get_var(id)
183
+ end
184
+
185
+ def execute_begin(expressions, env)
186
+ ret = nil
187
+ expressions.each do |expr|
188
+ ret = execute(expr, env)
189
+ end
190
+ ret
191
+ end
192
+
193
+ def execute_list(elements, env)
194
+ element = elements.delete_at(0)
195
+ if element
196
+ PObject.new(:list, [execute(element, env), execute_list(elements, env)])
197
+ else
198
+ PObject.new(:empty, [])
199
+ end
200
+ end
201
+
202
+ def execute_object_message(object, message, env)
203
+ get_object_message = PLang::Parser::Node.new(:id, {:value => :get_object_message})
204
+ message = PLang::Parser::Node.new(:object, {:id => PLang::Parser::Node.new(:id, {:value => message.value}), :params => []})
205
+ execute_call(get_object_message, [object, message], env)
206
+ end
207
+ end
208
+ end
209
+ end
@@ -0,0 +1,46 @@
1
+ module PLang
2
+ module VM
3
+ module PFunctions
4
+
5
+ def plambda(*params)
6
+ lamb = PLambda.new do |values|
7
+ yield(values)
8
+ end
9
+
10
+ obj_params = []
11
+ params.each do |param|
12
+ param = object(param)
13
+ case param.type
14
+ when :id
15
+ lamb.form << nil
16
+ else
17
+ lamb.form << param
18
+ end
19
+ obj_params << param
20
+ end
21
+
22
+ PObject.new(:lambda, [lamb])
23
+ end
24
+
25
+ def object_message(object, message)
26
+ lamb = plambda(object, "{#{message.to_s}}") do |values|
27
+ yield(values[0], values[1])
28
+ end
29
+ begin
30
+ @env.set_var(:get_object_message, lamb)
31
+ rescue
32
+ @env.add_lambda(:get_object_message, lamb)
33
+ end
34
+ end
35
+
36
+ def var(id, value)
37
+ @env.set_var(id.to_sym, value)
38
+ end
39
+
40
+ def object(expr)
41
+ PLang::Parser::SyntaxAnalyser.new(expr).parse[0]
42
+ end
43
+
44
+ end
45
+ end
46
+ end
data/lib/vm/plambda.rb ADDED
@@ -0,0 +1,42 @@
1
+ module PLang
2
+ module VM
3
+ class PLambda < Proc
4
+
5
+ def call?(params)
6
+ _call?(params, @form||[])
7
+ end
8
+
9
+ def _call?(params, form)
10
+ if form.length == params.length
11
+ form.each_with_index do |f, i|
12
+ if f
13
+ case f.type
14
+ when :integer, :decimal, :char, :string
15
+ if f.type == params[i].id
16
+ unless f.value == params[i].params[0]
17
+ return false
18
+ end
19
+ end
20
+ when :object
21
+ unless f.id.value == params[i].id
22
+ return false
23
+ else
24
+ unless _call?(params[i].params, f.params)
25
+ return false
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ return true
32
+ else
33
+ return false
34
+ end
35
+ end
36
+
37
+ def form
38
+ @form ||= []
39
+ end
40
+ end
41
+ end
42
+ end
data/lib/vm/pobject.rb CHANGED
@@ -1,47 +1,49 @@
1
1
  module PLang
2
- class PObject
3
- attr_accessor :type
4
- attr_accessor :params
5
-
6
- def initialize(type, params)
7
- @type = type
8
- @params = params
9
- end
10
-
11
- def ==(obj)
12
- if @type == obj.type
13
- @params.each_with_index do |param, i|
14
- unless param == obj.params[i]
15
- return false
16
- end
17
- end
18
- return true
19
- else
20
- return false
21
- end
22
- end
23
-
24
- def form
25
- case @type
26
- when :integer, :decimal, :boolean, :char, :string
27
- [:literal, @type, @params[0]]
28
- else
29
- [:object, @type, @params.collect(&:form)]
2
+ module VM
3
+ class PObject
4
+ attr_reader :id
5
+ attr_accessor :params
6
+
7
+ def initialize(id, params)
8
+ @id = id
9
+ @params = params
30
10
  end
31
- end
32
-
33
- def to_s
34
- case @type
35
- when :integer, :decimal, :boolean
36
- @params[0]
37
- when :string
38
- "\"#{@params[0]}\""
39
- when :char
40
- "\'#{@params[0]}\'"
41
- else
42
- "{#{@type}: #{@params.collect(&:to_s).join(",")}}"
11
+
12
+ def to_s
13
+ case @id
14
+ when :integer, :decimal, :char, :string, :boolean
15
+ return params[0]
16
+ when :empty
17
+ return "'()"
18
+ when :list
19
+ str = "'("
20
+ params = @params
21
+ ok = false
22
+ while params and params != []
23
+ str += "#{params[0].to_s}, "
24
+ params = params[1].params
25
+ ok = true
26
+ end
27
+ if ok
28
+ str[-2] = ')'
29
+ else
30
+ str += ')'
31
+ end
32
+ return str.strip
33
+ else
34
+ str = "{#{@id}"
35
+ if @params.length > 0
36
+ str += ": "
37
+ @params.each do |param|
38
+ str += "#{param.to_s}, "
39
+ end
40
+ str[-2] = "}"
41
+ else
42
+ str += "}"
43
+ end
44
+ return str.strip
45
+ end
43
46
  end
44
47
  end
45
-
46
48
  end
47
- end
49
+ end
data/test/test_lexer ADDED
@@ -0,0 +1,34 @@
1
+ abc
2
+ 123
3
+
4
+ "aaaaaa"
5
+ 's'
6
+ [
7
+ ]
8
+ (
9
+ )
10
+ {
11
+ }
12
+ ,
13
+ |
14
+ :
15
+ -
16
+ ->
17
+ +
18
+ *
19
+ /
20
+ %
21
+ =
22
+ ==
23
+ !=
24
+ >
25
+ >=
26
+ <
27
+ <=
28
+ and
29
+ or
30
+ not
31
+ true
32
+ false
33
+ nil
34
+ begin
@@ -0,0 +1,19 @@
1
+ require 'helper'
2
+
3
+ class TestLexer < Test::Unit::TestCase
4
+
5
+ EXPRESSIONS = File.readlines(File.join(File.dirname(__FILE__), "test_lexer"))
6
+ TOKENS = File.readlines(File.join(File.dirname(__FILE__), "test_lexer_tokens"))
7
+
8
+ context "The Lexer" do
9
+
10
+ EXPRESSIONS.each_with_index do |expr, i|
11
+ lexer = PLang::Parser::Lexer.new(EXPRESSIONS[i])
12
+ should "tokenize the expression ##{i}" do
13
+ assert_equal lexer.next_token.type, eval(TOKENS[i])
14
+ end
15
+ end
16
+
17
+ end
18
+
19
+ end