tp_plus 0.0.73 → 0.0.74
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/README.md +74 -65
- data/Rakefile +35 -21
- data/bin/tpp +73 -73
- data/lib/tp_plus/interpreter.rb +152 -129
- data/lib/tp_plus/namespace.rb +66 -66
- data/lib/tp_plus/nodes/abort_node.rb +9 -9
- data/lib/tp_plus/nodes/address_node.rb +22 -0
- data/lib/tp_plus/nodes/argument_node.rb +20 -19
- data/lib/tp_plus/nodes/assignment_node.rb +45 -45
- data/lib/tp_plus/nodes/call_node.rb +34 -34
- data/lib/tp_plus/nodes/case_condition_node.rb +26 -26
- data/lib/tp_plus/nodes/case_node.rb +33 -33
- data/lib/tp_plus/nodes/comment_node.rb +22 -22
- data/lib/tp_plus/nodes/conditional_node.rb +60 -54
- data/lib/tp_plus/nodes/definition_node.rb +22 -22
- data/lib/tp_plus/nodes/digit_node.rb +22 -21
- data/lib/tp_plus/nodes/empty_stmt_node.rb +9 -0
- data/lib/tp_plus/nodes/eval_node.rb +13 -13
- data/lib/tp_plus/nodes/expression_node.rb +68 -65
- data/lib/tp_plus/nodes/for_node.rb +20 -20
- data/lib/tp_plus/nodes/header_node.rb +27 -27
- data/lib/tp_plus/nodes/indirect_node.rb +51 -49
- data/lib/tp_plus/nodes/inline_conditional_node.rb +40 -40
- data/lib/tp_plus/nodes/io_method_node.rb +55 -55
- data/lib/tp_plus/nodes/io_node.rb +31 -30
- data/lib/tp_plus/nodes/jump_node.rb +23 -23
- data/lib/tp_plus/nodes/label_definition_node.rb +21 -21
- data/lib/tp_plus/nodes/motion_node.rb +62 -62
- data/lib/tp_plus/nodes/namespace_node.rb +16 -16
- data/lib/tp_plus/nodes/namespaced_var_node.rb +38 -38
- data/lib/tp_plus/nodes/numreg_node.rb +26 -25
- data/lib/tp_plus/nodes/offset_node.rb +27 -27
- data/lib/tp_plus/nodes/operator_node.rb +78 -72
- data/lib/tp_plus/nodes/paren_expression_node.rb +17 -0
- data/lib/tp_plus/nodes/pause_node.rb +9 -9
- data/lib/tp_plus/nodes/position_data_node.rb +64 -50
- data/lib/tp_plus/nodes/position_node.rb +26 -25
- data/lib/tp_plus/nodes/posreg_node.rb +64 -48
- data/lib/tp_plus/nodes/raise_node.rb +13 -13
- data/lib/tp_plus/nodes/real_node.rb +27 -27
- data/lib/tp_plus/nodes/set_skip_node.rb +14 -0
- data/lib/tp_plus/nodes/skip_node.rb +22 -22
- data/lib/tp_plus/nodes/speed_node.rb +29 -29
- data/lib/tp_plus/nodes/string_node.rb +13 -13
- data/lib/tp_plus/nodes/string_register_node.rb +26 -25
- data/lib/tp_plus/nodes/termination_node.rb +23 -18
- data/lib/tp_plus/nodes/terminator_node.rb +16 -16
- data/lib/tp_plus/nodes/time_node.rb +24 -24
- data/lib/tp_plus/nodes/timer_method_node.rb +37 -37
- data/lib/tp_plus/nodes/timer_node.rb +16 -21
- data/lib/tp_plus/nodes/units_node.rb +20 -20
- data/lib/tp_plus/nodes/use_node.rb +21 -21
- data/lib/tp_plus/nodes/user_alarm_node.rb +16 -15
- data/lib/tp_plus/nodes/var_method_node.rb +23 -23
- data/lib/tp_plus/nodes/var_node.rb +39 -39
- data/lib/tp_plus/nodes/vision_register_node.rb +22 -21
- data/lib/tp_plus/nodes/wait_for_node.rb +54 -54
- data/lib/tp_plus/nodes/wait_until_node.rb +65 -65
- data/lib/tp_plus/nodes/while_node.rb +42 -36
- data/lib/tp_plus/parser.rb +1682 -1592
- data/lib/tp_plus/scanner.rb +283 -383
- data/lib/tp_plus/token.rb +97 -0
- data/lib/tp_plus/version.rb +3 -3
- data/lib/tp_plus.rb +66 -62
- data/test/test_helper.rb +5 -5
- data/test/tp_plus/test_interpreter.rb +1309 -1168
- data/test/tp_plus/test_parser.rb +496 -489
- data/test/tp_plus/test_scanner.rb +577 -522
- data/tp_plus.gemspec +31 -28
- metadata +61 -14
- data/lib/tp_plus/nodes/set_node.rb +0 -22
data/lib/tp_plus/namespace.rb
CHANGED
@@ -1,66 +1,66 @@
|
|
1
|
-
module TPPlus
|
2
|
-
class Namespace
|
3
|
-
def initialize(name, block)
|
4
|
-
@name = name
|
5
|
-
@block = block
|
6
|
-
@namespaces = {}
|
7
|
-
@variables = {}
|
8
|
-
@constants = {}
|
9
|
-
|
10
|
-
define!
|
11
|
-
end
|
12
|
-
|
13
|
-
def define!
|
14
|
-
@block.flatten.select {|n| [TPPlus::Nodes::DefinitionNode, TPPlus::Nodes::NamespaceNode].include? n.class }.each do |node|
|
15
|
-
node.eval(self)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def reopen!(block)
|
20
|
-
@block = block
|
21
|
-
define!
|
22
|
-
end
|
23
|
-
|
24
|
-
def add_constant(identifier, node)
|
25
|
-
raise "Constant (#{identifier}) already defined within namespace #{@name}" unless @constants[identifier.to_sym].nil?
|
26
|
-
|
27
|
-
@constants[identifier.to_sym] = node
|
28
|
-
end
|
29
|
-
|
30
|
-
def add_namespace(identifier, block)
|
31
|
-
if @namespaces[identifier.to_sym].nil?
|
32
|
-
@namespaces[identifier.to_sym] = TPPlus::Namespace.new("#{@name} #{identifier}", block)
|
33
|
-
else
|
34
|
-
@namespaces[identifier.to_sym].reopen!(block)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def add_var(identifier, node)
|
39
|
-
raise "Variable (#{identifier}) already defined within namespace #{@name}" unless @variables[identifier.to_sym].nil?
|
40
|
-
|
41
|
-
@variables[identifier.to_sym] = node
|
42
|
-
node.comment = "#{@name} #{identifier}"
|
43
|
-
end
|
44
|
-
|
45
|
-
def get_constant(identifier)
|
46
|
-
raise "Constant (#{identifier}) not defined within namespace #{@name}" if @constants[identifier.to_sym].nil?
|
47
|
-
|
48
|
-
@constants[identifier.to_sym]
|
49
|
-
end
|
50
|
-
|
51
|
-
def get_var(identifier)
|
52
|
-
return get_constant(identifier) if identifier.upcase == identifier
|
53
|
-
raise "Variable (#{identifier}) not defined within namespace #{@name}" if @variables[identifier.to_sym].nil?
|
54
|
-
|
55
|
-
@variables[identifier.to_sym]
|
56
|
-
end
|
57
|
-
|
58
|
-
def get_namespace(identifier)
|
59
|
-
if ns = @namespaces[identifier.to_sym]
|
60
|
-
return ns
|
61
|
-
end
|
62
|
-
|
63
|
-
false
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
1
|
+
module TPPlus
|
2
|
+
class Namespace
|
3
|
+
def initialize(name, block)
|
4
|
+
@name = name
|
5
|
+
@block = block
|
6
|
+
@namespaces = {}
|
7
|
+
@variables = {}
|
8
|
+
@constants = {}
|
9
|
+
|
10
|
+
define!
|
11
|
+
end
|
12
|
+
|
13
|
+
def define!
|
14
|
+
@block.flatten.select {|n| [TPPlus::Nodes::DefinitionNode, TPPlus::Nodes::NamespaceNode].include? n.class }.each do |node|
|
15
|
+
node.eval(self)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def reopen!(block)
|
20
|
+
@block = block
|
21
|
+
define!
|
22
|
+
end
|
23
|
+
|
24
|
+
def add_constant(identifier, node)
|
25
|
+
raise "Constant (#{identifier}) already defined within namespace #{@name}" unless @constants[identifier.to_sym].nil?
|
26
|
+
|
27
|
+
@constants[identifier.to_sym] = node
|
28
|
+
end
|
29
|
+
|
30
|
+
def add_namespace(identifier, block)
|
31
|
+
if @namespaces[identifier.to_sym].nil?
|
32
|
+
@namespaces[identifier.to_sym] = TPPlus::Namespace.new("#{@name} #{identifier}", block)
|
33
|
+
else
|
34
|
+
@namespaces[identifier.to_sym].reopen!(block)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def add_var(identifier, node)
|
39
|
+
raise "Variable (#{identifier}) already defined within namespace #{@name}" unless @variables[identifier.to_sym].nil?
|
40
|
+
|
41
|
+
@variables[identifier.to_sym] = node
|
42
|
+
node.comment = "#{@name} #{identifier}"
|
43
|
+
end
|
44
|
+
|
45
|
+
def get_constant(identifier)
|
46
|
+
raise "Constant (#{identifier}) not defined within namespace #{@name}" if @constants[identifier.to_sym].nil?
|
47
|
+
|
48
|
+
@constants[identifier.to_sym]
|
49
|
+
end
|
50
|
+
|
51
|
+
def get_var(identifier)
|
52
|
+
return get_constant(identifier) if identifier.upcase == identifier
|
53
|
+
raise "Variable (#{identifier}) not defined within namespace #{@name}" if @variables[identifier.to_sym].nil?
|
54
|
+
|
55
|
+
@variables[identifier.to_sym]
|
56
|
+
end
|
57
|
+
|
58
|
+
def get_namespace(identifier)
|
59
|
+
if ns = @namespaces[identifier.to_sym]
|
60
|
+
return ns
|
61
|
+
end
|
62
|
+
|
63
|
+
false
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -1,9 +1,9 @@
|
|
1
|
-
module TPPlus
|
2
|
-
module Nodes
|
3
|
-
class AbortNode
|
4
|
-
def eval(context)
|
5
|
-
"ABORT"
|
6
|
-
end
|
7
|
-
end
|
8
|
-
end
|
9
|
-
end
|
1
|
+
module TPPlus
|
2
|
+
module Nodes
|
3
|
+
class AbortNode
|
4
|
+
def eval(context)
|
5
|
+
"ABORT"
|
6
|
+
end
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module TPPlus
|
2
|
+
module Nodes
|
3
|
+
class AddressNode
|
4
|
+
attr_reader :id
|
5
|
+
def initialize(id)
|
6
|
+
@id = id
|
7
|
+
end
|
8
|
+
|
9
|
+
def requires_mixed_logic?(context)
|
10
|
+
false
|
11
|
+
end
|
12
|
+
|
13
|
+
def node(context)
|
14
|
+
context.get_var(@id)
|
15
|
+
end
|
16
|
+
|
17
|
+
def eval(context,options={})
|
18
|
+
node(context).id.to_s
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -1,19 +1,20 @@
|
|
1
|
-
module TPPlus
|
2
|
-
module Nodes
|
3
|
-
class ArgumentNode
|
4
|
-
attr_accessor :comment
|
5
|
-
|
6
|
-
|
7
|
-
@
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
end
|
1
|
+
module TPPlus
|
2
|
+
module Nodes
|
3
|
+
class ArgumentNode
|
4
|
+
attr_accessor :comment
|
5
|
+
attr_reader :id
|
6
|
+
def initialize(id)
|
7
|
+
@id = id
|
8
|
+
@comment = comment
|
9
|
+
end
|
10
|
+
|
11
|
+
def requires_mixed_logic?(context)
|
12
|
+
true
|
13
|
+
end
|
14
|
+
|
15
|
+
def eval(context,options={})
|
16
|
+
"AR[#{@id}]"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -1,45 +1,45 @@
|
|
1
|
-
module TPPlus
|
2
|
-
module Nodes
|
3
|
-
class AssignmentNode
|
4
|
-
attr_reader :identifier, :assignable
|
5
|
-
def initialize(identifier,assignable)
|
6
|
-
@identifier = identifier
|
7
|
-
@assignable = assignable
|
8
|
-
end
|
9
|
-
|
10
|
-
def assignable_string(context,options={})
|
11
|
-
if @assignable.is_a?(ExpressionNode)
|
12
|
-
options[:mixed_logic] = true if @assignable.contains_expression?
|
13
|
-
options[:mixed_logic] = true if @assignable.op.requires_mixed_logic?(context)
|
14
|
-
options[:mixed_logic] = true if @assignable.op.boolean?
|
15
|
-
options[:mixed_logic] = true if @assignable.boolean_result?
|
16
|
-
else
|
17
|
-
options[:mixed_logic] = true if @assignable.requires_mixed_logic?(context)
|
18
|
-
options[:mixed_logic] = true if @identifier.requires_mixed_logic?(context)
|
19
|
-
end
|
20
|
-
|
21
|
-
if options[:mixed_logic]
|
22
|
-
"(#{@assignable.eval(context)})"
|
23
|
-
else
|
24
|
-
@assignable.eval(context)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def requires_mixed_logic?(context)
|
29
|
-
true
|
30
|
-
end
|
31
|
-
|
32
|
-
def can_be_inlined?
|
33
|
-
true
|
34
|
-
end
|
35
|
-
|
36
|
-
def identifier_string(context)
|
37
|
-
@identifier.eval(context)
|
38
|
-
end
|
39
|
-
|
40
|
-
def eval(context,options={})
|
41
|
-
"#{identifier_string(context)}=#{assignable_string(context,options)}"
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
1
|
+
module TPPlus
|
2
|
+
module Nodes
|
3
|
+
class AssignmentNode
|
4
|
+
attr_reader :identifier, :assignable
|
5
|
+
def initialize(identifier,assignable)
|
6
|
+
@identifier = identifier
|
7
|
+
@assignable = assignable
|
8
|
+
end
|
9
|
+
|
10
|
+
def assignable_string(context,options={})
|
11
|
+
if @assignable.is_a?(ExpressionNode)
|
12
|
+
options[:mixed_logic] = true if @assignable.contains_expression?
|
13
|
+
options[:mixed_logic] = true if @assignable.op.requires_mixed_logic?(context)
|
14
|
+
options[:mixed_logic] = true if @assignable.op.boolean?
|
15
|
+
options[:mixed_logic] = true if @assignable.boolean_result?
|
16
|
+
else
|
17
|
+
options[:mixed_logic] = true if @assignable.requires_mixed_logic?(context)
|
18
|
+
options[:mixed_logic] = true if @identifier.requires_mixed_logic?(context)
|
19
|
+
end
|
20
|
+
|
21
|
+
if options[:mixed_logic]
|
22
|
+
"(#{@assignable.eval(context)})"
|
23
|
+
else
|
24
|
+
@assignable.eval(context)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def requires_mixed_logic?(context)
|
29
|
+
true
|
30
|
+
end
|
31
|
+
|
32
|
+
def can_be_inlined?
|
33
|
+
true
|
34
|
+
end
|
35
|
+
|
36
|
+
def identifier_string(context)
|
37
|
+
@identifier.eval(context)
|
38
|
+
end
|
39
|
+
|
40
|
+
def eval(context,options={})
|
41
|
+
"#{identifier_string(context)}=#{assignable_string(context,options)}"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -1,34 +1,34 @@
|
|
1
|
-
module TPPlus
|
2
|
-
module Nodes
|
3
|
-
class CallNode
|
4
|
-
attr_reader :args
|
5
|
-
def initialize(program_name, args, options={})
|
6
|
-
@program_name = program_name
|
7
|
-
@args = args
|
8
|
-
@async = options[:async]
|
9
|
-
end
|
10
|
-
|
11
|
-
def requires_mixed_logic?(context)
|
12
|
-
false
|
13
|
-
end
|
14
|
-
|
15
|
-
def async?
|
16
|
-
@async
|
17
|
-
end
|
18
|
-
|
19
|
-
def args_string(context)
|
20
|
-
return "" unless @args.any?
|
21
|
-
|
22
|
-
"(" + @args.map {|a| a.eval(context) }.join(",") + ")"
|
23
|
-
end
|
24
|
-
|
25
|
-
def can_be_inlined?
|
26
|
-
true
|
27
|
-
end
|
28
|
-
|
29
|
-
def eval(context,options={})
|
30
|
-
"#{async? ? "RUN" : "CALL"} #{@program_name.upcase}#{args_string(context)}"
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
1
|
+
module TPPlus
|
2
|
+
module Nodes
|
3
|
+
class CallNode
|
4
|
+
attr_reader :args
|
5
|
+
def initialize(program_name, args, options={})
|
6
|
+
@program_name = program_name
|
7
|
+
@args = args
|
8
|
+
@async = options[:async]
|
9
|
+
end
|
10
|
+
|
11
|
+
def requires_mixed_logic?(context)
|
12
|
+
false
|
13
|
+
end
|
14
|
+
|
15
|
+
def async?
|
16
|
+
@async
|
17
|
+
end
|
18
|
+
|
19
|
+
def args_string(context)
|
20
|
+
return "" unless @args.any?
|
21
|
+
|
22
|
+
"(" + @args.map {|a| a.eval(context) }.join(",") + ")"
|
23
|
+
end
|
24
|
+
|
25
|
+
def can_be_inlined?
|
26
|
+
true
|
27
|
+
end
|
28
|
+
|
29
|
+
def eval(context,options={})
|
30
|
+
"#{async? ? "RUN" : "CALL"} #{@program_name.upcase}#{args_string(context)}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -1,26 +1,26 @@
|
|
1
|
-
module TPPlus
|
2
|
-
module Nodes
|
3
|
-
class CaseConditionNode
|
4
|
-
def initialize(condition, block)
|
5
|
-
@condition = condition
|
6
|
-
@block = block
|
7
|
-
end
|
8
|
-
|
9
|
-
def eval(context, options={})
|
10
|
-
options[:no_indent] ||= false
|
11
|
-
|
12
|
-
s = ""
|
13
|
-
if !options[:no_indent]
|
14
|
-
s += " "
|
15
|
-
end
|
16
|
-
|
17
|
-
if @condition
|
18
|
-
s += "=#{@condition.eval(context)},#{@block.eval(context)}"
|
19
|
-
else
|
20
|
-
s += "ELSE,#{@block.eval(context)}"
|
21
|
-
end
|
22
|
-
s
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
1
|
+
module TPPlus
|
2
|
+
module Nodes
|
3
|
+
class CaseConditionNode
|
4
|
+
def initialize(condition, block)
|
5
|
+
@condition = condition
|
6
|
+
@block = block
|
7
|
+
end
|
8
|
+
|
9
|
+
def eval(context, options={})
|
10
|
+
options[:no_indent] ||= false
|
11
|
+
|
12
|
+
s = ""
|
13
|
+
if !options[:no_indent]
|
14
|
+
s += " "
|
15
|
+
end
|
16
|
+
|
17
|
+
if @condition
|
18
|
+
s += "=#{@condition.eval(context)},#{@block.eval(context)}"
|
19
|
+
else
|
20
|
+
s += "ELSE,#{@block.eval(context)}"
|
21
|
+
end
|
22
|
+
s
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -1,33 +1,33 @@
|
|
1
|
-
module TPPlus
|
2
|
-
module Nodes
|
3
|
-
class CaseNode
|
4
|
-
def initialize(var, conditions, else_condition)
|
5
|
-
@var = var
|
6
|
-
@conditions = conditions
|
7
|
-
@else_condition = else_condition
|
8
|
-
end
|
9
|
-
|
10
|
-
def else_condition(context)
|
11
|
-
return "" if @else_condition.nil?
|
12
|
-
|
13
|
-
" ;\n#{@else_condition.eval(context)}"
|
14
|
-
end
|
15
|
-
|
16
|
-
def other_conditions(context)
|
17
|
-
return "" if @conditions.empty?
|
18
|
-
|
19
|
-
s = " ;\n"
|
20
|
-
@conditions.reject! {|c| c.nil? }.each do |c|
|
21
|
-
s += c.eval(context)
|
22
|
-
s += " ;\n" unless c == @conditions.last
|
23
|
-
end
|
24
|
-
|
25
|
-
s
|
26
|
-
end
|
27
|
-
|
28
|
-
def eval(context)
|
29
|
-
"SELECT #{@var.eval(context)}#{@conditions.shift.eval(context, no_indent: true)}#{other_conditions(context)}#{else_condition(context)}"
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
1
|
+
module TPPlus
|
2
|
+
module Nodes
|
3
|
+
class CaseNode
|
4
|
+
def initialize(var, conditions, else_condition)
|
5
|
+
@var = var
|
6
|
+
@conditions = conditions
|
7
|
+
@else_condition = else_condition
|
8
|
+
end
|
9
|
+
|
10
|
+
def else_condition(context)
|
11
|
+
return "" if @else_condition.nil?
|
12
|
+
|
13
|
+
" ;\n#{@else_condition.eval(context)}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def other_conditions(context)
|
17
|
+
return "" if @conditions.empty?
|
18
|
+
|
19
|
+
s = " ;\n"
|
20
|
+
@conditions.reject! {|c| c.nil? }.each do |c|
|
21
|
+
s += c.eval(context)
|
22
|
+
s += " ;\n" unless c == @conditions.last
|
23
|
+
end
|
24
|
+
|
25
|
+
s
|
26
|
+
end
|
27
|
+
|
28
|
+
def eval(context)
|
29
|
+
"SELECT #{@var.eval(context)}#{@conditions.shift.eval(context, no_indent: true)}#{other_conditions(context)}#{else_condition(context)}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -1,22 +1,22 @@
|
|
1
|
-
module TPPlus
|
2
|
-
module Nodes
|
3
|
-
class CommentNode
|
4
|
-
def initialize(text)
|
5
|
-
@text = text[1,text.length]
|
6
|
-
end
|
7
|
-
|
8
|
-
def can_be_inlined?
|
9
|
-
false
|
10
|
-
end
|
11
|
-
|
12
|
-
def eval(context)
|
13
|
-
s = ""
|
14
|
-
width = 29
|
15
|
-
@text.scan(/\S.{0,#{width}}\S(?=\s|$)|\S+/).each do |piece|
|
16
|
-
s += "! #{piece} ;\n"
|
17
|
-
end
|
18
|
-
s[0,s.length-3]
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
1
|
+
module TPPlus
|
2
|
+
module Nodes
|
3
|
+
class CommentNode
|
4
|
+
def initialize(text)
|
5
|
+
@text = text[1,text.length]
|
6
|
+
end
|
7
|
+
|
8
|
+
def can_be_inlined?
|
9
|
+
false
|
10
|
+
end
|
11
|
+
|
12
|
+
def eval(context)
|
13
|
+
s = ""
|
14
|
+
width = 29
|
15
|
+
@text.scan(/\S.{0,#{width}}\S(?=\s|$)|\S+/).each do |piece|
|
16
|
+
s += "! #{piece} ;\n"
|
17
|
+
end
|
18
|
+
s[0,s.length-3]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -1,54 +1,60 @@
|
|
1
|
-
module TPPlus
|
2
|
-
module Nodes
|
3
|
-
class ConditionalNode
|
4
|
-
def initialize(type,condition,true_block,false_block)
|
5
|
-
@type = type
|
6
|
-
@condition = condition
|
7
|
-
@true_block = true_block.flatten.reject {|n| n.is_a? TerminatorNode }
|
8
|
-
@false_block = false_block.flatten.reject {|n| n.is_a? TerminatorNode }
|
9
|
-
end
|
10
|
-
|
11
|
-
def true_label(context)
|
12
|
-
@true_label ||= context.next_label
|
13
|
-
end
|
14
|
-
|
15
|
-
def end_label(context)
|
16
|
-
@end_label ||= context.next_label
|
17
|
-
end
|
18
|
-
|
19
|
-
def true_block(context)
|
20
|
-
@t ||= string_for(@true_block,context)
|
21
|
-
end
|
22
|
-
|
23
|
-
def false_block(context)
|
24
|
-
@f ||= string_for(@false_block,context)
|
25
|
-
end
|
26
|
-
|
27
|
-
def string_for(block,context)
|
28
|
-
block.inject("") {|s,n| s << "#{n.eval(context)} ;\n" }
|
29
|
-
end
|
30
|
-
|
31
|
-
def can_be_inlined?
|
32
|
-
return false unless @false_block.empty?
|
33
|
-
return false unless @true_block.length == 1
|
34
|
-
|
35
|
-
@true_block.first.can_be_inlined?
|
36
|
-
end
|
37
|
-
|
38
|
-
def opposite?
|
39
|
-
@type == "if"
|
40
|
-
end
|
41
|
-
|
42
|
-
def
|
43
|
-
return
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
1
|
+
module TPPlus
|
2
|
+
module Nodes
|
3
|
+
class ConditionalNode
|
4
|
+
def initialize(type,condition,true_block,false_block)
|
5
|
+
@type = type
|
6
|
+
@condition = condition
|
7
|
+
@true_block = true_block.flatten.reject {|n| n.is_a? TerminatorNode }
|
8
|
+
@false_block = false_block.flatten.reject {|n| n.is_a? TerminatorNode }
|
9
|
+
end
|
10
|
+
|
11
|
+
def true_label(context)
|
12
|
+
@true_label ||= context.next_label
|
13
|
+
end
|
14
|
+
|
15
|
+
def end_label(context)
|
16
|
+
@end_label ||= context.next_label
|
17
|
+
end
|
18
|
+
|
19
|
+
def true_block(context)
|
20
|
+
@t ||= string_for(@true_block,context)
|
21
|
+
end
|
22
|
+
|
23
|
+
def false_block(context)
|
24
|
+
@f ||= string_for(@false_block,context)
|
25
|
+
end
|
26
|
+
|
27
|
+
def string_for(block,context)
|
28
|
+
block.inject("") {|s,n| s << "#{n.eval(context)} ;\n" }
|
29
|
+
end
|
30
|
+
|
31
|
+
def can_be_inlined?
|
32
|
+
return false unless @false_block.empty?
|
33
|
+
return false unless @true_block.length == 1
|
34
|
+
|
35
|
+
@true_block.first.can_be_inlined?
|
36
|
+
end
|
37
|
+
|
38
|
+
def opposite?
|
39
|
+
@type == "if"
|
40
|
+
end
|
41
|
+
|
42
|
+
def parens(s, context)
|
43
|
+
return s unless @condition.requires_mixed_logic?(context) || !@condition.is_a?(ExpressionNode)
|
44
|
+
|
45
|
+
"(#{s})"
|
46
|
+
end
|
47
|
+
|
48
|
+
def eval(context, options={})
|
49
|
+
return InlineConditionalNode.new(@type,@condition,@true_block.first).eval(context) if can_be_inlined?
|
50
|
+
|
51
|
+
if @false_block.empty?
|
52
|
+
"IF #{parens(@condition.eval(context,opposite: opposite?), context)},JMP LBL[#{true_label(context)}] ;\n#{true_block(context)}LBL[#{true_label(context)}]"
|
53
|
+
else
|
54
|
+
# could be if-else or unless-else
|
55
|
+
"IF #{parens(@condition.eval(context,opposite: opposite?), context)},JMP LBL[#{true_label(context)}] ;\n#{true_block(context)}JMP LBL[#{end_label(context)}] ;\nLBL[#{true_label(context)}] ;\n#{false_block(context)}LBL[#{end_label(context)}]"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|