Class: SyntaxTree::CSS::Parser

Inherits:
Object
  • Object
show all
Defined in:
lib/syntax_tree/css/parser.rb

Overview

Parses CSS3 stylesheets according to www.w3.org/TR/css-syntax-3 from the version dated 24 December 2021.

Defined Under Namespace

Classes: ParseError, State

Constant Summary collapse

DIGIT =
"[0-9]"
UPPERCASE_LETTER =
"[A-Z]"
LOWERCASE_LETTER =
"[a-z]"
LETTER =
"[#{UPPERCASE_LETTER}#{LOWERCASE_LETTER}]"
NONASCII =
"[\u{80}-\u{10FFFF}]"
IDENT_START =
"[#{LETTER}#{NONASCII}_]"
IDENT =
"[#{IDENT_START}#{DIGIT}-]"
NON_PRINTABLE =
"[\x00-\x08\x0B\x0E-\x1F\x7F]"
WHITESPACE =
"[\n\t ]"

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(source) ⇒ Parser

Returns a new instance of Parser.



52
53
54
55
# File 'lib/syntax_tree/css/parser.rb', line 52

def initialize(source)
  @source = preprocess(source)
  @errors = []
end

Instance Attribute Details

#errorsObject (readonly)

Returns the value of attribute errors.



50
51
52
# File 'lib/syntax_tree/css/parser.rb', line 50

def errors
  @errors
end

#sourceObject (readonly)

Returns the value of attribute source.



50
51
52
# File 'lib/syntax_tree/css/parser.rb', line 50

def source
  @source
end

Instance Method Details

#error?Boolean

Returns:

  • (Boolean)


57
58
59
# File 'lib/syntax_tree/css/parser.rb', line 57

def error?
  errors.any?
end

#parse(grammar: :stylesheet) ⇒ Object

5.3.1. Parse something according to a CSS grammar www.w3.org/TR/css-syntax-3/#parse-grammar



68
69
70
71
72
73
74
75
# File 'lib/syntax_tree/css/parser.rb', line 68

def parse(grammar: :stylesheet)
  case grammar
  in :stylesheet
    parse_css_stylesheet
  else
    raise ArgumentError, "Unsupported grammar: #{grammar}"
  end
end

#parse_component_valueObject

5.3.9. Parse a component value www.w3.org/TR/css-syntax-3/#parse-component-value



189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
# File 'lib/syntax_tree/css/parser.rb', line 189

def parse_component_value
  # 1.
  tokens = tokenize

  # 2.
  loop do
    case tokens.peek
    in CommentToken | WhitespaceToken
      tokens.next
    else
      break
    end
  end

  # 3.
  if tokens.peek.is_a?(EOFToken)
    return ParseError.new("Unexpected end of input parsing component value")
  end

  # 4.
  value = consume_component_value(tokens)

  # 5.
  loop do
    case tokens.peek
    in CommentToken | WhitespaceToken
      tokens.next
    else
      break
    end
  end

  # 6.
  if tokens.peek.is_a?(EOFToken)
    value
  else
    ParseError.new("Expected end of input parsing component value")
  end
end

#parse_component_valuesObject

5.3.10. Parse a list of component values www.w3.org/TR/css-syntax-3/#parse-list-of-component-values



231
232
233
234
235
236
237
# File 'lib/syntax_tree/css/parser.rb', line 231

def parse_component_values
  tokens = tokenize
  values = []

  values << consume_component_value(tokens) until tokens.peek.is_a?(EOFToken)
  values
end

#parse_declarationObject



149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/syntax_tree/css/parser.rb', line 149

def parse_declaration
  # 1.
  tokens = tokenize

  # 2.
  loop do
    case tokens.peek
    in CommentToken | WhitespaceToken
      tokens.next
    else
      break
    end
  end

  # 3.
  case tokens.peek
  in IdentToken
    # do nothing
  in EOFToken
    return ParseError.new("Unexpected end of input parsing declaration")
  else
    return ParseError.new("Expected an identifier at #{tokens.peek.location.start_char}")
  end

  # 4.
  if (declaration = consume_declaration(tokens))
    declaration
  else
    ParseError.new("Expected a declaration at #{tokens.peek.location.start_char}")
  end
end

#parse_declaration_listObject

5.3.8. Parse a list of declarations www.w3.org/TR/css-syntax-3/#parse-list-of-declarations



183
184
185
# File 'lib/syntax_tree/css/parser.rb', line 183

def parse_declaration_list
  consume_declaration_list(tokenize)
end

#parse_ruleObject



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/syntax_tree/css/parser.rb', line 101

def parse_rule
  # 1.
  tokens = tokenize

  # 2.
  loop do
    case tokens.peek
    in CommentToken | WhitespaceToken
      tokens.next
    else
      break
    end
  end

  # 3.
  rule = nil

  case tokens.peek
  in EOFToken
    return ParseError.new("Unexpected end of input parsing rule")
  in AtKeywordToken
    rule = consume_at_rule(tokens)
  else
    rule = consume_qualified_rule(tokens)
    return ParseError.new("Expected a rule at #{tokens.peek.location.start_char}") unless rule
  end

  # 4.
  loop do
    case tokens.peek
    in CommentToken | WhitespaceToken
      tokens.next
    else
      break
    end
  end

  # 5.
  case tokens.peek
  in EOFToken
    rule
  else
    ParseError.new("Expected end of input parsing rule")
  end
end

#parse_rule_listObject



95
96
97
# File 'lib/syntax_tree/css/parser.rb', line 95

def parse_rule_list
  consume_rule_list(tokenize, top_level: false)
end

#parse_stylesheetObject



79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/syntax_tree/css/parser.rb', line 79

def parse_stylesheet
  tokens = tokenize
  rules = consume_rule_list(tokens, top_level: true)

  location =
    if rules.any?
      rules.first.location.to(rules.last.location)
    else
      tokens.reverse_each.first.location
    end

  StyleSheet.new(rules: rules, location: location)
end