Class: RDF::Turtle::Reader

Inherits:
Reader show all
Includes:
EBNF::LL1::Parser, Terminals, Util::Logger
Defined in:
vendor/bundler/ruby/3.4.0/bundler/gems/rdf-turtle-5818bab04efb/lib/rdf/turtle/reader.rb

Overview

A parser for the Turtle 2

Direct Known Subclasses

RDF::TriG::Reader

Defined Under Namespace

Classes: Recovery, SyntaxError

Constant Summary

Constants included from Util::Logger

Util::Logger::IOWrapper

Constants included from Terminals

Terminals::ANON, Terminals::BASE, Terminals::BLANK_NODE_LABEL, Terminals::DECIMAL, Terminals::DOUBLE, Terminals::ECHAR, Terminals::EXPONENT, Terminals::INTEGER, Terminals::IRIREF, Terminals::IRI_RANGE, Terminals::LANG_DIR, Terminals::PERCENT, Terminals::PLX, Terminals::PNAME_LN, Terminals::PNAME_NS, Terminals::PN_CHARS, Terminals::PN_CHARS_BASE, Terminals::PN_CHARS_BODY, Terminals::PN_CHARS_U, Terminals::PN_LOCAL, Terminals::PN_LOCAL_BODY, Terminals::PN_LOCAL_ESC, Terminals::PN_PREFIX, Terminals::PREFIX, Terminals::RDF_VERSION, Terminals::STRING_LITERAL_LONG_QUOTE, Terminals::STRING_LITERAL_LONG_SINGLE_QUOTE, Terminals::STRING_LITERAL_QUOTE, Terminals::STRING_LITERAL_SINGLE_QUOTE, Terminals::UCHAR, Terminals::U_CHARS1, Terminals::U_CHARS2, Terminals::WS

Instance Attribute Summary

Attributes included from EBNF::LL1::Parser

#lineno

Attributes inherited from Reader

#options

Attributes included from Enumerable

#existentials, #universals

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Util::Logger

#log_debug, #log_depth, #log_error, #log_fatal, #log_info, #log_recover, #log_recovering?, #log_statistics, #log_warn, #logger

Methods included from EBNF::LL1::Parser

#add_prod_data, #add_prod_datum, #depth, #parse, #prod_data

Methods inherited from Reader

#base_uri, #canonicalize?, #close, each, #each_pg_statement, #encoding, #fail_object, #fail_predicate, #fail_subject, for, format, #intern?, #lineno, open, #prefixes, #prefixes=, #read_triple, #rewind, to_sym, #to_sym, #valid?, #validate?, #version

Methods included from Util::Aliasing::LateBound

#alias_method

Methods included from Enumerable

add_entailment, #canonicalize, #canonicalize!, #dump, #each_graph, #each_object, #each_predicate, #each_quad, #each_subject, #each_term, #entail, #enum_graph, #enum_object, #enum_predicate, #enum_quad, #enum_statement, #enum_subject, #enum_term, #enum_triple, #graph?, #graph_names, #invalid?, #method_missing, #object?, #objects, #predicate?, #predicates, #project_graph, #quad?, #quads, #respond_to_missing?, #statement?, #statements, #subject?, #subjects, #supports?, #term?, #terms, #to_a, #to_h, #to_set, #triple?, #triples, #valid?, #validate!

Methods included from Isomorphic

#bijection_to, #isomorphic_with?

Methods included from Countable

#count, #empty?

Methods included from Readable

#readable?

Constructor Details

#initialize(input = nil, **options, &block) ⇒ RDF::Turtle::Reader

Initializes a new reader instance.

Note, the spec does not define a default mapping for the empty prefix, but it is so commonly used in examples that we define it to be the empty string anyway, except when validating.

Parameters:

