pycplus 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 913dc54e2125fc5beeb5f92f72e52f9ef3c17797215208c0c19210f50c8d41f5
4
- data.tar.gz: 33590ac845fad7ce3453768258a25056fa1d545e89193ea0abe69c6589c95472
3
+ metadata.gz: bd13b4d71513629e82bfdc275b30886005d1f0c7958c96562d4f9f8b0703ccc2
4
+ data.tar.gz: a925d460e45d955bef30bc3fb466b766f8e2aa26867763e70e82b613e8310dcf
5
5
  SHA512:
6
- metadata.gz: 8e01871ae474cd3d3b2372a60b1996e42573c92975915e2d6829cf5700745c8a4656d72db202012c9697a19eb73cb19a3e4638b71ca9e5c93474d462dc891da4
7
- data.tar.gz: c92bc545148e5b442367ab5466e255109c9e5c1ae86620915ebdd3c44b5643a529c5a36174c7da21e848b5df9f50863a7aa5d7376abae6f64c8cf80b788ff0f8
6
+ metadata.gz: 5927e705387375c7c05b90029993c51639c0bd523f117a435a7a531a4f9918d54e0feb7c622d049a29b8be2d8f0c239497c7ab9fb1d138214b600dfadf4a958f
7
+ data.tar.gz: 4deab1e187a588b7e2c19a6449252503c93be7057d785d19ed267956b587be60713e374347fe291b5f9cc34a43930590119244cc54798fb76152296543e153e1
data/lib/STL.rb CHANGED
@@ -1,12 +1,60 @@
1
- def print(x)
2
- pp x
3
- end
4
1
 
5
- module ArrayFunctions
6
- def self.pop()
7
- pop
2
+ module STL
3
+ def self.print(x)
4
+ pp x
5
+ return nil
6
+ end
7
+
8
+ def self.size(array)
9
+ unless array.is_a?(Array)
10
+ raise TypeError, "Function #{__method__} must be used on an array."
11
+ end
12
+
13
+ return array.count
14
+ end
15
+
16
+ def self.pop(array)
17
+ unless array.is_a?(Array)
18
+ raise TypeError, "Function #{__method__} must be used on an array."
19
+ end
20
+ if array.empty?
21
+ raise IndexError, "Can not use pop on an empty array."
22
+ end
23
+ pop_element = array.last
24
+ array.delete_at(-1)
25
+ return pop_element
26
+ end
27
+
28
+ def self.push(array, element)
29
+ unless array.is_a?(Array)
30
+ raise TypeError, "Function #{__method__} must be used on an array."
31
+ end
32
+ array << element
33
+ return array
34
+ end
35
+
36
+ def self.get_element(array, index)
37
+ unless array.is_a?(Array)
38
+ raise TypeError, "Function #{__method__} must be used on an array."
39
+ end
40
+ unless index.between?(0, array.size-1)
41
+ raise IndexError, "Index out of bounds. Max index: #{array.size-1}."
42
+ end
43
+
44
+ element = array[index]
45
+ return element
8
46
  end
9
47
 
10
- def self.push()
48
+ def self.delete_element(array, index)
49
+ unless array.is_a?(Array)
50
+ raise TypeError, "Function #{__method__} must be used on an array."
51
+ end
52
+ unless index.between?(0, array.size-1)
53
+ raise IndexError, "Index out of bounds. Max index: #{array.size-1}."
54
+ end
55
+
56
+ element = array[index]
57
+ array.delete_at(index)
58
+ return element
11
59
  end
12
- end
60
+ end
data/lib/nodes.rb CHANGED
@@ -2,78 +2,70 @@
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 :variables, :functions
7
+ attr_reader :identifiers,:parent_scope, :non_local_variables
7
8
  def initialize(parent_scope = nil)
8
- @variables = {}
9
- @functions = {}
9
+ @identifiers = {}
10
+ @non_local_variables = []
10
11
  @parent_scope = parent_scope
11
12
  end
12
13
 
14
+ # Set variable in current scope
13
15
  def set_variable(name, op, expression)
14
- case op
15
- when '='
16
- @variables[name] = expression
17
- when '+='
18
- @variables[name] += expression
19
- when '-='
20
- @variables[name] -= expression
16
+ if @non_local_variables.include?(name)
17
+ raise NameError, "local identifier #{name} referenced before assignment"
21
18
  end
