tp_plus 0.0.73

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 (67) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +65 -0
  3. data/Rakefile +21 -0
  4. data/bin/tpp +73 -0
  5. data/lib/tp_plus/interpreter.rb +129 -0
  6. data/lib/tp_plus/namespace.rb +66 -0
  7. data/lib/tp_plus/nodes/abort_node.rb +9 -0
  8. data/lib/tp_plus/nodes/argument_node.rb +19 -0
  9. data/lib/tp_plus/nodes/assignment_node.rb +45 -0
  10. data/lib/tp_plus/nodes/call_node.rb +34 -0
  11. data/lib/tp_plus/nodes/case_condition_node.rb +26 -0
  12. data/lib/tp_plus/nodes/case_node.rb +33 -0
  13. data/lib/tp_plus/nodes/comment_node.rb +22 -0
  14. data/lib/tp_plus/nodes/conditional_node.rb +54 -0
  15. data/lib/tp_plus/nodes/definition_node.rb +22 -0
  16. data/lib/tp_plus/nodes/digit_node.rb +21 -0
  17. data/lib/tp_plus/nodes/eval_node.rb +13 -0
  18. data/lib/tp_plus/nodes/expression_node.rb +65 -0
  19. data/lib/tp_plus/nodes/for_node.rb +20 -0
  20. data/lib/tp_plus/nodes/header_node.rb +27 -0
  21. data/lib/tp_plus/nodes/indirect_node.rb +49 -0
  22. data/lib/tp_plus/nodes/inline_conditional_node.rb +40 -0
  23. data/lib/tp_plus/nodes/io_method_node.rb +55 -0
  24. data/lib/tp_plus/nodes/io_node.rb +30 -0
  25. data/lib/tp_plus/nodes/jump_node.rb +23 -0
  26. data/lib/tp_plus/nodes/label_definition_node.rb +21 -0
  27. data/lib/tp_plus/nodes/motion_node.rb +62 -0
  28. data/lib/tp_plus/nodes/namespace_node.rb +16 -0
  29. data/lib/tp_plus/nodes/namespaced_var_node.rb +38 -0
  30. data/lib/tp_plus/nodes/numreg_node.rb +25 -0
  31. data/lib/tp_plus/nodes/offset_node.rb +27 -0
  32. data/lib/tp_plus/nodes/operator_node.rb +72 -0
  33. data/lib/tp_plus/nodes/pause_node.rb +9 -0
  34. data/lib/tp_plus/nodes/position_data_node.rb +50 -0
  35. data/lib/tp_plus/nodes/position_node.rb +25 -0
  36. data/lib/tp_plus/nodes/posreg_node.rb +48 -0
  37. data/lib/tp_plus/nodes/raise_node.rb +13 -0
  38. data/lib/tp_plus/nodes/real_node.rb +27 -0
  39. data/lib/tp_plus/nodes/set_node.rb +22 -0
  40. data/lib/tp_plus/nodes/skip_node.rb +22 -0
  41. data/lib/tp_plus/nodes/speed_node.rb +29 -0
  42. data/lib/tp_plus/nodes/string_node.rb +13 -0
  43. data/lib/tp_plus/nodes/string_register_node.rb +25 -0
  44. data/lib/tp_plus/nodes/termination_node.rb +18 -0
  45. data/lib/tp_plus/nodes/terminator_node.rb +16 -0
  46. data/lib/tp_plus/nodes/time_node.rb +24 -0
  47. data/lib/tp_plus/nodes/timer_method_node.rb +37 -0
  48. data/lib/tp_plus/nodes/timer_node.rb +21 -0
  49. data/lib/tp_plus/nodes/units_node.rb +20 -0
  50. data/lib/tp_plus/nodes/use_node.rb +21 -0
  51. data/lib/tp_plus/nodes/user_alarm_node.rb +15 -0
  52. data/lib/tp_plus/nodes/var_method_node.rb +23 -0
  53. data/lib/tp_plus/nodes/var_node.rb +39 -0
  54. data/lib/tp_plus/nodes/vision_register_node.rb +21 -0
  55. data/lib/tp_plus/nodes/wait_for_node.rb +54 -0
  56. data/lib/tp_plus/nodes/wait_until_node.rb +65 -0
  57. data/lib/tp_plus/nodes/while_node.rb +36 -0
  58. data/lib/tp_plus/parser.rb +1592 -0
  59. data/lib/tp_plus/scanner.rb +383 -0
  60. data/lib/tp_plus/version.rb +3 -0
  61. data/lib/tp_plus.rb +62 -0
  62. data/test/test_helper.rb +5 -0
  63. data/test/tp_plus/test_interpreter.rb +1168 -0
  64. data/test/tp_plus/test_parser.rb +489 -0
  65. data/test/tp_plus/test_scanner.rb +522 -0
  66. data/tp_plus.gemspec +28 -0
  67. metadata +156 -0