Options Hash (**options):

  • :prefixes (Hash) — default: Hash.new

    the prefix mappings to use (for acessing intermediate parser productions)

  • :base_uri (#to_s) — default: nil

    the base URI to use when resolving relative URIs (for acessing intermediate parser productions)

  • :anon_base (#to_s) — default: "b0"

    Basis for generating anonymous Nodes

  • :validate (Boolean) — default: false

    whether to validate the parsed statements and values. If not validating, the parser will attempt to recover from errors.

  • :logger (Logger, #write, #<<)

    Record error/info/debug output

  • :freebase (Boolean) — default: false

    Use optimized Freebase reader

  • :version (String) — default: "1.2"

    Parse a specific version of RDF ("1.1', "1.2", or "1.2-basic"")



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'vendor/bundler/ruby/3.4.0/bundler/gems/rdf-turtle-5818bab04efb/lib/rdf/turtle/reader.rb', line 97

def initialize(input = nil, **options, &block)
  super do
    @options = {
      anon_base:  "b0",
      whitespace:  WS,
      depth: 0,
    }.merge(@options)
    @prod_stack = []

    @options[:base_uri] = RDF::URI(base_uri || "")
    debug("base IRI") {base_uri.inspect}
    
    debug("validate") {validate?.inspect}
    debug("canonicalize") {canonicalize?.inspect}
    debug("intern") {intern?.inspect}

    @lexer = EBNF::LL1::Lexer.new(input, self.class.patterns, **@options)

    if block_given?
      case block.arity
        when 0 then instance_eval(&block)
        else block.call(self)
      end
    end
  end
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class RDF::Enumerable

Class Method Details

.optionsObject

Reader options



47
48
49
50
51
52
53
54
55
# File 'vendor/bundler/ruby/3.4.0/bundler/gems/rdf-turtle-5818bab04efb/lib/rdf/turtle/reader.rb', line 47

def self.options
  super + [
    RDF::CLI::Option.new(
      symbol: :freebase,
      datatype: TrueClass,
      on: ["--freebase"],
      description: "Use optimized Freebase reader.") {true},
  ]
end

Instance Method Details

#add_statement(production, statement) ⇒ RDF::Statement

add a statement, object can be literal or URI or bnode

Parameters:

Returns:

Raises:

  • (RDF::ReaderError)

    Checks parameter types and raises if they are incorrect if parsing mode is validate.



177
178
179
180
181
182
183
# File 'vendor/bundler/ruby/3.4.0/bundler/gems/rdf-turtle-5818bab04efb/lib/rdf/turtle/reader.rb', line 177

def add_statement(production, statement)
  error("Statement is invalid: #{statement.inspect}", production: produciton) if validate? && statement.invalid?
  @callback.call(statement) if statement.subject &&
                               statement.predicate &&
                               statement.object &&
                               (validate? ? statement.valid? : true)
end

#bnode(value = nil) ⇒ Object

Keep track of allocated BNodes



248
249
250
251
252
# File 'vendor/bundler/ruby/3.4.0/bundler/gems/rdf-turtle-5818bab04efb/lib/rdf/turtle/reader.rb', line 248

def bnode(value = nil)
  return RDF::Node.new unless value
  @bnode_cache ||= {}
  @bnode_cache[value.to_s] ||= RDF::Node.new(value)
end

#debug(*args, &block) ⇒ Object (protected)



777
778
779
780
781
782
783
# File 'vendor/bundler/ruby/3.4.0/bundler/gems/rdf-turtle-5818bab04efb/lib/rdf/turtle/reader.rb', line 777

def debug(*args, &block)
  lineno = (options[:token].lineno if options[:token].respond_to?(:lineno)) || (@lexer && @lexer.lineno)
  opts = args.last.is_a?(Hash) ? args.pop : {}
  opts[:level] ||= 0
  opts[:lineno] ||= lineno
  log_debug(*args, **opts, &block)
end

#each_statement {|statement| ... }

This method returns an undefined value.

Iterates the given block for each RDF statement in the input.

Yields:

  • (statement)

Yield Parameters:



134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'vendor/bundler/ruby/3.4.0/bundler/gems/rdf-turtle-5818bab04efb/lib/rdf/turtle/reader.rb', line 134

def each_statement(&block)
  if block_given?
    log_recover
    @callback = block

    begin
      while (@lexer.first rescue true)
        read_statement
      end
    rescue EBNF::LL1::Lexer::Error, SyntaxError, EOFError, Recovery
      # Terminate loop if EOF found while recovering
    end

    if validate? && log_statistics[:error]
      raise RDF::ReaderError, "Errors found during processing"
    end
  end
  enum_for(:each_statement)
end

#each_triple {|subject, predicate, object| ... }

This method returns an undefined value.

Iterates the given block for each RDF triple in the input.

Yields:

  • (subject, predicate, object)

Yield Parameters:



162
163
164
165
166
167
168
169
# File 'vendor/bundler/ruby/3.4.0/bundler/gems/rdf-turtle-5818bab04efb/lib/rdf/turtle/reader.rb', line 162

def each_triple(&block)
  if block_given?
    each_statement do |statement|
      block.call(*statement.to_triple)
    end
  end
  enum_for(:each_triple)
end

#error(node, message, options) ⇒ Object (protected)

Error information, used as level 0 debug messages.

Parameters:

  • node (String)

    Relevant location associated with message

  • message (String)

    Error string

  • options (Hash)

Options Hash (options):

  • :production (URI, #to_s)
  • :token (Token)

See Also:

  • RDF::Turtle::Reader.{{#debug}


803
804
805
806
807
808
809
810
811
812
813
814
# File 'vendor/bundler/ruby/3.4.0/bundler/gems/rdf-turtle-5818bab04efb/lib/rdf/turtle/reader.rb', line 803

def error(*args)
  ctx = ""
  ctx += "(found #{options[:token].inspect})" if options[:token]
  ctx += ", production = #{options[:production].inspect}" if options[:production]
  lineno = @lineno || (options[:token].lineno if options[:token].respond_to?(:lineno)) || @lexer.lineno
  log_error(*args, ctx,
    lineno:     lineno,
    token:      options[:token],
    production: options[:production],
    depth:      options[:depth],
    exception:  SyntaxError,)
end

#inspectObject



124
125
126
# File 'vendor/bundler/ruby/3.4.0/bundler/gems/rdf-turtle-5818bab04efb/lib/rdf/turtle/reader.rb', line 124

def inspect
  sprintf("#<%s:%#0x(%s)>", self.class.name, __id__, base_uri.to_s)
end

#literal(value, **options) ⇒ Object

Create a literal



199
200
201
202
203
204
205
206
207
208
209
# File 'vendor/bundler/ruby/3.4.0/bundler/gems/rdf-turtle-5818bab04efb/lib/rdf/turtle/reader.rb', line 199

def literal(value, **options)
  debug("literal", depth: @options[:depth]) do
    "value: #{value.inspect}, " +
    "options: #{options.inspect}, " +
    "validate: #{validate?.inspect}, " +
    "c14n?: #{canonicalize?.inspect}"
  end
  RDF::Literal.new(value, validate:  validate?, canonicalize:  canonicalize?, **options)
rescue ArgumentError => e
  error("Argument Error #{e.message}", production: :literal, token: @lexer.first)
end

#pname(prefix, suffix) ⇒ Object

Expand a PNAME using string concatenation



225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
# File 'vendor/bundler/ruby/3.4.0/bundler/gems/rdf-turtle-5818bab04efb/lib/rdf/turtle/reader.rb', line 225

def pname(prefix, suffix)
  # Prefixes must be defined, except special case for empty prefix being alias for current @base
  base = if prefix(prefix)
    prefix(prefix).to_s
  elsif prefix.to_s.empty? && !validate?
    base_uri.to_s
  else
    error("undefined prefix", production: :pname, token: prefix)
    ''
  end

  # Unescape PN_LOCAL_ESC
  suffix = suffix.gsub(PN_LOCAL_ESC) {|esc| esc[1]} if
    suffix.match?(PN_LOCAL_ESC)

  # Remove any redundant leading hash from suffix
  suffix = suffix.sub(/^\#/, "") if base.index("#")

  debug("pname", depth: options[:depth]) {"base: '#{base}', suffix: '#{suffix}'"}
  process_iri(base + suffix.to_s)
end

#prefix(prefix, iri = nil) ⇒ Object

Override #prefix to take a relative IRI

prefix directives map a local name to an IRI, also resolved against the current In-Scope Base URI. Spec confusion, presume that an undefined empty prefix has an empty relative IRI, which uses string contatnation rules against the in-scope IRI at the time of use



217
218
219
220
221
# File 'vendor/bundler/ruby/3.4.0/bundler/gems/rdf-turtle-5818bab04efb/lib/rdf/turtle/reader.rb', line 217

def prefix(prefix, iri = nil)
  # Relative IRIs are resolved against @base
  iri = process_iri(iri) if iri
  super(prefix, iri)
end

#process_iri(iri) ⇒ Object

Process a URI against base



186
187
188
189
190
191
192
193
194
195
196
# File 'vendor/bundler/ruby/3.4.0/bundler/gems/rdf-turtle-5818bab04efb/lib/rdf/turtle/reader.rb', line 186

def process_iri(iri)
  iri = iri.value[1..-2] if iri === :IRIREF
  value = RDF::URI(iri)
  value = base_uri.join(value) if value.relative?
  value.validate! if validate?
  value.canonicalize! if canonicalize? && !value.frozen?
  value = RDF::URI.intern(value) if intern?
  value
rescue ArgumentError => e
  error("process_iri", e)
end

#prod(production, recover_to = []) ⇒ Object (protected)



707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
# File 'vendor/bundler/ruby/3.4.0/bundler/gems/rdf-turtle-5818bab04efb/lib/rdf/turtle/reader.rb', line 707

def prod(production, recover_to = [])
  @prod_stack << {prod: production, recover_to: recover_to}
  @options[:depth] += 1
  recover("#{production}(start)", depth: options[:depth], token: @lexer.first)
  yield
rescue EBNF::LL1::Lexer::Error, SyntaxError, Recovery =>  e
  # Lexer encountered an illegal token or the parser encountered
  # a terminal which is inappropriate for the current production.
  # Perform error recovery to find a reasonable terminal based
  # on the follow sets of the relevant productions. This includes
  # remaining terms from the current production and the stacked
  # productions
  case e
  when EBNF::LL1::Lexer::Error
    @lexer.recover
    begin
      error("Lexer error", "With input '#{e.input}': #{e.message}",
        production: production,
        token: e.token)
    rescue SyntaxError
    end
  end
  raise EOFError, "End of input found when recovering" if @lexer.first.nil?
  debug("recovery", "current token: #{@lexer.first.inspect}", depth: options[:depth])

  unless e.is_a?(Recovery)
    # Get the list of follows for this sequence, this production and the stacked productions.
    debug("recovery", "stack follows:", depth: options[:depth])
    @prod_stack.reverse.each do |prod|
      debug("recovery", level: 4, depth: options[:depth]) {"  #{prod[:prod]}: #{prod[:recover_to].inspect}"}
    end
  end

  # Find all follows to the top of the stack
  follows = @prod_stack.map {|prod| Array(prod[:recover_to])}.flatten.compact.uniq

  # Skip tokens until one is found in follows
  while (token = (@lexer.first rescue @lexer.recover)) && follows.none? {|t| token === t}
    skipped = @lexer.shift
    debug("recovery", depth: options[:depth]) {"skip #{skipped.inspect}"}
  end
  debug("recovery", depth: options[:depth]) {"found #{token.inspect} in follows"}

  # Re-raise the error unless token is a follows of this production
  raise Recovery unless Array(recover_to).any? {|t| token === t}

  # Skip that token to get something reasonable to start the next production with
  @lexer.shift
ensure
  progress("#{production}(finish)", depth: options[:depth])
  @options[:depth] -= 1
  @prod_stack.pop
end

#progress(*args, &block) ⇒ Object (protected)



761
762
763
764
765
766
767
# File 'vendor/bundler/ruby/3.4.0/bundler/gems/rdf-turtle-5818bab04efb/lib/rdf/turtle/reader.rb', line 761

def progress(*args, &block)
  lineno = (options[:token].lineno if options[:token].respond_to?(:lineno)) || (@lexer && @lexer.lineno)
  opts = args.last.is_a?(Hash) ? args.pop : {}
  opts[:level] ||= 1
  opts[:lineno] ||= lineno
  log_info(*args, **opts, &block)
end

#read_annotation(subject, predicate, object) ⇒ Object (protected)

Read an annotation on a triple

 annotation := (reifier | annotationBlock)*

The reifier becomes the identifier for a subsequent annotation block (if it exists). If there is no reifier, then a blank node is created.



569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
# File 'vendor/bundler/ruby/3.4.0/bundler/gems/rdf-turtle-5818bab04efb/lib/rdf/turtle/reader.rb', line 569

def read_annotation(subject, predicate, object)
  error("Unexpected end of file", production: :annotation) unless @lexer.first

  tt = RDF::Statement(subject, predicate, object, tripleTerm: true)
  reifier = nil

  while %w(~ {|).include? @lexer.first.to_s
    if @lexer.first === '~'
      prod(:annotation, %(~)) do
        @lexer.shift # eat '~'
        reifier = read_iri || read_BlankNode || bnode
        add_statement('annotation', RDF::Statement(reifier, RDF.reifies, tt))
      end
    else
      prod(:annotation, %({||})) do
        @lexer.shift # eat '{|'
        unless reifier
          # Emit the reifiedTriple
          reifier = bnode
          add_statement('annotation', RDF::Statement(reifier, RDF.reifies, tt))
        end

        # id becomes subject for predicateObjectList
        read_predicateObjectList(reifier) ||
          error("Expected predicateObjectList", production: :annotation, token: @lexer.first)
        error("annotation", "Expected closing '|}'") unless @lexer.first === '|}'
        @lexer.shift # eat '|}'
        reifier = nil
      end
    end
  end
end

#read_BlankNodeRDF::Node (protected)

Returns:



699
700
701
702
703
704
705
# File 'vendor/bundler/ruby/3.4.0/bundler/gems/rdf-turtle-5818bab04efb/lib/rdf/turtle/reader.rb', line 699

def read_BlankNode
  token = @lexer.first
  case token && token.type
  when :BLANK_NODE_LABEL then prod(:BlankNode) {bnode(@lexer.shift.value[2..-1])}
  when :ANON then @lexer.shift && prod(:BlankNode) {bnode}
  end
end

#read_blankNodePropertyListRDF::Node (protected)

Returns:



652
653
654
655
656
657
658
659
660
661
662
663
664
665
# File 'vendor/bundler/ruby/3.4.0/bundler/gems/rdf-turtle-5818bab04efb/lib/rdf/turtle/reader.rb', line 652

def read_blankNodePropertyList
  token = @lexer.first
  if token === '['
    prod(:blankNodePropertyList, %{]}) do
      @lexer.shift
      progress("blankNodePropertyList", depth: options[:depth]) {"token: #{token.inspect}"}
      node = bnode
      read_predicateObjectList(node)
      error("blankNodePropertyList", "Expected closing ']'") unless @lexer.first === ']'
      @lexer.shift
      node
    end
  end
end

#read_collectionRDF::Node (protected)

Returns:



668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
# File 'vendor/bundler/ruby/3.4.0/bundler/gems/rdf-turtle-5818bab04efb/lib/rdf/turtle/reader.rb', line 668

def read_collection
  if @lexer.first === '('
    prod(:collection, %{)}) do
      @lexer.shift
      token = @lexer.first
      progress("collection", depth: options[:depth]) {"token: #{token.inspect}"}
      objects = []
      while object = read_object
        objects << object
      end
      list = RDF::List.new(values: objects)
      list.each_statement do |statement|
        add_statement("collection", statement)
      end
      error("collection", "Expected closing ')'") unless @lexer.first === ')'
      @lexer.shift
      list.subject
    end
  end
end

#read_directive (protected)

This method returns an undefined value.

Read directive

directive ::= prefixID | base | version
            | sparqlPrefix | sparqlBase | sparqlVersion


287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
# File 'vendor/bundler/ruby/3.4.0/bundler/gems/rdf-turtle-5818bab04efb/lib/rdf/turtle/reader.rb', line 287

def read_directive
  prod(:directive, %w{.}) do
    token = @lexer.first
    case token.type
    when :BASE
      prod(:base) do
        @lexer.shift
        terminated = token.value == '@base'
        iri = @lexer.shift
        error("Expected IRIREF", production: :base, token: iri) unless iri === :IRIREF
        @options[:base_uri] = process_iri(iri)
        error("base", "#{token} should be downcased") if token.value.start_with?('@') && token.value != '@base'

        if terminated
          error("base", "Expected #{token} to be terminated") unless @lexer.first === '.'
          @lexer.shift
        elsif @lexer.first === '.'
          error("base", "Expected #{token} not to be terminated") 
        else
          true
        end
      end
    when :PREFIX
      prod(:prefixID, %w{.}) do
        @lexer.shift
        pfx, iri = @lexer.shift, @lexer.shift
        terminated = token.value == '@prefix'
        error("Expected PNAME_NS", production: :prefix, token: pfx) unless pfx === :PNAME_NS
        error("Expected IRIREF", production: :prefix, token: iri) unless iri === :IRIREF
        debug("prefixID", depth: options[:depth]) {"Defined prefix #{pfx.inspect} mapping to #{iri.inspect}"}
        prefix(pfx.value[0..-2], process_iri(iri))
        error("prefixId", "#{token} should be downcased") if token.value.start_with?('@') && token.value != '@prefix'

        if terminated
          error("prefixID", "Expected #{token} to be terminated") unless @lexer.first === '.'
          @lexer.shift
        elsif @lexer.first === '.'
          error("prefixID", "Expected #{token} not to be terminated") 
        else
          true
        end
      end
    when :VERSION
      prod(:version) do
        @lexer.shift
        terminated = token.value == '@version'
        vers_tok = @lexer.shift
        error("version", "Expected #{vers_tok} to be a string") unless [:STRING_LITERAL_QUOTE, :STRING_LITERAL_SINGLE_QUOTE].include?(vers_tok.type)
        @options[:version] = vers_tok.value[1..-2]
        if %w(1.1 1.2 1.2-basic).include?(@options[:version])
          progress("version") {@options[:version]}
        else
          warn("version", "Expected version to be one of #{RDF::Format::VERSIONS.join(', ')}, was #{@options[:version]}") unless @options[:version] == "1.2"
        end

        if terminated
          error("version", "Expected #{token} to be terminated") unless @lexer.first === '.'
          @lexer.shift
        elsif @lexer.first === '.'
          error("version", "Expected #{token} not to be terminated") 
        else
          true
        end
      end
    end
  end
end

#read_iriRDF::URI (protected)

Returns:



690
691
692
693
694
695
696
# File 'vendor/bundler/ruby/3.4.0/bundler/gems/rdf-turtle-5818bab04efb/lib/rdf/turtle/reader.rb', line 690

def read_iri
  token = @lexer.first
  case token && token.type
  when :IRIREF then prod(:iri)  {process_iri(@lexer.shift)}
  when :PNAME_LN, :PNAME_NS then prod(:iri) {pname(*@lexer.shift.value.split(':', 2))}
  end
end

#read_literalRDF::Literal (protected)

Returns:



603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
# File 'vendor/bundler/ruby/3.4.0/bundler/gems/rdf-turtle-5818bab04efb/lib/rdf/turtle/reader.rb', line 603

def read_literal
  token = @lexer.first
  error("Unexpected end of file", production: :literal) unless token
  case token.type || token.value
  when :DOUBLE then prod(:literal) {literal(@lexer.shift.value.sub(/\.([eE])/, '.0\1'), datatype:  RDF::XSD.double)}
  when :DECIMAL
    prod(:literal) do
      value = @lexer.shift.value
      value = "0#{value}" if value.start_with?(".")
      literal(value, datatype:  RDF::XSD.decimal)
    end
  when :INTEGER then prod(:literal) {literal(@lexer.shift.value, datatype:  RDF::XSD.integer)}
  when "true", "false" then prod(:literal) {literal(@lexer.shift.value, datatype: RDF::XSD.boolean)}
  when :STRING_LITERAL_QUOTE, :STRING_LITERAL_SINGLE_QUOTE
    prod(:literal) do
      value = @lexer.shift.value[1..-2]
      error("read_literal", "Unexpected end of file") unless token = @lexer.first
      case token.type || token.value
      when :LANG_DIR
        lang_dir = @lexer.shift.value[1..-1]
        language, direction = lang_dir.split('--')
        literal(value, language: language, direction: direction)
      when '^^'
        @lexer.shift
        literal(value, datatype: read_iri)
      else
        literal(value)
      end
    end
  when :STRING_LITERAL_LONG_QUOTE, :STRING_LITERAL_LONG_SINGLE_QUOTE
    prod(:literal) do
      value = @lexer.shift.value[3..-4]
      error("read_literal", "Unexpected end of file") unless token = @lexer.first
      case token.type || token.value
      when :LANG_DIR
        lang_dir = @lexer.shift.value[1..-1]
        language, direction = lang_dir.split('--')
        literal(value, language: language, direction: direction)
      when '^^'
        @lexer.shift
        literal(value, datatype: read_iri)
      else
        literal(value)
      end
    end
  end
end

#read_object(subject = nil, predicate = nil) (protected)

This method returns an undefined value.

Read object

 object ::= iri | BlankNode | collection | blankNodePropertyList
          | literal | tripleTerm | reifiedTriple


461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
# File 'vendor/bundler/ruby/3.4.0/bundler/gems/rdf-turtle-5818bab04efb/lib/rdf/turtle/reader.rb', line 461

def read_object(subject = nil, predicate = nil)
  prod(:object) do
    if object = read_iri ||
      read_BlankNode ||
      read_collection ||
      read_blankNodePropertyList ||
      read_literal ||
      read_tripleTerm ||
      read_reifiedTriple

      add_statement(:object, RDF::Statement(subject, predicate, object)) if subject && predicate
      object
    end
  end
end

#read_objectList(subject, predicate) ⇒ RDF::Term (protected)

Read objectList

objectList ::= object annotation* ( ',' object annotation* )*

Returns:



408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
# File 'vendor/bundler/ruby/3.4.0/bundler/gems/rdf-turtle-5818bab04efb/lib/rdf/turtle/reader.rb', line 408

def read_objectList(subject, predicate)
  prod(:objectList, %{,}) do
    last_object = nil
    while object = prod(:_objectList_2) {read_object(subject, predicate)}
      last_object = object

      # If object is followed by annotations, read them.
      read_annotation(subject, predicate, object)

      break unless @lexer.first === ','
      @lexer.shift while @lexer.first === ','
    end
    last_object
  end
end

#read_predicateObjectList(subject) ⇒ RDF::URI (protected)

Read predicateObjectList

 predicateObjectList ::= verb objectList (';' (verb objectList)? )*

Parameters:

Returns:



387
388
389
390
391
392
393
394
395
396
397
398
399
400
# File 'vendor/bundler/ruby/3.4.0/bundler/gems/rdf-turtle-5818bab04efb/lib/rdf/turtle/reader.rb', line 387

def read_predicateObjectList(subject)
  prod(:predicateObjectList, %{;}) do
    last_verb = nil
    while verb = read_verb
      last_verb = verb
      prod(:_predicateObjectList_5) do
        read_objectList(subject, verb) || error("Expected objectList", production: :predicateObjectList, token: @lexer.first)
      end
      break unless @lexer.first === ';'
      @lexer.shift while @lexer.first === ';'
    end
    last_verb
  end
end

#read_reifiedTripleRDF::Term (protected)

Read reifiedTriple

 reifiedTriple ::= '<<' (subject | reifiedTriple) predicate object reifier? '>>'

Returns:



483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
# File 'vendor/bundler/ruby/3.4.0/bundler/gems/rdf-turtle-5818bab04efb/lib/rdf/turtle/reader.rb', line 483

def read_reifiedTriple
  return unless @options[:rdfstar]
  if @lexer.first.value == '<<'
    prod(:reifiedTriple) do
      @lexer.shift # eat <<
      subject = read_ttSubject || read_reifiedTriple || error("Failed to parse subject", production: :reifiedTriple, token: @lexer.first)
      predicate = read_verb || error("Failed to parse predicate", production: :reifiedTriple, token: @lexer.first)
      object = read_ttObject || read_tripleTerm || read_reifiedTriple || error("Failed to parse object", production: :reifiedTriple, token: @lexer.first)
      tt = RDF::Statement(subject, predicate, object, tripleTerm: true)

      # An optional reifier. If not specified it is a new blank node.
      id = if @lexer.first.value == '~'
        @lexer.shift
        read_iri || read_BlankNode
      end || bnode

      statement = RDF::Statement(id, RDF.to_uri + 'reifies', tt)
      add_statement('reifiedTriple', statement)

      unless @lexer.first.value == '>>'
        error("Failed to end of triple occurence", production: :reifiedTriple, token: @lexer.first)
      end
      @lexer.shift
      id
    end
  end
end

#read_statement (protected)

This method returns an undefined value.

Read objectList

statement ::= directive | triples '.'


261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
# File 'vendor/bundler/ruby/3.4.0/bundler/gems/rdf-turtle-5818bab04efb/lib/rdf/turtle/reader.rb', line 261

def read_statement
  prod(:statement, %w{.}) do
    error("read_statement", "Unexpected end of file") unless token = @lexer.first
    case token.type
    when :BASE, :PREFIX, :VERSION
      read_directive || error("Failed to parse directive", production: :directive, token: token)
    else
      read_triples || error("Expected token", production: :statement, token: token)
      if !log_recovering? || @lexer.first === '.'
        # If recovering, we will have eaten the closing '.'
        token = @lexer.shift
        unless token && token.value == '.'
          error("Expected '.' following triple", production: :statement, token: token)
        end
      end
    end
  end
end

#read_subjectRDF::Resource (protected)

subject ::= iri | BlankNode | collection

Returns:



445
446
447
448
449
450
451
452
# File 'vendor/bundler/ruby/3.4.0/bundler/gems/rdf-turtle-5818bab04efb/lib/rdf/turtle/reader.rb', line 445

def read_subject
  prod(:subject) do
    read_iri ||
    read_BlankNode ||
    read_collection ||
    error( "Expected subject", production: :subject, token: @lexer.first)
  end
end

#read_triplesObject (protected)

Read triples

 triples ::= subject predicateObjectList | blankNodePropertyList predicateObjectList?

Returns:

  • (Object)

    returns the last verb matched, or subject BNode on predicateObjectList?



361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
# File 'vendor/bundler/ruby/3.4.0/bundler/gems/rdf-turtle-5818bab04efb/lib/rdf/turtle/reader.rb', line 361

def read_triples
  prod(:triples, %w{.}) do
    error("read_triples", "Unexpected end of file") unless token = @lexer.first
    case token.type || token.value
    when '['
      # blankNodePropertyList predicateObjectList? 
      subject = read_blankNodePropertyList || error("Failed to parse blankNodePropertyList", production: :triples, token: @lexer.first)
      read_predicateObjectList(subject) || subject
    when '<<'
      subject = read_reifiedTriple || error("Failed to parse reifiedTriple", production: :triples, token: @lexer.first)
      read_predicateObjectList(subject) || subject
    else
      # subject predicateObjectList
      subject = read_subject || error("Failed to parse subject", production: :triples, token: @lexer.first)
      read_predicateObjectList(subject) || error("Expected predicateObjectList", production: :triples, token: @lexer.first)
    end
  end
end

#read_tripleTermRDF::Statement (protected)

Read triple term

 tripleTerm ::= '<<(' ttSubject predicate ttObject ')>>'

Returns:



517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
# File 'vendor/bundler/ruby/3.4.0/bundler/gems/rdf-turtle-5818bab04efb/lib/rdf/turtle/reader.rb', line 517

def read_tripleTerm
  return unless @options[:rdfstar]
  if @lexer.first.value == '<<('
    prod(:tripleTerm) do
      @lexer.shift # eat <<(
      subject = read_ttSubject || error("Failed to parse subject", production: :tripleTerm, token: @lexer.first)
      predicate = read_verb || error("Failed to parse predicate", production: :tripleTerm, token: @lexer.first)
      object = read_ttObject || error("Failed to parse object", production: :tripleTerm, token: @lexer.first)
      unless @lexer.first.value == ')>>'
        error("Failed to end of triple term", production: :tripleTerm, token: @lexer.first)
      end
      @lexer.shift
      statement = RDF::Statement(subject, predicate, object, tripleTerm: true)
      statement
    end
  end
end

#read_ttObject(subject = nil, predicate = nil) ⇒ RDF::Term (protected)

Read ttObject

 ttObject::=    iri | BlankNode | literal | tripleTerm

Returns:



554
555
556
557
558
559
560
561
# File 'vendor/bundler/ruby/3.4.0/bundler/gems/rdf-turtle-5818bab04efb/lib/rdf/turtle/reader.rb', line 554

def read_ttObject(subject = nil, predicate = nil)
  prod(:ttObject) do
    read_iri ||
    read_BlankNode ||
    read_literal ||
    read_tripleTerm
  end
end

#read_ttSubjectRDF::Term (protected)

Read ttSubject

 ttSubject::=   iri | BlankNode

Returns:



541
542
543
544
545
546
# File 'vendor/bundler/ruby/3.4.0/bundler/gems/rdf-turtle-5818bab04efb/lib/rdf/turtle/reader.rb', line 541

def read_ttSubject
  prod(:ttSubject) do
    read_iri ||
    read_BlankNode
  end
end

#read_verbRDF::URI (protected)

Read verb

verb ::= predicate | 'a'

Returns:



430
431
432
433
434
435
436
437
438
439
440
# File 'vendor/bundler/ruby/3.4.0/bundler/gems/rdf-turtle-5818bab04efb/lib/rdf/turtle/reader.rb', line 430

def read_verb
  if @cached_verb
    v, @cached_verb = @cached_verb, nil
    return v
  end
  error("read_verb", "Unexpected end of file") unless token = @lexer.first
  case token.type || token.value
  when 'a' then prod(:verb) {@lexer.shift && RDF.type}
  else prod(:verb) {read_iri}
  end
end

#recover(*args, &block) ⇒ Object (protected)



769
770
771
772
773
774
775
# File 'vendor/bundler/ruby/3.4.0/bundler/gems/rdf-turtle-5818bab04efb/lib/rdf/turtle/reader.rb', line 769

def recover(*args, &block)
  lineno = (options[:token].lineno if options[:token].respond_to?(:lineno)) || (@lexer && @lexer.lineno)
  opts = args.last.is_a?(Hash) ? args.pop : {}
  opts[:level] ||= 1
  opts[:lineno] ||= lineno
  log_recover(*args, **opts, &block)
end

#warn(*args, &block) ⇒ Object (protected)



785
786
787
788
789
790
791
# File 'vendor/bundler/ruby/3.4.0/bundler/gems/rdf-turtle-5818bab04efb/lib/rdf/turtle/reader.rb', line 785

def warn(*args, &block)
  lineno = (options[:token].lineno if options[:token].respond_to?(:lineno)) || (@lexer && @lexer.lineno)
  opts = args.last.is_a?(Hash) ? args.pop : {}
  opts[:level] ||= 0
  opts[:lineno] ||= lineno
  log_warn(*args, **opts, &block)
end