haml-edge 2.1.21 → 2.1.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/EDGE_GEM_VERSION +1 -1
- data/FAQ.md +142 -0
- data/{README.rdoc → README.md} +141 -141
- data/Rakefile +29 -17
- data/VERSION +1 -1
- data/lib/haml/buffer.rb +63 -27
- data/lib/haml/engine.rb +103 -80
- data/lib/haml/error.rb +7 -7
- data/lib/haml/exec.rb +80 -26
- data/lib/haml/filters.rb +106 -40
- data/lib/haml/helpers/action_view_extensions.rb +34 -39
- data/lib/haml/helpers/action_view_mods.rb +132 -139
- data/lib/haml/helpers.rb +207 -153
- data/lib/haml/html.rb +40 -21
- data/lib/haml/precompiler.rb +2 -0
- data/lib/haml/shared.rb +34 -3
- data/lib/haml/template/patch.rb +1 -1
- data/lib/haml/template/plugin.rb +0 -2
- data/lib/haml/template.rb +5 -0
- data/lib/haml/util.rb +136 -1
- data/lib/haml/version.rb +16 -4
- data/lib/haml.rb +502 -481
- data/lib/sass/css.rb +106 -68
- data/lib/sass/engine.rb +55 -22
- data/lib/sass/environment.rb +52 -21
- data/lib/sass/error.rb +23 -12
- data/lib/sass/files.rb +27 -0
- data/lib/sass/plugin/merb.rb +2 -2
- data/lib/sass/plugin/rails.rb +0 -2
- data/lib/sass/plugin.rb +32 -23
- data/lib/sass/repl.rb +7 -0
- data/lib/sass/script/bool.rb +9 -5
- data/lib/sass/script/color.rb +87 -1
- data/lib/sass/script/funcall.rb +23 -2
- data/lib/sass/script/functions.rb +93 -44
- data/lib/sass/script/lexer.rb +33 -3
- data/lib/sass/script/literal.rb +93 -1
- data/lib/sass/script/node.rb +14 -0
- data/lib/sass/script/number.rb +128 -4
- data/lib/sass/script/operation.rb +16 -1
- data/lib/sass/script/parser.rb +51 -21
- data/lib/sass/script/string.rb +7 -4
- data/lib/sass/script/unary_operation.rb +14 -1
- data/lib/sass/script/variable.rb +12 -1
- data/lib/sass/script.rb +26 -5
- data/lib/sass/tree/attr_node.rb +46 -9
- data/lib/sass/tree/comment_node.rb +41 -1
- data/lib/sass/tree/debug_node.rb +8 -0
- data/lib/sass/tree/directive_node.rb +20 -0
- data/lib/sass/tree/file_node.rb +12 -0
- data/lib/sass/tree/for_node.rb +15 -0
- data/lib/sass/tree/if_node.rb +22 -0
- data/lib/sass/tree/mixin_def_node.rb +12 -1
- data/lib/sass/tree/mixin_node.rb +13 -0
- data/lib/sass/tree/node.rb +136 -6
- data/lib/sass/tree/rule_node.rb +66 -7
- data/lib/sass/tree/variable_node.rb +10 -0
- data/lib/sass/tree/while_node.rb +11 -1
- data/lib/sass.rb +544 -534
- metadata +7 -6
- data/FAQ +0 -138
data/lib/sass/script/literal.rb
CHANGED
@@ -1,80 +1,172 @@
|
|
1
1
|
module Sass::Script
|
2
|
-
|
2
|
+
# The abstract superclass for SassScript objects.
|
3
|
+
#
|
4
|
+
# Many of these methods, especially the ones that correspond to SassScript operations,
|
5
|
+
# are designed to be overridden by subclasses which may change the semantics somewhat.
|
6
|
+
# The operations listed here are just the defaults.
|
7
|
+
class Literal < Node
|
3
8
|
require 'sass/script/string'
|
4
9
|
require 'sass/script/number'
|
5
10
|
require 'sass/script/color'
|
6
11
|
require 'sass/script/bool'
|
7
12
|
|
13
|
+
# Returns the Ruby value of the literal.
|
14
|
+
# The type of this value varies based on the subclass.
|
15
|
+
#
|
16
|
+
# @return [Object]
|
8
17
|
attr_reader :value
|
9
18
|
|
19
|
+
# Creates a new literal.
|
20
|
+
#
|
21
|
+
# @param value [Object] The object for \{#value}
|
10
22
|
def initialize(value = nil)
|
11
23
|
@value = value
|
12
24
|
end
|
13
25
|
|
26
|
+
# Evaluates the literal.
|
27
|
+
#
|
28
|
+
# @param environment [Sass::Environment] The environment in which to evaluate the SassScript
|
29
|
+
# @return [Literal] This literal
|
14
30
|
def perform(environment)
|
15
31
|
self
|
16
32
|
end
|
17
33
|
|
34
|
+
# The SassScript `and` operation.
|
35
|
+
#
|
36
|
+
# @param other [Literal] The right-hand side of the operator
|
37
|
+
# @return [Literal] The result of a logical and:
|
38
|
+
# `other` if this literal isn't a false {Bool},
|
39
|
+
# and this literal otherwise
|
18
40
|
def and(other)
|
19
41
|
to_bool ? other : self
|
20
42
|
end
|
21
43
|
|
44
|
+
# The SassScript `or` operation.
|
45
|
+
#
|
46
|
+
# @param other [Literal] The right-hand side of the operator
|
47
|
+
# @return [Literal] The result of the logical or:
|
48
|
+
# this literal if it isn't a false {Bool},
|
49
|
+
# and `other` otherwise
|
22
50
|
def or(other)
|
23
51
|
to_bool ? self : other
|
24
52
|
end
|
25
53
|
|
54
|
+
# The SassScript `==` operation.
|
55
|
+
# **Note that this returns a {Sass::Script::Bool} object,
|
56
|
+
# not a Ruby boolean**.
|
57
|
+
#
|
58
|
+
# @param other [Literal] The right-hand side of the operator
|
59
|
+
# @return [Bool] True if this literal is the same as the other,
|
60
|
+
# false otherwise
|
26
61
|
def eq(other)
|
27
62
|
Sass::Script::Bool.new(self.class == other.class && self.value == other.value)
|
28
63
|
end
|
29
64
|
|
65
|
+
# The SassScript `!=` operation.
|
66
|
+
# **Note that this returns a {Sass::Script::Bool} object,
|
67
|
+
# not a Ruby boolean**.
|
68
|
+
#
|
69
|
+
# @param other [Literal] The right-hand side of the operator
|
70
|
+
# @return [Bool] False if this literal is the same as the other,
|
71
|
+
# true otherwise
|
30
72
|
def neq(other)
|
31
73
|
Sass::Script::Bool.new(!eq(other).to_bool)
|
32
74
|
end
|
33
75
|
|
76
|
+
# The SassScript `==` operation.
|
77
|
+
# **Note that this returns a {Sass::Script::Bool} object,
|
78
|
+
# not a Ruby boolean**.
|
79
|
+
#
|
80
|
+
# @param other [Literal] The right-hand side of the operator
|
81
|
+
# @return [Bool] True if this literal is the same as the other,
|
82
|
+
# false otherwise
|
34
83
|
def unary_not
|
35
84
|
Sass::Script::Bool.new(!to_bool)
|
36
85
|
end
|
37
86
|
|
87
|
+
# The SassScript default operation (e.g. `!a !b`, `"foo" "bar"`).
|
88
|
+
#
|
89
|
+
# @param other [Literal] The right-hand side of the operator
|
90
|
+
# @return [Script::String] A string containing both literals
|
91
|
+
# separated by a space
|
38
92
|
def concat(other)
|
39
93
|
Sass::Script::String.new("#{self.to_s} #{other.to_s}")
|
40
94
|
end
|
41
95
|
|
96
|
+
# The SassScript `,` operation (e.g. `!a, !b`, `"foo", "bar"`).
|
97
|
+
#
|
98
|
+
# @param other [Literal] The right-hand side of the operator
|
99
|
+
# @return [Script::String] A string containing both literals
|
100
|
+
# separated by `", "`
|
42
101
|
def comma(other)
|
43
102
|
Sass::Script::String.new("#{self.to_s}, #{other.to_s}")
|
44
103
|
end
|
45
104
|
|
105
|
+
# The SassScript `+` operation.
|
106
|
+
#
|
107
|
+
# @param other [Literal] The right-hand side of the operator
|
108
|
+
# @return [Script::String] A string containing both literals
|
109
|
+
# without any separation
|
46
110
|
def plus(other)
|
47
111
|
Sass::Script::String.new(self.to_s + other.to_s)
|
48
112
|
end
|
49
113
|
|
114
|
+
# The SassScript `-` operation.
|
115
|
+
#
|
116
|
+
# @param other [Literal] The right-hand side of the operator
|
117
|
+
# @return [Script::String] A string containing both literals
|
118
|
+
# separated by `"-"`
|
50
119
|
def minus(other)
|
51
120
|
Sass::Script::String.new("#{self.to_s}-#{other.to_s}")
|
52
121
|
end
|
53
122
|
|
123
|
+
# The SassScript `/` operation.
|
124
|
+
#
|
125
|
+
# @param other [Literal] The right-hand side of the operator
|
126
|
+
# @return [Script::String] A string containing both literals
|
127
|
+
# separated by `"/"`
|
54
128
|
def div(other)
|
55
129
|
Sass::Script::String.new("#{self.to_s}/#{other.to_s}")
|
56
130
|
end
|
57
131
|
|
132
|
+
# The SassScript unary `-` operation (e.g. `-!a`).
|
133
|
+
#
|
134
|
+
# @param other [Literal] The right-hand side of the operator
|
135
|
+
# @return [Script::String] A string containing the literal
|
136
|
+
# preceded by `"-"`
|
58
137
|
def unary_minus
|
59
138
|
Sass::Script::String.new("-#{self.to_s}")
|
60
139
|
end
|
61
140
|
|
141
|
+
# The SassScript unary `/` operation (e.g. `/!a`).
|
142
|
+
#
|
143
|
+
# @param other [Literal] The right-hand side of the operator
|
144
|
+
# @return [Script::String] A string containing the literal
|
145
|
+
# preceded by `"/"`
|
62
146
|
def unary_div
|
63
147
|
Sass::Script::String.new("/#{self.to_s}")
|
64
148
|
end
|
65
149
|
|
150
|
+
# @return [String] A readable representation of the literal
|
66
151
|
def inspect
|
67
152
|
value.inspect
|
68
153
|
end
|
69
154
|
|
155
|
+
# @return [Boolean] `true` (the Ruby boolean value)
|
70
156
|
def to_bool
|
71
157
|
true
|
72
158
|
end
|
73
159
|
|
160
|
+
# Compares this object with another.
|
161
|
+
#
|
162
|
+
# @param other [Object] The object to compare with
|
163
|
+
# @return [Boolean] Whether or not this literal is equivalent to `other`
|
74
164
|
def ==(other)
|
75
165
|
eq(other).to_bool
|
76
166
|
end
|
77
167
|
|
168
|
+
# @return [Fixnum] The integer value of this literal
|
169
|
+
# @raise [Sass::SyntaxError] if this literal isn't an integer
|
78
170
|
def to_i
|
79
171
|
raise Sass::SyntaxError.new("#{self.inspect} is not an integer.")
|
80
172
|
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Sass::Script
|
2
|
+
# The abstract superclass for SassScript parse tree nodes.
|
3
|
+
#
|
4
|
+
# Use \{#perform} to evaluate a parse tree.
|
5
|
+
class Node
|
6
|
+
# Evaluates the node.
|
7
|
+
#
|
8
|
+
# @param environment [Sass::Environment] The environment in which to evaluate the SassScript
|
9
|
+
# @return [Literal] The SassScript object that is the value of the SassScript
|
10
|
+
def perform(environment)
|
11
|
+
raise NotImplementedError.new("All subclasses of Sass::Script::Node must override #perform.")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/lib/sass/script/number.rb
CHANGED
@@ -1,12 +1,38 @@
|
|
1
1
|
require 'sass/script/literal'
|
2
2
|
|
3
3
|
module Sass::Script
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
# A SassScript object representing a number.
|
5
|
+
# SassScript numbers can have decimal values,
|
6
|
+
# and can also have units.
|
7
|
+
# For example, `12`, `1px`, and `10.45em`
|
8
|
+
# are all valid values.
|
9
|
+
#
|
10
|
+
# Numbers can also have more complex units, such as `1px*em/in`.
|
11
|
+
# These cannot be inputted directly in Sass code at the moment.
|
12
|
+
class Number < Literal
|
13
|
+
# The Ruby value of the number.
|
14
|
+
#
|
15
|
+
# @return [Numeric]
|
16
|
+
attr_reader :value
|
17
|
+
|
18
|
+
# A list of units in the numerator of the number.
|
19
|
+
# For example, `1px*em/in*cm` would return `["px", "em"]`
|
20
|
+
# @return [Array<String>]
|
21
|
+
attr_reader :numerator_units
|
22
|
+
|
23
|
+
# A list of units in the denominator of the number.
|
24
|
+
# For example, `1px*em/in*cm` would return `["in", "cm"]`
|
25
|
+
# @return [Array<String>]
|
26
|
+
attr_reader :denominator_units
|
27
|
+
|
28
|
+
# The precision with which numbers will be printed to CSS files.
|
29
|
+
# For example, if this is `1000.0`,
|
30
|
+
# `3.1415926` will be printed as `3.142`.
|
8
31
|
PRECISION = 1000.0
|
9
32
|
|
33
|
+
# @param value [Numeric] The value of the number
|
34
|
+
# @param numerator_units [Array<String>] See \{#numerator\_units}
|
35
|
+
# @param denominator_units [Array<String>] See \{#denominator\_units}
|
10
36
|
def initialize(value, numerator_units = [], denominator_units = [])
|
11
37
|
super(value)
|
12
38
|
@numerator_units = numerator_units
|
@@ -14,6 +40,21 @@ module Sass::Script
|
|
14
40
|
normalize!
|
15
41
|
end
|
16
42
|
|
43
|
+
# The SassScript `+` operation.
|
44
|
+
# Its functionality depends on the type of its argument:
|
45
|
+
#
|
46
|
+
# {Number}
|
47
|
+
# : Adds the two numbers together, converting units if possible.
|
48
|
+
#
|
49
|
+
# {Color}
|
50
|
+
# : Adds this number to each of the RGB color channels.
|
51
|
+
#
|
52
|
+
# {Literal}
|
53
|
+
# : See {Literal#plus}.
|
54
|
+
#
|
55
|
+
# @param other [Literal] The right-hand side of the operator
|
56
|
+
# @return [Literal] The result of the operation
|
57
|
+
# @raise [Sass::SyntaxError] if `other` is a number with incompatible units
|
17
58
|
def plus(other)
|
18
59
|
if other.is_a? Number
|
19
60
|
operate(other, :+)
|
@@ -24,6 +65,18 @@ module Sass::Script
|
|
24
65
|
end
|
25
66
|
end
|
26
67
|
|
68
|
+
# The SassScript binary `-` operation (e.g. `!a - !b`).
|
69
|
+
# Its functionality depends on the type of its argument:
|
70
|
+
#
|
71
|
+
# {Number}
|
72
|
+
# : Subtracts this number from the other, converting units if possible.
|
73
|
+
#
|
74
|
+
# {Literal}
|
75
|
+
# : See {Literal#minus}.
|
76
|
+
#
|
77
|
+
# @param other [Literal] The right-hand side of the operator
|
78
|
+
# @return [Literal] The result of the operation
|
79
|
+
# @raise [Sass::SyntaxError] if `other` is a number with incompatible units
|
27
80
|
def minus(other)
|
28
81
|
if other.is_a? Number
|
29
82
|
operate(other, :-)
|
@@ -32,10 +85,25 @@ module Sass::Script
|
|
32
85
|
end
|
33
86
|
end
|
34
87
|
|
88
|
+
# The SassScript unary `-` operation (e.g. `-!a`).
|
89
|
+
#
|
90
|
+
# @return [Number] The negative value of this number
|
35
91
|
def unary_minus
|
36
92
|
Number.new(-value, numerator_units, denominator_units)
|
37
93
|
end
|
38
94
|
|
95
|
+
# The SassScript `*` operation.
|
96
|
+
# Its functionality depends on the type of its argument:
|
97
|
+
#
|
98
|
+
# {Number}
|
99
|
+
# : Multiplies the two numbers together, converting units appropriately.
|
100
|
+
#
|
101
|
+
# {Color}
|
102
|
+
# : Multiplies each of the RGB color channels by this number.
|
103
|
+
#
|
104
|
+
# @param other [Number, Color] The right-hand side of the operator
|
105
|
+
# @return [Number, Color] The result of the operation
|
106
|
+
# @raise [NoMethodError] if `other` is an invalid type
|
39
107
|
def times(other)
|
40
108
|
if other.is_a? Number
|
41
109
|
self.operate(other, :*)
|
@@ -46,6 +114,17 @@ module Sass::Script
|
|
46
114
|
end
|
47
115
|
end
|
48
116
|
|
117
|
+
# The SassScript `/` operation.
|
118
|
+
# Its functionality depends on the type of its argument:
|
119
|
+
#
|
120
|
+
# {Number}
|
121
|
+
# : Divides this number by the other, converting units appropriately.
|
122
|
+
#
|
123
|
+
# {Literal}
|
124
|
+
# : See {Literal#div}.
|
125
|
+
#
|
126
|
+
# @param other [Literal] The right-hand side of the operator
|
127
|
+
# @return [Literal] The result of the operation
|
49
128
|
def div(other)
|
50
129
|
if other.is_a? Number
|
51
130
|
operate(other, :/)
|
@@ -54,6 +133,12 @@ module Sass::Script
|
|
54
133
|
end
|
55
134
|
end
|
56
135
|
|
136
|
+
# The SassScript `%` operation.
|
137
|
+
#
|
138
|
+
# @param other [Number] The right-hand side of the operator
|
139
|
+
# @return [Number] This number modulo the other
|
140
|
+
# @raise [NoMethodError] if `other` is an invalid type
|
141
|
+
# @raise [Sass::SyntaxError] if `other` has any units
|
57
142
|
def mod(other)
|
58
143
|
if other.is_a?(Number)
|
59
144
|
unless other.unitless?
|
@@ -65,37 +150,70 @@ module Sass::Script
|
|
65
150
|
end
|
66
151
|
end
|
67
152
|
|
153
|
+
# The SassScript `==` operation.
|
154
|
+
#
|
155
|
+
# @param other [Literal] The right-hand side of the operator
|
156
|
+
# @return [Boolean] Whether this number is equal to the other object
|
68
157
|
def eq(other)
|
69
158
|
Sass::Script::Bool.new(super.to_bool &&
|
70
159
|
self.numerator_units.sort == other.numerator_units.sort &&
|
71
160
|
self.denominator_units.sort == other.denominator_units.sort)
|
72
161
|
end
|
73
162
|
|
163
|
+
# The SassScript `>` operation.
|
164
|
+
#
|
165
|
+
# @param other [Number] The right-hand side of the operator
|
166
|
+
# @return [Boolean] Whether this number is greater than the other
|
167
|
+
# @raise [NoMethodError] if `other` is an invalid type
|
74
168
|
def gt(other)
|
75
169
|
raise NoMethodError.new(nil, :gt) unless other.is_a?(Number)
|
76
170
|
operate(other, :>)
|
77
171
|
end
|
78
172
|
|
173
|
+
# The SassScript `>=` operation.
|
174
|
+
#
|
175
|
+
# @param other [Number] The right-hand side of the operator
|
176
|
+
# @return [Boolean] Whether this number is greater than or equal to the other
|
177
|
+
# @raise [NoMethodError] if `other` is an invalid type
|
79
178
|
def gte(other)
|
80
179
|
raise NoMethodError.new(nil, :gte) unless other.is_a?(Number)
|
81
180
|
operate(other, :>=)
|
82
181
|
end
|
83
182
|
|
183
|
+
# The SassScript `<` operation.
|
184
|
+
#
|
185
|
+
# @param other [Number] The right-hand side of the operator
|
186
|
+
# @return [Boolean] Whether this number is less than the other
|
187
|
+
# @raise [NoMethodError] if `other` is an invalid type
|
84
188
|
def lt(other)
|
85
189
|
raise NoMethodError.new(nil, :lt) unless other.is_a?(Number)
|
86
190
|
operate(other, :<)
|
87
191
|
end
|
88
192
|
|
193
|
+
# The SassScript `<=` operation.
|
194
|
+
#
|
195
|
+
# @param other [Number] The right-hand side of the operator
|
196
|
+
# @return [Boolean] Whether this number is less than or equal to the other
|
197
|
+
# @raise [NoMethodError] if `other` is an invalid type
|
89
198
|
def lte(other)
|
90
199
|
raise NoMethodError.new(nil, :lte) unless other.is_a?(Number)
|
91
200
|
operate(other, :<=)
|
92
201
|
end
|
93
202
|
|
203
|
+
# @return [String] The CSS representation of this number
|
204
|
+
# @raise [Sass::SyntaxError] if this number has units that can't be used in CSS
|
205
|
+
# (e.g. `px*in`)
|
94
206
|
def to_s
|
95
207
|
raise Sass::SyntaxError.new("#{inspect} isn't a valid CSS value.") unless legal_units?
|
96
208
|
inspect
|
97
209
|
end
|
98
210
|
|
211
|
+
# Returns a readable representation of this number.
|
212
|
+
#
|
213
|
+
# This representation is valid CSS (and valid SassScript)
|
214
|
+
# as long as there is only one unit.
|
215
|
+
#
|
216
|
+
# @return [String] The representation
|
99
217
|
def inspect
|
100
218
|
value =
|
101
219
|
if self.value.is_a?(Float) && (self.value.infinite? || self.value.nan?)
|
@@ -108,19 +226,25 @@ module Sass::Script
|
|
108
226
|
"#{value}#{unit_str}"
|
109
227
|
end
|
110
228
|
|
229
|
+
# @return [Fixnum] The integer value of the number
|
230
|
+
# @raise [Sass::SyntaxError] if the number isn't an integer
|
111
231
|
def to_i
|
112
232
|
super unless int?
|
113
233
|
return value
|
114
234
|
end
|
115
235
|
|
236
|
+
# @return [Boolean] Whether or not this number is an integer.
|
116
237
|
def int?
|
117
238
|
value % 1 == 0.0
|
118
239
|
end
|
119
240
|
|
241
|
+
# @return [Boolean] Whether or not this number has no units.
|
120
242
|
def unitless?
|
121
243
|
numerator_units.empty? && denominator_units.empty?
|
122
244
|
end
|
123
245
|
|
246
|
+
# @return [Boolean] Whether or not this number has units that can be represented in CSS
|
247
|
+
# (that is, zero or one \{#numerator\_units}).
|
124
248
|
def legal_units?
|
125
249
|
(numerator_units.empty? || numerator_units.size == 1) && denominator_units.empty?
|
126
250
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'set'
|
1
2
|
require 'sass/script/string'
|
2
3
|
require 'sass/script/number'
|
3
4
|
require 'sass/script/color'
|
@@ -5,17 +6,31 @@ require 'sass/script/functions'
|
|
5
6
|
require 'sass/script/unary_operation'
|
6
7
|
|
7
8
|
module Sass::Script
|
8
|
-
|
9
|
+
# A SassScript parse node representing a binary operation,
|
10
|
+
# such as `!a + !b` or `"foo" + 1`.
|
11
|
+
class Operation < Node
|
12
|
+
# @param operand1 [Script::Node] The parse-tree node
|
13
|
+
# for the right-hand side of the operator
|
14
|
+
# @param operand2 [Script::Node] The parse-tree node
|
15
|
+
# for the left-hand side of the operator
|
16
|
+
# @param operator [Symbol] The operator to perform.
|
17
|
+
# This should be one of the binary operator names in {Lexer::OPERATORS}
|
9
18
|
def initialize(operand1, operand2, operator)
|
10
19
|
@operand1 = operand1
|
11
20
|
@operand2 = operand2
|
12
21
|
@operator = operator
|
13
22
|
end
|
14
23
|
|
24
|
+
# @return [String] A human-readable s-expression representation of the operation
|
15
25
|
def inspect
|
16
26
|
"(#{@operator.inspect} #{@operand1.inspect} #{@operand2.inspect})"
|
17
27
|
end
|
18
28
|
|
29
|
+
# Evaluates the operation.
|
30
|
+
#
|
31
|
+
# @param environment [Sass::Environment] The environment in which to evaluate the SassScript
|
32
|
+
# @return [Literal] The SassScript object that is the value of the operation
|
33
|
+
# @raise [Sass::SyntaxError] if the operation is undefined for the operands
|
19
34
|
def perform(environment)
|
20
35
|
literal1 = @operand1.perform(environment)
|
21
36
|
literal2 = @operand2.perform(environment)
|
data/lib/sass/script/parser.rb
CHANGED
@@ -2,55 +2,85 @@ require 'sass/script/lexer'
|
|
2
2
|
|
3
3
|
module Sass
|
4
4
|
module Script
|
5
|
+
# The parser for SassScript.
|
6
|
+
# It parses a string of code into a tree of {Script::Node}s.
|
5
7
|
class Parser
|
8
|
+
# @param str [String, StringScanner] The source text to parse
|
9
|
+
# @param line [Fixnum] The line on which the SassScript appears.
|
10
|
+
# Used for error reporting
|
11
|
+
# @param offset [Fixnum] The number of characters in on which the SassScript appears.
|
12
|
+
# Used for error reporting
|
13
|
+
# @param filename [String] The name of the file in which the SassScript appears.
|
14
|
+
# Used for error reporting
|
6
15
|
def initialize(str, line, offset, filename = nil)
|
7
16
|
@filename = filename
|
8
17
|
@lexer = Lexer.new(str, line, offset)
|
9
18
|
end
|
10
19
|
|
20
|
+
# Parses a SassScript expression within an interpolated segment (`#{}`).
|
21
|
+
# This means that it stops when it comes across an unmatched `}`,
|
22
|
+
# which signals the end of an interpolated segment,
|
23
|
+
# it returns rather than throwing an error.
|
24
|
+
#
|
25
|
+
# @return [Script::Node] The root node of the parse tree
|
26
|
+
# @raise [Sass::SyntaxError] if the expression isn't valid SassScript
|
11
27
|
def parse_interpolated
|
12
28
|
expr = assert_expr :expr
|
13
29
|
assert_tok :end_interpolation
|
14
30
|
expr
|
15
31
|
end
|
16
32
|
|
33
|
+
# Parses a SassScript expression.
|
34
|
+
#
|
35
|
+
# @return [Script::Node] The root node of the parse tree
|
36
|
+
# @raise [Sass::SyntaxError] if the expression isn't valid SassScript
|
17
37
|
def parse
|
18
38
|
expr = assert_expr :expr
|
19
39
|
raise Sass::SyntaxError.new("Unexpected #{@lexer.peek.type} token.") unless @lexer.done?
|
20
40
|
expr
|
21
41
|
end
|
22
42
|
|
43
|
+
# Parses a SassScript expression.
|
44
|
+
#
|
45
|
+
# @overload parse(str, line, offset, filename = nil)
|
46
|
+
# @return [Script::Node] The root node of the parse tree
|
47
|
+
# @see Parser#initialize
|
48
|
+
# @see Parser#parse
|
23
49
|
def self.parse(*args)
|
24
50
|
new(*args).parse
|
25
51
|
end
|
26
52
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
53
|
+
class << self
|
54
|
+
private
|
55
|
+
|
56
|
+
# Defines a simple left-associative production.
|
57
|
+
# name is the name of the production,
|
58
|
+
# sub is the name of the production beneath it,
|
59
|
+
# and ops is a list of operators for this precedence level
|
60
|
+
def production(name, sub, *ops)
|
61
|
+
class_eval <<RUBY
|
62
|
+
def #{name}
|
63
|
+
return unless e = #{sub}
|
64
|
+
while tok = try_tok(#{ops.map {|o| o.inspect}.join(', ')})
|
65
|
+
e = Operation.new(e, assert_expr(#{sub.inspect}), tok.type)
|
66
|
+
end
|
67
|
+
e
|
39
68
|
end
|
40
|
-
e
|
41
|
-
end
|
42
69
|
RUBY
|
43
|
-
|
70
|
+
end
|
44
71
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
72
|
+
def unary(op, sub)
|
73
|
+
class_eval <<RUBY
|
74
|
+
def unary_#{op}
|
75
|
+
return #{sub} unless try_tok(:#{op})
|
76
|
+
UnaryOperation.new(assert_expr(:unary_#{op}), :#{op})
|
77
|
+
end
|
51
78
|
RUBY
|
79
|
+
end
|
52
80
|
end
|
53
81
|
|
82
|
+
private
|
83
|
+
|
54
84
|
production :expr, :concat, :comma
|
55
85
|
|
56
86
|
def concat
|
data/lib/sass/script/string.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
1
|
require 'sass/script/literal'
|
2
2
|
|
3
3
|
module Sass::Script
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
# A SassScript object representing a string of text.
|
5
|
+
class String < Literal
|
6
|
+
# The Ruby value of the string.
|
7
|
+
#
|
8
|
+
# @return [String]
|
9
|
+
attr_reader :value
|
10
|
+
alias_method :to_s, :value
|
8
11
|
end
|
9
12
|
end
|
@@ -1,14 +1,27 @@
|
|
1
1
|
module Sass::Script
|
2
|
-
|
2
|
+
# A SassScript parse node representing a unary operation,
|
3
|
+
# such as `-!b` or `not true`.
|
4
|
+
#
|
5
|
+
# Currently only `-`, `/`, and `not` are unary operators.
|
6
|
+
class UnaryOperation < Node
|
7
|
+
# @param operand [Script::Node] The parse-tree node
|
8
|
+
# for the object of the operator
|
9
|
+
# @param operator [Symbol] The operator to perform
|
3
10
|
def initialize(operand, operator)
|
4
11
|
@operand = operand
|
5
12
|
@operator = operator
|
6
13
|
end
|
7
14
|
|
15
|
+
# @return [String] A human-readable s-expression representation of the operation
|
8
16
|
def inspect
|
9
17
|
"(#{@operator.inspect} #{@operand.inspect})"
|
10
18
|
end
|
11
19
|
|
20
|
+
# Evaluates the operation.
|
21
|
+
#
|
22
|
+
# @param environment [Sass::Environment] The environment in which to evaluate the SassScript
|
23
|
+
# @return [Literal] The SassScript object that is the value of the operation
|
24
|
+
# @raise [Sass::SyntaxError] if the operation is undefined for the operand
|
12
25
|
def perform(environment)
|
13
26
|
operator = "unary_#{@operator}"
|
14
27
|
literal = @operand.perform(environment)
|
data/lib/sass/script/variable.rb
CHANGED
@@ -1,16 +1,27 @@
|
|
1
1
|
module Sass
|
2
2
|
module Script
|
3
|
-
|
3
|
+
# A SassScript parse node representing a variable.
|
4
|
+
class Variable < Node
|
5
|
+
# The name of the variable.
|
6
|
+
#
|
7
|
+
# @return [String]
|
4
8
|
attr_reader :name
|
5
9
|
|
10
|
+
# @param name [String] See \{#name}
|
6
11
|
def initialize(name)
|
7
12
|
@name = name
|
8
13
|
end
|
9
14
|
|
15
|
+
# @return [String] A string representation of the variable
|
10
16
|
def inspect
|
11
17
|
"!#{name}"
|
12
18
|
end
|
13
19
|
|
20
|
+
# Evaluates the variable.
|
21
|
+
#
|
22
|
+
# @param environment [Sass::Environment] The environment in which to evaluate the SassScript
|
23
|
+
# @return [Literal] The SassScript object that is the value of the variable
|
24
|
+
# @raise [Sass::SyntaxError] if the variable is undefined
|
14
25
|
def perform(environment)
|
15
26
|
(val = environment.var(name)) && (return val)
|
16
27
|
raise SyntaxError.new("Undefined variable: \"!#{name}\".")
|