19
+ if op == '='
20
+ @identifiers[name] = expression
21
+ else
22
+ unless @identifiers.has_key?(name)
23
+ raise NameError, "local identifier #{name} referenced before assignment"
24
+ end
25
+ if op == '+='
26
+ @identifiers[name] += expression
27
+ else
28
+ @identifiers[name] -= expression
29
+ end
30
+ end
31
+ end
22
32
 
23
- return unless @parent_scope
24
-
25
- variable_scope = @parent_scope.get_scope(name, :variables)
26
-
27
- if variable_scope
28
- variable_scope.set_variable(name, op, expression)
33
+ def set_non_local_variable(name)
34
+ unless @non_local_variables.include?(name) && is_function(name)
35
+ @non_local_variables.append(name)
29
36
  end
30
37
  end
31
38
 
32
- def get_identifier(name, id_type)
33
- scope = get_scope(name, id_type)
39
+ # Get value of identifier in current or parent scope(s) if defined.
40
+ def get_identifier(name)
41
+ scope = get_scope(name)
34
42
  if scope
35
- return scope.instance_variable_get("@#{id_type}")[name]
43
+ return scope.identifiers[name]
36
44
  else
37
- raise "[#{id_type}] #{name} not found."
45
+ raise NameError,"Identifier #{name} not defined in scope."
38
46
  end
39
47
  end
40
48
 
41
- def get_scope(name, id_type)
42
- if instance_variable_get("@#{id_type}").has_key?(name)
49
+ # Get first scope where identifier is defined.
50
+ def get_scope(name)
51
+ if @identifiers.has_key?(name)
43
52
  return self
44
53
  elsif @parent_scope
45
- return @parent_scope.get_scope(name, id_type)
54
+ return @parent_scope.get_scope(name)
46
55
  end
47
56
  end
48
57
 
58
+ # Checks if a identifier is a function.
59
+ def is_function?(name)
60
+ scope = get_scope(name)
61
+ id_value = scope.get_identifier(name) if scope
62
+ return id_value.is_a?(Hash)
63
+ end
64
+
65
+ # Set a function in current scope.
49
66
  def set_function(name, block, parameters)
50
- @functions[name] = {:parameters => parameters, :block => block}
51
- if @parent_scope
52
- function_scope = @parent_scope.get_scope(name, :functions)
53
- end
54
- if function_scope
55
- function_scope.set_function(name, block, parameters)
56
- end
67
+ @identifiers[name] = {:parameters => parameters, :block => block}
57
68
  end
58
-
59
- # def initialize_STL
60
- # return unless defined?(STL)
61
- # # STL.methods(false).each do |name|
62
- # # method_object = STL.method(name)
63
- # # @functions[name] = {:parameters => method_object.parameters.flatten[1..-1], :block => method_object}
64
- # # end
65
- # STL.singleton_methods(false).each do |name|
66
- # method_object = STL.method(name)
67
- # parameters = method_object.parameters.map { |type, name| name }.compact
68
- # @functions[name] = { parameters: parameters, block: method_object }
69
- # end
70
-
71
- # STL.instance_methods(false).each do |name|
72
- # method_object = STL.instance_method(name)
73
- # parameters = method_object.parameters.map { |type, name| name }.compact
74
- # @functions[name] = { parameters: parameters, block: method_object }
75
- # end
76
- # end
77
69
  end
78
70
 
79
71
 
@@ -84,10 +76,12 @@ class BlockNode
84
76
 
85
77
  def evaluate(scope)
86
78
  return unless @block
79
+ result = nil
87
80
  @block.each do |statement|
88
81
  result = statement.evaluate(scope)
89
82
  return result if result.is_a?(ReturnValue)
90
83
  end
84
+ return result
91
85
  end
92
86
  end
93
87
 
@@ -105,27 +99,29 @@ class FunctiondefNode
105
99
  end
106
100
 
107
101
  class FunctioncallNode
108
- def initialize(identifier, arguments = [])
102
+ include STL
103
+ def initialize(identifier, object = nil, arguments = [])
109
104
  @identifier = identifier.value
110
105
  @arguments = arguments
106
+ @object = object
111
107
  end
112
108
 
113
109
  def validate_arguments(parameters)
114
110
  if @arguments.size != parameters.size
115
- raise "Wrong number of arguments (given: #{@arguments.size} expected: #{parameters.size})."
111
+ raise ArgumentError, "Wrong number of arguments (given: #{@arguments.size} expected: #{parameters.size})."
116
112
  end
