lib/wlang/dialect.rb in wlang-0.10.2 vs lib/wlang/dialect.rb in wlang-2.0.0.beta
- old
+ new
@@ -1,250 +1,53 @@
-require 'wlang/encoder_set'
-require 'wlang/rule_set'
+require 'wlang/dialect/dispatching'
+require 'wlang/dialect/evaluation'
+require 'wlang/dialect/tags'
module WLang
-
- #
- # Implements the _dialect_ abstraction (see {README}[link://files/README.rdoc]).
- # A dialect instance is an aggregation of encoders and ruleset (through EncoderSet
- # and RuleSet classes). A dialect is also a node in the dialect tree and has a
- # qualified name through this tree. For example <tt>wlang/xhtml</tt> is the
- # qualified name of a <tt>xhtml</tt> dialect which is a child dialect of
- # <tt>wlang</tt>.
- #
- # Users are not intended to use this class directly. Use the Domain Specific
- # Language instead (see WLang::Dialect::DSL).
- #
- # === For developers only
- #
- # In order to avoid having users to install all required gems of all dialects
- # wlang implements a lazy load design pattern on the dialect tree, through the
- # WLang::Dialect::DSL and WLang::Dialect::Loader classes. The former only creates
- # Dialect instances as tree nodes (by chaining dialects through @parent) and
- # installs mapping with file extensions. Rules and encoders are not initially
- # installed (precisely: WLang::Dialect::DSL#require_ruby is simply ignored).
- # When a given dialect is needed by wlang it is first built (through the build!
- # method and the WLang::Dialect::Loader class).
- #
- # Standard dialect obtention methods (WLang#dialect as well as WLang::Dialect#dialect)
- # ensure that returned dialects are built. If you obtain dialects another way,
- # be sure that they are built before using them (is_built? and build! are your
- # friends to achieve that goal).
- #
- # Moreover, child dialects may require tools of their ancestors. The following
- # invariant should always be respected: if a dialect is built, all its ancestors
- # are built as well. This invariant is not enforced by the build! method because
- # it is trivially respected by the way WLang::Dialect#dialect is implemented.
- #
class Dialect
-
- # Underlying ruleset
- attr_reader :ruleset
-
- # Underlying encoders
- attr_reader :encoders
+ include Dialect::Dispatching
+ include Dialect::Evaluation
+ include Dialect::Tags
- # Dialect name
- attr_reader :name
-
- # Parent dialect
- attr_reader :parent
-
- # Sub dialects by name
- attr_reader :dialects
-
- # Post transformer
- attr_accessor :post_transformer
-
- #
- # Creates a dialect instance. _builder_ block is a chunk of code of the DSL
- # that will be executed twice: once at construction time to create sub dialects
- # nodes and install file extensions and once at building time to install ruleset
- # and encoders.
- #
- def initialize(name, parent, &builder)
- @name, @parent = name, parent
- @builder, @built = builder, builder.nil?
- @dialects = nil
- @encoders = nil
- @ruleset = nil
- DSL.new(self).instance_eval(&builder) unless builder.nil?
- end
-
- ### Lazy load mechanism ######################################################
-
- #
- # Force the dialect to be built. Has no effect if it is already built. Invokes
- # the DSL chunk of code through WLang::DSL::Loader otherwise.
- #
- def build!
- unless is_built?
- WLang::Dialect::Loader.new(self).instance_eval(&@builder)
- @built = true
+ class << self
+
+ def factor(options = {})
+ new(default_options.merge(options))
end
- self
- end
- # Returns true if this dialect is already built, false otherwise.
- def is_built?
- return @built
- end
+ def default_options(options = {})
+ @default_options ||= (superclass.default_options.dup rescue {})
+ @default_options.merge!(options)
+ end
-
- ### Installation #############################################################
-
- #
- # Adds a child dialect under _name_. _name_ cannot be qualified and must be a
- # valid dialect name according to the wlang specification (see WLang::DIALECT_NAME_REGEXP).
- # _child_ must be a Dialect instance.
- #
- def add_child_dialect(name, child)
- raise(ArgumentError, "Invalid dialect name") unless WLang::DIALECT_NAME_REGEXP =~ name
- raise(ArgumentError, "Dialect expected") unless Dialect===child
- @dialects = {} if @dialects.nil?
- @dialects[name] = child
- end
-
- # See EncoderSet#add_encoder
- def add_encoder(name, &block)
- @encoders = EncoderSet.new if @encoders.nil?
- @encoders.add_encoder(name, &block)
- end
-
- # See EncoderSet#add_encoders
- def add_encoders(mod, pairs)
- @encoders = EncoderSet.new if @encoders.nil?
- @encoders.add_encoders(mod, pairs)
- end
-
- # See RuleSet::add_rule
- def add_rule(name, &block)
- @ruleset = RuleSet.new if @ruleset.nil?
- @ruleset.add_rule(name, &block)
- end
-
- # See RuleSet::add_rules
- def add_rules(mod, pairs)
- @ruleset = RuleSet.new if @ruleset.nil?
- @ruleset.add_rules(mod, pairs)
- end
-
- ### Query API ################################################################
-
- # Returns qualified name of this dialect
- def qualified_name
- parentname = @parent.nil? ? "" : @parent.to_s
- return ""==parentname ? @name : parentname + '/' + @name
- end
-
- #
- # Finds a child dialect by name. _name_ can be a String denoting a qualified
- # name as well as an Array of strings, resulting from a qualified name split.
- # This method should always be invoked on built dialects, it always returns nil
- # otherwise. When found, returned dialect is automatically built as well as all
- # its ancestors. When not found, the method returns nil.
- #
- def dialect(name)
- # implement argument conventions
- if String===name
- raise(ArgumentError, "Invalid dialect name #{name}") unless WLang::QUALIFIED_DIALECT_NAME_REGEXP =~ name
- name = name.split('/')
- elsif not(Array===name)
- raise(ArgumentError,"Invalid dialect name #{name}")
+ def compiler(options = {})
+ factor(options).compiler
end
-
- # not built or no child at all
- return nil if @dialects.nil?
-
- # get first child name and find it
- child_name = name[0]
- child_dialect = @dialects[child_name]
-
- if child_dialect.nil?
- # unexisting, return nil
- return nil
- elsif name.length==1
- # found and last of qualified name -> build it
- return child_dialect.build!
- else
- # found but not last of qualified name -> build it and delegate
- child_dialect.build!
- return child_dialect.dialect(name[1..-1])
+
+ def compile(source, options = {})
+ compiler(options).compile(source)
end
- end
-
- # Applies post transformation
- def apply_post_transform(text)
- case self.post_transformer
- when String
- WLang::encode(text, self.post_transformer, {})
- when Proc
- self.post_transformer.call(text)
- else
- text
+
+ def to_ruby_code(source, options = {})
+ compiler(options).to_ruby_code(source)
end
- end
-
- #
- # Finds an encoder by name.
- #
- def encoder(name)
- # implement argument conventions
- if String===name
- raise(ArgumentError, "Invalid encoder name #{name}") unless WLang::QUALIFIED_ENCODER_NAME_REGEXP =~ name
- name = name.split('/')
- elsif not(Array===name)
- raise(ArgumentError,"Invalid encoder name #{name}")
+
+ def render(source, scope = {}, buffer = "")
+ compile(source).call(scope, buffer)
end
-
- # last name in qualified?
- if name.length==1
- # delegate to encoders
- return nil if @encoders.nil?
- return @encoders.get_encoder(name[0])
- else
- # find sub dialect, and delegate
- child_name = name[0]
- child_dialect = dialect(child_name)
- if child_dialect.nil?
- return nil
- else
- return child_dialect.encoder(name[1..-1])
- end
- end
+
end
-
- # Finds a encoder in dialect tree
- def find_encoder(name)
- raise(ArgumentError, "Invalid (relative) encoder name #{name}") unless String===name
- raise(ArgumentError, "Invalid (relative) encoder name #{name}") if name.include?("/")
- return nil if @encoders.nil?
- if @encoders.has_encoder?(name)
- @encoders.get_encoder(name)
- elsif @parent
- @parent.find_encoder(name)
- else
- nil
- end
+
+ default_options :braces => WLang::BRACES,
+ :autospacing => false
+
+ attr_reader :options
+ def braces; options[:braces]; end
+
+ attr_reader :compiler
+
+ def initialize(options = {})
+ @options = options
+ @compiler = WLang::Compiler.new(self)
end
-
- # See RuleSet#pattern.
- def pattern(block_symbols)
- return RuleSet.new.pattern(block_symbols) if @ruleset.nil?
- @ruleset.pattern(block_symbols)
- end
-
- ### Other utilities ##########################################################
-
- # Factors a spacing friendly buffer for instantiation in this dialect
- def factor_buffer
- #IntelligentBuffer.new
- ""
- end
-
- # Returns a string representation
- def to_s
- qualified_name
- end
-
+
end # class Dialect
-
-end #module WLang
\ No newline at end of file
+end # module WLang