pycplus 0.3.0 → 0.4.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.
- checksums.yaml +4 -4
- data/bin/pycplus +1 -1
- data/lib/nodes.rb +33 -13
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9ba4de43decc549bf60ae97669e59b7e8dc597897d9f9f943c9547e93f260880
|
4
|
+
data.tar.gz: a8e6c2e1815da2725a6f5af2841a6d9ff7db0bf5ec58fd6a05ccde637df12a96
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1fdf3493c38f21ed5d515f1b4ea4c80849913ac6a4b6398bc6000a27df445ffa8161222cc9115d9bae0162b06809dc5531576d5182e0525ca998f74ad3f6895d
|
7
|
+
data.tar.gz: d51d284dac74989f444902c43ff177e706daf2887bf4e6fd80aae0aa250c744d6b6f9d979d61862ecc8353195b12c91cfaeacec0a8e77cd7eb974c759aafa412
|
data/bin/pycplus
CHANGED
data/lib/nodes.rb
CHANGED
@@ -2,38 +2,51 @@
|
|
2
2
|
|
3
3
|
require_relative 'STL.rb'
|
4
4
|
|
5
|
+
# Class to handle scopes when evaluating AST.
|
5
6
|
class Scope
|
6
|
-
attr_reader :identifiers,:parent_scope
|
7
|
+
attr_reader :identifiers,:parent_scope, :non_local_variables
|
7
8
|
def initialize(parent_scope = nil)
|
8
9
|
@identifiers = {}
|
10
|
+
@non_local_variables = []
|
9
11
|
@parent_scope = parent_scope
|
10
12
|
end
|
11
13
|
|
14
|
+
# Set variable in current scope
|
12
15
|
def set_variable(name, op, expression)
|
16
|
+
if @non_local_variables.include?(name)
|
17
|
+
raise NameError, "local identifier #{name} referenced before assignment"
|
18
|
+
end
|
13
19
|
if op == '='
|
14
20
|
@identifiers[name] = expression
|
15
21
|
else
|
16
|
-
|
17
|
-
|
22
|
+
unless @identifiers.has_key?(name)
|
23
|
+
raise NameError, "local identifier #{name} referenced before assignment"
|
24
|
+
end
|
18
25
|
if op == '+='
|
19
|
-
@identifiers[name] = 0 if !id_scope
|
20
26
|
@identifiers[name] += expression
|
21
27
|
else
|
22
|
-
@identifiers[name] = 0 if !id_scope
|
23
28
|
@identifiers[name] -= expression
|
24
29
|
end
|
25
30
|
end
|
26
31
|
end
|
27
32
|
|
33
|
+
def set_non_local_variable(name)
|
34
|
+
unless @non_local_variables.include?(name) && is_function(name)
|
35
|
+
@non_local_variables.append(name)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Get value of identifier in current or parent scope(s) if defined.
|
28
40
|
def get_identifier(name)
|
29
41
|
scope = get_scope(name)
|
30
42
|
if scope
|
31
43
|
return scope.identifiers[name]
|
32
44
|
else
|
33
|
-
raise NameError,"Identifier #{name} not defined."
|
45
|
+
raise NameError,"Identifier #{name} not defined in scope."
|
34
46
|
end
|
35
47
|
end
|
36
48
|
|
49
|
+
# Get first scope where identifier is defined.
|
37
50
|
def get_scope(name)
|
38
51
|
if @identifiers.has_key?(name)
|
39
52
|
return self
|
@@ -42,17 +55,20 @@ class Scope
|
|
42
55
|
end
|
43
56
|
end
|
44
57
|
|
58
|
+
# Checks if a identifier is a function.
|
45
59
|
def is_function?(name)
|
46
60
|
scope = get_scope(name)
|
47
61
|
id_value = scope.get_identifier(name) if scope
|
48
62
|
return id_value.is_a?(Hash)
|
49
63
|
end
|
50
64
|
|
65
|
+
# Set a function in current scope.
|
51
66
|
def set_function(name, block, parameters)
|
52
67
|
@identifiers[name] = {:parameters => parameters, :block => block}
|
53
68
|
end
|
54
69
|
end
|
55
70
|
|
71
|
+
|
56
72
|
class BlockNode
|
57
73
|
def initialize(statements = nil)
|
58
74
|
@block = statements
|
@@ -102,10 +118,10 @@ class FunctioncallNode
|
|
102
118
|
return result
|
103
119
|
end
|
104
120
|
|
105
|
-
def evaluate_block(parameters, block,
|
106
|
-
new_scope = Scope.new(
|
121
|
+
def evaluate_block(parameters, block, current_scope, id_scope)
|
122
|
+
new_scope = Scope.new(id_scope)
|
107
123
|
parameters.zip(@arguments).each do |parameter, argument|
|
108
|
-
new_scope.set_variable(parameter, '=', argument.evaluate(
|
124
|
+
new_scope.set_variable(parameter, '=', argument.evaluate(current_scope))
|
109
125
|
end
|
110
126
|
|
111
127
|
result = block.evaluate(new_scope)
|
@@ -135,7 +151,7 @@ class FunctioncallNode
|
|
135
151
|
parameters = function[:parameters]
|
136
152
|
block = function[:block]
|
137
153
|
validate_arguments(parameters)
|
138
|
-
evaluate_block(parameters, block,
|
154
|
+
evaluate_block(parameters, block,scope,id_scope)
|
139
155
|
end
|
140
156
|
end
|
141
157
|
end
|
@@ -274,9 +290,12 @@ class IdentifierNode < PrimitiveNode
|
|
274
290
|
def evaluate(scope)
|
275
291
|
if scope.is_function?(@value)
|
276
292
|
raise SyntaxError, "Identifier #{@value} is assigned to a function. Please use correct syntax for function call."
|
277
|
-
else
|
278
|
-
return scope.get_identifier(@value)
|
279
293
|
end
|
294
|
+
id_value = scope.get_identifier(@value)
|
295
|
+
unless scope.identifiers.has_key?(@value)
|
296
|
+
scope.set_non_local_variable(@value)
|
297
|
+
end
|
298
|
+
return id_value
|
280
299
|
end
|
281
300
|
end
|
282
301
|
|
@@ -287,4 +306,5 @@ class DigitNode < PrimitiveNode
|
|
287
306
|
end
|
288
307
|
|
289
308
|
class BoolNode < PrimitiveNode
|
290
|
-
end
|
309
|
+
end
|
310
|
+
|