emfrp 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|