bel_parser 1.0.0.alpha.3 → 1.0.0.alpha.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fc1ced9daf61e6924edb4e15fe137e76fac85049
4
- data.tar.gz: 1662c4c080eb06306ddc52a0c730bb226fe89e69
3
+ metadata.gz: 3ef8ebaf115a02e0b19b7af93039277e7e31ec98
4
+ data.tar.gz: 9a34c875fa35ea3926b2c285b7ea031320e39194
5
5
  SHA512:
6
- metadata.gz: 614db5a804a2ded6d9df1e93fe0a656fc033deccce4a20b649a52ead92eb18efc89900cbb3946f48faa97f29c0657b4c2190e7a987db0fc86b8c8ed9864356ee
7
- data.tar.gz: 1d10d5b3a5605cd52ed3adde6998a0f6d0412c4f5008b71f818398e7f80e173348ac849f82b333c89ead3b1015fd75db5aff08fdf395f59198e60aabc43648a0
6
+ metadata.gz: 2c355a19969807bc4d582a62a66f84cdac544efbd2a2a117d18c53c21dcb2dd0ae9043ce18d801f6475e0e40af1d2886518c3249ec77b3951d8e4b178586ed07
7
+ data.tar.gz: 0c7e304b87dea0e1b27009d93190a1f862f04e8cc4283f482e3117b55441467f160da8e0925bc05d3b7c4a12119cf6ec71786c2d11084c5a58f4e8bb1147a550
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.0.alpha.3
1
+ 1.0.0.alpha.4
data/bin/bel2_validator CHANGED
@@ -13,7 +13,5 @@ namespaces = Hash[ARGV[1..-1].map { |ns| ns.split('=') }]
13
13
  require 'bel_parser'
14
14
  require 'bel_parser/expression/term_validator'
15
15
  BELParser::Expression::TermValidator.new(ARGV.first, namespaces).each($stdin) do |res|
16
- res.each do |res|
17
- puts " #{res}"
18
- end
16
+ puts res.map { |r| "#{r}\n" }.join.each_line.map { |l| " #{l}" }.join
19
17
  end
@@ -44,7 +44,7 @@ if __FILE__ == $PROGRAM_NAME
44
44
  namespaces = Hash[ARGV[1..-1].map { |ns| ns.split('=') }]
45
45
  BELParser::Expression::TermValidator.new(ARGV.first, namespaces).each($stdin) do |res|
46
46
  res.each do |res|
47
- puts " #{res}"
47
+ puts res.each_line.map { |l| " #{l}" }.join
48
48
  end
49
49
  end
50
50
  end
@@ -5,27 +5,57 @@ module BELParser
5
5
  module Language
6
6
  class ExpressionValidator
7
7
  def initialize(spec, namespaces)
8
- @spec = spec
9
- @namespaces = namespaces
10
- @syntax_functions = Syntax.syntax_functions
8
+ @spec = spec
9
+ @namespaces = namespaces
10
+ @syntax_functions = Syntax.syntax_functions
11
+ @semantics_functions = Semantics.semantics_functions
11
12
  end
12
13
 
13
- def validate(expression_ast)
14
- syntax_problems = syntax(expression_ast)
15
- return syntax_problems unless syntax_problems.empty?
16
- [Syntax::Valid.new(expression_ast, @spec)] + semantics(expression_ast)
14
+ def validate(term_ast)
15
+ results = syntax(term_ast)
16
+ if results.empty?
17
+ results << Syntax::Valid.new(term_ast, @spec)
18
+ results.concat(semantics(term_ast))
19
+ end
20
+ results
17
21
  end
18
22
 
19
23
  private
20
24
 
