LaTeXML

 view release on metacpan or  search on metacpan

lib/LaTeXML/Common/Model/RelaxNG.pm  view on Meta::CPAN

    else {
      return ([$op, $name, $self->simplify_args($binding, $parentbinding, $container, @args)]); } }
  else {
    return ($form); } }

sub simplify_args {
  my ($self, $binding, $parentbinding, $container, @forms) = @_;
  return map { $self->simplify($_, $binding, $parentbinding, $container) } @forms; }

sub simplify_override {
  my ($self, $binding, $parentbinding, $container, @args) = @_;
  # Note that we do NOT simplify till we've made the replacements!
  my ($module, @replacements) = @args;
  my ($modop, $modname, @patterns) = @$module;
  # Replace any start from @patterns by that from @replacement, if any.
  if (my @replacement_start = grep { eqOp($_, 'start') } @replacements) {
    @patterns = grep { !eqOp($_, 'start') } @patterns; }
  foreach my $def (grep { (ref $_ eq 'ARRAY') && ($$_[0] =~ /^def/) } @replacements) {
    my ($defop, $symbol) = @$def;
    @patterns = grep { !(eqOp($_, $defop) && ($$_[1] eq $symbol)) } @patterns; }
  # Recurse on the overridden module
  return $self->simplify(['module', "$modname (overridden)", @patterns, @replacements],
    $binding, $parentbinding, $container); }

sub simplifyCombination {
  my ($combination) = @_;
  if ((ref $combination) && ($$combination[0] eq 'combination')) {
    my ($c, $op, @stuff) = @$combination;
    @stuff = map { simplifyCombination($_) } @stuff;
    if ($op =~ /^(group|choice)$/) {    # These can be flattened.
      @stuff = map { ((ref $_) && ($$_[0] eq 'combination') && ($$_[1] eq $op)
          ? @$_[2 .. $#$_] : ($_)) }
        @stuff; }
    return (($op eq 'group') && (scalar(@stuff) == 1) ? $stuff[0] : [$c, $op, @stuff]); }
  else {
    return $combination; } }

#======================================================================
# For debugging...
sub showSchema {
  my ($item, $level) = @_;
  $level = 0 unless defined $level;
  if (ref $item eq 'ARRAY') {
    my ($op, $name, @args) = @$item;
    if ($op eq 'doc') { $name = "..."; @args = (); }
    Debug("" . (' ' x (2 * $level)) . $op . ($name ? " " . $name : ''));

    foreach my $arg (@args) {
      showSchema($arg, $level + 1); } }
  else {
    Debug("" . (' ' x (2 * $level)) . $item); }
  return; }

#======================================================================
# Generate TeX documentation for a Schema
#======================================================================
# The svg schema can only just barely be read in and recognized,
# but it is structured in a way that makes a joke of our attempt at automatic documentation
my $SKIP_SVG   = 1;    # [CONFIGURABLE?]
my $SKIP_ARIA  = 1;
my $SKIP_XHTML = 1;

sub documentModules {
  my ($self) = @_;
  my $docs = "";
  $$self{defined_patterns} = {};
  foreach my $module (@{ $$self{modules} }) {
    my ($op, $name, @content) = @$module;
    next if $SKIP_SVG && $name =~ /:svg:/;                        # !!!!
    $name =~ s/^urn:x-LaTeXML:RelaxNG://;                         # Remove the urn part.
    $docs = join("\n", $docs,
      "\\begin{schemamodule}{$name}",
      (map { $self->toTeX($_) } @content),
      "\\end{schemamodule}"); }
  foreach my $name (sort keys %{ $$self{defined_patterns} }) {
    if ($$self{defined_patterns}{$name} < 0) {
      $docs =~ s/\\patternadd\{$name\}/\\patterndefadd{$name}/s; } }
  return $docs; }

sub cleanTeX {
  my ($string) = @_;
  return '\typename{text}' if $string eq '#PCDATA';
  $string =~ s/^urn:x-LaTeXML:RelaxNG://;    # Remove the urn part, if any
  $string =~ s/\#/\\#/g;
  $string =~ s/<([^>]*)>/\\texttt{$1}/g;     # An apparent convention <sometext> == ttfont?
  $string =~ s/_/\\_/g;
  return $string; }

sub cleanTeXName {
  my ($string) = @_;
  $string = cleanTeX($string);
  $string =~ s/^ltx://;
  #  $string =~ s/:/../;
  return $string; }

sub toTeX {
  my ($self, $object) = @_;
  if (ref $object eq 'HASH') {
    return join(', ', map { "$_=" . $self->toTeX($$object{$_}) } sort keys %$object); }
  elsif (ref $object eq 'ARRAY') {    # an object?
    my ($op, $name, @data) = @$object;
    if ($op eq 'doc') {
      return join(' ', map { cleanTeX($_) } @data) . "\n"; }
    elsif ($op eq 'ref') {
      return $self->toTeX_ref($op, $name); }
    elsif ($op =~ /^def(choice|interleave|)$/) {
      return $self->toTeX_def($1, $name, @data); }
    elsif ($op eq 'element') {
      return $self->toTeX_element($name, @data); }
    elsif ($op eq 'attribute') {
      return $self->toTeX_attribute($name, @data); }
    elsif ($op eq 'combination') {
      return $self->toTeX_combination($name, @data); }
    elsif ($op eq 'data') {
      return "\\typename{" . cleanTeX($data[0]) . "}"; }
    elsif ($op eq 'value') {
      return '\attrval{' . cleanTeX($data[0]) . "}"; }
    elsif ($op eq 'start') {
      my ($docs, @spec) = $self->toTeXExtractDocs(@data);
      my $content = join(' ', map { $self->toTeX($_) } @spec);
      return "\\item[\\textit{Start}]\\textbf{==}\\ $content" . ($docs ? " \\par$docs" : ''); }
    elsif ($op eq 'grammar') {    # Don't otherwise mention it?
      my (@mods, @rest);          # Collapse any iniitial module inclusions for brevity
      foreach my $datum (@data) {
        if ((ref $datum eq 'ARRAY') && ($$datum[0] eq 'module')) {
          push(@mods, $$datum[1]); }
        else { push(@rest, $datum); } }
      return join("\n",
        (@mods
          ? '\item[\textit{Included}]' . join(', ', map { '\moduleref{' . cleanTeX($_) . '}'; } @mods)
          : ()),
        map { $self->toTeX($_) } @rest); }
    elsif ($op eq 'module') {
      if (($name =~ /:svg:/) && $SKIP_SVG) {
        return '\item[\textit{Module }' . cleanTeX($name) . '] included.'; }
      else {
        return '\item[\textit{Module }\moduleref{' . cleanTeX($name) . '}] included.'; } }
    else {
      Warn('unexpected', $op, undef, "RelaxNG->toTeX: Unrecognized item $op");
      return "[$op: " . join(', ', map { $self->toTeX($_) } @data) . "]"; } }
  else {
    return cleanTeX($object); } }

sub toTeX_ref {
  my ($self, $op, $name) = @_;
  if (my $el = $$self{elementdefs}{$name}) {
    $el = cleanTeXName($el);
    return ($SKIP_XHTML && ($el eq 'xhtml:*') ? '\texttt{xhtml:*}' : "\\elementref{$el}"); }
  elsif ($name =~ /_(?:attributes|model)$/) {
    return $self->toTeX($$self{defs}{$name}); }
  else {
    $name =~ s/^\w+://;    # Strip off qualifier!!!! (watch for clash in docs?)
    return ($SKIP_SVG && ($name eq 'svg') ? '\texttt{svg:svg}'
      : "\\patternref{" . cleanTeX($name) . "}"); } }

sub toTeX_def {
  my ($self, $combiner, $name, @data) = @_;
  my $qname = $name;
  return "" if ($name =~ /\baria\b/) && $SKIP_ARIA;
  return "" if $name =~ /_(?:attributes|model)$/;
  $name =~ s/^\w+://;    # Strip off qualifier!!!! (watch for clash in docs?)
  return "" if $SKIP_SVG && ($name =~ /^svg/);
  $name = cleanTeX($name);
  my ($docs, @spec)    = $self->toTeXExtractDocs(@data);
  my ($attr, $content) = $self->toTeXBody(@spec);

  if ($combiner) {
    my $body = $attr;
    $body .= '\item[' . ($combiner eq 'choice' ? '\textbar=' : '\&=') . '] ' . $content if $content;
    $$self{defined_patterns}{$name} = -1 unless defined $$self{defined_patterns}{$name};
    return "\\patternadd{$name}{$docs}{$body}\n"; }
  else {
    $attr    = '\item[\textit{Attributes:}] \textit{empty}' if !$attr    && ($name =~ /\\_attributes/);
    $content = '\textit{empty}'                             if !$content && ($name =~ /\\_model/);
    my $body = $attr;
    $body .= '\item[\textit{Content}:] ' . $content if $content;
    if (!$attr && $self->toTeX_isContent($$self{defs}{$qname})) {
      my ($xattr, $xcontent) = $self->toTeXBody($$self{defs}{$qname});
      $body .= '\item[\textit{Expansion}:] ' . $xcontent
        if !$xattr && $xcontent && ($xcontent ne $content); }
    if (my $uses = $self->getSymbolUses($qname)) {
      $body .= '\item[\textit{Used by}:] ' . $uses; }
    if ((defined $$self{defined_patterns}{$name}) && ($$self{defined_patterns}{$name} > 0)) { # Already been defined???
      return ''; }
    else {
      $$self{defined_patterns}{$name} = 1;
      return "\\patterndef{$name}{$docs}{$body}\n"; } } }

sub toTeX_element {
  my ($self, $name, @data) = @_;
  my $qname = $name;
  $name =~ s/^ltx://;
  return "" if $SKIP_XHTML && ($name eq 'xhtml:*');
  $name = cleanTeXName($name);
  my ($docs, @spec)    = $self->toTeXExtractDocs(@data);
  my ($attr, $content) = $self->toTeXBody(@spec);
  $content = "\\typename{empty}" unless $content;
  # Shorten display for element-specific attributes & model, ASSUMING they immediately folllow!
  my $body = $attr;
  $body .= '\item[\textit{Content}:] ' . $content if $content;
  if (my $ename = $$self{elementreversedefs}{$qname}) {
    if (my $uses = $self->getSymbolUses($ename)) {
      $body .= '\item[\textit{Used by}:] ' . $uses; } }
  return "\\elementdef{$name}{$docs}{$body}\n"; }

sub toTeX_attribute {
  my ($self, $name, @data) = @_;
  $name = cleanTeXName($name);
  my ($docs, @spec) = $self->toTeXExtractDocs(@data);
  my $content = join(' ', map { $self->toTeX($_) } @spec) || '\typename{text}';
  if ($name =~ /^!(.*)/) {    # Excluded attribute?
    return "\\item[\\textit{Exluding attribute }]\\texttt{$1}"; }
  return "\\attrdef{$name}{$docs}{$content}"; }

sub toTeX_combination {
  my ($self, $name, @data) = @_;
  if ($name eq 'group') {
    return (scalar(@data) == 1 ? $self->toTeX($data[0])
      : "(" . join(', ', map { $self->toTeX($_) } @data) . ")"); }
  elsif ($name eq 'interleave') {
    return "(" . join(' ~\&~ ', map { $self->toTeX($_) } @data) . ")"; }    # ?
  elsif ($name eq 'choice') {
    return "(" . join(' ~\textbar~ ', map { $self->toTeX($_) } @data) . ")"; }
  elsif ($name eq 'optional') {
    if ((@data == 1) && eqOp($data[0], 'attribute')) {
      return $self->toTeX($data[0]); }
    else {
      return $self->toTeX($data[0]) . '\textsuperscript{?}'; } }
  elsif ($name eq 'zeroOrMore') {
    return $self->toTeX($data[0]) . '\textsuperscript{*}'; }
  elsif ($name eq 'oneOrMore') {
    return $self->toTeX($data[0]) . '\textsuperscript{*}'; }
  elsif ($name eq 'list') {
    return "(" . join(', ', map { $self->toTeX($_) } @data) . ")"; }    # ?
  else {
    Warn('unexpected', $name, undef, "RelaxNG->toTeX: Unrecognized combination $name");
    return; } }

sub getSymbolUses {
  my ($self, $qname) = @_;
  if (my $uses = $$self{usesname}{$qname}) {
    my @uses = sort keys %$uses;
    @uses = grep { !/\bSVG./ } @uses if $SKIP_SVG;                                               # !!!
    @uses = map  { (/pattern:[^:]*:(.*?)_(?:attributes|model)$/ ? "element:$1" : $_); } @uses;
    return join(', ',
      (map { /^pattern:[^:]*:(.*)$/ ? ('\patternref{' . cleanTeX($1) . '}')     : () } @uses),
      (map { /^element:(.*)$/       ? ('\elementref{' . cleanTeXName($1) . '}') : () } @uses)); }
  else {
    return ''; } }

# Extract any documentation nodes from @data
sub toTeXExtractDocs {
  my ($self, @data) = @_;



( run in 2.269 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )