# -*- CPERL -*-
package LaTeXML::Package::Pool;
use strict;
use LaTeXML::Global;
use LaTeXML::Package;
RequirePackage('keyval');
DefKeyVal('Module','cd','Semiverbatim');
DefKeyVal('Module','id','Semiverbatim');
DefEnvironment('{module} OptionalKeyVals:Module',
"?#excluded()( #body)",
#closed bracket ) seems to work fine now
#commented this out - do we need current_theory?
#plus: keyvals->getValue seems to be undefined?!
#beforeConstruct=> sub {
#my ($doc, $keyvals, %props) = @_;
#my $theory = $keyvals->getValue('id') if $keyvals;
#$theory = ref $theory ? $theory->toString : 'UNDEFINED';
#AssignValue(current_theory => $theory);
#return;},
# $Doc->openElement('omdoc:theory', 'xml:id' => $theory);
# my $uses = $keyvals->getValue('usses');
# $uses = ref $uses ? $uses->toString || '' : '';
# $uses =~ s/\s+//g; $uses=~ s/^\{//; $uses=~ s/\}$//;
# my $module_paths = LookupValue('module_paths') || {};
# foreach my $used(split(',',$uses)) {
# my $file = $module_paths->{$used}; $file .= '.omdoc#' if $file;
# $doc->openElement('omdoc:imports', 'from' => $file.$used);
# $doc->closeElement('omdoc:imports'); }
# $doc->absorb($props{body}) if $props{body};
# $doc->closeElement('omdoc:theory'); }
# return; },
beforeDigest=>\&useTheoryItemizations,
afterDigestBegin=>sub {
my($stomach, $whatsit)=@_;
$whatsit->setProperty(excluded=>LookupValue('excluding_modules'));
my $keys = $whatsit->getArg(1);
my($id, $cd)=$keys
&& map(ToString($keys->getValue($_)),qw(id cd));
$cd = $id unless $cd;
# update the catalog with paths for modules
my $module_paths = LookupValue('module_paths') || {};
$module_paths->{$id} = LookupValue('last_module_path');
AssignValue('module_paths', $module_paths, 'global');
#Update the current module position
AssignValue(current_module => $id);
AssignValue(module_cd => $cd) if $cd;
# my @uses = ();
# if($uses){
# $uses =~ s/\s//g; $uses=~ s/^\{//; $uses=~ s/\}$//;
# @uses = split(',',$uses); }
############### AssignValue("module_${id}_uses" => [@uses], 'global');
#Idea: introdcue global list of used modules and activateScope on it once at the
# main block.
#use_module($id); #22.02.08 need to ALWAYS invoke this to make things global
#activate the module in our current scope
$STATE->activateScope("module:".$id); #changed from use_module as only needs to take care of current module
return; });
sub use_module {
my($module)=@_;
$module = ToString($module);
# Depth-first load definitions from used modules
foreach my $used_module (@{ LookupValue("module_${module}_uses") || []}){
use_module($used_module); }
# then load definitions for this module
$STATE->activateScope("module:$module"); }
DefConstructor('\importmodule[]{}',"",
afterDigest=>sub {
my($stomach,$whatsit)=@_;
my $file = $whatsit->getArg(1);
my $module = $whatsit->getArg(2);
$module = ToString($module);
#if filepath is not supply simply look for the $module.sms file
if (!$file) {$file=ToString($module)};
my $containing_module = LookupValue('current_module');
#set the relation between the current module and the one to be imported
PushValue("module_".$containing_module."_uses"=>$module);
#check if we've already loaded this module
if(LookupValue('module_'.$module.'_loaded')) {use_module($module);} #if so activate it!
else {
#if not:
my $gullet = $stomach->getGullet;
#1) mark as loaded
AssignValue('module_'.$module.'_loaded' => 1, 'global');
#open a group for its definitions so that they are localized
$stomach->bgroup;
#update the last module path
AssignValue('last_module_path', $file);
#queue the closing tag for this module in the gullet where it will be executed
#after all other definitions of the imported module have been taken care of
$gullet->unread(Invocation(T_CS('\end@requiredmodule'), T_OTHER($module))->unlist);
#we only need to load the sms definitions without generating any xml output, so we set the flag to 1
AssignValue('excluding_modules' => 1);
#queue this module's sms file in the gullet so that its definitions are imported
$gullet->input($file,['sms']);
}
return;});
DefKeyVal('symdef','aliases','Semiverbatim');
DefKeyVal('symdef','local','Semiverbatim','true');
DefKeyVal('symdef','cmml','Semiverbatim','true');
DefKeyVal('symdef','cattrs','Semiverbatim','true');
DefKeyVal('symdef','definitionURL','Semiverbatim','true');
DefMacro('\symdef OptionalKeyVals:symdef {}[][]{}',
sub {
my($self,@args)=@_;
# print STDERR "excluding" if LookupValue('excluding_modules');
((Invocation(T_CS('\@symdef'),@args)->unlist),
(LookupValue('excluding_modules') ? ()
: (Invocation(T_CS('\@symdef@pres'), @args)->unlist)));
});
DefPrimitive('\@symdef OptionalKeyVals:symdef {}[][]{}', sub {
my($stomach,$keys,$cs,$nargs,$opt,$presentation)=@_;
my($name,$cd,$role,$cmml,$cattrs,$definitionURL)=$keys
&& map($_ && $_->toString,map($keys->getValue($_), qw(name cd role cmml cattrs definitionURL)));
$cd = LookupValue('module_cd') unless $cd;
$nargs = (ref $nargs ? $nargs->toString : $nargs || 0);
my $module = LookupValue('current_module');
# print STDERR "Define ".Stringify($cs)." in $module\n";
my $scope = (($keys && ($keys->getValue('local') || '' eq 'true')) ? 'module_local' : 'module').":".$module;
my $attr="name='#name' meaning='#meaning' omcd='#omcd'";
DefConstructorI("\\".$cs->toString,convertLaTeXArgs($nargs,$opt),
($nargs == 0
? ""
: ""
. ""
. join('',map("#$_", (1..$nargs)))
.""),
properties => {name=>$name, meaning=>$cs->toString,omcd=>$cd,role => $role},
scope=>$scope);
return; });
DefPrimitive('\abbrdef OptionalKeyVals:symdef {}[][]{}', sub {
my($stomach,$keys,$cs,$nargs,$opt,$presentation)=@_;
my $module = LookupValue('current_module');
my $scope = (($keys && ($keys->getValue('local') || '' eq 'true')) ? 'module_local' : 'module').":$module";
DefMacroI("\\".$cs->toString,convertLaTeXArgs($nargs,$opt),$presentation,
scope=>$scope);
return; });
DefPrimitive('\requiremodules{}', sub {
my($stomach,$module)=@_;
my $GULLET = $stomach->getGullet;
$module = Digest($module)->toString;
if(LookupValue('module_'.$module.'_loaded')) {}
else {
AssignValue('module_'.$module.'_loaded' => 1, 'global');
$stomach->bgroup;
AssignValue('last_module_path', $module);
$GULLET->unread(T_CS('\end@requiredmodule'));
AssignValue('excluding_modules' => 1);
$GULLET->input($module,['sms']);
}
return;});
DefPrimitive('\end@requiredmodule{}',sub {
#close the group
$_[0]->egroup;
#print STDERR "END: ".ToString(Digest($_[1])->toString);
#Take care of any imported elements in this current module by activating it and all its dependencies
#print STDERR "Important: ".ToString(Digest($_[1])->toString)."\n";
use_module(ToString(Digest($_[1])->toString));
return; });
DefPrimitive('\sinput{}', sub {
my($stomach,$module)=@_;
my $GULLET = $stomach->getGullet;
$module = Digest($module)->toString;
AssignValue('module_'.$module.'_loaded' => 1, 'global');
$stomach->bgroup;
AssignValue('last_module_path', $module);
$GULLET->unread(Invocation(T_CS('\end@requiredmodule'),T_OTHER($module))->unlist);
$GULLET->input($module,['tex']);
return;});
DefMacro('\@symdef@pres OptionalKeyVals:symdef {}[][]{}', sub {
my($self,$keys, $cs,$nargs,$opt,$presentation)=@_;
Invocation(T_CS('\@symdef@pres@aux'),
$cs,
($nargs || Tokens(T_OTHER(0))),
symdef_presentation_pmml($cs,ToString($nargs)||0,$presentation),
symdef_presentation_TeX($presentation),
$keys)->unlist; });
sub symdef_presentation_pmml {
my($cs,$nargs,$presentation)=@_;
my @toks = $presentation->unlist;
while(@toks && $toks[0]->equals(T_SPACE)){ pop(@toks); } # Remove leading space
$presentation = Tokens(@toks);
# Wrap with \@use, unless already has a recognized formatter.
$presentation = Invocation(T_CS('\@use'),$presentation) # Using simple text for now, until getting a proper \@use
unless @toks && ($toks[0]->toString =~ /^\\(infix|prefix|postfix|assoc|use|mixfixi|mixfixa|mixfixii|mixfixia|mixfixai|mixfixiii)$/);
# Low level substitution.
my @args = map(Invocation(T_CS('\@SYMBOL'),T_OTHER("pres_arg:".($_+1))),1..$nargs);
$presentation = Tokens(LaTeXML::Expandable::substituteTokens($presentation,@args));
$presentation; }
DefConstructor('\@use {}',
""
. ""
.""
.""
. "#1"
."",
mode=>'inline_math');
sub get_cd {
my($name,$cd,$role,$cmml,$cattrs,$definitionURL)=@_;
return $cd;}
DefConstructor('\@symdef@pres@aux{}{}{}{} OptionalKeyVals:symdef',
""
.""
."#3"
."",
afterDigest=>sub { my ($stomach, $whatsit) = @_;
my $keys = $whatsit->getArg(5);
my $module = LookupValue('current_module');
$whatsit->setProperties(for=>ToString($whatsit->getArg(1)));
$whatsit->setProperty(role=>($keys ? $keys->getValue('role')
: (ToString($whatsit->getArg(2)) ? 'applied'
: undef))); });
sub symdef_presentation_TeX {
my($presentation)=@_;
my @tokens = $presentation->unlist;
my(@frag,@frags) = ();
while(my $tok = shift(@tokens)){
if($tok->equals(T_PARAM)){
push(@frags,Invocation(T_CS('\@symdef@pres@text'),Tokens(@frag))) if @frag;
@frag=();
my $n = shift(@tokens)->getString;
push(@frags,Invocation(T_CS('\@symdef@pres@arg'),T_OTHER($n+1))); }
else {
push(@frag,T_OTHER($tok->getString)); }} # IMPORTANT! Neutralize the tokens!
push(@frags,Invocation(T_CS('\@symdef@pres@text'),Tokens(@frag))) if @frag;
Tokens(map($_->unlist,@frags)); }
DefConstructor('\@symdef@pres@arg{}', "",
afterDigest=>sub { my ($stomach, $whatsit) = @_;
my $select = $whatsit->getArg(1);
$select = ref $select ? $select->toString : '';
$whatsit->setProperty(select=>"*[".$select."]"); });
DefConstructor('\@symdef@pres@text{}', "#1");
DefConstructor('\requirepackage{} Semiverbatim',"",
afterDigest=>sub { my ($stomach, $whatsit) = @_;
my $select = $whatsit->getArg(1);
RequirePackage($select->toString); });
1;