p-lang 0.0.1
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.
- 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
|