@@ -0,0 +1,48 @@
1
+ module TPPlus
2
+ module Nodes
3
+ class PosregNode
4
+
5
+ COMPONENTS = {
6
+ "x" => 1,
7
+ "y" => 2,
8
+ "z" => 3,
9
+ "w" => 4,
10
+ "p" => 5,
11
+ "r" => 6
12
+ }
13
+
14
+ attr_accessor :comment
15
+ def initialize(id)
16
+ @id = id
17
+ @comment = ""
18
+ end
19
+
20
+ def comment_string
21
+ return "" if @comment == ""
22
+
23
+ ":#{@comment}"
24
+ end
25
+
26
+ def component(m)
27
+ return "" if m == ""
28
+
29
+ ",#{COMPONENTS[m]}"
30
+ end
31
+
32
+ def component_valid?(c)
33
+ [""].concat(COMPONENTS.keys).include? c
34
+ end
35
+
36
+ def requires_mixed_logic?(context)
37
+ false
38
+ end
39
+
40
+ def eval(context,options={})
41
+ options[:method] ||= ""
42
+ raise "Invalid component" unless component_valid?(options[:method])
43
+
44
+ "PR[#{@id}#{component(options[:method])}#{comment_string}]"
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,13 @@
1
+ module TPPlus
2
+ module Nodes
3
+ class RaiseNode
4
+ def initialize(target)
5
+ @target = target
6
+ end
7
+
8
+ def eval(context, options={})
9
+ "#{@target.eval(context)}"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,27 @@
1
+ module TPPlus
2
+ module Nodes
3
+ class RealNode
4
+ def initialize(value)
5
+ @value = value
6
+ end
7
+
8
+ def requires_mixed_logic?(context)
9
+ false
10
+ end
11
+
12
+ def eval(context,options={})
13
+ val = if options[:as_string]
14
+ ("%.2f" % @value).sub(/^0/,'')
15
+ else
16
+ @value
17
+ end
18
+
19
+ if @value < 0
20
+ "(#{val})"
21
+ else
22
+ val
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,22 @@
1
+ module TPPlus
2
+ module Nodes
3
+ class SetNode
4
+ def initialize(type, target, value)
5
+ @type = type
6
+ @target = target
7
+ @value = value
8
+ end
9
+
10
+ def eval(context)
11
+ case @type
12
+ when "set_uframe"
13
+ "UFRAME[#{@target.eval(context)}]=#{@value.eval(context)}"
14
+ when "set_skip_condition"
15
+ "SKIP CONDITION #{@value.eval(context, disable_mixed_logic: true)}"
16
+ else
17
+ raise "Unsupported FANUC setter"
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ module TPPlus
2
+ module Nodes
3
+ class SkipNode
4
+ def initialize(target, lpos_pr)
5
+ @target = target
6
+ @lpos_pr = lpos_pr
7
+ end
8
+
9
+ def lpos_pr(context)
10
+ return "" if @lpos_pr.nil?
11
+
12
+ ",#{@lpos_pr.eval(context)}=LPOS"
13
+ end
14
+
15
+ def eval(context)
16
+ raise "Label (#{@target}) not found" if context.labels[@target.to_sym].nil?
17
+
18
+ "Skip,LBL[#{context.labels[@target.to_sym]}]#{lpos_pr(context)}"
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,29 @@
1
+ module TPPlus
2
+ module Nodes
3
+ class SpeedNode
4
+ def initialize(speed_hash)
5
+ @speed_hash = speed_hash
6
+ end
7
+
8
+ def speed(context)
9
+ @speed_hash[:speed].eval(context)
10
+ end
11
+
12
+ def units
13
+ case @speed_hash[:units]
14
+ when "mm/s"
15
+ "mm/sec"
16
+ else
17
+ @speed_hash[:units]
18
+ end
19
+ end
20
+
21
+
22
+ def eval(context)
23
+ return @speed_hash[:speed] if @speed_hash[:units].nil?
24
+
25
+ "#{speed(context)}#{units}"
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,13 @@
1
+ module TPPlus
2
+ module Nodes
3
+ class StringNode
4
+ def initialize(s)
5
+ @s = s
6
+ end
7
+
8
+ def eval(context)
9
+ "'#{@s}'"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,25 @@
1
+ module TPPlus
2
+ module Nodes
3
+ class StringRegisterNode
4
+ attr_accessor :comment
5
+ def initialize(id)
6
+ @id = id
7
+ @comment = ""
8
+ end
9
+
10
+ def requires_mixed_logic?(context)
11
+ false
12
+ end
13
+
14
+ def comment_string
15
+ return "" if @comment == ""
16
+
17
+ ":#{@comment}"
18
+ end
19
+
20
+ def eval(context,options={})
21
+ "SR[#{@id}#{comment_string}]"
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,18 @@
1
+ module TPPlus
2
+ module Nodes
3
+ class TerminationNode
4
+ def initialize(value)
5
+ @value = value
6
+ end
7
+
8
+ def eval(context)
9
+ if @value.is_a? DigitNode
10
+ "CNT#{@value.eval(context)}"
11
+ else
12
+ # for registers
13
+ "CNT #{@value.eval(context)}"
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,16 @@
1
+ module TPPlus
2
+ module Nodes
3
+ class TerminatorNode
4
+ def eval(context)
5
+ nil
6
+ end
7
+ end
8
+ end
9
+ end
10
+
11
+ # IF R[1:foo]<>1,JMP LBL[100] ;
12
+ # R[1:foo]=2 ;
13
+ # JMP LBL[101] ;
14
+ # LBL[100] ;
15
+ # R[1:foo]=1 ;
16
+ # LBL[101] ;
@@ -0,0 +1,24 @@
1
+ module TPPlus
2
+ module Nodes
3
+ class TimeNode
4
+ def initialize(type, time, action)
5
+ @type = type
6
+ @time = time
7
+ @action = action
8
+ end
9
+
10
+ def type
11
+ case @type.downcase
12
+ when "time_before"
13
+ "TB"
14
+ when "time_after"
15
+ "TA"
16
+ end
17
+ end
18
+
19
+ def eval(context)
20
+ "#{type} #{@time.eval(context,as_string: true)}sec,#{@action.eval(context)}"
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,37 @@
1
+ module TPPlus
2
+ module Nodes
3
+ class TimerMethodNode
4
+ def initialize(method, target)
5
+ @method = method
6
+ @target = target
7
+ end
8
+
9
+ def requires_mixed_logic?(context)
10
+ true
11
+ end
12
+
13
+ def can_be_inlined?
14
+ false
15
+ end
16
+
17
+ def timer(context)
18
+ @timer ||= @target.eval(context)
19
+ end
20
+
21
+ def eval(context,options={})
22
+ case @method
23
+ when :start
24
+ "#{timer(context)}=START"
25
+ when :stop
26
+ "#{timer(context)}=STOP"
27
+ when :reset
28
+ "#{timer(context)}=RESET"
29
+ when :restart
30
+ "#{timer(context)}=STOP ;\n#{timer(context)}=RESET ;\n#{timer(context)}=START"
31
+ else
32
+ raise "Invalid timer method (#{@method})"
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,21 @@
1
+ module TPPlus
2
+ module Nodes
3
+ class TimerNode
4
+ attr_accessor :comment
5
+ def initialize(id)
6
+ @id = id
7
+ @comment = ""
8
+ end
9
+
10
+ def comment_string
11
+ return "" if @comment == ""
12
+
13
+ ":#{comment}"
14
+ end
15
+
16
+ def eval(context, options={})
17
+ "TIMER[#{@id}#{comment_string}]"
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,20 @@
1
+ module TPPlus
2
+ module Nodes
3
+ class UnitsNode
4
+ def initialize(s)
5
+ @s = s
6
+ end
7
+
8
+ def eval(context)
9
+ case @s
10
+ when "mm/s"
11
+ "mm/sec"
12
+ when "%"
13
+ "%"
14
+ else
15
+ raise "Unknown unit: #{@s}"
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,21 @@
1
+ module TPPlus
2
+ module Nodes
3
+ class UseNode
4
+ def initialize(type, value)
5
+ @type = type
6
+ @value = value
7
+ end
8
+
9
+ def eval(context)
10
+ case @type
11
+ when "use_uframe"
12
+ "UFRAME_NUM=#{@value.eval(context)}"
13
+ when "use_utool"
14
+ "UTOOL_NUM=#{@value.eval(context)}"
15
+ when "use_payload"
16
+ "PAYLOAD[#{@value.eval(context)}]"
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,15 @@
1
+ module TPPlus
2
+ module Nodes
3
+ class UserAlarmNode
4
+ attr_accessor :comment
5
+ def initialize(id)
6
+ @id = id
7
+ @comment = ""
8
+ end
9
+
10
+ def eval(context, options={})
11
+ "UALM[#{@id}]"
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,23 @@
1
+ module TPPlus
2
+ module Nodes
3
+ class VarMethodNode
4
+ attr_reader :identifier
5
+ def initialize(identifier, method)
6
+ @identifier = identifier
7
+ @method = method
8
+ end
9
+
10
+ def requires_mixed_logic?(context)
11
+ node(context).requires_mixed_logic?(context)
12
+ end
13
+
14
+ def node(context)
15
+ context.get_var(@identifier)
16
+ end
17
+
18
+ def eval(context,options={})
19
+ node(context).eval(context,options.merge(method:@method))
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,39 @@
1
+ module TPPlus
2
+ module Nodes
3
+ class VarNode
4
+ attr_reader :identifier
5
+ def initialize(identifier)
6
+ @identifier = identifier
7
+ end
8
+
9
+ def target_node(context)
10
+ constant? ? context.get_constant(@identifier) : context.get_var(@identifier)
11
+ end
12
+
13
+ def constant?
14
+ @identifier.upcase == @identifier
15
+ end
16
+
17
+ def requires_mixed_logic?(context)
18
+ target_node(context).requires_mixed_logic?(context)
19
+ end
20
+
21
+ def with_parens(s, options)
22
+ return s unless options[:as_condition]
23
+
24
+ "(#{s})"
25
+ end
26
+
27
+ def eval(context,options={})
28
+ return target_node(context).eval(context) if constant?
29
+
30
+ s = ""
31
+ if options[:opposite]
32
+ s += "!"
33
+ end
34
+
35
+ with_parens(s + target_node(context).eval(context, options), options)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,21 @@
1
+ module TPPlus
2
+ module Nodes
3
+ class VisionRegisterNode
4
+ attr_accessor :comment
5
+ def initialize(id)
6
+ @id = id
7
+ @comment = ""
8
+ end
9
+
10
+ def comment_string
11
+ return "" if @comment == ""
12
+
13
+ ":#{@comment}"
14
+ end
15
+
16
+ def eval(context,options={})
17
+ "VR[#{@id}#{comment_string}]"
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,54 @@
1
+ module TPPlus
2
+ module Nodes
3
+ class WaitForNode
4
+ def initialize(time, units)
5
+ @time = time
6
+ @units = units
7
+ end
8
+
9
+ def units_valid?
10
+ ["s","ms"].include?(@units)
11
+ end
12
+
13
+ # 2 decimal places and remove leading 0s
14
+ def time(context)
15
+ if @time.eval(context).is_a?(String)
16
+ case @units
17
+ when "s"
18
+ @time.eval(context)
19
+ else
20
+ raise "Invalid units"
21
+ end
22
+ else
23
+ ("%.2f" % case @units
24
+ when "s"
25
+ @time.eval(context)
26
+ when "ms"
27
+ @time.eval(context).to_f / 1000
28
+ end).sub(/^0+/, "") + "(sec)"
29
+ end
30
+ end
31
+
32
+ def can_be_inlined?
33
+ false
34
+ end
35
+
36
+ def expression
37
+ case @units
38
+ when "s"
39
+ @time
40
+ when "ms"
41
+ e = ExpressionNode.new(@time,"/",DigitNode.new(1000))
42
+ e.grouped = true
43
+ e
44
+ end
45
+ end
46
+
47
+ def eval(context)
48
+ raise "Invalid units" unless units_valid?
49
+
50
+ "WAIT #{time(context)}"
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,65 @@
1
+ module TPPlus
2
+ module Nodes
3
+ class WaitUntilNode
4
+ def initialize(expression, timeout_options)
5
+ @expression = expression
6
+ @timeout_options = timeout_options || {}
7
+ end
8
+
9
+ def timeout(context)
10
+ return "" if @timeout_options[:label].nil?
11
+
12
+ " TIMEOUT,LBL[#{context.labels[@timeout_options[:label].to_sym]}]"
13
+ end
14
+
15
+ def val(context)
16
+ value_node = @timeout_options[:timeout][0]
17
+ units = @timeout_options[:timeout][1]
18
+
19
+ if value_node.is_a?(VarNode)
20
+ value = value_node.eval(context)
21
+
22
+ case units
23
+ when "s"
24
+ value = "#{value}*100"
25
+ when "ms"
26
+ value = "#{value}*.1"
27
+ else
28
+ raise "invalid units"
29
+ end
30
+ else
31
+ value = value_node.eval(context).to_i
32
+
33
+ case units
34
+ when "s"
35
+ value = (value * 100).to_i
36
+ when "ms"
37
+ value = (value * 0.1).to_i
38
+ else
39
+ raise "invalid units"
40
+ end
41
+ end
42
+
43
+ value
44
+ end
45
+
46
+ def can_be_inlined?
47
+ false
48
+ end
49
+
50
+ def wait_timeout(context)
51
+ return "" if @timeout_options[:timeout].nil?
52
+
53
+ "$WAITTMOUT=(#{val(context)}) ;\n"
54
+ end
55
+
56
+ def string_value(context)
57
+ "#{@expression.eval(context, force_parens: true)}"
58
+ end
59
+
60
+ def eval(context)
61
+ "#{wait_timeout(context)}WAIT #{string_value(context)}#{timeout(context)}"
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,36 @@
1
+ module TPPlus
2
+ module Nodes
3
+ class WhileNode
4
+ def initialize(condition_node, block)
5
+ @condition_node = condition_node
6
+ @block = block.flatten.reject {|n| n.is_a?(TerminatorNode) }
7
+ end
8
+
9
+ def top_label(context)
10
+ @top_label ||= context.next_label
11
+ end
12
+
13
+ def bottom_label(context)
14
+ @bottom_label ||= context.next_label
15
+ end
16
+
17
+ def if_statement(context)
18
+ "IF #{condition(context)},JMP LBL[#{bottom_label(context)}] ;\n"
19
+ end
20
+
21
+
22
+ def condition(context)
23
+ @condition_node.eval(context, opposite: true, as_condition: true)
24
+ end
25
+
26
+
27
+ def block(context)
28
+ @block.inject("") {|s,n| s << "#{n.eval(context)} ;\n" }
29
+ end
30
+
31
+ def eval(context)
32
+ "LBL[#{top_label(context)}] ;\n#{if_statement(context)}#{block(context)}JMP LBL[#{top_label(context)}] ;\nLBL[#{bottom_label(context)}]"
33
+ end
34
+ end
35
+ end
36
+ end