117
113
  end
118
114
 
119
- def evaluate_method(method, scope)
115
+ def evaluate_method(scope)
120
116
  args = @arguments.map {|arg| arg.evaluate(scope)}
121
- method.call(*args)
117
+ result = STL.send(@identifier, *args)
118
+ return result
122
119
  end
123
120
 
124
- def evaluate_block(parameters, block, scope)
125
- new_scope = Scope.new(scope)
126
-
121
+ def evaluate_block(parameters, block, current_scope, id_scope)
122
+ new_scope = Scope.new(id_scope)
127
123
  parameters.zip(@arguments).each do |parameter, argument|
128
- new_scope.set_variable(parameter, '=', argument.evaluate(scope))
124
+ new_scope.set_variable(parameter, '=', argument.evaluate(current_scope))
129
125
  end
130
126
 
131
127
  result = block.evaluate(new_scope)
@@ -133,40 +129,47 @@ class FunctioncallNode
133
129
  end
134
130
 
135
131
  def evaluate(scope)
136
- function_scope = scope.get_scope(@identifier, :functions)
137
- if !function_scope
138
- if self.respond_to?(@identifier, true)
139
- method_object = method(@identifier)
140
- parameters = method_object.parameters.map {|type, name| name}.compact
132
+
133
+ id_scope = scope.get_scope(@identifier)
134
+ if id_scope && !id_scope.is_function?(@identifier)
135
+ raise TypeError, "Identifier #{@identifier} is not defined as a function."
136
+ end
137
+ if @object
138
+ @arguments.unshift(@object)
139
+ end
140
+ if !id_scope
141
+ if STL.respond_to?(@identifier)
142
+ method = STL.method(@identifier)
143
+ parameters = method.parameters
141
144
  validate_arguments(parameters)
142
- evaluate_method(method_object, scope)
145
+ evaluate_method(scope)
143
146
  else
144
- raise "Function #{@identifier} not found."
147
+ raise NameError, "Function #{@identifier} not defined."
145
148
  end
146
149
  else
147
- function = function_scope.get_identifier(@identifier, :functions)
150
+ function = id_scope.get_identifier(@identifier)
148
151
  parameters = function[:parameters]
149
152
  block = function[:block]
150
153
  validate_arguments(parameters)
151
- evaluate_block(parameters, block, scope)
154
+ evaluate_block(parameters, block,scope,id_scope)
152
155
  end
153
156
  end
154
157
  end
155
158
 
156
159
  class ProgramNode
160
+ attr_reader :statements
157
161
  def initialize(statements)
158
162
  @statements = statements
159
163
  end
160
164
 
161
165
  def evaluate
162
166
  global_scope = Scope.new
163
- # global_scope.initialize_STL
164
-
167
+ result = nil
165
168
  @statements.each do |statement|
166
169
  result = statement.evaluate(global_scope)
167
170
  return result.value if statement.is_a?(ReturnNode)
168
171
  end
169
- return
172
+ return result
170
173
  end
171
174
  end
172
175
 
@@ -187,7 +190,6 @@ class ReturnNode
187
190
  end
188
191
  end
189
192
 
190
-
191
193
  class BinaryexpressionNode
192
194
  def initialize(lhs, op, rhs)
193
195
  @lhs = lhs
@@ -196,7 +198,11 @@ class BinaryexpressionNode
196
198
  end
197
199
 
198
200
  def evaluate(scope)
199
- return @lhs.evaluate(scope).send(@op, @rhs.evaluate(scope))
201
+ rhs_value = @rhs.evaluate(scope)
202
+ if @op == :fdiv && rhs_value == 0
203
+ raise ZeroDivisionError,"Division by 0 not possible."
204
+ end
205
+ return @lhs.evaluate(scope).send(@op, rhs_value)
200
206
  end
201
207
  end
202
208
 
@@ -254,38 +260,21 @@ end
254
260
  class WhileNode < ControlflowNode
255
261
  def evaluate(scope)
256
262
  while @expression.evaluate(scope)
257
- result = @block.evaluate(scope)
263
+ @block.evaluate(scope)
258
264
  end
259
265
  end
260
266
  end
261
267
 
262
-
263
- # Unsure about implementation, will check with project assistant
264
268
  class ArrayNode
265
269
  def initialize(elements = [])
266
270
  @elements = elements
267
- @data_container = {}
268
271
  end
269
272
 
270
273
  def evaluate(scope)
