Skip to content

Commit

Permalink
Limit number values to a sensible range
Browse files Browse the repository at this point in the history
Number values are now limited to a maximum of `Float::MAX` and a minimum
of negative `Float::MAX`.

Internally, `Integer` is now used for numbers parsed as the "integer"
type (as defined in the spec), while `Float` is used for numbers parsed
as the "number" type.

Fixes #10
  • Loading branch information
rgrove committed Jan 12, 2020
1 parent fbedb91 commit 3e02596
Show file tree
Hide file tree
Showing 2 changed files with 181 additions and 13 deletions.
45 changes: 32 additions & 13 deletions lib/crass/tokenizer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -429,27 +429,36 @@ def consume_number
# 4.3.3. http://dev.w3.org/csswg/css-syntax/#consume-a-numeric-token
def consume_numeric
number = consume_number
repr = number[0]
value = number[1]
type = number[2]

if type == :integer
value = value.to_i
else
value = value.to_f
end

if start_identifier?(@s.peek(3))
create_token(:dimension,
:repr => number[0],
:type => number[2],
:unit => consume_name,
:value => number[1])
:repr => repr,
:type => type,
:unit => consume_name,
:value => value)

elsif @s.peek == '%'
@s.consume

create_token(:percentage,
:repr => number[0],
:type => number[2],
:value => number[1])
:repr => repr,
:type => type,
:value => value)

else
create_token(:number,
:repr => number[0],
:type => number[2],
:value => number[1])
:repr => repr,
:type => type,
:value => value)
end
end

Expand Down Expand Up @@ -588,9 +597,19 @@ def convert_string_to_number(str)
t = matches[:exponent_sign] == '-' ? -1 : 1
e = matches[:exponent].to_i

# I know this looks nutty, but it's exactly what's defined in the spec,
# and it works.
s * (i + f * 10**-d) * 10**(t * e)
# I know this formula looks nutty, but it's exactly what's defined in the
# spec, and it works.
value = s * (i + f * 10**-d) * 10**(t * e)

# Maximum and minimum values aren't defined in the spec, but are enforced
# here for sanity.
if value > Float::MAX
value = Float::MAX
elsif value < -Float::MAX
value = -Float::MAX
end

value
end

# Creates and returns a new token with the given _properties_.
Expand Down
149 changes: 149 additions & 0 deletions test/shared/parse_rules.rb
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,155 @@
end
end

# https://github.com/rgrove/crass/issues/10
it 'should limit number values to a maximum of `Float::MAX`' do
tree = parse("div { height: 5e99999 }")

assert_equal([
{:node=>:style_rule,
:selector=>
{:node=>:selector,
:value=>"div",
:tokens=>
[{:node=>:ident, :pos=>0, :raw=>"div", :value=>"div"},
{:node=>:whitespace, :pos=>3, :raw=>" "}]},
:children=>
[{:node=>:whitespace, :pos=>5, :raw=>" "},
{:node=>:property,
:name=>"height",
:value=>"5e99999",
:children=>
[{:node=>:whitespace, :pos=>13, :raw=>" "},
{:node=>:number,
:pos=>14,
:raw=>"5e99999",
:repr=>"5e99999",
:type=>:number,
:value=>1.7976931348623157e+308},
{:node=>:whitespace, :pos=>21, :raw=>" "}],
:important=>false,
:tokens=>
[{:node=>:ident, :pos=>6, :raw=>"height", :value=>"height"},
{:node=>:colon, :pos=>12, :raw=>":"},
{:node=>:whitespace, :pos=>13, :raw=>" "},
{:node=>:number,
:pos=>14,
:raw=>"5e99999",
:repr=>"5e99999",
:type=>:number,
:value=>1.7976931348623157e+308},
{:node=>:whitespace, :pos=>21, :raw=>" "}]}]}
], tree)
end

# https://github.com/rgrove/crass/issues/10
it 'should limit number values to a minimum of `-Float::MAX`' do
tree = parse("div { margin: -5e99999 }")

