pycplus 0.3.0 → 0.4.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.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/bin/pycplus +45 -42
  3. data/lib/nodes.rb +33 -13
  4. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2fde7222ccd4137c44659d5df46a12bc2cb57facbb373c129d54af19596aeb93
4
- data.tar.gz: b86597ee3514507775c3a2be65e9fd8ed1f2778be48d276b45b99898e0ba8223
3
+ metadata.gz: 5f3bc5bfe8923bf561c4a2b3167a862151f1487d62b84bb1587f9f07b0433c63
4
+ data.tar.gz: 4872ec376c3501b869ed773b0a535b894abe35d9af05af81784cf081a34696dc
5
5
  SHA512:
6
- metadata.gz: 1437d02dc107e13a85893882db8d325e42d46e62783eeb27c7c58cbf4ce08bc844103e011084a36686ed465fac755bb3e45f96b274e9df4788637fd64ae33bfc
7
- data.tar.gz: 03faa5bad0cd3ca3242d64e236995baa1d03337d68fe013d3152e6f2a82d74919c8311cd2d1c1361486a8ff55515134d7cd7c0e3be9931b9f72533160f6adb74
6
+ metadata.gz: 84dd3244332bfe07a86e8448276f0bdb7ebd5318696ba882ab707fbb8e82aaeba63e40c6cc531a166012461df549a47bede2e9a07bab81cf58255f1d6faeb784
7
+ data.tar.gz: 3002a3bc7ce8f595fd1f84371796cd4ad0ce9de8ad4f0d08c5dbe7278685c9278f8be3fbc7f7d8618b923ef03af483c0e0f4d65cda9b934918f3bc3ff0c918b6
data/bin/pycplus CHANGED
@@ -7,59 +7,62 @@ require_relative '../lib/pcpparse'
7
7
 
8
8
  # Method to print gem version
9
9
  def print_version
10
- spec = Gem::Specification.load('../pycplus.gemspec')
11
- puts "#{spec.name} version #{spec.version}"
10
+ begin
11
+ spec = Gem.loaded_specs['pycplus']
12
+ puts "#{spec.name} version #{spec.version}"
13
+ rescue
14
+ begin
15
+ spec = Gem::Specification.load('../pycplus.gemspec')
16
+ puts "#{spec.name} version #{spec.version}"
17
+ rescue
18
+ puts "Error: Unable to find version for pycplus gem"
19
+ end
20
+ end
12
21
  end
13
22
 
14
- def main
15
- # Parse other command-line options using OptionParser
16
- options = {}
17
- OptionParser.new do |opts|
18
23
 
19
- opts.banner = "Usage: #{File.basename($PROGRAM_NAME)} [options] filename"
24
+ # Parse other command-line options using OptionParser
25
+ options = {}
26
+ OptionParser.new do |opts|
20
27
 
21
- # version is handled as a special case as it doesn't make sense to use it alongside the other options
22
- opts.on("-v", "--version", "Display version information") do
23
- print_version
24
- exit
25
- end
28
+ opts.banner = "Usage: #{File.basename($PROGRAM_NAME)} [options] filename"
26
29
 
27
- opts.on("-d", "--debug", "Enable debug mode") do
28
- options[:debug] = true
29
- print("dhsdhshdshds")
30
- end
31
- end.parse!
30
+ # version is handled as a special case as it doesn't make sense to use it alongside the other options
31
+ opts.on("-v", "--version", "Display version information") do
32
+ print_version
33
+ exit
34
+ end
32
35
 
33
- # Check if a filename argument is provided
34
- if ARGV.empty?
35
- puts "Error: No filename or arguments provided."
36
- exit 1
36
+ opts.on("-d", "--debug", "Enable debug mode") do
37
+ options[:debug] = true
38
+ print("dhsdhshdshds")
37
39
  end
40
+ end.parse!
38
41
 
39
- filename = ARGV.shift
40
- @lang_parser = Pycplus.new
42
+ # Check if a filename argument is provided
43
+ if ARGV.empty?
44
+ puts "Error: No filename or arguments provided."
45
+ exit 1
46
+ end
41
47
 
42
- # Enable debug mode if specified
43
- if options[:debug]
44
- @lang_parser.log(true)
45
- else
46
- @lang_parser.log(false)
47
- end
48
+ filename = ARGV.shift
49
+ @lang_parser = Pycplus.new
48
50
 
49
- if File.file?(filename)
50
- extension = File.extname(filename)
51
+ # Enable debug mode if specified
52
+ if options[:debug]
53
+ @lang_parser.log(true)
54
+ else
55
+ @lang_parser.log(false)
56
+ end
51
57
 
52
- if extension == ".pcp"
53
- @lang_parser.parse_file(filename)
54
- else
55
- puts "Error: File is not a .pcp file. Please provide a file with the correct extension."
56
- end
58
+ if File.file?(filename)
59
+ extension = File.extname(filename)
60
+
61
+ if extension == ".pcp"
62
+ @lang_parser.parse_file(filename)
57
63
  else
58
- puts "Error: Unable to find file #{filename}"
64
+ puts "Error: File is not a .pcp file. Please provide a file with the correct extension."
59
65
  end
66
+ else
67
+ puts "Error: Unable to find file #{filename}"
60
68
  end
61
-
62
-
63
- if __FILE__ == $PROGRAM_NAME
64
- main
65
- end
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
- id_scope = get_scope(name)
17
- @identifiers[name] = get_identifier(name) if id_scope
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, scope)
106
- new_scope = Scope.new(scope)
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(scope))
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, scope)
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
+
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.3.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Johannes