1
0
Fork 0
mirror of https://github.com/haml/haml.git synced 2022-11-09 12:33:31 -05:00

[Sass] Keep track of the runtime stack so it can be inspected without unwinding.

This commit is contained in:
Chris Eppstein 2010-04-10 11:51:43 -07:00
parent 708838a2bd
commit 8e787b51b6
3 changed files with 69 additions and 17 deletions

View file

@ -23,7 +23,8 @@ module Sass
@vars = {}
@mixins = {}
@parent = parent
@stack = []
@ignore_parent_stack = false
set_var("important", Script::String.new("!important")) unless @parent
end
@ -35,6 +36,49 @@ module Sass
@options || (parent && parent.options) || {}
end
# Push lexical frame information onto the runtime stack.
# @param frame_info [{Symbol => Object}]
# Frame information has the following keys:
#
# `:filename`
# : The name of the file in which the lexical scope changed.
#
# `:mixin`
# : The name of the mixin in which the lexical scope changed,
# or `nil` if it wasn't within in a mixin.
#
# `:line`
# : The line of the file on which the lexical scope changed. Never nil.
#
# `:import`
# : Set to `true` when the lexical scope is changing due to an import.
def push(frame_info)
@stack.push frame_info
end
# Pop runtime frame information from the stack.
def pop
@stack.pop
end
# A list of the runtime stack frame information
# The last element in the list was pushed onto the stack most recently.
def stack
prev = (!@ignore_parent_stack && parent && parent.stack) || []
prev + @stack
end
# Temporarily assume the runtime stack that is passed in.
# @param stk A stack value from another environment.
def with_stack(stk)
@stack, old_stack = stk, @stack
@ignore_parent_stack = true
yield self
ensure
@ignore_parent_stack = false
@stack = old_stack
end
class << self
private

View file

@ -62,6 +62,7 @@ module Sass
# @param environment [Sass::Environment] The lexical environment containing
# variable and mixin values
def perform!(environment)
environment.push(:filename => @filename, :line => @line, :import => true)
root = Sass::Files.tree_for(full_filename, @options)
@template = root.template
self.children = root.children
@ -70,6 +71,8 @@ module Sass
e.modify_backtrace(:filename => full_filename)
e.add_backtrace(:filename => @filename, :line => @line)
raise e
ensure
environment.pop
end
private

View file

@ -50,6 +50,8 @@ module Sass::Tree
# @raise [Sass::SyntaxError] if an incorrect number of arguments was passed
# @see Sass::Tree
def perform!(environment)
original_env = environment
original_env.push(:filename => filename, :mixin => @name, :line => line)
raise Sass::SyntaxError.new("Undefined mixin '#{@name}'.") unless mixin = environment.mixin(@name)
raise Sass::SyntaxError.new(<<END.gsub("\n", "")) if mixin.args.size < @args.size
@ -57,27 +59,30 @@ Mixin #{@name} takes #{mixin.args.size} argument#{'s' if mixin.args.size != 1}
but #{@args.size} #{@args.size == 1 ? 'was' : 'were'} passed.
END
environment = mixin.args.zip(@args).
inject(Sass::Environment.new(mixin.environment)) do |env, ((var, default), value)|
env.set_local_var(var.name,
if value
value.perform(environment)
elsif default
val = default.perform(env)
if default.context == :equals && val.is_a?(Sass::Script::String)
val = Sass::Script::String.new(val.value)
end
val
end)
raise Sass::SyntaxError.new("Mixin #{@name} is missing parameter #{var.inspect}.") unless env.var(var.name)
env
mixin.environment.with_stack(original_env.stack) do |mixin_env|
environment = mixin.args.zip(@args).
inject(Sass::Environment.new(mixin_env)) do |env, ((var, default), value)|
env.set_local_var(var.name,
if value
value.perform(environment)
elsif default
val = default.perform(env)
if default.context == :equals && val.is_a?(Sass::Script::String)
val = Sass::Script::String.new(val.value)
end
val
end)
raise Sass::SyntaxError.new("Mixin #{@name} is missing parameter #{var.inspect}.") unless env.var(var.name)
env
end
self.children = mixin.tree.map {|c| c.perform(environment)}.flatten
end
self.children = mixin.tree.map {|c| c.perform(environment)}.flatten
rescue Sass::SyntaxError => e
e.modify_backtrace(:mixin => @name, :line => @line)
e.add_backtrace(:line => @line)
raise e
ensure
original_env.pop
end
end
end