sfrp 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
data/lib/sfrp/error.rb
ADDED
data/lib/sfrp/file.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'sfrp/error'
|
2
|
+
|
3
|
+
module SFRP
|
4
|
+
VirtualFile = Struct.new(:fmodule_uri, :file_ext, :content)
|
5
|
+
SourceFile = Struct.new(:fmodule_uri, :content)
|
6
|
+
|
7
|
+
class FileResolveError < CompileError
|
8
|
+
def initialize(fmodule_uri, include_paths)
|
9
|
+
@fmodule_uri = fmodule_uri
|
10
|
+
@include_paths = include_paths
|
11
|
+
end
|
12
|
+
|
13
|
+
def message
|
14
|
+
"cannot find '#{@fmodule_uri}' in include paths:\n" +
|
15
|
+
@include_paths.join("\n")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module SFRP
|
2
|
+
module Flat
|
3
|
+
extend SFRP::F = self
|
4
|
+
|
5
|
+
def t(tconst_str, args, sp = nil)
|
6
|
+
TypeAnnotationType.new(tconst_str, args, sp)
|
7
|
+
end
|
8
|
+
|
9
|
+
def tv(var_str, sp = nil)
|
10
|
+
TypeAnnotationVar.new(var_str, sp)
|
11
|
+
end
|
12
|
+
|
13
|
+
def ft(ret_t, arg_ts)
|
14
|
+
FuncTypeAnnotation.new(ret_t, arg_ts)
|
15
|
+
end
|
16
|
+
|
17
|
+
def v_e(var_str, sp = nil)
|
18
|
+
VarRefExp.new(var_str, sp)
|
19
|
+
end
|
20
|
+
|
21
|
+
def nr_e(node_str, last, sp = nil)
|
22
|
+
NodeRefExp.new(node_str, last, sp)
|
23
|
+
end
|
24
|
+
|
25
|
+
def call_e(func_str, args, sp = nil)
|
26
|
+
FuncCallExp.new(func_str, args, sp)
|
27
|
+
end
|
28
|
+
|
29
|
+
def vc_call_e(vconst_str, args, sp = nil)
|
30
|
+
VConstCallExp.new(vconst_str, args, sp)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module SFRP
|
2
|
+
module Flat
|
3
|
+
class Function < Struct.new(:str, :ret_ta, :pstrs, :ptas, :exp, :ffi_str, :sp)
|
4
|
+
def to_poly(_src_set, dest_set)
|
5
|
+
pstrs.reject(&:nil?).each do |s|
|
6
|
+
raise DuplicatedVariableError.new(s) if pstrs.count(s) > 1
|
7
|
+
end
|
8
|
+
dest_set << P.func(str, ret_ta && ret_ta.to_poly) do |f|
|
9
|
+
pstrs.zip(ptas) do |s, ta|
|
10
|
+
f.param(s, ta && ta.to_poly)
|
11
|
+
end
|
12
|
+
if exp
|
13
|
+
f.exp do
|
14
|
+
table = Hash[pstrs.map { |s| [s, s] }]
|
15
|
+
exp.alpha_convert(table, (0..1000).to_a).to_poly
|
16
|
+
end
|
17
|
+
end
|
18
|
+
f.ffi_str(ffi_str) if ffi_str
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class TConst < Struct.new(:str, :pstrs, :vc_strs, :native_str, :static, :sp)
|
24
|
+
def type_annot
|
25
|
+
TypeAnnotationType.new(str, pstrs.map { |s| TypeAnnotationVar.new(s) })
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_poly(_src_set, dest_set)
|
29
|
+
argc = pstrs.size
|
30
|
+
dest_set << Poly::TConst.new(str, argc, vc_strs, static, native_str)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class VConst < Struct.new(:str, :tconst_str, :native_str, :param_tas, :sp)
|
35
|
+
def to_poly(src_set, dest_set)
|
36
|
+
tconst = src_set.tconst(tconst_str)
|
37
|
+
fta = FuncTypeAnnotation.new(tconst.type_annot, param_tas)
|
38
|
+
dest_set << Poly::VConst.new(str, tconst.pstrs, fta.to_poly, native_str)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class Node < Struct.new(:str, :ta, :exp, :init_exp, :sp)
|
43
|
+
def initialized?
|
44
|
+
!init_exp.nil?
|
45
|
+
end
|
46
|
+
|
47
|
+
def to_poly(src_set, dest_set)
|
48
|
+
dest_set << P.node(str, ta && ta.to_poly) do |n|
|
49
|
+
collected_node_refs = []
|
50
|
+
poly_exp = exp.alpha_convert({}, (0..1000).to_a)
|
51
|
+
.lift_node_ref(collected_node_refs).to_poly
|
52
|
+
collected_node_refs.each do |nr|
|
53
|
+
if nr.last && !src_set.node(nr.node_str).initialized?
|
54
|
+
raise NodeInvalidLastReferrenceError.new(nr.node_str)
|
55
|
+
end
|
56
|
+
nr.last ? n.l(nr.node_str) : n.c(nr.node_str)
|
57
|
+
end
|
58
|
+
dest_set << n.eval_func(str, ta && ta.to_poly) do |f|
|
59
|
+
f.exp { poly_exp }
|
60
|
+
collected_node_refs.each_with_index.map do |_, i|
|
61
|
+
f.param("__node_ref_#{i}")
|
62
|
+
end
|
63
|
+
end
|
64
|
+
next if init_exp.nil?
|
65
|
+
dest_set << n.init_func(str + '#init', ta && ta.to_poly) do |f|
|
66
|
+
f.exp { init_exp.alpha_convert({}, (0..1000).to_a).to_poly }
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
class FuncTypeAnnotation < Struct.new(:ret_ta, :arg_tas, :sp)
|
73
|
+
def to_poly
|
74
|
+
Poly::FuncTypeAnnotation.new(ret_ta.to_poly, arg_tas.map(&:to_poly))
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
class TypeAnnotationType < Struct.new(:tconst_str, :arg_tas, :sp)
|
79
|
+
def to_poly
|
80
|
+
P.t(tconst_str, *arg_tas.map(&:to_poly))
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
class TypeAnnotationVar < Struct.new(:var_str, :sp)
|
85
|
+
def to_poly
|
86
|
+
P.tv(var_str)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'sfrp/error'
|
2
|
+
|
3
|
+
module SFRP
|
4
|
+
module Flat
|
5
|
+
class NodeRefInIllegalPositionError < CompileError
|
6
|
+
def initialize(node_str)
|
7
|
+
@node_str = node_str
|
8
|
+
end
|
9
|
+
|
10
|
+
def message
|
11
|
+
"don't refer node '#{@node_str}'"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class DuplicatedVariableError < CompileError
|
16
|
+
def initialize(var_str)
|
17
|
+
@var_str = var_str
|
18
|
+
end
|
19
|
+
|
20
|
+
def message
|
21
|
+
"duplicated variable '#{@var_str}'"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class UnboundLocalVariableError < CompileError
|
26
|
+
def initialize(var_str)
|
27
|
+
@var_str = var_str
|
28
|
+
end
|
29
|
+
|
30
|
+
def message
|
31
|
+
"unbound variable '#{@var_str}'"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class NodeInvalidLastReferrenceError < CompileError
|
36
|
+
def initialize(node_str)
|
37
|
+
@node_str = node_str
|
38
|
+
end
|
39
|
+
|
40
|
+
def message
|
41
|
+
"node '#{@node_str}' should be initialized"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
module SFRP
|
2
|
+
module Flat
|
3
|
+
class FuncCallExp < Struct.new(:func_str, :arg_exps, :sp)
|
4
|
+
def lift_node_ref(collected_node_refs)
|
5
|
+
args = arg_exps.map { |e| e.lift_node_ref(collected_node_refs) }
|
6
|
+
FuncCallExp.new(func_str, args, sp)
|
7
|
+
end
|
8
|
+
|
9
|
+
def alpha_convert(table, serial)
|
10
|
+
args = arg_exps.map { |e| e.alpha_convert(table, serial) }
|
11
|
+
FuncCallExp.new(func_str, args)
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_poly
|
15
|
+
P.call_e(func_str, *arg_exps.map(&:to_poly))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class VConstCallExp < Struct.new(:vconst_str, :arg_exps, :sp)
|
20
|
+
def lift_node_ref(collected_node_refs)
|
21
|
+
args = arg_exps.map { |e| e.lift_node_ref(collected_node_refs) }
|
22
|
+
VConstCallExp.new(vconst_str, args, sp)
|
23
|
+
end
|
24
|
+
|
25
|
+
def alpha_convert(table, serial)
|
26
|
+
args = arg_exps.map { |e| e.alpha_convert(table, serial) }
|
27
|
+
VConstCallExp.new(vconst_str, args)
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_poly
|
31
|
+
P.vc_call_e(vconst_str, *arg_exps.map(&:to_poly))
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class NodeRefExp < Struct.new(:node_str, :last, :sp)
|
36
|
+
NodeRef = Struct.new(:node_str, :last)
|
37
|
+
|
38
|
+
def lift_node_ref(collected_node_refs)
|
39
|
+
node_ref = NodeRef.new(node_str, last)
|
40
|
+
unless collected_node_refs.include?(node_ref)
|
41
|
+
collected_node_refs << node_ref
|
42
|
+
end
|
43
|
+
VarRefExp.new("__node_ref_#{collected_node_refs.index(node_ref)}", sp)
|
44
|
+
end
|
45
|
+
|
46
|
+
def alpha_convert(_table, _serial)
|
47
|
+
self
|
48
|
+
end
|
49
|
+
|
50
|
+
def to_poly
|
51
|
+
raise NodeRefInIllegalPositionError.new(node_str)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class MatchExp < Struct.new(:left_exp, :cases, :sp)
|
56
|
+
Case = Struct.new(:pattern, :exp)
|
57
|
+
|
58
|
+
class Pattern < Struct.new(:vconst_str, :ref_var_str, :args, :sp)
|
59
|
+
def alpha_convert(table, serial)
|
60
|
+
new_ref_var_str =
|
61
|
+
ref_var_str && (table[ref_var_str] = "_alpha#{serial.shift}")
|
62
|
+
new_args = args.map { |a| a.alpha_convert(table, serial) }
|
63
|
+
Pattern.new(vconst_str, new_ref_var_str, new_args)
|
64
|
+
end
|
65
|
+
|
66
|
+
def var_strs
|
67
|
+
[ref_var_str, *args.flat_map(&:var_strs)].reject(&:nil?)
|
68
|
+
end
|
69
|
+
|
70
|
+
def duplicated_var_check
|
71
|
+
vstrs = var_strs
|
72
|
+
vstrs.each do |s|
|
73
|
+
raise DuplicatedVariableError.new(s) if vstrs.count(s) > 1
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def to_poly
|
78
|
+
Poly::Pattern.new(vconst_str, ref_var_str, args.map(&:to_poly))
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def lift_node_ref(collected_node_refs)
|
83
|
+
new_left_exp = left_exp.lift_node_ref(collected_node_refs)
|
84
|
+
new_cases = cases.map do |c|
|
85
|
+
Case.new(c.pattern, c.exp.lift_node_ref(collected_node_refs))
|
86
|
+
end
|
87
|
+
MatchExp.new(new_left_exp, new_cases, sp)
|
88
|
+
end
|
89
|
+
|
90
|
+
def alpha_convert(table, serial)
|
91
|
+
new_left_exp = left_exp.alpha_convert(table, serial)
|
92
|
+
new_cases = cases.map do |c|
|
93
|
+
c.pattern.duplicated_var_check
|
94
|
+
new_table = table.clone
|
95
|
+
new_pattern = c.pattern.alpha_convert(new_table, serial)
|
96
|
+
new_exp = c.exp.alpha_convert(new_table, serial)
|
97
|
+
Case.new(new_pattern, new_exp)
|
98
|
+
end
|
99
|
+
MatchExp.new(new_left_exp, new_cases)
|
100
|
+
end
|
101
|
+
|
102
|
+
def to_poly
|
103
|
+
poly_cases = cases.map do |c|
|
104
|
+
Poly::MatchExp::Case.new(c.pattern.to_poly, c.exp.to_poly)
|
105
|
+
end
|
106
|
+
Poly::MatchExp.new(left_exp.to_poly, poly_cases)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
class VarRefExp < Struct.new(:var_str, :sp)
|
111
|
+
def lift_node_ref(_collected_node_refs)
|
112
|
+
self
|
113
|
+
end
|
114
|
+
|
115
|
+
def alpha_convert(table, _)
|
116
|
+
raise UnboundLocalVariableError.new(var_str) unless table.key?(var_str)
|
117
|
+
VarRefExp.new(table[var_str])
|
118
|
+
end
|
119
|
+
|
120
|
+
def to_poly
|
121
|
+
P.v_e(var_str)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'sfrp/flat/elements'
|
2
|
+
require 'sfrp/flat/exception'
|
3
|
+
require 'sfrp/flat/expression'
|
4
|
+
require 'sfrp/flat/dsl'
|
5
|
+
|
6
|
+
module SFRP
|
7
|
+
module Flat
|
8
|
+
class Set
|
9
|
+
def initialize(&block)
|
10
|
+
@funcs = []
|
11
|
+
@tconsts = []
|
12
|
+
@vconsts = []
|
13
|
+
@nodes = []
|
14
|
+
@output_node_strs = []
|
15
|
+
@init_func_strs = []
|
16
|
+
block.call(self) if block
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_poly
|
20
|
+
Poly::Set.new do |dest_set|
|
21
|
+
(@funcs + @tconsts + @vconsts + @nodes).each do |element|
|
22
|
+
element.to_poly(self, dest_set)
|
23
|
+
end
|
24
|
+
@output_node_strs.each { |s| dest_set.append_output_node_str(s) }
|
25
|
+
@init_func_strs.each { |s| dest_set.append_init_func_str(s) }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def append_output_node_str(node_str)
|
30
|
+
@output_node_strs << node_str
|
31
|
+
end
|
32
|
+
|
33
|
+
def append_init_func_str(init_func_str)
|
34
|
+
@init_func_strs << init_func_str
|
35
|
+
end
|
36
|
+
|
37
|
+
def <<(element)
|
38
|
+
case element
|
39
|
+
when Function
|
40
|
+
@funcs << element
|
41
|
+
when TConst
|
42
|
+
@tconsts << element
|
43
|
+
when VConst
|
44
|
+
@vconsts << element
|
45
|
+
when Node
|
46
|
+
@nodes << element
|
47
|
+
else
|
48
|
+
raise
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def tconst(str)
|
53
|
+
@tconsts.find { |tconst| tconst.str == str }
|
54
|
+
end
|
55
|
+
|
56
|
+
def node(str)
|
57
|
+
@nodes.find { |node| node.str == str }
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'sfrp/error'
|
2
|
+
|
3
|
+
module SFRP
|
4
|
+
module Input
|
5
|
+
class ParseError < CompileError
|
6
|
+
def initialize(message)
|
7
|
+
@message = message
|
8
|
+
end
|
9
|
+
|
10
|
+
def message
|
11
|
+
"Syntax error. The raw error message from Parslet is as follows:\n" +
|
12
|
+
@message
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,417 @@
|
|
1
|
+
require 'sfrp/input/exception'
|
2
|
+
require 'parslet'
|
3
|
+
|
4
|
+
module SFRP
|
5
|
+
module Input
|
6
|
+
module Parser
|
7
|
+
extend self
|
8
|
+
|
9
|
+
def parse(source_file)
|
10
|
+
parser = Parser.new
|
11
|
+
transformer = Transformer.new
|
12
|
+
defs = transformer.apply(parser.parse(source_file.content))
|
13
|
+
imports, others = defs.each_with_object([[], []]) do |a, o|
|
14
|
+
case a
|
15
|
+
when Raw::Import
|
16
|
+
o[0] << a
|
17
|
+
else
|
18
|
+
o[1] << a
|
19
|
+
end
|
20
|
+
end
|
21
|
+
ns = Raw::Namespace.new(source_file.fmodule_uri, imports)
|
22
|
+
others.each do |a|
|
23
|
+
a.ns = ns
|
24
|
+
a.vconsts.each { |b| b.ns = ns } if a.is_a?(Raw::TConst)
|
25
|
+
end
|
26
|
+
others
|
27
|
+
rescue Parslet::ParseFailed => err
|
28
|
+
raise ParseError.new(err.cause.ascii_tree)
|
29
|
+
end
|
30
|
+
|
31
|
+
class Parser < Parslet::Parser
|
32
|
+
# file
|
33
|
+
root(:file)
|
34
|
+
rule(:file) {
|
35
|
+
(ws? >> listing(toplevel_definition, ws_inc_newline).as(:defs) >> ws?)
|
36
|
+
.as(:file)
|
37
|
+
}
|
38
|
+
|
39
|
+
# toplevel definition
|
40
|
+
rule(:toplevel_definition) {
|
41
|
+
import_def |
|
42
|
+
init_def |
|
43
|
+
prim_type_def | prim_enum_type_def | type_def |
|
44
|
+
foreign_func_def | function_def | infix_def |
|
45
|
+
node_def | input_def | output_def
|
46
|
+
}
|
47
|
+
rule(:import_def) {
|
48
|
+
(str('import') >> ws >> listing(up_ident, str('.')).as(:path) >>
|
49
|
+
(ws >> str('as') >> ws >> up_ident.as(:qualifier_name))
|
50
|
+
.maybe.as(:as_maybe)).as(:import_def)
|
51
|
+
}
|
52
|
+
rule(:init_def) {
|
53
|
+
(str('init').as(:key) >> ws >> io_func_ref.as(:func_ref) >>
|
54
|
+
ws_inline? >>
|
55
|
+
str('(') >> ws? >> listing0(exp, ws? >> str(',') >> ws?).as(:args) >>
|
56
|
+
ws? >> str(')')).as(:init_def)
|
57
|
+
}
|
58
|
+
rule(:prim_type_def) {
|
59
|
+
(str('ptype') >> ws >> up_ident.as(:tconst_str) >> ws? >>
|
60
|
+
foreign_str.as(:c_type_str) >> ws? >> str('=') >> ws? >>
|
61
|
+
str('/') >> match['^/'].repeat(1).as(:rexp) >> str('/') >>
|
62
|
+
match['^/'].repeat(1).as(:replace) >> str('/')).as(:prim_type_def)
|
63
|
+
}
|
64
|
+
rule(:prim_enum_type_def) {
|
65
|
+
(str('ptype') >> ws >> up_ident.as(:tconst_str) >> ws? >>
|
66
|
+
foreign_str.as(:c_type_str) >> ws? >> str('=') >> ws? >>
|
67
|
+
listing(prim_enum_vconst_def, ws? >> str('|') >> ws?)
|
68
|
+
.as(:vconst_defs)).as(:prim_enum_type_def)
|
69
|
+
}
|
70
|
+
rule(:prim_enum_vconst_def) {
|
71
|
+
(up_ident.as(:vconst_str) >> ws? >> foreign_str.as(:c_value_str))
|
72
|
+
.as(:prim_enum_vconst_def)
|
73
|
+
}
|
74
|
+
rule(:type_def) {
|
75
|
+
tconst_params = (str('[') >> ws? >>
|
76
|
+
listing0(low_ident, ws? >> str(',') >> ws?).as(:params) >> ws? >>
|
77
|
+
str(']')).maybe.as(:params_maybe)
|
78
|
+
(str('type') >> ws? >> ((str('+') | str('*')).as(:m) >> ws?)
|
79
|
+
.maybe.as(:modifier) >> up_ident.as(:tconst_name) >> ws_inline? >>
|
80
|
+
tconst_params >> ws? >> str('=') >> ws? >> listing(vconst_def,
|
81
|
+
ws? >> str('|') >> ws?).as(:vconst_defs)).as(:type_def)
|
82
|
+
}
|
83
|
+
rule(:vconst_def) {
|
84
|
+
(up_ident.as(:vconst_name) >>
|
85
|
+
(ws_inline? >> str('(') >> ws? >> listing0(type_annot, ws? >>
|
86
|
+
str(',') >> ws?).as(:type_annots) >> ws? >> str(')'))
|
87
|
+
.maybe.as(:type_annots_maybe)).as(:vconst_def)
|
88
|
+
}
|
89
|
+
rule(:foreign_func_def) {
|
90
|
+
(str('foreign') >> ws >>
|
91
|
+
(low_ident | up_ident | op_ident).as(:c_func_name) >> ws >>
|
92
|
+
str('as') >> ws >>
|
93
|
+
((str('$').maybe >> low_ident) | op_ident).as(:func_name) >>
|
94
|
+
ws_inline? >>
|
95
|
+
str('(') >> ws? >> listing0(fixed_type_annot, ws? >> str(',') >>
|
96
|
+
ws?).as(:params) >> ws? >>
|
97
|
+
str(')') >> ws? >> str(':') >> ws? >>
|
98
|
+
fixed_type_annot.as(:ret_type_annot))
|
99
|
+
.as(:foreign_func_def)
|
100
|
+
}
|
101
|
+
rule(:function_def) {
|
102
|
+
param = low_ident.as(:param_name) >> type_annot_maybe.as(:type_annot)
|
103
|
+
(((str('op') >> ws? >> op_ident.as(:func_name)) | (str('$').maybe >>
|
104
|
+
low_ident).as(:func_name)) >> ws_inline? >>
|
105
|
+
str('(') >> ws? >> listing0(param, ws? >> str(',') >> ws?)
|
106
|
+
.as(:params) >> ws? >>
|
107
|
+
str(')') >> type_annot_maybe.as(:ret_type_annot) >> ws? >> str('=') >>
|
108
|
+
ws? >> where_exp.as(:exp)).as(:function_def)
|
109
|
+
}
|
110
|
+
rule(:infix_def) {
|
111
|
+
(str('infix') >> (str('l') | str('r')).maybe.as(:direction) >>
|
112
|
+
ws >> (op_ref | bq_op_ref).as(:func_ref) >> ws >>
|
113
|
+
match['0-9'].repeat(1).as(:priority)).as(:infix_def)
|
114
|
+
}
|
115
|
+
rule(:node_def) {
|
116
|
+
((str('@') >> low_ident).as(:node_name) >>
|
117
|
+
init_def_maybe.as(:init_exp) >> type_annot_maybe.as(:type_annot) >>
|
118
|
+
ws? >> str('=') >> ws? >> where_exp.as(:eval_exp)).as(:node_def)
|
119
|
+
}
|
120
|
+
rule(:input_def) {
|
121
|
+
(str('in') >> ws >> (str('@') >> low_ident).as(:node_name) >>
|
122
|
+
init_def_maybe.as(:init_exp) >>
|
123
|
+
type_annot_maybe.as(:type_annot) >>
|
124
|
+
ws >> str('from') >> ws >> io_func_ref.as(:func_ref) >> ws_inline? >>
|
125
|
+
str('(') >> ws? >> listing0(exp, ws? >> str(',') >> ws?).as(:args) >>
|
126
|
+
ws? >> str(')')).as(:input_def)
|
127
|
+
}
|
128
|
+
rule(:output_def) {
|
129
|
+
(str('out').as(:key) >> ws >> io_func_ref.as(:func_ref) >>
|
130
|
+
ws_inline? >>
|
131
|
+
str('(') >> ws? >> listing(exp, ws? >> str(',') >> ws?).as(:args) >>
|
132
|
+
ws? >> str(')')).as(:output_def)
|
133
|
+
}
|
134
|
+
rule(:init_def_maybe) {
|
135
|
+
(ws? >> exp.as(:init_exp)).maybe.as(:init_def_maybe)
|
136
|
+
}
|
137
|
+
rule(:foreign_str) {
|
138
|
+
(str('{') >> match['^}'].repeat(1).as(:str) >> str('}'))
|
139
|
+
.as(:foreign_str)
|
140
|
+
}
|
141
|
+
|
142
|
+
# type annotation
|
143
|
+
rule(:type_annot_maybe) {
|
144
|
+
(ws? >> str(':') >> ws? >> type_annot).maybe.as(:type_annot_maybe)
|
145
|
+
}
|
146
|
+
rule(:type_annot) {
|
147
|
+
type_annot_type | type_annot_var | type_annot_tuple
|
148
|
+
}
|
149
|
+
rule(:type_annot_type) {
|
150
|
+
whole = tconst_ref.as(:tconst_ref) >> (ws_inline? >> str('[') >>
|
151
|
+
ws? >> listing0(type_annot, ws? >> str(',') >> ws?).as(:args) >>
|
152
|
+
ws? >> str(']')).maybe.as(:args_maybe)
|
153
|
+
whole.as(:type_annot_type)
|
154
|
+
}
|
155
|
+
rule(:type_annot_tuple) {
|
156
|
+
(str('(') >> ws? >> listing2(type_annot, ws? >> str(',') >> ws?)
|
157
|
+
.as(:args) >> ws? >> str(')')).as(:type_annot_tuple)
|
158
|
+
}
|
159
|
+
rule(:type_annot_var) {
|
160
|
+
low_ident.as(:type_annot_var)
|
161
|
+
}
|
162
|
+
|
163
|
+
# fixed type annotation
|
164
|
+
rule(:fixed_type_annot) {
|
165
|
+
fixed_type_annot_type | fixed_type_annot_tuple
|
166
|
+
}
|
167
|
+
rule(:fixed_type_annot_type) {
|
168
|
+
whole = tconst_ref.as(:tconst_ref) >> (ws_inline? >> str('[') >>
|
169
|
+
ws? >> listing0(fixed_type_annot, ws? >> str(',') >>
|
170
|
+
ws?).as(:args) >> ws? >> str(']')).maybe.as(:args_maybe)
|
171
|
+
whole.as(:type_annot_type)
|
172
|
+
}
|
173
|
+
rule(:fixed_type_annot_tuple) {
|
174
|
+
(str('(') >> ws? >> listing2(fixed_type_annot, ws? >> str(',') >>
|
175
|
+
ws?).as(:args) >> ws? >> str(')')).as(:type_annot_tuple)
|
176
|
+
}
|
177
|
+
|
178
|
+
# expression
|
179
|
+
rule(:exp) {
|
180
|
+
seq_exp
|
181
|
+
}
|
182
|
+
rule(:where_exp) {
|
183
|
+
whole = seq_exp.as(:exp) >> (ws >> str('where') >> ws >>
|
184
|
+
dynamic { |s, _|
|
185
|
+
indent = str("\s").repeat(s.line_and_column[1] - 1)
|
186
|
+
separator = (ws_inline? >> newline >> indent) | ws? >> str(';') >> ws?
|
187
|
+
listing(assign, separator).as(:assignments)
|
188
|
+
}).maybe.as(:where_clause_maybe)
|
189
|
+
whole.as(:where_exp)
|
190
|
+
}
|
191
|
+
rule(:seq_exp) {
|
192
|
+
whole = single_exp.as(:exp) >> (ws? >>
|
193
|
+
(op_ref | bq_op_ref).as(:func_ref) >> ws? >>
|
194
|
+
single_exp.as(:exp)).repeat
|
195
|
+
whole.as(:seq_exp)
|
196
|
+
}
|
197
|
+
rule(:single_exp) {
|
198
|
+
# controling
|
199
|
+
if_exp | let_exp | match_exp | unary_op_exp |
|
200
|
+
# calling
|
201
|
+
func_call_exp | io_func_call_exp |
|
202
|
+
vc_call_exp_with_paren | vc_call_exp_without_paren |
|
203
|
+
tuple_exp |
|
204
|
+
# reference
|
205
|
+
node_last_ref_exp | node_current_ref_exp | var_ref_exp |
|
206
|
+
# parenthesis
|
207
|
+
str('(') >> ws? >> exp >> ws? >> str(')')
|
208
|
+
}
|
209
|
+
|
210
|
+
# ref exp
|
211
|
+
rule(:node_last_ref_exp) {
|
212
|
+
node_last_ref.as(:node_ref).as(:node_last_ref_exp)
|
213
|
+
}
|
214
|
+
rule(:node_current_ref_exp) {
|
215
|
+
node_current_ref.as(:node_ref).as(:node_current_ref_exp)
|
216
|
+
}
|
217
|
+
rule(:var_ref_exp) {
|
218
|
+
low_ident.as(:var_ref_exp)
|
219
|
+
}
|
220
|
+
|
221
|
+
# call exp
|
222
|
+
rule(:func_call_exp) {
|
223
|
+
whole = func_ref.as(:func_ref) >> ws_inline? >>
|
224
|
+
paren(listing0(exp, ws? >> str(',') >> ws?)).as(:args)
|
225
|
+
whole.as(:func_call_exp)
|
226
|
+
}
|
227
|
+
rule(:io_func_call_exp) {
|
228
|
+
whole = io_func_ref.as(:func_ref) >> ws_inline? >>
|
229
|
+
paren(listing0(exp, ws? >> str(',') >> ws?)).as(:args)
|
230
|
+
whole.as(:io_func_call_exp)
|
231
|
+
}
|
232
|
+
rule(:vc_call_exp_with_paren) {
|
233
|
+
whole = vconst_ref.as(:vconst_ref) >> ws_inline? >> str('(') >> ws? >>
|
234
|
+
listing0(exp, ws? >> str(',') >> ws?).as(:args) >> ws? >> str(')')
|
235
|
+
whole.as(:vc_call_exp_with_paren)
|
236
|
+
}
|
237
|
+
rule(:vc_call_exp_without_paren) {
|
238
|
+
vconst_ref.as(:vconst_ref).as(:vc_call_exp_without_paren)
|
239
|
+
}
|
240
|
+
rule(:tuple_exp) {
|
241
|
+
whole = str('(') >> ws? >>
|
242
|
+
listing2(exp, ws? >> str(',') >> ws?).as(:args) >>
|
243
|
+
ws? >> str(')')
|
244
|
+
whole.as(:tuple_exp)
|
245
|
+
}
|
246
|
+
|
247
|
+
# if exp
|
248
|
+
rule(:if_exp) {
|
249
|
+
whole = str('if') >> ws >> exp.as(:cond_exp) >> ws >> str('then') >>
|
250
|
+
ws >> exp.as(:then_exp) >> ws >> str('else') >> ws >>
|
251
|
+
exp.as(:else_exp)
|
252
|
+
whole.as(:if_exp)
|
253
|
+
}
|
254
|
+
|
255
|
+
# let exp
|
256
|
+
rule(:let_exp) {
|
257
|
+
whole = str('let') >> ws >> dynamic { |s, _|
|
258
|
+
indent = str("\s").repeat(s.line_and_column[1] - 1)
|
259
|
+
separator = (ws_inline? >> newline >> indent) | ws? >> str(';') >> ws?
|
260
|
+
listing(assign, separator).as(:assignments)
|
261
|
+
} >> ws >> str('in') >> ws >> exp.as(:in_exp)
|
262
|
+
whole.as(:let_exp)
|
263
|
+
}
|
264
|
+
rule(:assign) {
|
265
|
+
whole = pattern.as(:left_pattern) >> ws? >> str('=') >> ws? >>
|
266
|
+
(where_exp | exp).as(:right_exp)
|
267
|
+
whole.as(:assign)
|
268
|
+
}
|
269
|
+
|
270
|
+
# match exp
|
271
|
+
rule(:match_exp) {
|
272
|
+
whole = str('case') >> ws >> exp.as(:left_exp) >> ws >> str('of') >>
|
273
|
+
ws? >> dynamic { |s, _|
|
274
|
+
indent = str("\s").repeat(s.line_and_column[1] - 1)
|
275
|
+
separator = (ws_inline? >> newline >> indent) | ws? >> str(';') >> ws?
|
276
|
+
listing(match_case, separator).as(:cases)
|
277
|
+
}
|
278
|
+
whole.as(:match_exp)
|
279
|
+
}
|
280
|
+
rule(:match_case) {
|
281
|
+
(
|
282
|
+
pattern.as(:pattern) >> ws? >> str('->') >> ws? >> exp.as(:exp)
|
283
|
+
).as(:match_case)
|
284
|
+
}
|
285
|
+
|
286
|
+
# unary op exp
|
287
|
+
rule(:unary_op_exp) {
|
288
|
+
(op_ref.as(:func_ref) >> ws? >> single_exp.as(:exp))
|
289
|
+
.as(:unary_op_exp)
|
290
|
+
}
|
291
|
+
|
292
|
+
# pattern
|
293
|
+
rule(:pattern) {
|
294
|
+
vc_pattern_with_paren | vc_pattern_without_paren |
|
295
|
+
tuple_pattern | any_pattern
|
296
|
+
}
|
297
|
+
rule(:vc_pattern_with_paren) {
|
298
|
+
whole = vconst_ref.as(:vconst_ref) >> ws_inline? >> str('(') >> ws? >>
|
299
|
+
listing0(pattern, ws? >> str(',') >> ws?).as(:args) >> ws? >>
|
300
|
+
str(')') >> (ws? >> as).maybe.as(:var_ref)
|
301
|
+
whole.as(:vc_pattern_with_paren)
|
302
|
+
}
|
303
|
+
rule(:vc_pattern_without_paren) {
|
304
|
+
whole = vconst_ref.as(:vconst_ref) >> (ws? >> as).maybe.as(:var_ref)
|
305
|
+
whole.as(:vc_pattern_without_paren)
|
306
|
+
}
|
307
|
+
rule(:tuple_pattern) {
|
308
|
+
whole = str('(') >> ws? >>
|
309
|
+
listing2(pattern, ws? >> str(',') >> ws?).as(:args) >>
|
310
|
+
ws? >> str(')') >> (ws? >> as).maybe.as(:var_ref)
|
311
|
+
whole.as(:tuple_pattern)
|
312
|
+
}
|
313
|
+
rule(:any_pattern) {
|
314
|
+
low_ident.as(:any_pattern)
|
315
|
+
}
|
316
|
+
rule(:as) {
|
317
|
+
(str('as') >> ws? >> low_ident.as(:str)).as(:as)
|
318
|
+
}
|
319
|
+
|
320
|
+
# reference
|
321
|
+
rule(:node_last_ref) {
|
322
|
+
qualifier >> str('@') >> (str('@') >> low_ident).as(:name)
|
323
|
+
}
|
324
|
+
rule(:node_current_ref) {
|
325
|
+
qualifier >> (str('@') >> low_ident).as(:name)
|
326
|
+
}
|
327
|
+
rule(:func_ref) {
|
328
|
+
qualifier >> low_ident.as(:name)
|
329
|
+
}
|
330
|
+
rule(:io_func_ref) {
|
331
|
+
qualifier >> (str('$') >> low_ident).as(:name)
|
332
|
+
}
|
333
|
+
rule(:op_ref) {
|
334
|
+
qualifier >> op_ident.as(:name)
|
335
|
+
}
|
336
|
+
rule(:bq_op_ref) {
|
337
|
+
str('`') >> qualifier >> low_ident.as(:name) >> str('`')
|
338
|
+
}
|
339
|
+
rule(:vconst_ref) {
|
340
|
+
qualifier >> (up_ident | num_ident).as(:name)
|
341
|
+
}
|
342
|
+
rule(:tconst_ref) {
|
343
|
+
qualifier >> up_ident.as(:name)
|
344
|
+
}
|
345
|
+
rule(:qualifier) {
|
346
|
+
(up_ident.as(:str) >> str('.')).maybe.as(:qualifier)
|
347
|
+
}
|
348
|
+
|
349
|
+
rule(:num_ident) {
|
350
|
+
match['0-9'] >> match['a-zA-Z0-9.'].repeat
|
351
|
+
}
|
352
|
+
rule(:op_ident) {
|
353
|
+
enabled_char = "!#%&*+/<=>?\\^|-~'.".chars.map { |c| str(c) }.reduce(&:|)
|
354
|
+
enabled_char.repeat(1).capture(:name) >> dynamic { |_, c|
|
355
|
+
disabled_strs = ["=", "."]
|
356
|
+
disabled_strs.include?(c.captures[:name].to_s) ? str('*') : str('')
|
357
|
+
}
|
358
|
+
}
|
359
|
+
rule(:low_ident) {
|
360
|
+
(match['a-z_'] >> match['a-zA-Z0-9_'].repeat).capture(:name) >>
|
361
|
+
dynamic { |_, c|
|
362
|
+
keywords = ['from']
|
363
|
+
keywords.include?(c.captures[:name].to_s) ? str('a') : str('')
|
364
|
+
}
|
365
|
+
}
|
366
|
+
rule(:up_ident) {
|
367
|
+
match['A-Z'] >> match['a-zA-Z0-9_'].repeat
|
368
|
+
}
|
369
|
+
rule(:ws) {
|
370
|
+
(str("\s") | line_feed).repeat(1)
|
371
|
+
}
|
372
|
+
rule(:ws?) {
|
373
|
+
ws.maybe
|
374
|
+
}
|
375
|
+
rule(:ws_inline) {
|
376
|
+
str("\s").repeat(1)
|
377
|
+
}
|
378
|
+
rule(:ws_inline?) {
|
379
|
+
ws_inline.maybe
|
380
|
+
}
|
381
|
+
rule(:newline) {
|
382
|
+
line_feed.repeat(1)
|
383
|
+
}
|
384
|
+
rule(:line_feed) {
|
385
|
+
(str('--') >> (str("\n").absent? >> any).repeat).maybe >> str("\n")
|
386
|
+
}
|
387
|
+
rule(:ws_inc_newline) {
|
388
|
+
ws_inline? >> newline >> ws?
|
389
|
+
}
|
390
|
+
|
391
|
+
def listing(e, separator)
|
392
|
+
(e.as(:e) >> (separator >> e.as(:e)).repeat).as(:listing)
|
393
|
+
end
|
394
|
+
|
395
|
+
def listing0(e, separator)
|
396
|
+
listing(e, separator).maybe.as(:listing0)
|
397
|
+
end
|
398
|
+
|
399
|
+
def listing2(e, separator)
|
400
|
+
(e.as(:e) >> (separator >> e.as(:e)).repeat(1)).as(:listing)
|
401
|
+
end
|
402
|
+
|
403
|
+
def opt(left_separator, optional_rule)
|
404
|
+
(left_separator >> optional_rule.as(:entity)).maybe.as(:opt)
|
405
|
+
end
|
406
|
+
|
407
|
+
def paren(rule)
|
408
|
+
wrap('(', rule, ')')
|
409
|
+
end
|
410
|
+
|
411
|
+
def wrap(lstr, rule, rstr)
|
412
|
+
str(lstr) >> ws? >> rule >> ws? >> str(rstr)
|
413
|
+
end
|
414
|
+
end
|
415
|
+
end
|
416
|
+
end
|
417
|
+
end
|