# -*- 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;