Module: MilkTea::Parse::Blocks

Included in:
MilkTea::Parser
Defined in:
lib/milk_tea/core/parser/blocks.rb

Instance Method Summary collapse

Instance Method Details

#parse_and_dedent_block_bodyObject



14
15
16
17
18
19
20
21
22
23
# File 'lib/milk_tea/core/parser/blocks.rb', line 14

def parse_and_dedent_block_body
  statements = parse_statement_block_body
  consume(:dedent, "expected end of block")
  statements
rescue ParseError => e
  raise unless @recovery_errors

  @recovery_errors << e
  []
end

#parse_blockObject



6
7
8
9
10
11
12
# File 'lib/milk_tea/core/parser/blocks.rb', line 6

def parse_block
  consume(:colon, "expected ':' before block")
  consume(:newline, "expected newline before block")
  consume(:indent, "expected indented block")

  parse_and_dedent_block_body
end

#parse_block_body(&block) ⇒ Object



77
78
79
80
81
82
83
84
85
86
87
# File 'lib/milk_tea/core/parser/blocks.rb', line 77

def parse_block_body(&block)
  items = []
  skip_newlines
  until check(:dedent) || eof?
    items << block.call
    skip_newlines
  end

  consume(:dedent, "expected end of block")
  items
end

#parse_declaration_blockObject



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/milk_tea/core/parser/blocks.rb', line 89

def parse_declaration_block
  consume(:colon, "expected ':' before block")
  consume(:newline, "expected newline before block")
  consume(:indent, "expected indented block")

  declarations = []
  skip_newlines
  until check(:dedent) || eof?
    declarations << parse_declaration
    skip_newlines
  end

  consume(:dedent, "expected end of block")
  declarations
end

#parse_named_block(&block) ⇒ Object



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/milk_tea/core/parser/blocks.rb', line 54

def parse_named_block(&block)
  consume(:colon, "expected ':' before block")
  consume(:newline, "expected newline before block")
  consume(:indent, "expected indented block")

  parse_block_body(&block)
rescue ParseError => e
  raise unless @recovery_errors

  @recovery_errors << e
  match(:newline)
  if match(:indent)
    begin
      parse_block_body(&block)
    rescue ParseError => e2
      @recovery_errors << e2
      []
    end
  else
    []
  end
end

#parse_statement_block_bodyObject



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/milk_tea/core/parser/blocks.rb', line 25

def parse_statement_block_body
  statements = []
  skip_newlines
  until check(:dedent) || eof?
    if @recovery_errors
      begin
        raise error(unexpected_statement_block_indent_token, "unexpected indentation in statement block") if check(:indent)

        statements << parse_statement
      rescue ParseError => e
        @recovery_errors << e
        header_type = recovery_statement_header_type(e)
        recovered_body = synchronize_to_statement_boundary
        statements << if recovered_body
                        recovery_error_block_stmt(e, recovered_body, header_type:)
                      else
                        recovery_error_stmt(e)
                      end
      end
    else
      raise error(unexpected_statement_block_indent_token, "unexpected indentation in statement block") if check(:indent)

      statements << parse_statement
    end
    skip_newlines
  end
  statements
end

#unexpected_statement_block_indent_tokenObject



105
106
107
108
109
110
111
112
113
114
# File 'lib/milk_tea/core/parser/blocks.rb', line 105

def unexpected_statement_block_indent_token
  token = peek
  return token unless token&.type == :indent

  candidate = @tokens[@current + 1]
  return token unless candidate
  return token if %i[newline dedent eof].include?(candidate.type)

  candidate
end