p-lang 0.1.1 → 0.2.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.
@@ -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