271
- @elements.each_with_index do |element, index|
272
- @data_container[index] = element.evaluate(scope)
273
- end
274
+ return @elements.map {|element| element.evaluate(scope)}
274
275
  end
275
276
  end
276
277
 
277
-
278
- # Not implemented yet
279
- class StringNode
280
- def initialize(chars = [])
281
- @chars = chars
282
- end
283
-
284
- def evaluate(scope)
285
- end
286
- end
287
-
288
-
289
278
  class PrimitiveNode
290
279
  attr_reader :value
291
280
  def initialize(value)
@@ -299,7 +288,14 @@ end
299
288
 
300
289
  class IdentifierNode < PrimitiveNode
301
290
  def evaluate(scope)
302
- return scope.get_identifier(@value, :variables)
291
+ if scope.is_function?(@value)
292
+ raise SyntaxError, "Identifier #{@value} is assigned to a function. Please use correct syntax for function call."
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
303
299
  end
304
300
  end
305
301
 
@@ -310,4 +306,5 @@ class DigitNode < PrimitiveNode
310
306
  end
311
307
 
312
308
  class BoolNode < PrimitiveNode
313
- end
309
+ end
310
+
@@ -3,17 +3,20 @@
3
3
  require_relative 'rdparse.rb'
4
4
  require_relative 'nodes.rb'
5
5
 
6
- class MyLang
6
+ class Pycplus
7
7
 
8
8
  def initialize
9
9
 
