require 'treetop' require 'weskit/wml' grammar WesnothMarkupLanguage rule document contents { def wml ::Weskit::WML::Root.new.push *::Weskit::WML::Mixins::Grammar.reject_non_wml(elements) end } end # parts ------------------------------------------------------------------------------- rule identifier [a-z] [a-z_]* { def name text_value end } end rule raw_string (!eol .)* { def data text_value end } end rule code_content (!'>>' content)* { def contents text_value end } end rule code_string '<<' string:code_content '>>' { def data string.contents end } end rule multiline_content (!quote content)* { def contents text_value end } end rule multiline_string (quote string:multiline_content quote)* { def data elements.collect(&:string).collect(&:contents).join '"' end } end rule translatable_string '_' lws string:multiline_string { def data string.contents end } end rule opening_tag lws '[' tag:identifier ']' fws { def name tag.name end } end rule amending_tag lws '[+' tag:identifier ']' fws { def name tag.name end } end rule closing_tag lws '[/' tag:identifier ']' fws { def name tag.name end } end rule blank_line ws* "\n" end rule item code_attribute / multiline_attribute / translatable_attribute / attribute / amending_element / element end rule contents (blank_line / item)* { def items ::Weskit::WML::Mixins::Grammar.reject_non_wml elements end } end # items ------------------------------------------------------------------------------- rule attribute lws id:identifier lws equals value:raw_string eol { def item ::Weskit::WML::Attribute.new id.name, value.data end } end rule code_attribute lws id:identifier lws equals lws value:code_string fws { def item ::Weskit::WML::Attribute.new id.name, value.data, :code => true end } end rule multiline_attribute lws id:identifier lws equals lws value:multiline_string fws { def item ::Weskit::WML::Attribute.new id.name, value.data end } end rule translatable_attribute lws id:identifier lws equals lws '_' lws value:multiline_string fws { def item ::Weskit::WML::Attribute.new id.name, value.data, :translatable => true end } end rule element open:opening_tag nested:contents close:closing_tag { def item ::Weskit::WML::Mixins::Grammar.raise_on_mismatching open, close ::Weskit::WML::Element.new(open.name).push *nested.items end } end rule amending_element open:amending_tag nested:contents close:closing_tag { def item ::Weskit::WML::Mixins::Grammar.raise_on_mismatching open, close ::Weskit::WML::Element.new(open.name, :amendment => true).push *nested.items end } end # helpers ----------------------------------------------------------------------------- rule content "\n" / . end rule eol "\n" / !. end rule equals '=' end rule quote '"' end # whitespace rule ws "\s" / "\t" end # leading whitespaces rule lws ws* end # following whitespaces rule fws ws* eol end end