bel_parser 1.0.0.alpha.1
Sign up to get free protection for your applications and to get access to all the features.
- 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,42 @@
|
|
1
|
+
require_relative '../ast_filter'
|
2
|
+
require_relative '../ast_generator'
|
3
|
+
require_relative '../parsers/common'
|
4
|
+
require_relative '../parsers/expression'
|
5
|
+
require_relative '../mixin/line_mapping'
|
6
|
+
|
7
|
+
module BELParser
|
8
|
+
module Expression
|
9
|
+
# Parser for BEL Expression.
|
10
|
+
class Parser
|
11
|
+
include BELParser::Parsers::Common
|
12
|
+
include BELParser::Parsers::Expression
|
13
|
+
|
14
|
+
FILTER = BELParser::ASTFilter.new(
|
15
|
+
:statement_simple,
|
16
|
+
:observed_term,
|
17
|
+
:nested_statement
|
18
|
+
)
|
19
|
+
|
20
|
+
def each(io)
|
21
|
+
if block_given?
|
22
|
+
filtered_ast = FILTER.each(BELParser::ASTGenerator.new.each(io))
|
23
|
+
filtered_ast.each do |results|
|
24
|
+
yield results
|
25
|
+
end
|
26
|
+
else
|
27
|
+
enum_for(:each, io)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
if __FILE__ == $PROGRAM_NAME
|
35
|
+
BELParser::Expression::Parser.new.each($stdin) do |line_result|
|
36
|
+
line_number, line, ast_results = line_result
|
37
|
+
puts "#{line_number}: #{line}"
|
38
|
+
ast_results.each do |ast|
|
39
|
+
puts ast.to_s(1)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require_relative '../ast_filter'
|
2
|
+
require_relative '../ast_generator'
|
3
|
+
require_relative '../parsers/expression'
|
4
|
+
require_relative '../language/version2'
|
5
|
+
require_relative '../language/semantics/analyzer'
|
6
|
+
|
7
|
+
module BELParser
|
8
|
+
module Expression
|
9
|
+
# Parser for BEL Expression.
|
10
|
+
class TermSemanticsParser
|
11
|
+
include BELParser::Parsers::Common
|
12
|
+
include BELParser::Parsers::Expression
|
13
|
+
|
14
|
+
FILTER = BELParser::ASTFilter.new(:term)
|
15
|
+
|
16
|
+
def each(io)
|
17
|
+
if block_given?
|
18
|
+
v2 = BELParser::Language::Version2::Specification.new
|
19
|
+
filtered_ast = FILTER.each(BELParser::ASTGenerator.new.each(io))
|
20
|
+
filtered_ast.each do |results|
|
21
|
+
term = results.last.first
|
22
|
+
yield BELParser::Language::Semantics.check_term(term, v2)
|
23
|
+
end
|
24
|
+
else
|
25
|
+
enum_for(:each, io)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
if __FILE__ == $PROGRAM_NAME
|
33
|
+
BELParser::Expression::TermSemanticsParser.new.each($stdin) do |semantics|
|
34
|
+
puts semantics.join(", ")
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
require_relative 'language/function'
|
2
|
+
require_relative 'language/quoting'
|
3
|
+
require_relative 'language/semantic_ast'
|
4
|
+
require_relative 'language/signature'
|
5
|
+
require_relative 'language/specification'
|
6
|
+
|
7
|
+
# BEL language/version1 and language/version2 files are loaded when needed.
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module BELParser
|
2
|
+
module Language
|
3
|
+
# Function allows you to describe the type of BEL Term.
|
4
|
+
#
|
5
|
+
# BEL Terms are composed of BEL Functions and entity definitions
|
6
|
+
# referenced using BEL Namespace identifiers. Each BEL Term represents
|
7
|
+
# either an abundance of a biological entity, the abundance of human AKT1
|
8
|
+
# for example, or a biological process such as cardiomyopathy.
|
9
|
+
module Function
|
10
|
+
def short
|
11
|
+
raise NotImplementedError, "#{__method__} is not implemented."
|
12
|
+
end
|
13
|
+
|
14
|
+
def long
|
15
|
+
raise NotImplementedError, "#{__method__} is not implemented."
|
16
|
+
end
|
17
|
+
|
18
|
+
def return_type
|
19
|
+
raise NotImplementedError, "#{__method__} is not implemented."
|
20
|
+
end
|
21
|
+
|
22
|
+
def description
|
23
|
+
raise NotImplementedError, "#{__method__} is not implemented."
|
24
|
+
end
|
25
|
+
|
26
|
+
def signatures
|
27
|
+
raise NotImplementedError, "#{__method__} is not implemented."
|
28
|
+
end
|
29
|
+
|
30
|
+
def ===(other)
|
31
|
+
return false if other.nil?
|
32
|
+
short == other || long == other
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_sym(form = :short)
|
36
|
+
value = _form_value(form)
|
37
|
+
return nil unless value
|
38
|
+
value.to_s
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_s(form = :short)
|
42
|
+
value = _form_value(form)
|
43
|
+
return nil unless value
|
44
|
+
value.to_s
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def _form_value(form = :short)
|
50
|
+
case form
|
51
|
+
when :short
|
52
|
+
short
|
53
|
+
when :long
|
54
|
+
long
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,236 @@
|
|
1
|
+
module BELParser
|
2
|
+
|
3
|
+
# The Quoting module implements quoting rules consistent with BEL
|
4
|
+
# and BEL Script. Double quotes are used to group a string together
|
5
|
+
# which may contain whitespace or special characters.
|
6
|
+
#
|
7
|
+
# A value can either be an identifier or a string value. An
|
8
|
+
# identifier can only include the characters +[0-9A-Za-z_]+. A string
|
9
|
+
# value is necessary when at least one of +[^0-9A-Za-z_]+ exists in
|
10
|
+
# the value.
|
11
|
+
#
|
12
|
+
# Uses:
|
13
|
+
#
|
14
|
+
# BEL: The BEL parameters must be an identifier or string value.
|
15
|
+
#
|
16
|
+
# BEL Script: BEL parameters, document property values, and annotation
|
17
|
+
# values must be an identifier or string value.
|
18
|
+
module Quoting
|
19
|
+
|
20
|
+
# Declares BEL Script keywords that cause problems with the OpenBEL
|
21
|
+
# Framework parser.
|
22
|
+
Keywords = %w(SET DEFINE a g p r m)
|
23
|
+
|
24
|
+
# Regular expression that matches one of {Quoting::Keywords}.
|
25
|
+
KeywordMatcher = Regexp.compile(/^(#{Keywords.join('|')})$/)
|
26
|
+
|
27
|
+
# Regular expression that matches on any non-word character.
|
28
|
+
NonWordMatcher = Regexp.compile(/[^0-9a-zA-Z_]/)
|
29
|
+
|
30
|
+
# Regular expression that matches a value surrounded by unescaped
|
31
|
+
# double quotes.
|
32
|
+
StrictQuotedMatcher = Regexp.compile(/\A".*?(?<!\\)"\Z/m)
|
33
|
+
|
34
|
+
# Regular expression that matches a value surrounded by double quotes
|
35
|
+
# that may be escaped.
|
36
|
+
LenientQuotedMatcher = Regexp.compile(/\A".*?"\Z/m)
|
37
|
+
|
38
|
+
# Regular expression that matches double quotes that are not escaped.
|
39
|
+
QuoteNotEscapedMatcher = Regexp.compile(/(?<!\\)"/m)
|
40
|
+
|
41
|
+
# Returns +value+ surrounded by double quotes. This method is idempotent
|
42
|
+
# so +value+ will only be quoted once regardless of how may times the
|
43
|
+
# method is called on it.
|
44
|
+
#
|
45
|
+
# @example Quoting a BEL parameter.
|
46
|
+
# quote("apoptotic process")
|
47
|
+
# # => "\"apoptotic process\""
|
48
|
+
# @example Escaping quotes within a value.
|
49
|
+
# quote("vesicle fusion with \"Golgi apparatus\"")
|
50
|
+
# # => "\"vesicle fusion with \\\"Golgi apparatus\\\"\""
|
51
|
+
#
|
52
|
+
# @parameter [#to_s] value a value to be quoted
|
53
|
+
# @return [String] value surrounded by double quotes
|
54
|
+
def quote(value)
|
55
|
+
string = value.to_s
|
56
|
+
unquoted = unquote(string)
|
57
|
+
escaped = unquoted.gsub(QuoteNotEscapedMatcher, "\\\"")
|
58
|
+
%Q{"#{escaped}"}
|
59
|
+
end
|
60
|
+
|
61
|
+
# Returns +value+ with surrounded quotes removed.
|
62
|
+
#
|
63
|
+
# @example Unquoting a BEL parameter.
|
64
|
+
# unquote("\"apoptotic process\"")
|
65
|
+
# # => "apoptotic process"
|
66
|
+
# @example Escaped quotes are preserved.
|
67
|
+
# unquote("\"vesicle fusion with \"Golgi apparatus\"\"")
|
68
|
+
#
|
69
|
+
# @parameter [#to_s] value a value to be unquoted
|
70
|
+
# @return [String] value with surrounding double quotes removed
|
71
|
+
def unquote(value)
|
72
|
+
string = value.to_s
|
73
|
+
if string =~ StrictQuotedMatcher
|
74
|
+
string[1...-1]
|
75
|
+
else
|
76
|
+
string
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Returns +value+ with quoting applied only if necessary. A +value+
|
81
|
+
# consisting of only word character (e.g. [0-9A-Za-z_]) does not need
|
82
|
+
# quoting. A +value+ consisting of at least one non-word character
|
83
|
+
# (e.g. [^0-9A-Za-z_]) will requiring quoting.
|
84
|
+
#
|
85
|
+
# @example Quotes added when value includes spaces.
|
86
|
+
# quote_if_needed("apoptotic process")
|
87
|
+
# # => "\"apoptotic process\""
|
88
|
+
# @example Quotes added when value includes double quote.
|
89
|
+
# quote_if_needed("vesicle fusion with \"Golgi apparatus\"")
|
90
|
+
# # => "\"vesicle fusion with \\\"Golgi apparatus\\\"\""
|
91
|
+
# @example No quotes necessary for identifier.
|
92
|
+
# quote_if_needed("AKT1_HUMAN")
|
93
|
+
# # => "AKT1_HUMAN"
|
94
|
+
#
|
95
|
+
# @parameter [#to_s] value that may be quoted
|
96
|
+
# @return [String] original value or quoted value
|
97
|
+
def quote_if_needed(value)
|
98
|
+
if string_value?(value)
|
99
|
+
quote(value)
|
100
|
+
else
|
101
|
+
value.to_s
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# Returns whether the +value+ is surrounded by double quotes.
|
106
|
+
#
|
107
|
+
# @example Returns +true+ when value is quoted.
|
108
|
+
# quoted?("\"vesicle fusion with \"Golgi apparatus\"")
|
109
|
+
# # => true
|
110
|
+
# @example Returns +false+ when value is not quoted.
|
111
|
+
# quoted?("apoptotic process")
|
112
|
+
# # => false
|
113
|
+
#
|
114
|
+
# @parameter [#to_s] value to test
|
115
|
+
# @return [Boolean] +true+ if +value+ is quoted, +false+ if
|
116
|
+
# +value+ is not quoted
|
117
|
+
def quoted?(value)
|
118
|
+
string = value.to_s
|
119
|
+
(string =~ LenientQuotedMatcher) != nil
|
120
|
+
end
|
121
|
+
|
122
|
+
# Returns whether the +value+ is not surrounded by double quotes.
|
123
|
+
#
|
124
|
+
# @example Returns +true+ when value is not quoted.
|
125
|
+
# unquoted?("apoptotic process")
|
126
|
+
# # => true
|
127
|
+
# @example Returns +false+ when value is quoted.
|
128
|
+
# unquoted?("\"vesicle fusion with \"Golgi apparatus\"")
|
129
|
+
# # => false
|
130
|
+
#
|
131
|
+
# @parameter [#to_s] value to test
|
132
|
+
# @return [Boolean] +true+ if +value+ is not quoted, +false+ if
|
133
|
+
# +value+ is quoted
|
134
|
+
def unquoted?(value)
|
135
|
+
!quoted?(value)
|
136
|
+
end
|
137
|
+
|
138
|
+
# Returns whether the +value+ represents an identifier. An
|
139
|
+
# identifier consists of only word characters (e.g. [0-9A-Za-z_]).
|
140
|
+
#
|
141
|
+
# @example Returns +true+ when representing an identifier.
|
142
|
+
# identifier_value?("AKT1_HUMAN")
|
143
|
+
# # => true
|
144
|
+
# @example Returns +false+ when not representing an identifier.
|
145
|
+
# identifier_value?("apoptotic process")
|
146
|
+
# # => false
|
147
|
+
#
|
148
|
+
# @parameter [#to_s] value to test
|
149
|
+
# @return [Boolean] +true+ if +value+ is an identifier,
|
150
|
+
# +false+ if +value+ is not an identifier
|
151
|
+
def identifier_value?(value)
|
152
|
+
string = value.to_s
|
153
|
+
[NonWordMatcher, KeywordMatcher].none? { |matcher|
|
154
|
+
matcher.match string
|
155
|
+
}
|
156
|
+
end
|
157
|
+
|
158
|
+
# Returns whether the +value+ represents a string value. A string
|
159
|
+
# value consists of at least one non-word character
|
160
|
+
# (e.g. [^0-9A-Za-z_]).
|
161
|
+
#
|
162
|
+
# @example Returns +true+ when representing a string value.
|
163
|
+
# string_value?("apoptotic process")
|
164
|
+
# # => true
|
165
|
+
# @example Returns +false+ when not representing a string value.
|
166
|
+
# string_value?("AKT1_HUMAN")
|
167
|
+
# # => false
|
168
|
+
#
|
169
|
+
# @parameter [#to_s] value to test
|
170
|
+
# @return [Boolean] +true+ if +value+ is a string value,
|
171
|
+
# +false+ if +value+ is not a string value
|
172
|
+
def string_value?(value)
|
173
|
+
string = value.to_s
|
174
|
+
[NonWordMatcher, KeywordMatcher].any? { |matcher|
|
175
|
+
matcher.match string
|
176
|
+
}
|
177
|
+
end
|
178
|
+
|
179
|
+
## Deprecated, remove in [0.6.0].
|
180
|
+
|
181
|
+
# @deprecated Use {#quote_if_needed} instead. Will be removed in a
|
182
|
+
# future release.
|
183
|
+
def ensure_quotes identifier
|
184
|
+
warn <<-DOC.gsub(/^\s+/, '')
|
185
|
+
Deprecation Warning
|
186
|
+
-------------------
|
187
|
+
The BEL::Quoting::ensure_quotes method is deprecated and
|
188
|
+
will be removed in a future relase.
|
189
|
+
Call module method BEL::Quoting.quote_if_needed instead.
|
190
|
+
DOC
|
191
|
+
quote_if_needed(identifier)
|
192
|
+
end
|
193
|
+
|
194
|
+
# @deprecated Use {#unquote} instead. Will be removed in a
|
195
|
+
# future release.
|
196
|
+
def remove_quotes identifier
|
197
|
+
warn <<-DOC.gsub(/^\s+/, '')
|
198
|
+
Deprecation Warning
|
199
|
+
-------------------
|
200
|
+
The BEL::Quoting::remove_quotes method is deprecated and
|
201
|
+
will be removed in a future relase.
|
202
|
+
Call module method BEL::Quoting.unquote instead.
|
203
|
+
DOC
|
204
|
+
unquote(identifier)
|
205
|
+
end
|
206
|
+
|
207
|
+
# @deprecated Use {#quote} instead. Will be removed in a
|
208
|
+
# future release.
|
209
|
+
def always_quote identifier
|
210
|
+
warn <<-DOC.gsub(/^\s+/, '')
|
211
|
+
Deprecation Warning
|
212
|
+
-------------------
|
213
|
+
The BEL::Quoting::always_quote method is deprecated and
|
214
|
+
will be removed in a future relase.
|
215
|
+
Call module method BEL::Quoting.quote instead.
|
216
|
+
DOC
|
217
|
+
quote(identifier)
|
218
|
+
end
|
219
|
+
|
220
|
+
# @deprecated Use {#quoted?} or {#unquoted?} instead. Will be removed
|
221
|
+
# in a future release.
|
222
|
+
def quotes_required? identifier
|
223
|
+
warn <<-DOC.gsub(/^\s+/, '')
|
224
|
+
Deprecation Warning
|
225
|
+
-------------------
|
226
|
+
The BEL::Quoting::quotes_required? method is deprecated and
|
227
|
+
will be removed in a future relase.
|
228
|
+
You can use BEL::Quoting.quoted? and BEL::Quoting.unquoted?
|
229
|
+
going forward.
|
230
|
+
DOC
|
231
|
+
[NonWordMatcher, KeywordMatcher].any? { |m|
|
232
|
+
m.match identifier.to_s
|
233
|
+
}
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
@@ -0,0 +1,604 @@
|
|
1
|
+
require_relative 'quoting'
|
2
|
+
require_relative '../parsers/ast/node'
|
3
|
+
|
4
|
+
module BELParser
|
5
|
+
module Language
|
6
|
+
# Semantics capture BEL version-independent semantics for terms and
|
7
|
+
# statements.
|
8
|
+
module Semantics
|
9
|
+
# rubocop:disable Metrics/MethodLength
|
10
|
+
# rubocop:disable Metrics/AbcSize
|
11
|
+
def self.match(input_ast, semantic_ast, spec, match_results = [])
|
12
|
+
res = semantic_ast.match(input_ast, spec)
|
13
|
+
match_results.concat(res)
|
14
|
+
if res.flatten.all?(&:success?) && !semantic_ast.terminal?
|
15
|
+
return match_results if semantic_ast.children.empty?
|
16
|
+
|
17
|
+
var_test = semantic_ast.children.any? { |x| x.is_a?(SemanticVariadicArguments) }
|
18
|
+
if var_test
|
19
|
+
test_pairs = input_ast.children.zip(semantic_ast.children).select do |pair|
|
20
|
+
!pair.include?(nil)
|
21
|
+
end
|
22
|
+
|
23
|
+
test_pairs.each do |(input_child, semantic_child)|
|
24
|
+
if semantic_child.is_a?(SemanticVariadicArguments)
|
25
|
+
input_children = input_ast.children
|
26
|
+
input_arguments = input_children[input_children.index(input_child)..-1]
|
27
|
+
argument_pattern = semantic_child.children.first
|
28
|
+
input_arguments.each do |argument_child|
|
29
|
+
res = semantic_child.match(argument_child, spec)
|
30
|
+
match_results << res
|
31
|
+
if res.all?(&:success?)
|
32
|
+
param_or_term = argument_child.children.first
|
33
|
+
match(param_or_term, argument_pattern, spec, match_results)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
else
|
37
|
+
match(input_child, semantic_child, spec, match_results)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
else
|
41
|
+
semantic_ast
|
42
|
+
.children
|
43
|
+
.zip(input_ast.children)
|
44
|
+
.each do |semantic_child, input_child|
|
45
|
+
match(input_child, semantic_child, spec, match_results)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
match_results.flatten
|
50
|
+
end
|
51
|
+
|
52
|
+
# MatchResult holds the results of an input AST to semantic AST match.
|
53
|
+
class MatchResult
|
54
|
+
attr_reader :input_node, :semantic_node
|
55
|
+
|
56
|
+
def initialize(success, input_node, semantic_node)
|
57
|
+
@success = success
|
58
|
+
@input_node = input_node
|
59
|
+
@semantic_node = semantic_node
|
60
|
+
end
|
61
|
+
|
62
|
+
def success?
|
63
|
+
@success
|
64
|
+
end
|
65
|
+
|
66
|
+
def failure?
|
67
|
+
!@success
|
68
|
+
end
|
69
|
+
|
70
|
+
def to_s
|
71
|
+
msg
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Builder contains methods to build semantic AST nodes.
|
76
|
+
# A convenient {Builder.build} method allows you to use these
|
77
|
+
# methods within a block scope.
|
78
|
+
#
|
79
|
+
# see Builder.build
|
80
|
+
module Builder
|
81
|
+
def self.build(&block)
|
82
|
+
raise ArgumentError, 'expecting block' unless block_given?
|
83
|
+
|
84
|
+
builder = _builder_class.new
|
85
|
+
builder.instance_eval(&block)
|
86
|
+
builder.result
|
87
|
+
end
|
88
|
+
|
89
|
+
def self._builder_class
|
90
|
+
Class.new do
|
91
|
+
include Builder
|
92
|
+
|
93
|
+
attr_reader :result
|
94
|
+
|
95
|
+
def term(function, *arguments, **properties)
|
96
|
+
@result = super
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
private_class_method :_builder_class
|
101
|
+
|
102
|
+
def term(function, *arguments, **properties)
|
103
|
+
SemanticTerm.new([function, *arguments], **properties)
|
104
|
+
end
|
105
|
+
|
106
|
+
def function(identifier, **properties)
|
107
|
+
SemanticFunction.new([identifier], **properties)
|
108
|
+
end
|
109
|
+
|
110
|
+
def argument(param_or_term, **properties)
|
111
|
+
cls = param_or_term.class
|
112
|
+
if cls != SemanticParameter && cls != SemanticTerm
|
113
|
+
raise ArgumentError, 'expected SemanticParameter or SemanticTerm'
|
114
|
+
end
|
115
|
+
|
116
|
+
SemanticArgument.new([param_or_term], **properties)
|
117
|
+
end
|
118
|
+
|
119
|
+
def parameter(prefix, value, **properties)
|
120
|
+
SemanticParameter.new([prefix, value], **properties)
|
121
|
+
end
|
122
|
+
|
123
|
+
def identifier(*value_patterns, **properties)
|
124
|
+
SemanticIdentifier.new(value_patterns, **properties)
|
125
|
+
end
|
126
|
+
|
127
|
+
def prefix(has_namespace, **properties)
|
128
|
+
SemanticPrefix.new([has_namespace], **properties)
|
129
|
+
end
|
130
|
+
|
131
|
+
def value(value_type, **properties)
|
132
|
+
SemanticValue.new([value_type], **properties)
|
133
|
+
end
|
134
|
+
|
135
|
+
def value_type(*value_patterns, **properties)
|
136
|
+
SemanticValueType.new(value_patterns, **properties)
|
137
|
+
end
|
138
|
+
|
139
|
+
def any(**properties)
|
140
|
+
SemanticAny.new(**properties)
|
141
|
+
end
|
142
|
+
|
143
|
+
# rubocop:disable Style/PredicateName
|
144
|
+
def is_nil(**properties)
|
145
|
+
SemanticIsNil.new(**properties)
|
146
|
+
end
|
147
|
+
|
148
|
+
def has_namespace(**properties)
|
149
|
+
SemanticHasNamespace.new(**properties)
|
150
|
+
end
|
151
|
+
|
152
|
+
def has_encoding(**properties)
|
153
|
+
SemanticHasEncoding.new(**properties)
|
154
|
+
end
|
155
|
+
|
156
|
+
def function_of(*functions, **properties)
|
157
|
+
SemanticFunctionOf.new(functions, **properties)
|
158
|
+
end
|
159
|
+
|
160
|
+
def return_type_of(*return_types, **properties)
|
161
|
+
SemanticReturnTypeOf.new(return_types, **properties)
|
162
|
+
end
|
163
|
+
|
164
|
+
def namespace_of(*namespaces, **properties)
|
165
|
+
SemanticNamespaceOf.new(namespaces, **properties)
|
166
|
+
end
|
167
|
+
|
168
|
+
def encoding_of(*encoding_types, **properties)
|
169
|
+
SemanticEncodingOf.new(encoding_types, **properties)
|
170
|
+
end
|
171
|
+
|
172
|
+
def covalent_modification_of(*covalent_mod_types, **properties)
|
173
|
+
SemanticCovalentModificationOf.new(covalent_mod_types, **properties)
|
174
|
+
end
|
175
|
+
|
176
|
+
def amino_acid_of(*amino_acids, **properties)
|
177
|
+
SemanticAminoAcidOf.new(amino_acids, **properties)
|
178
|
+
end
|
179
|
+
|
180
|
+
def is_amino_acid_range_pattern(**properties)
|
181
|
+
SemanticIsAminoAcidRange.new(**properties)
|
182
|
+
end
|
183
|
+
|
184
|
+
def variadic_arguments(*params_or_terms, **properties)
|
185
|
+
SemanticVariadicArguments.new(params_or_terms, **properties)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
# SemanticASTNode represents a node in the semantic tree structure.
|
190
|
+
class SemanticASTNode < AST::Node
|
191
|
+
def initialize(type, children = [], **properties)
|
192
|
+
super(type, children, properties)
|
193
|
+
end
|
194
|
+
|
195
|
+
def terminal?
|
196
|
+
false
|
197
|
+
end
|
198
|
+
|
199
|
+
protected
|
200
|
+
|
201
|
+
def updated(_ = nil, children = nil, properties = nil)
|
202
|
+
new_children = children || @children
|
203
|
+
new_properties = properties || {}
|
204
|
+
|
205
|
+
if @children == new_children && properties.nil?
|
206
|
+
self
|
207
|
+
else
|
208
|
+
# Maybe change call?
|
209
|
+
original_dup.send :initialize, new_children, new_properties
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
def success(node)
|
214
|
+
[MatchResult.new(true, node, self)]
|
215
|
+
end
|
216
|
+
|
217
|
+
def failure(node)
|
218
|
+
[MatchResult.new(false, node, self)]
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
# AST node for Term is a semantic AST.
|
223
|
+
class SemanticTerm < SemanticASTNode
|
224
|
+
def initialize(children = [], **properties)
|
225
|
+
super(:term, children, properties)
|
226
|
+
end
|
227
|
+
|
228
|
+
def match(parse_node, _)
|
229
|
+
type == parse_node.type ? success(parse_node) : failure(parse_node)
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
# AST node for Statement is a semantic AST.
|
234
|
+
class SemanticStatement < SemanticASTNode
|
235
|
+
def initialize(children = [], **properties)
|
236
|
+
super(:statement, children, properties)
|
237
|
+
end
|
238
|
+
|
239
|
+
def match(parse_node, _)
|
240
|
+
type == parse_node.type ? success(parse_node) : failure(parse_node)
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
# AST node for Parameter is a semantic AST.
|
245
|
+
class SemanticParameter < SemanticASTNode
|
246
|
+
def initialize(children = [], **properties)
|
247
|
+
super(:parameter, children, properties)
|
248
|
+
end
|
249
|
+
|
250
|
+
def match(parse_node, _)
|
251
|
+
type == parse_node.type ? success(parse_node) : failure(parse_node)
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
# AST node for Function is a semantic AST.
|
256
|
+
class SemanticFunction < SemanticASTNode
|
257
|
+
def initialize(children = [], **properties)
|
258
|
+
super(:function, children, properties)
|
259
|
+
end
|
260
|
+
|
261
|
+
def match(parse_node, _)
|
262
|
+
type == parse_node.type ? success(parse_node) : failure(parse_node)
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
# AST node for Argument is a semantic AST.
|
267
|
+
class SemanticArgument < SemanticASTNode
|
268
|
+
def initialize(children = [], **properties)
|
269
|
+
super(:argument, children, properties)
|
270
|
+
end
|
271
|
+
|
272
|
+
def match(parse_node, _)
|
273
|
+
return failure(nil) if parse_node.nil?
|
274
|
+
type == parse_node.type ? success(parse_node) : failure(parse_node)
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
# AST node for VariadicArguments is a semantic AST.
|
279
|
+
class SemanticVariadicArguments < SemanticASTNode
|
280
|
+
def initialize(children = [], **properties)
|
281
|
+
super(:variadic_arguments, children, properties)
|
282
|
+
end
|
283
|
+
|
284
|
+
def match(parse_node, _)
|
285
|
+
if parse_node.type == BELParser::Parsers::AST::Argument.ast_type
|
286
|
+
success(parse_node)
|
287
|
+
else
|
288
|
+
failure(parse_node)
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
# AST node for Prefix is a semantic AST.
|
294
|
+
class SemanticPrefix < SemanticASTNode
|
295
|
+
def initialize(children = [], **properties)
|
296
|
+
super(:prefix, children, properties)
|
297
|
+
end
|
298
|
+
|
299
|
+
def match(parse_node, _)
|
300
|
+
type == parse_node.type ? success(parse_node) : failure(parse_node)
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
# AST node for Value is a semantic AST.
|
305
|
+
class SemanticValue < SemanticASTNode
|
306
|
+
def initialize(children = [], **properties)
|
307
|
+
super(:value, children, properties)
|
308
|
+
end
|
309
|
+
|
310
|
+
def match(parse_node, _)
|
311
|
+
type == parse_node.type ? success(parse_node) : failure(parse_node)
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
# AST node for Nil is a semantic AST.
|
316
|
+
class SemanticIsNil < SemanticASTNode
|
317
|
+
def initialize(**properties)
|
318
|
+
super(:is_nil, [], properties)
|
319
|
+
end
|
320
|
+
|
321
|
+
def terminal?
|
322
|
+
true
|
323
|
+
end
|
324
|
+
|
325
|
+
def match(parse_node, _)
|
326
|
+
parse_node.nil? ? success(parse_node) : failure(nil)
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
# AST node for Identifier is a semantic AST.
|
331
|
+
class SemanticIdentifier < SemanticASTNode
|
332
|
+
def initialize(children = [], **properties)
|
333
|
+
super(:identifier, children, properties)
|
334
|
+
end
|
335
|
+
|
336
|
+
def terminal?
|
337
|
+
true
|
338
|
+
end
|
339
|
+
|
340
|
+
def value_patterns
|
341
|
+
children
|
342
|
+
end
|
343
|
+
|
344
|
+
def match(identifier, spec)
|
345
|
+
return failure(nil) if identifier.nil?
|
346
|
+
return failure(identifier) if type != identifier.type
|
347
|
+
|
348
|
+
value_results = value_patterns.map do |pattern|
|
349
|
+
pattern.match(identifier, spec)
|
350
|
+
end
|
351
|
+
|
352
|
+
failure_result = value_results.flatten.find(&:failure?)
|
353
|
+
|
354
|
+
if failure_result
|
355
|
+
[failure(identifier), failure_result]
|
356
|
+
else
|
357
|
+
value_results.unshift(success(identifier))
|
358
|
+
end
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
# AST node for Any is a semantic AST.
|
363
|
+
class SemanticAny < SemanticASTNode
|
364
|
+
def initialize(**properties)
|
365
|
+
super(:any, [], properties)
|
366
|
+
end
|
367
|
+
|
368
|
+
def match(parse_node, _)
|
369
|
+
success(parse_node)
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
373
|
+
# AST node for HasNamespace is a semantic AST.
|
374
|
+
class SemanticHasNamespace < SemanticASTNode
|
375
|
+
def initialize(**properties)
|
376
|
+
super(:has_namespace, [], properties)
|
377
|
+
end
|
378
|
+
|
379
|
+
def match(identifier, _)
|
380
|
+
# FIXME: Implement :namespace property assignment to AST.
|
381
|
+
return success(identifier)
|
382
|
+
if identifier.respond_to?(:namespace)
|
383
|
+
success(identifier)
|
384
|
+
else
|
385
|
+
failure(identifier)
|
386
|
+
end
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
390
|
+
# AST node for NamespaceOf is a semantic AST.
|
391
|
+
class SemanticNamespaceOf < SemanticASTNode
|
392
|
+
def initialize(namespaces, **properties)
|
393
|
+
super(:namespace_of, namespaces, properties)
|
394
|
+
end
|
395
|
+
|
396
|
+
def match(identifier, _)
|
397
|
+
# FIXME: Implement :namespace property assignment to AST.
|
398
|
+
return success(identifier)
|
399
|
+
return failure(identifier) unless identifier.respond_to?(:namespace)
|
400
|
+
input_namespace = identifier.namespace
|
401
|
+
return failure(identifier) if input_namespace.nil?
|
402
|
+
|
403
|
+
namespace_set = children
|
404
|
+
if namespace_set.any? { |i| i == :* || i == input_namespace }
|
405
|
+
success(identifier)
|
406
|
+
else
|
407
|
+
failure(identifier)
|
408
|
+
end
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
412
|
+
# AST node for HasEncoding is a semantic AST.
|
413
|
+
class SemanticHasEncoding < SemanticASTNode
|
414
|
+
def initialize(**properties)
|
415
|
+
super(:has_encoding, [], properties)
|
416
|
+
end
|
417
|
+
|
418
|
+
def match(value_type, _)
|
419
|
+
# FIXME: Implement :encoding property assignment to AST.
|
420
|
+
return success(value_type)
|
421
|
+
if value_type.respond_to?(:encoding)
|
422
|
+
success(value_type)
|
423
|
+
else
|
424
|
+
failure(value_type)
|
425
|
+
end
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|
429
|
+
# AST node for EncodingOf is a semantic AST.
|
430
|
+
class SemanticEncodingOf < SemanticASTNode
|
431
|
+
def initialize(encodings, **properties)
|
432
|
+
super(:encoding_of, encodings, properties)
|
433
|
+
end
|
434
|
+
|
435
|
+
def match(value_type, _)
|
436
|
+
# FIXME: Implement :encoding property assignment to AST.
|
437
|
+
return success(value_type)
|
438
|
+
encoding_set = children
|
439
|
+
return success(value_type) if encoding_set.include?(:*)
|
440
|
+
|
441
|
+
return failure(value_type) unless value_type.respond_to?(:encoding)
|
442
|
+
|
443
|
+
input_encoding = value_type.encoding
|
444
|
+
return failure(value_type) if input_encoding.nil?
|
445
|
+
|
446
|
+
if encoding_set.include?(input_encoding)
|
447
|
+
success(value_type)
|
448
|
+
else
|
449
|
+
failure(value_type)
|
450
|
+
end
|
451
|
+
end
|
452
|
+
end
|
453
|
+
|
454
|
+
# AST node for FunctionOf is a semantic AST.
|
455
|
+
class SemanticFunctionOf < SemanticASTNode
|
456
|
+
def initialize(functions, **properties)
|
457
|
+
super(:function_of, functions, properties)
|
458
|
+
end
|
459
|
+
|
460
|
+
def functions
|
461
|
+
children
|
462
|
+
end
|
463
|
+
|
464
|
+
def match(identifier, spec)
|
465
|
+
return success(identifier) if functions.include?(:*)
|
466
|
+
|
467
|
+
function = spec.function(identifier.children[0].to_sym)
|
468
|
+
if functions.include?(function)
|
469
|
+
success(identifier)
|
470
|
+
else
|
471
|
+
failure(identifier)
|
472
|
+
end
|
473
|
+
end
|
474
|
+
end
|
475
|
+
|
476
|
+
# AST node for ReturnTypeOf is a semantic AST.
|
477
|
+
class SemanticReturnTypeOf < SemanticASTNode
|
478
|
+
def initialize(return_types, **properties)
|
479
|
+
super(:return_type_of, return_types, properties)
|
480
|
+
end
|
481
|
+
|
482
|
+
def return_types
|
483
|
+
children
|
484
|
+
end
|
485
|
+
|
486
|
+
def match(identifier, spec)
|
487
|
+
return success(identifier) if return_types.include?(:*)
|
488
|
+
|
489
|
+
fx_return = spec.function(identifier.children[0].to_sym).return_type
|
490
|
+
if return_types.any? { |rt| fx_return <= rt }
|
491
|
+
success(identifier)
|
492
|
+
else
|
493
|
+
failure(identifier)
|
494
|
+
end
|
495
|
+
end
|
496
|
+
end
|
497
|
+
|
498
|
+
# AST node for ValueType is a semantic AST.
|
499
|
+
class SemanticValueType < SemanticASTNode
|
500
|
+
TYPES = [
|
501
|
+
BELParser::Parsers::AST::Identifier.ast_type,
|
502
|
+
BELParser::Parsers::AST::String.ast_type
|
503
|
+
].freeze
|
504
|
+
|
505
|
+
def initialize(children = [], **properties)
|
506
|
+
super(:value_type, children, properties)
|
507
|
+
end
|
508
|
+
|
509
|
+
def terminal?
|
510
|
+
true
|
511
|
+
end
|
512
|
+
|
513
|
+
def value_patterns
|
514
|
+
children
|
515
|
+
end
|
516
|
+
|
517
|
+
def match(value_type, spec)
|
518
|
+
return failure(value_type) unless TYPES.include?(value_type.type)
|
519
|
+
|
520
|
+
value_results = value_patterns.map do |pattern|
|
521
|
+
pattern.match(value_type, spec)
|
522
|
+
end
|
523
|
+
|
524
|
+
failure_result = value_results.flatten.find(&:failure?)
|
525
|
+
|
526
|
+
if failure_result
|
527
|
+
[failure(value_type), failure_result]
|
528
|
+
else
|
529
|
+
value_results.unshift(success(value_type))
|
530
|
+
end
|
531
|
+
end
|
532
|
+
end
|
533
|
+
|
534
|
+
# AST node for CovalentModificationOf is a semantic AST.
|
535
|
+
class SemanticCovalentModificationOf < SemanticASTNode
|
536
|
+
def initialize(covalent_mod_types, **properties)
|
537
|
+
properties[:hashed] = Hash[covalent_mod_types.map { |t| [t, true] }]
|
538
|
+
super(:covalent_modification_of, covalent_mod_types, properties)
|
539
|
+
end
|
540
|
+
|
541
|
+
def covalent_mod_types
|
542
|
+
children
|
543
|
+
end
|
544
|
+
|
545
|
+
def match(value_type, _)
|
546
|
+
string_literal_sym = value_type.children[0].to_sym
|
547
|
+
return success(value_type) if @hashed[:*]
|
548
|
+
|
549
|
+
if @hashed.key?(string_literal_sym)
|
550
|
+
success(value_type)
|
551
|
+
else
|
552
|
+
failure(value_type)
|
553
|
+
end
|
554
|
+
end
|
555
|
+
end
|
556
|
+
|
557
|
+
# AST node for AminoAcidOf is a semantic AST.
|
558
|
+
class SemanticAminoAcidOf < SemanticASTNode
|
559
|
+
def initialize(amino_acids, **properties)
|
560
|
+
properties[:hashed] = Hash[amino_acids.map { |t| [t, true] }]
|
561
|
+
super(:amino_acid_of, amino_acids, properties)
|
562
|
+
end
|
563
|
+
|
564
|
+
def amino_acids
|
565
|
+
children
|
566
|
+
end
|
567
|
+
|
568
|
+
def match(value_type, _)
|
569
|
+
string_literal_sym = value_type.children[0].to_sym
|
570
|
+
return success(value_type) if @hashed[:*]
|
571
|
+
|
572
|
+
if @hashed.key?(string_literal_sym)
|
573
|
+
success(value_type)
|
574
|
+
else
|
575
|
+
failure(value_type)
|
576
|
+
end
|
577
|
+
end
|
578
|
+
end
|
579
|
+
|
580
|
+
# AST node for IsAminoAcidRange is a semantic AST.
|
581
|
+
class SemanticIsAminoAcidRange < SemanticASTNode
|
582
|
+
START_STOP = /[1-9][0-9]*_[1-9][0-9]*/
|
583
|
+
UNDETERMINED = /[1?]_[?*]/
|
584
|
+
UNKNOWN_START_STOP = "?"
|
585
|
+
|
586
|
+
include BELParser::Quoting
|
587
|
+
|
588
|
+
def initialize(**properties)
|
589
|
+
super(:is_amino_acid_range, [], properties)
|
590
|
+
end
|
591
|
+
|
592
|
+
def match(value_type, _)
|
593
|
+
string_literal = unquote(value_type.children[0])
|
594
|
+
case string_literal
|
595
|
+
when START_STOP, UNDETERMINED, UNKNOWN_START_STOP
|
596
|
+
success(value_type)
|
597
|
+
else
|
598
|
+
failure(value_type)
|
599
|
+
end
|
600
|
+
end
|
601
|
+
end
|
602
|
+
end
|
603
|
+
end
|
604
|
+
end
|