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
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
|