21
- def syntax(expression_ast)
22
- @syntax_functions.flat_map do |syntax_function|
23
- syntax_function.map(expression_ast, @spec, @namespaces)
25
+ def syntax(term_ast)
26
+ syntax_results = syntax_term(term_ast).compact
27
+ end
28
+
29
+ def semantics(term_ast)
30
+ semantics_term(term_ast)
31
+ end
32
+
33
+ def syntax_term(term_ast)
34
+ syntax_results = @syntax_functions.flat_map do |syntax_func|
35
+ syntax_func.map(term_ast, @spec, @namespaces)
24
36
  end
37
+
38
+ term_ast.arguments
39
+ .select(&:has_term?)
40
+ .map(&:child)
41
+ .each do |child_term|
42
+ syntax_results.concat(syntax_term(child_term))
43
+ end
44
+ syntax_results
25
45
  end
26
46
 
27
- def semantics(expression_ast)
28
- BELParser::Language::Semantics.check_term(expression_ast, @spec)
47
+ def semantics_term(term_ast)
48
+ semantics_results = @semantics_functions.flat_map do |semantics_func|
49
+ semantics_func.map(term_ast, @spec, @namespaces)
50
+ end
51
+
52
+ term_ast.arguments
53
+ .select(&:has_term?)
54
+ .map(&:child)
55
+ .each do |child_term|
56
+ semantics_results.concat(semantics_term(child_term))
57
+ end
58
+ semantics_results
29
59
  end
30
60
  end
31
61
  end
@@ -0,0 +1,78 @@
1
+ require 'bel_parser/parsers/ast/node'
2
+
3
+ module BELParser
4
+ module Language
5
+ module Semantics
6
+ class SignatureMapping
7
+ include SemanticsFunction
8
+
9
+ private_class_method :new
10
+
11
+ # Map {BELParser::Parsers::AST::Term term} to BEL signatures defined
12
+ # by a {BELParser::Language::Specification}. The mapping includes both
13
+ # successful and failed signature matches.
14
+ def self.map(term_ast, spec, namespaces)
15
+ unless term_ast.is_a?(BELParser::Parsers::AST::Term)
16
+ raise(
17
+ ArgumentError,
18
+ "term_ast: expected BELParser::Parsers::AST::Term")
19
+ end
20
+
21
+ function_name = term_ast.function.identifier.string_literal
22
+ function = spec.function(function_name.to_sym)
23
+ match = BELParser::Language::Semantics.method(:match)
24
+
25
+ successes, failures = function.signatures
26
+ .map { |sig| [sig, match.call(term_ast, sig.semantic_ast, spec)] }
27
+ .partition { |(sig, results)| results.all?(&:success?) }
28
+
29
+ if successes.empty?
30
+ SignatureMappingWarning.new(term_ast, spec, failures)
31
+ else
32
+ SignatureMappingSuccess.new(term_ast, spec, successes, failures)
33
+ end
34
+ end
35
+ end
36
+
37
+ class SignatureMappingSuccess < SemanticsResult
38
+ attr_reader :success_signatures
39
+ attr_reader :failure_signatures
40
+
41
+ def initialize(expression_node, spec, successes, failures)
42
+ super(expression_node, spec)
43
+ @success_signatures = successes
44
+ @failure_signatures = failures
45
+ end
46
+
47
+ def to_s
48
+ sig_list = success_signatures
49
+ .map { |(sig, results)| sig.string_form }
50
+ .join("\n ")
51
+ <<-MSG.gsub(/ {12}/, '').gsub(/\n$/, '')
52
+ Term matches function signatures:
53
+ #{sig_list}
54
+ MSG
55
+ end
56
+ end
57
+
58
+ class SignatureMappingWarning < SemanticsWarning
59
+ attr_reader :failure_signatures
60
+
61
+ def initialize(expression_node, spec, failure_signatures)
62
+ super(expression_node, spec)
63
+ @failure_signatures = failure_signatures
64
+ end
65
+
66
+ def to_s
67
+ sig_list = failure_signatures
68
+ .map { |(sig, results)| sig.string_form }
69
+ .join("\n ")
70
+ <<-MSG.gsub(/ {12}/, '').gsub(/\n$/, '')
71
+ Term did not conform to function signatures:
72
+ #{sig_list}
73
+ MSG
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -1,2 +1,35 @@
1
- require_relative 'semantics/semantic_ast'
2
- require_relative 'semantics/analyzer'
1
+ require_relative 'semantics_match'
2
+ require_relative 'semantics_ast'
3
+ require_relative 'semantics_result'
4
+ require_relative 'semantics_warning'
5
+ require_relative 'semantics_function'
6
+
7
+ module BELParser
8
+ module Language
9
+ module Semantics
10
+ def self.semantics_functions
11
+ self.constants.collect do |symbol|
12
+ const = self.const_get(symbol)
13
+ const if
14
+ const.respond_to?(:include?) &&
15
+ const.include?(SemanticsFunction)
16
+ end.compact
17
+ end
18
+
19
+ class Valid < SemanticsResult
20
+ def msg
21
+ 'Semantics are valid.'
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ # Require all semantics functions.
29
+ Dir[
30
+ File.join(
31
+ File.dirname(File.expand_path(__FILE__)),
32
+ 'semantics', '*.rb')
33
+ ].each do |path|
34
+ require_relative "semantics/#{File.basename(path)}"
35
+ end
@@ -1,6 +1,6 @@
1
- require_relative 'semantic_match'
2
- require_relative '../quoting'
3
- require_relative '../../parsers/ast/node'
1
+ require_relative 'semantics_match'
2
+ require_relative 'quoting'
3
+ require_relative '../parsers/ast/node'
4
4
 
5
5
  module BELParser
6
6
  module Language
@@ -0,0 +1,13 @@
1
+ module BELParser
2
+ module Language
3
+ module Semantics
4
+ module SemanticsFunction
5
+ # @abstract Include {SemanticsFunction} and override {#map} to check
6
+ # term semantics (e.g. signatures).
7
+ def self.map(term_ast, spec, namespaces)
8
+ raise NotImplementedError, "#{__method__} is not implemented."
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,23 @@
1
+ module BELParser
2
+ module Language
3
+ module Semantics
4
+ class SemanticsResult
5
+ attr_reader :expression_node, :specification
6
+
7
+ def initialize(expression_node, specification)
8
+ @expression_node = expression_node
9
+ @specification = specification
10
+ end
11
+
12
+ # @abstract Subclass and override {#msg} to provide the message.
13
+ def msg
14
+ raise NotImplementedError, "#{__method__} is not implemented."
15
+ end
16
+
17
+ def to_s
18
+ "Info: #{msg}"
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,17 @@
1
+ require_relative 'semantics_result'
2
+
3
+ module BELParser
4
+ module Language
5
+ module Semantics
6
+ class SemanticsWarning < SemanticsResult
7
+ def initialize(expression_node, specification)
8
+ super(expression_node, specification)
9
+ end
10
+
11
+ def to_s
12
+ "Warning: #{msg}"
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -10,33 +10,27 @@ module BELParser
10
10
 
11
11
  private_class_method :new
12
12
 
13
- def self.map(expression_ast, spec, namespaces)
14
- errors = []
15
- expression_ast.traverse.map do |node|
16
- next unless node.is_a?(BELParser::Parsers::AST::Function)
17
- function_name = node.identifier.string_literal
18
- unless spec.function(function_name.to_sym)
19
- errors << InvalidFunctionSyntaxError.new(
20
- expression_ast, spec, node, spec.functions)
21
- end
13
+ def self.map(term_node, spec, namespaces)
14
+ function_name = term_node.function.identifier.string_literal
15
+ unless spec.function(function_name.to_sym)
16
+ InvalidFunctionSyntaxError.new(term_node, spec, function_name)
22
17
  end
23
- errors
24
18
  end
25
19
  end
26
20
 
27
21
  # InvalidFunctionSyntaxError indicates a function name was invalid.
