# Parser ======================================================================= %% header { module Weskit::WML::Parsers } %% name = KPEG %% { attr_accessor :result private def strip_chars string, chars string[chars, string.length - chars * 2] end } %% footer { end } # Rules ======================================================================== id = < /[a-z][0-9a-z_]*/i > { text } ids = ids:i1 - ',' - ids:i2 { i1 + i2 } | id:i { [i] } item = attribute | attributes | element items = items:i1 items:i2 { i1 + i2 } | item:i { (i.is_a? Array) ? i : [i] } contents = items?:i { i.to_a } # Attributes ------------------------------------------------------------------- single_attr = - id:n - '=' - val:v - eol { Weskit::WML::Attribute.new n, *v } multiple_attrs = - ids:n - '=' - vals:v - eol { n.reduce(Array.new) do |attrs, name| value =v.shift or [nil] attrs << Weskit::WML::Attribute.new(name, *value) end } attribute = blk_lines single_attr:a blk_lines { a } attributes = blk_lines multiple_attrs:a blk_lines { a } # Attribute values ------------------------------------------------------------- code = < /<<.*?>>/m > { [strip_chars(text, 2), {:code => true}] } in_brackets = < /\(.*?\)/m > { [strip_chars(text, 1)] } in_quotes = < /".*?"/m > { [strip_chars(text, 1)] } raw = < /.*/ > { [text.strip] } escaped = in_quotes:s1 escaped:s2 { s1[0] += '"' + s2[0] ; s1 } | in_quotes i18n = '_' - (in_brackets | in_quotes):s { [s[0], {:translatable => true}] } val = val:v1 - '+' sp_lf val:v2 { v1[0] += v2[0] ; v1 } | escaped | i18n | code | in_brackets | in_quotes | raw vals = vals:v1 - ',' - vals:v2 { v1 + v2 } | val:v { [v] } # Elements --------------------------------------------------------------------- amendment = - amending_tag:n - eol contents:c - closing_tag(n) - eol { Weskit::WML::Element.new(n, :amendment => true).push *c } regular = - opening_tag:n - eol contents:c - closing_tag(n) - eol { Weskit::WML::Element.new(n).push *c } element = blk_lines (amendment | regular):e blk_lines { e } # Tags ------------------------------------------------------------------------- amending_tag = '[+' id:n ']' { n } closing_tag(m) = '[/' id:n ']' &{ n == m } opening_tag = '[' id:n ']' { n } # Whitespace ------------------------------------------------------------------- eof = !. eol = "\r\n" | "\n" sp = " " | "\t" - = sp* sp_lf = (sp | eol)* blk_lines = (- eol)* # Root ------------------------------------------------------------------------- root = contents:c { c.empty? ? nil : Weskit::WML::Root.new.push(*c) }