sfrp 1.1.0

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.
Files changed (85) hide show
  1. checksums.yaml +7 -0
  2. data/.ctags +3 -0
  3. data/.editorconfig +9 -0
  4. data/.gitignore +14 -0
  5. data/.rubocop.yml +629 -0
  6. data/.travis.yml +12 -0
  7. data/Gemfile +2 -0
  8. data/LICENSE +28 -0
  9. data/README.md +34 -0
  10. data/Rakefile +1 -0
  11. data/base-library/Base.sfrp +81 -0
  12. data/base-library/IO/AVR/ATMEGA8.c +9 -0
  13. data/base-library/IO/AVR/ATMEGA8.h +6 -0
  14. data/base-library/IO/AVR/ATMEGA8.sfrp +4 -0
  15. data/base-library/IO/STDIO.c +40 -0
  16. data/base-library/IO/STDIO.h +13 -0
  17. data/base-library/IO/STDIO.sfrp +10 -0
  18. data/bin/sfrp +7 -0
  19. data/lib/sfrp.rb +2 -0
  20. data/lib/sfrp/command.rb +73 -0
  21. data/lib/sfrp/compiler.rb +94 -0
  22. data/lib/sfrp/error.rb +4 -0
  23. data/lib/sfrp/file.rb +18 -0
  24. data/lib/sfrp/flat/dsl.rb +33 -0
  25. data/lib/sfrp/flat/elements.rb +90 -0
  26. data/lib/sfrp/flat/exception.rb +45 -0
  27. data/lib/sfrp/flat/expression.rb +125 -0
  28. data/lib/sfrp/flat/set.rb +61 -0
  29. data/lib/sfrp/input/exception.rb +16 -0
  30. data/lib/sfrp/input/parser.rb +417 -0
  31. data/lib/sfrp/input/set.rb +29 -0
  32. data/lib/sfrp/input/transformer.rb +219 -0
  33. data/lib/sfrp/low/dsl.rb +126 -0
  34. data/lib/sfrp/low/element.rb +126 -0
  35. data/lib/sfrp/low/set.rb +62 -0
  36. data/lib/sfrp/mono/dsl.rb +120 -0
  37. data/lib/sfrp/mono/environment.rb +26 -0
  38. data/lib/sfrp/mono/exception.rb +21 -0
  39. data/lib/sfrp/mono/expression.rb +124 -0
  40. data/lib/sfrp/mono/function.rb +86 -0
  41. data/lib/sfrp/mono/memory.rb +32 -0
  42. data/lib/sfrp/mono/node.rb +125 -0
  43. data/lib/sfrp/mono/pattern.rb +69 -0
  44. data/lib/sfrp/mono/set.rb +151 -0
  45. data/lib/sfrp/mono/type.rb +210 -0
  46. data/lib/sfrp/mono/vconst.rb +134 -0
  47. data/lib/sfrp/output/set.rb +33 -0
  48. data/lib/sfrp/poly/dsl.rb +171 -0
  49. data/lib/sfrp/poly/elements.rb +168 -0
  50. data/lib/sfrp/poly/exception.rb +42 -0
  51. data/lib/sfrp/poly/expression.rb +170 -0
  52. data/lib/sfrp/poly/monofier.rb +73 -0
  53. data/lib/sfrp/poly/set.rb +90 -0
  54. data/lib/sfrp/poly/typing.rb +197 -0
  55. data/lib/sfrp/raw/dsl.rb +41 -0
  56. data/lib/sfrp/raw/elements.rb +164 -0
  57. data/lib/sfrp/raw/exception.rb +40 -0
  58. data/lib/sfrp/raw/expression.rb +168 -0
  59. data/lib/sfrp/raw/namespace.rb +30 -0
  60. data/lib/sfrp/raw/set.rb +109 -0
  61. data/lib/sfrp/version.rb +3 -0
  62. data/sfrp.gemspec +40 -0
  63. data/spec/sfrp/Test.sfrp +4 -0
  64. data/spec/sfrp/compiler_spec.rb +17 -0
  65. data/spec/sfrp/flat/set_spec.rb +40 -0
  66. data/spec/sfrp/input/parse_test.sfrp +20 -0
  67. data/spec/sfrp/input/set_spec.rb +18 -0
  68. data/spec/sfrp/low/set_spec.rb +20 -0
  69. data/spec/sfrp/mono/expected.yml +295 -0
  70. data/spec/sfrp/mono/set_spec.rb +152 -0
  71. data/spec/sfrp/output/set_spec.rb +29 -0
  72. data/spec/sfrp/poly/set_spec.rb +290 -0
  73. data/spec/sfrp/raw/set_spec.rb +38 -0
  74. data/spec/spec_helper.rb +16 -0
  75. data/test/IntTest/Main.c +5 -0
  76. data/test/IntTest/Main.h +6 -0
  77. data/test/IntTest/Main.sfrp +10 -0
  78. data/test/IntTest/in.txt +3 -0
  79. data/test/IntTest/out.txt +4 -0
  80. data/test/MaybeTest/Main.sfrp +8 -0
  81. data/test/MaybeTest/SubDir/Lib.sfrp +9 -0
  82. data/test/MaybeTest/in.txt +6 -0
  83. data/test/MaybeTest/out.txt +6 -0
  84. data/test/Rakefile +15 -0
  85. metadata +290 -0
data/lib/sfrp/error.rb ADDED
@@ -0,0 +1,4 @@
1
+ module SFRP
2
+ class CompileError < StandardError
3
+ end
4
+ end
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