10
- @lang_parser = Parser.new("lang parser") do
10
+ @pycplus_parser = Parser.new("Pycplus parser") do
11
+ token(/#[^#]*#/)
11
12
  token(/\n/)
12
- # token(/\\/)
13
- # token(/"/) {|m| m}
14
- token(/"[^"]"/) {|m| m.chars}
15
13
  token(/\s+/)
16
- token(/if/) {|m| m}
14
+ token(/if/) {:if}
15
+ token(/while/) {:while}
16
+ token(/def/) {:def}
17
+ token(/return/) {:return}
18
+ token(/false/) {|m| m}
19
+ token(/true/) {|m| m}
17
20
  token(/>=/) {|m| m}
18
21
  token(/<=/) {|m| m}
19
22
  token(/==/) {|m| m}
@@ -22,11 +25,6 @@ class MyLang
22
25
  token(/\-=/) {|m| m}
23
26
  token(/&&/) {|m| m}
24
27
  token(/\|\|/) {|m| m}
25
- token(/true/) {|m| m}
26
- token(/false/) {|m| m}
27
- token(/return/) {|m| m}
28
- token(/def/) {|m| m}
29
- token(/while/) {|m| m}
30
28
  token(/\d+\.\d+/) {|m| m.to_f}
31
29
  token(/\d+/) {|m| m.to_i}
32
30
  token(/\w+/) {|m| m}
@@ -43,17 +41,18 @@ class MyLang
43
41
 
44
42
  rule :statement do
45
43
  match(:assignment, ';')
46
- match(:function_def)
47
44
  match(:function_call, ';')
48
- match(:return, ';')
45
+ match(:function_def)
46
+ match(:return_statement, ';')
49
47
  match(:if_statement)
50
48
  match(:while_statement)
49
+ match(:expression_statement)
51
50
  end
52
51
 
53
52
  rule :assignment do
54
- match(:identifier, :assignment_OP, :container) {|a, b, c| AssignmentNode.new(a,b,c)}
53
+ # match(:identifier, :assignment_OP, :function_call) {|a, b, c| AssignmentNode.new(a,b,c)}
55
54
  match(:identifier, :assignment_OP, :logical_expr) {|a, b, c| AssignmentNode.new(a,b,c)}
56
- match(:identifier, :assignment_OP, :function_call) {|a, b, c| AssignmentNode.new(a,b,c)}
55
+ match(:identifier, :assignment_OP, :array) {|a, b, c| AssignmentNode.new(a,b,c)}
57
56
  end
58
57
 
59
58
  rule :assignment_OP do
@@ -63,8 +62,8 @@ class MyLang
63
62
  end
64
63
 
65
64
  rule :function_def do
66
- match('def', :identifier, '(', :parameters , ')', :block) {|_, a, _, b, _, c| FunctiondefNode.new(a,c,b)}
67
- match('def', :identifier, '(', ')', :block) {|_, a, _, _, b| FunctiondefNode.new(a,b)}
65
+ match(:def, :identifier, '(', :parameters , ')', :block) {|_, a, _, b, _, c| FunctiondefNode.new(a,c,b)}
66
+ match(:def, :identifier, '(', ')', :block) {|_, a, _, _, b| FunctiondefNode.new(a,b)}
68
67
  end
69
68
 
70
69
  rule :parameters do
@@ -82,10 +81,17 @@ class MyLang
82
81
  end
83
82
 
84
83
  rule :function_call do
85
- match(:identifier,'(', :arguments, ')') {|a, _, b, _| FunctioncallNode.new(a,b)}
84
+ match(:identifier,'(', :arguments, ')') {|a, _, b, _| FunctioncallNode.new(a,nil,b)}
86
85
  match(:identifier,'(', ')') {|a, _, _| FunctioncallNode.new(a)}
87
- # match(:identifier, '.', :identifier,'(', :arguments, ')') {|a, _, b, _| FunctioncallNode.new(a,b)}
88
- # match(:identifier, '.', :identifier,'(',')')
86
+ match(:function_call,'.',:identifier ,'(',')') {|a, _, b, _, _| FunctioncallNode.new(b, a)}
87
+ match(:function_call,'.',:identifier ,'(',:arguments,')') {|a, _, b, _, c, _| FunctioncallNode.new(b,a,c)}
88
+ match(:object,'.',:identifier ,'(',')') {|a, _, b, _, _| FunctioncallNode.new(b, a)}
89
+ match(:object,'.',:identifier ,'(',:arguments,')') {|a, _, b, _, c, _| FunctioncallNode.new(b,a,c)}
90
+ end
91
+
92
+ rule :object do
93
+ match(:array)
94
+ match(:atom)
89
95
  end
90
96
 
91
97
  rule :arguments do
@@ -95,20 +101,25 @@ class MyLang
95
101
 
96
102
  rule :argument do
97
103
  match(:logical_expr)
98
- match(:function_call)
104
+ match(:array)
99
105
  end
100
106
 
101
- rule :return do
102
- match('return', :logical_expr) {|_, a| ReturnNode.new(a)}
103
- match('return', :function_call) {|_, a| ReturnNode.new(a)}
107
+ rule :return_statement do
108
+ match(:return, :logical_expr) {|_, a| ReturnNode.new(a)}
109
+ match(:return, :array) {|_, a| ReturnNode.new(a)}
110
+ # match(:return, :function_call) {|_, a| ReturnNode.new(a)}
104
111
  end
105
112
 
106
113
  rule :while_statement do
107
- match('while', '(', :logical_expr, ')', :block) {|_,_,a,_,b| WhileNode.new(a,b)}
114
+ match(:while, '(', :logical_expr, ')', :block) {|_,_,a,_,b| WhileNode.new(a,b)}
108
115
  end
109
116
 
110
117
  rule :if_statement do
111
- match('if', '(', :logical_expr, ')', :block) {|_,_,a,_,b| IfNode.new(a,b)}
118
+ match(:if, '(', :logical_expr, ')', :block) {|_,_,a,_,b| IfNode.new(a,b)}
119
+ end
120
+
121
+ rule :expression_statement do
122
+ match(:logical_expr, ';')
112
123
  end
113
124
 
114
125
  rule :logical_expr do
@@ -153,7 +164,7 @@ class MyLang
153
164
  rule :multiplication_OP do
154
165
  match('%') {|a| a}
155
166
  match('*') {|a| a}
156
- match('/') {|a| a}
167
+ match('/') {|_| :fdiv}
157
168
  end
158
169
 
159
170
  rule :power_expr do
@@ -173,21 +184,17 @@ class MyLang
173
184
  rule :unary_OP do
174
185
  match('!') {|a| a}
175
186
  match('-') {|a| a}
187
+ match('+') {|a| a}
176
188
  end
177
189
 
178
190
  rule :binary_operand do
191
+ match(:function_call)
179
192
  match(:bool)
180
193
  match(:digit)
181
- match(:function_call)
182
194
  match(:identifier)
183
195
  match('(', :logical_expr, ')') {|_, a, _| a}
184
196
  end
185
197
 
186
- rule :container do
187
- match(:string)
188
- match(:array)
189
- end
190
-
191
198
  rule :array do
192
199
  match('[', :elements , ']') {|_, a, _| ArrayNode.new(a)}
193
200
  match('[', ']') {|_,_| ArrayNode.new()}
@@ -200,33 +207,18 @@ class MyLang
200
207
 
201
208
  rule :element do
202
209
  match(:logical_expr)
203
- match(:container)
204
- end
205
-
206
- rule :string do
207
- match('"', :chars, '"') {|_, a, _| StringNode.new(a)}
208
- match('"', '"') {|_, _| StringNode.new()}
209
- end
210
-
211
- rule :chars do
212
- match(:chars, :char) {|a , b| a << b}
213
- match(:char) {|a| [a]}
210
+ match(:array)
214
211
  end
215
212
 
216
213
  rule :atom do
217
214
  match(:bool)
218
215
  match(:digit)
219
- match(:char)
220
216
  match(:identifier)
221
217
  end
222
218
 
223
- rule :char do
224
- match(/./) {|a| CharNode.new(a)}
225
- end
226
-
227
219
  rule :bool do
228
- match('true') {|_| BoolNode.new(true)}
229
- match('false') {|_| BoolNode.new(false)}
220
+ match('true') {|a| BoolNode.new(true)}
221
+ match('false') {|a| BoolNode.new(false)}
230
222
  end
231
223
 
232
224
  rule :digit do
@@ -235,7 +227,7 @@ class MyLang
235
227
  end
236
228
 
237
229
  rule :identifier do
238
- match(/_?[a-zA-Z*]\w*/) {|a| IdentifierNode.new(a.to_sym)}
230
+ match(/[_a-zA-Z]+\w*/) {|a| IdentifierNode.new(a.to_sym)}
239
231
  end
240
232
  end
241
233
  end
@@ -243,23 +235,30 @@ class MyLang
243
235
  def parse_file(filename)
244
236
  file = File.open(filename)
245
237
  file_data = file.read
246
- result = @lang_parser.parse(file_data)
247
- return result.evaluate
238
+ result = @pycplus_parser.parse(file_data)
239
+ return result.evaluate if result
248
240
  end
249
241
 
250
- def parse_string(str, display_output = false)
251
- output = @lang_parser.parse(str)
242
+ def parse_string(str, return_tree = false, display_output = false)
243
+ output = @pycplus_parser.parse(str)
252
244
  if display_output
253
245
  puts "=> #{output}"
254
246
  end
255
- return output.evaluate
247
+ if return_tree
248
+ return output
249
+ else
250
+ return output.evaluate if output
251
+ end
256
252
  end
257
253
 
258
254
  def log(state = true)
259
255
  if state
260
- @lang_parser.logger.level = Logger::DEBUG
256
+ @pycplus_parser.logger.level = Logger::DEBUG
261
257
  else
262
- @lang_parser.logger.level = Logger::WARN
258
+ @pycplus_parser.logger.level = Logger::WARN
263
259
  end
264
260
  end
265
- end
261
+ end
262
+
263
+
264
+ # _?[a-zA-Z*]\w*
data/lib/rdparse.rb CHANGED
@@ -219,7 +219,7 @@ class Parser
219
219
  def rule(name,&block)
220
220
  @current_rule = Rule.new(name, self)
221
221
  @rules[name] = @current_rule
222
- instance_eval &block # In practise, calls match 1..N times
222
+ instance_eval(&block) # In practise, calls match 1..N times
223
223
  @current_rule = nil
224
224
  end
225
225
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pycplus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Johannes
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2024-05-01 00:00:00.000000000 Z
12
+ date: 2024-05-05 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: test-unit
@@ -31,8 +31,8 @@ dependencies:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: 3.6.0
34
- description: This Ruby Gem provides a framework for creating and utilizing a domain-specific
35
- language (DSL) developed as part of a school project at LiU (Linköping University).
34
+ description: This Ruby Gem provides a framework for creating and utilizing a programming
35
+ language developed as part of a school project at LiU (Linköping University).
36
36
  email: test@test.com
37
37
  executables:
38
38
  - pycplus
@@ -42,11 +42,10 @@ files:
42
42
  - README.md
43
43
  - bin/pycplus
44
44
  - lib/STL.rb
45
- - lib/lang.rb
46
45
  - lib/nodes.rb
46
+ - lib/pcpparse.rb
47
47
  - lib/rdparse.rb
48
- - lib/test.rb
49
- homepage: https://rubygems.org/gems/mytestdsl
48
+ homepage: https://rubygems.org/gems/pycplus
50
49
  licenses: []
51
50
  metadata: {}
52
51
  post_install_message:
@@ -67,5 +66,5 @@ requirements: []
67
66
  rubygems_version: 3.3.5
68
67
  signing_key:
69
68
  specification_version: 4
70
- summary: A Ruby Gem for creating and using a domain-specific language (DSL)
69
+ summary: A Ruby Gem for creating and using a programming language.
71
70
  test_files: []
data/lib/test.rb DELETED
@@ -1,161 +0,0 @@
1
- require_relative '../lib/lang.rb'
2
- require 'test/unit'
3
-
4
- class TestFaculty < Test::Unit::TestCase
5
- def setup
6
- @lang_parser = MyLang.new
7
- @lang_parser.log(false)
8
- end
9
-
10
- # # Test for simple addition
11
- # def test_addition_expr
12
- # assert_equal(1, @lang_parser.parse_string("return 0+1;"))
13
- # assert_equal(0, @lang_parser.parse_string("return -1+1;"))
14
- # assert_equal(-1, @lang_parser.parse_string("return -2+1;"))
15
- # end
16
-
17
- # # Test for simple subtraction
18
- # def test_subtraction_expr
19
- # assert_equal(1, @lang_parser.parse_string("return 2-1;"))
20
- # assert_equal(0, @lang_parser.parse_string("return 1-1;"))
21
- # assert_equal(-1, @lang_parser.parse_string("return 1-2;"))
22
- # assert_equal(2, @lang_parser.parse_string("return 1--1;"))
23
- # end
24
-
25
- # # Test for simple multiplication
26
- # def test_multiplication_expr
27
- # assert_equal(1, @lang_parser.parse_string("return 1*1;"))
28
- # assert_equal(0, @lang_parser.parse_string("return 0*1;"))
29
- # assert_equal(-1, @lang_parser.parse_string("return -1*1;"))
30
- # end
31
-
32
- # # Test for simple division
33
- # def test_division_expr
34
- # assert_equal(1, @lang_parser.parse_string("return 1/1;"))
35
- # assert_equal(0, @lang_parser.parse_string("return 0/1;"))
36
- # assert_equal(-1, @lang_parser.parse_string("return -1/1;"))
37
- # end
38
-
39
- # # Test for simple modulo
40
- # def test_modulo_expr
41
- # assert_equal(0, @lang_parser.parse_string("return 9%3;"))
42
- # assert_equal(1, @lang_parser.parse_string("return 5%2;"))
43
- # end
44
-
45
- # # Test for parentheses priority
46
- # def test_parentheses_priority
47
- # assert_equal(3, @lang_parser.parse_string("return (3-2)*3;"))
48
- # assert_equal(7, @lang_parser.parse_string("return (3+4)*(6-2)/(2+2);"))
49
- # assert_equal(1, @lang_parser.parse_string("return (5-3)/(1*2);"))
50
- # end
51
-
52
- # # test for power expressions
53
- # def test_power_expr
54
- # assert_equal(4, @lang_parser.parse_string("return 2^2;"))
55
- # assert_equal(8, @lang_parser.parse_string("return 2^2*2;"))
56
- # assert_equal(256, @lang_parser.parse_string("return 2^2^3;"))
57
- # end
58
-
59
- # # Test for variable names
60
- # def test_variable_names
61
- # assert_equal(1, @lang_parser.parse_string("a = 1; return a;"))
62
- # assert_equal(1, @lang_parser.parse_string("_a = 1; return _a;"))
63
- # assert_equal(1, @lang_parser.parse_string("A131 = 1; return A131;"))
64
-
65
- # # Forbidden variable names throws parsing error
66
- # assert_raises Parser::ParseError do
67
- # @lang_parser.parse_string("1a = 1;")
68
- # end
69
- # assert_raises Parser::ParseError do
70
- # @lang_parser.parse_string("_1 = 1;")
71
- # end
72
- # assert_raises Parser::ParseError do
73
- # @lang_parser.parse_string("1 = 1;")
74
- # end
75
- # assert_raises Parser::ParseError do
76
- # @lang_parser.parse_string("1 = 1;")
77
- # end
78
- # assert_raises Parser::ParseError do
79
- # @lang_parser.parse_string("_a? = 1;")
80
- # end
81
- # end
82
-
83
- # # Test for comparsion expressions
84
- # def test_comparison_expr
85
- # assert_equal(true, @lang_parser.parse_string("return 1 < 2;"))
86
- # assert_equal(false, @lang_parser.parse_string("return 1 > 2;"))
87
-
88
- # assert_equal(false, @lang_parser.parse_string("return 1 >= 2;"))
89
- # assert_equal(true, @lang_parser.parse_string("return 2 >= 2;"))
90
- # assert_equal(true, @lang_parser.parse_string("return 1 <= 2;"))
91
- # assert_equal(false, @lang_parser.parse_string("return 3 <= 2;"))
92
-
93
- # assert_equal(false, @lang_parser.parse_string("return 1 == 2;"))
94
- # assert_equal(true, @lang_parser.parse_string("return 2 == 2;"))
95
- # assert_equal(true, @lang_parser.parse_string("return false == false;"))
96
- # assert_equal(true, @lang_parser.parse_string("a=2; return a == 2;"))
97
- # assert_equal(false, @lang_parser.parse_string("a=2; return a == 3;"))
98
-
99
- # assert_equal(true, @lang_parser.parse_string("return 1 != 2;"))
100
- # assert_equal(false, @lang_parser.parse_string("return 2 != 2;"))
101
- # end
102
-
103
- # # Test for bool assignment
104
- # def test_assignmen_bool
105
- # assert_equal(false, @lang_parser.parse_string("a = false; return a;"))
106
- # assert_equal(true, @lang_parser.parse_string("a = true; return a;"))
107
- # end
108
-
109
- # # Test for logical expressions
110
- # def test_logical_expr
111
- # assert_equal(false, @lang_parser.parse_string("a = true && false; return a;"))
112
- # assert_equal(true, @lang_parser.parse_string("a = false || true; return a;"))
113
- # assert_equal(true, @lang_parser.parse_string("a = true && false || true; return a;"))
114
- # end
115
-
116
- # # Test for if statements
117
- # def test_if_statement
118
- # assert_equal(11, @lang_parser.parse_string("a=1; if(10>1){b=10; a=a+b;} return a;"))
119
- # assert_equal(1, @lang_parser.parse_string("a=1; if(a<1){b=10; a=a+b;} return a;"))
120
-
121
- # # Raises error when variable has not been defined in if-statement
122
- # assert_raises RuntimeError do
123
- # @lang_parser.parse_string("if(10<1){a=33;} return a;")
124
- # end
125
- # end
126
-
127
- # # Test for define function and call
128
- # def test_function_def_and_call
129
- # assert_equal(4, @lang_parser.parse_string("def test(z,x){a = z+x; return a+1;} b=test(1,2); return b;"))
130
- # assert_equal(11, @lang_parser.parse_string("def test(){a = 10; return a+1;} return test();"))
131
- # assert_equal(true, @lang_parser.parse_string("def test(x){return x && true;} return test(true);"))
132
- # assert_equal(100, @lang_parser.parse_string("a=1; b=99; def test(x){c=x+b; return c;} return test(a);"))
133
- # assert_equal(100, @lang_parser.parse_string("a=1; b=99; def test(x){a=x+b;} test(a); return a;"))
134
-
135
- # # Raises error when functioncall with wrong number of arguments
136
- # assert_raises RuntimeError do
137
- # @lang_parser.parse_string("def test(){a = 10; return a+1;} return test(1);")
138
- # end
139
-
140
- # # Raises error when functioncall with wrong name
141
- # assert_raises RuntimeError do
142
- # @lang_parser.parse_string("def test(){a = 10; return a+1;} a(1);")
143
- # end
144
- # end
145
-
146
- # # Test for while-statement
147
- # def test_while_statement
148
- # assert_equal(10, @lang_parser.parse_string("a=1; while(a<10){a=a+1;} return a;"))
149
- # assert_equal(18, @lang_parser.parse_string("a=1; while(a<10){b=a*2; a=a+1;} return b;"))
150
-
151
- # assert_raises RuntimeError do
152
- # assert_equal(10, @lang_parser.parse_string("a=1; while(a>10){b=a+1;} return b;"))
153
- # end
154
- # end
155
-
156
- # Test for recursion
157
- def test_recursion
158
- # assert_equal(720, @lang_parser.parse_string("def factorial(n){if(n==0 || n==1){return 1;} return n*factorial(n-1);} print(factorial(6);)"))
159
- assert_equal(720, @lang_parser.parse_string("x=1; def hahatest(){ print(x); return x;} x=99; def tt(){x=22;} print(hahatest()); tt(); return x;"))
160
- end
161
- end