tp_plus 0.0.73 → 0.0.74

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +74 -65
  3. data/Rakefile +35 -21
  4. data/bin/tpp +73 -73
  5. data/lib/tp_plus/interpreter.rb +152 -129
  6. data/lib/tp_plus/namespace.rb +66 -66
  7. data/lib/tp_plus/nodes/abort_node.rb +9 -9
  8. data/lib/tp_plus/nodes/address_node.rb +22 -0
  9. data/lib/tp_plus/nodes/argument_node.rb +20 -19
  10. data/lib/tp_plus/nodes/assignment_node.rb +45 -45
  11. data/lib/tp_plus/nodes/call_node.rb +34 -34
  12. data/lib/tp_plus/nodes/case_condition_node.rb +26 -26
  13. data/lib/tp_plus/nodes/case_node.rb +33 -33
  14. data/lib/tp_plus/nodes/comment_node.rb +22 -22
  15. data/lib/tp_plus/nodes/conditional_node.rb +60 -54
  16. data/lib/tp_plus/nodes/definition_node.rb +22 -22
  17. data/lib/tp_plus/nodes/digit_node.rb +22 -21
  18. data/lib/tp_plus/nodes/empty_stmt_node.rb +9 -0
  19. data/lib/tp_plus/nodes/eval_node.rb +13 -13
  20. data/lib/tp_plus/nodes/expression_node.rb +68 -65
  21. data/lib/tp_plus/nodes/for_node.rb +20 -20
  22. data/lib/tp_plus/nodes/header_node.rb +27 -27
  23. data/lib/tp_plus/nodes/indirect_node.rb +51 -49
  24. data/lib/tp_plus/nodes/inline_conditional_node.rb +40 -40
  25. data/lib/tp_plus/nodes/io_method_node.rb +55 -55
  26. data/lib/tp_plus/nodes/io_node.rb +31 -30
  27. data/lib/tp_plus/nodes/jump_node.rb +23 -23
  28. data/lib/tp_plus/nodes/label_definition_node.rb +21 -21
  29. data/lib/tp_plus/nodes/motion_node.rb +62 -62
  30. data/lib/tp_plus/nodes/namespace_node.rb +16 -16
  31. data/lib/tp_plus/nodes/namespaced_var_node.rb +38 -38
  32. data/lib/tp_plus/nodes/numreg_node.rb +26 -25
  33. data/lib/tp_plus/nodes/offset_node.rb +27 -27
  34. data/lib/tp_plus/nodes/operator_node.rb +78 -72
  35. data/lib/tp_plus/nodes/paren_expression_node.rb +17 -0
  36. data/lib/tp_plus/nodes/pause_node.rb +9 -9
  37. data/lib/tp_plus/nodes/position_data_node.rb +64 -50
  38. data/lib/tp_plus/nodes/position_node.rb +26 -25
  39. data/lib/tp_plus/nodes/posreg_node.rb +64 -48
  40. data/lib/tp_plus/nodes/raise_node.rb +13 -13
  41. data/lib/tp_plus/nodes/real_node.rb +27 -27
  42. data/lib/tp_plus/nodes/set_skip_node.rb +14 -0
  43. data/lib/tp_plus/nodes/skip_node.rb +22 -22
  44. data/lib/tp_plus/nodes/speed_node.rb +29 -29
  45. data/lib/tp_plus/nodes/string_node.rb +13 -13
  46. data/lib/tp_plus/nodes/string_register_node.rb +26 -25
  47. data/lib/tp_plus/nodes/termination_node.rb +23 -18
  48. data/lib/tp_plus/nodes/terminator_node.rb +16 -16
  49. data/lib/tp_plus/nodes/time_node.rb +24 -24
  50. data/lib/tp_plus/nodes/timer_method_node.rb +37 -37
  51. data/lib/tp_plus/nodes/timer_node.rb +16 -21
  52. data/lib/tp_plus/nodes/units_node.rb +20 -20
  53. data/lib/tp_plus/nodes/use_node.rb +21 -21
  54. data/lib/tp_plus/nodes/user_alarm_node.rb +16 -15
  55. data/lib/tp_plus/nodes/var_method_node.rb +23 -23
  56. data/lib/tp_plus/nodes/var_node.rb +39 -39
  57. data/lib/tp_plus/nodes/vision_register_node.rb +22 -21
  58. data/lib/tp_plus/nodes/wait_for_node.rb +54 -54
  59. data/lib/tp_plus/nodes/wait_until_node.rb +65 -65
  60. data/lib/tp_plus/nodes/while_node.rb +42 -36
  61. data/lib/tp_plus/parser.rb +1682 -1592
  62. data/lib/tp_plus/scanner.rb +283 -383
  63. data/lib/tp_plus/token.rb +97 -0
  64. data/lib/tp_plus/version.rb +3 -3
  65. data/lib/tp_plus.rb +66 -62
  66. data/test/test_helper.rb +5 -5
  67. data/test/tp_plus/test_interpreter.rb +1309 -1168
  68. data/test/tp_plus/test_parser.rb +496 -489
  69. data/test/tp_plus/test_scanner.rb +577 -522
  70. data/tp_plus.gemspec +31 -28
  71. metadata +61 -14
  72. data/lib/tp_plus/nodes/set_node.rb +0 -22
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 67da7b5806591383225c3d09717b6df2951a3c39
4
- data.tar.gz: d11d8ac4716e5cccfc17b9913d587b2209a3438f
3
+ metadata.gz: 145a37ef7d63642c1a654a9e804c0dc8ce21f1b0
4
+ data.tar.gz: 3229bc8c6be259a54326b1d83ff5cc295a443b6c
5
5
  SHA512:
6
- metadata.gz: 82ef1ac3fbfa26321b17e679613c69b7bb43ccb5997f927fe2c8a87677600996a93e3f42708b2f997aaab7e83caefbc6e8ddbc82ef786c1a6209d928387fc9ef
7
- data.tar.gz: fc6b978abb2f2952d3622f165549b0c7e700c0e60b78ebc2b6496201216f7a666cf62835be5ca9605692a5e7fb98488a957382ac5fdf9fe6086bf7592d62bd02
6
+ metadata.gz: 33068559319eff301cd865cef17e9db384ab30b50b7f59fa44659b4ba4ad87289a195ac500ce9105a7355a5561e9f483f6c9b22946c59e89458d5b85c395df9b
7
+ data.tar.gz: 0c4db71fa16f12d8fa0d244c0a1b59a25a492f9911049a3697c8fa33a5b46ee6387848928dcf0daaa8ce912b461d589e353c5214d4255f0ca2eec29f3a32a2cf
data/README.md CHANGED
@@ -1,65 +1,74 @@
1
- TP+
2
- ===
3
-
4
- TP+ is a higher-level language abstraction that translates into FANUC
5
- TP. It features many useful utilities that makes creating TP programs
6
- easier:
7
-
8
- * Identifiers for registers, position registers, IO, etc.
9
- * Re-usable methods
10
- * If-else blocks
11
- * Readable motion statements
12
- * Automatic label numbering
13
-
14
- Of course adding another layer of abstraction takes you a step further
15
- away from the code the robot is running. However, it's hoped that the
16
- increased productivity and rigid syntax requirements will actually
17
- improve your TP code.
18
-
19
- Examples
20
- --------
21
-
22
- example_1.tpp
23
-
24
- foo := R[1]
25
-
26
- bar := DO[1]
27
- baz := DO[2]
28
-
29
- home := PR[1]
30
-
31
-
32
- foo = 1
33
-
34
- @loop
35
- foo += 1
36
-
37
- jump_to @foo if foo < 10
38
-
39
- turn_on bar if foo == 5
40
- toggle baz
41
-
42
- linear_move.to(home).at(2000mm/s).term(0)
43
-
44
-
45
- example_1.ls
46
-
47
- /PROG example_1
48
- /MN
49
- 1: R[1:foo] = 1 ;
50
- 1: ;
51
- 1: LBL[1:loop] ;
52
- 1: R[1:foo]=R[1:foo]+1 ;
53
- 1: IF R[1:foo]<10,JMP LBL[1] ;
54
- 1: ;
55
- 1: IF (R[1:foo]=5),DO[1:bar]=(ON) ;
56
- 1: DO[2:baz]=(!DO[2:baz]) ;
57
- 1: ;
58
- 1: L PR[1:home] 2000mm/sec CNT0 ;
59
- /END
60
-
61
-
62
- License
63
- -------
64
-
65
- TP+ is released under the [MIT License](http://www.opensource.org/licenses/MIT).
1
+ TP+
2
+ ===
3
+
4
+ [![Build Status](https://travis-ci.org/onerobotics/tp_plus.svg?branch=master)](https://travis-ci.org/onerobotics/tp_plus)
5
+
6
+ TP+ is a higher-level language abstraction that translates into FANUC
7
+ TP. It features many useful utilities that makes creating TP programs
8
+ easier:
9
+
10
+ * Identifiers for registers, position registers, IO, etc.
11
+ * Re-usable methods
12
+ * If-else blocks
13
+ * Readable motion statements
14
+ * Automatic label numbering
15
+
16
+ Of course adding another layer of abstraction takes you a step further
17
+ away from the code the robot is running. However, it's hoped that the
18
+ increased productivity and rigid syntax requirements will actually
19
+ improve your TP code.
20
+
21
+ Examples
22
+ --------
23
+
24
+ example_1.tpp
25
+
26
+ foo := R[1]
27
+ bar := DO[1]
28
+ baz := DO[2]
29
+
30
+ home := PR[1]
31
+
32
+ foo = 1
33
+
34
+ @loop
35
+ foo += 1
36
+
37
+ jump_to @loop if foo < 10
38
+
39
+ turn_on bar if foo == 5
40
+ toggle baz
41
+
42
+ linear_move.to(home).at(2000mm/s).term(0)
43
+
44
+
45
+ example_1.ls
46
+
47
+ /PROG example_1
48
+ /MN
49
+ 1: R[1:foo] = 1 ;
50
+ 1: ;
51
+ 1: LBL[100:loop] ;
52
+ 1: R[1:foo]=R[1:foo]+1 ;
53
+ 1: IF R[1:foo]<10,JMP LBL[100] ;
54
+ 1: ;
55
+ 1: IF (R[1:foo]=5),DO[1:bar]=(ON) ;
56
+ 1: DO[2:baz]=(!DO[2:baz]) ;
57
+ 1: ;
58
+ 1: L PR[1:home] 2000mm/sec CNT0 ;
59
+ /END
60
+
61
+ For a more extensive example and test environment, visit http://tp-plus.herokuapp.com/.
62
+
63
+ Usage
64
+ -----
65
+
66
+ 1. `gem install tp_plus`
67
+ 2. `tpp filename.tpp > filename.ls`
68
+
69
+ See `tpp --help` for options.
70
+
71
+ License
72
+ -------
73
+
74
+ TP+ is released under the [MIT License](http://www.opensource.org/licenses/MIT).
data/Rakefile CHANGED
@@ -1,21 +1,35 @@
1
- namespace :compile do
2
- task :parser do
3
- sh "racc -l -o lib/tp_plus/parser.rb generators/parser.y"
4
- end
5
-
6
- task :scanner do
7
- sh "rex generators/scanner.rex -o lib/tp_plus/scanner.rb --stub"
8
- end
9
- end
10
-
11
- task compile: ["compile:parser","compile:scanner"]
12
-
13
- require 'rake/testtask'
14
-
15
- Rake::TestTask.new do |t|
16
- t.libs << "test"
17
- t.test_files = FileList['test/**/test_*.rb']
18
- t.verbose = true
19
- end
20
-
21
- task default: :test
1
+ file "lib/tp_plus/parser.rb" => ["generators/parser.y"] do |t|
2
+ sh "racc -l -t -v -o lib/tp_plus/parser.rb generators/parser.y"
3
+ end
4
+
5
+ namespace :compile do
6
+ task :parser do
7
+ Rake::Task["lib/tp_plus/parser.rb"].invoke
8
+ end
9
+ end
10
+
11
+ task compile: ["compile:parser"]
12
+
13
+ require 'rake/testtask'
14
+
15
+ Rake::TestTask.new do |t|
16
+ # build the parser if necessary
17
+ Rake::Task["lib/tp_plus/parser.rb"].invoke
18
+
19
+ t.libs << "test"
20
+ t.test_files = FileList['test/**/test_*.rb']
21
+ t.verbose = true
22
+ end
23
+
24
+ task default: :test
25
+
26
+
27
+ desc "Run the TP+ benchmark"
28
+ task :benchmark do
29
+ ruby "./performance/benchmark.rb"
30
+ end
31
+
32
+ desc "Run the TP+ profiler"
33
+ task :profile do
34
+ ruby "./performance/profile.rb"
35
+ end
data/bin/tpp CHANGED
@@ -1,73 +1,73 @@
1
- #!/usr/bin/env ruby
2
- require 'tp_plus'
3
- require 'optparse'
4
-
5
- options = {}
6
- OptionParser.new do |opts|
7
- opts.banner = "Usage: tpp [options] filename"
8
-
9
- opts.on("-e", "--environment env_file.tpp", "Require an environment file before parsing files") do |e|
10
- options[:environment] = e
11
- end
12
-
13
- opts.on_tail("-h", "--help", "Show this message") do
14
- puts opts
15
- exit
16
- end
17
- end.parse!
18
-
19
- def contents(filename)
20
- if !File.exist?(filename)
21
- puts "File (#{filename}) does not exist"
22
- exit
23
- end
24
- f = File.open(filename,'rb')
25
- src = f.read
26
- f.close
27
- return src
28
- end
29
-
30
- scanner = TPPlus::Scanner.new
31
- parser = TPPlus::Parser.new(scanner)
32
- interpreter = parser.interpreter
33
- if options[:environment]
34
- interpreter.load_environment(contents(options[:environment]))
35
- end
36
-
37
- if ARGV.length != 1
38
- puts "Must provide filename argument. See tpp --help for details"
39
- exit
40
- end
41
-
42
- src = contents(ARGV[0])
43
-
44
- scanner.scan_setup(src)
45
- parser.parse
46
-
47
- lines = interpreter.eval
48
-
49
- tpp_filename = File.basename(ARGV[0],".*")
50
- output = %(/PROG #{tpp_filename.upcase}
51
- /ATTR
52
- COMMENT = "#{interpreter.header_data[:comment] || tpp_filename.upcase}";
53
- TCD: STACK_SIZE = 0,
54
- TASK_PRIORITY = 50,
55
- TIME_SLICE = 0,
56
- BUSY_LAMP_OFF = 0,
57
- ABORT_REQUEST = 0,
58
- PAUSE_REQUEST = #{interpreter.header_data[:ignore_pause] ? "7" : "0"};
59
- DEFAULT_GROUP = #{interpreter.header_data[:group_mask] || "1,*,*,*,*"};
60
- /MN\n)
61
-
62
- lines.each_line do |line|
63
- output += " : " + line
64
- end
65
-
66
- if interpreter.pos_section != ""
67
- output += "/POS\n"
68
- output += interpreter.pos_section
69
- end
70
-
71
- output += %(/END\n)
72
-
73
- print output
1
+ #!/usr/bin/env ruby
2
+ require 'tp_plus'
3
+ require 'optparse'
4
+
5
+ options = {}
6
+ OptionParser.new do |opts|
7
+ opts.banner = "Usage: tpp [options] filename"
8
+
9
+ opts.on("-e", "--environment env_file.tpp", "Require an environment file before parsing files") do |e|
10
+ options[:environment] = e
11
+ end
12
+
13
+ opts.on_tail("-h", "--help", "Show this message") do
14
+ puts opts
15
+ exit
16
+ end
17
+ end.parse!
18
+
19
+ def contents(filename)
20
+ if !File.exist?(filename)
21
+ puts "File (#{filename}) does not exist"
22
+ exit
23
+ end
24
+ f = File.open(filename,'rb')
25
+ src = f.read
26
+ f.close
27
+ return src
28
+ end
29
+
30
+ scanner = TPPlus::Scanner.new
31
+ parser = TPPlus::Parser.new(scanner)
32
+ interpreter = parser.interpreter
33
+ if options[:environment]
34
+ interpreter.load_environment(contents(options[:environment]))
35
+ end
36
+
37
+ if ARGV.length != 1
38
+ puts "Must provide filename argument. See tpp --help for details"
39
+ exit
40
+ end
41
+
42
+ src = contents(ARGV[0])
43
+
44
+ scanner.scan_setup(src)
45
+ parser.parse
46
+
47
+ lines = interpreter.eval
48
+
49
+ tpp_filename = File.basename(ARGV[0],".*")
50
+ output = %(/PROG #{tpp_filename.upcase}
51
+ /ATTR
52
+ COMMENT = "#{interpreter.header_data[:comment] || tpp_filename.upcase}";
53
+ TCD: STACK_SIZE = 0,
54
+ TASK_PRIORITY = 50,
55
+ TIME_SLICE = 0,
56
+ BUSY_LAMP_OFF = 0,
57
+ ABORT_REQUEST = 0,
58
+ PAUSE_REQUEST = #{interpreter.header_data[:ignore_pause] ? "7" : "0"};
59
+ DEFAULT_GROUP = #{interpreter.header_data[:group_mask] || "1,*,*,*,*"};
60
+ /MN\n)
61
+
62
+ lines.each_line do |line|
63
+ output += " : " + line
64
+ end
65
+
66
+ if interpreter.pos_section != ""
67
+ output += "/POS\n"
68
+ output += interpreter.pos_section
69
+ end
70
+
71
+ output += %(/END\n)
72
+
73
+ print output
@@ -1,129 +1,152 @@
1
- require 'tp_plus/parser'
2
-
3
- module TPPlus
4
- class Interpreter
5
- attr_accessor :line_count, :nodes, :position_data, :header_data
6
- attr_reader :labels, :variables, :constants, :namespaces, :source_line_count
7
- def initialize
8
- @line_count = 0
9
- @nodes = []
10
- @labels = {}
11
- @namespaces = {}
12
- @variables = {}
13
- @constants = {}
14
- @position_data = {}
15
- @header_data = {}
16
- @current_label = 99
17
- end
18
-
19
- def load_environment(string)
20
- scanner = TPPlus::Scanner.new
21
- parser = TPPlus::Parser.new(scanner, self)
22
- scanner.scan_setup(string)
23
- parser.parse
24
- eval
25
- rescue RuntimeError => e
26
- raise "Runtime error in environment on line #{@source_line_count}:\n#{e}"
27
- end
28
-
29
- def next_label
30
- @current_label += 1
31
- end
32
-
33
- def add_namespace(name, block)
34
- if @namespaces[name.to_sym].nil?
35
- @namespaces[name.to_sym] = TPPlus::Namespace.new(name, block)
36
- else
37
- @namespaces[name.to_sym].reopen!(block)
38
- end
39
- end
40
-
41
- def add_label(identifier)
42
- raise "Label @#{identifier} already defined" if @labels[identifier.to_sym]
43
- @labels[identifier.to_sym] = next_label
44
- end
45
-
46
- def add_var(identifier, node)
47
- raise "Variable #{identifier} already defined" if @variables[identifier.to_sym]
48
-
49
- @variables[identifier.to_sym] = node
50
- node.comment = identifier
51
- end
52
-
53
- def add_constant(identifier, node)
54
- raise "Constant #{identifier} already defined" if @constants[identifier.to_sym]
55
-
56
- @constants[identifier.to_sym] = node
57
- end
58
-
59
- def get_namespace(identifier)
60
- if ns = @namespaces[identifier.to_sym]
61
- return ns
62
- end
63
-
64
- false
65
- end
66
-
67
- def get_var(identifier)
68
- raise "Variable (#{identifier}) not defined" if @variables[identifier.to_sym].nil?
69
-
70
- @variables[identifier.to_sym]
71
- end
72
-
73
- def get_constant(identifier)
74
- raise "Constant (#{identifier}) not defined" if @constants[identifier.to_sym].nil?
75
-
76
- @constants[identifier.to_sym]
77
- end
78
-
79
- def define_labels
80
- @nodes.select {|n| n.is_a? Nodes::LabelDefinitionNode}.each do |n|
81
- add_label(n.identifier)
82
- end
83
- end
84
-
85
- def pos_section
86
- return "" if @position_data.empty?
87
- return "" if @position_data[:positions].empty?
88
-
89
- @position_data[:positions].inject("") do |s,p|
90
- s << %(P[#{p[:id]}:"#{p[:comment]}"]{
91
- GP#{p[:group]}:
92
- UF : #{p[:uframe]}, UT : #{p[:utool]}, CONFIG : '#{p[:config][:flip] ? 'F' : 'N'} #{p[:config][:up] ? 'U' : 'D'} #{p[:config][:top] ? 'T' : 'B'}, #{p[:config][:turn_counts].join(', ')}',
93
- X = #{p[:components][:x]} mm, Y = #{p[:components][:y]} mm, Z = #{p[:components][:z]} mm,
94
- W = #{p[:components][:w]} deg, P = #{p[:components][:p]} deg, R = #{p[:components][:r]} deg
95
- };\n)
96
- end
97
- end
98
-
99
- def eval
100
- s = ""
101
- last_node = nil
102
-
103
- define_labels
104
-
105
- @source_line_count = 0
106
-
107
- @nodes.each do |n|
108
- @source_line_count += 1 unless n.is_a?(Nodes::TerminatorNode) && !last_node.is_a?(Nodes::TerminatorNode)
109
- raise if n.is_a?(String)
110
-
111
- res = n.eval(self)
112
-
113
- # preserve whitespace
114
- if n.is_a?(Nodes::TerminatorNode) && last_node.is_a?(Nodes::TerminatorNode)
115
- s += " ;\n"
116
- end
117
- last_node = n
118
- # end preserve whitespace
119
-
120
- next if res.nil?
121
-
122
- s += "#{res} ;\n"
123
- end
124
- s
125
- rescue RuntimeError => e
126
- raise "Runtime error on line #{@source_line_count}:\n#{e}"
127
- end
128
- end
129
- end
1
+ require 'tp_plus/parser'
2
+
3
+ module TPPlus
4
+ class Interpreter
5
+ attr_accessor :line_count, :nodes, :position_data, :header_data
6
+ attr_reader :labels, :variables, :constants, :namespaces, :source_line_count
7
+ def initialize
8
+ @line_count = 0
9
+ @nodes = []
10
+ @labels = {}
11
+ @namespaces = {}
12
+ @variables = {}
13
+ @constants = {}
14
+ @position_data = {}
15
+ @header_data = {}
16
+ @current_label = 99
17
+ end
18
+
19
+ def load_environment(string)
20
+ scanner = TPPlus::Scanner.new
21
+ parser = TPPlus::Parser.new(scanner, self)
22
+ scanner.scan_setup(string)
23
+ parser.parse
24
+ eval
25
+ rescue RuntimeError => e
26
+ raise "Runtime error in environment on line #{@source_line_count}:\n#{e}"
27
+ end
28
+
29
+ def next_label
30
+ @current_label += 1
31
+ end
32
+
33
+ def add_namespace(name, block)
34
+ if @namespaces[name.to_sym].nil?
35
+ @namespaces[name.to_sym] = TPPlus::Namespace.new(name, block)
36
+ else
37
+ @namespaces[name.to_sym].reopen!(block)
38
+ end
39
+ end
40
+
41
+ def add_label(identifier)
42
+ raise "Label @#{identifier} already defined" if @labels[identifier.to_sym]
43
+ @labels[identifier.to_sym] = next_label
44
+ end
45
+
46
+ def add_var(identifier, node)
47
+ raise "Variable #{identifier} already defined" if @variables[identifier.to_sym]
48
+
49
+ @variables[identifier.to_sym] = node
50
+ node.comment = identifier
51
+ end
52
+
53
+ def add_constant(identifier, node)
54
+ raise "Constant #{identifier} already defined" if @constants[identifier.to_sym]
55
+
56
+ @constants[identifier.to_sym] = node
57
+ end
58
+
59
+ def get_namespace(identifier)
60
+ if ns = @namespaces[identifier.to_sym]
61
+ return ns
62
+ end
63
+
64
+ false
65
+ end
66
+
67
+ def get_var(identifier)
68
+ raise "Variable (#{identifier}) not defined" if @variables[identifier.to_sym].nil?
69
+
70
+ @variables[identifier.to_sym]
71
+ end
72
+
73
+ def get_constant(identifier)
74
+ raise "Constant (#{identifier}) not defined" if @constants[identifier.to_sym].nil?
75
+
76
+ @constants[identifier.to_sym]
77
+ end
78
+
79
+ def define_labels
80
+ @nodes.select {|n| n.is_a? Nodes::LabelDefinitionNode}.each do |n|
81
+ add_label(n.identifier)
82
+ end
83
+ end
84
+
85
+ def pos_section
86
+ return "" if @position_data.empty?
87
+ return "" if @position_data[:positions].empty?
88
+
89
+ @position_data[:positions].inject("") do |s,p|
90
+ s << %(P[#{p[:id]}:"#{p[:comment]}"]{\n)
91
+
92
+ p[:mask].each do |q|
93
+ s << pos_return(q)
94
+ end
95
+
96
+ s << %(\n};\n)
97
+ end
98
+ end
99
+
100
+ def pos_return(position_hash)
101
+ s = ""
102
+ if position_hash[:config].is_a?(Hash)
103
+ s << %( GP#{position_hash[:group]}:
104
+ UF : #{position_hash[:uframe]}, UT : #{position_hash[:utool]}, CONFIG : '#{position_hash[:config][:flip] ? 'F' : 'N'} #{position_hash[:config][:up] ? 'U' : 'D'} #{position_hash[:config][:top] ? 'T' : 'B'}, #{position_hash[:config][:turn_counts].join(', ')}',
105
+ X = #{position_hash[:components][:x]} mm, Y = #{position_hash[:components][:y]} mm, Z = #{position_hash[:components][:z]} mm,
106
+ W = #{position_hash[:components][:w]} deg, P = #{position_hash[:components][:p]} deg, R = #{position_hash[:components][:r]} deg)
107
+ else
108
+ s << %( GP#{position_hash[:group]}:
109
+ UF : #{position_hash[:uframe]}, UT : #{position_hash[:utool]})
110
+ if position_hash[:components].is_a?(Hash)
111
+ position_hash[:components].each_with_index do |key, joint|
112
+ s << %(, \n)
113
+ s << %(\tJ#{key} = #{joint[1]} deg)
114
+ end
115
+ s << %(\n)
116
+ end
117
+ end
118
+
119
+ return s
120
+ end
121
+
122
+ def eval
123
+ s = ""
124
+ last_node = nil
125
+
126
+ define_labels
127
+
128
+ @source_line_count = 0
129
+
130
+ @nodes.each do |n|
131
+ @source_line_count += 1 unless n.is_a?(Nodes::TerminatorNode) && !last_node.is_a?(Nodes::TerminatorNode)
132
+ raise if n.is_a?(String)
133
+
134
+ res = n.eval(self)
135
+
136
+ # preserve whitespace
137
+ if n.is_a?(Nodes::TerminatorNode) && last_node.is_a?(Nodes::TerminatorNode)
138
+ s += " ;\n"
139
+ end
140
+ last_node = n
141
+ # end preserve whitespace
142
+
143
+ next if res.nil?
144
+
145
+ s += "#{res} ;\n"
146
+ end
147
+ s
148
+ rescue RuntimeError => e
149
+ raise "Runtime error on line #{@source_line_count}:\n#{e}"
150
+ end
151
+ end
152
+ end