bel_parser 1.0.0.alpha.1
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.
- checksums.yaml +7 -0
- data/.gemspec +28 -0
- data/CHANGELOG.md +10 -0
- data/LICENSE +191 -0
- data/README.md +9 -0
- data/VERSION +1 -0
- data/bin/bel2_termcheck +39 -0
- data/lib/bel_parser.rb +17 -0
- data/lib/bel_parser/ast_filter.rb +27 -0
- data/lib/bel_parser/ast_generator.rb +86 -0
- data/lib/bel_parser/ast_validator.rb +40 -0
- data/lib/bel_parser/expression/parser.rb +42 -0
- data/lib/bel_parser/expression/term_semantics.rb +36 -0
- data/lib/bel_parser/language.rb +7 -0
- data/lib/bel_parser/language/function.rb +59 -0
- data/lib/bel_parser/language/quoting.rb +236 -0
- data/lib/bel_parser/language/semantic_ast.rb +604 -0
- data/lib/bel_parser/language/semantics/analyzer.rb +59 -0
- data/lib/bel_parser/language/signature.rb +39 -0
- data/lib/bel_parser/language/specification.rb +49 -0
- data/lib/bel_parser/language/syntax/expression/incomplete_node.rb +14 -0
- data/lib/bel_parser/language/syntax/expression/invalid_term_function.rb +22 -0
- data/lib/bel_parser/language/version1.rb +50 -0
- data/lib/bel_parser/language/version1/functions/abundance.rb +85 -0
- data/lib/bel_parser/language/version1/functions/biological_process.rb +85 -0
- data/lib/bel_parser/language/version1/functions/catalytic_activity.rb +110 -0
- data/lib/bel_parser/language/version1/functions/cell_secretion.rb +80 -0
- data/lib/bel_parser/language/version1/functions/cell_surface_expression.rb +80 -0
- data/lib/bel_parser/language/version1/functions/chaperone_activity.rb +110 -0
- data/lib/bel_parser/language/version1/functions/complex_abundance.rb +115 -0
- data/lib/bel_parser/language/version1/functions/composite_abundance.rb +80 -0
- data/lib/bel_parser/language/version1/functions/degradation.rb +80 -0
- data/lib/bel_parser/language/version1/functions/fusion.rb +302 -0
- data/lib/bel_parser/language/version1/functions/gene_abundance.rb +125 -0
- data/lib/bel_parser/language/version1/functions/gtp_bound_activity.rb +110 -0
- data/lib/bel_parser/language/version1/functions/kinase_activity.rb +110 -0
- data/lib/bel_parser/language/version1/functions/list.rb +115 -0
- data/lib/bel_parser/language/version1/functions/micro_rna_abundance.rb +85 -0
- data/lib/bel_parser/language/version1/functions/molecular_activity.rb +80 -0
- data/lib/bel_parser/language/version1/functions/pathology.rb +85 -0
- data/lib/bel_parser/language/version1/functions/peptidase_activity.rb +110 -0
- data/lib/bel_parser/language/version1/functions/phosphatase_activity.rb +110 -0
- data/lib/bel_parser/language/version1/functions/products.rb +80 -0
- data/lib/bel_parser/language/version1/functions/protein_abundance.rb +245 -0
- data/lib/bel_parser/language/version1/functions/protein_modification.rb +167 -0
- data/lib/bel_parser/language/version1/functions/reactants.rb +80 -0
- data/lib/bel_parser/language/version1/functions/reaction.rb +85 -0
- data/lib/bel_parser/language/version1/functions/ribosylation_activity.rb +110 -0
- data/lib/bel_parser/language/version1/functions/rna_abundance.rb +125 -0
- data/lib/bel_parser/language/version1/functions/substitution.rb +96 -0
- data/lib/bel_parser/language/version1/functions/transcriptional_activity.rb +110 -0
- data/lib/bel_parser/language/version1/functions/translocation.rb +100 -0
- data/lib/bel_parser/language/version1/functions/transport_activity.rb +110 -0
- data/lib/bel_parser/language/version1/functions/truncation.rb +82 -0
- data/lib/bel_parser/language/version1/return_types/abundance.rb +20 -0
- data/lib/bel_parser/language/version1/return_types/any.rb +74 -0
- data/lib/bel_parser/language/version1/return_types/biological_process.rb +17 -0
- data/lib/bel_parser/language/version1/return_types/catalytic_activity.rb +20 -0
- data/lib/bel_parser/language/version1/return_types/chaperone_activity.rb +20 -0
- data/lib/bel_parser/language/version1/return_types/complex_abundance.rb +17 -0
- data/lib/bel_parser/language/version1/return_types/fusion.rb +17 -0
- data/lib/bel_parser/language/version1/return_types/gene_abundance.rb +17 -0
- data/lib/bel_parser/language/version1/return_types/gtp_bound_activity.rb +20 -0
- data/lib/bel_parser/language/version1/return_types/kinase_activity.rb +20 -0
- data/lib/bel_parser/language/version1/return_types/list.rb +17 -0
- data/lib/bel_parser/language/version1/return_types/micro_rna_abundance.rb +17 -0
- data/lib/bel_parser/language/version1/return_types/molecular_activity.rb +20 -0
- data/lib/bel_parser/language/version1/return_types/pathology.rb +17 -0
- data/lib/bel_parser/language/version1/return_types/peptidase_activity.rb +20 -0
- data/lib/bel_parser/language/version1/return_types/phosphatase_activity.rb +20 -0
- data/lib/bel_parser/language/version1/return_types/products.rb +17 -0
- data/lib/bel_parser/language/version1/return_types/protein_abundance.rb +17 -0
- data/lib/bel_parser/language/version1/return_types/protein_modification.rb +17 -0
- data/lib/bel_parser/language/version1/return_types/reactants.rb +17 -0
- data/lib/bel_parser/language/version1/return_types/ribosylation_activity.rb +20 -0
- data/lib/bel_parser/language/version1/return_types/rna_abundance.rb +17 -0
- data/lib/bel_parser/language/version1/return_types/substitution.rb +17 -0
- data/lib/bel_parser/language/version1/return_types/transcriptional_activity.rb +20 -0
- data/lib/bel_parser/language/version1/return_types/transport_activity.rb +20 -0
- data/lib/bel_parser/language/version1/return_types/truncation.rb +17 -0
- data/lib/bel_parser/language/version2.rb +50 -0
- data/lib/bel_parser/language/version2/functions/abundance.rb +165 -0
- data/lib/bel_parser/language/version2/functions/activity.rb +115 -0
- data/lib/bel_parser/language/version2/functions/biological_process.rb +85 -0
- data/lib/bel_parser/language/version2/functions/cell_secretion.rb +80 -0
- data/lib/bel_parser/language/version2/functions/cell_surface_expression.rb +80 -0
- data/lib/bel_parser/language/version2/functions/complex_abundance.rb +190 -0
- data/lib/bel_parser/language/version2/functions/composite_abundance.rb +80 -0
- data/lib/bel_parser/language/version2/functions/degradation.rb +80 -0
- data/lib/bel_parser/language/version2/functions/fragment.rb +119 -0
- data/lib/bel_parser/language/version2/functions/from_location.rb +85 -0
- data/lib/bel_parser/language/version2/functions/fusion.rb +227 -0
- data/lib/bel_parser/language/version2/functions/gene_abundance.rb +195 -0
- data/lib/bel_parser/language/version2/functions/list.rb +115 -0
- data/lib/bel_parser/language/version2/functions/location.rb +85 -0
- data/lib/bel_parser/language/version2/functions/micro_rna_abundance.rb +165 -0
- data/lib/bel_parser/language/version2/functions/molecular_activity.rb +83 -0
- data/lib/bel_parser/language/version2/functions/pathology.rb +85 -0
- data/lib/bel_parser/language/version2/functions/products.rb +80 -0
- data/lib/bel_parser/language/version2/functions/protein_abundance.rb +285 -0
- data/lib/bel_parser/language/version2/functions/protein_modification.rb +167 -0
- data/lib/bel_parser/language/version2/functions/reactants.rb +80 -0
- data/lib/bel_parser/language/version2/functions/reaction.rb +85 -0
- data/lib/bel_parser/language/version2/functions/rna_abundance.rb +195 -0
- data/lib/bel_parser/language/version2/functions/to_location.rb +85 -0
- data/lib/bel_parser/language/version2/functions/translocation.rb +90 -0
- data/lib/bel_parser/language/version2/functions/variant.rb +83 -0
- data/lib/bel_parser/language/version2/return_types/abundance.rb +20 -0
- data/lib/bel_parser/language/version2/return_types/activity.rb +20 -0
- data/lib/bel_parser/language/version2/return_types/any.rb +74 -0
- data/lib/bel_parser/language/version2/return_types/biological_process.rb +17 -0
- data/lib/bel_parser/language/version2/return_types/complex_abundance.rb +17 -0
- data/lib/bel_parser/language/version2/return_types/fragment.rb +20 -0
- data/lib/bel_parser/language/version2/return_types/from_location.rb +20 -0
- data/lib/bel_parser/language/version2/return_types/fusion.rb +17 -0
- data/lib/bel_parser/language/version2/return_types/gene_abundance.rb +17 -0
- data/lib/bel_parser/language/version2/return_types/list.rb +17 -0
- data/lib/bel_parser/language/version2/return_types/location.rb +20 -0
- data/lib/bel_parser/language/version2/return_types/micro_rna_abundance.rb +17 -0
- data/lib/bel_parser/language/version2/return_types/molecular_activity.rb +20 -0
- data/lib/bel_parser/language/version2/return_types/pathology.rb +17 -0
- data/lib/bel_parser/language/version2/return_types/products.rb +17 -0
- data/lib/bel_parser/language/version2/return_types/protein_abundance.rb +17 -0
- data/lib/bel_parser/language/version2/return_types/protein_modification.rb +17 -0
- data/lib/bel_parser/language/version2/return_types/reactants.rb +17 -0
- data/lib/bel_parser/language/version2/return_types/rna_abundance.rb +17 -0
- data/lib/bel_parser/language/version2/return_types/to_location.rb +20 -0
- data/lib/bel_parser/language/version2/return_types/variant.rb +20 -0
- data/lib/bel_parser/mixin/line_continuator.rb +15 -0
- data/lib/bel_parser/mixin/line_mapping.rb +14 -0
- data/lib/bel_parser/parser.rb +54 -0
- data/lib/bel_parser/parsers/ast/mapped_traversal.rb +36 -0
- data/lib/bel_parser/parsers/ast/node.rb +705 -0
- data/lib/bel_parser/parsers/ast/sexp.rb +8 -0
- data/lib/bel_parser/parsers/ast/traversal.rb +21 -0
- data/lib/bel_parser/parsers/bel_script.rb +4 -0
- data/lib/bel_parser/parsers/bel_script/define_annotation.rb +5476 -0
- data/lib/bel_parser/parsers/bel_script/define_annotation.rl +141 -0
- data/lib/bel_parser/parsers/bel_script/define_namespace.rb +1780 -0
- data/lib/bel_parser/parsers/bel_script/define_namespace.rl +121 -0
- data/lib/bel_parser/parsers/bel_script/set.rb +4556 -0
- data/lib/bel_parser/parsers/bel_script/set.rl +116 -0
- data/lib/bel_parser/parsers/bel_script/unset.rb +706 -0
- data/lib/bel_parser/parsers/bel_script/unset.rl +95 -0
- data/lib/bel_parser/parsers/common.rb +5 -0
- data/lib/bel_parser/parsers/common/blank_line.rb +211 -0
- data/lib/bel_parser/parsers/common/blank_line.rl +81 -0
- data/lib/bel_parser/parsers/common/comment_line.rb +245 -0
- data/lib/bel_parser/parsers/common/comment_line.rl +97 -0
- data/lib/bel_parser/parsers/common/common.rb +7 -0
- data/lib/bel_parser/parsers/common/common.rl +13 -0
- data/lib/bel_parser/parsers/common/identifier.rb +289 -0
- data/lib/bel_parser/parsers/common/identifier.rl +106 -0
- data/lib/bel_parser/parsers/common/list.rb +2142 -0
- data/lib/bel_parser/parsers/common/list.rl +144 -0
- data/lib/bel_parser/parsers/common/string.rb +271 -0
- data/lib/bel_parser/parsers/common/string.rl +107 -0
- data/lib/bel_parser/parsers/expression.rb +7 -0
- data/lib/bel_parser/parsers/expression/comment.rb +239 -0
- data/lib/bel_parser/parsers/expression/comment.rl +97 -0
- data/lib/bel_parser/parsers/expression/parameter.rb +1506 -0
- data/lib/bel_parser/parsers/expression/parameter.rl +97 -0
- data/lib/bel_parser/parsers/expression/relationship.rb +254 -0
- data/lib/bel_parser/parsers/expression/relationship.rl +98 -0
- data/lib/bel_parser/parsers/expression/statement_nested.rb +17802 -0
- data/lib/bel_parser/parsers/expression/statement_nested.rl +141 -0
- data/lib/bel_parser/parsers/expression/statement_observed_term.rb +7291 -0
- data/lib/bel_parser/parsers/expression/statement_observed_term.rl +92 -0
- data/lib/bel_parser/parsers/expression/statement_simple.rb +10475 -0
- data/lib/bel_parser/parsers/expression/statement_simple.rl +112 -0
- data/lib/bel_parser/parsers/expression/term.rb +3989 -0
- data/lib/bel_parser/parsers/expression/term.rl +157 -0
- data/lib/bel_parser/parsers/line_parser.rb +92 -0
- data/lib/bel_parser/parsers/mixin/buffer.rb +10 -0
- data/lib/bel_parser/parsers/nonblocking_io_wrapper.rb +50 -0
- data/lib/bel_parser/script/parser.rb +49 -0
- data/lib/bel_parser/vendor/ast.rb +17 -0
- data/lib/bel_parser/vendor/ast/node.rb +254 -0
- data/lib/bel_parser/vendor/ast/processor.rb +12 -0
- data/lib/bel_parser/vendor/ast/processor/mixin.rb +282 -0
- data/lib/bel_parser/vendor/ast/sexp.rb +30 -0
- 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,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
|