assert_equal([
{:node=>:style_rule,
:selector=>
{:node=>:selector,
:value=>"div",
:tokens=>
[{:node=>:ident, :pos=>0, :raw=>"div", :value=>"div"},
{:node=>:whitespace, :pos=>3, :raw=>" "}]},
:children=>
[{:node=>:whitespace, :pos=>5, :raw=>" "},
{:node=>:property,
:name=>"margin",
:value=>"-5e99999",
:children=>
[{:node=>:whitespace, :pos=>13, :raw=>" "},
{:node=>:number,
:pos=>14,
:raw=>"-5e99999",
:repr=>"-5e99999",
:type=>:number,
:value=>-1.7976931348623157e+308},
{:node=>:whitespace, :pos=>22, :raw=>" "}],
:important=>false,
:tokens=>
[{:node=>:ident, :pos=>6, :raw=>"margin", :value=>"margin"},
{:node=>:colon, :pos=>12, :raw=>":"},
{:node=>:whitespace, :pos=>13, :raw=>" "},
{:node=>:number,
:pos=>14,
:raw=>"-5e99999",
:repr=>"-5e99999",
:type=>:number,
:value=>-1.7976931348623157e+308},
{:node=>:whitespace, :pos=>22, :raw=>" "}]}]}
], tree)
end

# https://github.com/rgrove/crass/issues/10
it 'should parse a class selector that looks like an exponent' do
tree = parse("p.5e1367490fa5f06927cafe55msonormal {}")

assert_equal([
{:node=>:style_rule,
:selector=>
{:node=>:selector,
:value=>"p.5e1367490fa5f06927cafe55msonormal",
:tokens=>
[{:node=>:ident, :pos=>0, :raw=>"p", :value=>"p"},
{:node=>:dimension,
:pos=>1,
:raw=>".5e1367490fa5f06927cafe55msonormal",
:repr=>".5e1367490",
:type=>:number,
:unit=>"fa5f06927cafe55msonormal",
:value=>1.7976931348623157e+308},
{:node=>:whitespace, :pos=>35, :raw=>" "}]},
:children=>[]}
], tree)
end

# https://github.com/rgrove/crass/issues/10
it 'should parse a property value that looks like an exponent' do
tree = parse("p { mso-style-name:5e1367490fa5f06927cafe55msonormal }")

assert_equal([
{:node=>:style_rule,
:selector=>
{:node=>:selector,
:value=>"p",
:tokens=>
[{:node=>:ident, :pos=>0, :raw=>"p", :value=>"p"},
{:node=>:whitespace, :pos=>1, :raw=>" "}]},
:children=>
[{:node=>:whitespace, :pos=>3, :raw=>" "},
{:node=>:property,
:name=>"mso-style-name",
:value=>"5e1367490fa5f06927cafe55msonormal",
:children=>
[{:node=>:dimension,
:pos=>19,
:raw=>"5e1367490fa5f06927cafe55msonormal",
:repr=>"5e1367490",
:type=>:number,
:unit=>"fa5f06927cafe55msonormal",
:value=>1.7976931348623157e+308},
{:node=>:whitespace, :pos=>52, :raw=>" "}],
:important=>false,
:tokens=>
[{:node=>:ident,
:pos=>4,
:raw=>"mso-style-name",
:value=>"mso-style-name"},
{:node=>:colon, :pos=>18, :raw=>":"},
{:node=>:dimension,
:pos=>19,
:raw=>"5e1367490fa5f06927cafe55msonormal",
:repr=>"5e1367490",
:type=>:number,
:unit=>"fa5f06927cafe55msonormal",
:value=>1.7976931348623157e+308},
{:node=>:whitespace, :pos=>52, :raw=>" "}]}]}
], tree)
end

it 'should parse property values containing functions' do
tree = parse("p:before { content: a\\ttr(data-foo) \" \"; }")

Expand Down

0 comments on commit 3e02596

Please sign in to comment.