sfrp 1.1.0

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