bel_parser 1.0.0.alpha.13 → 1.0.0.alpha.14
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 +4 -4
- data/VERSION +1 -1
- data/lib/bel_parser/language/apply_namespace_encoding.rb +5 -2
- data/lib/bel_parser/language/expression_validator.rb +25 -7
- data/lib/bel_parser/language/syntax/undefined_namespace_value.rb +5 -6
- data/lib/bel_parser/language.rb +8 -0
- data/lib/bel_parser/parsers/ast/node.rb +30 -3
- data/lib/bel_parser/parsers/bel_script/define_annotation.rb +1732 -1288
- data/lib/bel_parser/parsers/bel_script/set.rb +1424 -972
- data/lib/bel_parser/parsers/bel_script/set_document.rb +2735 -2100
- data/lib/bel_parser/parsers/common/list.rb +708 -462
- data/lib/bel_parser/parsers/common/list.rl +6 -4
- data/lib/bel_parser/resource/eager_reader.rb +9 -9
- data/lib/bel_parser/resource/http_cache.rb +26 -8
- data/lib/bel_parser/resource/resource_file_reader.rb +1 -0
- data/lib/bel_parser/resource/sparql_reader.rb +1 -0
- data/lib/bel_parser/script/state/annotation_definition.rb +62 -0
- data/lib/bel_parser/script/state/bel_version.rb +35 -0
- data/lib/bel_parser/script/state/document_property.rb +29 -0
- data/lib/bel_parser/script/state/namespace_definition.rb +32 -0
- data/lib/bel_parser/script/state/set.rb +57 -0
- data/lib/bel_parser/script/state/unset.rb +43 -0
- data/lib/bel_parser/script/state_function.rb +10 -0
- data/lib/bel_parser/script/syntax/expression_validation.rb +46 -0
- data/lib/bel_parser/script/syntax/invalid_regex_pattern.rb +49 -0
- data/lib/bel_parser/script/syntax/undefined_annotation.rb +60 -0
- data/lib/bel_parser/script/syntax/undefined_annotation_value.rb +83 -0
- data/lib/bel_parser/script/syntax/unresolvable_namespace.rb +55 -0
- data/lib/bel_parser/script/syntax/unsupported_bel_version.rb +58 -0
- data/lib/bel_parser/script/validator.rb +153 -0
- metadata +15 -1
@@ -25,9 +25,11 @@
|
|
25
25
|
|
26
26
|
action append_list {
|
27
27
|
# Append list argument if its value is not empty.
|
28
|
-
|
29
|
-
|
30
|
-
|
28
|
+
if @buffers[:list_arg]
|
29
|
+
list_arg_value = @buffers[:list_arg].children[0].children[0]
|
30
|
+
if list_arg_value != ''
|
31
|
+
@buffers[:list] <<= @buffers[:list_arg]
|
32
|
+
end
|
31
33
|
end
|
32
34
|
}
|
33
35
|
|
@@ -60,7 +62,7 @@
|
|
60
62
|
(
|
61
63
|
STRING %string $err(error_list_string) |
|
62
64
|
IDENT %ident $err(error_list_ident)
|
63
|
-
) $err(append_list) %append_list
|
65
|
+
)? $err(append_list) %append_list
|
64
66
|
SP*
|
65
67
|
(
|
66
68
|
',' @clear
|
@@ -34,7 +34,7 @@ module BELParser
|
|
34
34
|
return cached_concept if cached_concept
|
35
35
|
end
|
36
36
|
|
37
|
-
|
37
|
+
nil
|
38
38
|
end
|
39
39
|
|
40
40
|
def retrieve_values_from_resource(resource_identifier)
|
@@ -52,17 +52,17 @@ module BELParser
|
|
52
52
|
if lock.try_lock
|
53
53
|
Thread.new do
|
54
54
|
value_hash = {
|
55
|
-
:name =>
|
56
|
-
:identifier =>
|
57
|
-
:title =>
|
58
|
-
:synonyms =>
|
55
|
+
:name => {},
|
56
|
+
:identifier => {},
|
57
|
+
:title => {},
|
58
|
+
:synonyms => {}
|
59
59
|
}
|
60
60
|
retrieve_values_from_resource(identifier).each do |concept|
|
61
|
-
value_hash[:name][concept.name]
|
62
|
-
value_hash[:identifier][concept.identifier]
|
63
|
-
value_hash[:title][concept.title]
|
61
|
+
value_hash[:name][concept.name] = concept
|
62
|
+
value_hash[:identifier][concept.identifier] = concept
|
63
|
+
value_hash[:title][concept.title] = concept
|
64
64
|
concept.synonyms.each do |synonym|
|
65
|
-
value_hash[:synonyms][synonym]
|
65
|
+
value_hash[:synonyms][synonym] = concept
|
66
66
|
end
|
67
67
|
end
|
68
68
|
resources[identifier] = value_hash
|
@@ -32,24 +32,42 @@ module BELParser
|
|
32
32
|
end
|
33
33
|
else
|
34
34
|
uri = URI.parse(url)
|
35
|
-
cached_file = File.open(cached_url_path, 'w')
|
36
35
|
begin
|
37
36
|
Net::HTTP.start(uri.host, uri.port) do |http|
|
38
37
|
http.request(Net::HTTP::Get.new(uri)) do |response|
|
38
|
+
|
39
39
|
if block_given?
|
40
|
-
response.
|
41
|
-
cached_file.
|
42
|
-
|
40
|
+
if response.is_a?(Net::HTTPOK)
|
41
|
+
cached_file = File.open(cached_url_path, 'w')
|
42
|
+
response.read_body do |chunk|
|
43
|
+
cached_file.write(chunk)
|
44
|
+
yield StringIO.new(chunk)
|
45
|
+
end
|
46
|
+
else
|
47
|
+
yield nil
|
43
48
|
end
|
44
49
|
else
|
45
|
-
|
46
|
-
|
47
|
-
|
50
|
+
if response.is_a?(Net::HTTPOK)
|
51
|
+
cached_file = File.open(cached_url_path, 'w')
|
52
|
+
content = response.read_body
|
53
|
+
cached_file.write(content)
|
54
|
+
return StringIO.new(content)
|
55
|
+
else
|
56
|
+
return nil
|
57
|
+
end
|
48
58
|
end
|
49
59
|
end
|
50
60
|
end
|
61
|
+
rescue SocketError
|
62
|
+
if block_given?
|
63
|
+
yield nil
|
64
|
+
else
|
65
|
+
return nil
|
66
|
+
end
|
51
67
|
ensure
|
52
|
-
cached_file
|
68
|
+
if defined? cached_file
|
69
|
+
cached_file.close
|
70
|
+
end
|
53
71
|
end
|
54
72
|
end
|
55
73
|
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'bel_parser/language'
|
2
|
+
require 'bel_parser/quoting'
|
3
|
+
require 'bel_parser/parsers/ast/node'
|
4
|
+
require 'concurrent/hash'
|
5
|
+
require_relative '../state_function'
|
6
|
+
|
7
|
+
module BELParser
|
8
|
+
module Script
|
9
|
+
module State
|
10
|
+
class AnnotationDefinition
|
11
|
+
extend StateFunction
|
12
|
+
extend BELParser::Quoting
|
13
|
+
|
14
|
+
TARGET_NODE = BELParser::Parsers::AST::AnnotationDefinition
|
15
|
+
|
16
|
+
def self.consume(ast_node, script_context)
|
17
|
+
return nil unless ast_node.is_a?(TARGET_NODE)
|
18
|
+
resource_reader = script_context[:resource_reader]
|
19
|
+
|
20
|
+
keyword, domain = ast_node.children
|
21
|
+
prefix = keyword.identifier.string_literal
|
22
|
+
case
|
23
|
+
when domain.list?
|
24
|
+
handle_list(prefix, domain.child, script_context)
|
25
|
+
when domain.url?
|
26
|
+
handle_url(prefix, domain.child, script_context)
|
27
|
+
when domain.pattern?
|
28
|
+
handle_pattern(prefix, domain.child, script_context)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.handle_list(prefix, list_node, script_context)
|
33
|
+
script_context[:annotation_definitions] ||= Concurrent::Hash.new
|
34
|
+
script_context[:annotation_definitions][prefix] = [
|
35
|
+
:list,
|
36
|
+
list_node.list_items.map do |li|
|
37
|
+
unquote(li.children[0].string_literal)
|
38
|
+
end
|
39
|
+
]
|
40
|
+
end
|
41
|
+
private_class_method :handle_list
|
42
|
+
|
43
|
+
def self.handle_pattern(prefix, pattern_node, script_context)
|
44
|
+
script_context[:annotation_definitions] ||= Concurrent::Hash.new
|
45
|
+
script_context[:annotation_definitions][prefix] = [
|
46
|
+
:pattern,
|
47
|
+
unquote(pattern_node.string)
|
48
|
+
]
|
49
|
+
end
|
50
|
+
private_class_method :handle_pattern
|
51
|
+
|
52
|
+
def self.handle_url(prefix, url_node, script_context)
|
53
|
+
url = unquote(url_node.string.string_literal)
|
54
|
+
dataset = script_context[:resource_reader].retrieve_resource(url)
|
55
|
+
script_context[:annotation_definitions] ||= Concurrent::Hash.new
|
56
|
+
script_context[:annotation_definitions][prefix] = [:url, dataset]
|
57
|
+
end
|
58
|
+
private_class_method :handle_url
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'bel_parser/language'
|
2
|
+
require 'bel_parser/parsers/ast/node'
|
3
|
+
require 'bel_parser/quoting'
|
4
|
+
require 'concurrent/hash'
|
5
|
+
require_relative '../state_function'
|
6
|
+
|
7
|
+
module BELParser
|
8
|
+
module Script
|
9
|
+
module State
|
10
|
+
class BELVersion
|
11
|
+
extend StateFunction
|
12
|
+
extend BELParser::Quoting
|
13
|
+
|
14
|
+
TARGET_NODE = BELParser::Parsers::AST::DocumentProperty
|
15
|
+
BEL_VERSION_REGEX = /#{Regexp.escape('bel_version')}/i
|
16
|
+
DEFAULT_BEL_VERSION = '2.0'
|
17
|
+
|
18
|
+
def self.consume(ast_node, script_context)
|
19
|
+
return unless ast_node.is_a?(TARGET_NODE)
|
20
|
+
name, value = ast_node.children
|
21
|
+
name_string = name.identifier.string_literal
|
22
|
+
return unless name_string =~ BEL_VERSION_REGEX
|
23
|
+
|
24
|
+
value_string = unquote(value.children[0].string_literal)
|
25
|
+
begin
|
26
|
+
spec = BELParser::Language.specification(value_string)
|
27
|
+
rescue ArgumentError
|
28
|
+
spec = BELParser::Language.specification(DEFAULT_BEL_VERSION)
|
29
|
+
end
|
30
|
+
script_context[:specification] = spec
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'bel_parser/parsers/ast/node'
|
2
|
+
require 'bel_parser/quoting'
|
3
|
+
require 'concurrent/hash'
|
4
|
+
require_relative '../state_function'
|
5
|
+
|
6
|
+
module BELParser
|
7
|
+
module Script
|
8
|
+
module State
|
9
|
+
class DocumentProperty
|
10
|
+
extend StateFunction
|
11
|
+
extend BELParser::Quoting
|
12
|
+
|
13
|
+
TARGET_NODE = BELParser::Parsers::AST::DocumentProperty
|
14
|
+
|
15
|
+
def self.consume(ast_node, script_context)
|
16
|
+
return nil unless ast_node.is_a?(TARGET_NODE)
|
17
|
+
hash = script_context[:document_properties] ||= Concurrent::Hash.new
|
18
|
+
|
19
|
+
name, value = ast_node.children
|
20
|
+
if name && value
|
21
|
+
name_string = name.identifier.string_literal
|
22
|
+
value_string = value.children[0].string_literal
|
23
|
+
hash[name_string] = unquote(value_string)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'bel_parser/language'
|
2
|
+
require 'bel_parser/quoting'
|
3
|
+
require 'bel_parser/parsers/ast/node'
|
4
|
+
require 'concurrent/hash'
|
5
|
+
require_relative '../state_function'
|
6
|
+
|
7
|
+
module BELParser
|
8
|
+
module Script
|
9
|
+
module State
|
10
|
+
class NamespaceDefinition
|
11
|
+
extend StateFunction
|
12
|
+
extend BELParser::Quoting
|
13
|
+
|
14
|
+
TARGET_NODE = BELParser::Parsers::AST::NamespaceDefinition
|
15
|
+
|
16
|
+
def self.consume(ast_node, script_context)
|
17
|
+
return nil unless ast_node.is_a?(TARGET_NODE)
|
18
|
+
resource_reader = script_context[:resource_reader]
|
19
|
+
|
20
|
+
keyword, domain = ast_node.children
|
21
|
+
if domain.url?
|
22
|
+
prefix = keyword.identifier.string_literal
|
23
|
+
url = unquote(domain.child.string.string_literal)
|
24
|
+
dataset = resource_reader.retrieve_resource(url)
|
25
|
+
script_context[:namespace_definitions] ||= Concurrent::Hash.new
|
26
|
+
script_context[:namespace_definitions][prefix] = dataset
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'bel_parser/language'
|
2
|
+
require 'bel_parser/quoting'
|
3
|
+
require 'bel_parser/parsers/ast/node'
|
4
|
+
require 'concurrent/hash'
|
5
|
+
require_relative '../state_function'
|
6
|
+
|
7
|
+
module BELParser
|
8
|
+
module Script
|
9
|
+
module State
|
10
|
+
class Set
|
11
|
+
extend StateFunction
|
12
|
+
extend BELParser::Quoting
|
13
|
+
|
14
|
+
TARGET_NODE = BELParser::Parsers::AST::Set
|
15
|
+
LIST_NODE = BELParser::Parsers::AST::List
|
16
|
+
|
17
|
+
def self.consume(ast_node, script_context)
|
18
|
+
return nil unless ast_node.is_a?(TARGET_NODE)
|
19
|
+
name, value = ast_node.children
|
20
|
+
name_string = name.identifier.string_literal
|
21
|
+
value_node = ast_node.value.children[0]
|
22
|
+
if value_node.is_a?(LIST_NODE)
|
23
|
+
value_node
|
24
|
+
.list_items.map { |li| li.children[0].string_literal }
|
25
|
+
.each do |string|
|
26
|
+
handle_annotation(name_string, string, script_context)
|
27
|
+
end
|
28
|
+
else
|
29
|
+
value_string = value_node.string_literal
|
30
|
+
case name_string
|
31
|
+
when /\ASTATEMENT_GROUP\Z/
|
32
|
+
handle_statement_group(value_string, script_context)
|
33
|
+
else
|
34
|
+
handle_annotation(name_string, value_string, script_context)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.handle_annotation(name, value, script_context)
|
40
|
+
# add to annotation state
|
41
|
+
script_context[:annotations] ||= Concurrent::Hash.new
|
42
|
+
script_context[:annotations][name] = value
|
43
|
+
end
|
44
|
+
private_class_method :handle_annotation
|
45
|
+
|
46
|
+
def self.handle_statement_group(value, script_context)
|
47
|
+
script_context[:statement_group] = value
|
48
|
+
|
49
|
+
# clear annotation state
|
50
|
+
script_context[:annotations] ||= Concurrent::Hash.new
|
51
|
+
script_context[:annotations].clear
|
52
|
+
end
|
53
|
+
private_class_method :handle_statement_group
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'bel_parser/language'
|
2
|
+
require 'bel_parser/quoting'
|
3
|
+
require 'bel_parser/parsers/ast/node'
|
4
|
+
require 'concurrent/hash'
|
5
|
+
require_relative '../state_function'
|
6
|
+
|
7
|
+
module BELParser
|
8
|
+
module Script
|
9
|
+
module State
|
10
|
+
class Unset
|
11
|
+
extend StateFunction
|
12
|
+
extend BELParser::Quoting
|
13
|
+
|
14
|
+
TARGET_NODE = BELParser::Parsers::AST::Unset
|
15
|
+
|
16
|
+
def self.consume(ast_node, script_context)
|
17
|
+
return nil unless ast_node.is_a?(TARGET_NODE)
|
18
|
+
name_string = ast_node.name.identifier.string_literal
|
19
|
+
case name_string
|
20
|
+
when /\ASTATEMENT_GROUP\Z/
|
21
|
+
handle_statement_group(script_context)
|
22
|
+
else
|
23
|
+
handle_annotation(name_string, script_context)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.handle_annotation(name, script_context)
|
28
|
+
script_context[:annotations] ||= Concurrent::Hash.new
|
29
|
+
script_context[:annotations].delete(name)
|
30
|
+
end
|
31
|
+
private_class_method :handle_annotation
|
32
|
+
|
33
|
+
def self.handle_statement_group(script_context)
|
34
|
+
script_context.delete(:statement_group)
|
35
|
+
|
36
|
+
script_context[:annotations] ||= Concurrent::Hash.new
|
37
|
+
script_context[:annotations].clear
|
38
|
+
end
|
39
|
+
private_class_method :handle_statement_group
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'bel_parser/language'
|
2
|
+
require 'bel_parser/language/expression_validator'
|
3
|
+
require 'bel_parser/language/syntax_function'
|
4
|
+
require 'bel_parser/language/syntax_warning'
|
5
|
+
require 'bel_parser/quoting'
|
6
|
+
require 'bel_parser/parsers/ast/node'
|
7
|
+
require 'concurrent/hash'
|
8
|
+
|
9
|
+
module BELParser
|
10
|
+
module Script
|
11
|
+
module Syntax
|
12
|
+
class ExpressionValidation
|
13
|
+
extend BELParser::Language::Syntax::SyntaxFunction
|
14
|
+
extend BELParser::Quoting
|
15
|
+
|
16
|
+
TARGET_NODES = [
|
17
|
+
BELParser::Parsers::AST::ObservedTerm,
|
18
|
+
BELParser::Parsers::AST::SimpleStatement,
|
19
|
+
BELParser::Parsers::AST::NestedStatement
|
20
|
+
]
|
21
|
+
EXP_VALIDATOR = BELParser::Language::ExpressionValidator
|
22
|
+
|
23
|
+
def self.map(ast_node, script_context)
|
24
|
+
return nil unless TARGET_NODES.include?(ast_node.class)
|
25
|
+
return nil unless script_context.key?(:specification)
|
26
|
+
|
27
|
+
validator = expression_validator(script_context)
|
28
|
+
validator.validate(ast_node).select(&:failure?)
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.expression_validator(script_context)
|
32
|
+
unless defined? @expression_validator
|
33
|
+
spec, namespaces, reader =
|
34
|
+
script_context
|
35
|
+
.values_at(
|
36
|
+
:specification,
|
37
|
+
:namespace_definitions,
|
38
|
+
:resource_reader)
|
39
|
+
@expression_validator = EXP_VALIDATOR.new(spec, namespaces, reader)
|
40
|
+
end
|
41
|
+
@expression_validator
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'bel_parser/language'
|
2
|
+
require 'bel_parser/language/syntax_function'
|
3
|
+
require 'bel_parser/language/syntax_error'
|
4
|
+
require 'bel_parser/quoting'
|
5
|
+
require 'bel_parser/parsers/ast/node'
|
6
|
+
require 'concurrent/hash'
|
7
|
+
|
8
|
+
module BELParser
|
9
|
+
module Script
|
10
|
+
module Syntax
|
11
|
+
class InvalidRegexPattern
|
12
|
+
extend BELParser::Language::Syntax::SyntaxFunction
|
13
|
+
extend BELParser::Quoting
|
14
|
+
|
15
|
+
TARGET_NODE = BELParser::Parsers::AST::Pattern
|
16
|
+
|
17
|
+
def self.map(ast_node, script_context)
|
18
|
+
return nil unless ast_node.is_a?(TARGET_NODE)
|
19
|
+
pattern = unquote(ast_node.string.string_literal)
|
20
|
+
begin
|
21
|
+
Regexp.new(pattern)
|
22
|
+
nil
|
23
|
+
rescue RegexpError => error
|
24
|
+
InvalidRegexPatternError.new(ast_node, pattern, error.to_s)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# InvalidRegexPattern indicates that a pattern represented an invalid
|
30
|
+
# regular expression.
|
31
|
+
class InvalidRegexPatternError < BELParser::Language::Syntax::SyntaxError
|
32
|
+
# Gets the invalid pattern.
|
33
|
+
attr_reader :pattern
|
34
|
+
|
35
|
+
def initialize(pattern_node, pattern, error_msg)
|
36
|
+
super(pattern_node, nil)
|
37
|
+
@pattern = pattern
|
38
|
+
@error_msg = error_msg
|
39
|
+
end
|
40
|
+
|
41
|
+
def msg
|
42
|
+
<<-MSG.gsub(/^ +/, '').delete("\n")
|
43
|
+
"#@pattern" is not a valid regular expression (#@error_msg).
|
44
|
+
MSG
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'bel_parser/language'
|
2
|
+
require 'bel_parser/language/syntax_function'
|
3
|
+
require 'bel_parser/language/syntax_error'
|
4
|
+
require 'bel_parser/quoting'
|
5
|
+
require 'bel_parser/parsers/ast/node'
|
6
|
+
require 'concurrent/hash'
|
7
|
+
|
8
|
+
module BELParser
|
9
|
+
module Script
|
10
|
+
module Syntax
|
11
|
+
class UndefinedAnnotation
|
12
|
+
extend BELParser::Language::Syntax::SyntaxFunction
|
13
|
+
|
14
|
+
TARGET_NODE = BELParser::Parsers::AST::Set
|
15
|
+
IMPLICIT_KEYWORDS = ['Citation', 'Evidence', 'STATEMENT_GROUP']
|
16
|
+
|
17
|
+
def self.map(ast_node, script_context)
|
18
|
+
return nil unless ast_node.is_a?(TARGET_NODE)
|
19
|
+
name_string = ast_node.name.identifier.string_literal
|
20
|
+
annotation_definitions =
|
21
|
+
script_context[:annotation_definitions] ||= Concurrent::Hash.new
|
22
|
+
|
23
|
+
return nil if IMPLICIT_KEYWORDS.include?(name_string)
|
24
|
+
return nil if annotation_definitions.key?(name_string)
|
25
|
+
UndefinedAnnotationError.new(
|
26
|
+
ast_node,
|
27
|
+
name_string,
|
28
|
+
script_context[:annotation_definitions])
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# UndefinedAnnotationError represents an undefined annotation seen when
|
33
|
+
# checking a SET annotation.
|
34
|
+
class UndefinedAnnotationError < BELParser::Language::Syntax::SyntaxError
|
35
|
+
# Gets the undefined prefix.
|
36
|
+
attr_reader :prefix
|
37
|
+
|
38
|
+
def initialize(set_node, prefix, annotation_definitions)
|
39
|
+
super(set_node, nil)
|
40
|
+
@prefix = prefix
|
41
|
+
@annotation_definitions = annotation_definitions
|
42
|
+
end
|
43
|
+
|
44
|
+
def msg
|
45
|
+
defined_annotations =
|
46
|
+
if @annotation_definitions.empty?
|
47
|
+
'No annotations are defined.'
|
48
|
+
else
|
49
|
+
annotation_prefixes = @annotation_definitions.keys.join(', ')
|
50
|
+
"Defined annotations: #{annotation_prefixes}"
|
51
|
+
end
|
52
|
+
<<-MSG.gsub(/^ +/, '').delete("\n")
|
53
|
+
Annotation definition is missing for "#@prefix".
|
54
|
+
#{defined_annotations}
|
55
|
+
MSG
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'bel_parser/language'
|
2
|
+
require 'bel_parser/language/syntax_function'
|
3
|
+
require 'bel_parser/language/syntax_warning'
|
4
|
+
require 'bel_parser/quoting'
|
5
|
+
require 'bel_parser/parsers/ast/node'
|
6
|
+
require 'concurrent/hash'
|
7
|
+
|
8
|
+
module BELParser
|
9
|
+
module Script
|
10
|
+
module Syntax
|
11
|
+
class UndefinedAnnotationValue
|
12
|
+
extend BELParser::Language::Syntax::SyntaxFunction
|
13
|
+
extend BELParser::Quoting
|
14
|
+
|
15
|
+
TARGET_NODE = BELParser::Parsers::AST::Set
|
16
|
+
LIST_NODE = BELParser::Parsers::AST::List
|
17
|
+
IMPLICIT_KEYWORDS = ['Citation', 'Evidence', 'STATEMENT_GROUP']
|
18
|
+
|
19
|
+
def self.map(ast_node, script_context)
|
20
|
+
return nil unless ast_node.is_a?(TARGET_NODE)
|
21
|
+
name, value = ast_node.children
|
22
|
+
name_string = ast_node.name.identifier.string_literal
|
23
|
+
|
24
|
+
return nil if IMPLICIT_KEYWORDS.include?(name_string)
|
25
|
+
dataset = annotation(name_string, script_context)
|
26
|
+
return nil unless dataset
|
27
|
+
|
28
|
+
rr = script_context[:resource_reader]
|
29
|
+
value_node = ast_node.value.children[0]
|
30
|
+
if value_node.is_a?(LIST_NODE)
|
31
|
+
value_node
|
32
|
+
.list_items.map { |li| li.children[0].string_literal }
|
33
|
+
.map do |string|
|
34
|
+
map_value(ast_node, name_string, string, dataset.identifier, rr)
|
35
|
+
end
|
36
|
+
else
|
37
|
+
map_value(
|
38
|
+
ast_node,
|
39
|
+
name_string,
|
40
|
+
value_node.string_literal,
|
41
|
+
dataset.identifier,
|
42
|
+
rr)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.annotation(name_string, script_context)
|
47
|
+
hash =
|
48
|
+
script_context[:annotation_definitions] ||= Concurrent::Hash.new
|
49
|
+
type, definition = hash[name_string]
|
50
|
+
type == :url ? definition : nil
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.map_value(ast_node, name_string, value_string, identifier, rr)
|
54
|
+
value_string = unquote(value_string)
|
55
|
+
value = rr.retrieve_value_from_resource(identifier, value_string)
|
56
|
+
UndefinedAnnotationValueWarning.new(
|
57
|
+
ast_node,
|
58
|
+
name_string,
|
59
|
+
value_string) unless value
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# UndefinedAnnotationValueWarning represents an undefined annotation value
|
64
|
+
# while checking a SET annotation.
|
65
|
+
class UndefinedAnnotationValueWarning < BELParser::Language::Syntax::SyntaxWarning
|
66
|
+
# Gets the prefix.
|
67
|
+
attr_reader :prefix
|
68
|
+
# Gets the undefined annotation value.
|
69
|
+
attr_reader :value
|
70
|
+
|
71
|
+
def initialize(set_node, prefix, value)
|
72
|
+
super(set_node, nil)
|
73
|
+
@prefix = prefix
|
74
|
+
@value = value
|
75
|
+
end
|
76
|
+
|
77
|
+
def msg
|
78
|
+
%(Undefined annotation value "#@value" for annotation "#@prefix".)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|