bel_parser 1.0.0.alpha.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (182) hide show
  1. checksums.yaml +7 -0
  2. data/.gemspec +28 -0
  3. data/CHANGELOG.md +10 -0
  4. data/LICENSE +191 -0
  5. data/README.md +9 -0
  6. data/VERSION +1 -0
  7. data/bin/bel2_termcheck +39 -0
  8. data/lib/bel_parser.rb +17 -0
  9. data/lib/bel_parser/ast_filter.rb +27 -0
  10. data/lib/bel_parser/ast_generator.rb +86 -0
  11. data/lib/bel_parser/ast_validator.rb +40 -0
  12. data/lib/bel_parser/expression/parser.rb +42 -0
  13. data/lib/bel_parser/expression/term_semantics.rb +36 -0
  14. data/lib/bel_parser/language.rb +7 -0
  15. data/lib/bel_parser/language/function.rb +59 -0
  16. data/lib/bel_parser/language/quoting.rb +236 -0
  17. data/lib/bel_parser/language/semantic_ast.rb +604 -0
  18. data/lib/bel_parser/language/semantics/analyzer.rb +59 -0
  19. data/lib/bel_parser/language/signature.rb +39 -0
  20. data/lib/bel_parser/language/specification.rb +49 -0
  21. data/lib/bel_parser/language/syntax/expression/incomplete_node.rb +14 -0
  22. data/lib/bel_parser/language/syntax/expression/invalid_term_function.rb +22 -0
  23. data/lib/bel_parser/language/version1.rb +50 -0
  24. data/lib/bel_parser/language/version1/functions/abundance.rb +85 -0
  25. data/lib/bel_parser/language/version1/functions/biological_process.rb +85 -0
  26. data/lib/bel_parser/language/version1/functions/catalytic_activity.rb +110 -0
  27. data/lib/bel_parser/language/version1/functions/cell_secretion.rb +80 -0
  28. data/lib/bel_parser/language/version1/functions/cell_surface_expression.rb +80 -0
  29. data/lib/bel_parser/language/version1/functions/chaperone_activity.rb +110 -0
  30. data/lib/bel_parser/language/version1/functions/complex_abundance.rb +115 -0
  31. data/lib/bel_parser/language/version1/functions/composite_abundance.rb +80 -0
  32. data/lib/bel_parser/language/version1/functions/degradation.rb +80 -0
  33. data/lib/bel_parser/language/version1/functions/fusion.rb +302 -0
  34. data/lib/bel_parser/language/version1/functions/gene_abundance.rb +125 -0
  35. data/lib/bel_parser/language/version1/functions/gtp_bound_activity.rb +110 -0
  36. data/lib/bel_parser/language/version1/functions/kinase_activity.rb +110 -0
  37. data/lib/bel_parser/language/version1/functions/list.rb +115 -0
  38. data/lib/bel_parser/language/version1/functions/micro_rna_abundance.rb +85 -0
  39. data/lib/bel_parser/language/version1/functions/molecular_activity.rb +80 -0
  40. data/lib/bel_parser/language/version1/functions/pathology.rb +85 -0
  41. data/lib/bel_parser/language/version1/functions/peptidase_activity.rb +110 -0
  42. data/lib/bel_parser/language/version1/functions/phosphatase_activity.rb +110 -0
  43. data/lib/bel_parser/language/version1/functions/products.rb +80 -0
  44. data/lib/bel_parser/language/version1/functions/protein_abundance.rb +245 -0
  45. data/lib/bel_parser/language/version1/functions/protein_modification.rb +167 -0
  46. data/lib/bel_parser/language/version1/functions/reactants.rb +80 -0
  47. data/lib/bel_parser/language/version1/functions/reaction.rb +85 -0
  48. data/lib/bel_parser/language/version1/functions/ribosylation_activity.rb +110 -0
  49. data/lib/bel_parser/language/version1/functions/rna_abundance.rb +125 -0
  50. data/lib/bel_parser/language/version1/functions/substitution.rb +96 -0
  51. data/lib/bel_parser/language/version1/functions/transcriptional_activity.rb +110 -0
  52. data/lib/bel_parser/language/version1/functions/translocation.rb +100 -0
  53. data/lib/bel_parser/language/version1/functions/transport_activity.rb +110 -0
  54. data/lib/bel_parser/language/version1/functions/truncation.rb +82 -0
  55. data/lib/bel_parser/language/version1/return_types/abundance.rb +20 -0
  56. data/lib/bel_parser/language/version1/return_types/any.rb +74 -0
  57. data/lib/bel_parser/language/version1/return_types/biological_process.rb +17 -0
  58. data/lib/bel_parser/language/version1/return_types/catalytic_activity.rb +20 -0
  59. data/lib/bel_parser/language/version1/return_types/chaperone_activity.rb +20 -0
  60. data/lib/bel_parser/language/version1/return_types/complex_abundance.rb +17 -0
  61. data/lib/bel_parser/language/version1/return_types/fusion.rb +17 -0
  62. data/lib/bel_parser/language/version1/return_types/gene_abundance.rb +17 -0
  63. data/lib/bel_parser/language/version1/return_types/gtp_bound_activity.rb +20 -0
  64. data/lib/bel_parser/language/version1/return_types/kinase_activity.rb +20 -0
  65. data/lib/bel_parser/language/version1/return_types/list.rb +17 -0
  66. data/lib/bel_parser/language/version1/return_types/micro_rna_abundance.rb +17 -0
  67. data/lib/bel_parser/language/version1/return_types/molecular_activity.rb +20 -0
  68. data/lib/bel_parser/language/version1/return_types/pathology.rb +17 -0
  69. data/lib/bel_parser/language/version1/return_types/peptidase_activity.rb +20 -0
  70. data/lib/bel_parser/language/version1/return_types/phosphatase_activity.rb +20 -0
  71. data/lib/bel_parser/language/version1/return_types/products.rb +17 -0
  72. data/lib/bel_parser/language/version1/return_types/protein_abundance.rb +17 -0
  73. data/lib/bel_parser/language/version1/return_types/protein_modification.rb +17 -0
  74. data/lib/bel_parser/language/version1/return_types/reactants.rb +17 -0
  75. data/lib/bel_parser/language/version1/return_types/ribosylation_activity.rb +20 -0
  76. data/lib/bel_parser/language/version1/return_types/rna_abundance.rb +17 -0
  77. data/lib/bel_parser/language/version1/return_types/substitution.rb +17 -0
  78. data/lib/bel_parser/language/version1/return_types/transcriptional_activity.rb +20 -0
  79. data/lib/bel_parser/language/version1/return_types/transport_activity.rb +20 -0
  80. data/lib/bel_parser/language/version1/return_types/truncation.rb +17 -0
  81. data/lib/bel_parser/language/version2.rb +50 -0
  82. data/lib/bel_parser/language/version2/functions/abundance.rb +165 -0
  83. data/lib/bel_parser/language/version2/functions/activity.rb +115 -0
  84. data/lib/bel_parser/language/version2/functions/biological_process.rb +85 -0
  85. data/lib/bel_parser/language/version2/functions/cell_secretion.rb +80 -0
  86. data/lib/bel_parser/language/version2/functions/cell_surface_expression.rb +80 -0
  87. data/lib/bel_parser/language/version2/functions/complex_abundance.rb +190 -0
  88. data/lib/bel_parser/language/version2/functions/composite_abundance.rb +80 -0
  89. data/lib/bel_parser/language/version2/functions/degradation.rb +80 -0
  90. data/lib/bel_parser/language/version2/functions/fragment.rb +119 -0
  91. data/lib/bel_parser/language/version2/functions/from_location.rb +85 -0
  92. data/lib/bel_parser/language/version2/functions/fusion.rb +227 -0
  93. data/lib/bel_parser/language/version2/functions/gene_abundance.rb +195 -0
  94. data/lib/bel_parser/language/version2/functions/list.rb +115 -0
  95. data/lib/bel_parser/language/version2/functions/location.rb +85 -0
  96. data/lib/bel_parser/language/version2/functions/micro_rna_abundance.rb +165 -0
  97. data/lib/bel_parser/language/version2/functions/molecular_activity.rb +83 -0
  98. data/lib/bel_parser/language/version2/functions/pathology.rb +85 -0
  99. data/lib/bel_parser/language/version2/functions/products.rb +80 -0
  100. data/lib/bel_parser/language/version2/functions/protein_abundance.rb +285 -0
  101. data/lib/bel_parser/language/version2/functions/protein_modification.rb +167 -0
  102. data/lib/bel_parser/language/version2/functions/reactants.rb +80 -0
  103. data/lib/bel_parser/language/version2/functions/reaction.rb +85 -0
  104. data/lib/bel_parser/language/version2/functions/rna_abundance.rb +195 -0
  105. data/lib/bel_parser/language/version2/functions/to_location.rb +85 -0
  106. data/lib/bel_parser/language/version2/functions/translocation.rb +90 -0
  107. data/lib/bel_parser/language/version2/functions/variant.rb +83 -0
  108. data/lib/bel_parser/language/version2/return_types/abundance.rb +20 -0
  109. data/lib/bel_parser/language/version2/return_types/activity.rb +20 -0
  110. data/lib/bel_parser/language/version2/return_types/any.rb +74 -0
  111. data/lib/bel_parser/language/version2/return_types/biological_process.rb +17 -0
  112. data/lib/bel_parser/language/version2/return_types/complex_abundance.rb +17 -0
  113. data/lib/bel_parser/language/version2/return_types/fragment.rb +20 -0
  114. data/lib/bel_parser/language/version2/return_types/from_location.rb +20 -0
  115. data/lib/bel_parser/language/version2/return_types/fusion.rb +17 -0
  116. data/lib/bel_parser/language/version2/return_types/gene_abundance.rb +17 -0
  117. data/lib/bel_parser/language/version2/return_types/list.rb +17 -0
  118. data/lib/bel_parser/language/version2/return_types/location.rb +20 -0
  119. data/lib/bel_parser/language/version2/return_types/micro_rna_abundance.rb +17 -0
  120. data/lib/bel_parser/language/version2/return_types/molecular_activity.rb +20 -0
  121. data/lib/bel_parser/language/version2/return_types/pathology.rb +17 -0
  122. data/lib/bel_parser/language/version2/return_types/products.rb +17 -0
  123. data/lib/bel_parser/language/version2/return_types/protein_abundance.rb +17 -0
  124. data/lib/bel_parser/language/version2/return_types/protein_modification.rb +17 -0
  125. data/lib/bel_parser/language/version2/return_types/reactants.rb +17 -0
  126. data/lib/bel_parser/language/version2/return_types/rna_abundance.rb +17 -0
  127. data/lib/bel_parser/language/version2/return_types/to_location.rb +20 -0
  128. data/lib/bel_parser/language/version2/return_types/variant.rb +20 -0
  129. data/lib/bel_parser/mixin/line_continuator.rb +15 -0
  130. data/lib/bel_parser/mixin/line_mapping.rb +14 -0
  131. data/lib/bel_parser/parser.rb +54 -0
  132. data/lib/bel_parser/parsers/ast/mapped_traversal.rb +36 -0
  133. data/lib/bel_parser/parsers/ast/node.rb +705 -0
  134. data/lib/bel_parser/parsers/ast/sexp.rb +8 -0
  135. data/lib/bel_parser/parsers/ast/traversal.rb +21 -0
  136. data/lib/bel_parser/parsers/bel_script.rb +4 -0
  137. data/lib/bel_parser/parsers/bel_script/define_annotation.rb +5476 -0
  138. data/lib/bel_parser/parsers/bel_script/define_annotation.rl +141 -0
  139. data/lib/bel_parser/parsers/bel_script/define_namespace.rb +1780 -0
  140. data/lib/bel_parser/parsers/bel_script/define_namespace.rl +121 -0
  141. data/lib/bel_parser/parsers/bel_script/set.rb +4556 -0
  142. data/lib/bel_parser/parsers/bel_script/set.rl +116 -0
  143. data/lib/bel_parser/parsers/bel_script/unset.rb +706 -0
  144. data/lib/bel_parser/parsers/bel_script/unset.rl +95 -0
  145. data/lib/bel_parser/parsers/common.rb +5 -0
  146. data/lib/bel_parser/parsers/common/blank_line.rb +211 -0
  147. data/lib/bel_parser/parsers/common/blank_line.rl +81 -0
  148. data/lib/bel_parser/parsers/common/comment_line.rb +245 -0
  149. data/lib/bel_parser/parsers/common/comment_line.rl +97 -0
  150. data/lib/bel_parser/parsers/common/common.rb +7 -0
  151. data/lib/bel_parser/parsers/common/common.rl +13 -0
  152. data/lib/bel_parser/parsers/common/identifier.rb +289 -0
  153. data/lib/bel_parser/parsers/common/identifier.rl +106 -0
  154. data/lib/bel_parser/parsers/common/list.rb +2142 -0
  155. data/lib/bel_parser/parsers/common/list.rl +144 -0
  156. data/lib/bel_parser/parsers/common/string.rb +271 -0
  157. data/lib/bel_parser/parsers/common/string.rl +107 -0
  158. data/lib/bel_parser/parsers/expression.rb +7 -0
  159. data/lib/bel_parser/parsers/expression/comment.rb +239 -0
  160. data/lib/bel_parser/parsers/expression/comment.rl +97 -0
  161. data/lib/bel_parser/parsers/expression/parameter.rb +1506 -0
  162. data/lib/bel_parser/parsers/expression/parameter.rl +97 -0
  163. data/lib/bel_parser/parsers/expression/relationship.rb +254 -0
  164. data/lib/bel_parser/parsers/expression/relationship.rl +98 -0
  165. data/lib/bel_parser/parsers/expression/statement_nested.rb +17802 -0
  166. data/lib/bel_parser/parsers/expression/statement_nested.rl +141 -0
  167. data/lib/bel_parser/parsers/expression/statement_observed_term.rb +7291 -0
  168. data/lib/bel_parser/parsers/expression/statement_observed_term.rl +92 -0
  169. data/lib/bel_parser/parsers/expression/statement_simple.rb +10475 -0
  170. data/lib/bel_parser/parsers/expression/statement_simple.rl +112 -0
  171. data/lib/bel_parser/parsers/expression/term.rb +3989 -0
  172. data/lib/bel_parser/parsers/expression/term.rl +157 -0
  173. data/lib/bel_parser/parsers/line_parser.rb +92 -0
  174. data/lib/bel_parser/parsers/mixin/buffer.rb +10 -0
  175. data/lib/bel_parser/parsers/nonblocking_io_wrapper.rb +50 -0
  176. data/lib/bel_parser/script/parser.rb +49 -0
  177. data/lib/bel_parser/vendor/ast.rb +17 -0
  178. data/lib/bel_parser/vendor/ast/node.rb +254 -0
  179. data/lib/bel_parser/vendor/ast/processor.rb +12 -0
  180. data/lib/bel_parser/vendor/ast/processor/mixin.rb +282 -0
  181. data/lib/bel_parser/vendor/ast/sexp.rb +30 -0
  182. metadata +226 -0
