emfrp 0.1.2 → 0.1.3
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 +45 -12
- data/bin/emfrp +4 -1
- data/examples/LCDClock/LCDClock.mfrp +93 -93
- data/examples/LCDClock/LCDClock_LPC1768.bin +0 -0
- data/examples/LCDClock/README.md +24 -24
- data/examples/LCDPositioner/LCDPositioner.mfrp +30 -30
- data/examples/LCDPositioner/LCDPositionerMain.c +15 -15
- data/examples/MostDistantPoint/MostDistantPoint.mfrp +25 -25
- data/examples/MostDistantPoint/MostDistantPointMain.c +14 -14
- data/lib/emfrp/compile/c/alloc.rb +200 -200
- data/lib/emfrp/compile/c/codegen.rb +18 -18
- data/lib/emfrp/compile/c/codegen_context.rb +218 -218
- data/lib/emfrp/compile/c/monofy.rb +185 -185
- data/lib/emfrp/compile/c/syntax_codegen.rb +364 -364
- data/lib/emfrp/compile/c/syntax_exp_codegen.rb +119 -119
- data/lib/emfrp/compile/graphviz/graphviz.rb +53 -53
- data/lib/emfrp/compile_error.rb +95 -95
- data/lib/emfrp/interpreter/command_manager.rb +367 -367
- data/lib/emfrp/interpreter/evaluater.rb +146 -146
- data/lib/emfrp/interpreter/file_loader.rb +52 -52
- data/lib/emfrp/interpreter/interpreter.rb +200 -195
- data/lib/emfrp/parser/expression.rb +386 -386
- data/lib/emfrp/parser/misc.rb +184 -184
- data/lib/emfrp/parser/newnode_convert.rb +72 -72
- data/lib/emfrp/parser/operator.rb +25 -25
- data/lib/emfrp/parser/parser.rb +150 -150
- data/lib/emfrp/parser/parsing_error.rb +49 -49
- data/lib/emfrp/parser/toplevel.rb +555 -555
- data/lib/emfrp/pre_convert/pre_convert.rb +32 -32
- data/lib/emfrp/syntax.rb +171 -171
- data/lib/emfrp/typing/typing_error.rb +47 -47
- data/lib/emfrp/typing/union_type.rb +197 -197
- data/lib/emfrp/version.rb +1 -1
- data/mfrp_include/Std.mfrp +122 -122
- data/tests/Rakefile +8 -8
- data/tests/Rakefile.common +27 -27
- data/tests/command/Rakefile +2 -2
- data/tests/command/ReplaceNode.mfrp +39 -39
- data/tests/compiler/ComplexDataType/ComplexDataType.mfrp +14 -14
- data/tests/compiler/ComplexDataType/ComplexDataTypeMain.c +15 -15
- data/tests/compiler/ComplexDataType/Rakefile +2 -2
- data/tests/compiler/ComplexDataType/expected_out.txt +0 -0
- data/tests/compiler/ComplexDataType/in.txt +5 -5
- data/tests/compiler/LCDClock/LCDClock.mfrp +90 -90
- data/tests/compiler/LCDClock/LCDClockMain.c +0 -0
- data/tests/compiler/LCDClock/Rakefile +2 -2
- data/tests/compiler/LCDClock/expected_out.txt +0 -0
- data/tests/compiler/LCDClock/in.txt +0 -0
- data/tests/compiler/LCDPositioner/LCDPositioner.mfrp +30 -30
- data/tests/compiler/LCDPositioner/LCDPositionerMain.c +15 -15
- data/tests/compiler/LCDPositioner/Rakefile +2 -2
- data/tests/compiler/LCDPositioner/graph.dot +0 -0
- data/tests/compiler/LCDPositioner/graph.png +0 -0
- data/tests/compiler/Rakefile +8 -8
- data/tests/compiler/Rakefile.common +23 -23
- data/tests/compiler/UseData/Rakefile +2 -2
- data/tests/compiler/UseData/UseData.mfrp +8 -8
- data/tests/compiler/UseSubModule/Rakefile +2 -2
- data/tests/compiler/UseSubModule/SubModule.mfrp +8 -8
- data/tests/compiler/UseSubModule/SubModule2.mfrp +5 -5
- data/tests/compiler/UseSubModule/UseSubModule.mfrp +11 -11
- data/tests/core/FromAnnotation.mfrp +18 -18
- data/tests/core/Last.mfrp +10 -10
- data/tests/core/Rakefile +2 -2
- data/tests/core/TypingTest.mfrp +11 -11
- data/tests/core/WithoutInputs.mfrp +19 -19
- data/tests/load_time_error/Rakefile +32 -32
- data/tests/load_time_error/TypeMismatch.mfrp +4 -4
- metadata +3 -3
@@ -1,146 +1,146 @@
|
|
1
|
-
module Emfrp
|
2
|
-
class Interpreter
|
3
|
-
module Evaluater
|
4
|
-
extend self
|
5
|
-
|
6
|
-
def eval_exp(top, exp, env={})
|
7
|
-
case exp
|
8
|
-
when FuncCall
|
9
|
-
case f = top[:dict][:func_space][exp[:name][:desc]].get
|
10
|
-
when PrimFuncDef
|
11
|
-
if ruby_exp = f[:foreigns].find{|x| x[:language][:desc] == "ruby"}
|
12
|
-
proc_str = "proc{|#{f[:params].map{|x| x[:name][:desc]}.join(",")}| #{ruby_exp[:desc]}}"
|
13
|
-
return eval(proc_str).call(*exp[:args].map{|e| eval_exp(top, e, env)})
|
14
|
-
else
|
15
|
-
raise "Primitive Function `#{f[:name][:desc]}` is not defined for ruby"
|
16
|
-
end
|
17
|
-
when FuncDef
|
18
|
-
f[:params].map{|param| [param[:name], Link.new(f)]}.zip(exp[:args]).each do |key, arg|
|
19
|
-
env[key] = eval_exp(top, arg, env)
|
20
|
-
end
|
21
|
-
return eval_exp(top, f[:exp], env)
|
22
|
-
end
|
23
|
-
when ValueConst
|
24
|
-
return [exp[:name][:desc].to_sym] + exp[:args].map{|e| eval_exp(top, e, env)}
|
25
|
-
when LiteralIntegral
|
26
|
-
return exp[:entity][:desc].to_i
|
27
|
-
when LiteralChar
|
28
|
-
return exp[:entity].ord
|
29
|
-
when LiteralFloating
|
30
|
-
return exp[:entity][:desc].to_f
|
31
|
-
when VarRef
|
32
|
-
key = [exp[:name], exp[:binder]]
|
33
|
-
unless env[key]
|
34
|
-
if exp[:binder].get.is_a?(DataDef)
|
35
|
-
env[key] = eval_exp(top, exp[:binder].get[:exp], env)
|
36
|
-
else
|
37
|
-
raise "Assertion error: #{key} is unbound"
|
38
|
-
end
|
39
|
-
end
|
40
|
-
return env[key]
|
41
|
-
when ParenthExp
|
42
|
-
return eval_exp(top, exp[:exp], env)
|
43
|
-
when MatchExp
|
44
|
-
left_val = eval_exp(top, exp[:exp], env)
|
45
|
-
exp[:cases].each do |c|
|
46
|
-
if match_result = pattern_match(c, left_val)
|
47
|
-
return eval_exp(top, c[:exp], env.merge(match_result))
|
48
|
-
end
|
49
|
-
end
|
50
|
-
raise "pattern match fail"
|
51
|
-
when SkipExp
|
52
|
-
throw :skip, :skip
|
53
|
-
else
|
54
|
-
raise "Unexpected expression type #{exp.class} (bug)"
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def eval_node_as_func(top, node_def, exps)
|
59
|
-
env = {}
|
60
|
-
if node_def[:params].size != exps.size
|
61
|
-
raise "Assertion error: invalid length of args"
|
62
|
-
end
|
63
|
-
node_def[:params].map{|param| [param[:as], Link.new(node_def)]}.zip(exps).each do |key, arg|
|
64
|
-
env[key] = eval_exp(top, arg, env)
|
65
|
-
end
|
66
|
-
return catch(:skip) do
|
67
|
-
return eval_exp(top, node_def[:exp], env)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
def eval_module(top, input_exps, current_state, last_state, replacement)
|
72
|
-
top[:inputs].zip(input_exps).each do |i, e|
|
73
|
-
current_state[i] = eval_exp(top, e)
|
74
|
-
end
|
75
|
-
unless last_state
|
76
|
-
last_state = {}
|
77
|
-
(top[:inputs] + top[:nodes]).each do |d|
|
78
|
-
last_state[d] = eval_exp(top, d[:init_exp]) if d[:init_exp]
|
79
|
-
end
|
80
|
-
end
|
81
|
-
(top[:inputs] + top[:nodes]).each do |d|
|
82
|
-
eval_node(top, d, current_state, last_state, replacement)
|
83
|
-
end
|
84
|
-
return top[:outputs].map do |x|
|
85
|
-
eval_node(top, top[:dict][:node_space][x[:name][:desc]].get, current_state, last_state, replacement)
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
def eval_node(top, node_def, current_state, last_state, replacement)
|
90
|
-
if replacement[node_def[:name][:desc]]
|
91
|
-
rep_node = replacement[node_def[:name][:desc]]
|
92
|
-
return eval_node(top, rep_node, current_state, last_state, replacement)
|
93
|
-
end
|
94
|
-
return current_state[node_def] if current_state[node_def]
|
95
|
-
env = {}
|
96
|
-
node_def[:params].each do |param|
|
97
|
-
key = [param[:as], Link.new(node_def)]
|
98
|
-
pn = top[:dict][:node_space][param[:name][:desc]].get
|
99
|
-
if param[:last]
|
100
|
-
raise "Assertion error" unless last_state[pn]
|
101
|
-
if rep_node = replacement[param[:name][:desc]]
|
102
|
-
env[key] = last_state[rep_node]
|
103
|
-
else
|
104
|
-
env[key] = last_state[pn]
|
105
|
-
end
|
106
|
-
else
|
107
|
-
env[key] = eval_node(top, pn, current_state, last_state, replacement)
|
108
|
-
end
|
109
|
-
end
|
110
|
-
res = catch(:skip){ eval_exp(top, node_def[:exp], env) }
|
111
|
-
return current_state[node_def] = res == :skip ? last_state[node_def] : res
|
112
|
-
end
|
113
|
-
|
114
|
-
def pattern_match(c, v, pattern=c[:pattern], vars={})
|
115
|
-
if pattern[:ref]
|
116
|
-
key = [pattern[:ref], Link.new(c)]
|
117
|
-
vars[key] = v
|
118
|
-
end
|
119
|
-
case pattern
|
120
|
-
when ValuePattern
|
121
|
-
if v.is_a?(Array) && pattern[:name][:desc].to_sym == v[0]
|
122
|
-
res = v.drop(1).zip(pattern[:args]).all? do |ch_v, ch_p|
|
123
|
-
pattern_match(c, ch_v, ch_p, vars)
|
124
|
-
end
|
125
|
-
return vars if res
|
126
|
-
end
|
127
|
-
when IntegralPattern
|
128
|
-
if v.is_a?(Integer) && pattern[:val][:entity][:desc].to_i == v
|
129
|
-
return vars
|
130
|
-
end
|
131
|
-
when AnyPattern
|
132
|
-
return vars
|
133
|
-
end
|
134
|
-
return nil
|
135
|
-
end
|
136
|
-
|
137
|
-
def value_to_s(val)
|
138
|
-
if val.is_a?(Array) && val.first.is_a?(Symbol)
|
139
|
-
"#{val.first}" + (val.size > 1 ? "(#{val.drop(1).map{|x| value_to_s(x)}.join(", ")})" : "")
|
140
|
-
else
|
141
|
-
val.to_s
|
142
|
-
end
|
143
|
-
end
|
144
|
-
end
|
145
|
-
end
|
146
|
-
end
|
1
|
+
module Emfrp
|
2
|
+
class Interpreter
|
3
|
+
module Evaluater
|
4
|
+
extend self
|
5
|
+
|
6
|
+
def eval_exp(top, exp, env={})
|
7
|
+
case exp
|
8
|
+
when FuncCall
|
9
|
+
case f = top[:dict][:func_space][exp[:name][:desc]].get
|
10
|
+
when PrimFuncDef
|
11
|
+
if ruby_exp = f[:foreigns].find{|x| x[:language][:desc] == "ruby"}
|
12
|
+
proc_str = "proc{|#{f[:params].map{|x| x[:name][:desc]}.join(",")}| #{ruby_exp[:desc]}}"
|
13
|
+
return eval(proc_str).call(*exp[:args].map{|e| eval_exp(top, e, env)})
|
14
|
+
else
|
15
|
+
raise "Primitive Function `#{f[:name][:desc]}` is not defined for ruby"
|
16
|
+
end
|
17
|
+
when FuncDef
|
18
|
+
f[:params].map{|param| [param[:name], Link.new(f)]}.zip(exp[:args]).each do |key, arg|
|
19
|
+
env[key] = eval_exp(top, arg, env)
|
20
|
+
end
|
21
|
+
return eval_exp(top, f[:exp], env)
|
22
|
+
end
|
23
|
+
when ValueConst
|
24
|
+
return [exp[:name][:desc].to_sym] + exp[:args].map{|e| eval_exp(top, e, env)}
|
25
|
+
when LiteralIntegral
|
26
|
+
return exp[:entity][:desc].to_i
|
27
|
+
when LiteralChar
|
28
|
+
return exp[:entity].ord
|
29
|
+
when LiteralFloating
|
30
|
+
return exp[:entity][:desc].to_f
|
31
|
+
when VarRef
|
32
|
+
key = [exp[:name], exp[:binder]]
|
33
|
+
unless env[key]
|
34
|
+
if exp[:binder].get.is_a?(DataDef)
|
35
|
+
env[key] = eval_exp(top, exp[:binder].get[:exp], env)
|
36
|
+
else
|
37
|
+
raise "Assertion error: #{key} is unbound"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
return env[key]
|
41
|
+
when ParenthExp
|
42
|
+
return eval_exp(top, exp[:exp], env)
|
43
|
+
when MatchExp
|
44
|
+
left_val = eval_exp(top, exp[:exp], env)
|
45
|
+
exp[:cases].each do |c|
|
46
|
+
if match_result = pattern_match(c, left_val)
|
47
|
+
return eval_exp(top, c[:exp], env.merge(match_result))
|
48
|
+
end
|
49
|
+
end
|
50
|
+
raise "pattern match fail"
|
51
|
+
when SkipExp
|
52
|
+
throw :skip, :skip
|
53
|
+
else
|
54
|
+
raise "Unexpected expression type #{exp.class} (bug)"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def eval_node_as_func(top, node_def, exps)
|
59
|
+
env = {}
|
60
|
+
if node_def[:params].size != exps.size
|
61
|
+
raise "Assertion error: invalid length of args"
|
62
|
+
end
|
63
|
+
node_def[:params].map{|param| [param[:as], Link.new(node_def)]}.zip(exps).each do |key, arg|
|
64
|
+
env[key] = eval_exp(top, arg, env)
|
65
|
+
end
|
66
|
+
return catch(:skip) do
|
67
|
+
return eval_exp(top, node_def[:exp], env)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def eval_module(top, input_exps, current_state, last_state, replacement)
|
72
|
+
top[:inputs].zip(input_exps).each do |i, e|
|
73
|
+
current_state[i] = eval_exp(top, e)
|
74
|
+
end
|
75
|
+
unless last_state
|
76
|
+
last_state = {}
|
77
|
+
(top[:inputs] + top[:nodes]).each do |d|
|
78
|
+
last_state[d] = eval_exp(top, d[:init_exp]) if d[:init_exp]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
(top[:inputs] + top[:nodes]).each do |d|
|
82
|
+
eval_node(top, d, current_state, last_state, replacement)
|
83
|
+
end
|
84
|
+
return top[:outputs].map do |x|
|
85
|
+
eval_node(top, top[:dict][:node_space][x[:name][:desc]].get, current_state, last_state, replacement)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def eval_node(top, node_def, current_state, last_state, replacement)
|
90
|
+
if replacement[node_def[:name][:desc]]
|
91
|
+
rep_node = replacement[node_def[:name][:desc]]
|
92
|
+
return eval_node(top, rep_node, current_state, last_state, replacement)
|
93
|
+
end
|
94
|
+
return current_state[node_def] if current_state[node_def]
|
95
|
+
env = {}
|
96
|
+
node_def[:params].each do |param|
|
97
|
+
key = [param[:as], Link.new(node_def)]
|
98
|
+
pn = top[:dict][:node_space][param[:name][:desc]].get
|
99
|
+
if param[:last]
|
100
|
+
raise "Assertion error" unless last_state[pn]
|
101
|
+
if rep_node = replacement[param[:name][:desc]]
|
102
|
+
env[key] = last_state[rep_node]
|
103
|
+
else
|
104
|
+
env[key] = last_state[pn]
|
105
|
+
end
|
106
|
+
else
|
107
|
+
env[key] = eval_node(top, pn, current_state, last_state, replacement)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
res = catch(:skip){ eval_exp(top, node_def[:exp], env) }
|
111
|
+
return current_state[node_def] = res == :skip ? last_state[node_def] : res
|
112
|
+
end
|
113
|
+
|
114
|
+
def pattern_match(c, v, pattern=c[:pattern], vars={})
|
115
|
+
if pattern[:ref]
|
116
|
+
key = [pattern[:ref], Link.new(c)]
|
117
|
+
vars[key] = v
|
118
|
+
end
|
119
|
+
case pattern
|
120
|
+
when ValuePattern
|
121
|
+
if v.is_a?(Array) && pattern[:name][:desc].to_sym == v[0]
|
122
|
+
res = v.drop(1).zip(pattern[:args]).all? do |ch_v, ch_p|
|
123
|
+
pattern_match(c, ch_v, ch_p, vars)
|
124
|
+
end
|
125
|
+
return vars if res
|
126
|
+
end
|
127
|
+
when IntegralPattern
|
128
|
+
if v.is_a?(Integer) && pattern[:val][:entity][:desc].to_i == v
|
129
|
+
return vars
|
130
|
+
end
|
131
|
+
when AnyPattern
|
132
|
+
return vars
|
133
|
+
end
|
134
|
+
return nil
|
135
|
+
end
|
136
|
+
|
137
|
+
def value_to_s(val)
|
138
|
+
if val.is_a?(Array) && val.first.is_a?(Symbol)
|
139
|
+
"#{val.first}" + (val.size > 1 ? "(#{val.drop(1).map{|x| value_to_s(x)}.join(", ")})" : "")
|
140
|
+
else
|
141
|
+
val.to_s
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
@@ -1,52 +1,52 @@
|
|
1
|
-
module Emfrp
|
2
|
-
class FileLoader
|
3
|
-
FileLoadError = Class.new(StandardError)
|
4
|
-
|
5
|
-
def initialize(include_dirs)
|
6
|
-
@include_dirs = include_dirs
|
7
|
-
@loaded_hash = {}
|
8
|
-
end
|
9
|
-
|
10
|
-
def loaded?(path)
|
11
|
-
@loaded_hash.has_key?(path)
|
12
|
-
end
|
13
|
-
|
14
|
-
def loaded_full_path(path)
|
15
|
-
raise "assertion error" unless loaded?(path)
|
16
|
-
@loaded_hash[path][1]
|
17
|
-
end
|
18
|
-
|
19
|
-
def get_src_from_full_path(required_full_path)
|
20
|
-
@loaded_hash.each do |path, x|
|
21
|
-
src_str, full_path = *x
|
22
|
-
if full_path == required_full_path
|
23
|
-
return src_str
|
24
|
-
end
|
25
|
-
end
|
26
|
-
raise "#{required_full_path} is not found"
|
27
|
-
end
|
28
|
-
|
29
|
-
def add_to_loaded(path, src)
|
30
|
-
@loaded_hash[path] = [src, path]
|
31
|
-
end
|
32
|
-
|
33
|
-
def load(path)
|
34
|
-
path_str = path.is_a?(Array) ? path.join("/") : path
|
35
|
-
if path =~ /^\/.*?/ && File.exist?(path)
|
36
|
-
src_str = File.open(path, 'r'){|f| f.read}
|
37
|
-
return @loaded_hash[path] = [src_str, path]
|
38
|
-
end
|
39
|
-
@include_dirs.each do |d|
|
40
|
-
full_path = File.expand_path(d + path_str)
|
41
|
-
if File.exist?(full_path) && File.ftype(full_path) == "file"
|
42
|
-
src_str = File.open(full_path, 'r'){|f| f.read}
|
43
|
-
return @loaded_hash[path] = [src_str, full_path]
|
44
|
-
elsif File.exist?(full_path + ".mfrp") && File.ftype(full_path + ".mfrp") == "file"
|
45
|
-
src_str = File.open(full_path + ".mfrp", 'r'){|f| f.read}
|
46
|
-
return @loaded_hash[path] = [src_str, full_path + ".mfrp"]
|
47
|
-
end
|
48
|
-
end
|
49
|
-
raise FileLoadError.new("Cannot load #{path_str}")
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
1
|
+
module Emfrp
|
2
|
+
class FileLoader
|
3
|
+
FileLoadError = Class.new(StandardError)
|
4
|
+
|
5
|
+
def initialize(include_dirs)
|
6
|
+
@include_dirs = include_dirs
|
7
|
+
@loaded_hash = {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def loaded?(path)
|
11
|
+
@loaded_hash.has_key?(path)
|
12
|
+
end
|
13
|
+
|
14
|
+
def loaded_full_path(path)
|
15
|
+
raise "assertion error" unless loaded?(path)
|
16
|
+
@loaded_hash[path][1]
|
17
|
+
end
|
18
|
+
|
19
|
+
def get_src_from_full_path(required_full_path)
|
20
|
+
@loaded_hash.each do |path, x|
|
21
|
+
src_str, full_path = *x
|
22
|
+
if full_path == required_full_path
|
23
|
+
return src_str
|
24
|
+
end
|
25
|
+
end
|
26
|
+
raise "#{required_full_path} is not found"
|
27
|
+
end
|
28
|
+
|
29
|
+
def add_to_loaded(path, src)
|
30
|
+
@loaded_hash[path] = [src, path]
|
31
|
+
end
|
32
|
+
|
33
|
+
def load(path)
|
34
|
+
path_str = path.is_a?(Array) ? path.join("/") : path
|
35
|
+
if path =~ /^\/.*?/ && File.exist?(path)
|
36
|
+
src_str = File.open(path, 'r'){|f| f.read}
|
37
|
+
return @loaded_hash[path] = [src_str, path]
|
38
|
+
end
|
39
|
+
@include_dirs.each do |d|
|
40
|
+
full_path = File.expand_path(d + path_str)
|
41
|
+
if File.exist?(full_path) && File.ftype(full_path) == "file"
|
42
|
+
src_str = File.open(full_path, 'r'){|f| f.read}
|
43
|
+
return @loaded_hash[path] = [src_str, full_path]
|
44
|
+
elsif File.exist?(full_path + ".mfrp") && File.ftype(full_path + ".mfrp") == "file"
|
45
|
+
src_str = File.open(full_path + ".mfrp", 'r'){|f| f.read}
|
46
|
+
return @loaded_hash[path] = [src_str, full_path + ".mfrp"]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
raise FileLoadError.new("Cannot load #{path_str}")
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|