28
22
  class InvalidFunctionSyntaxError < SyntaxError
29
- # Gets the functions defined by a BEL specification.
30
- attr_reader :bel_functions
23
+ # Gets the function literal that was invalid according to a
24
+ # BEL specification.
25
+ attr_reader :function
31
26
 
32
- def initialize(expression_node, spec, error_node, bel_functions)
33
- super(expression_node, spec, error_node)
34
- @bel_functions = bel_functions
27
+ def initialize(term_node, spec, function)
28
+ super(term_node, spec)
29
+ @function = function
35
30
  end
36
31
 
37
32
  def msg
38
- invalid_function = error_node.identifier.string_literal
39
- %Q{Invalid function "#{invalid_function}".}
33
+ %Q{Invalid function "#{function}".}
40
34
  end
41
35
  end
42
36
  end
@@ -10,36 +10,43 @@ module BELParser
10
10
 
11
11
  private_class_method :new
12
12
 
13
- def self.map(expression_ast, spec, namespaces)
14
- errors = []
15
- expression_ast.traverse.map do |node|
16
- next unless node.is_a?(BELParser::Parsers::AST::Prefix)
17
- next if node.identifier.nil?
18
-
19
- namespace_prefix = node.identifier.string_literal
20
- unless namespaces[namespace_prefix]
21
- errors << UndefinedNamespaceError.new(
22
- expression_ast, node, namespaces)
13
+ def self.map(term_node, spec, namespaces)
14
+ syntax_results = []
15
+ term_node.arguments
16
+ .select(&:has_parameter?)
17
+ .map(&:child)
18
+ .each do |child_parameter|
19
+ prefix_identifier = child_parameter.prefix.identifier
20
+ next if prefix_identifier.nil?
21
+
22
+ namespace_prefix = prefix_identifier.string_literal
23
+ unless namespaces[namespace_prefix]
24
+ syntax_results << UndefinedNamespaceError.new(term_node, node, namespaces)
25
+ end
23
26
  end
24
- end
25
- errors
27
+ syntax_results
26
28
  end
27
29
  end
28
30
 
29
31
  # UndefinedNamespaceError indicates a parameter prefix is referencing
30
32
  # an undefined namespace.
31
33
  class UndefinedNamespaceError < SyntaxError
34
+ # Gets the invalid prefix.
35
+ attr_reader :invalid_prefix
32
36
  # Gets the defined namespaces.
33
37
  attr_reader :defined_namespaces
34
38
 
35
- def initialize(expression_node, spec, error_node, defined_namespaces)
36
- super(expression_node, spec, error_node)
39
+ def initialize(term_node, spec, invalid_prefix, defined_namespaces)
40
+ super(term_node, spec, error_node)
41
+ @invalid_prefix = invalid_prefix
37
42
  @defined_namespaces = defined_namespaces.dup
38
43
  end
39
44
 
40
45
  def msg
41
- undefined_namespace = error_node.identifier.string_literal
42
- %Q{Undefined namespace "#{undefined_namespace}".}
46
+ <<-MSG.gsub(/ {10}/, '')
47
+ Undefined namespace "#{invalid_prefix}".
48
+ Defined namespaces are: #{defined_namespaces.keys.join(', ')}
49
+ MSG
43
50
  end
44
51
  end
45
52
  end
@@ -4,11 +4,8 @@ module BELParser
4
4
  module Language
5
5
  module Syntax
6
6
  class SyntaxError < SyntaxResult
7
- attr_reader :expression_node, :target_node
8
-
9
- def initialize(expression_node, specification, target_node)
7
+ def initialize(expression_node, specification)
10
8
  super(expression_node, specification)
11
- @target_node = target_node
12
9
  end
13
10
 
14
11
  # @abstract Subclass and override {#msg} to provide the message.
@@ -4,7 +4,7 @@ module BELParser
4
4
  module Language
5
5
  module Syntax
6
6
  class SyntaxWarning < SyntaxResult
7
- attr_reader :expression_node, :target_node
7
+ attr_reader :target_node
8
8
 
9
9
  def initialize(expression_node, specification, target_node)
10
10
  super(expression_node, specification)
@@ -352,6 +352,16 @@ module BELParser
352
352
  def initialize(children = [], properties = {})
353
353
  super(Parameter.ast_type, children, properties)
354
354
  end
355
+
356
+ # Get the prefix for the parameter.
357
+ def prefix
358
+ children[0]
359
+ end
360
+
361
+ # Get the value for the parameter.
362
+ def value
363
+ children[1]
364
+ end
355
365
  end
356
366
 
357
367
  # AST node representing a relationship.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bel_parser
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.alpha.3
4
+ version: 1.0.0.alpha.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Anthony Bargnesi
@@ -36,9 +36,12 @@ files:
36
36
  - lib/bel_parser/language/quoting.rb
37
37
  - lib/bel_parser/language/relationship.rb
38
38
  - lib/bel_parser/language/semantics.rb
39
- - lib/bel_parser/language/semantics/analyzer.rb
40
- - lib/bel_parser/language/semantics/semantic_ast.rb
41
- - lib/bel_parser/language/semantics/semantic_match.rb
39
+ - lib/bel_parser/language/semantics/signature_mapping.rb
40
+ - lib/bel_parser/language/semantics_ast.rb
41
+ - lib/bel_parser/language/semantics_function.rb
42
+ - lib/bel_parser/language/semantics_match.rb
43
+ - lib/bel_parser/language/semantics_result.rb
44
+ - lib/bel_parser/language/semantics_warning.rb
42
45
  - lib/bel_parser/language/signature.rb
43
46
  - lib/bel_parser/language/specification.rb
44
47
  - lib/bel_parser/language/syntax.rb
@@ -1,59 +0,0 @@
1
- require 'bel_parser/parsers/ast/node'
2
-
3
- module BELParser
4
- module Language
5
- module Semantics
6
- # Recursively apply function semantics to each term.
7
- # AST Term Property = :function_semantics
8
- def self.apply_function_semantics(term, spec)
9
- unless term.is_a?(BELParser::Parsers::AST::Term)
10
- raise ArgumentError, "term_ast: expected BELParser::Parsers::AST::Term"
11
- end
12
-
13
- function_name = term.function.identifier.string_literal
14
- function = spec.function(function_name.to_sym)
15
-
16
- valid_signature =
17
- function.signatures.select do |sig|
18
- match(term, sig.semantic_ast, spec).all?(&:success?)
19
- end.max
20
- if valid_signature
21
- term.function_semantics = valid_signature
22
- term.arguments.select(&:has_term?).map(&:child).each do |term|
23
- apply_function_semantics(term, spec)
24
- end
25
- else
26
- nullify_function_semantics(term)
27
- end
28
- end
29
-
30
- def self.nullify_function_semantics(term)
31
- unless term.is_a?(BELParser::Parsers::AST::Term)
32
- raise ArgumentError, "term_ast: expected BELParser::Parsers::AST::Term"
33
- end
34
-
35
- term.function_semantics = nil
36
- term.arguments.select(&:has_term?).map(&:child).each do |term|
37
- nullify_function_semantics(term)
38
- end
39
- end
40
-
41
- def self.check_term(term, spec)
42
- unless term.is_a?(BELParser::Parsers::AST::Term)
43
- raise ArgumentError, "term_ast: expected BELParser::Parsers::AST::Term"
44
- end
45
-
46
- apply_function_semantics(term, spec)
47
-
48
- semantics = []
49
- terms = [term]
50
- while !terms.empty? do
51
- term = terms.shift
52
- semantics << term.function_semantics
53
- terms.concat(term.arguments.select(&:has_term?).map(&:child))
54
- end
55
- semantics
56
- end
57
- end
58
- end
59
- end