p-lang 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README.rdoc +17 -0
- data/Rakefile +54 -0
- data/VERSION.yml +5 -0
- data/bin/p-lang +13 -0
- data/lib/p-lang.rb +24 -0
- data/lib/parser/ast.rb +168 -0
- data/lib/parser/nodes.rb +212 -0
- data/lib/parser/p-lang.treetop +197 -0
- data/lib/vm/environment.rb +51 -0
- data/lib/vm/pobject.rb +47 -0
- data/lib/vm/proc.rb +41 -0
- data/lib/vm/std/io.rb +17 -0
- data/lib/vm/vm.rb +211 -0
- data/test/helper.rb +10 -0
- data/test/test_parser.rb +26 -0
- data/test/test_parser_build.txt +72 -0
- data/test/test_parser_ok.txt +72 -0
- data/test/test_vm.rb +22 -0
- data/test/test_vm_programs.txt +37 -0
- data/test/test_vm_results.txt +37 -0
- metadata +119 -0
@@ -0,0 +1,197 @@
|
|
1
|
+
grammar PLang
|
2
|
+
|
3
|
+
rule statements
|
4
|
+
(spaces? statement spaces?)* <NStatements>
|
5
|
+
end
|
6
|
+
|
7
|
+
rule statement
|
8
|
+
unop / binop / let / object_op / expr
|
9
|
+
end
|
10
|
+
|
11
|
+
rule object_op
|
12
|
+
object_msg /
|
13
|
+
object_get
|
14
|
+
end
|
15
|
+
|
16
|
+
rule object_msg
|
17
|
+
expr spaces? '->' spaces? id sspaces? '(' spaces? statement_list:statement_list? spaces? ')' <NObjectMsg>
|
18
|
+
end
|
19
|
+
|
20
|
+
rule object_get
|
21
|
+
expr spaces? '->' spaces? id spaces? <NObjectGet>
|
22
|
+
end
|
23
|
+
|
24
|
+
rule let
|
25
|
+
var_let /
|
26
|
+
obj_let
|
27
|
+
end
|
28
|
+
|
29
|
+
rule var_let
|
30
|
+
var spaces? '=' spaces? statement <NVarLet>
|
31
|
+
end
|
32
|
+
|
33
|
+
rule obj_let
|
34
|
+
object_form spaces? '->' spaces? var spaces? '=' spaces? statement <NObjectLet>
|
35
|
+
end
|
36
|
+
|
37
|
+
rule var
|
38
|
+
id / object
|
39
|
+
end
|
40
|
+
|
41
|
+
rule unop
|
42
|
+
'not' spaces? statement <NUnOp>
|
43
|
+
end
|
44
|
+
|
45
|
+
rule binop
|
46
|
+
expr spaces? op spaces? statement <NBinOp>
|
47
|
+
end
|
48
|
+
|
49
|
+
rule op
|
50
|
+
'+' / '-' / '*' / '/' / '%' / '>=' / '<=' / '>' / '<' / '==' / 'and' / 'or'
|
51
|
+
end
|
52
|
+
|
53
|
+
rule call
|
54
|
+
cid:(id / lambda) sspaces? '(' spaces? cparams:statement_list? spaces? ')' <NCall>
|
55
|
+
end
|
56
|
+
|
57
|
+
rule sspaces
|
58
|
+
[\s\t]*
|
59
|
+
end
|
60
|
+
|
61
|
+
rule expr
|
62
|
+
number / boolean / call / id / object / char / string / lambda / parem_expr
|
63
|
+
end
|
64
|
+
|
65
|
+
rule parem_expr
|
66
|
+
'(' spaces? statement spaces? ')' <NParemExpr>
|
67
|
+
end
|
68
|
+
|
69
|
+
rule statement_list
|
70
|
+
cstatement_list / statement
|
71
|
+
end
|
72
|
+
|
73
|
+
rule cstatement_list
|
74
|
+
statement spaces? ',' spaces? statement_list <NCStatementList>
|
75
|
+
end
|
76
|
+
|
77
|
+
rule lambda
|
78
|
+
clamb / lamb
|
79
|
+
end
|
80
|
+
|
81
|
+
rule clamb
|
82
|
+
lamb spaces? ',' spaces? lambda <NCLambda>
|
83
|
+
end
|
84
|
+
|
85
|
+
rule lamb
|
86
|
+
'[' spaces? params:lambda_params? spaces? statement spaces? ']' spaces? where:where? <NLambda>
|
87
|
+
end
|
88
|
+
|
89
|
+
rule where
|
90
|
+
':' spaces? '(' spaces? where_params spaces? ')' <NWhere>
|
91
|
+
end
|
92
|
+
|
93
|
+
rule where_params
|
94
|
+
cwhere_params / let
|
95
|
+
end
|
96
|
+
|
97
|
+
rule cwhere_params
|
98
|
+
let spaces? ',' spaces? where_params <NCWhereParams>
|
99
|
+
end
|
100
|
+
|
101
|
+
rule lambda_params
|
102
|
+
lambda_params_list spaces? '|' <NLambdaParams>
|
103
|
+
end
|
104
|
+
|
105
|
+
rule lambda_params_list
|
106
|
+
clambda_params_list / form
|
107
|
+
end
|
108
|
+
|
109
|
+
rule clambda_params_list
|
110
|
+
form spaces? ',' spaces? lambda_params_list <NCLambdaParamsList>
|
111
|
+
end
|
112
|
+
|
113
|
+
rule form
|
114
|
+
number / id / object_form / char / string
|
115
|
+
end
|
116
|
+
|
117
|
+
rule object_form
|
118
|
+
'{' spaces? id spaces? obj_form_list:object_form_list? spaces? '}' <NObjectForm>
|
119
|
+
end
|
120
|
+
|
121
|
+
rule object_form_list
|
122
|
+
':' spaces? lambda_params_list <NLambdaParams>
|
123
|
+
end
|
124
|
+
|
125
|
+
rule object
|
126
|
+
'{' spaces? id spaces? obj_list:object_list? spaces? '}' <NObject>
|
127
|
+
end
|
128
|
+
|
129
|
+
rule object_list
|
130
|
+
':' spaces? statement_list <NObjectList>
|
131
|
+
end
|
132
|
+
|
133
|
+
rule boolean
|
134
|
+
(true / false) <NBoolean>
|
135
|
+
end
|
136
|
+
|
137
|
+
rule true
|
138
|
+
"true"
|
139
|
+
end
|
140
|
+
|
141
|
+
rule false
|
142
|
+
"false"
|
143
|
+
end
|
144
|
+
|
145
|
+
rule id
|
146
|
+
[a-zA-Z_0-9]+ <NId>
|
147
|
+
end
|
148
|
+
|
149
|
+
rule string
|
150
|
+
"\"" str:(!"\"" .)* "\"" <NString>
|
151
|
+
end
|
152
|
+
|
153
|
+
rule char
|
154
|
+
"'" c:(!"'" .) "'" <NChar>
|
155
|
+
end
|
156
|
+
|
157
|
+
rule number
|
158
|
+
decimal / integer
|
159
|
+
end
|
160
|
+
|
161
|
+
rule decimal
|
162
|
+
sign? spaces? digits? dot digits <NDecimal>
|
163
|
+
end
|
164
|
+
|
165
|
+
rule integer
|
166
|
+
sign? spaces? digits <NInteger>
|
167
|
+
end
|
168
|
+
|
169
|
+
rule digits
|
170
|
+
digit+
|
171
|
+
end
|
172
|
+
|
173
|
+
rule digit
|
174
|
+
[0-9]
|
175
|
+
end
|
176
|
+
|
177
|
+
rule sign
|
178
|
+
"-"
|
179
|
+
end
|
180
|
+
|
181
|
+
rule dot
|
182
|
+
"."
|
183
|
+
end
|
184
|
+
|
185
|
+
rule spaces
|
186
|
+
space* ("#" (!break .)* break+ space*)*
|
187
|
+
end
|
188
|
+
|
189
|
+
rule space
|
190
|
+
[\r\n\t\s]
|
191
|
+
end
|
192
|
+
|
193
|
+
rule break
|
194
|
+
[\r\n]
|
195
|
+
end
|
196
|
+
|
197
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module PLang
|
2
|
+
class Environment
|
3
|
+
attr_accessor :parent
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@vars = Hash.new
|
7
|
+
@parent = nil
|
8
|
+
@object_call = Hash.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def add_var(id, value)
|
12
|
+
unless @vars[id]
|
13
|
+
@vars[id] = value
|
14
|
+
else
|
15
|
+
raise "add_var"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def get_var(id)
|
20
|
+
v = @vars[id]
|
21
|
+
if v
|
22
|
+
return v
|
23
|
+
elsif @parent
|
24
|
+
return @parent.get_var(id)
|
25
|
+
else
|
26
|
+
raise "get_var"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def add_object_call(form, msg, value)
|
31
|
+
unless @object_call[msg]
|
32
|
+
@object_call[msg] = Hash.new
|
33
|
+
end
|
34
|
+
@object_call[msg][form] = value
|
35
|
+
end
|
36
|
+
|
37
|
+
def get_object_call(object, msg)
|
38
|
+
begin
|
39
|
+
lamb = []
|
40
|
+
@object_call[msg].each do |obj|
|
41
|
+
if obj[0][1] == object.type
|
42
|
+
lamb |= obj[1]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
return lamb
|
46
|
+
rescue
|
47
|
+
raise "get_object_call"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/lib/vm/pobject.rb
ADDED
@@ -0,0 +1,47 @@
|
|
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)]
|
30
|
+
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(",")}}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
data/lib/vm/proc.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
class Proc
|
2
|
+
def form=(form)
|
3
|
+
@form = form
|
4
|
+
end
|
5
|
+
|
6
|
+
def compare_form(form, obj)
|
7
|
+
if(form)
|
8
|
+
unless obj[1] == form[1]
|
9
|
+
return false
|
10
|
+
else
|
11
|
+
if form[0] == :literal
|
12
|
+
unless form == obj
|
13
|
+
return false
|
14
|
+
end
|
15
|
+
else
|
16
|
+
form[2].each_with_index do |p, i|
|
17
|
+
unless p[0] == :id
|
18
|
+
unless p == obj[2][i]
|
19
|
+
if p[0] == :object
|
20
|
+
return compare_form(p, obj[2][i])
|
21
|
+
else
|
22
|
+
return false
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
return true
|
31
|
+
end
|
32
|
+
|
33
|
+
def call?(params)
|
34
|
+
params.each_with_index do |param, i|
|
35
|
+
unless compare_form(@form[i], param.form)
|
36
|
+
return false
|
37
|
+
end
|
38
|
+
end
|
39
|
+
return true
|
40
|
+
end
|
41
|
+
end
|
data/lib/vm/std/io.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
module PLang
|
2
|
+
module IO
|
3
|
+
def IO.def_pfunctions(env)
|
4
|
+
env.add_var(:print, IO.pprint)
|
5
|
+
end
|
6
|
+
|
7
|
+
def IO.pprint
|
8
|
+
lamb = Proc.new do |values|
|
9
|
+
values.each do |value|
|
10
|
+
puts value.to_s
|
11
|
+
end
|
12
|
+
end
|
13
|
+
lamb.form = []
|
14
|
+
[lamb]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/vm/vm.rb
ADDED
@@ -0,0 +1,211 @@
|
|
1
|
+
module PLang
|
2
|
+
class VM
|
3
|
+
def initialize(ast)
|
4
|
+
@ast = ast
|
5
|
+
end
|
6
|
+
|
7
|
+
def execute!
|
8
|
+
env = PLang::Environment.new
|
9
|
+
initialize_global_environment(env)
|
10
|
+
@ast.each do |expr|
|
11
|
+
@ret = execute(expr, env)
|
12
|
+
end
|
13
|
+
@ret
|
14
|
+
end
|
15
|
+
|
16
|
+
def execute(expr, env)
|
17
|
+
case expr[0]
|
18
|
+
when :literal
|
19
|
+
execute_literal(expr[1], expr[2], env)
|
20
|
+
when :let
|
21
|
+
execute_let(expr[1], expr[2], env)
|
22
|
+
when :lambda
|
23
|
+
execute_lambda(expr[1], expr[2], expr[3], expr[4], env)
|
24
|
+
when :call
|
25
|
+
execute_call(expr[1], expr[2], env)
|
26
|
+
when :id
|
27
|
+
execute_id(expr[1], env)
|
28
|
+
when :+, :-, :*, :/, :%, :>, :<, :>=, :<=, :==
|
29
|
+
execute_binop(expr[0], expr[1], expr[2], env)
|
30
|
+
when :and
|
31
|
+
execute_and(expr[1], expr[2], env)
|
32
|
+
when :or
|
33
|
+
execute_or(expr[1], expr[2], env)
|
34
|
+
when :if
|
35
|
+
execute_if(expr[1], expr[2], expr[3], env)
|
36
|
+
when :begin
|
37
|
+
execute_begin(expr[1], env)
|
38
|
+
when :object
|
39
|
+
execute_object(expr[1], expr[2], env)
|
40
|
+
when :object_let
|
41
|
+
execute_object_let(expr[1], expr[2], expr[3], env)
|
42
|
+
when :object_call
|
43
|
+
execute_object_call(expr[1], expr[2], env)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def execute_literal(type, value, env)
|
48
|
+
case type
|
49
|
+
when :integer, :decimal, :char, :string
|
50
|
+
PObject.new(type, [value])
|
51
|
+
when :boolean
|
52
|
+
if value == :true
|
53
|
+
PObject.new(:boolean, [true])
|
54
|
+
elsif value == :false
|
55
|
+
PObject.new(:boolean, [false])
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def execute_let(id, value, env)
|
61
|
+
case id[0]
|
62
|
+
when :id
|
63
|
+
unless id[1] == :_
|
64
|
+
env.add_var(id[1], execute(value, env))
|
65
|
+
end
|
66
|
+
when :object
|
67
|
+
add_object_var(id, execute(value, env), env)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def add_object_var(obj, value, env)
|
72
|
+
if obj[1] == value.type
|
73
|
+
obj[2].each_with_index do |param, i|
|
74
|
+
case param[0]
|
75
|
+
when :id
|
76
|
+
unless param[1] == :_
|
77
|
+
case value.type
|
78
|
+
when :integer, :decimal, :boolean
|
79
|
+
env.add_var(param[1], PObject.new(value.type, [value.params[i]]))
|
80
|
+
else
|
81
|
+
env.add_var(param[1], value.params[i])
|
82
|
+
end
|
83
|
+
end
|
84
|
+
when :object
|
85
|
+
add_object_var(param, value.params[i], env)
|
86
|
+
else
|
87
|
+
unless execute(param, env) == value.params[i]
|
88
|
+
raise "add_object_var #1"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
else
|
93
|
+
raise "add_object_var #2"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def execute_lambda(params, body, where, next_lambda, env)
|
98
|
+
lambda = []
|
99
|
+
lambda << Proc.new do |values|
|
100
|
+
new_env = PLang::Environment.new
|
101
|
+
new_env.parent = env
|
102
|
+
values.each_with_index do |value, i|
|
103
|
+
case params[i][0]
|
104
|
+
when :id
|
105
|
+
unless params[i][1] == :_
|
106
|
+
new_env.add_var(params[i][1], value)
|
107
|
+
end
|
108
|
+
when :object
|
109
|
+
add_object_var(params[i], value, new_env)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
where.each do |w|
|
113
|
+
execute(w, new_env)
|
114
|
+
end
|
115
|
+
execute(body, new_env)
|
116
|
+
end
|
117
|
+
form = []
|
118
|
+
params.each do |param|
|
119
|
+
case param[0]
|
120
|
+
when :id
|
121
|
+
form << nil
|
122
|
+
when :object
|
123
|
+
form << param
|
124
|
+
else
|
125
|
+
form << execute(param, env).form
|
126
|
+
end
|
127
|
+
end
|
128
|
+
lambda[0].form = form
|
129
|
+
if next_lambda
|
130
|
+
lambda |= execute(next_lambda, env)
|
131
|
+
end
|
132
|
+
lambda
|
133
|
+
end
|
134
|
+
|
135
|
+
def execute_call(id, params, env)
|
136
|
+
values = []
|
137
|
+
params.each do |param|
|
138
|
+
values << execute(param, env)
|
139
|
+
end
|
140
|
+
execute(id, env).each do |lambda|
|
141
|
+
if lambda.call?(values)
|
142
|
+
return lambda.call(values)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
raise "execute_call"
|
146
|
+
end
|
147
|
+
|
148
|
+
def execute_id(id, env)
|
149
|
+
env.get_var(id)
|
150
|
+
end
|
151
|
+
|
152
|
+
def execute_binop(op, lhs, rhs, env)
|
153
|
+
lhs = execute(lhs, env)
|
154
|
+
rhs = execute(rhs, env)
|
155
|
+
result = lhs.params[0].send(op,rhs.params[0])
|
156
|
+
if result.class == Fixnum or result.class == Bignum
|
157
|
+
return PObject.new(:integer, [result])
|
158
|
+
elsif result.class == Float
|
159
|
+
return PObject.new(:decimal, [result])
|
160
|
+
elsif result.class == TrueClass or result.class == FalseClass
|
161
|
+
return PObject.new(:boolean, [result])
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def execute_and(lhs, rhs, env)
|
166
|
+
lhs = execute(lhs, env)
|
167
|
+
rhs = execute(rhs, env)
|
168
|
+
PObject.new(:boolean, [(lhs.params[0] and rhs.params[0])])
|
169
|
+
end
|
170
|
+
|
171
|
+
def execute_or(lhs, rhs, env)
|
172
|
+
lhs = execute(lhs, env)
|
173
|
+
rhs = execute(rhs, env)
|
174
|
+
PObject.new(:boolean, [(lhs.params[0] or rhs.params[0])])
|
175
|
+
end
|
176
|
+
|
177
|
+
def execute_if(cond, t, f, env)
|
178
|
+
cond = execute(cond, env)
|
179
|
+
if cond.params[0]
|
180
|
+
execute(t, env)
|
181
|
+
else
|
182
|
+
execute(f, env)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def execute_begin(exprs, env)
|
187
|
+
ret = nil
|
188
|
+
exprs.each do |expr|
|
189
|
+
ret = execute(expr, env)
|
190
|
+
end
|
191
|
+
ret
|
192
|
+
end
|
193
|
+
|
194
|
+
def execute_object(type, params, env)
|
195
|
+
values = []
|
196
|
+
params.each do |param|
|
197
|
+
values << execute(param, env)
|
198
|
+
end
|
199
|
+
PObject.new(type, values)
|
200
|
+
end
|
201
|
+
|
202
|
+
def execute_object_let(obj, msg, value, env)
|
203
|
+
value[1] << obj
|
204
|
+
env.add_object_call(obj, msg[1], execute(value, env))
|
205
|
+
end
|
206
|
+
|
207
|
+
def execute_object_call(object, id, env)
|
208
|
+
env.get_object_call(execute(object, env), id[1])
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|