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
data/lib/emfrp/parser/parser.rb
CHANGED
@@ -1,150 +1,150 @@
|
|
1
|
-
require 'parser_combinator/string_parser'
|
2
|
-
|
3
|
-
require 'emfrp/syntax'
|
4
|
-
require 'emfrp/parser/toplevel'
|
5
|
-
require 'emfrp/parser/expression'
|
6
|
-
require 'emfrp/parser/misc'
|
7
|
-
require 'emfrp/parser/operator'
|
8
|
-
require 'emfrp/parser/parsing_error'
|
9
|
-
require 'emfrp/parser/newnode_convert'
|
10
|
-
|
11
|
-
module Emfrp
|
12
|
-
class Parser < ParserCombinator::StringParser
|
13
|
-
def self.parse_input(path, file_loader, file_type=module_file)
|
14
|
-
if file_loader.loaded?(path)
|
15
|
-
return Top.new
|
16
|
-
end
|
17
|
-
src_str, file_name = file_loader.load(path)
|
18
|
-
parse_src(src_str, file_name, file_loader, file_type)
|
19
|
-
end
|
20
|
-
|
21
|
-
def self.parse_src(src_str, file_name, file_loader, file_type=module_file)
|
22
|
-
case res = file_type.parse_from_string(convert_case_group(src_str), file_name)
|
23
|
-
when Fail
|
24
|
-
raise ParsingError.new(src_str, file_name, res.status)
|
25
|
-
when Ok
|
26
|
-
newnode_tops = res.parsed[:newnodes].map do |newnode|
|
27
|
-
NewNodeConvert.parse_module(res.parsed[:module_name][:desc], newnode, file_loader)
|
28
|
-
end
|
29
|
-
res.parsed[:newnodes] = []
|
30
|
-
tops = res.parsed[:uses].map do |use_path|
|
31
|
-
parse_input(use_path.map{|x| x[:desc]}, file_loader, material_file)
|
32
|
-
end
|
33
|
-
return Top.new(*tops, res.parsed, *newnode_tops)
|
34
|
-
else
|
35
|
-
raise "unexpected return of parser (bug)"
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def self.parse(src_str, file_name, parser)
|
40
|
-
case res = parser.parse_from_string(convert_case_group(src_str), file_name)
|
41
|
-
when Fail
|
42
|
-
raise ParsingError.new(src_str, file_name, res.status)
|
43
|
-
when Ok
|
44
|
-
return res.parsed
|
45
|
-
else
|
46
|
-
raise "unexpected return of parser (bug)"
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
def self.convert_case_group(src_str)
|
51
|
-
raise ParsingError.new("TAB is not allowed to use in sources.") if src_str.chars.include?("\t")
|
52
|
-
lines = src_str.each_line.to_a.map(&:chomp)
|
53
|
-
len = lines.length
|
54
|
-
len.times do |ln|
|
55
|
-
if lines[ln].strip.chars.last == ":"
|
56
|
-
width = lines[ln].chars.take_while{|c| c == "\s"}.size
|
57
|
-
((ln+1)..(len-1)).each do |ln2|
|
58
|
-
width2 = lines[ln2].chars.take_while{|c| c == "\s"}.size
|
59
|
-
if lines[ln2].strip == ""
|
60
|
-
next
|
61
|
-
elsif width2 <= width
|
62
|
-
lines[ln2 - 1] << " :endcase"
|
63
|
-
break
|
64
|
-
elsif ln2 == len - 1
|
65
|
-
lines[ln2] << " :endcase"
|
66
|
-
break
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
lines.map{|l| l + "\n"}.join
|
72
|
-
end
|
73
|
-
|
74
|
-
def self.from_infixes_to_parser(infixes)
|
75
|
-
priority_listl = [[], [], [], [], [], [], [], [], [], []]
|
76
|
-
priority_listr = [[], [], [], [], [], [], [], [], [], []]
|
77
|
-
priority_listn = [[], [], [], [], [], [], [], [], [], []]
|
78
|
-
defined_op = {}
|
79
|
-
infixes.reverse.each do |id|
|
80
|
-
if defined_op[id[:op][:desc]]
|
81
|
-
next
|
82
|
-
else
|
83
|
-
defined_op[id[:op][:desc]] = true
|
84
|
-
end
|
85
|
-
if id[:priority] == nil || ("0" <= id[:priority][:desc] && id[:priority][:desc] <= "9")
|
86
|
-
priority = id[:priority] == nil ? 9 : id[:priority][:desc].to_i
|
87
|
-
opp = sat{|i| i.is_a?(SSymbol) && i[:desc] == id[:op][:desc]}.map(&:item)
|
88
|
-
if id[:type][:desc] == "infix"
|
89
|
-
priority_listn[priority] << opp
|
90
|
-
elsif id[:type][:desc] == "infixl"
|
91
|
-
priority_listl[priority] << opp
|
92
|
-
elsif id[:type][:desc] == "infixr"
|
93
|
-
priority_listr[priority] << opp
|
94
|
-
else
|
95
|
-
raise "invalid infix type"
|
96
|
-
end
|
97
|
-
else
|
98
|
-
raise "invalid prirority"
|
99
|
-
end
|
100
|
-
end
|
101
|
-
priority_list = [{:op => sat{|i| i.is_a?(SSymbol)}.map(&:item), :dir => "left"}]
|
102
|
-
10.times do |i|
|
103
|
-
if priority_listl[i].length > 0
|
104
|
-
priority_list << {:op => priority_listl[i].inject(&:|), :dir => "left"}
|
105
|
-
end
|
106
|
-
if priority_listr[i].length > 0
|
107
|
-
priority_list << {:op => priority_listr[i].inject(&:|), :dir => "right"}
|
108
|
-
end
|
109
|
-
if priority_listn[i].length > 0
|
110
|
-
priority_list << {:op => priority_listn[i].inject(&:|), :dir => "left"}
|
111
|
-
end
|
112
|
-
end
|
113
|
-
return OpParser.make_op_parser(priority_list)
|
114
|
-
end
|
115
|
-
|
116
|
-
def self.infix_rearrange(top)
|
117
|
-
infix_parser = from_infixes_to_parser(top[:infixes])
|
118
|
-
return infix_convert(top, infix_parser)
|
119
|
-
end
|
120
|
-
|
121
|
-
def self.infix_convert(s, parser)
|
122
|
-
case s
|
123
|
-
when Syntax
|
124
|
-
new_s = s.class[s.map{|k, v| [k, infix_convert(v, parser)]}]
|
125
|
-
if s.is_a?(OperatorSeq)
|
126
|
-
items = Items.new(new_s[:seq].map{|c| Item.new(c, nil)})
|
127
|
-
res = parser.parse(items)
|
128
|
-
if res.is_a?(Fail)
|
129
|
-
raise "operator parsing fail!!"
|
130
|
-
end
|
131
|
-
res.parsed
|
132
|
-
else
|
133
|
-
new_s
|
134
|
-
end
|
135
|
-
when Array
|
136
|
-
s.map{|c| infix_convert(c, parser)}
|
137
|
-
else
|
138
|
-
s
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
def err(place, required, code=nil)
|
143
|
-
self.onfail(:place => place, :required => required, :code => code)
|
144
|
-
end
|
145
|
-
|
146
|
-
def to_nil
|
147
|
-
self.map{|x| x[0]}
|
148
|
-
end
|
149
|
-
end
|
150
|
-
end
|
1
|
+
require 'parser_combinator/string_parser'
|
2
|
+
|
3
|
+
require 'emfrp/syntax'
|
4
|
+
require 'emfrp/parser/toplevel'
|
5
|
+
require 'emfrp/parser/expression'
|
6
|
+
require 'emfrp/parser/misc'
|
7
|
+
require 'emfrp/parser/operator'
|
8
|
+
require 'emfrp/parser/parsing_error'
|
9
|
+
require 'emfrp/parser/newnode_convert'
|
10
|
+
|
11
|
+
module Emfrp
|
12
|
+
class Parser < ParserCombinator::StringParser
|
13
|
+
def self.parse_input(path, file_loader, file_type=module_file)
|
14
|
+
if file_loader.loaded?(path)
|
15
|
+
return Top.new
|
16
|
+
end
|
17
|
+
src_str, file_name = file_loader.load(path)
|
18
|
+
parse_src(src_str, file_name, file_loader, file_type)
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.parse_src(src_str, file_name, file_loader, file_type=module_file)
|
22
|
+
case res = file_type.parse_from_string(convert_case_group(src_str), file_name)
|
23
|
+
when Fail
|
24
|
+
raise ParsingError.new(src_str, file_name, res.status)
|
25
|
+
when Ok
|
26
|
+
newnode_tops = res.parsed[:newnodes].map do |newnode|
|
27
|
+
NewNodeConvert.parse_module(res.parsed[:module_name][:desc], newnode, file_loader)
|
28
|
+
end
|
29
|
+
res.parsed[:newnodes] = []
|
30
|
+
tops = res.parsed[:uses].map do |use_path|
|
31
|
+
parse_input(use_path.map{|x| x[:desc]}, file_loader, material_file)
|
32
|
+
end
|
33
|
+
return Top.new(*tops, res.parsed, *newnode_tops)
|
34
|
+
else
|
35
|
+
raise "unexpected return of parser (bug)"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.parse(src_str, file_name, parser)
|
40
|
+
case res = parser.parse_from_string(convert_case_group(src_str), file_name)
|
41
|
+
when Fail
|
42
|
+
raise ParsingError.new(src_str, file_name, res.status)
|
43
|
+
when Ok
|
44
|
+
return res.parsed
|
45
|
+
else
|
46
|
+
raise "unexpected return of parser (bug)"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.convert_case_group(src_str)
|
51
|
+
raise ParsingError.new("TAB is not allowed to use in sources.") if src_str.chars.include?("\t")
|
52
|
+
lines = src_str.each_line.to_a.map(&:chomp)
|
53
|
+
len = lines.length
|
54
|
+
len.times do |ln|
|
55
|
+
if lines[ln].strip.chars.last == ":"
|
56
|
+
width = lines[ln].chars.take_while{|c| c == "\s"}.size
|
57
|
+
((ln+1)..(len-1)).each do |ln2|
|
58
|
+
width2 = lines[ln2].chars.take_while{|c| c == "\s"}.size
|
59
|
+
if lines[ln2].strip == ""
|
60
|
+
next
|
61
|
+
elsif width2 <= width
|
62
|
+
lines[ln2 - 1] << " :endcase"
|
63
|
+
break
|
64
|
+
elsif ln2 == len - 1
|
65
|
+
lines[ln2] << " :endcase"
|
66
|
+
break
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
lines.map{|l| l + "\n"}.join
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.from_infixes_to_parser(infixes)
|
75
|
+
priority_listl = [[], [], [], [], [], [], [], [], [], []]
|
76
|
+
priority_listr = [[], [], [], [], [], [], [], [], [], []]
|
77
|
+
priority_listn = [[], [], [], [], [], [], [], [], [], []]
|
78
|
+
defined_op = {}
|
79
|
+
infixes.reverse.each do |id|
|
80
|
+
if defined_op[id[:op][:desc]]
|
81
|
+
next
|
82
|
+
else
|
83
|
+
defined_op[id[:op][:desc]] = true
|
84
|
+
end
|
85
|
+
if id[:priority] == nil || ("0" <= id[:priority][:desc] && id[:priority][:desc] <= "9")
|
86
|
+
priority = id[:priority] == nil ? 9 : id[:priority][:desc].to_i
|
87
|
+
opp = sat{|i| i.is_a?(SSymbol) && i[:desc] == id[:op][:desc]}.map(&:item)
|
88
|
+
if id[:type][:desc] == "infix"
|
89
|
+
priority_listn[priority] << opp
|
90
|
+
elsif id[:type][:desc] == "infixl"
|
91
|
+
priority_listl[priority] << opp
|
92
|
+
elsif id[:type][:desc] == "infixr"
|
93
|
+
priority_listr[priority] << opp
|
94
|
+
else
|
95
|
+
raise "invalid infix type"
|
96
|
+
end
|
97
|
+
else
|
98
|
+
raise "invalid prirority"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
priority_list = [{:op => sat{|i| i.is_a?(SSymbol)}.map(&:item), :dir => "left"}]
|
102
|
+
10.times do |i|
|
103
|
+
if priority_listl[i].length > 0
|
104
|
+
priority_list << {:op => priority_listl[i].inject(&:|), :dir => "left"}
|
105
|
+
end
|
106
|
+
if priority_listr[i].length > 0
|
107
|
+
priority_list << {:op => priority_listr[i].inject(&:|), :dir => "right"}
|
108
|
+
end
|
109
|
+
if priority_listn[i].length > 0
|
110
|
+
priority_list << {:op => priority_listn[i].inject(&:|), :dir => "left"}
|
111
|
+
end
|
112
|
+
end
|
113
|
+
return OpParser.make_op_parser(priority_list)
|
114
|
+
end
|
115
|
+
|
116
|
+
def self.infix_rearrange(top)
|
117
|
+
infix_parser = from_infixes_to_parser(top[:infixes])
|
118
|
+
return infix_convert(top, infix_parser)
|
119
|
+
end
|
120
|
+
|
121
|
+
def self.infix_convert(s, parser)
|
122
|
+
case s
|
123
|
+
when Syntax
|
124
|
+
new_s = s.class[s.map{|k, v| [k, infix_convert(v, parser)]}]
|
125
|
+
if s.is_a?(OperatorSeq)
|
126
|
+
items = Items.new(new_s[:seq].map{|c| Item.new(c, nil)})
|
127
|
+
res = parser.parse(items)
|
128
|
+
if res.is_a?(Fail)
|
129
|
+
raise "operator parsing fail!!"
|
130
|
+
end
|
131
|
+
res.parsed
|
132
|
+
else
|
133
|
+
new_s
|
134
|
+
end
|
135
|
+
when Array
|
136
|
+
s.map{|c| infix_convert(c, parser)}
|
137
|
+
else
|
138
|
+
s
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def err(place, required, code=nil)
|
143
|
+
self.onfail(:place => place, :required => required, :code => code)
|
144
|
+
end
|
145
|
+
|
146
|
+
def to_nil
|
147
|
+
self.map{|x| x[0]}
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
@@ -1,49 +1,49 @@
|
|
1
|
-
require 'colorize'
|
2
|
-
|
3
|
-
module Emfrp
|
4
|
-
class Parser
|
5
|
-
class ParsingError < StandardError
|
6
|
-
def initialize(src_str, file_name, status)
|
7
|
-
@src_str = src_str
|
8
|
-
@file_name = file_name
|
9
|
-
@status = status
|
10
|
-
end
|
11
|
-
|
12
|
-
def code
|
13
|
-
@status.message[:code] || :noname
|
14
|
-
end
|
15
|
-
|
16
|
-
def line_number
|
17
|
-
if @status.rest.length > 0
|
18
|
-
@status.rest[0].tag[:line_number]
|
19
|
-
else
|
20
|
-
@src_str.each_line.count
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def column_number
|
25
|
-
if @status.rest.length > 0
|
26
|
-
@status.rest[0].tag[:column_number]
|
27
|
-
else
|
28
|
-
@src_str.each_line.last.length
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def line
|
33
|
-
@src_str.each_line.to_a[line_number - 1]
|
34
|
-
end
|
35
|
-
|
36
|
-
def print_error(output_io)
|
37
|
-
output_io << "#{@file_name}:#{line_number}: "
|
38
|
-
output_io << "SyntaxError, in `#{@status.message[:place]}`: "
|
39
|
-
output_io << "#{@status.message[:required]} is expected"
|
40
|
-
if @status.rest.length == 0
|
41
|
-
output_io << ", but parser reached end-of-file\n"
|
42
|
-
else
|
43
|
-
output_io << "\n#{line.chomp}\n"
|
44
|
-
output_io << "#{" " * (column_number - 1)}#{"^".colorize(:green)}\n"
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
1
|
+
require 'colorize'
|
2
|
+
|
3
|
+
module Emfrp
|
4
|
+
class Parser
|
5
|
+
class ParsingError < StandardError
|
6
|
+
def initialize(src_str, file_name, status)
|
7
|
+
@src_str = src_str
|
8
|
+
@file_name = file_name
|
9
|
+
@status = status
|
10
|
+
end
|
11
|
+
|
12
|
+
def code
|
13
|
+
@status.message[:code] || :noname
|
14
|
+
end
|
15
|
+
|
16
|
+
def line_number
|
17
|
+
if @status.rest.length > 0
|
18
|
+
@status.rest[0].tag[:line_number]
|
19
|
+
else
|
20
|
+
@src_str.each_line.count
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def column_number
|
25
|
+
if @status.rest.length > 0
|
26
|
+
@status.rest[0].tag[:column_number]
|
27
|
+
else
|
28
|
+
@src_str.each_line.last.length
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def line
|
33
|
+
@src_str.each_line.to_a[line_number - 1]
|
34
|
+
end
|
35
|
+
|
36
|
+
def print_error(output_io)
|
37
|
+
output_io << "#{@file_name}:#{line_number}: "
|
38
|
+
output_io << "SyntaxError, in `#{@status.message[:place]}`: "
|
39
|
+
output_io << "#{@status.message[:required]} is expected"
|
40
|
+
if @status.rest.length == 0
|
41
|
+
output_io << ", but parser reached end-of-file\n"
|
42
|
+
else
|
43
|
+
output_io << "\n#{line.chomp}\n"
|
44
|
+
output_io << "#{" " * (column_number - 1)}#{"^".colorize(:green)}\n"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|