sfrp 1.1.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 +7 -0
- data/.ctags +3 -0
- data/.editorconfig +9 -0
- data/.gitignore +14 -0
- data/.rubocop.yml +629 -0
- data/.travis.yml +12 -0
- data/Gemfile +2 -0
- data/LICENSE +28 -0
- data/README.md +34 -0
- data/Rakefile +1 -0
- data/base-library/Base.sfrp +81 -0
- data/base-library/IO/AVR/ATMEGA8.c +9 -0
- data/base-library/IO/AVR/ATMEGA8.h +6 -0
- data/base-library/IO/AVR/ATMEGA8.sfrp +4 -0
- data/base-library/IO/STDIO.c +40 -0
- data/base-library/IO/STDIO.h +13 -0
- data/base-library/IO/STDIO.sfrp +10 -0
- data/bin/sfrp +7 -0
- data/lib/sfrp.rb +2 -0
- data/lib/sfrp/command.rb +73 -0
- data/lib/sfrp/compiler.rb +94 -0
- data/lib/sfrp/error.rb +4 -0
- data/lib/sfrp/file.rb +18 -0
- data/lib/sfrp/flat/dsl.rb +33 -0
- data/lib/sfrp/flat/elements.rb +90 -0
- data/lib/sfrp/flat/exception.rb +45 -0
- data/lib/sfrp/flat/expression.rb +125 -0
- data/lib/sfrp/flat/set.rb +61 -0
- data/lib/sfrp/input/exception.rb +16 -0
- data/lib/sfrp/input/parser.rb +417 -0
- data/lib/sfrp/input/set.rb +29 -0
- data/lib/sfrp/input/transformer.rb +219 -0
- data/lib/sfrp/low/dsl.rb +126 -0
- data/lib/sfrp/low/element.rb +126 -0
- data/lib/sfrp/low/set.rb +62 -0
- data/lib/sfrp/mono/dsl.rb +120 -0
- data/lib/sfrp/mono/environment.rb +26 -0
- data/lib/sfrp/mono/exception.rb +21 -0
- data/lib/sfrp/mono/expression.rb +124 -0
- data/lib/sfrp/mono/function.rb +86 -0
- data/lib/sfrp/mono/memory.rb +32 -0
- data/lib/sfrp/mono/node.rb +125 -0
- data/lib/sfrp/mono/pattern.rb +69 -0
- data/lib/sfrp/mono/set.rb +151 -0
- data/lib/sfrp/mono/type.rb +210 -0
- data/lib/sfrp/mono/vconst.rb +134 -0
- data/lib/sfrp/output/set.rb +33 -0
- data/lib/sfrp/poly/dsl.rb +171 -0
- data/lib/sfrp/poly/elements.rb +168 -0
- data/lib/sfrp/poly/exception.rb +42 -0
- data/lib/sfrp/poly/expression.rb +170 -0
- data/lib/sfrp/poly/monofier.rb +73 -0
- data/lib/sfrp/poly/set.rb +90 -0
- data/lib/sfrp/poly/typing.rb +197 -0
- data/lib/sfrp/raw/dsl.rb +41 -0
- data/lib/sfrp/raw/elements.rb +164 -0
- data/lib/sfrp/raw/exception.rb +40 -0
- data/lib/sfrp/raw/expression.rb +168 -0
- data/lib/sfrp/raw/namespace.rb +30 -0
- data/lib/sfrp/raw/set.rb +109 -0
- data/lib/sfrp/version.rb +3 -0
- data/sfrp.gemspec +40 -0
- data/spec/sfrp/Test.sfrp +4 -0
- data/spec/sfrp/compiler_spec.rb +17 -0
- data/spec/sfrp/flat/set_spec.rb +40 -0
- data/spec/sfrp/input/parse_test.sfrp +20 -0
- data/spec/sfrp/input/set_spec.rb +18 -0
- data/spec/sfrp/low/set_spec.rb +20 -0
- data/spec/sfrp/mono/expected.yml +295 -0
- data/spec/sfrp/mono/set_spec.rb +152 -0
- data/spec/sfrp/output/set_spec.rb +29 -0
- data/spec/sfrp/poly/set_spec.rb +290 -0
- data/spec/sfrp/raw/set_spec.rb +38 -0
- data/spec/spec_helper.rb +16 -0
- data/test/IntTest/Main.c +5 -0
- data/test/IntTest/Main.h +6 -0
- data/test/IntTest/Main.sfrp +10 -0
- data/test/IntTest/in.txt +3 -0
- data/test/IntTest/out.txt +4 -0
- data/test/MaybeTest/Main.sfrp +8 -0
- data/test/MaybeTest/SubDir/Lib.sfrp +9 -0
- data/test/MaybeTest/in.txt +6 -0
- data/test/MaybeTest/out.txt +6 -0
- data/test/Rakefile +15 -0
- metadata +290 -0
@@ -0,0 +1,125 @@
|
|
1
|
+
module SFRP
|
2
|
+
module Mono
|
3
|
+
class Node
|
4
|
+
NodeRef = Struct.new(:node_str, :last)
|
5
|
+
|
6
|
+
attr_reader :str
|
7
|
+
|
8
|
+
def initialize(
|
9
|
+
str, type_str, node_refs, eval_func_str, init_func_str = nil
|
10
|
+
)
|
11
|
+
@str = str
|
12
|
+
@type_str = type_str
|
13
|
+
@node_refs = node_refs
|
14
|
+
@eval_func_str = eval_func_str
|
15
|
+
@init_func_str = init_func_str
|
16
|
+
end
|
17
|
+
|
18
|
+
def comp
|
19
|
+
[@str, @type_str, @node_refs, @eval_func_str, @init_func_str]
|
20
|
+
end
|
21
|
+
|
22
|
+
def ==(other)
|
23
|
+
comp == other.comp
|
24
|
+
end
|
25
|
+
|
26
|
+
# Is this node initialized?
|
27
|
+
def initialized?
|
28
|
+
@init_func_str
|
29
|
+
end
|
30
|
+
|
31
|
+
# Name of variable to hold current and last evaluated value of this node.
|
32
|
+
def low_node_str
|
33
|
+
@str
|
34
|
+
end
|
35
|
+
|
36
|
+
def memory_used_to_eval_node(set)
|
37
|
+
set.func(@eval_func_str).memory(set)
|
38
|
+
end
|
39
|
+
|
40
|
+
def memory_used_to_init_node(set)
|
41
|
+
return Memory.empty unless initialized?
|
42
|
+
set.func(@init_func_str).memory(set)
|
43
|
+
end
|
44
|
+
|
45
|
+
def memory_used_to_hold_node(set)
|
46
|
+
set.type(@type_str).memory(set)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Return referrence name of current evaluated value of this node.
|
50
|
+
def low_node_ref_current_str
|
51
|
+
index = (initialized? ? 'c' : '0')
|
52
|
+
"#{low_node_str}[#{index}]"
|
53
|
+
end
|
54
|
+
|
55
|
+
# Return referrence name of last evaluated value of this node.
|
56
|
+
def low_node_ref_last_str
|
57
|
+
"#{low_node_str}[l]"
|
58
|
+
end
|
59
|
+
|
60
|
+
# Return a list of nodes sorted by evaluation-order including this node.
|
61
|
+
# The list includes only nodes (recursively) depended by this node.
|
62
|
+
# So if you want to get a list including all nodes, you must call this
|
63
|
+
# method for an output node.
|
64
|
+
def sorted_node_strs(set)
|
65
|
+
cur = current_referred_node_strs(set)
|
66
|
+
last = last_referred_node_strs(set)
|
67
|
+
cur + (last - cur)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Generate a statement of initialization if needed.
|
71
|
+
def gen_initialize_stmt(set, stmts)
|
72
|
+
return unless initialized?
|
73
|
+
call_exp = set.func(@init_func_str).low_call_exp([])
|
74
|
+
stmts << L.stmt("#{low_node_str}[l] = #{call_exp}")
|
75
|
+
end
|
76
|
+
|
77
|
+
# Generate declaration for variable to hold value of node.
|
78
|
+
def gen_node_var_declaration(set, stmts)
|
79
|
+
type = set.type(@type_str)
|
80
|
+
size = (initialized? ? '2' : '1')
|
81
|
+
stmts << L.stmt("#{type.low_type_str} #{low_node_str}[#{size}]")
|
82
|
+
end
|
83
|
+
|
84
|
+
# Generate ststement to evaluate this node.
|
85
|
+
def gen_evaluate_stmt(set, stmts)
|
86
|
+
arg_exps = @node_refs.map do |node_ref|
|
87
|
+
n = set.node(node_ref.node_str)
|
88
|
+
node_ref.last ? n.low_node_ref_last_str : n.low_node_ref_current_str
|
89
|
+
end
|
90
|
+
call_exp = set.func(@eval_func_str).low_call_exp(arg_exps)
|
91
|
+
stmts << L.stmt("#{low_node_ref_current_str} = #{call_exp}")
|
92
|
+
end
|
93
|
+
|
94
|
+
# Generate statement to mark node[l].
|
95
|
+
def gen_node_var_mark_stmt(set, stmts)
|
96
|
+
return unless initialized?
|
97
|
+
return unless set.type(@type_str).need_mark?(set)
|
98
|
+
mark_func_str = set.type(@type_str).low_mark_func_str
|
99
|
+
stmts << L.stmt("#{mark_func_str}(#{low_node_str}[l])")
|
100
|
+
end
|
101
|
+
|
102
|
+
protected
|
103
|
+
|
104
|
+
# Return a list of (recursively) current-referred nodes including myself.
|
105
|
+
def current_referred_node_strs(set, visited = {})
|
106
|
+
return [] if visited.key?(@str)
|
107
|
+
visited[@str] = true
|
108
|
+
prereq_node_strs = @node_refs.reject(&:last).flat_map do |r|
|
109
|
+
set.node(r.node_str).current_referred_node_strs(set, visited)
|
110
|
+
end
|
111
|
+
prereq_node_strs + [@str]
|
112
|
+
end
|
113
|
+
|
114
|
+
# Return a list of (recursively) last-referred nodes.
|
115
|
+
def last_referred_node_strs(set, visited = {})
|
116
|
+
return [] if visited.key?(@str)
|
117
|
+
visited[@str] = true
|
118
|
+
rec = @node_refs.reject(&:last).flat_map do |r|
|
119
|
+
set.node(r.node_str).last_referred_node_strs(set, visited)
|
120
|
+
end
|
121
|
+
(@node_refs.select(&:last).map(&:node_str) + rec).uniq
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module SFRP
|
2
|
+
module Mono
|
3
|
+
class Pattern
|
4
|
+
PatternExample = Struct.new(:vconst_str, :args)
|
5
|
+
|
6
|
+
def initialize(type_str, vconst_str, ref_var_str, arg_patterns)
|
7
|
+
@type_str = type_str
|
8
|
+
@vconst_str = vconst_str
|
9
|
+
@ref_var_str = ref_var_str
|
10
|
+
@arg_patterns = arg_patterns
|
11
|
+
end
|
12
|
+
|
13
|
+
def comp
|
14
|
+
[@type_str, @vconst_str, @ref_var_str, @arg_patterns]
|
15
|
+
end
|
16
|
+
|
17
|
+
def ==(other)
|
18
|
+
comp == other.comp
|
19
|
+
end
|
20
|
+
|
21
|
+
def any?
|
22
|
+
@vconst_str.nil?
|
23
|
+
end
|
24
|
+
|
25
|
+
def named?
|
26
|
+
@ref_var_str
|
27
|
+
end
|
28
|
+
|
29
|
+
def accept?(pattern_example)
|
30
|
+
return true if any?
|
31
|
+
return false unless pattern_example.vconst_str == @vconst_str
|
32
|
+
@arg_patterns.zip(pattern_example.args).all? do |pat, pat_exam|
|
33
|
+
pat.accept?(pat_exam)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Return whole conditional-low-exps for the pattern-matching.
|
38
|
+
def low_cond_exps(set, receiver_exp)
|
39
|
+
return [] if any?
|
40
|
+
vconst = set.vconst(@vconst_str)
|
41
|
+
children = @arg_patterns.each_with_index.flat_map do |pat, mem_id|
|
42
|
+
new_receiver = child_receiver_exp(set, receiver_exp, mem_id)
|
43
|
+
pat.low_cond_exps(set, new_receiver)
|
44
|
+
end
|
45
|
+
vconst.low_compare_exps(set, receiver_exp) + children
|
46
|
+
end
|
47
|
+
|
48
|
+
# Return whole let-low-exps for the pattern-matching.
|
49
|
+
def low_let_exps(set, receiver_exp, env)
|
50
|
+
env.add_var(@ref_var_str, @type_str) if named?
|
51
|
+
lets = (named? ? ["#{@ref_var_str} = (#{receiver_exp})"] : [])
|
52
|
+
return lets if any?
|
53
|
+
children = @arg_patterns.each_with_index.flat_map do |pat, mem_id|
|
54
|
+
new_receiver = child_receiver_exp(set, receiver_exp, mem_id)
|
55
|
+
pat.low_let_exps(set, new_receiver, env)
|
56
|
+
end
|
57
|
+
lets + children
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def child_receiver_exp(set, parent_receiver_exp, member_id)
|
63
|
+
type = set.type(@type_str)
|
64
|
+
terms_str = type.terms_access_str(parent_receiver_exp)
|
65
|
+
"#{terms_str}.term#{type.term_id(@vconst_str)}.member#{member_id}"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
require 'sfrp/mono/environment'
|
2
|
+
require 'sfrp/mono/expression'
|
3
|
+
require 'sfrp/mono/function'
|
4
|
+
require 'sfrp/mono/memory'
|
5
|
+
require 'sfrp/mono/node'
|
6
|
+
require 'sfrp/mono/pattern'
|
7
|
+
require 'sfrp/mono/type'
|
8
|
+
require 'sfrp/mono/vconst'
|
9
|
+
require 'sfrp/mono/dsl'
|
10
|
+
|
11
|
+
module SFRP
|
12
|
+
module Mono
|
13
|
+
class Set
|
14
|
+
def initialize(&block)
|
15
|
+
@func_h = {}
|
16
|
+
@node_h = {}
|
17
|
+
@type_h = {}
|
18
|
+
@vconst_h = {}
|
19
|
+
@output_node_strs = []
|
20
|
+
@init_func_strs = []
|
21
|
+
@type_alias_h = {}
|
22
|
+
@constructor_alias_h = {}
|
23
|
+
block.call(self) if block
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_low(include_file_strs = [])
|
27
|
+
Low::Set.new do |low_set|
|
28
|
+
include_file_strs.each { |s| low_set << L.include_dq(s) }
|
29
|
+
@type_alias_h.each do |alias_str, original_str|
|
30
|
+
low_set << type(original_str).low_typedef_for_alias(alias_str)
|
31
|
+
end
|
32
|
+
@constructor_alias_h.each do |alias_str, original_str|
|
33
|
+
low_set << vconst(original_str).low_macro_for_alias(alias_str)
|
34
|
+
end
|
35
|
+
@func_h.values.each { |func| func.gen(self, low_set) }
|
36
|
+
@type_h.values.each { |type| type.gen(self, low_set) }
|
37
|
+
gen_main_func(low_set)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def check
|
42
|
+
# TODO: Check that all init_func does not waste any memory.
|
43
|
+
# TODO: Check completeness of pattern matchings.
|
44
|
+
end
|
45
|
+
|
46
|
+
def memory(type_str)
|
47
|
+
@memory ||= begin
|
48
|
+
to_init_nodes = nodes.reduce(Memory.empty) do |m, node|
|
49
|
+
m.and(node.memory_used_to_init_node(self))
|
50
|
+
end
|
51
|
+
to_hold_memoized_nodes = nodes.reduce(Memory.empty) do |m, node|
|
52
|
+
node.initialized? ? m.and(node.memory_used_to_hold_node(self)) : m
|
53
|
+
end
|
54
|
+
to_eval_nodes = nodes.reduce(Memory.empty) do |m, node|
|
55
|
+
m.and(node.memory_used_to_eval_node(self))
|
56
|
+
end
|
57
|
+
to_hold_memoized_nodes.and(to_eval_nodes).or(to_init_nodes)
|
58
|
+
end
|
59
|
+
@memory.count(type_str)
|
60
|
+
end
|
61
|
+
|
62
|
+
def <<(element)
|
63
|
+
case element
|
64
|
+
when Function
|
65
|
+
@func_h[element.str] = element
|
66
|
+
when Node
|
67
|
+
@node_h[element.str] = element
|
68
|
+
when Type
|
69
|
+
@type_h[element.str] = element
|
70
|
+
when VConst
|
71
|
+
@vconst_h[element.str] = element
|
72
|
+
else
|
73
|
+
raise
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def append_output_node_str(output_node_str)
|
78
|
+
@output_node_strs << output_node_str
|
79
|
+
end
|
80
|
+
|
81
|
+
def append_init_func_str(init_func_str)
|
82
|
+
@init_func_strs << init_func_str
|
83
|
+
end
|
84
|
+
|
85
|
+
def func(func_str)
|
86
|
+
raise func_str unless @func_h.key?(func_str)
|
87
|
+
@func_h[func_str]
|
88
|
+
end
|
89
|
+
|
90
|
+
def node(node_str)
|
91
|
+
raise node_str unless @node_h.key?(node_str)
|
92
|
+
@node_h[node_str]
|
93
|
+
end
|
94
|
+
|
95
|
+
def type(type_str)
|
96
|
+
raise type_str unless @type_h.key?(type_str)
|
97
|
+
@type_h[type_str]
|
98
|
+
end
|
99
|
+
|
100
|
+
def vconst(vconst_str)
|
101
|
+
raise vconst_str unless @vconst_h.key?(vconst_str)
|
102
|
+
@vconst_h[vconst_str]
|
103
|
+
end
|
104
|
+
|
105
|
+
def funcs
|
106
|
+
@func_h.values
|
107
|
+
end
|
108
|
+
|
109
|
+
def nodes
|
110
|
+
@node_h.values
|
111
|
+
end
|
112
|
+
|
113
|
+
def types
|
114
|
+
@type_h.values
|
115
|
+
end
|
116
|
+
|
117
|
+
def vconsts
|
118
|
+
@vconst_h.values
|
119
|
+
end
|
120
|
+
|
121
|
+
private
|
122
|
+
|
123
|
+
# All used nodes.
|
124
|
+
def used_nodes
|
125
|
+
node_strs = @output_node_strs.flat_map do |node_str|
|
126
|
+
node(node_str).sorted_node_strs(self)
|
127
|
+
end
|
128
|
+
node_strs.uniq.map { |node_str| node(node_str) }
|
129
|
+
end
|
130
|
+
|
131
|
+
# Generate the main-function.
|
132
|
+
def gen_main_func(dest_set)
|
133
|
+
dest_set << L.function('main', 'int') do |f|
|
134
|
+
f << L.stmt('int c = 0, l = 1')
|
135
|
+
used_nodes.each { |node| node.gen_node_var_declaration(self, f) }
|
136
|
+
@init_func_strs.each do |func_str|
|
137
|
+
f << L.stmt(func(func_str).low_call_exp([]))
|
138
|
+
end
|
139
|
+
used_nodes.each { |node| node.gen_initialize_stmt(self, f) }
|
140
|
+
f << L.while('1') do |wh|
|
141
|
+
@type_h.values.each { |type| type.gen_mark_cleanup_stmt(self, wh) }
|
142
|
+
used_nodes.each { |node| node.gen_node_var_mark_stmt(self, wh) }
|
143
|
+
used_nodes.each { |node| node.gen_evaluate_stmt(self, wh) }
|
144
|
+
wh << L.stmt('c ^= 1, l ^= 1')
|
145
|
+
end
|
146
|
+
f << L.stmt('return 0')
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
@@ -0,0 +1,210 @@
|
|
1
|
+
module SFRP
|
2
|
+
module Mono
|
3
|
+
class Type
|
4
|
+
attr_reader :str
|
5
|
+
|
6
|
+
def initialize(str, vconst_strs = nil, static = false, native_str = nil)
|
7
|
+
@str = str
|
8
|
+
@vconst_strs = vconst_strs
|
9
|
+
@static = static
|
10
|
+
@native_str = native_str
|
11
|
+
end
|
12
|
+
|
13
|
+
def comp
|
14
|
+
[@str, @vconst_strs, @static, @native_str]
|
15
|
+
end
|
16
|
+
|
17
|
+
def ==(other)
|
18
|
+
comp == other.comp
|
19
|
+
end
|
20
|
+
|
21
|
+
# Are objects of this type passed through value?
|
22
|
+
# Defalut is passing through referrence.
|
23
|
+
def static?
|
24
|
+
@static
|
25
|
+
end
|
26
|
+
|
27
|
+
# Does this type has infinite amount of vconsts?
|
28
|
+
def infinite?
|
29
|
+
@vconst_strs.nil?
|
30
|
+
end
|
31
|
+
|
32
|
+
# Is this type native type?
|
33
|
+
def native?
|
34
|
+
@native_str
|
35
|
+
end
|
36
|
+
|
37
|
+
# Does this type has single vconst of native type parameters
|
38
|
+
# e.g. Tuple3(Int, Int, Int)
|
39
|
+
def linear?(set)
|
40
|
+
single_vconst? && set.vconst(@vconst_strs[0]).native_args?(set)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Does this type has only one vconst?
|
44
|
+
def single_vconst?
|
45
|
+
!infinite? && @vconst_strs.size == 1
|
46
|
+
end
|
47
|
+
|
48
|
+
# Do objects of this type need to be passed to mark-function?
|
49
|
+
def need_mark?(set)
|
50
|
+
return true unless static?
|
51
|
+
return false if infinite?
|
52
|
+
@vconst_strs.any? { |v_str| set.vconst(v_str).param_needing_mark?(set) }
|
53
|
+
end
|
54
|
+
|
55
|
+
def has_meta_in_struct?
|
56
|
+
!(static? && single_vconst?)
|
57
|
+
end
|
58
|
+
|
59
|
+
def all_pattern_examples(set)
|
60
|
+
return [Pattern::PatternExample.new(nil, [])] if infinite?
|
61
|
+
@vconst_strs.flat_map do |vc_str|
|
62
|
+
set.vconst(vc_str).all_pattern_examples(set)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Return max memory size to hold an instance of this type.
|
67
|
+
def memory(set)
|
68
|
+
return Memory.one(@str) if infinite?
|
69
|
+
x = @vconst_strs.reduce(Memory.empty) do |m, v_str|
|
70
|
+
m.or(set.vconst(v_str).memory(set))
|
71
|
+
end
|
72
|
+
Memory.one(@str).and(x)
|
73
|
+
end
|
74
|
+
|
75
|
+
def low_typedef_for_alias(alias_str)
|
76
|
+
L.typedef("#{low_type_str} #{alias_str}")
|
77
|
+
end
|
78
|
+
|
79
|
+
def low_type_str
|
80
|
+
@native_str ? @native_str : @str
|
81
|
+
end
|
82
|
+
|
83
|
+
def low_allocator_str
|
84
|
+
"alloc_#{@str}"
|
85
|
+
end
|
86
|
+
|
87
|
+
def low_mark_func_str
|
88
|
+
"mark_#{@str}"
|
89
|
+
end
|
90
|
+
|
91
|
+
def meta_access_str(receiver_str)
|
92
|
+
"#{receiver_str}#{static? ? '.' : '->'}meta"
|
93
|
+
end
|
94
|
+
|
95
|
+
def terms_access_str(receiver_str)
|
96
|
+
"#{receiver_str}#{static? ? '.' : '->'}terms"
|
97
|
+
end
|
98
|
+
|
99
|
+
# Return term-id of given vconst of this type.
|
100
|
+
def term_id(vconst_str)
|
101
|
+
raise "#{@str} is infinite" if infinite?
|
102
|
+
res = @vconst_strs.index(vconst_str)
|
103
|
+
raise "#{vconst_str} is not a vconst of #{@str}" unless res
|
104
|
+
res
|
105
|
+
end
|
106
|
+
|
107
|
+
def low_member_pointers_for_single_vconst(set, receiver_str)
|
108
|
+
raise unless single_vconst?
|
109
|
+
set.vconst(@vconst_strs[0]).low_member_pointers(self, receiver_str)
|
110
|
+
end
|
111
|
+
|
112
|
+
# Generate C's elements for this type.
|
113
|
+
def gen(src_set, dest_set)
|
114
|
+
gen_struct(src_set, dest_set)
|
115
|
+
gen_typedef(src_set, dest_set)
|
116
|
+
gen_constructor(src_set, dest_set)
|
117
|
+
gen_allocator(src_set, dest_set)
|
118
|
+
gen_mark_function(src_set, dest_set)
|
119
|
+
end
|
120
|
+
|
121
|
+
# Generate statement to clean up objects of this types.
|
122
|
+
def gen_mark_cleanup_stmt(src_set, stmts)
|
123
|
+
return unless need_mark?(src_set)
|
124
|
+
return if src_set.memory(@str) == 0
|
125
|
+
stmts << L.stmt("#{low_allocator_str}(1)")
|
126
|
+
end
|
127
|
+
|
128
|
+
private
|
129
|
+
|
130
|
+
# Generate struct for this type.
|
131
|
+
def gen_struct(src_set, dest_set)
|
132
|
+
return if native? || infinite?
|
133
|
+
dest_set << L.struct(@str) do |top|
|
134
|
+
if has_meta_in_struct?
|
135
|
+
top << L.member_structure('struct', 'meta') do |meta|
|
136
|
+
meta << L.member('unsigned char term_id : 7')
|
137
|
+
meta << L.member('unsigned char mark : 1')
|
138
|
+
end
|
139
|
+
end
|
140
|
+
top << L.member_structure('union', 'terms') do |terms|
|
141
|
+
@vconst_strs.each_with_index do |v_str, term_id|
|
142
|
+
vconst = src_set.vconst(v_str)
|
143
|
+
vconst.gen_term_definition(src_set, term_id, terms)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
# Generate typedef for this type.
|
150
|
+
def gen_typedef(_src_set, dest_set)
|
151
|
+
return if native?
|
152
|
+
asta = static? ? '' : '*'
|
153
|
+
dest_set << L.typedef("struct #{@str}#{asta} #{@str}")
|
154
|
+
end
|
155
|
+
|
156
|
+
# Generate constructor-functions for vconsts.
|
157
|
+
def gen_constructor(src_set, dest_set)
|
158
|
+
return if infinite?
|
159
|
+
@vconst_strs.each_with_index do |v_str, term_id|
|
160
|
+
src_set.vconst(v_str).gen_constructor(src_set, term_id, dest_set)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
# Generate allocator-function for type.
|
165
|
+
def gen_allocator(src_set, dest_set)
|
166
|
+
return if static?
|
167
|
+
count = src_set.memory(@str)
|
168
|
+
memory_var = "memory_#{low_type_str}"
|
169
|
+
dest_set << L.function(low_allocator_str, low_type_str) do |f|
|
170
|
+
f.append_param('int', 'clean_up')
|
171
|
+
f << L.stmt('static int i = 0')
|
172
|
+
f << L.stmt("static struct #{low_type_str} #{memory_var}[#{count}]")
|
173
|
+
f << L.if_stmt('clean_up') do |if_stmts|
|
174
|
+
e = "#{memory_var}[i].meta.mark = 0"
|
175
|
+
if_stmts << L.stmt("for (i = 0; i < #{count}; i++) #{e}")
|
176
|
+
if_stmts << L.stmt('i = 0')
|
177
|
+
if_stmts << L.stmt('return 0')
|
178
|
+
end
|
179
|
+
f << L.stmt("while (#{memory_var}[i++].meta.mark)")
|
180
|
+
f << L.stmt("return #{memory_var} + (i - 1)")
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
# Generate mark function for this type.
|
185
|
+
def gen_mark_function(src_set, dest_set)
|
186
|
+
return unless need_mark?(src_set)
|
187
|
+
dest_set << L.function(low_mark_func_str, 'int') do |f|
|
188
|
+
f.append_param(low_type_str, 'target')
|
189
|
+
f << L.stmt("#{meta_access_str('target')}.mark = 1") unless static?
|
190
|
+
@vconst_strs.each_with_index do |v_str, term_id|
|
191
|
+
vconst = src_set.vconst(v_str)
|
192
|
+
cond_exps = vconst.low_compare_exps(src_set, 'target')
|
193
|
+
mark_exps = vconst.low_mark_element_exps(src_set, term_id, 'target')
|
194
|
+
next if mark_exps.empty?
|
195
|
+
mark_stmt = L.stmt(mark_exps.join(', '))
|
196
|
+
if cond_exps.empty?
|
197
|
+
f << mark_stmt
|
198
|
+
else
|
199
|
+
cond_exp = cond_exps.reduce { |a, e| "#{a} && #{e}" }
|
200
|
+
f << L.if_stmt(cond_exp) do |i|
|
201
|
+
i << mark_stmt
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
f << L.stmt('return 0')
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|