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:
parent
708838a2bd
commit
8e787b51b6
3 changed files with 69 additions and 17 deletions
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue