Class: Pdfrb::Source::Parser

Inherits:
Object
  • Object
show all
Defined in:
lib/pdfrb/source/parser.rb

Overview

Recursive-descent parser. Consumes tokens from a Tokenizer and produces Pdfrb::Model values.

Recognised productions:

value      := scalar | array | dict | stream_indirect
scalar     := number | name | string | hex_string | boolean | null | ref
ref        := integer integer 'R'
array      := '[' value* ']'
dict       := '<<' (name value)* '>>'
obj_decl   := integer integer 'obj'
stream_obj := obj_decl dict 'stream' <bytes> 'endstream' 'endobj'

References are emitted as Model::Reference values (deferred resolution). The caller resolves them via the owning Document.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(tokenizer, document: nil) ⇒ Parser

Returns a new instance of Parser.



24
25
26
27
# File 'lib/pdfrb/source/parser.rb', line 24

def initialize(tokenizer, document: nil)
  @tokenizer = tokenizer
  @document = document
end

Instance Attribute Details

#documentObject (readonly)

Returns the value of attribute document.



22
23
24
# File 'lib/pdfrb/source/parser.rb', line 22

def document
  @document
end

#tokenizerObject (readonly)

Returns the value of attribute tokenizer.



22
23
24
# File 'lib/pdfrb/source/parser.rb', line 22

def tokenizer
  @tokenizer
end

Instance Method Details

#parse_dictObject



67
68
69
70
71
72
73
74
# File 'lib/pdfrb/source/parser.rb', line 67

def parse_dict
  tok = tokenizer.peek
  return nil if tok.nil?
  raise syntax_error("expected <<, got #{tok.inspect}") unless tok.type == :dict_open

  tokenizer.next_token
  parse_dict_body
end

#parse_indirect_objectObject

Parse <N> <G> obj <body> endobj (with optional stream). Returns a Model::Object subclass (Dictionary / Stream / etc.).



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/pdfrb/source/parser.rb', line 49

def parse_indirect_object
  oid = expect_type(:integer).value
  gen = expect_type(:integer).value
  expect_keyword("obj")
  value = parse_value
  tok = tokenizer.peek
  if tok&.type == :keyword && tok.value == "stream"
    tokenizer.next_token
    stream = read_stream_payload(value)
    expect_keyword("endstream")
    expect_keyword("endobj")
    wrap_stream(value, stream, oid: oid, gen: gen)
  else
    expect_keyword("endobj")
    wrap_object(value, oid: oid, gen: gen)
  end
end

#parse_valueObject



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/pdfrb/source/parser.rb', line 29

def parse_value
  tok = tokenizer.next_token
  return nil if tok.nil?

  case tok.type
  when :integer, :real then maybe_reference(tok) || tok.value
  when :name then Pdfrb::Model::Cos::NameEncoding.decode(tok.value)
  when :string, :hex_string then tok.value
  when :true then true
  when :false then false
  when :null then nil
  when :array_open then parse_array_body
  when :dict_open then parse_dict_body
  else
    raise syntax_error("unexpected token #{tok.inspect}")
  end
end