From 6b1c52ac63f192ebe23a01a7a52d431b9d496433 Mon Sep 17 00:00:00 2001 From: Nathan Weizenbaum Date: Mon, 21 Dec 2009 21:30:20 -0800 Subject: [PATCH] [Sass] [SCSS] Add support for declaring variables. No way to use them as of yet. --- lib/sass/script/lexer.rb | 7 +++++++ lib/sass/script/parser.rb | 13 +++++++++++++ lib/sass/scss/parser.rb | 30 ++++++++++++++++++++++++++++-- 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/lib/sass/script/lexer.rb b/lib/sass/script/lexer.rb index 627e2350..8da52ac1 100644 --- a/lib/sass/script/lexer.rb +++ b/lib/sass/script/lexer.rb @@ -43,6 +43,7 @@ module Sass '<' => :lt, '#{' => :begin_interpolation, '}' => :end_interpolation, + ';' => :semicolon, } # A list of operator strings ordered with longer names first @@ -113,6 +114,12 @@ module Sass @tok ||= read_token end + # Rewinds the underlying StringScanner + # to before the token returned by \{#peek}. + def unpeek! + @scanner.pos -= @scanner.matched_size if @tok + end + # @return [Boolean] Whether or not there's more source text to lex. def done? whitespace unless after_interpolation? diff --git a/lib/sass/script/parser.rb b/lib/sass/script/parser.rb index d8823c98..2a838cf1 100644 --- a/lib/sass/script/parser.rb +++ b/lib/sass/script/parser.rb @@ -42,6 +42,19 @@ module Sass expr end + # Parses a single SassScript expression. + # Unlike \{#parse}, doesn't expect this expression + # to consume the entire input stream. + # + # @return [Script::Node] The root node of the parse tree + # @raise [Sass::SyntaxError] if the expression isn't valid SassScript + def parse_some + expr = assert_expr :expr + expr.options = @options + @lexer.unpeek! + expr + end + # Parses the argument list for a mixin include. # # @return [Array] The root nodes of the arguments. diff --git a/lib/sass/scss/parser.rb b/lib/sass/scss/parser.rb index 0aa3f855..edddf9dd 100644 --- a/lib/sass/scss/parser.rb +++ b/lib/sass/scss/parser.rb @@ -73,6 +73,23 @@ module Sass node end + def variable + return unless raw '!' + name = tok! IDENT + ss + + if raw '|' + raw! '|' + guarded = true + end + + raw! '=' + ss + expr = sass_script_parser.parse_some + + node(Sass::Tree::VariableNode.new(name, expr, guarded)) + end + def operator # Many of these operators (all except / and ,) # are disallowed by the CSS spec, @@ -115,14 +132,18 @@ module Sass # A block may contain declarations and/or rulesets def block_contents(node) block_given? ? yield : ss - node << (child = directive || declaration_or_ruleset) + node << (child = block_child) while raw(';') || (child && !child.children.empty?) block_given? ? yield : ss - node << (child = directive || declaration_or_ruleset) + node << (child = block_child) end node end + def block_child + variable || directive || declaration_or_ruleset + end + # This is a nasty hack, and the only place in the parser # that requires backtracking. # The reason is that we can't figure out if certain strings @@ -324,6 +345,11 @@ module Sass node end + def sass_script_parser + Sass::Script::Parser.new(@scanner, @line, + @scanner.pos - @scanner.string.rindex("\n")) + end + EXPR_NAMES = { :medium => "medium (e.g. print, screen)", :pseudo_expr => "expression (e.g. fr, 2n+1)",