@@ -0,0 +1,157 @@
1
+ # begin: ragel
2
+ =begin
3
+ %%{
4
+ machine bel;
5
+
6
+ include 'parameter.rl';
7
+
8
+ action start_function {
9
+ @buffers[:function] = []
10
+ }
11
+
12
+ action append_function {
13
+ @buffers[:function] << fc
14
+ }
15
+
16
+ action finish_function {
17
+ @buffers[:function] = identifier(utf8_string(@buffers[:function]))
18
+ }
19
+
20
+ action term_init {
21
+ @buffers[:term_stack] = [ term() ]
22
+ }
23
+
24
+ action inner_term_init {
25
+ @buffers[:term_stack] << term()
26
+ }
27
+
28
+ action term_fx {
29
+ fx = @buffers[:function]
30
+ @buffers[:term_stack][-1] = @buffers[:term_stack][-1] << function(fx)
31
+ }
32
+
33
+ action term_argument {
34
+ @buffers[:term_stack][-1] = @buffers[:term_stack][-1] << argument(@buffers[:parameter])
35
+ @buffers[:parameter] = nil
36
+ }
37
+
38
+ action fxbt {
39
+ fpc -= @buffers[:function].length + 1
40
+ fcall inner_term;
41
+ }
42
+
43
+ action fxret {
44
+ inner_term = @buffers[:term_stack].pop
45
+ @buffers[:term_stack][-1] = @buffers[:term_stack][-1] << argument(inner_term)
46
+ fret;
47
+ }
48
+
49
+ action yield_term_ast {
50
+ yield @buffers[:term_stack][-1]
51
+ }
52
+
53
+ inner_term :=
54
+ IDENT >inner_term_init >start_function $append_function %finish_function
55
+ SP*
56
+ '(' @term_fx
57
+ (
58
+ BEL_PARAMETER %term_argument |
59
+ IDENT >start_function $append_function '(' @fxbt
60
+ )
61
+ (
62
+ SP* ',' SP*
63
+ (
64
+ BEL_PARAMETER %term_argument |
65
+ IDENT >start_function $append_function '(' @fxbt
66
+ )
67
+ )*
68
+ ')' @fxret;
69
+
70
+ outer_term =
71
+ IDENT >term_init >start_function $append_function %finish_function
72
+ SP*
73
+ '(' @term_fx
74
+ (
75
+ BEL_PARAMETER %term_argument |
76
+ IDENT >start_function $append_function '(' @fxbt
77
+ )
78
+ (
79
+ SP* ',' SP*
80
+ (
81
+ BEL_PARAMETER %term_argument |
82
+ IDENT >start_function $append_function '(' @fxbt
83
+ )
84
+ )*
85
+ ')';
86
+
87
+ term :=
88
+ outer_term %yield_term_ast NL;
89
+ }%%
90
+ =end
91
+ # end: ragel
92
+
93
+ require_relative '../ast/node'
94
+ require_relative '../mixin/buffer'
95
+ require_relative '../nonblocking_io_wrapper'
96
+
97
+ module BELParser
98
+ module Parsers
99
+ module Expression
100
+ module Term
101
+
102
+ class << self
103
+
104
+ MAX_LENGTH = 1024 * 128 # 128K
105
+
106
+ def parse(content)
107
+ return nil unless content
108
+
109
+ Parser.new(content).each do |obj|
110
+ yield obj
111
+ end
112
+ end
113
+ end
114
+
115
+ private
116
+
117
+ class Parser
118
+ include Enumerable
119
+ include BELParser::Parsers::Buffer
120
+ include BELParser::Parsers::AST::Sexp
121
+
122
+ def initialize(content)
123
+ @content = content
124
+ # begin: ragel
125
+ %% write data;
126
+ # end: ragel
127
+ end
128
+
129
+ def each
130
+ @buffers = {}
131
+ stack = []
132
+ data = @content.unpack('C*')
133
+ p = 0
134
+ pe = data.length
135
+ eof = data.length
136
+
137
+ # begin: ragel
138
+ %% write init;
139
+ %% write exec;
140
+ # end: ragel
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end
146
+ end
147
+
148
+ if __FILE__ == $0
149
+ $stdin.each_line do |line|
150
+ BELParser::Parsers::Expression::Term.parse(line) { |obj|
151
+ puts obj.inspect
152
+ }
153
+ end
154
+ end
155
+
156
+ # vim: ft=ruby ts=2 sw=2:
157
+ # encoding: utf-8
@@ -0,0 +1,92 @@
1
+ require_relative 'common'
2
+ require_relative 'expression'
3
+ require_relative 'bel_script'
4
+
5
+ # Top-level LINE module.
6
+ module LINE
7
+ include BELParser::Parsers::Common
8
+ include BELParser::Parsers::Expression
9
+ include BELParser::Parsers::BELScript
10
+
11
+ BEL_PARSERS = [
12
+ BELParser::Parsers::Common::BlankLine,
13
+ BELParser::Parsers::Common::CommentLine,
14
+ BELParser::Parsers::Common::Identifier,
15
+ BELParser::Parsers::Common::String,
16
+ BELParser::Parsers::Common::List,
17
+ BELParser::Parsers::Expression::Parameter,
18
+ BELParser::Parsers::Expression::Term,
19
+ BELParser::Parsers::Expression::Relationship,
20
+ BELParser::Parsers::Expression::Comment,
21
+ BELParser::Parsers::Expression::StatementObservedTerm,
22
+ BELParser::Parsers::Expression::StatementSimple,
23
+ BELParser::Parsers::Expression::StatementNested,
24
+ BELParser::Parsers::BELScript::DefineAnnotation,
25
+ BELParser::Parsers::BELScript::DefineNamespace,
26
+ BELParser::Parsers::BELScript::Set,
27
+ BELParser::Parsers::BELScript::Unset
28
+ ].freeze
29
+
30
+ # rubocop:disable MethodLength, AbcSize
31
+ def self.parse(io)
32
+ # single line transform
33
+ line_enum = io
34
+ .each_line
35
+ .lazy
36
+ .map { |line| LINE.normalize_line_terminators(line) }
37
+
38
+ # multi-line transform
39
+ loop do
40
+ begin
41
+ line = line_enum.next
42
+
43
+ while line.end_with?("\\\n")
44
+ line.chomp!("\\\n")
45
+ line += line_enum.next
46
+ end
47
+
48
+ BEL_PARSERS.each do |parser|
49
+ # rubocop:disable BlockDelimiters
50
+ parser.parse(line) { |obj|
51
+ puts "parser: #{parser.inspect},"\
52
+ "line: #{line.strip},"\
53
+ "object: \n#{obj.inspect}"
54
+ }
55
+ end
56
+ rescue StopIteration
57
+ return
58
+ end
59
+ end
60
+ end
61
+
62
+ def self.normalize_line_terminators(string)
63
+ return nil unless string
64
+ string.strip + "\n"
65
+ end
66
+
67
+ def self.map_empty_line(string)
68
+ if LINE.match_empty_line(string)
69
+ nil
70
+ else
71
+ string
72
+ end
73
+ end
74
+
75
+ def self.map_comment_line(string)
76
+ if LINE.match_comment_line(string)
77
+ nil
78
+ else
79
+ string
80
+ end
81
+ end
82
+
83
+ def self.match_empty_line(string)
84
+ string =~ /^\s*$/
85
+ end
86
+
87
+ def self.match_comment_line(string)
88
+ string =~ /^\s*#/
89
+ end
90
+ end
91
+
92
+ LINE.parse($stdin) if FILE == $PROGRAM_NAME
@@ -0,0 +1,10 @@
1
+ module BELParser
2
+ module Parsers
3
+ # Buffer module.
4
+ module Buffer
5
+ def utf8_string(buffer)
6
+ buffer.pack('C*').force_encoding('utf-8')
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,50 @@
1
+ # Provides a platform-independent, non-blocking wrapper for reading an
2
+ # {http://ruby-doc.org/core-2.2.2/IO.html IO}-like object. This wrapper
3
+ # object must be enumerated using the {#each} method.
4
+ class NonblockingIOWrapper
5
+ # Initialize this wrapper around the +io+ object and read at most
6
+ # +read_length+ bytes in a non-blocking manner.
7
+ #
8
+ # @param [IO] io an IO-like object
9
+ # @param [Fixnum] read_length the buffer length to read
10
+ def initialize(io, read_length = (128 * 1024))
11
+ @io = io
12
+ @read_length = read_length
13
+ @read_method = nonblocking_read(@io)
14
+ end
15
+
16
+ # Yields each buffer read from the wrapped IO-like object to the provided
17
+ # block (e.g. +{ |block| ... }+). The read length is set on {#initialize}.
18
+ #
19
+ # @yield the buffers read from the IO-like object
20
+ # @yieldparam [String] buffer the read buffer as uninterpreted bytes
21
+ def each
22
+ while (buffer = @read_method.call(@read_length))
23
+ yield buffer
24
+ end
25
+ rescue IO::WaitReadable
26
+ IO.select([@io])
27
+ retry
28
+ # rubocop:disable HandleExceptions
29
+ rescue EOFError
30
+ # end of stream; parsing complete
31
+ end
32
+
33
+ private
34
+
35
+ # Returns the method, appropriate for your platform, to read IO in a
36
+ # non-blocking manner.
37
+ #
38
+ # @example Call directly.
39
+ # nonblocking_read(StringIO.new('hello')).call(4)
40
+ #
41
+ # @param [IO] io an IO-like object
42
+ # @return [Method] a non-blocking read method
43
+ def nonblocking_read(io)
44
+ if Gem.win_platform?
45
+ io.method(:sysread)
46
+ else
47
+ io.method(:read_nonblock)
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,49 @@
1
+ require_relative '../ast_filter'
2
+ require_relative '../ast_generator'
3
+ require_relative '../parsers/common'
4
+ require_relative '../parsers/expression'
5
+ require_relative '../parsers/bel_script'
6
+
7
+ module BELParser
8
+ module Script
9
+ # Parser for BEL Script.
10
+ class Parser
11
+ include BELParser::Parsers::Common
12
+ include BELParser::Parsers::Expression
13
+ include BELParser::Parsers::BELScript
14
+
15
+ FILTER = BELParser::ASTFilter.new(
16
+ :statement_simple,
17
+ :observed_term,
18
+ :nested_statement,
19
+ :define_annotation,
20
+ :define_namespace,
21
+ :set,
22
+ :unset,
23
+ :blank_line,
24
+ :comment_line
25
+ )
26
+
27
+ def each(io)
28
+ if block_given?
29
+ filtered_ast = FILTER.each(BELParser::ASTGenerator.new.each(io))
30
+ filtered_ast.each do |results|
31
+ yield results
32
+ end
33
+ else
34
+ enum_for(:each, io)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+
41
+ if __FILE__ == $PROGRAM_NAME
42
+ BELParser::Script::Parser.new.each($stdin) do |line_result|
43
+ line_number, line, ast_results = line_result
44
+ puts "#{line_number}: #{line}"
45
+ ast_results.each do |ast|
46
+ puts ast.to_s(1)
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,17 @@
1
+ # {AST} is a library for manipulating abstract syntax trees.
2
+ #
3
+ # It embraces immutability; each AST node is inherently frozen at
4
+ # creation, and updating a child node requires recreating that node
5
+ # and its every parent, recursively.
6
+ # This is a design choice. It does create some pressure on
7
+ # garbage collector, but completely eliminates all concurrency
8
+ # and aliasing problems.
9
+ #
10
+ # See also {AST::Node}, {AST::Processor::Mixin} and {AST::Sexp} for
11
+ # additional recommendations and design patterns.
12
+ #
13
+ module AST
14
+ require_relative 'ast/node'
15
+ require_relative 'ast/processor'
16
+ require_relative 'ast/sexp'
17
+ end
@@ -0,0 +1,254 @@
1
+ module AST
2
+ # Node is an immutable class, instances of which represent abstract
3
+ # syntax tree nodes. It combines semantic information (i.e. anything
4
+ # that affects the algorithmic properties of a program) with
5
+ # meta-information (line numbers or compiler intermediates).
6
+ #
7
+ # Notes on inheritance
8
+ # ====================
9
+ #
10
+ # The distinction between semantics and metadata is important. Complete
11
+ # semantic information should be contained within just the {#type} and
12
+ # {#children} of a Node instance; in other words, if an AST was to be
13
+ # stripped of all meta-information, it should remain a valid AST which
14
+ # could be successfully processed to yield a result with the same
15
+ # algorithmic properties.
16
+ #
17
+ # Thus, Node should never be inherited in order to define methods which
18
+ # affect or return semantic information, such as getters for `class_name`,
19
+ # `superclass` and `body` in the case of a hypothetical `ClassNode`. The
20
+ # correct solution is to use a generic Node with a {#type} of `:class`
21
+ # and three children. See also {Processor} for tips on working with such
22
+ # ASTs.
23
+ #
24
+ # On the other hand, Node can and should be inherited to define
25
+ # application-specific metadata (see also {#initialize}) or customize the
26
+ # printing format. It is expected that an application would have one or two
27
+ # such classes and use them across the entire codebase.
28
+ #
29
+ # The rationale for this pattern is extensibility and maintainability.
30
+ # Unlike static ones, dynamic languages do not require the presence of a
31
+ # predefined, rigid structure, nor does it improve dispatch efficiency,
32
+ # and while such a structure can certainly be defined, it does not add
33
+ # any value but incurs a maintaining cost.
34
+ # For example, extending the AST even with a transformation-local
35
+ # temporary node type requires making globally visible changes to
36
+ # the codebase.
37
+ #
38
+ class Node
39
+ # Returns the type of this node.
40
+ # @return [Symbol]
41
+ attr_reader :type
42
+
43
+ # Returns the children of this node.
44
+ # The returned value is frozen.
45
+ # @return [Array]
46
+ attr_reader :children
47
+
48
+ # Returns the precomputed hash value for this node
49
+ # @return [Fixnum]
50
+ attr_reader :hash
51
+
52
+ # Constructs a new instance of Node.
53
+ #
54
+ # The arguments `type` and `children` are converted with `to_sym` and
55
+ # `to_a` respectively. Additionally, the result of converting `children`
56
+ # is frozen. While mutating the arguments is generally considered harmful,
57
+ # the most common case is to pass an array literal to the constructor. If
58
+ # your code does not expect the argument to be frozen, use `#dup`.
59
+ #
60
+ # The `properties` hash is passed to {#assign_properties}.
61
+ def initialize(type, children=[], properties={})
62
+ @type, @children = type.to_sym, children.to_a.freeze
63
+
64
+ assign_properties(properties)
65
+
66
+ @hash = [@type, @children, self.class].hash
67
+
68
+ freeze
69
+ end
70
+
71
+ # Test if other object is equal to
72
+ # @param [Object] other
73
+ # @return [Boolean]
74
+ def eql?(other)
75
+ self.class.eql?(other.class) &&
76
+ @type.eql?(other.type) &&
77
+ @children.eql?(other.children)
78
+ end
79
+
80
+ # By default, each entry in the `properties` hash is assigned to
81
+ # an instance variable in this instance of Node. A subclass should define
82
+ # attribute readers for such variables. The values passed in the hash
83
+ # are not frozen or whitelisted; such behavior can also be implemented
84
+ # by subclassing Node and overriding this method.
85
+ #
86
+ # @return [nil]
87
+ def assign_properties(properties)
88
+ properties.each do |name, value|
89
+ instance_variable_set :"@#{name}", value
90
+ end
91
+
92
+ nil
93
+ end
94
+ protected :assign_properties
95
+
96
+ alias :original_dup :dup
97
+ private :original_dup
98
+
99
+ # Nodes are already frozen, so there is no harm in returning the
100
+ # current node as opposed to initializing from scratch and freezing
101
+ # another one.
102
+ #
103
+ # @return self
104
+ def dup
105
+ self
106
+ end
107
+ alias :clone :dup
108
+
109
+ # Returns a new instance of Node where non-nil arguments replace the
110
+ # corresponding fields of `self`.
111
+ #
112
+ # For example, `Node.new(:foo, [ 1, 2 ]).updated(:bar)` would yield
113
+ # `(bar 1 2)`, and `Node.new(:foo, [ 1, 2 ]).updated(nil, [])` would
114
+ # yield `(foo)`.
115
+ #
116
+ # If the resulting node would be identical to `self`, does nothing.
117
+ #
118
+ # @param [Symbol, nil] type
119
+ # @param [Array, nil] children
120
+ # @param [Hash, nil] properties
121
+ # @return [AST::Node]
122
+ def updated(type=nil, children=nil, properties=nil)
123
+ new_type = type || @type
124
+ new_children = children || @children
125
+ new_properties = properties || {}
126
+
127
+ if @type == new_type &&
128
+ @children == new_children &&
129
+ properties.nil?
130
+ self
131
+ else
132
+ # Maybe change call?
133
+ original_dup.send :initialize, new_type, new_children, new_properties
134
+ end
135
+ end
136
+
137
+ # Compares `self` to `other`, possibly converting with `to_ast`. Only
138
+ # `type` and `children` are compared; metadata is deliberately ignored.
139
+ #
140
+ # @return [Boolean]
141
+ def ==(other)
142
+ if equal?(other)
143
+ true
144
+ elsif other.respond_to? :to_ast
145
+ other = other.to_ast
146
+ other.type == self.type &&
147
+ other.children == self.children
148
+ else
149
+ false
150
+ end
151
+ end
152
+
153
+ # Concatenates `array` with `children` and returns the resulting node.
154
+ #
155
+ # @return [AST::Node]
156
+ def concat(array)
157
+ updated(nil, @children + array.to_a)
158
+ end
159
+
160
+ alias + concat
161
+
162
+ # Appends `element` to `children` and returns the resulting node.
163
+ #
164
+ # @return [AST::Node]
165
+ def append(element)
166
+ updated(nil, @children + [element])
167
+ end
168
+
169
+ alias << append
170
+
171
+ # Returns {#children}. This is very useful in order to decompose nodes
172
+ # concisely. For example:
173
+ #
174
+ # node = s(:gasgn, :$foo, s(:integer, 1))
175
+ # s
176
+ # var_name, value = *node
177
+ # p var_name # => :$foo
178
+ # p value # => (integer 1)
179
+ #
180
+ # @return [Array]
181
+ def to_a
182
+ children
183
+ end
184
+
185
+ # Converts `self` to a pretty-printed s-expression.
186
+ #
187
+ # @param [Integer] indent Base indentation level.
188
+ # @return [String]
189
+ def to_sexp(indent=0)
190
+ indented = " " * indent
191
+ sexp = "#{indented}(#{fancy_type}"
192
+
193
+ first_node_child = children.index do |child|
194
+ child.is_a?(Node) || child.is_a?(Array)
195
+ end || children.count
196
+
197
+ children.each_with_index do |child, idx|
198
+ if child.is_a?(Node) && idx >= first_node_child
199
+ sexp << "\n#{child.to_sexp(indent + 1)}"
200
+ else
201
+ sexp << " #{child.inspect}"
202
+ end
203
+ end
204
+
205
+ sexp << ")"
206
+
207
+ sexp
208
+ end
209
+
210
+ alias to_s to_sexp
211
+
212
+ # Converts `self` to a s-expression ruby string.
213
+ # The code return will recreate the node, using the sexp module s()
214
+ #
215
+ # @param [Integer] indent Base indentation level.
216
+ # @return [String]
217
+ def inspect(indent=0)
218
+ indented = " " * indent
219
+ sexp = "#{indented}s(:#{@type}"
220
+
221
+ first_node_child = children.index do |child|
222
+ child.is_a?(Node) || child.is_a?(Array)
223
+ end || children.count
224
+
225
+ children.each_with_index do |child, idx|
226
+ if child.is_a?(Node) && idx >= first_node_child
227
+ sexp << ",\n#{child.inspect(indent + 1)}"
228
+ else
229
+ sexp << ", #{child.inspect}"
230
+ end
231
+ end
232
+
233
+ sexp << ")"
234
+
235
+ sexp
236
+ end
237
+
238
+ # @return [AST::Node] self
239
+ def to_ast
240
+ self
241
+ end
242
+
243
+ protected
244
+
245
+ # Returns `@type` with all underscores replaced by dashes. This allows
246
+ # to write symbol literals without quotes in Ruby sources and yet have
247
+ # nicely looking s-expressions.
248
+ #
249
+ # @return [String]
250
+ def fancy_type
251
+ @type.to_s.gsub('_', '-')
252
+ end
253
+ end
254
+ end