diff options
45 files changed, 3095 insertions, 1615 deletions
diff --git a/doc/context/documents/general/manuals/cld-mkiv.pdf b/doc/context/documents/general/manuals/cld-mkiv.pdf Binary files differindex bac02979f..63f1c36dc 100644 --- a/doc/context/documents/general/manuals/cld-mkiv.pdf +++ b/doc/context/documents/general/manuals/cld-mkiv.pdf diff --git a/doc/context/documents/general/manuals/luametatex.pdf b/doc/context/documents/general/manuals/luametatex.pdf Binary files differindex bd3333189..9c9f1c5bd 100644 --- a/doc/context/documents/general/manuals/luametatex.pdf +++ b/doc/context/documents/general/manuals/luametatex.pdf diff --git a/doc/context/sources/general/manuals/cld/cld-introduction.tex b/doc/context/sources/general/manuals/cld/cld-introduction.tex index 82fcb8007..a1a74cde4 100644 --- a/doc/context/sources/general/manuals/cld/cld-introduction.tex +++ b/doc/context/sources/general/manuals/cld/cld-introduction.tex @@ -26,6 +26,67 @@ that is available at the \TEX\ end, or you can use \LUA\ code to do the work, or you can use a combination. So, from now on, in \CONTEXT\ you can code your style and document source in (a mixture of) \TEX, \XML, \METAPOST\ and in \LUA. +% \CONTEXT\ being a \TEX\ macro package quite some action happens at the \TEX\ end; +% although we do a lot in \LUA, there is no need to abandon the macro language. If +% I wanted a typesetting system written in procedural language I'd already come up +% with one but I have no need for it and \TEX\ is more fun anyway. But the fact +% that we mix these conceptual different languages means that we need ways to +% communicate between them. The possibilities to communicate and switch between +% \TEX, \LUA, and of course \METAPOST\ have evolved over time. It started with just +% \type {\directlua} but we now can use tokens scanners that permit nice +% interfaces. So, as a consequence the interfaces in \CONTEXT\ also evolved, +% although mostly deep down out of sight of users: \CONTEXT\ always tries to offer +% abstract interfaces that as designed in a way that permits upward compatible +% upgrades. + +% Going from \LUA\ to \TEX\ is mostly done with the \type {context} command. The +% most low level approach would be to use the \type {tex.print} functions but using +% the \type {context} interface is often better. Going from \TEX\ to \LUA\ is done +% with \type {\ctxlua} and friends, btu again, you can decide to go low level with +% \type {\directlua}. Indeed, there is no need to use these interfaces and quite +% often we see users use low level calls in combination with macros that pass +% arguments and there's nothing wrong with that. We see no reason to block or +% overload them. + +% In these internet times it is no problem to find comments on code and coding +% practices (of course not seldom by people who themselves produce code that +% deserves a lot of comment but get away with it). The same is true for complaints +% about bugs that not always are put in the perspective of the total amount of well +% working code or experiments; on the average \TEX\ systems behave quite well and +% have not that many bugs, but some low level features they can be confusing. We +% don't impose a coding style in user files but we do so in the core, but that only +% hampers ourselves. + +% Another issue is complaints about manuals or lack of documentation, again, often +% by people who themselves never produced something that those who they complain +% about can use, but, that said, lack of documentation has the benefit that one can +% learn by playing around. There are plenty of examples to learn from, also in the +% over ten thousand pages of \CONTEXT\ documentation and articles. And of course +% there is the test suite which has examples. Some users even like to look into the +% source code to learn some tricks. Now, the internet is not always the friendly +% and tolerant environment that its marketing suggests and one can run into +% patronizing comments on how to do thing, but: we don't (and cannot) enforce best +% practices. + +% However, when you define \LUA\ functions you should {\em not} overload existing +% functions without knowing what you deal with, simply because the whole \CONTEXT\ +% ecosystem could be affected. Don't expect support when you do so. The same is +% true for \TEX\ macros and even more so for primitives. Although there is some +% protection going on we think the system should be as open as possible, so little +% is hidden for the user. \footnote {In the core code and modules that come with +% \CONTEXT\ we are rather rigourous. There we have patterns that need to be +% followed. Hacking around and patching at will is not an option there. In the +% rather open system that a macro package provides it is no problem to quickly mess +% up the lot with bad code.} + +% The reason for mentioning this is that we do see users come up with (often +% surprising) solutions and we invite them to keep playing around, even with low +% level code. When writing a document, playing around can be a nice distraction. +% But, using a high level interface has some benefits too. It gives a bit of +% protection against bad interactions with other code. It also often involves less +% coding. Performance might be better although that is not always a real issue as +% there are plenty of ways to make a \TEX\ system slow anyway. + In the following chapters I will introduce typesetting in \LUA, but as we rely on \CONTEXT\ it is unavoidable that some regular \CONTEXT\ code shows up. The fact that you can ignore backslashes does not mean that you can do without knowledge diff --git a/doc/context/sources/general/manuals/cld/cld-luafunctions.tex b/doc/context/sources/general/manuals/cld/cld-luafunctions.tex index b2760e05b..c48b852fb 100644 --- a/doc/context/sources/general/manuals/cld/cld-luafunctions.tex +++ b/doc/context/sources/general/manuals/cld/cld-luafunctions.tex @@ -2306,20 +2306,22 @@ one provided by \LUATEX\ as it is more precise: os.gettimeofday() \stoptyping -There is also a more extensive variant: - -\starttyping -os.times() -\stoptyping - -This one is platform dependent and returns a table with \type {utime} (use time), -\type {stime} (system time), \type {cutime} (children user time), and \type -{cstime} (children system time). +% % This one is gone in luametatex: +% +% There is also a more extensive variant: +% +% \starttyping +% os.times() +% \stoptyping +% +% This one is platform dependent and returns a table with \type {utime} (use time), +% \type {stime} (system time), \type {cutime} (children user time), and \type +% {cstime} (children system time). \stopsummary \ShowLuaExampleThree {os} {gettimeofday} {} -\ShowLuaExampleTwo {os} {times} {} +%ShowLuaExampleTwo {os} {times} {} \startsummary[title={runtime}] diff --git a/doc/context/sources/general/manuals/cld/cld-macros.tex b/doc/context/sources/general/manuals/cld/cld-macros.tex index a177db9f8..7b6f578e7 100644 --- a/doc/context/sources/general/manuals/cld/cld-macros.tex +++ b/doc/context/sources/general/manuals/cld/cld-macros.tex @@ -128,9 +128,9 @@ local function startmore(opt_1) context.startnarrower() end -local function stopmore(opt_1) +local function stopmore() context.stopnarrower() - context("stop more, options: %s",interfaces.tolist(opt_1)) + context("stop more") context.stopnarrower() end @@ -175,7 +175,7 @@ If needed you can access the body of a macro. Take for instance: \typebuffer \getbuffer -The following example demonsttaies how we can look inside these macros. You need +The following example demonstrates how we can look inside these macros. You need to be aware of the fact that the whole blob of \LUA\ codes is finished before we return to \TEX, so when we pipe the meaning of \type {TestB} back to \TEX\ it only gets expanded afterwards. We can use a function to get back to \LUA. It's diff --git a/doc/context/sources/general/manuals/cld/cld-mkiv.tex b/doc/context/sources/general/manuals/cld/cld-mkiv.tex index 5c35fa4e7..9267732fa 100644 --- a/doc/context/sources/general/manuals/cld/cld-mkiv.tex +++ b/doc/context/sources/general/manuals/cld/cld-mkiv.tex @@ -74,6 +74,8 @@ \component cld-logging \component cld-luafunctions \component cld-ctxfunctions + \component cld-scanners + \component cld-variables \component cld-callbacks \component cld-backendcode \component cld-goodies @@ -84,8 +86,8 @@ \component cld-files \stopbodymatter -% \startbackmatter -% \component cld-index -% \stopbackmatter +\startbackmatter + \component cld-index +\stopbackmatter \stopproduct diff --git a/doc/context/sources/general/manuals/cld/cld-scanners.tex b/doc/context/sources/general/manuals/cld/cld-scanners.tex new file mode 100644 index 000000000..e0dfc30b0 --- /dev/null +++ b/doc/context/sources/general/manuals/cld/cld-scanners.tex @@ -0,0 +1,1046 @@ +% language=uk + +\startcomponent cld-ctxscanners + +\environment cld-environment + +\startchapter[title={Scanners}] + +\startsection[title={Introduction}] + +\index {implementors} +\index {scanners} + +Here we discuss methods to define macros that directly interface with the \LUA\ +side. It involves all kind of scanners. There are actually more than we discuss +here but some are meant for low level usage. What is describe here has been used +for ages and works quite well. + +{\em We don't discuss some of the more obscure options here. Some are there just +because we need them as part of bootstrapping or initializing code and are of no +real use to users.} + +\stopsection + +\startsection[title={A teaser first}] + +Most of this chapter is examples and you learn \TEX\ (and \LUA) best by just +playing around. The nice thing about \TEX\ is that it's all about visual output, +so that's why in the next examples we just typeset some of what we just scanned. +Of course in practice the \type {actions} will be more complex. + +\unexpanded\def\showmeaning#1% + {\begingroup + \dontleavehmode + \ttbf\string #1\space + \tttf\meaning#1% + \endgroup} + +\startbuffer[definition] +\startluacode + interfaces.implement { + name = "MyMacroA", + public = true, + arguments = "string", + actions = function(s) + context("(%s)",s) + end, + } +\stopluacode +\stopbuffer + +\startbuffer[usage] +\MyMacroA{123} +\MyMacroA{abc} +\edef\temp{\MyMacroA{abc}} +\stopbuffer + +\typebuffer[definition] \getbuffer[definition] + +By default a macro gets defined in the \type {\clf_} namespace but the \type +{public} option makes it visible. This default indicates that it is actually a +low level mechanism in origin. More often than not these interfaces are used like +this: + +\starttyping +\def\MyMacro#1{... \clf_MyMacroA{#1} ...} +\stoptyping + +When we look at the meaning of \type {\MyMacroA} we get: + +\blank \showmeaning\MyMacroA \blank + +And when we apply this macro as: + +\typebuffer[usage] + +We get + +\blank \getbuffer[usage] \blank + +The meaning of \type {\temp} is: + +\blank \showmeaning\temp \blank + +We can also define the macro to be protected (\type {\unexpanded}) in \CONTEXT\ +speak). We can overload existing scanners but unless we specify the \type +{overload} option, we get a warning on the console. + +\startbuffer[definition] +\startluacode + interfaces.implement { + name = "MyMacroA", + public = true, +-- overload = true, + protected = true, + arguments = "string", + actions = function(s) + context("[%s]",s) + end, + } +\stopluacode +\stopbuffer + +\typebuffer[definition] \getbuffer[definition] + +This time we get: + +\getbuffer[usage] + +The meaning of \type {\temp} is: + +\blank \showmeaning\temp \blank + +\stopsection + +\startsection[title={Basic data types}] + +\index {implementors+arguments} + +It is actually possible to write very advanced scanners but unless you're in for +obscurity the limited subset discussed here is normally enough. The \CONTEXT\ +user interface is rather predictable, unless you want to show off with weird +additional interfaces, for instance by using delimiters other than curly braces +and brackets, or by using separators other than commas. + +\startbuffer[definition] +\startluacode + interfaces.implement { + name = "MyMacroB", + public = true, + arguments = { "string", "integer", "boolean", "dimen" }, + actions = function(s,i,b,d) + context("<%s> <%i> <%l> <%p>",s,i,b,d) + end, + } +\stopluacode +\stopbuffer + +\typebuffer[definition] \getbuffer[definition] + +This time we grab four arguments, each of a different type: + +\startbuffer[usage] +\MyMacroB{foo} 123 true 45.67pt + +\def\temp {oof} +\scratchcounter 321 +\scratchdimen 76.54pt + +\MyMacroB\temp \scratchcounter false \scratchdimen +\stopbuffer + +\typebuffer[usage] + +The above usage gives: + +\getbuffer[usage] + +As you can see, registers can be used as well, and the \type {\temp} macro is +also accepted as argument. The integer and dimen arguments scan standard \TEX\ +values. If you want a \LUA\ number you can specify that as well. As our first +example showed, when there is one argument you don't need an array to specify +it. + +\startbuffer[definition] +\startluacode + interfaces.implement { + name = "MyMacroC", + public = true, + arguments = "number", + actions = function(f) + context("<%.2f>",f) + end, + } +\stopluacode +\stopbuffer + +\typebuffer[definition] \getbuffer[definition] + +\startbuffer[usage] +\MyMacroC 1.23 +\MyMacroC 1.23E4 +\MyMacroC -1.23E4 +\MyMacroC 0x1234 +\stopbuffer + +As you can see, hexadecimal numbers are also accepted: + +\typebuffer[usage] + +The above usage gives: + +\getbuffer[usage] + +\stopsection + +\startsection[title={Tables}] + +\index {implementors+tables} + +A list can be grabbed too. The individual items are separated by spaces and +items can be bound by braces. + +\startbuffer[definition] +\startluacode + interfaces.implement { + name = "MyMacroD", + public = true, + arguments = "list", + actions = function(t) + context("< % + t >",t) + end, + } +\stopluacode +\stopbuffer + +\typebuffer[definition] \getbuffer[definition] + +\startbuffer[usage] +\MyMacroD { 1 2 3 4 {5 6} } +\stopbuffer + +The macro call: + +\typebuffer[usage] + +results in: + +\getbuffer[usage] + +Often in \LUA\ scripts tables are uses all over the place. Picking up a table is +also supported by the implementer. + +\startbuffer[definition] +\startluacode + interfaces.implement { + name = "MyMacroE", + public = true, + arguments = { + { + { "bar", "integer" }, + { "foo", "dimen" }, + } + }, + actions = function(t) + context("<foo : %p> <bar : %i>",t.foo,t.bar) + end, + } +\stopluacode +\stopbuffer + +\typebuffer[definition] \getbuffer[definition] + +\startbuffer[usage] +\MyMacroE { + foo 12pt + bar 34 +} +\stopbuffer + +Watch out, we don't use equal signs and commas here: + +\typebuffer[usage] + +We get: + +\getbuffer[usage] + +All the above can be combined: + +\startbuffer[definition] +\startluacode + interfaces.implement { + name = "MyMacroF", + public = true, + arguments = { + "string", + { + { "bar", "integer" }, + { "foo", "dimen" }, + }, + { + { "one", "string" }, + { "two", "string" }, + }, + }, + actions = function(s,t1,t2) + context("<%s> <%p> <%i> <%s> <%s>",s,t1.foo,t1.bar,t2.one,t2.two) + end, + } +\stopluacode +\stopbuffer + +\typebuffer[definition] \getbuffer[definition] + +\startbuffer[usage] +\MyMacroF + {oeps} + { foo 12pt bar 34 } + { one {x} two {y} } +\stopbuffer + +The following call: + +\typebuffer[usage] + +Results in one string and two table arguments. + +\getbuffer[usage] + +You can nest tables, as in: + +\startbuffer[definition] +\startluacode + interfaces.implement { + name = "MyMacroG", + public = true, + arguments = { + "string", + "string", + { + { "data", "string" }, + { "tab", "string" }, + { "method", "string" }, + { "foo", { + { "method", "integer" }, + { "compact", "number" }, + { "nature" }, + { "*" }, -- any key + } }, + { "compact", "string", "tonumber" }, + { "nature", "boolean" }, + { "escape" }, + }, + "boolean", + }, + actions = function(s1, s2, t, b) + context("<%s> <%s>",s1,s2) + context("<%s> <%s> <%s>",t.data,t.tab,t.compact) + context("<%i> <%s> <%s>",t.foo.method,t.foo.nature,t.foo.whatever) + context("<%l>",b) + end, + } +\stopluacode +\stopbuffer + +\typebuffer[definition] \getbuffer[definition] + +\startbuffer[usage] +\MyMacroG + {s1} + {s2} + { + data {d} + tab {t} + compact {12.34} + foo { method 1 nature {n} whatever {w} } + } + true +\relax +\stopbuffer + +Although the \type {\relax} is not really needed in the next calls, I often use +it to indicate that we're done: + +\typebuffer[usage] + +This typesets: + +\getbuffer[usage] + +\stopsection + +\startsection[title=Expansion] + +\index {implementors+expansion} + +When working with scanners it is important to realize that we have to do with an +expansion engine. When \TEX\ picks up a token, it can be done as-is, that is the +raw token, but it can also expand that token first (which can be recursive) and +then pick up the first token that results from that. Sometimes you want that +expansion, for instance when you pick up keywords, sometimes you don't. + +Expansion effects are most noticeable when we pickup a \quote {string} kind of +value. In the implementor we have two methods for that: \type {string} and \type +{argument}. The argument method has an expandable form (the default) and one +that doesn't expand. Take this: + +\startbuffer[definition] +\startluacode + interfaces.implement { + name = "MyMacroH", + public = true, + arguments = { + "string", + "argument", + "argumentasis", + }, + actions = function(a,b,c) + context.type(a or "-") context.quad() + context.type(b or "-") context.quad() + context.type(c or "-") context.crlf() + end, + } +\stopluacode +\stopbuffer + +\typebuffer[definition] \getbuffer[definition] + +Now take this input: + +\startbuffer[usage] +\def\a{A} \def\b{B} \def\c{C} +\MyMacroH{a}{b}{c} +\MyMacroH{a\a}{b\b}{c\c} +\MyMacroH\a\b\c\relax +\MyMacroH\a xx\relax +\stopbuffer + +\typebuffer[usage] + +We we use the string method we need a \type {\relax} (or some spacer) to end +scanning of the string when we don't use curly braces. The last line is +actually kind of tricky because the macro expects two arguments after +scanning the first string. + +\blank {\getbuffer[usage]} \blank + +\startbuffer[definition] +\startluacode + interfaces.implement { + name = "MyMacroI", + public = true, + arguments = { + "argument", + "argumentasis", + }, + actions = function(a,b,c) + context.type(a or "-") context.quad() + context.type(b or "-") context.quad() + context.type(c or "-") context.crlf() + end, + } +\stopluacode +\stopbuffer + +Here is a variant: + +\typebuffer[definition] \getbuffer[definition] + +\startbuffer[usage] +\def\a{A} \def\b{B} +\MyMacroI{a}{b} +\MyMacroI{a\a}{b\b} +\MyMacroI\a\b\relax +\stopbuffer + +With: + +\typebuffer[usage] + +we get: + +\blank {\getbuffer[usage]} \blank + +\stopsection + +\startsection[title=Boxes] + +\index {implementors+boxes} + +You can pick up a box too. The value returned is a list node: + +\startbuffer[definition] +\startluacode + interfaces.implement { + name = "MyMacroJ", + public = true, + arguments = "box", + actions = function(b) + context(b) + end, + } +\stopluacode +\stopbuffer + +\typebuffer[definition] \getbuffer[definition] + +The usual box specifiers are supported: + +\startbuffer[usage] +\MyMacroJ \hbox {\strut Test 1} +\MyMacroJ \hbox to 4cm {\strut Test 2} +\stopbuffer + +So, with: + +\typebuffer[usage] + +we get: + +\blank {\forgetall\dontcomplain\getbuffer[usage]} \blank + +There are three variants that don't need the box operator \type {hbox}, \type +{vbox} and \type {vtop}: + +\startbuffer[definition] +\startluacode + interfaces.implement { + name = "MyMacroL", + public = true, + arguments = { + "hbox", + "vbox", + }, + actions = function(h,v) + context(h) + context(v) + end, + } +\stopluacode +\stopbuffer + +\typebuffer[definition] \getbuffer[definition] + +Again, the usual box specifiers are supported: + +\startbuffer[usage] +\MyMacroL {\strut Test 1h} to 10mm {\vfill Test 1v\vfill} +\MyMacroL spread 1cm {\strut Test 2h} to 15mm {\vfill Test 2v\vfill} +\stopbuffer + +This: + +\typebuffer[usage] + +gives: + +\blank {\forgetall\dontcomplain\showboxes \getbuffer[usage]} \blank + +\stopsection + +\startsection[title=Like \CONTEXT] + +\index {implementors+hashes} +\index {implementors+arrays} + +The previously discussed scanners don't use equal signs and commas as separators, +but you can enforce that regime in the following way: + + +\startbuffer[definition] +\startluacode + interfaces.implement { + name = "MyMacroN", + public = true, + arguments = { + "hash", + "array", + }, + actions = function(h, a) + context.totable(h) + context.quad() + context.totable(a) + end, + } +\stopluacode +\stopbuffer + +\typebuffer[definition] \getbuffer[definition] + +\startbuffer[usage] +\MyMacroN + [ a = 1, b = 2 ] + [ 3, 4, 5, {6 7} ] +\stopbuffer + +This: + +\typebuffer[usage] + +gives: + +\blank {\getbuffer[usage]} \blank + +\stopsection + +\startsection[title=Verbatim] + +\index {implementors+verbatim} + +There are a couple of rarely used scanners (there are more of course but these +are pretty low level and not really used directly using implementors). + +\startbuffer[definition] +\startluacode + interfaces.implement { + name = "MyMacroO", + public = true, + arguments = "verbatim", + actions = function(v) + context.type(v) + end, + } +\stopluacode +\stopbuffer + +\typebuffer[definition] \getbuffer[definition] + +\startbuffer[usage] +\MyMacroO{this is \something verbatim} +\stopbuffer + +There is no expansion applied in: + +\typebuffer[usage] + +so we get what we input: + +\blank {\getbuffer[usage]} \blank + +\stopsection + +\startsection[title=Macros] + +\index {implementors+macros} + +We can pick up a control sequence without bothering what it actually +represents: + +\startbuffer[definition] +\startluacode + interfaces.implement { + name = "MyMacroP", + public = true, + arguments = "csname", + actions = function(c) + context("{\\ttbf name:} {\\tttf %s}",c) + end, + } +\stopluacode +\stopbuffer + +\typebuffer[definition] \getbuffer[definition] + +\startbuffer[usage] +\MyMacroP\framed +\stopbuffer + +The next control sequence is picked up and its name without the leading +escape character is returned: + +\typebuffer[usage] + +So here we get: + +\blank {\getbuffer[usage]} \blank + +\stopsection + +\startsection[title={Token lists}] + +\index {implementors+token lists} + +If you have no clue what tokens are in the perspective of \TEX, you can skip this +section. We can grab a token list in two ways. The most \LUA ish way is to grab +it as a table: + +\startbuffer[definition] +\startluacode + interfaces.implement { + name = "MyMacroQ", + public = true, + arguments = "toks", + actions = function(t) + context("%S : ",t) + context.sprint(t) + context.crlf() + end, + } +\stopluacode +\stopbuffer + +\typebuffer[definition] \getbuffer[definition] + +\startbuffer[usage] +\MyMacroQ{this is a {\bf token} list} +\MyMacroQ{this is a \inframed{token} list} +\stopbuffer + +\typebuffer[usage] + +The above sample code gives us: + +\blank {\getbuffer[usage]} \blank + +An alternative is to keep the list a user data object: + +\startbuffer[definition] +\startluacode + interfaces.implement { + name = "MyMacroR", + public = true, + arguments = "tokenlist", + actions = function(t) + context("%S : ",t) + context.sprint(t) + context.crlf() + end, + } +\stopluacode +\stopbuffer + +\typebuffer[definition] \getbuffer[definition] + +\startbuffer[usage] +\MyMacroR{this is a {\bf token} list} +\MyMacroR{this is a \inframed{token} list} +\stopbuffer + +\typebuffer[usage] + +Now we get: + +\blank {\getbuffer[usage]} \blank + +\stopsection + +\startsection[title={Actions}] + +\index {implementors+actions} + +The plural \type {actions} suggests that there can be more than one and indeed +that is the case. The next example shows a sequence of actions that are applied. +The first one gets the arguments passes. + +\startbuffer[definition] +\startluacode + interfaces.implement { + name = "MyMacroS", + public = true, + arguments = "string", + actions = { characters.upper, context }, + } +\stopluacode +\stopbuffer + +\typebuffer[definition] \getbuffer[definition] + +\startbuffer[usage] +\MyMacroS{uppercase} +\stopbuffer + +\typebuffer[usage] + +Gives: \inlinebuffer[usage] + +You can pass default arguments too. That way you can have multiple macros using +the same action. Here's how to do that: + +\startbuffer[definition] +\startluacode + local function MyMacro(a,b,sign) + if sign then + context("$%i + %i = %i$",a,b,a+b) + else + context("$%i - %i = %i$",a,b,a-b) + end + end + + interfaces.implement { + name = "MyMacroPlus", + public = true, + arguments = { "integer", "integer", true }, + actions = MyMacro, + } + + interfaces.implement { + name = "MyMacroMinus", + public = true, + arguments = { "integer", "integer", false }, + actions = MyMacro, + } +\stopluacode +\stopbuffer + +\typebuffer[definition] \getbuffer[definition] + +So, + +\startbuffer[usage] +\MyMacroPlus 654 321 \crlf +\MyMacroMinus 654 321 \crlf +\stopbuffer + +\typebuffer[usage] + +Gives: + +\getbuffer[usage] + + +\stopsection + +\startsection[title={Embedded \LUA\ code}] + +When you mix \TEX\ and \LUA, you can put the \LUA\ code in a \TEX\ file, for +instance a style. In the previous sections we used this approach: + +\starttyping +\startluacode + -- lua code +\stopluacode +\stoptyping + +This method is both reliable and efficient but you need to keep into mind that +macros get expanded. In the next code, the second line will give an error when +you have not defined \type {\foo} as expandable macro. When it is unexpandable it +will get passed as it is and \LUA\ will see a \type {\f} as an escaped character. +So, when you want a macro be passes as macro, you need to do it as in the third +line. The fact that there is a comment trigger (\type {--}) doesn't help here. + +\starttyping +\startluacode + context("foo") + -- context("\foo") + context("\\bar") +\stopluacode +\stoptyping + +When you use \type {\ctxlua} the same is true but there you also need to keep an +eye on special characters. For instance a percent sign is then interpreted in the +\TEX\ way and because all becomes one line, a \type {--} somewhere in the middle +will make the rest of the line comment: + +\starttyping +\ctxlua { + context("foo") + % context("\foo") + -- context("\\bar") +} +\stoptyping + +Here, the second line goes away (\TEX\ comment) and the third line obscures all +that follows. You can use \type {\letterpercent} to smuggle a percent sign in a +\type {\ctxlua} call. Special characters like a hash symbol also need to be +passed by name. Normally curly braces are no problem because \LUA\ also likes +them properly nested. + +When things become too messy and complex you can always put the code in an +external file and load that one (e.g. with \type {require}. + +In the examples in this chapter we put the function in the table, but for long +ones you might want to do this: + +\starttyping +\startluacode + local function MyMacro(s) + -- lots of code + end + + interfaces.implement { + name = "MyMacro", + public = true, + arguments = "string", + actions = MyMacro, + } +\stopluacode +\stoptyping + +It is a common mistake not to define variables and functions as local. If you +define them global for sure there will become a time when this bites you. + +\stopsection + +\stopchapter + +\stopcomponent + +% conditional : true|false|0=true|!0=false : too weird for users +% bracketed : maybe, but first I need a use case +% bracketedasis : maybe, but first I need a use case +% optional : maybe, but first I need a use case + +\startluacode + + local function Grabbed(t) + context(t) + end + + interfaces.implement { + name = "GrabC", + public = true, + actions = Grabbed, + arguments = "bracketed", + } + interfaces.implement { + name = "GrabD", + public = true, + actions = Grabbed, + arguments = "bracketedasis", + } + interfaces.implement { + name = "GrabE", + public = true, + actions = Grabbed, + arguments = "optional", + } +\stopluacode + +\GrabC [foo {\red okay C} bar] \par +\GrabC \par +\GrabD [foo {\red okay D} bar] \par +\GrabE [foo {\red okay E} bar] \par +\GrabE \par + +% once stable: + +\startluacode + local random = math.random + local randomseed = math.randomseed + + local scan_word = tokens.scanners.word + local scan_integer = tokens.scanners.integer + local scan_dimen = tokens.scanners.dimen + local scan_number = tokens.scanners.float + + local scan_integer = tokens.scanners.luainteger + local scan_cardinal = tokens.scanners.luacardinal + local scan_number = tokens.scanners.luanumber + + local I = 0 + local D = 0 + local F = 0 + + interfaces.implement { + name = "TestInteger", + public = true, + actions = function(b) if b then return I else I = scan_integer() end end, + valuetype = "count", + } + + interfaces.implement { + name = "TestDimension", + public = true, + actions = function(b) if b then return D else D = scan_dimen() end end, + valuetype = "dimen", + } + + interfaces.implement { + name = "TestFloat", + public = true, + actions = function(b) + if b then + context("%q",F) + else + F = scan_number() + end + end, + valuetype = "none", + } + + interfaces.implement { + name = "TestThis", + public = true, + actions = function(b) + if b then + return random(scan_integer(),scan_integer()) + else + randomseed(scan_integer(true)) + end + end, + valuetype = "count", + } + +\stopluacode + +{\tttf [set:\TestInteger 808714][get: \the\TestInteger ]}\par % [get: \number\TestInteger ]}\par +{\tttf [set:\TestDimension 12.34pt][get: \the\TestDimension]}\par % [get: \number\TestDimension]}\par +{\tttf [set:\TestFloat 12.34567890e99][get: \the\TestFloat ]}\par % [get: \number\TestFloat ]}\par + +{\tttf \TestThis 123 \dorecurse{10}{\the \TestThis 1 10 \space}}\par +{\tttf \TestThis 123 \dorecurse{10}{\the \TestThis 1 10 \space}}\par +{\tttf \TestThis 456 \dorecurse{10}{\the \TestThis 1 10 \space}}\par +{\tttf \dorecurse{10}{\the \TestThis 1 10 \space}}\par + +\TestFloat .1e20\relax +\TestFloat -0x1.693d8e8943f17p+332\relax +\TestFloat 0x1.693d8e8943f17p+332\relax + +\TestFloat 123.345E67\relax + +{\tttf [\the\TestFloat]} + +% maybe some day: + +% \startluacode +% local t1 = token.get_next() +% local t2 = token.get_next() +% local t3 = token.get_next() +% local t4 = token.get_next() +% -- watch out, we flush in sequence +% token.put_next { t1, t2 } +% -- but this one gets pushed in front +% token.put_next ( t3, t4 ) +% \stopluacode +% abcd + +% \ctxlua{whatever = { } whatever.bf = token.get_next()}\bf + +\startluacode + local t_bf = whatever and whatever.bf or token.create("bf") + local put = token.put_next + + interfaces.implement { + name = "whateverbfone", + public = true, + actions = function() + put(t_bf) + end + } + + local ctx_whateverbfxxx = context.whateverbfxxx + + interfaces.implement { + name = "whateverbftwo", + public = true, + actions = function() + ctx_whateverbfxxx(false) + end + } + + interfaces.implement { + name = "whateverbfthree", + public = true, + actions = context.core.cs.whateverbfxxx + } + +\stopluacode + +\let\whateverbfxxx\bf + +\dontleavehmode{xxx: \whateverbfxxx xxx}\quad +\dontleavehmode{one: \whateverbfone one}\quad +\dontleavehmode{two: \whateverbftwo two}\quad +\dontleavehmode{two: \whateverbfthree three}\par diff --git a/doc/context/sources/general/manuals/cld/cld-specialcommands.tex b/doc/context/sources/general/manuals/cld/cld-specialcommands.tex index 37ecf45c6..510c820f9 100644 --- a/doc/context/sources/general/manuals/cld/cld-specialcommands.tex +++ b/doc/context/sources/general/manuals/cld/cld-specialcommands.tex @@ -237,14 +237,14 @@ context.stepwise(function() end) \stopluacode \stoptext -\starttyping +\stoptyping Instead of the \type {testpage} function you can also play directly with registers, like: \starttyping if tex.pagegtotal + tex.count.lineheight > tex.pagetotal then -\starttyping +\stoptyping but often an already defined helper does a better job. Of course you will probably never need this kind of hacks anyway, if only because much more is going diff --git a/doc/context/sources/general/manuals/cld/cld-variables.tex b/doc/context/sources/general/manuals/cld/cld-variables.tex new file mode 100644 index 000000000..c9afbd44c --- /dev/null +++ b/doc/context/sources/general/manuals/cld/cld-variables.tex @@ -0,0 +1,340 @@ +% language=uk + +\startcomponent cld-variables + +\environment cld-environment + +\startchapter[title={Variables}] + +\startsection[title={Introduction}] + +\index {variables} + +Sometimes a bit of experimenting and exploring the boundaries of the \TEX|-|\LUA\ +interfaces results in new mechanisms. To what extent they are really useful is +hard to say but we just keep them around. Some are described here. This is, at +least for the moment, a \LMTX\ specific chapter. + +\stopsection + +\startsection[title={Simple tables}] + +\index {variables+grouped tables} + +The basic \TEX\ data types are counters (integers), dimensions (kind of floating +point variables with typographic dimensions), token lists, node lists (boxes), +fonts, and so on, but no data organized in tables. The first mechanism that we +discuss is one that obeys grouping. In that respect is behaves like regular +registers. + +\startbuffer +\newhashedtable\somehashtable + +\somehashtable{ foo = 123, bar = "foo" } +[123 = \the\somehashtable{foo}] +[foo = \the\somehashtable{bar}] + +\bgroup +\somehashtable{ foo = 456, bar = "oof" } +[456 = \the\somehashtable{foo}] +[oof = \the\somehashtable{bar}] +\egroup + +[123 = \the\somehashtable{foo}] +[foo = \the\somehashtable{bar}] + +\bgroup +\global\somehashtable{ foo = 456 } + \somehashtable{ bar = "oof" } +[456 = \the\somehashtable{foo}] +[oof = \the\somehashtable{bar}] +\egroup + +[456 = \the\somehashtable{foo}] +[foo = \the\somehashtable{bar}] +\stopbuffer + +\typebuffer + +We define a hashed table, one with keys and values. The definition is global. +We can then assign values to this table where the assignments themselves are +hash tables. The above code generates: + +\getbuffer + +As you can see, the \type {\global} prefix makes the value persistent outside the +group. You can mix local and global assignments. + +Instead of a hashed table, you can have an indexed table. This time the keys are +numbers. + +\startbuffer +\newindexedtable\someindextable + +\someindextable{ 123, "foo" } +[123 = \the\someindextable 1] +[foo = \the\someindextable 2] + +\bgroup +\someindextable{ 456, "oof" } +[456 = \the\someindextable 1] +[oof = \the\someindextable 2] +\egroup + +[123 = \the\someindextable 1] +[foo = \the\someindextable 2] + +\bgroup +\global\someindextable{ [1] = 456 } + \someindextable{ [2] = "oof" } +[456 = \the\someindextable 1] +[oof = \the\someindextable 2] +\egroup + +[456 = \the\someindextable 1] +[foo = \the\someindextable 2] +\stopbuffer + +\typebuffer + +The outcome is the same as before: + +\getbuffer + +At the \LUA\ end you can access these tables too: + +\startbuffer +\startluacode +context("[hashed : bar = %s]",context.hashedtables.somehashtable.bar) +context("[indexed : 2 = %s]", context.indexedtables.someindextable[2]) +\stopluacode +\stopbuffer + +\typebuffer + +Indeed we get: + +\getbuffer + +\stopsection + +\startsection[title={Data tables}] + +\index {variables+data tables} + +In \LUA, tables can be more complex than in the previous section. When you need +more complex tables, it is likely that your grouping needs are also different, +which is why we have another mechanism. This mechanism is build on top of another +model: data values. There are 64K integer registers in any modern \TEX\ engine +and normally that is more than enough. However, in addition in \LUAMETATEX\ we +have a variant integer storage unit, one that is lightweight and where the amount +is limited by the size of the hash table. It was added as part of the low level +cleanup up of the \LUA\ token interface (a bit more abstraction). Here is an +example of its usage: + +\startbuffer +\dorecurse {100} { + \setdatavalue{#1}{#1} +} + +\start \tttf \darkred \raggedright \dorecurse {100} { + #1=\scratchcounter\getdatavalue{#1}\the\scratchcounter +} \par \stop \blank + +\start \tttf \darkgreen \raggedright \dorecurse {100} { + #1=\thedatavalue{#1}% +} \par \stop \blank +\stopbuffer + +\typebuffer + +\getbuffer + +We define hundred values which are a simple numeric macros. Here we use two +auxiliary macros because we prefer to use a dedicated namespace for these +variables. However, there are also primitives that deal with these data values: + +\startbuffer[usage] +\setdatavalue{my-data}{12345}% +\letdatacode \MyData 67890 +\thedatavalue{my-data} \the\MyData +\stopbuffer + +\typebuffer[usage] + +gives: \inlinebuffer[usage] + +But, when more is needed than simple integers, tables come into view. This interface +is different from the simple one and involves more commands. The next examples show +about all: + +\startbuffer +\newluatable\testtable +\setluatable\testtable{ foo = 123, bar = "456", oof = "rab" } +% \inspectluatable\testtable +\darkcyan +foo = \getfromluatable\testtable{foo}\par +bar = \getfromluatable\testtable{bar}\par +oof = \getfromluatable\testtable{oof}\par +\bgroup + \useluatable\testtable + \setluatable\testtable{ foo = 123123, bar = "456456" } + % \inspectluatable\testtable + \darkmagenta + foo = \getfromluatable\testtable{foo}\par + bar = \getfromluatable\testtable{bar}\par + oof = \getfromluatable\testtable{oof}\par + \startluacode + local t = context.luatables.get("testtable") + context("<%s %s %s>",t.foo,t.bar,t.oof) + \stopluacode \par +\egroup +\darkyellow +foo = \getfromluatable\testtable{foo}\par +bar = \getfromluatable\testtable{bar}\par +oof = \getfromluatable\testtable{oof}\par +\startluacode + local t = context.luatables.get("testtable") + context("<%s %s %s>",t.foo,t.bar,t.oof) +\stopluacode \par +% \inspectluatable\testtable +\stopbuffer + +\typebuffer + +The tables are semi|-|local: \type {\newluatable} creates a table and \type +{\useluatable} will create a local copy that is discarded when the group ends. + +\startpacked +\tttf \getbuffer +\stoppacked + +Hashed and indexed tables can be used mixed, but there are additional accessors +for indexed tables because there we expect numbers. + +\startbuffer +\newluatable\moretable +\setluatable\moretable{ 1, "foo" } +\darkcyan +[1] = \getfromluatable\moretable{1}\par +[2] = \idxfromluatable\moretable 2 \par +\bgroup + \useluatable\moretable + \setluatable\moretable{ foo = 123123, bar = "456456" } + \darkmagenta + [1] = \getfromluatable\moretable{1}\par + [2] = \idxfromluatable\moretable 2 \par + \startluacode + local t = context.luatables.get("moretable") + context("<%s %s>",t[1],t[2]) + \stopluacode \par +\egroup +\darkyellow +[1] = \getfromluatable\moretable{1}\par +[2] = \idxfromluatable\moretable 2 \par +\startluacode + local t = context.luatables.get("moretable") + context("<%s %s>",t[1],t[2]) +\stopluacode \par +\stopbuffer + +\typebuffer + +\startpacked +\tttf \getbuffer +\stoppacked + +You can create more complex (nested) tables that you can handle at the \LUA\ +end in the usual way. Basically any \LUA\ that makes a table can go between +the curly braces. + +\stopsection + +\startsection[title=Named variables] + +\index {variables+named} +\index {variables+integers} +\index {variables+cardinals} +\index {variables+floats} +\index {integers} +\index {cardinals} +\index {floats} + +Just because it can be done, and maybe it even has it use, we offer additional +numbers, stored and accessible by name. The different types all live in their +own namespace: + +\startbuffer[definition] +\luainteger bar 123456 +\luafloat bar 123.456e12 +\luainteger gnu = 0xFFFF +\stopbuffer + +\startbuffer[usage] +{\darkcyan \the\luainteger bar} +{\darkmagenta\the\luafloat bar} +{\darkyellow \the\luainteger gnu} +\stopbuffer + +\typebuffer[definition,usage] \getbuffer[definition] + +These serialize like: \getbuffer[usage]\removeunwantedspaces , and when not set they +default to zero. There is an extra type, cardinal: + +\startbuffer +\luainteger a 0x7FFFFFFFFFFFFFFF +\luainteger b -0x7FFFFFFFFFFFFFFF +\luacardinal c 0xFFFFFFFFFFFFFFFF +\stopbuffer + +\typebuffer \getbuffer + +We cheat a bit behind the screens because it is actually a double but we scan +it as positive integer and serialize it as such. + +\startbuffer +[\the \luainteger a\relax]\par +[\the \luainteger b\relax]\par +[\the \luacardinal c\relax]\par +\stopbuffer + +\typebuffer \getbuffer + +You have access to the numbers at the \LUA\ end, as in: + +\startbuffer +\luainteger one 123 \luafloat two 456.678 +\luaexpr{interfaces.numbers.one/1000 + interfaces.numbers.two/10000} +\stopbuffer + +\typebuffer + +There are \type {integers}, \type {cardinals} and \type {floats} but the \type +{numbers} one is the most generic as it tries to resolve it from one of these +namespaces, so we get: [\inlinebuffer\space\space]. There is also a related +expression command: + +\startbuffer +(?: \luaexpression {n.one/1000 + n.two/10000}) +(f: \luaexpression float {n.one/1000 + n.two/10000}) +(i: \luaexpression integer {n.one/1000 + n.two/10000}) +(c: \luaexpression cardinal {n.one/1000 + n.two/10000}) +(l: \luaexpression lua {n.one/1000 + n.two/10000}) +\stopbuffer + +\typebuffer + +It typesets this (watch the \type {lua} variant, which is a precise +roundtrip serialization method): + +\startlines +\tttf \getbuffer +\stoplines + +The \type {n} table is just a shortcut to \type {interfaces.numbers}. + +\stopsection + +\stopchapter + +\stopcomponent diff --git a/scripts/context/lua/mtxrun.lua b/scripts/context/lua/mtxrun.lua index 74cb62938..f0b9b7cd2 100644 --- a/scripts/context/lua/mtxrun.lua +++ b/scripts/context/lua/mtxrun.lua @@ -6563,7 +6563,7 @@ do -- create closure to overcome 200 locals limit package.loaded["util-str"] = package.loaded["util-str"] or true --- original size: 45153, stripped down to: 22734 +-- original size: 43947, stripped down to: 22741 if not modules then modules={} end modules ['util-str']={ version=1.001, @@ -7219,33 +7219,36 @@ local format_extension=function(extensions,f,name) local extension=extensions[name] or "tostring(%s)" local f=tonumber(f) or 1 local w=find(extension,"%.%.%.") - if w then - if f==0 then + if f==0 then + if w then extension=gsub(extension,"%.%.%.","") - return extension - elseif f==1 then + end + return extension + elseif f==1 then + if w then extension=gsub(extension,"%.%.%.","%%s") - n=n+1 - local a="a"..n - return format(extension,a,a) - elseif f<0 then + end + n=n+1 + local a="a"..n + return format(extension,a,a) + elseif f<0 then + if w then + extension=gsub(extension,"%.%.%.","") + return extension + else local a="a"..(n+f+1) return format(extension,a,a) - else - extension=gsub(extension,"%.%.%.",rep("%%s,",f-1).."%%s") - local t={} - for i=1,f do - n=n+1 - t[i]="a"..n - end - return format(extension,unpack(t)) end else - extension=gsub(extension,"%%s",function() + if w then + extension=gsub(extension,"%.%.%.",rep("%%s,",f-1).."%%s") + end + local t={} + for i=1,f do n=n+1 - return "a"..n - end) - return extension + t[i]="a"..n + end + return format(extension,unpack(t)) end end local builder=Cs { "start", @@ -26169,8 +26172,8 @@ end -- of closure -- used libraries : l-bit32.lua l-lua.lua l-macro.lua l-sandbox.lua l-package.lua l-lpeg.lua l-function.lua l-string.lua l-table.lua l-io.lua l-number.lua l-set.lua l-os.lua l-file.lua l-gzip.lua l-md5.lua l-sha.lua l-url.lua l-dir.lua l-boolean.lua l-unicode.lua l-math.lua util-str.lua util-tab.lua util-fil.lua util-sac.lua util-sto.lua util-prs.lua util-fmt.lua util-soc-imp-reset.lua util-soc-imp-socket.lua util-soc-imp-copas.lua util-soc-imp-ltn12.lua util-soc-imp-mime.lua util-soc-imp-url.lua util-soc-imp-headers.lua util-soc-imp-tp.lua util-soc-imp-http.lua util-soc-imp-ftp.lua util-soc-imp-smtp.lua trac-set.lua trac-log.lua trac-inf.lua trac-pro.lua util-lua.lua util-deb.lua util-tpl.lua util-sbx.lua util-mrg.lua util-env.lua luat-env.lua util-zip.lua lxml-tab.lua lxml-lpt.lua lxml-mis.lua lxml-aux.lua lxml-xml.lua trac-xml.lua data-ini.lua data-exp.lua data-env.lua data-tmp.lua data-met.lua data-res.lua data-pre.lua data-inp.lua data-out.lua data-fil.lua data-con.lua data-use.lua data-zip.lua data-tre.lua data-sch.lua data-lua.lua data-aux.lua data-tmf.lua data-lst.lua libs-ini.lua luat-sta.lua luat-fmt.lua -- skipped libraries : - --- original bytes : 1040906 --- stripped bytes : 411386 +-- original bytes : 1039700 +-- stripped bytes : 410173 -- end library merge diff --git a/scripts/context/stubs/mswin/mtxrun.lua b/scripts/context/stubs/mswin/mtxrun.lua index 74cb62938..f0b9b7cd2 100644 --- a/scripts/context/stubs/mswin/mtxrun.lua +++ b/scripts/context/stubs/mswin/mtxrun.lua @@ -6563,7 +6563,7 @@ do -- create closure to overcome 200 locals limit package.loaded["util-str"] = package.loaded["util-str"] or true --- original size: 45153, stripped down to: 22734 +-- original size: 43947, stripped down to: 22741 if not modules then modules={} end modules ['util-str']={ version=1.001, @@ -7219,33 +7219,36 @@ local format_extension=function(extensions,f,name) local extension=extensions[name] or "tostring(%s)" local f=tonumber(f) or 1 local w=find(extension,"%.%.%.") - if w then - if f==0 then + if f==0 then + if w then extension=gsub(extension,"%.%.%.","") - return extension - elseif f==1 then + end + return extension + elseif f==1 then + if w then extension=gsub(extension,"%.%.%.","%%s") - n=n+1 - local a="a"..n - return format(extension,a,a) - elseif f<0 then + end + n=n+1 + local a="a"..n + return format(extension,a,a) + elseif f<0 then + if w then + extension=gsub(extension,"%.%.%.","") + return extension + else local a="a"..(n+f+1) return format(extension,a,a) - else - extension=gsub(extension,"%.%.%.",rep("%%s,",f-1).."%%s") - local t={} - for i=1,f do - n=n+1 - t[i]="a"..n - end - return format(extension,unpack(t)) end else - extension=gsub(extension,"%%s",function() + if w then + extension=gsub(extension,"%.%.%.",rep("%%s,",f-1).."%%s") + end + local t={} + for i=1,f do n=n+1 - return "a"..n - end) - return extension + t[i]="a"..n + end + return format(extension,unpack(t)) end end local builder=Cs { "start", @@ -26169,8 +26172,8 @@ end -- of closure -- used libraries : l-bit32.lua l-lua.lua l-macro.lua l-sandbox.lua l-package.lua l-lpeg.lua l-function.lua l-string.lua l-table.lua l-io.lua l-number.lua l-set.lua l-os.lua l-file.lua l-gzip.lua l-md5.lua l-sha.lua l-url.lua l-dir.lua l-boolean.lua l-unicode.lua l-math.lua util-str.lua util-tab.lua util-fil.lua util-sac.lua util-sto.lua util-prs.lua util-fmt.lua util-soc-imp-reset.lua util-soc-imp-socket.lua util-soc-imp-copas.lua util-soc-imp-ltn12.lua util-soc-imp-mime.lua util-soc-imp-url.lua util-soc-imp-headers.lua util-soc-imp-tp.lua util-soc-imp-http.lua util-soc-imp-ftp.lua util-soc-imp-smtp.lua trac-set.lua trac-log.lua trac-inf.lua trac-pro.lua util-lua.lua util-deb.lua util-tpl.lua util-sbx.lua util-mrg.lua util-env.lua luat-env.lua util-zip.lua lxml-tab.lua lxml-lpt.lua lxml-mis.lua lxml-aux.lua lxml-xml.lua trac-xml.lua data-ini.lua data-exp.lua data-env.lua data-tmp.lua data-met.lua data-res.lua data-pre.lua data-inp.lua data-out.lua data-fil.lua data-con.lua data-use.lua data-zip.lua data-tre.lua data-sch.lua data-lua.lua data-aux.lua data-tmf.lua data-lst.lua libs-ini.lua luat-sta.lua luat-fmt.lua -- skipped libraries : - --- original bytes : 1040906 --- stripped bytes : 411386 +-- original bytes : 1039700 +-- stripped bytes : 410173 -- end library merge diff --git a/scripts/context/stubs/unix/mtxrun b/scripts/context/stubs/unix/mtxrun index 74cb62938..f0b9b7cd2 100644 --- a/scripts/context/stubs/unix/mtxrun +++ b/scripts/context/stubs/unix/mtxrun @@ -6563,7 +6563,7 @@ do -- create closure to overcome 200 locals limit package.loaded["util-str"] = package.loaded["util-str"] or true --- original size: 45153, stripped down to: 22734 +-- original size: 43947, stripped down to: 22741 if not modules then modules={} end modules ['util-str']={ version=1.001, @@ -7219,33 +7219,36 @@ local format_extension=function(extensions,f,name) local extension=extensions[name] or "tostring(%s)" local f=tonumber(f) or 1 local w=find(extension,"%.%.%.") - if w then - if f==0 then + if f==0 then + if w then extension=gsub(extension,"%.%.%.","") - return extension - elseif f==1 then + end + return extension + elseif f==1 then + if w then extension=gsub(extension,"%.%.%.","%%s") - n=n+1 - local a="a"..n - return format(extension,a,a) - elseif f<0 then + end + n=n+1 + local a="a"..n + return format(extension,a,a) + elseif f<0 then + if w then + extension=gsub(extension,"%.%.%.","") + return extension + else local a="a"..(n+f+1) return format(extension,a,a) - else - extension=gsub(extension,"%.%.%.",rep("%%s,",f-1).."%%s") - local t={} - for i=1,f do - n=n+1 - t[i]="a"..n - end - return format(extension,unpack(t)) end else - extension=gsub(extension,"%%s",function() + if w then + extension=gsub(extension,"%.%.%.",rep("%%s,",f-1).."%%s") + end + local t={} + for i=1,f do n=n+1 - return "a"..n - end) - return extension + t[i]="a"..n + end + return format(extension,unpack(t)) end end local builder=Cs { "start", @@ -26169,8 +26172,8 @@ end -- of closure -- used libraries : l-bit32.lua l-lua.lua l-macro.lua l-sandbox.lua l-package.lua l-lpeg.lua l-function.lua l-string.lua l-table.lua l-io.lua l-number.lua l-set.lua l-os.lua l-file.lua l-gzip.lua l-md5.lua l-sha.lua l-url.lua l-dir.lua l-boolean.lua l-unicode.lua l-math.lua util-str.lua util-tab.lua util-fil.lua util-sac.lua util-sto.lua util-prs.lua util-fmt.lua util-soc-imp-reset.lua util-soc-imp-socket.lua util-soc-imp-copas.lua util-soc-imp-ltn12.lua util-soc-imp-mime.lua util-soc-imp-url.lua util-soc-imp-headers.lua util-soc-imp-tp.lua util-soc-imp-http.lua util-soc-imp-ftp.lua util-soc-imp-smtp.lua trac-set.lua trac-log.lua trac-inf.lua trac-pro.lua util-lua.lua util-deb.lua util-tpl.lua util-sbx.lua util-mrg.lua util-env.lua luat-env.lua util-zip.lua lxml-tab.lua lxml-lpt.lua lxml-mis.lua lxml-aux.lua lxml-xml.lua trac-xml.lua data-ini.lua data-exp.lua data-env.lua data-tmp.lua data-met.lua data-res.lua data-pre.lua data-inp.lua data-out.lua data-fil.lua data-con.lua data-use.lua data-zip.lua data-tre.lua data-sch.lua data-lua.lua data-aux.lua data-tmf.lua data-lst.lua libs-ini.lua luat-sta.lua luat-fmt.lua -- skipped libraries : - --- original bytes : 1040906 --- stripped bytes : 411386 +-- original bytes : 1039700 +-- stripped bytes : 410173 -- end library merge diff --git a/scripts/context/stubs/win64/mtxrun.lua b/scripts/context/stubs/win64/mtxrun.lua index 74cb62938..f0b9b7cd2 100644 --- a/scripts/context/stubs/win64/mtxrun.lua +++ b/scripts/context/stubs/win64/mtxrun.lua @@ -6563,7 +6563,7 @@ do -- create closure to overcome 200 locals limit package.loaded["util-str"] = package.loaded["util-str"] or true --- original size: 45153, stripped down to: 22734 +-- original size: 43947, stripped down to: 22741 if not modules then modules={} end modules ['util-str']={ version=1.001, @@ -7219,33 +7219,36 @@ local format_extension=function(extensions,f,name) local extension=extensions[name] or "tostring(%s)" local f=tonumber(f) or 1 local w=find(extension,"%.%.%.") - if w then - if f==0 then + if f==0 then + if w then extension=gsub(extension,"%.%.%.","") - return extension - elseif f==1 then + end + return extension + elseif f==1 then + if w then extension=gsub(extension,"%.%.%.","%%s") - n=n+1 - local a="a"..n - return format(extension,a,a) - elseif f<0 then + end + n=n+1 + local a="a"..n + return format(extension,a,a) + elseif f<0 then + if w then + extension=gsub(extension,"%.%.%.","") + return extension + else local a="a"..(n+f+1) return format(extension,a,a) - else - extension=gsub(extension,"%.%.%.",rep("%%s,",f-1).."%%s") - local t={} - for i=1,f do - n=n+1 - t[i]="a"..n - end - return format(extension,unpack(t)) end else - extension=gsub(extension,"%%s",function() + if w then + extension=gsub(extension,"%.%.%.",rep("%%s,",f-1).."%%s") + end + local t={} + for i=1,f do n=n+1 - return "a"..n - end) - return extension + t[i]="a"..n + end + return format(extension,unpack(t)) end end local builder=Cs { "start", @@ -26169,8 +26172,8 @@ end -- of closure -- used libraries : l-bit32.lua l-lua.lua l-macro.lua l-sandbox.lua l-package.lua l-lpeg.lua l-function.lua l-string.lua l-table.lua l-io.lua l-number.lua l-set.lua l-os.lua l-file.lua l-gzip.lua l-md5.lua l-sha.lua l-url.lua l-dir.lua l-boolean.lua l-unicode.lua l-math.lua util-str.lua util-tab.lua util-fil.lua util-sac.lua util-sto.lua util-prs.lua util-fmt.lua util-soc-imp-reset.lua util-soc-imp-socket.lua util-soc-imp-copas.lua util-soc-imp-ltn12.lua util-soc-imp-mime.lua util-soc-imp-url.lua util-soc-imp-headers.lua util-soc-imp-tp.lua util-soc-imp-http.lua util-soc-imp-ftp.lua util-soc-imp-smtp.lua trac-set.lua trac-log.lua trac-inf.lua trac-pro.lua util-lua.lua util-deb.lua util-tpl.lua util-sbx.lua util-mrg.lua util-env.lua luat-env.lua util-zip.lua lxml-tab.lua lxml-lpt.lua lxml-mis.lua lxml-aux.lua lxml-xml.lua trac-xml.lua data-ini.lua data-exp.lua data-env.lua data-tmp.lua data-met.lua data-res.lua data-pre.lua data-inp.lua data-out.lua data-fil.lua data-con.lua data-use.lua data-zip.lua data-tre.lua data-sch.lua data-lua.lua data-aux.lua data-tmf.lua data-lst.lua libs-ini.lua luat-sta.lua luat-fmt.lua -- skipped libraries : - --- original bytes : 1040906 --- stripped bytes : 411386 +-- original bytes : 1039700 +-- stripped bytes : 410173 -- end library merge diff --git a/tex/context/base/mkii/cont-new.mkii b/tex/context/base/mkii/cont-new.mkii index 242fe472a..380edf717 100644 --- a/tex/context/base/mkii/cont-new.mkii +++ b/tex/context/base/mkii/cont-new.mkii @@ -11,7 +11,7 @@ %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. -\newcontextversion{2020.06.20 13:33} +\newcontextversion{2020.06.25 10:55} %D This file is loaded at runtime, thereby providing an %D excellent place for hacks, patches, extensions and new diff --git a/tex/context/base/mkii/context.mkii b/tex/context/base/mkii/context.mkii index bbe1f8fca..0cf1b1e6c 100644 --- a/tex/context/base/mkii/context.mkii +++ b/tex/context/base/mkii/context.mkii @@ -20,7 +20,7 @@ %D your styles an modules. \edef\contextformat {\jobname} -\edef\contextversion{2020.06.20 13:33} +\edef\contextversion{2020.06.25 10:55} %D For those who want to use this: diff --git a/tex/context/base/mkiv/anch-pos.lua b/tex/context/base/mkiv/anch-pos.lua index 2788c9d1a..da95eeb1a 100644 --- a/tex/context/base/mkiv/anch-pos.lua +++ b/tex/context/base/mkiv/anch-pos.lua @@ -13,16 +13,19 @@ more efficient.</p> --ldx]]-- -- plus (extra) is obsolete but we will keep it for a while - +-- -- maybe replace texsp by our own converter (stay at the lua end) -- eventually mp will have large numbers so we can use sp there too - --- this is one of the first modules using scanners and we need to replace --- it by implement and friends - +-- +-- this is one of the first modules using scanners and we need to replace it by +-- implement and friends +-- -- we could have namespaces, like p, page, region, columnarea, textarea but then -- we need virtual table accessors as well as have tag/id accessors ... we don't -- save much here (at least not now) +-- +-- This was the last module that got rid of directly setting scanners, with a little +-- performance degradation but not that noticeable. local tostring, next, setmetatable, tonumber = tostring, next, setmetatable, tonumber local sort = table.sort @@ -38,8 +41,7 @@ local scanstring = scanners.string local scaninteger = scanners.integer local scandimen = scanners.dimen -local compilescanner = tokens.compile -local scanners = interfaces.scanners +local implement = interfaces.implement local commands = commands local context = context @@ -124,9 +126,9 @@ local nofregular = 0 local nofspecial = 0 local splitter = lpeg.splitat(":",true) -local pagedata = { } -local columndata = setmetatableindex("table") -- per page -local freedata = setmetatableindex("table") -- per page +local pagedata = { } +local columndata = setmetatableindex("table") -- per page +local freedata = setmetatableindex("table") -- per page local function initializer() tobesaved = jobpositions.tobesaved @@ -376,19 +378,22 @@ jobpositions.set = set jobpositions.setspec = setspec jobpositions.get = get -scanners.dosaveposition = compilescanner { +implement { + name = "dosaveposition", + arguments = { "string", "integer", "dimen", "dimen" }, actions = setall, -- name p x y - arguments = { "string", "integer", "dimen", "dimen" } } -scanners.dosavepositionwhd = compilescanner { -- somehow fails +implement { + name = "dosavepositionwhd", + arguments = { "string", "integer", "dimen", "dimen", "dimen", "dimen", "dimen" }, actions = setall, -- name p x y w h d - arguments = { "string", "integer", "dimen", "dimen", "dimen", "dimen", "dimen" } } -scanners.dosavepositionplus = compilescanner { +implement { + name = "dosavepositionplus", + arguments = { "string", "integer", "dimen", "dimen", "dimen", "dimen", "dimen", "string" }, actions = setall, -- name p x y w h d extra - arguments = { "string", "integer", "dimen", "dimen", "dimen", "dimen", "dimen", "string" } } -- will become private table (could also become attribute driven but too nasty @@ -424,29 +429,41 @@ end jobpositions.b_column = b_column jobpositions.e_column = e_column -scanners.bposcolumn = function() -- tag - local tag = scanstring() - insert(columns,tag) - column = tag -end +implement { + name = "bposcolumn", + arguments = "string", + actions = function(tag) + insert(columns,tag) + column = tag + end +} -scanners.bposcolumnregistered = function() -- tag - local tag = scanstring() - insert(columns,tag) - column = tag - ctx_latelua { action = b_column, tag = tag } -end +implement { + name = "bposcolumnregistered", + arguments = "string", + actions = function(tag) + insert(columns,tag) + column = tag + ctx_latelua { action = b_column, tag = tag } + end +} -scanners.eposcolumn = function() - remove(columns) - column = columns[#columns] -end +implement { + name = "eposcolumn", + actions = function() + remove(columns) + column = columns[#columns] + end +} -scanners.eposcolumnregistered = function() - ctx_latelua { action = e_column } - remove(columns) - column = columns[#columns] -end +implement { + name = "eposcolumnregistered", + actions = function() + ctx_latelua { action = e_column } + remove(columns) + column = columns[#columns] + end +} -- regions @@ -551,167 +568,181 @@ end local nofparagraphs = 0 -scanners.parpos = function() - nofparagraphs = nofparagraphs + 1 - texsetcount("global","c_anch_positions_paragraph",nofparagraphs) - local box = getbox("strutbox") - local w, h, d = getwhd(box) - local t = { - p = true, - c = true, - r = true, - x = true, - y = true, - h = h, - d = d, - hs = texget("hsize"), -- never 0 - } - local leftskip = texget("leftskip",false) - local rightskip = texget("rightskip",false) - local hangindent = texget("hangindent") - local hangafter = texget("hangafter") - local parindent = texget("parindent") - local parshape = texget("parshape") - if leftskip ~= 0 then - t.ls = leftskip - end - if rightskip ~= 0 then - t.rs = rightskip - end - if hangindent ~= 0 then - t.hi = hangindent - end - if hangafter ~= 1 and hangafter ~= 0 then -- can not be zero .. so it needs to be 1 if zero - t.ha = hangafter - end - if parindent ~= 0 then - t.pi = parindent - end - if parshape and #parshape > 0 then - t.ps = parshape +implement { + name = "parpos", + actions = function() + nofparagraphs = nofparagraphs + 1 + texsetcount("global","c_anch_positions_paragraph",nofparagraphs) + local box = getbox("strutbox") + local w, h, d = getwhd(box) + local t = { + p = true, + c = true, + r = true, + x = true, + y = true, + h = h, + d = d, + hs = texget("hsize"), -- never 0 + } + local leftskip = texget("leftskip",false) + local rightskip = texget("rightskip",false) + local hangindent = texget("hangindent") + local hangafter = texget("hangafter") + local parindent = texget("parindent") + local parshape = texget("parshape") + if leftskip ~= 0 then + t.ls = leftskip + end + if rightskip ~= 0 then + t.rs = rightskip + end + if hangindent ~= 0 then + t.hi = hangindent + end + if hangafter ~= 1 and hangafter ~= 0 then -- can not be zero .. so it needs to be 1 if zero + t.ha = hangafter + end + if parindent ~= 0 then + t.pi = parindent + end + if parshape and #parshape > 0 then + t.ps = parshape + end + local name = f_p_tag(nofparagraphs) + tobesaved[name] = t + ctx_latelua { action = enhance, specification = t } end - local name = f_p_tag(nofparagraphs) - tobesaved[name] = t - ctx_latelua { action = enhance, specification = t } -end +} -scanners.dosetposition = function() -- name - local name = scanstring() - local spec = { - p = true, - c = column, - r = true, - x = true, - y = true, - n = nofparagraphs > 0 and nofparagraphs or nil, - r2l = texgetcount("inlinelefttoright") == 1 or nil, - } - tobesaved[name] = spec - ctx_latelua { action = enhance, specification = spec } -end +implement { + name = "dosetposition", + arguments = "string", + actions = function(name) + local spec = { + p = true, + c = column, + r = true, + x = true, + y = true, + n = nofparagraphs > 0 and nofparagraphs or nil, + r2l = texgetcount("inlinelefttoright") == 1 or nil, + } + tobesaved[name] = spec + ctx_latelua { action = enhance, specification = spec } + end +} -scanners.dosetpositionwhd = function() -- name w h d extra - local name = scanstring() - local w = scandimen() - local h = scandimen() - local d = scandimen() - local spec = { - p = true, - c = column, - r = true, - x = true, - y = true, - w = w ~= 0 and w or nil, - h = h ~= 0 and h or nil, - d = d ~= 0 and d or nil, - n = nofparagraphs > 0 and nofparagraphs or nil, - r2l = texgetcount("inlinelefttoright") == 1 or nil, - } - tobesaved[name] = spec - ctx_latelua { action = enhance, specification = spec } -end +implement { + name = "dosetpositionwhd", + arguments = { "string", "dimen", "dimen", "dimen" }, + actions = function(name,w,h,d) + local spec = { + p = true, + c = column, + r = true, + x = true, + y = true, + w = w ~= 0 and w or nil, + h = h ~= 0 and h or nil, + d = d ~= 0 and d or nil, + n = nofparagraphs > 0 and nofparagraphs or nil, + r2l = texgetcount("inlinelefttoright") == 1 or nil, + } + tobesaved[name] = spec + ctx_latelua { action = enhance, specification = spec } + end +} -scanners.dosetpositionbox = function() -- name box - local name = scanstring() - local box = getbox(scaninteger()) - local w, h, d = getwhd(box) - local spec = { - p = true, - c = column, - r = true, - x = true, - y = true, - w = w ~= 0 and w or nil, - h = h ~= 0 and h or nil, - d = d ~= 0 and d or nil, - n = nofparagraphs > 0 and nofparagraphs or nil, - r2l = texgetcount("inlinelefttoright") == 1 or nil, - } - tobesaved[name] = spec - ctx_latelua { action = enhance, specification = spec } -end +implement { + name = "dosetpositionbox", + arguments = { "string", "integer" }, + actions = function(name,n) + local box = getbox(n) + local w, h, d = getwhd(box) + local spec = { + p = true, + c = column, + r = true, + x = true, + y = true, + w = w ~= 0 and w or nil, + h = h ~= 0 and h or nil, + d = d ~= 0 and d or nil, + n = nofparagraphs > 0 and nofparagraphs or nil, + r2l = texgetcount("inlinelefttoright") == 1 or nil, + } + tobesaved[name] = spec + ctx_latelua { action = enhance, specification = spec } + end +} -scanners.dosetpositionplus = function() -- name w h d extra - local name = scanstring() - local w = scandimen() - local h = scandimen() - local d = scandimen() - local spec = { - p = true, - c = column, - r = true, - x = true, - y = true, - w = w ~= 0 and w or nil, - h = h ~= 0 and h or nil, - d = d ~= 0 and d or nil, - n = nofparagraphs > 0 and nofparagraphs or nil, - e = scanstring(), - r2l = texgetcount("inlinelefttoright") == 1 or nil, - } - tobesaved[name] = spec - ctx_latelua { action = enhance, specification = spec } -end +implement { + name = "dosetpositionplus", + arguments = { "string", "dimen", "dimen", "dimen" }, + actions = function(name,w,h,d) + local spec = { + p = true, + c = column, + r = true, + x = true, + y = true, + w = w ~= 0 and w or nil, + h = h ~= 0 and h or nil, + d = d ~= 0 and d or nil, + n = nofparagraphs > 0 and nofparagraphs or nil, + e = scanstring(), + r2l = texgetcount("inlinelefttoright") == 1 or nil, + } + tobesaved[name] = spec + ctx_latelua { action = enhance, specification = spec } + end +} -scanners.dosetpositionstrut = function() -- name - local name = scanstring() - local box = getbox("strutbox") - local w, h, d = getwhd(box) - local spec = { - p = true, - c = column, - r = true, - x = true, - y = true, - h = h ~= 0 and h or nil, - d = d ~= 0 and d or nil, - n = nofparagraphs > 0 and nofparagraphs or nil, - r2l = texgetcount("inlinelefttoright") == 1 or nil, - } - tobesaved[name] = spec - ctx_latelua { action = enhance, specification = spec } -end +implement { + name = "dosetpositionstrut", + arguments = "string", + actions = function(name) + local box = getbox("strutbox") + local w, h, d = getwhd(box) + local spec = { + p = true, + c = column, + r = true, + x = true, + y = true, + h = h ~= 0 and h or nil, + d = d ~= 0 and d or nil, + n = nofparagraphs > 0 and nofparagraphs or nil, + r2l = texgetcount("inlinelefttoright") == 1 or nil, + } + tobesaved[name] = spec + ctx_latelua { action = enhance, specification = spec } + end +} -scanners.dosetpositionstrutkind = function() -- name - local name = scanstring() - local kind = scaninteger() - local box = getbox("strutbox") - local w, h, d = getwhd(box) - local spec = { - k = kind, - p = true, - c = column, - r = true, - x = true, - y = true, - h = h ~= 0 and h or nil, - d = d ~= 0 and d or nil, - n = nofparagraphs > 0 and nofparagraphs or nil, - r2l = texgetcount("inlinelefttoright") == 1 or nil, - } - tobesaved[name] = spec - ctx_latelua { action = enhance, specification = spec } -end +implement { + name = "dosetpositionstrutkind", + arguments = { "string", "integer" }, + actions = function(name,kind) + local box = getbox("strutbox") + local w, h, d = getwhd(box) + local spec = { + k = kind, + p = true, + c = column, + r = true, + x = true, + y = true, + h = h ~= 0 and h or nil, + d = d ~= 0 and d or nil, + n = nofparagraphs > 0 and nofparagraphs or nil, + r2l = texgetcount("inlinelefttoright") == 1 or nil, + } + tobesaved[name] = spec + ctx_latelua { action = enhance, specification = spec } + end +} function jobpositions.getreserved(tag,n) if tag == v_column then @@ -990,166 +1021,222 @@ jobpositions.columnofpos = columnofpos -- interface -scanners.replacepospxywhd = function() -- name page x y w h d - collected[scanstring()] = { - p = scaninteger(), - x = scandimen(), - y = scandimen(), - w = scandimen(), - h = scandimen(), - d = scandimen(), - } -end +implement { + name = "replacepospxywhd", + arguments = { "string", "integer", "dimen", "dimen", "dimen", "dimen", "dimen" }, + actions = function(name,page,x,y,w,h,d) + collected[name] = { + p = page, + x = x, + y = y, + w = w, + h = h, + d = d, + } + end +} -scanners.copyposition = function() -- target source - collected[scanstring()] = collected[scanstring()] -end +implement { + name = "copyposition", + arguments = "2 strings", + actions = function(target,source) + collected[target] = collected[source] + end +} -scanners.MPp = function() -- name - local jpi = collected[scanstring()] - if jpi then - local p = jpi.p - if p and p ~= true then - context(p) - return +implement { + name = "MPp", + arguments = "string", + actions = function(name) + local jpi = collected[name] + if jpi then + local p = jpi.p + if p and p ~= true then + context(p) + return + end end + context('0') end - context('0') -end +} -scanners.MPx = function() -- name - local jpi = collected[scanstring()] - if jpi then - local x = jpi.x - if x and x ~= true and x ~= 0 then - context("%.5Fpt",x*pt) - return +implement { + name = "MPx", + arguments = "string", + actions = function(name) + local jpi = collected[name] + if jpi then + local x = jpi.x + if x and x ~= true and x ~= 0 then + context("%.5Fpt",x*pt) + return + end end + context('0pt') end - context('0pt') -end +} -scanners.MPy = function() -- name - local jpi = collected[scanstring()] - if jpi then - local y = jpi.y - if y and y ~= true and y ~= 0 then - context("%.5Fpt",y*pt) - return +implement { + name = "MPy", + arguments = "string", + actions = function(name) + local jpi = collected[name] + if jpi then + local y = jpi.y + if y and y ~= true and y ~= 0 then + context("%.5Fpt",y*pt) + return + end end + context('0pt') end - context('0pt') -end +} -scanners.MPw = function() -- name - local jpi = collected[scanstring()] - if jpi then - local w = jpi.w - if w and w ~= 0 then - context("%.5Fpt",w*pt) - return +implement { + name = "MPw", + arguments = "string", + actions = function(name) + local jpi = collected[name] + if jpi then + local w = jpi.w + if w and w ~= 0 then + context("%.5Fpt",w*pt) + return + end end + context('0pt') end - context('0pt') -end +} -scanners.MPh = function() -- name - local jpi = collected[scanstring()] - if jpi then - local h = jpi.h - if h and h ~= 0 then - context("%.5Fpt",h*pt) - return +implement { + name = "MPh", + arguments = "string", + actions = function(name) + local jpi = collected[name] + if jpi then + local h = jpi.h + if h and h ~= 0 then + context("%.5Fpt",h*pt) + return + end end + context('0pt') end - context('0pt') -end +} -scanners.MPd = function() -- name - local jpi = collected[scanstring()] - if jpi then - local d = jpi.d - if d and d ~= 0 then - context("%.5Fpt",d*pt) - return +implement { + name = "MPd", + arguments = "string", + actions = function(name) + local jpi = collected[name] + if jpi then + local d = jpi.d + if d and d ~= 0 then + context("%.5Fpt",d*pt) + return + end end + context('0pt') end - context('0pt') -end +} -scanners.MPxy = function() -- name - local jpi = collected[scanstring()] - if jpi then - context('(%.5Fpt,%.5Fpt)', - jpi.x*pt, - jpi.y*pt - ) - else - context('(0,0)') +implement { + name = "MPxy", + arguments = "string", + actions = function(name) + local jpi = collected[name] + if jpi then + context('(%.5Fpt,%.5Fpt)', + jpi.x*pt, + jpi.y*pt + ) + else + context('(0,0)') + end end -end +} -scanners.MPwhd = function() -- name - local jpi = collected[scanstring()] - if jpi then - local w = jpi.w or 0 - local h = jpi.h or 0 - local d = jpi.d or 0 - if w ~= 0 or h ~= 0 or d ~= 0 then - context("%.5Fpt,%.5Fpt,%.5Fpt",w*pt,h*pt,d*pt) - return +implement { + name = "MPwhd", + arguments = "string", + actions = function(name) + local jpi = collected[name] + if jpi then + local w = jpi.w or 0 + local h = jpi.h or 0 + local d = jpi.d or 0 + if w ~= 0 or h ~= 0 or d ~= 0 then + context("%.5Fpt,%.5Fpt,%.5Fpt",w*pt,h*pt,d*pt) + return + end end + context('0pt,0pt,0pt') end - context('0pt,0pt,0pt') -end +} -scanners.MPll = function() -- name - local jpi = collected[scanstring()] - if jpi then - context('(%.5Fpt,%.5Fpt)', - jpi.x *pt, - (jpi.y-jpi.d)*pt - ) - else - context('(0,0)') -- for mp only +implement { + name = "MPll", + arguments = "string", + actions = function(name) + local jpi = collected[name] + if jpi then + context('(%.5Fpt,%.5Fpt)', + jpi.x *pt, + (jpi.y-jpi.d)*pt + ) + else + context('(0,0)') -- for mp only + end end -end +} -scanners.MPlr = function() -- name - local jpi = collected[scanstring()] - if jpi then - context('(%.5Fpt,%.5Fpt)', - (jpi.x + jpi.w)*pt, - (jpi.y - jpi.d)*pt - ) - else - context('(0,0)') -- for mp only +implement { + name = "MPlr", + arguments = "string", + actions = function(name) + local jpi = collected[name] + if jpi then + context('(%.5Fpt,%.5Fpt)', + (jpi.x + jpi.w)*pt, + (jpi.y - jpi.d)*pt + ) + else + context('(0,0)') -- for mp only + end end -end +} -scanners.MPur = function() -- name - local jpi = collected[scanstring()] - if jpi then - context('(%.5Fpt,%.5Fpt)', - (jpi.x + jpi.w)*pt, - (jpi.y + jpi.h)*pt - ) - else - context('(0,0)') -- for mp only +implement { + name = "MPur", + arguments = "string", + actions = function(name) + local jpi = collected[name] + if jpi then + context('(%.5Fpt,%.5Fpt)', + (jpi.x + jpi.w)*pt, + (jpi.y + jpi.h)*pt + ) + else + context('(0,0)') -- for mp only + end end -end +} -scanners.MPul = function() -- name - local jpi = collected[scanstring()] - if jpi then - context('(%.5Fpt,%.5Fpt)', - jpi.x *pt, - (jpi.y + jpi.h)*pt - ) - else - context('(0,0)') -- for mp only +implement { + name = "MPul", + arguments = "string", + actions = function(name) + local jpi = collected[name] + if jpi then + context('(%.5Fpt,%.5Fpt)', + jpi.x *pt, + (jpi.y + jpi.h)*pt + ) + else + context('(0,0)') -- for mp only + end end -end +} local function MPpos(id) local jpi = collected[id] @@ -1170,53 +1257,67 @@ local function MPpos(id) context('0,0,0,0,0,0') -- for mp only end -scanners.MPpos = function() -- name - MPpos(scanstring()) -end +implement { + name = "MPpos", + arguments = "string", + actions = MPpos +} -scanners.MPn = function() -- name - local jpi = collected[scanstring()] - if jpi then - local n = jpi.n - if n then - context(n) - return +implement { + name = "MPn", + arguments = "string", + actions = function(name) + local jpi = collected[name] + if jpi then + local n = jpi.n + if n then + context(n) + return + end end + context(0) end - context(0) -end +} -scanners.MPc = function() -- name - local jpi = collected[scanstring()] - if jpi then - local c = jpi.c - if c and c ~= true then - context(c) - return +implement { + name = "MPc", + arguments = "string", + actions = function(name) + local jpi = collected[name] + if jpi then + local c = jpi.c + if c and c ~= true then + context(c) + return + end end + context('0') -- okay ? end - context('0') -- okay ? -end +} -scanners.MPr = function() -- name - local jpi = collected[scanstring()] - if jpi then - local r = jpi.r - if r and r ~= true then - context(r) - return - end - local p = jpi.p - if p then - context("page:" .. p) +implement { + name = "MPr", + arguments = "string", + actions = function(name) + local jpi = collected[name] + if jpi then + local r = jpi.r + if r and r ~= true then + context(r) + return + end + local p = jpi.p + if p then + context("page:" .. p) + end end end -end +} -local function MPpardata(n) - local t = collected[n] +local function MPpardata(id) + local t = collected[id] if not t then - local tag = f_p_tag(n) + local tag = f_p_tag(id) t = collected[tag] end if t then @@ -1233,157 +1334,213 @@ local function MPpardata(n) end end -scanners.MPpardata = function() -- name - MPpardata(scanstring()) -end +implement { + name = "MPpardata", + arguments = "string", + actions = MPpardata +} -scanners.MPposset = function() -- name (special helper, used in backgrounds) - local name = scanstring() - local b = f_b_tag(name) - local e = f_e_tag(name) - local w = f_w_tag(name) - local p = f_p_tag(getparagraph(b)) - MPpos(b) context(",") MPpos(e) context(",") MPpos(w) context(",") MPpos(p) context(",") MPpardata(p) -end +implement { + name = "MPposset", + arguments = "string", + actions = function(name) + local b = f_b_tag(name) + local e = f_e_tag(name) + local w = f_w_tag(name) + local p = f_p_tag(getparagraph(b)) + MPpos(b) context(",") MPpos(e) context(",") MPpos(w) context(",") MPpos(p) context(",") MPpardata(p) + end +} -scanners.MPls = function() -- name - local jpi = collected[scanstring()] - if jpi then - context("%.5Fpt",jpi.ls*pt) - else - context("0pt") +implement { + name = "MPls", + arguments = "string", + actions = function(name) + local jpi = collected[name] + if jpi then + context("%.5Fpt",jpi.ls*pt) + else + context("0pt") + end end -end +} -scanners.MPrs = function() -- name - local jpi = collected[scanstring()] - if jpi then - context("%.5Fpt",jpi.rs*pt) - else - context("0pt") +implement { + name = "MPrs", + arguments = "string", + actions = function(name) + local jpi = collected[name] + if jpi then + context("%.5Fpt",jpi.rs*pt) + else + context("0pt") + end end -end +} local splitter = lpeg.tsplitat(",") -scanners.MPplus = function() -- name n default - local jpi = collected[scanstring()] - local n = scaninteger() - local default = scanstring() - if jpi then - local e = jpi.e - if e then - local split = jpi.split - if not split then - split = lpegmatch(splitter,jpi.e) - jpi.split = split +implement { + name = "MPplus", + arguments = { "string", "integer", "string" }, + actions = function(name,n,default) + local jpi = collected[name] + if jpi then + local e = jpi.e + if e then + local split = jpi.split + if not split then + split = lpegmatch(splitter,jpi.e) + jpi.split = split + end + context(split[n] or default) + return end - context(split[n] or default) - return end + context(default) end - context(default) -end +} -scanners.MPrest = function() -- name default - local jpi = collected[scanstring()] - local default = scanstring() - context(jpi and jpi.e or default) -end +implement { + name = "MPrest", + arguments = { "string", "string" }, + actions = function(name,default) + local jpi = collected[name] + context(jpi and jpi.e or default) + end +} -scanners.MPxywhd = function() -- name - local jpi = collected[scanstring()] - if jpi then - context("%.5Fpt,%.5Fpt,%.5Fpt,%.5Fpt,%.5Fpt", - jpi.x*pt, - jpi.y*pt, - jpi.w*pt, - jpi.h*pt, - jpi.d*pt - ) - else - context("0,0,0,0,0") -- for mp only +implement { + name = "MPxywhd", + arguments = "string", + actions = function(name) + local jpi = collected[name] + if jpi then + context("%.5Fpt,%.5Fpt,%.5Fpt,%.5Fpt,%.5Fpt", + jpi.x*pt, + jpi.y*pt, + jpi.w*pt, + jpi.h*pt, + jpi.d*pt + ) + else + context("0,0,0,0,0") -- for mp only + end end -end +} local doif = commands.doif local doifelse = commands.doifelse -scanners.doifelseposition = function() -- name - doifelse(collected[scanstring()]) -end - -scanners.doifposition = function() -- name - doif(collected[scanstring()]) -end +implement { + name = "doifelseposition", + arguments = "string", + actions = function(name) + doifelse(collected[name]) + end +} --- local ctx_iftrue = context.protected.cs.iftrue --- local ctx_iffalse = context.protected.cs.iffalse --- --- scanners.ifknownposition = function() -- name --- (collected[scanstring()] and ctx_iftrue or ctx_iffalse)() --- end - -scanners.doifelsepositiononpage = function() -- name page -- probably always realpageno - local c = collected[scanstring()] - local p = scaninteger() - doifelse(c and c.p == p) -end +implement { + name = "doifposition", + arguments = "string", + actions = function(name) + doif(collected[name]) + end +} -scanners.doifelseoverlapping = function() -- one two - doifelse(overlapping(scanstring(),scanstring())) -end +implement { + name = "doifelsepositiononpage", + arguments = { "string", "integer" }, + actions = function(name,p) + local c = collected[name] + doifelse(c and c.p == p) + end +} -scanners.doifelsepositionsonsamepage = function() -- list - doifelse(onsamepage(scanstring())) -end +implement { + name = "doifelseoverlapping", + arguments = { "string", "string" }, + actions = function(one,two) + doifelse(overlapping(one,two)) + end +} -scanners.doifelsepositionsonthispage = function() -- list - doifelse(onsamepage(scanstring(),tostring(texgetcount("realpageno")))) -end +implement { + name = "doifelsepositionsonsamepage", + arguments = "string", + actions = function(list) + doifelse(onsamepage(list)) + end +} --- scanners.columnofpos = function() --- context(columnofpos(scaninteger(),scandimen()) --- end +implement { + name = "doifelsepositionsonthispage", + arguments = "string", + actions = function(list) + doifelse(onsamepage(list,tostring(texgetcount("realpageno")))) + end +} -scanners.doifelsepositionsused = function() - doifelse(next(collected)) -end +implement { + name = "doifelsepositionsused", + actions = function() + doifelse(next(collected)) + end +} -scanners.markregionbox = function() -- box - markregionbox(scaninteger()) -end +implement { + name = "markregionbox", + arguments = "integer", + actions = markregionbox +} -scanners.setregionbox = function() -- box - setregionbox(scaninteger()) -end +implement { + name = "setregionbox", + arguments = "integer", + actions = setregionbox +} -scanners.markregionboxtagged = function() -- box tag - markregionbox(scaninteger(),scanstring()) -end +implement { + name = "markregionboxtagged", + arguments = { "integer", "string" }, + actions = markregionbox +} -scanners.markregionboxtaggedn = function() -- box tag n - markregionbox(scaninteger(),scanstring(),nil, - nil,nil,nil,nil,nil,scaninteger()) -end +implement { + name = "markregionboxtaggedn", + arguments = { "integer", "string", "integer" }, + actions = function(box,tag,n) + markregionbox(box,tag,nil,nil,nil,nil,nil,nil,n) + end +} -scanners.setregionboxtagged = function() -- box tag - setregionbox(scaninteger(),scanstring()) -end +implement { + name = "setregionboxtagged", + arguments = { "integer", "string" }, + actions = setregionbox +} -scanners.markregionboxcorrected = function() -- box tag - markregionbox(scaninteger(),scanstring(),true) -end +implement { + name = "markregionboxcorrected", + arguments = { "integer", "string", true }, + actions = markregionbox +} -scanners.markregionboxtaggedkind = function() -- box tag kind - markregionbox(scaninteger(),scanstring(),nil, - scaninteger(),scandimen(),scandimen(),scandimen(),scandimen()) -end +implement { + name = "markregionboxtaggedkind", + arguments = { "integer", "string", "integer", "dimen", "dimen", "dimen", "dimen" }, + actions = function(box,tag,n,d1,d2,d3,d4) + markregionbox(box,tag,nil,n,d1,d2,d3,d4) + end +} -scanners.reservedautoregiontag = function() - nofregions = nofregions + 1 - context(f_region(nofregions)) -end +implement { + name = "reservedautoregiontag", + actions = function() + nofregions = nofregions + 1 + context(f_region(nofregions)) + end +} -- statistics (at least for the moment, when testing) @@ -1409,7 +1566,6 @@ end) -- We support the low level positional commands too: local newsavepos = nodes.pool.savepos -local implement = interfaces.implement implement { name = "savepos", actions = function() context(newsavepos()) end } implement { name = "lastxpos", actions = function() context(gethpos()) end } diff --git a/tex/context/base/mkiv/back-res.lua b/tex/context/base/mkiv/back-res.lua index 2ca4a5ac8..4ee6d15d3 100644 --- a/tex/context/base/mkiv/back-res.lua +++ b/tex/context/base/mkiv/back-res.lua @@ -19,7 +19,6 @@ local scandimension = scanners.dimension local scanword = scanners.word local scanwhd = scanners.whd -local scanners = interfaces.scanners local implement = interfaces.implement local constants = interfaces.constants local variables = interfaces.variables diff --git a/tex/context/base/mkiv/buff-ini.lua b/tex/context/base/mkiv/buff-ini.lua index e4f01c03f..b4290f8b1 100644 --- a/tex/context/base/mkiv/buff-ini.lua +++ b/tex/context/base/mkiv/buff-ini.lua @@ -46,8 +46,6 @@ local getcommand = token.get_command local getcsname = token.get_csname local getnextchar = token.get_next_char -local scanners = interfaces.scanners - local variables = interfaces.variables local settings_to_array = utilities.parsers.settings_to_array local formatters = string.formatters @@ -623,21 +621,26 @@ end tokens.pickup = pickup -scanners.pickupbuffer = function() - local name = scanstring() - local start = scanstring() - local stop = scanstring() - local finish = scanstring() - local catcodes = scaninteger() - local doundent = scanboolean() - local data = pickup(start,stop) - if doundent or (autoundent and doundent == nil) then - data = undent(data) - end - buffers.assign(name,data,catcodes) - -- context[finish]() - context(finish) -end +implement { + name = "pickupbuffer", + actions = function() + -- let's pickup all here (no arguments) + local name = scanstring() + local start = scanstring() + local stop = scanstring() + local finish = scanstring() + local catcodes = scaninteger() + local doundent = scanboolean() + -- could be a scanner: + local data = pickup(start,stop) + if doundent or (autoundent and doundent == nil) then + data = undent(data) + end + buffers.assign(name,data,catcodes) + -- context[finish]() + context(finish) + end +} local function savebuffer(list,name,prefix) -- name is optional if not list or list == "" then diff --git a/tex/context/base/mkiv/buff-ver.lua b/tex/context/base/mkiv/buff-ver.lua index 2bf663704..ccb8ab0df 100644 --- a/tex/context/base/mkiv/buff-ver.lua +++ b/tex/context/base/mkiv/buff-ver.lua @@ -588,7 +588,7 @@ end local function realign(lines,strip) -- "yes", <number> local n if strip == v_yes then - n = math.huge + n = 0xFFFF for i=1, #lines do local spaces = find(lines[i],"%S") -- can be lpeg if not spaces then diff --git a/tex/context/base/mkiv/buff-ver.mkiv b/tex/context/base/mkiv/buff-ver.mkiv index 24aaa57d3..a3c27977f 100644 --- a/tex/context/base/mkiv/buff-ver.mkiv +++ b/tex/context/base/mkiv/buff-ver.mkiv @@ -1016,4 +1016,8 @@ \stopcontextdefinitioncode +%D This is \type {\asciimode} without the double comment hackery: + +\unexpanded\def\literalmode{\setcatcodetable\txtcatcodes} + \protect \endinput diff --git a/tex/context/base/mkiv/cldf-ini.lua b/tex/context/base/mkiv/cldf-ini.lua index 8e2d6f051..9569cf357 100644 --- a/tex/context/base/mkiv/cldf-ini.lua +++ b/tex/context/base/mkiv/cldf-ini.lua @@ -26,7 +26,7 @@ if not modules then modules = { } end modules ['cldf-ini'] = { -- 0.651 local foo = getcount("ctxcatcodes") -- 0.408 local foo = getcount(ctxcatcodes) -- local ctxcatcodes = tex.iscount("ctxcatcodes") --- maybe: (escape) or 0x2061 (apply function) or 0x2394 (software function ⎔) +-- maybe: (escape) or 0x2061 (apply function) or 0x2394 (software function ⎔) (old) -- note : tex.print == line with endlinechar appended -- todo : context("%bold{total: }%s",total) -- todo : context.documentvariable("title") @@ -58,6 +58,20 @@ if not modules then modules = { } end modules ['cldf-ini'] = { -- time (for the better or worse). There have been no fundamental changes for many years -- and performance has not changed much either. +-- The code here has evolved over time, and was already present in the early versions of +-- mkiv. However, it got adapted when feature were added to luatex, like the ability to +-- "print" nodes and later tokens. We use to have control over the method used (if only +-- for testing) but the older code has been removed now. The history is in the archives. +-- These were the controls: + +-- local tokenflushmode = true +-- local nodeflushmode = true +-- local scannerdefmode = true +-- local maxflushnodeindex = 0x10FFFF - 1 + +-- In earlier experiments a function tables was referred to as lua.calls and the primitive +-- \luafunctions was \luacall and we used our own implementation of a function table (more +-- indirectness). local format, stripstring = string.format, string.strip local next, type, tostring, tonumber, unpack, select, rawset = next, type, tostring, tonumber, unpack, select, rawset @@ -85,9 +99,6 @@ local texprint = tex.print -- each arg a separate line (not last in ----- texwrite = tex.write -- all 'space' and 'character' local texgetcount = tex.getcount --- local function texsprint(...) print("sprint",...) tex.sprint(...) end --- local function texprint (...) print("print", ...) tex.print (...) end - local isnode = node.is_node local writenode = node.write local copynodelist = node.copy_list @@ -118,19 +129,6 @@ local report_cld = logs.reporter("cld","stack") local processlines = true -- experiments.register("context.processlines", function(v) processlines = v end) -local tokenflushmode = true -local nodeflushmode = true -local scannerdefmode = true -local maxflushnodeindex = 0x10FFFF - 1 - --- tokenflushmode = false --- nodeflushmode = false --- scannerdefmode = false - --- In earlier experiments a function tables was referred to as lua.calls and the --- primitive \luafunctions was \luacall and we used our own implementation of --- a function table (more indirectness). - local trialtypesettingstate = createtoken("trialtypesettingstate").index function context.trialtypesetting() @@ -142,7 +140,9 @@ local showstackusage = false trackers.register("context.stack",function(v) showstackusage = v end) -local freed, nofused, noffreed = { }, 0, 0 +local freed = { } +local nofused = 0 +local noffreed = 0 local usedstack = function() return nofused, noffreed @@ -208,11 +208,11 @@ local initex = environment.initex storage.register("storage/storedfunctions", storedfunctions, "storage.storedfunctions") local f_resolve = nil -local p_resolve = ((1-lpegP("."))^1 / function(s) f_resolve = f_resolve[s] end * lpegP(".")^0)^1 +local p_resolve = ((1-lpegP("."))^1 / function(s) f_resolve = f_resolve[s] end * lpegP(".")^0)^1 local function resolvestoredfunction(str) if type(str) == "string" then - f_resolve = global + f_resolve = global -- namespace lpegmatch(p_resolve,str) return f_resolve else @@ -257,9 +257,11 @@ else end end -local registerfunction = function(f,direct) -- either f=code or f=namespace,direct=name - local slot, func - if noffreed > 0 then +local registerfunction = function(f,direct,slot) -- either f=code or f=namespace,direct=name + local func + if slot then + -- already used + elseif noffreed > 0 then slot = freed[noffreed] freed[noffreed] = nil noffreed = noffreed - 1 @@ -269,12 +271,8 @@ local registerfunction = function(f,direct) -- either f=code or f=namespace,dire end if direct then if initex then - func = function(...) - expose(slot,f,...) - end - if initex then - storedfunctions[slot] = f - end + func = function(...) expose(slot,f,...) end + storedfunctions[slot] = f else func = resolvestoredfunction(f) end @@ -357,73 +355,46 @@ do end --- so far - --- The next hack is a convenient way to define scanners at the Lua end and --- get them available at the TeX end. There is some dirty magic needed to --- prevent overload during format loading. +-- The next hack is a convenient way to define scanners at the Lua end and get them +-- available at the TeX end. There is some dirty magic needed to prevent overload +-- during format loading. Nowadays we prefer to use the slightly less efficient way +-- of defining interfaces using the implementer. There is a little more overhead in +-- defining as well as runtime overhead, but we accept that. -- interfaces.scanners.foo = function() context("[%s]",tokens.scanners.string()) end : \scan_foo -interfaces.storedscanners = interfaces.storedscanners or { } -local storedscanners = interfaces.storedscanners +local storedscanners = interfaces.storedscanners or { } +local interfacescanners = { } +local privatenamespace = "clf_" -storage.register("interfaces/storedscanners", storedscanners, "interfaces.storedscanners") +interfaces.storedscanners = storedscanners -local interfacescanners = setmetatablenewindex(function(t,k,v) - rawset(t,k,v) - if storedscanners[k] then - -- report_cld("warning: scanner %a is already set (mode 1a)",k) - -- os.exit() - -- \scan_<k> is already in the format - -- report_cld("using interface scanner: %s",k) - elseif scannerdefmode then - -- report_cld("installing interface scanner: %s (mode 1b)",k) - -- local n = registerfunction(interfaces.scanners[k],true) - local n = registerfunction("interfaces.scanners."..k,true) - storedscanners[k] = n - local name = "clf_" .. k - setluatoken(name,n,"global") -- todo : protected and "protected" or "" - else - -- report_cld("installing interface scanner: %s (mode 1c)",k) - storedscanners[k] = true - context("\\installctxscanner{clf_%s}{interfaces.scanners.%s}",k,k) - end - -- rawset(t,k,v) -end) +storage.register("interfaces/storedscanners", storedscanners, "interfaces.storedscanners") -function interfaces.registerscanner(name,action,protected,public,value) +local function registerscanner(name,action,protected,public,value) rawset(interfacescanners,name,action) - if storedscanners[name] then - -- report_cld("warning: scanner %a is already set (mode 2a)",name) - -- os.exit() - -- \scan_<k> is already in the format - -- report_cld("using interface scanner: %s",k) - elseif scannerdefmode then - -- report_cld("installing interface scanner: %s (mode 2b)",name) - -- local n = registerfunction(action,true) -- todo - local n = registerfunction("interfaces.scanners."..name,true) - storedscanners[name] = n - local name = public and name or ("clf_" .. name) - setluatoken(name,n,"global",protected and "protected" or "",value and "value" or "") - else - storedscanners[name] = true - -- report_cld("installing interface scanner: %s (mode 2c)",name) - context("\\install%sctxscanner{%s%s}{interfaces.scanners.%s}", - protected and "protected" or "", - public and "" or "clf_", - name, - name - ) - end - -- rawset(interfacescanners,name,action) + local n = storedscanners[name] + n = registerfunction("interfaces.scanners."..name,true,n) + storedscanners[name] = n + name = public and name or (privatenamespace .. name) + setluatoken(name,n,"global",protected and "protected" or "",value and "value" or "") end +interfaces.registerscanner = registerscanner + +function interfaces.knownscanner(name) + return interfacescanners[name] +end + +setmetatablenewindex(interfacescanners, function(t,k,v) + report_cld("don't register scanner %a directly",k) + -- registerscanner(k,v) +end) + interfaces.scanners = storage.mark(interfacescanners) -interfaces._ = interfaces.scanners context.functions = { - register = registerfunction, + register = function(qualifiedname) return registerfunction(qualifiedname) end, -- only one argument unregister = unregisterfunction, reserve = reservefunction, known = knownfunctions, @@ -448,7 +419,7 @@ function commands.ctxresetter(name) -- to be checked return function() if storedscanners[name] then rawset(interfacescanners,name,dummy) - context.resetctxscanner("clf_" .. name) + context.resetctxscanner(privatenamespace .. name) end end end @@ -540,25 +511,11 @@ local endstripper = beginstripper * lpegP(-1) local justaspace = space * lpegCc("") local justanewline = newline * lpegCc("") -local function n_content(s) - flush(contentcatcodes,s) -end - -local function n_verbose(s) - flush(vrbcatcodes,s) -end - -local function n_endofline() - flush(currentcatcodes," \r") -end - -local function n_emptyline() - flushdirect(currentcatcodes,"\r") -end - -local function n_simpleline() - flush(currentcatcodes," \r") -end +local function n_content (s) flush (contentcatcodes,s ) end +local function n_verbose (s) flush (vrbcatcodes, s ) end +local function n_endofline () flush (currentcatcodes," \r") end +local function n_emptyline () flushdirect(currentcatcodes,"\r" ) end +local function n_simpleline() flush (currentcatcodes," \r") end local n_exception = "" @@ -646,7 +603,7 @@ function context.newverbosehandler(specification) -- a special variant for e.g. specification = specification or { } -- local f_line = specification.line or function() flushdirect("\r") end - local f_space = specification.space or function() flush(" ") end + local f_space = specification.space or function() flush (" ") end local f_content = specification.content or n_verbose local f_before = specification.before local f_after = specification.after @@ -700,20 +657,6 @@ function context.printlines(str,raw) -- todo: see if via file is useable end end --- function context.printtable(t,separator) -- todo: see if via file is useable --- if separator == nil or separator == true then --- separator = "\r" --- elseif separator == "" then --- separator = false --- end --- for i=1,#t do --- context(t[i]) -- we need to go through catcode handling --- if separator then --- context(separator) --- end --- end --- end - function context.printtable(t,separator) -- todo: see if via file is useable if separator == nil or separator == true then separator = "\r" @@ -730,22 +673,6 @@ end local containseol = patterns.containseol -local s_cldl_option_b = "[\\cldl" -local s_cldl_option_f = "[\\cldl" -- add space (not needed) -local s_cldl_option_e = "]" -local s_cldl_option_s = "\\cldl" ------ s_cldl_option_d = "\\cldd" -local s_cldl_option_d = s_cldl_option_s -local s_cldl_argument_b = "{\\cldl" -local s_cldl_argument_f = "{\\cldl " -local s_cldl_argument_e = "}" - --- local s_cldl_option_b = "[" --- local s_cldl_option_f = "" -- add space (not needed) --- local s_cldl_option_s = "" --- local s_cldl_argument_b = "{" --- local s_cldl_argument_f = "{ " - local t_cldl_luafunction = newtoken("luafunctioncall",0) local lua_expandable_call_token_code = token.command_id and token.command_id("lua_expandable_call") @@ -756,17 +683,12 @@ directives.register("context.sorthash",function(v) end) local function writer(parent,command,...) -- already optimized before call - if type(command) == "string" then -- for now flush(currentcatcodes,command) -- todo: ctx|prt|texcatcodes else flush(command) -- todo: ctx|prt|texcatcodes end - local direct = false - -- local t = { ... } - -- for i=1,#t do - -- local ti = t[i] for i=1,select("#",...) do local ti = select(i,...) if direct then @@ -849,15 +771,7 @@ local function writer(parent,command,...) -- already optimized before call local tj = ti[1] if type(tj) == "function" then tj = storefunction(tj) - if tokenflushmode then - -- if newtoken then - flush(currentcatcodes,"[",newtoken(tj,lua_expandable_call_token_code),"]") - -- else - -- flush(currentcatcodes,"[",t_cldl_luafunction,tj,"]") - -- end - else - flush(currentcatcodes,s_cldl_option_b,tj,s_cldl_option_e) - end + flush(currentcatcodes,"[",newtoken(tj,lua_expandable_call_token_code),"]") else flush(currentcatcodes,"[",tj,"]") end @@ -867,15 +781,7 @@ local function writer(parent,command,...) -- already optimized before call local tj = ti[j] if type(tj) == "function" then tj = storefunction(tj) - if tokenflushmode then - -- if newtoken then - flush(currentcatcodes,"[",newtoken(tj,lua_expandable_call_token_code),j == tn and "]" or ",") - -- else - -- flush(currentcatcodes,"[",t_cldl_luafunction,tj,j == tn and "]" or ",") - -- end - else - flush(currentcatcodes,s_cldl_option_s,tj,j == tn and "]" or ",") - end + flush(currentcatcodes,"[",newtoken(tj,lua_expandable_call_token_code),j == tn and "]" or ",") else if j == tn then flush(currentcatcodes,tj,"]") @@ -888,15 +794,7 @@ local function writer(parent,command,...) -- already optimized before call elseif typ == "function" then -- todo: ctx|prt|texcatcodes ti = storefunction(ti) - if tokenflushmode then - -- if newtoken then - flush(currentcatcodes,"{",newtoken(ti,lua_expandable_call_token_code),"}") - -- else - -- flush(currentcatcodes,"{",t_cldl_luafunction,ti,"}") - -- end - else - flush(currentcatcodes,s_cldl_argument_f,ti,s_cldl_argument_e) - end + flush(currentcatcodes,"{",newtoken(ti,lua_expandable_call_token_code),"}") elseif typ == "boolean" then if ti then flushdirect(currentcatcodes,"\r") @@ -906,16 +804,7 @@ local function writer(parent,command,...) -- already optimized before call elseif typ == "thread" then report_context("coroutines not supported as we cannot yield across boundaries") elseif isnode(ti) then -- slow | why {} here ? - if nodeflushmode then - local n = tonut(ti) - if n <= maxflushnodeindex then - flush(currentcatcodes,"{",ti,"}") - else - flush(currentcatcodes,s_cldl_argument_b,storenode(ti),s_cldl_argument_e) - end - else - flush(currentcatcodes,s_cldl_argument_b,storenode(ti),s_cldl_argument_e) - end + flush(currentcatcodes,"{",ti,"}") else local s = tostring(ti) if s then @@ -924,109 +813,47 @@ local function writer(parent,command,...) -- already optimized before call report_context("error: %a gets a weird argument %a",command,ti) end end --- else --- local n = isnode(ti) --- if n then --- if nodeflushmode and n <= maxflushnodeindex then --- flush(ti) --- else --- flush(currentcatcodes,s_cldl_argument_b,storenode(ti),s_cldl_argument_e) --- end --- else --- report_context("error: %a gets a weird argument %a",command,ti) --- end --- end + -- else + -- local n = isnode(ti) + -- if n then + -- flush(ti) + -- else + -- report_context("error: %a gets a weird argument %a",command,ti) + -- end end end end -local core +local toks = tokens.cache +context.tokenizedcs = toks -if tokenflushmode then -- combine them - - local toks = tokens.cache - - context.tokenizedcs = toks - - core = setmetatableindex(function(parent,k) - local t - local f = function(first,...) - if not t then - t = toks[k] - end - if first == nil then - flush(t) - else - return writer(context,t,first,...) - end +local core = setmetatableindex(function(parent,k) + local t + local f = function(first,...) + if not t then + t = toks[k] end - parent[k] = f - return f - end) - --- core = setmetatableindex(function(parent,k) --- local t --- local f = function(first,...) --- if not t then --- t = toks[k] --- end --- local f = function(first,...) --- if first == nil then --- flush(t) --- else --- return writer(context,t,first,...) --- end --- end --- parent[k] = f --- if first == nil then --- flush(t) --- else --- return writer(context,t,first,...) --- end --- end --- parent[k] = f --- return f --- end) - - core.cs = setmetatableindex(function(parent,k) - local t - local f = function() - if not t then - t = toks[k] - end + if first == nil then flush(t) + else + return writer(context,t,first,...) end - parent[k] = f - return f - end) - -else - - context.tokenizedcs = false - - core = setmetatableindex(function(parent,k) - local c = "\\" .. k - local f = function(first,...) - if first == nil then - flush(currentcatcodes,c) - else - return writer(context,c,first,...) - end - end - parent[k] = f - return f - end) + end + parent[k] = f + return f +end) - core.cs = setmetatableindex(function(parent,k) - local c = "\\" .. k -- tostring(k) - local f = function() - flush(currentcatcodes,c) +core.cs = setmetatableindex(function(parent,k) + local t + local f = function() + if not t then + t = toks[k] end - parent[k] = f - return f - end) - -end + flush(t) + end + parent[k] = f + return f +end) local indexer = function(parent,k) if type(k) == "string" then @@ -1122,15 +949,7 @@ local caller = function(parent,f,a,...) elseif typ == "function" then -- ignored: a ... f = storefunction(f) - if tokenflushmode then - -- if newtoken then - flush(currentcatcodes,"{",newtoken(f,lua_expandable_call_token_code),"}") - -- else - -- flush(currentcatcodes,"{",t_cldl_luafunction,f,"}") - -- end - else - flush(currentcatcodes,s_cldl_argument_b,f,s_cldl_argument_e) -- todo: ctx|prt|texcatcodes - end + flush(currentcatcodes,"{",newtoken(f,lua_expandable_call_token_code),"}") elseif typ == "boolean" then if f then if a ~= nil then @@ -1149,16 +968,7 @@ local caller = function(parent,f,a,...) elseif typ == "thread" then report_context("coroutines not supported as we cannot yield across boundaries") elseif isnode(f) then -- slow - if nodeflushmode then - local n = tonut(f) - if n <= maxflushnodeindex then - flush(f) - else - flush(currentcatcodes,s_cldl_option_s,storenode(f)," ") - end - else - flush(currentcatcodes,s_cldl_option_s,storenode(f)," ") - end + flush(f) else local s = tostring(f) if s then @@ -1167,29 +977,20 @@ local caller = function(parent,f,a,...) report_context("error: %a gets a weird argument %a","context",f) end end --- else --- local n = isnode(f) --- if n then --- if nodeflushmode and n <= maxflushnodeindex then --- flush(f) --- else --- flush(currentcatcodes,s_cldl_option_s,storenode(f)," ") --- end --- else --- report_context("error: %a gets a weird argument %a","context",f) --- end --- end + -- else + -- local n = isnode(f) + -- if n then + -- flush(f) + -- else + -- report_context("error: %a gets a weird argument %a","context",f) + -- end end end context.nodes = { -- todo store = storenode, flush = function(n) - if nodeflushmode and tonut(n) <= maxflushnodeindex then - flush(n) - else - flush(currentcatcodes,d and s_cldl_option_d or s_cldl_option_s,storenode(n)," ") - end + flush(n) end, } @@ -1198,11 +999,7 @@ context.nuts = { -- todo return storenode(tonut(n)) end, flush = function(n,d) - if nodeflushmode and n <= maxflushnodeindex then - flush(tonode(n)) - else - flush(currentcatcodes,d and s_cldl_option_d or s_cldl_option_s,storenode(tonode(n))," ") - end + flush(tonode(n)) end, } @@ -1640,22 +1437,7 @@ function context.newindexer(catcodes,cmdcodes) contentcatcodes = savedcatcodes end - if tokenflushmode then - - handler.cs = core.cs - - else - - handler.cs = setmetatableindex(function(parent,k) - local c = "\\" .. k -- tostring(k) - local f = function() - flush(cmdcodes,c) - end - parent[k] = f - return f - end) - - end + handler.cs = core.cs setmetatableindex(handler,indexer) setmetatablecall (handler,caller) @@ -1675,23 +1457,6 @@ do -- formatted.command([catcodes,]format[,...]) --- local function formattedflush(parent,c,catcodes,fmt,...) --- if type(catcodes) == "number" then --- if fmt then --- local result --- pushcatcodes(catcodes) --- result = writer(parent,c,formatters[fmt](...)) --- popcatcodes() --- return result --- else --- -- no need to change content catcodes --- return writer(parent,c) --- end --- else --- return writer(parent,c,formatters[catcodes](fmt,...)) --- end --- end - local function formattedflush(parent,c,catcodes,fmt,...) if not catcodes then return writer(parent,c) @@ -1708,51 +1473,26 @@ do end end - local indexer - - if tokenflushmode then -- combine them - - local toks = tokens.cache + local toks = tokens.cache - indexer = function(parent,k) - if type(k) == "string" then - local t - local f = function(first,...) - if not t then - t = toks[k] - end - if first == nil then - flush(t) - else - return formattedflush(parent,t,first,...) - end + local indexer = function(parent,k) + if type(k) == "string" then + local t + local f = function(first,...) + if not t then + t = toks[k] end - parent[k] = f - return f - else - return context -- catch - end - end - - else - - indexer = function(parent,k) - if type(k) == "string" then - local c = "\\" .. k - local f = function(first,...) - if first == nil then - flush(currentcatcodes,c) - else - return formattedflush(parent,c,first,...) - end + if first == nil then + flush(t) + else + return formattedflush(parent,t,first,...) end - parent[k] = f - return f - else - return context -- catch end + parent[k] = f + return f + else + return context -- catch end - end -- formatted([catcodes,]format[,...]) diff --git a/tex/context/base/mkiv/cldf-int.lua b/tex/context/base/mkiv/cldf-int.lua index 86420f422..d869f3154 100644 --- a/tex/context/base/mkiv/cldf-int.lua +++ b/tex/context/base/mkiv/cldf-int.lua @@ -313,18 +313,22 @@ else end function interfaces.tolist(t) - local r = { } - for i=1,#t do - r[i] = t[i] - end - local n = #r - for k,v in table.sortedhash(t) do - if type(k) ~= "number" then - n = n + 1 - r[n] = k .. "=" .. v + if t then + local r = { } + for i=1,#t do + r[i] = t[i] + end + local n = #r + for k,v in table.sortedhash(t) do + if type(k) ~= "number" then + n = n + 1 + r[n] = k .. "=" .. v + end end + return concat(r,", ") + else + return "" end - return concat(r,", ") end -- \startluacode @@ -358,9 +362,9 @@ end -- context.startnarrower() -- end -- --- local function stopmore(opt_1) +-- local function stopmore() -- context.stopnarrower() --- context("stop more, options: %s",interfaces.tolist(opt_1)) +-- context("stop more") -- context.stopnarrower() -- end -- diff --git a/tex/context/base/mkiv/cldf-lmt.lua b/tex/context/base/mkiv/cldf-lmt.lua index ab25f962e..4855372fa 100644 --- a/tex/context/base/mkiv/cldf-lmt.lua +++ b/tex/context/base/mkiv/cldf-lmt.lua @@ -8,8 +8,9 @@ if not modules then modules = { } end modules ['cldf-lmt'] = { local next, load = next, load -local setmetatableindex = table.setmetatableindex -local serialize = table.serialize +local setmetatableindex = table.setmetatableindex +local setmetatablenewindex = table.setmetatablenewindex +local serialize = table.serialize local random = math.random local randomseed = math.randomseed @@ -30,8 +31,12 @@ local scancardinal = scanners.luacardinal local scannumber = scanners.luanumber local scanargument = scanners.argument local scantoken = scanners.token +local scancsname = scanners.csname + local getindex = token.get_index + local texsetdimen = tex.setdimen +local texget = tex.get local values = tokens.values local none_code = values.none @@ -57,7 +62,7 @@ implement { value = true, actions = function(b) local n = scanword() - if b then + if b == "value" then context("%.99g",floats[n] or 0) else floats[n] = scannumber(true) @@ -72,7 +77,7 @@ implement { value = true, actions = function(b) local n = scanword() - if b then + if b == "value" then context("%i",integers[n] or 0) else integers[n] = scaninteger(true) @@ -86,7 +91,7 @@ implement { value = true, actions = function(b) local n = scanword() - if b then + if b == "value" then return integer_code, integers[n] or 0 else integers[n] = scancount(true) @@ -100,7 +105,7 @@ implement { value = true, actions = function(b) local n = scanword() - if b then + if b == "value" then return dimension_code, integers[n] or 0 else integers[n] = scandimen(false,false,true) @@ -114,8 +119,8 @@ implement { value = true, actions = function(b) local n = scanword() - if b then - context("%d",cardinals[n] or 0) + if b == "value" then + context("%1.0f",cardinals[n] or 0) else cardinals[n] = scancardinal(true) end @@ -128,8 +133,8 @@ implement { value = true, actions = function(b) local n = scanword() - if b then - context("%d",floats[n] or integers[n] or cardinals[n] or 0) + if b == "value" then + context("%N",floats[n] or integers[n] or cardinals[n] or 0) -- maybe %N else -- floats[n] = scanfloat(true) floats[n] = scannumber(true) @@ -142,7 +147,7 @@ implement { public = true, value = true, actions = function(b) - if b then + if b == "value" then return integer_code, random(scaninteger(),scaninteger()) else randomseed(scaninteger(true)) @@ -243,7 +248,7 @@ implement { d = d[scaninteger()] end local x = scaninteger() - if b then + if b == "value" then local code = a.code if code == float_code then context("%.99g",d[x]) @@ -258,7 +263,6 @@ implement { end, } - implement { name = "arrayequals", public = true, @@ -275,7 +279,7 @@ implement { d = d[scaninteger()] end local x = scaninteger() - if b then + if b == "value" then return boolean_code, a.scanner() == d[x] end end @@ -299,7 +303,7 @@ implement { d = d[scaninteger()] end local x = scaninteger() - if b then + if b == "value" then local v = a.scanner() local d = d[x] if d < v then @@ -379,7 +383,7 @@ implement { public = true, value = true, actions = function(b) - if b then + if b == "value" then local how = scanword() local what = scandimen() if how then @@ -417,7 +421,7 @@ local setdata = tokens.setdata local report = logs.reporter("lua table") ------ ctxsprint = context.sprint +local ctxsprint = context.sprint -- we could have an extra one that collects all end of grouped actions -- so that we dispose more in one go but it doesn's pay off @@ -607,3 +611,109 @@ context.luatables = { inspect = inspectluatable, show = showluatables, } + +-- Here's another mechanism ... + +local tables = { } +local stack = setmetatableindex("table") + +interfaces.implement { + name = "droptablegroup", + public = true, + actions = function() + local g = texget("currentgrouplevel") -- todo: tex.getgrouplevel() + local s = stack[g] + if s then + for t, data in next, s do + for k, v in next, data do + t[k] = v + end + end + stack[g] = { } + end + end, +} + +local ctx_atendofgroup = context.core.cs.atendofgroup +local ctx_droptablegroup = context.core.cs.droptablegroup + +local function handletable(t,b,array) + if b == "value" then + local k = array and scaninteger() or scanargument() + local v = t[k] + if v then + context(v) + end + else + local data = scanargument() + data = load("return {" .. data .. "}") + if data then + data = data() + if data then + local l = t.level + local g = texget("currentgrouplevel") -- todo: tex.getgrouplevel() + local s = stack[g] + local d = s[t] + if not d then + d = { } + s[t] = d + ctx_atendofgroup() + ctx_droptablegroup() + end + for k, v in next, data do + if not d[k] then + d[k] = t[k] + end + t[k] = v + end + if b == "global" then + for k, v in next, stack do + local t = s[t] + if t then + for k, v in next, data do + if t[k] then + t[k] = nil + end + end + end + end + end + end + end + end +end + +local function newtable(array) + local name = scancsname(true) + if not tables[name] then + local t = { } + tables[name] = t + interfaces.implement { + name = name, + public = true, + value = true, + actions = function(b) + handletable(t,b,array) + end, + } + else + -- already defined + end +end + +implement { + name = "newhashedtable", + protected = true, + public = true, + actions = newtable, +} + +implement { + name = "newindexedtable", + protected = true, + public = true, + actions = function() newtable(true) end, +} + +context.hashedtables = setmetatableindex(function(t,k) return tables[k] end) +context.indexedtables = context.hashedtables diff --git a/tex/context/base/mkiv/cldf-scn.lua b/tex/context/base/mkiv/cldf-scn.lua index 1e5fe221d..fc4ea1e4a 100644 --- a/tex/context/base/mkiv/cldf-scn.lua +++ b/tex/context/base/mkiv/cldf-scn.lua @@ -8,32 +8,35 @@ if not modules then modules = { } end modules ['cldf-scn'] = { local load, type, tostring = load, type, tostring -local formatters = string.formatters -local char = string.char -local concat = table.concat +local formatters = string.formatters +local char = string.char +local concat = table.concat -local lpegmatch = lpeg.match -local p_unquoted = lpeg.Cs(lpeg.patterns.unquoted) +local lpegmatch = lpeg.match +local p_unquoted = lpeg.Cs(lpeg.patterns.unquoted) -local f_action_f = formatters["action%s(%s)"] -local f_action_s = formatters["local action%s = action[%s]"] -local f_command = formatters["local action = tokens._action\n%\nt\nreturn function(%s) return %s end"] +local f_action_f = formatters["action%s(%s)"] +local f_action_s = formatters["local action%s = action[%s]"] +local f_command = formatters["local action = tokens._action\n%\nt\nreturn function(%s) return %s end"] -local interfaces = interfaces -local commands = commands -local scanners = interfaces.scanners -local register = interfaces.registerscanner +local interfaces = interfaces +local commands = commands +local register = interfaces.registerscanner +local knownscanner = interfaces.knownscanner -local compile = tokens.compile or function() end -local presets = tokens.presets +local compile = tokens.compile or function() end +local presets = tokens.presets -local dummy = function() end +local dummy = function() end -local report = logs.reporter("interfaces","implementor") +local report = logs.reporter("interfaces","implementor") function interfaces.implement(specification) + local name = specification.name + if name == "" then + name = nil + end local actions = specification.actions - local name = specification.name local arguments = specification.arguments local private = specification.scope == "private" local onlyonce = specification.onlyonce @@ -45,9 +48,6 @@ function interfaces.implement(specification) end return end - if name == "" then - name = nil - end local p = arguments and presets[arguments] if p then arguments = p @@ -74,8 +74,8 @@ function interfaces.implement(specification) if not name then return scanner end - if scanners[name] and not specification.overload then - report("warning: 'scanners.%s' is redefined",name) + if knownscanner(name) and not specification.overload then + report("warning: interface scanner %a is overloaded",name) end register(name,scanner,specification.protected,specification.public,specification.value) if private then @@ -160,12 +160,3 @@ interfaces.defined = tokens.defined interfaces.setmacro = tokens.setters.macro interfaces.setcount = tokens.setters.count interfaces.setdimen = tokens.setters.dimen - -interfaces.strings = table.setmetatableindex(function(t,k) - local v = { } - for i=1,k do - v[i] = "string" - end - t[k] = v - return v -end) diff --git a/tex/context/base/mkiv/colo-ini.mkxl b/tex/context/base/mkiv/colo-ini.mkxl index 63d29d0a6..724316629 100644 --- a/tex/context/base/mkiv/colo-ini.mkxl +++ b/tex/context/base/mkiv/colo-ini.mkxl @@ -250,8 +250,8 @@ %D The following command is obsolete: -\unexpanded\def\startcolorpage {\startcolor[\ifempty\maintextcolor\defaulttextcolor\else\maintextcolor\fi]} -\unexpanded\def\stopcolorpage {\stopcolor} +\unexpanded\def\startcolorpage{\startcolor[\ifempty\maintextcolor\defaulttextcolor\else\maintextcolor\fi]} +\unexpanded\def\stopcolorpage {\stopcolor} \unexpanded\def\getcolorattributevalue#1#2% obsolete, use \thecolorattribute instead ... {\begingroup diff --git a/tex/context/base/mkiv/cont-new.mkiv b/tex/context/base/mkiv/cont-new.mkiv index bdee367d1..3b01c297e 100644 --- a/tex/context/base/mkiv/cont-new.mkiv +++ b/tex/context/base/mkiv/cont-new.mkiv @@ -13,7 +13,7 @@ % \normalend % uncomment this to get the real base runtime -\newcontextversion{2020.06.20 13:33} +\newcontextversion{2020.06.25 10:55} %D This file is loaded at runtime, thereby providing an excellent place for hacks, %D patches, extensions and new features. There can be local overloads in cont-loc diff --git a/tex/context/base/mkiv/context.mkiv b/tex/context/base/mkiv/context.mkiv index f5d02a708..bbefc17e6 100644 --- a/tex/context/base/mkiv/context.mkiv +++ b/tex/context/base/mkiv/context.mkiv @@ -45,7 +45,7 @@ %D {YYYY.MM.DD HH:MM} format. \edef\contextformat {\jobname} -\edef\contextversion{2020.06.20 13:33} +\edef\contextversion{2020.06.25 10:55} \edef\contextkind {beta} %D Kind of special: diff --git a/tex/context/base/mkiv/context.mkxl b/tex/context/base/mkiv/context.mkxl index e69d387f2..45a8e2f2f 100644 --- a/tex/context/base/mkiv/context.mkxl +++ b/tex/context/base/mkiv/context.mkxl @@ -29,7 +29,7 @@ %D {YYYY.MM.DD HH:MM} format. \edef\contextformat {\jobname} -\edef\contextversion{2020.06.20 13:33} +\edef\contextversion{2020.06.25 10:55} \edef\contextkind {beta} %D Kind of special: diff --git a/tex/context/base/mkiv/file-mod.lua b/tex/context/base/mkiv/file-mod.lua index 10a187178..c10e557c7 100644 --- a/tex/context/base/mkiv/file-mod.lua +++ b/tex/context/base/mkiv/file-mod.lua @@ -246,18 +246,16 @@ function environment.useluamodule(list) end end -local strings = interfaces.strings - implement { name = "usemodules", actions = environment.usemodules, - arguments = strings[2] + arguments = "2 strings", } implement { name = "doifelseolderversion", actions = function(one,two) commands.doifelse(comparedversion(one,two) >= 0) end, - arguments = strings[2] + arguments = "2 strings" } implement { diff --git a/tex/context/base/mkiv/font-ctx.lua b/tex/context/base/mkiv/font-ctx.lua index 9e59c66bc..3b2676667 100644 --- a/tex/context/base/mkiv/font-ctx.lua +++ b/tex/context/base/mkiv/font-ctx.lua @@ -1168,69 +1168,56 @@ local specifiers = { } do -- else too many locals - ----- ctx_setdefaultfontname = context.fntsetdefname - ----- ctx_setsomefontname = context.fntsetsomename - ----- ctx_setemptyfontsize = context.fntsetnopsize - ----- ctx_setsomefontsize = context.fntsetsomesize - ----- ctx_letvaluerelax = context.letvaluerelax + local starttiming = statistics.starttiming + local stoptiming = statistics.stoptiming - local starttiming = statistics.starttiming - local stoptiming = statistics.stoptiming + local setmacro = tokens.setters.macro - local scanners = tokens.scanners - local scanstring = scanners.string - local scaninteger = scanners.integer - local scannumber = scanners.number - local scanboolean = scanners.boolean - - local setmacro = tokens.setters.macro - local scanners = interfaces.scanners - - -- function commands.definefont_one(str) - - scanners.definefont_one = function() - local str = scanstring() - - starttiming(fonts) - if trace_defining then - report_defining("memory usage before: %s",statistics.memused()) - report_defining("start stage one: %s",str) - end - local fullname, size = lpegmatch(splitpattern,str) - local lookup, name, sub, method, detail = getspecification(fullname) - if not name then - report_defining("strange definition %a",str) - -- ctx_setdefaultfontname() - elseif name == "unknown" then - -- ctx_setdefaultfontname() - else - -- ctx_setsomefontname(name) - setmacro("somefontname",name,"global") - end - -- we can also use a count for the size - if size and size ~= "" then - local mode, size = lpegmatch(sizepattern,size) - if size and mode then - texsetcount("scaledfontmode",mode) - -- ctx_setsomefontsize(size) - setmacro("somefontsize",size) + implement { + name = "definefont_one", + arguments = "string", + actions = function(str) + starttiming(fonts) + if trace_defining then + report_defining("memory usage before: %s",statistics.memused()) + report_defining("start stage one: %s",str) + end + local fullname, size = lpegmatch(splitpattern,str) + local lookup, name, sub, method, detail = getspecification(fullname) + if not name then + report_defining("strange definition %a",str) + -- ctx_setdefaultfontname() + elseif name == "unknown" then + -- ctx_setdefaultfontname() + else + -- ctx_setsomefontname(name) + setmacro("somefontname",name,"global") + end + -- we can also use a count for the size + if size and size ~= "" then + local mode, size = lpegmatch(sizepattern,size) + if size and mode then + texsetcount("scaledfontmode",mode) + -- ctx_setsomefontsize(size) + setmacro("somefontsize",size) + else + texsetcount("scaledfontmode",0) + -- ctx_setemptyfontsize() + end + elseif true then + -- so we don't need to check in tex + texsetcount("scaledfontmode",2) + -- ctx_setemptyfontsize() else texsetcount("scaledfontmode",0) -- ctx_setemptyfontsize() end - elseif true then - -- so we don't need to check in tex - texsetcount("scaledfontmode",2) - -- ctx_setemptyfontsize() - else - texsetcount("scaledfontmode",0) - -- ctx_setemptyfontsize() - end - specification = definers.makespecification(str,lookup,name,sub,method,detail,size) - if trace_defining then - report_defining("stop stage one") + specification = definers.makespecification(str,lookup,name,sub,method,detail,size) + if trace_defining then + report_defining("stop stage one") + end end - end + } local function nice_cs(cs) return (gsub(cs,".->", "")) @@ -1244,179 +1231,228 @@ do -- else too many locals combinefeatures = v end) - scanners.definefont_two = function() - local global = scanboolean() -- \ifx\fontclass\empty\s!false\else\s!true\fi - local cs = scanstring () -- {#csname}% - local str = scanstring () -- \somefontfile - local size = scaninteger() -- \d_font_scaled_font_size - local inheritancemode = scaninteger() -- \c_font_feature_inheritance_mode - local classfeatures = scanstring () -- \m_font_class_features - local fontfeatures = scanstring () -- \m_font_features - local classfallbacks = scanstring () -- \m_font_class_fallbacks - local fontfallbacks = scanstring () -- \m_font_fallbacks - local mathsize = scaninteger() -- \fontface - local textsize = scaninteger() -- \d_font_scaled_text_face - local relativeid = scaninteger() -- \relativefontid - local classgoodies = scanstring () -- \m_font_class_goodies - local goodies = scanstring () -- \m_font_goodies - local classdesignsize = scanstring () -- \m_font_class_designsize - local fontdesignsize = scanstring () -- \m_font_designsize - local scaledfontmode = scaninteger() -- \scaledfontmode - - if trace_defining then - report_defining("start stage two: %s, size %s, features %a & %a, mode %a",str,size,classfeatures,fontfeatures,inheritancemode) - end - -- name is now resolved and size is scaled cf sa/mo - local lookup, name, sub, method, detail = getspecification(str or "") - -- new (todo: inheritancemode) - local designsize = fontdesignsize ~= "" and fontdesignsize or classdesignsize or "" - local designname = designsizefilename(name,designsize,size) - if designname and designname ~= "" then - if trace_defining or trace_designsize then - report_defining("remapping name %a, specification %a, size %a, designsize %a",name,designsize,size,designname) - end - -- we don't catch detail here - local o_lookup, o_name, o_sub, o_method, o_detail = getspecification(designname) - if o_lookup and o_lookup ~= "" then lookup = o_lookup end - if o_method and o_method ~= "" then method = o_method end - if o_detail and o_detail ~= "" then detail = o_detail end - name = o_name - sub = o_sub - end - -- so far - -- some settings can have been overloaded - if lookup and lookup ~= "" then - specification.lookup = lookup - end - if relativeid and relativeid ~= "" then -- experimental hook - local id = tonumber(relativeid) or 0 - specification.relativeid = id > 0 and id - end - -- - specification.name = name - specification.size = size - specification.sub = (sub and sub ~= "" and sub) or specification.sub - specification.mathsize = mathsize - specification.textsize = textsize - specification.goodies = goodies - specification.cs = cs - specification.global = global - specification.scalemode = scaledfontmode -- context specific - if detail and detail ~= "" then - specification.method = method or "*" - specification.detail = detail - elseif specification.detail and specification.detail ~= "" then - -- already set - elseif inheritancemode == 0 then - -- nothing - elseif inheritancemode == 1 then - -- fontonly - if fontfeatures and fontfeatures ~= "" then - specification.method = "*" - specification.detail = fontfeatures - end - if fontfallbacks and fontfallbacks ~= "" then - specification.fallbacks = fontfallbacks - end - elseif inheritancemode == 2 then - -- classonly - if classfeatures and classfeatures ~= "" then - specification.method = "*" - specification.detail = classfeatures - end - if classfallbacks and classfallbacks ~= "" then - specification.fallbacks = classfallbacks - end - elseif inheritancemode == 3 then - -- fontfirst - if combinefeatures then - if classfeatures and classfeatures ~= "" then - specification.method = "*" - if fontfeatures and fontfeatures ~= "" and fontfeatures ~= classfeatures then - specification.detail = classfeatures .. "," .. fontfeatures - else - specification.detail = classfeatures - end - elseif fontfeatures and fontfeatures ~= "" then - specification.method = "*" - specification.detail = fontfeatures + + + + + + implement { + name = "definefont_two", + arguments = { + "boolean", "string", "string", "integer", "integer", "string", "string", "string", "string", + "integer", "integer", "integer", "string", "string", "string", "string", "integer", + }, + actions = function ( + global, -- \ifx\fontclass\empty\s!false\else\s!true\fi + cs, -- {#csname}% + str, -- \somefontfile + size, -- \d_font_scaled_font_size + inheritancemode, -- \c_font_feature_inheritance_mode + classfeatures, -- \m_font_class_features + fontfeatures, -- \m_font_features + classfallbacks, -- \m_font_class_fallbacks + fontfallbacks, -- \m_font_fallbacks + mathsize, -- \fontface + textsize, -- \d_font_scaled_text_face + relativeid, -- \relativefontid + classgoodies, -- \m_font_class_goodies + goodies, -- \m_font_goodies + classdesignsize, -- \m_font_class_designsize + fontdesignsize, -- \m_font_designsize + scaledfontmode -- \scaledfontmode + ) + + if trace_defining then + report_defining("start stage two: %s, size %s, features %a & %a, mode %a",str,size,classfeatures,fontfeatures,inheritancemode) + end + -- name is now resolved and size is scaled cf sa/mo + local lookup, name, sub, method, detail = getspecification(str or "") + -- new (todo: inheritancemode) + local designsize = fontdesignsize ~= "" and fontdesignsize or classdesignsize or "" + local designname = designsizefilename(name,designsize,size) + if designname and designname ~= "" then + if trace_defining or trace_designsize then + report_defining("remapping name %a, specification %a, size %a, designsize %a",name,designsize,size,designname) end - else + -- we don't catch detail here + local o_lookup, o_name, o_sub, o_method, o_detail = getspecification(designname) + if o_lookup and o_lookup ~= "" then lookup = o_lookup end + if o_method and o_method ~= "" then method = o_method end + if o_detail and o_detail ~= "" then detail = o_detail end + name = o_name + sub = o_sub + end + -- so far + -- some settings can have been overloaded + if lookup and lookup ~= "" then + specification.lookup = lookup + end + if relativeid and relativeid ~= "" then -- experimental hook + local id = tonumber(relativeid) or 0 + specification.relativeid = id > 0 and id + end + -- + specification.name = name + specification.size = size + specification.sub = (sub and sub ~= "" and sub) or specification.sub + specification.mathsize = mathsize + specification.textsize = textsize + specification.goodies = goodies + specification.cs = cs + specification.global = global + specification.scalemode = scaledfontmode -- context specific + if detail and detail ~= "" then + specification.method = method or "*" + specification.detail = detail + elseif specification.detail and specification.detail ~= "" then + -- already set + elseif inheritancemode == 0 then + -- nothing + elseif inheritancemode == 1 then + -- fontonly if fontfeatures and fontfeatures ~= "" then specification.method = "*" specification.detail = fontfeatures - elseif classfeatures and classfeatures ~= "" then + end + if fontfallbacks and fontfallbacks ~= "" then + specification.fallbacks = fontfallbacks + end + elseif inheritancemode == 2 then + -- classonly + if classfeatures and classfeatures ~= "" then specification.method = "*" specification.detail = classfeatures end - end - if fontfallbacks and fontfallbacks ~= "" then - specification.fallbacks = fontfallbacks - elseif classfallbacks and classfallbacks ~= "" then - specification.fallbacks = classfallbacks - end - elseif inheritancemode == 4 then - -- classfirst - if combinefeatures then - if fontfeatures and fontfeatures ~= "" then - specification.method = "*" - if classfeatures and classfeatures ~= "" and classfeatures ~= fontfeatures then - specification.detail = fontfeatures .. "," .. classfeatures - else + if classfallbacks and classfallbacks ~= "" then + specification.fallbacks = classfallbacks + end + elseif inheritancemode == 3 then + -- fontfirst + if combinefeatures then + if classfeatures and classfeatures ~= "" then + specification.method = "*" + if fontfeatures and fontfeatures ~= "" and fontfeatures ~= classfeatures then + specification.detail = classfeatures .. "," .. fontfeatures + else + specification.detail = classfeatures + end + elseif fontfeatures and fontfeatures ~= "" then + specification.method = "*" specification.detail = fontfeatures end - elseif classfeatures and classfeatures ~= "" then - specification.method = "*" - specification.detail = classfeatures + else + if fontfeatures and fontfeatures ~= "" then + specification.method = "*" + specification.detail = fontfeatures + elseif classfeatures and classfeatures ~= "" then + specification.method = "*" + specification.detail = classfeatures + end end - else - if classfeatures and classfeatures ~= "" then - specification.method = "*" - specification.detail = classfeatures - elseif fontfeatures and fontfeatures ~= "" then - specification.method = "*" - specification.detail = fontfeatures + if fontfallbacks and fontfallbacks ~= "" then + specification.fallbacks = fontfallbacks + elseif classfallbacks and classfallbacks ~= "" then + specification.fallbacks = classfallbacks + end + elseif inheritancemode == 4 then + -- classfirst + if combinefeatures then + if fontfeatures and fontfeatures ~= "" then + specification.method = "*" + if classfeatures and classfeatures ~= "" and classfeatures ~= fontfeatures then + specification.detail = fontfeatures .. "," .. classfeatures + else + specification.detail = fontfeatures + end + elseif classfeatures and classfeatures ~= "" then + specification.method = "*" + specification.detail = classfeatures + end + else + if classfeatures and classfeatures ~= "" then + specification.method = "*" + specification.detail = classfeatures + elseif fontfeatures and fontfeatures ~= "" then + specification.method = "*" + specification.detail = fontfeatures + end + end + if classfallbacks and classfallbacks ~= "" then + specification.fallbacks = classfallbacks + elseif fontfallbacks and fontfallbacks ~= "" then + specification.fallbacks = fontfallbacks end end - if classfallbacks and classfallbacks ~= "" then - specification.fallbacks = classfallbacks - elseif fontfallbacks and fontfallbacks ~= "" then - specification.fallbacks = fontfallbacks - end - end - -- - local tfmdata = definers.read(specification,size) -- id not yet known (size in spec?) - -- - local lastfontid = 0 - local tfmtype = type(tfmdata) - if tfmtype == "table" then - -- setting the extra characters will move elsewhere - local characters = tfmdata.characters - local parameters = tfmdata.parameters - local properties = tfmdata.properties - -- we use char0 as signal; cf the spec pdf can handle this (no char in slot) - characters[0] = nil - -- characters[0x00A0] = { width = parameters.space } - -- characters[0x2007] = { width = characters[0x0030] and characters[0x0030].width or parameters.space } -- figure - -- characters[0x2008] = { width = characters[0x002E] and characters[0x002E].width or parameters.space } -- period -- - local fallbacks = specification.fallbacks or "" - local mathsize = (mathsize == 1 or mathsize == 2 or mathsize == 3) and mathsize or nil -- can be unset so we test 1 2 3 - if fallbacks ~= "" and mathsize and not busy then - busy = true - -- We need this ugly hack in order to resolve fontnames (at the \TEX end). Originally - -- math was done in Lua after loading (plugged into aftercopying). + local tfmdata = definers.read(specification,size) -- id not yet known (size in spec?) + -- + local lastfontid = 0 + local tfmtype = type(tfmdata) + if tfmtype == "table" then + -- setting the extra characters will move elsewhere + local characters = tfmdata.characters + local parameters = tfmdata.parameters + local properties = tfmdata.properties + -- we use char0 as signal; cf the spec pdf can handle this (no char in slot) + characters[0] = nil + -- characters[0x00A0] = { width = parameters.space } + -- characters[0x2007] = { width = characters[0x0030] and characters[0x0030].width or parameters.space } -- figure + -- characters[0x2008] = { width = characters[0x002E] and characters[0x002E].width or parameters.space } -- period -- - -- After tl 2017 I'll also do text fallbacks this way (although backups there are done - -- in a completely different way.) - if trace_defining then - report_defining("defining %a, id %a, target %a, features %a / %a, fallbacks %a / %a, step %a", - name,id,nice_cs(cs),classfeatures,fontfeatures,classfallbacks,fontfallbacks,1) - end - mathematics.resolvefallbacks(tfmdata,specification,fallbacks) - context(function() - busy = false - mathematics.finishfallbacks(tfmdata,specification,fallbacks) + local fallbacks = specification.fallbacks or "" + local mathsize = (mathsize == 1 or mathsize == 2 or mathsize == 3) and mathsize or nil -- can be unset so we test 1 2 3 + if fallbacks ~= "" and mathsize and not busy then + busy = true + -- We need this ugly hack in order to resolve fontnames (at the \TEX end). Originally + -- math was done in Lua after loading (plugged into aftercopying). + -- + -- After tl 2017 I'll also do text fallbacks this way (although backups there are done + -- in a completely different way.) + if trace_defining then + report_defining("defining %a, id %a, target %a, features %a / %a, fallbacks %a / %a, step %a", + name,id,nice_cs(cs),classfeatures,fontfeatures,classfallbacks,fontfallbacks,1) + end + mathematics.resolvefallbacks(tfmdata,specification,fallbacks) + context(function() + busy = false + mathematics.finishfallbacks(tfmdata,specification,fallbacks) + local id = definefont(tfmdata) + csnames[id] = specification.cs + properties.id = id + definers.register(tfmdata,id) -- to be sure, normally already done + texdefinefont(global,cs,id) + constructors.cleanuptable(tfmdata) + constructors.finalize(tfmdata) + if trace_defining then + report_defining("defining %a, id %a, target %a, features %a / %a, fallbacks %a / %a, step %a", + name,id,nice_cs(cs),classfeatures,fontfeatures,classfallbacks,fontfallbacks,2) + end + -- resolved (when designsize is used): + local size = round(tfmdata.parameters.size or 655360) + setmacro("somefontsize",size.."sp") + -- ctx_setsomefontsize(size .. "sp") + texsetcount("scaledfontsize",size) + lastfontid = id + -- + if trace_defining then + report_defining("memory usage after: %s",statistics.memused()) + report_defining("stop stage two") + end + -- + texsetcount("global","lastfontid",lastfontid) + specifiers[lastfontid] = { str, size } + if not mathsize then + -- forget about it (can't happen here) + elseif mathsize == 0 then + -- can't happen (here) + else + -- maybe only 1 2 3 (we already test for this) + lastmathids[mathsize] = lastfontid + end + stoptiming(fonts) + end) + return + else local id = definefont(tfmdata) csnames[id] = specification.cs properties.id = id @@ -1426,7 +1462,7 @@ do -- else too many locals constructors.finalize(tfmdata) if trace_defining then report_defining("defining %a, id %a, target %a, features %a / %a, fallbacks %a / %a, step %a", - name,id,nice_cs(cs),classfeatures,fontfeatures,classfallbacks,fontfallbacks,2) + name,id,nice_cs(cs),classfeatures,fontfeatures,classfallbacks,fontfallbacks,"-") end -- resolved (when designsize is used): local size = round(tfmdata.parameters.size or 655360) @@ -1434,102 +1470,78 @@ do -- else too many locals -- ctx_setsomefontsize(size .. "sp") texsetcount("scaledfontsize",size) lastfontid = id - -- - if trace_defining then - report_defining("memory usage after: %s",statistics.memused()) - report_defining("stop stage two") - end - -- - texsetcount("global","lastfontid",lastfontid) - specifiers[lastfontid] = { str, size } - if not mathsize then - -- forget about it (can't happen here) - elseif mathsize == 0 then - -- can't happen (here) - else - -- maybe only 1 2 3 (we already test for this) - lastmathids[mathsize] = lastfontid - end - stoptiming(fonts) - end) - return - else - local id = definefont(tfmdata) - csnames[id] = specification.cs - properties.id = id - definers.register(tfmdata,id) -- to be sure, normally already done - texdefinefont(global,cs,id) - constructors.cleanuptable(tfmdata) - constructors.finalize(tfmdata) + end + elseif tfmtype == "number" then if trace_defining then - report_defining("defining %a, id %a, target %a, features %a / %a, fallbacks %a / %a, step %a", - name,id,nice_cs(cs),classfeatures,fontfeatures,classfallbacks,fontfallbacks,"-") + report_defining("reusing %s, id %a, target %a, features %a / %a, fallbacks %a / %a, goodies %a / %a, designsize %a / %a", + name,tfmdata,nice_cs(cs),classfeatures,fontfeatures,classfallbacks,fontfallbacks,classgoodies,goodies,classdesignsize,fontdesignsize) end + csnames[tfmdata] = specification.cs + texdefinefont(global,cs,tfmdata) -- resolved (when designsize is used): - local size = round(tfmdata.parameters.size or 655360) - setmacro("somefontsize",size.."sp") + local size = round(fontdata[tfmdata].parameters.size or 0) -- ctx_setsomefontsize(size .. "sp") + setmacro("somefontsize",size.."sp") texsetcount("scaledfontsize",size) - lastfontid = id + lastfontid = tfmdata + else + report_defining("unable to define %a as %a",name,nice_cs(cs)) + lastfontid = -1 + texsetcount("scaledfontsize",0) + -- ctx_letvaluerelax(cs) -- otherwise the current definition takes the previous one end - elseif tfmtype == "number" then if trace_defining then - report_defining("reusing %s, id %a, target %a, features %a / %a, fallbacks %a / %a, goodies %a / %a, designsize %a / %a", - name,tfmdata,nice_cs(cs),classfeatures,fontfeatures,classfallbacks,fontfallbacks,classgoodies,goodies,classdesignsize,fontdesignsize) - end - csnames[tfmdata] = specification.cs - texdefinefont(global,cs,tfmdata) - -- resolved (when designsize is used): - local size = round(fontdata[tfmdata].parameters.size or 0) - -- ctx_setsomefontsize(size .. "sp") - setmacro("somefontsize",size.."sp") - texsetcount("scaledfontsize",size) - lastfontid = tfmdata - else - report_defining("unable to define %a as %a",name,nice_cs(cs)) - lastfontid = -1 - texsetcount("scaledfontsize",0) - -- ctx_letvaluerelax(cs) -- otherwise the current definition takes the previous one - end - if trace_defining then - report_defining("memory usage after: %s",statistics.memused()) - report_defining("stop stage two") - end - -- - texsetcount("global","lastfontid",lastfontid) - specifiers[lastfontid] = { str, size } - if not mathsize then - -- forget about it - elseif mathsize == 0 then - -- can't happen (here) - else - -- maybe only 1 2 3 - lastmathids[mathsize] = lastfontid + report_defining("memory usage after: %s",statistics.memused()) + report_defining("stop stage two") + end + -- + texsetcount("global","lastfontid",lastfontid) + specifiers[lastfontid] = { str, size } + if not mathsize then + -- forget about it + elseif mathsize == 0 then + -- can't happen (here) + else + -- maybe only 1 2 3 + lastmathids[mathsize] = lastfontid + end + -- + stoptiming(fonts) end - -- - stoptiming(fonts) - end + } - function scanners.specifiedfontspec() - local f = specifiers[scaninteger()] - if f then - context(f[1]) - end - end - function scanners.specifiedfontsize() - local f = specifiers[scaninteger()] - if f then - context(f[2]) + implement { + name = "specifiedfontspec", + arguments = "integer", + actions = function(id) + local f = specifiers[id] + if f then + context(f[1]) + end end - end - function scanners.specifiedfont() - local f = specifiers[scaninteger()] - local s = scannumber() - if f and s then - context("%s at %0.2p",f[1],s * f[2]) -- we round to 2 decimals (as at the tex end) + } + + implement { + name = "specifiedfontsize", + arguments = "integer", + actions = function(id) + local f = specifiers[id] + if f then + context(f[2]) + end end - end + } + implement { + name = "specifiedfont", + arguments = { "integer", "number" }, + actions = function(id,size) + local f = specifiers[id] + if f and size then + context("%s at %0.2p",f[1],size * f[2]) -- we round to 2 decimals (as at the tex end) + end + end + } -- local function define(specification) diff --git a/tex/context/base/mkiv/grph-chk.lua b/tex/context/base/mkiv/grph-chk.lua index ed78b856c..0688f46ef 100644 --- a/tex/context/base/mkiv/grph-chk.lua +++ b/tex/context/base/mkiv/grph-chk.lua @@ -127,9 +127,9 @@ function checkers.pdf(data) return genericchecker(data) end -local function wrappedidentify(identify,filename) +local function wrappedidentify(identify,filename,filetype) local wrapup = function() report_inclusion("fatal error reading %a",filename) end - local _, result = xpcall(identify,wrapup,filename) + local _, result = xpcall(identify,wrapup,filename,filetype) if result then local xsize = result.xsize or 0 local ysize = result.ysize or 0 @@ -166,7 +166,7 @@ function checkers.jpg(data) local inject = lpdf.injectors.jpg local found = false request.scanimage = function(t) - local result = wrappedidentify(identify,t.filename) + local result = wrappedidentify(identify,t.filename,"jpg") found = not result.error return { filename = result.filename, @@ -202,7 +202,7 @@ function checkers.jp2(data) -- idem as jpg local inject = lpdf.injectors.jp2 local found = false request.scanimage = function(t) - local result = wrappedidentify(identify,t.filename) + local result = wrappedidentify(identify,t.filename,"jp2") found = not result.error return { filename = result.filename, @@ -238,7 +238,7 @@ function checkers.png(data) -- same as jpg (for now) local inject = lpdf.injectors.png -- currently pdf specific local found = false request.scanimage = function(t) - local result = wrappedidentify(identify,t.filename) + local result = wrappedidentify(identify,t.filename,"png") found = not result.error return { filename = result.filename, diff --git a/tex/context/base/mkiv/lpdf-ini.lua b/tex/context/base/mkiv/lpdf-ini.lua index 2163e8748..c6dd4765e 100644 --- a/tex/context/base/mkiv/lpdf-ini.lua +++ b/tex/context/base/mkiv/lpdf-ini.lua @@ -25,7 +25,6 @@ local report_finalizing = logs.reporter("backend","finalizing") local report_blocked = logs.reporter("backend","blocked") local implement = interfaces.implement -local two_strings = interfaces.strings[2] local context = context @@ -1553,16 +1552,16 @@ end -- interface implement { name = "lpdf_collectedresources", actions = { lpdf.collectedresources, context } } -implement { name = "lpdf_addtocatalog", arguments = two_strings, actions = lpdf.addtocatalog } -implement { name = "lpdf_addtoinfo", arguments = two_strings, actions = function(a,b,c) lpdf.addtoinfo(a,b,c) end } -- gets adapted -implement { name = "lpdf_addtonames", arguments = two_strings, actions = lpdf.addtonames } -implement { name = "lpdf_addtopageattributes", arguments = two_strings, actions = lpdf.addtopageattributes } -implement { name = "lpdf_addtopagesattributes", arguments = two_strings, actions = lpdf.addtopagesattributes } -implement { name = "lpdf_addtopageresources", arguments = two_strings, actions = lpdf.addtopageresources } -implement { name = "lpdf_adddocumentextgstate", arguments = two_strings, actions = function(a,b) lpdf.adddocumentextgstate (a,pdfverbose(b)) end } -implement { name = "lpdf_adddocumentcolorspace", arguments = two_strings, actions = function(a,b) lpdf.adddocumentcolorspace(a,pdfverbose(b)) end } -implement { name = "lpdf_adddocumentpattern", arguments = two_strings, actions = function(a,b) lpdf.adddocumentpattern (a,pdfverbose(b)) end } -implement { name = "lpdf_adddocumentshade", arguments = two_strings, actions = function(a,b) lpdf.adddocumentshade (a,pdfverbose(b)) end } +implement { name = "lpdf_addtocatalog", arguments = "2 strings", actions = lpdf.addtocatalog } +implement { name = "lpdf_addtoinfo", arguments = "2 strings", actions = function(a,b,c) lpdf.addtoinfo(a,b,c) end } -- gets adapted +implement { name = "lpdf_addtonames", arguments = "2 strings", actions = lpdf.addtonames } +implement { name = "lpdf_addtopageattributes", arguments = "2 strings", actions = lpdf.addtopageattributes } +implement { name = "lpdf_addtopagesattributes", arguments = "2 strings", actions = lpdf.addtopagesattributes } +implement { name = "lpdf_addtopageresources", arguments = "2 strings", actions = lpdf.addtopageresources } +implement { name = "lpdf_adddocumentextgstate", arguments = "2 strings", actions = function(a,b) lpdf.adddocumentextgstate (a,pdfverbose(b)) end } +implement { name = "lpdf_adddocumentcolorspace", arguments = "2 strings", actions = function(a,b) lpdf.adddocumentcolorspace(a,pdfverbose(b)) end } +implement { name = "lpdf_adddocumentpattern", arguments = "2 strings", actions = function(a,b) lpdf.adddocumentpattern (a,pdfverbose(b)) end } +implement { name = "lpdf_adddocumentshade", arguments = "2 strings", actions = function(a,b) lpdf.adddocumentshade (a,pdfverbose(b)) end } -- more helpers: copy from lepd to lpdf diff --git a/tex/context/base/mkiv/luat-ini.mkiv b/tex/context/base/mkiv/luat-ini.mkiv index d1d829be9..f059d2b85 100644 --- a/tex/context/base/mkiv/luat-ini.mkiv +++ b/tex/context/base/mkiv/luat-ini.mkiv @@ -121,13 +121,13 @@ %D \edef\luaescapestring#1{\!!bs#1\!!es} %D \stoptyping -\def\setdocumentfilename #1#2{\clf_setdocumentfilename\numexpr#1\relax{#2}} -\def\setdocumentargument #1#2{\clf_setdocumentargument{#1}{#2}} -\def\setdocumentargumentdefault#1#2{\clf_setdocumentdefaultargument{#1}{#2}} -\def\getdocumentfilename #1{\clf_getdocumentfilename\numexpr#1\relax} -\def\getdocumentargument #1{\clf_getdocumentargument{#1}{}} -\def\setdocumentargument #1#2{\clf_setdocumentargument{#1}{#2}} -\def\getdocumentargumentdefault#1#2{\clf_getdocumentargument{#1}{#2}} +\normalprotected\def\setdocumentfilename #1#2{\clf_setdocumentfilename\numexpr#1\relax{#2}} +\normalprotected\def\setdocumentargument #1#2{\clf_setdocumentargument{#1}{#2}} +\normalprotected\def\setdocumentargumentdefault#1#2{\clf_setdocumentdefaultargument{#1}{#2}} + \def\getdocumentfilename #1{\clf_getdocumentfilename\numexpr#1\relax} + \def\getdocumentargument #1{\clf_getdocumentargument{#1}{}} +\normalprotected\def\setdocumentargument #1#2{\clf_setdocumentargument{#1}{#2}} + \def\getdocumentargumentdefault#1#2{\clf_getdocumentargument{#1}{#2}} % seldom used so no need for speedy variants: diff --git a/tex/context/base/mkiv/luat-usr.lua b/tex/context/base/mkiv/luat-usr.lua index b49379bbf..1756bb198 100644 --- a/tex/context/base/mkiv/luat-usr.lua +++ b/tex/context/base/mkiv/luat-usr.lua @@ -102,23 +102,6 @@ interfaces.implement { arguments = "2 strings", } --- local scanners = interfaces.scanners --- --- local function ctxscanner(name) --- local scanner = scanners[name] --- if scanner then --- scanner() --- else --- report("unknown scanner: %s",name) --- end --- end --- --- interfaces.implement { --- name = "clfscanner", --- actions = ctxscanner, --- arguments = "string", --- } - local function registername(name,message) if not name or name == "" then report_instance("no valid name given") diff --git a/tex/context/base/mkiv/publ-aut.lua b/tex/context/base/mkiv/publ-aut.lua index e74c7ee18..123a67009 100644 --- a/tex/context/base/mkiv/publ-aut.lua +++ b/tex/context/base/mkiv/publ-aut.lua @@ -530,9 +530,9 @@ implement { name = "btxauthor", actions = btxauthor, arguments = { - "string", - "string", - "string", + "argument", + "argument", + "argument", { { "combiner" }, { "kind" }, diff --git a/tex/context/base/mkiv/status-files.pdf b/tex/context/base/mkiv/status-files.pdf Binary files differindex 374d3b695..26777bb6d 100644 --- a/tex/context/base/mkiv/status-files.pdf +++ b/tex/context/base/mkiv/status-files.pdf diff --git a/tex/context/base/mkiv/status-lua.pdf b/tex/context/base/mkiv/status-lua.pdf Binary files differindex a39f37412..ad3136f2a 100644 --- a/tex/context/base/mkiv/status-lua.pdf +++ b/tex/context/base/mkiv/status-lua.pdf diff --git a/tex/context/base/mkiv/strc-itm.mklx b/tex/context/base/mkiv/strc-itm.mklx index 2f3cc8425..3d1861d12 100644 --- a/tex/context/base/mkiv/strc-itm.mklx +++ b/tex/context/base/mkiv/strc-itm.mklx @@ -1321,6 +1321,7 @@ \letvalue{\??itemgroupstart\v!ran }\strc_itemgroups_start_edge \letvalue{\??itemgroupstart\v!its }\strc_itemgroups_start_items \letvalue{\??itemgroupstart\v!mar }\strc_itemgroups_start_margin +\letvalue{\??itemgroupstart\v!txt }\strc_itemgroups_start_text \def\optimizelistitemsbreak {\ifcase\c_strc_itemgroups_column_depth @@ -1578,6 +1579,11 @@ \appendtoks \let\item \strc_itemgroups_start_do_item + \let\sub \strc_itemgroups_start_subitem + \let\sym \strc_itemgroups_start_symbol + \let\ran \strc_itemgroups_start_edge + \let\its \strc_itemgroups_start_items + \let\mar \strc_itemgroups_start_margin \let\noitem \strc_itemgroups_start_no_item \let\itm \strc_itemgroups_start_do_item \let\but \strc_itemgroups_start_button @@ -1588,27 +1594,29 @@ \let\startitem \startitemgroupitem \let\stopitem \stopitemgroupitem \let\starthead \startitemgrouphead - \let\stophead \stopitemgroupitemhead + \let\stophead \stopitemgrouphead \let\startspecialitem\startspecialitemgroupitem \let\stopspecialitem \stopspecialitemgroupitem \to \itemgroupcommands -\ifx\currentinterface \v!english \else - - \appendtoks - \expandafter\let\csname\v!item \endcsname\strc_itemgroups_start_do_item - \expandafter\let\csname\v!sub \endcsname\strc_itemgroups_start_subitem - \expandafter\let\csname\v!sym \endcsname\strc_itemgroups_start_symbol - \expandafter\let\csname\v!ran \endcsname\strc_itemgroups_start_edge - \expandafter\let\csname\v!head \endcsname\strc_itemgroups_head - \expandafter\let\csname\v!its \endcsname\strc_itemgroups_start_items - \expandafter\let\csname\v!mar \endcsname\strc_itemgroups_start_margin - \expandafter\let\csname\v!txt \endcsname\strc_itemgroups_start_text - \expandafter\let\csname\e!start\v!item\endcsname\startitemgroupitem - \expandafter\let\csname\e!stop \v!item\endcsname\stopitemgroupitem - \expandafter\let\csname\e!start\v!head\endcsname\startitemgrouphead - \expandafter\let\csname\e!stop \v!head\endcsname\stopitemgrouphead - \to \itemgroupcommands +\ifx\currentinterface \s!english \else + + \def\next#1#2{\ifcsname#1\endcsname\else\let\csname#1\endcsname#2\fi} + + \etoksapp\itemgroupcommands{% + \next{\v!item }\strc_itemgroups_start_do_item + \next{\v!sub }\strc_itemgroups_start_subitem + \next{\v!sym }\strc_itemgroups_start_symbol + \next{\v!ran }\strc_itemgroups_start_edge + \next{\v!head }\strc_itemgroups_head + \next{\v!its }\strc_itemgroups_start_items + \next{\v!mar }\strc_itemgroups_start_margin + \next{\v!txt }\strc_itemgroups_start_text + \next{\e!start\v!item}\startitemgroupitem + \next{\e!stop \v!item}\stopitemgroupitem + \next{\e!start\v!head}\startitemgrouphead + \next{\e!stop \v!head}\stopitemgrouphead + } \fi diff --git a/tex/context/base/mkiv/strc-itm.mkvi b/tex/context/base/mkiv/strc-itm.mkvi index cbbefd5db..1b306fe18 100644 --- a/tex/context/base/mkiv/strc-itm.mkvi +++ b/tex/context/base/mkiv/strc-itm.mkvi @@ -1321,6 +1321,7 @@ \letvalue{\??itemgroupstart\v!ran }\strc_itemgroups_start_edge \letvalue{\??itemgroupstart\v!its }\strc_itemgroups_start_items \letvalue{\??itemgroupstart\v!mar }\strc_itemgroups_start_margin +\letvalue{\??itemgroupstart\v!txt }\strc_itemgroups_start_text \def\optimizelistitemsbreak {\ifcase\c_strc_itemgroups_column_depth \ifconditional\c_strc_itemgroups_optimize @@ -1577,6 +1578,11 @@ \appendtoks \let\item \strc_itemgroups_start_do_item + \let\sub \strc_itemgroups_start_subitem + \let\sym \strc_itemgroups_start_symbol + \let\ran \strc_itemgroups_start_edge + \let\its \strc_itemgroups_start_items + \let\mar \strc_itemgroups_start_margin \let\noitem \strc_itemgroups_start_no_item \let\itm \strc_itemgroups_start_do_item \let\but \strc_itemgroups_start_button @@ -1587,27 +1593,29 @@ \let\startitem \startitemgroupitem \let\stopitem \stopitemgroupitem \let\starthead \startitemgrouphead - \let\stophead \stopitemgroupitemhead + \let\stophead \stopitemgrouphead \let\startspecialitem\startspecialitemgroupitem \let\stopspecialitem \stopspecialitemgroupitem \to \itemgroupcommands -\ifx\currentinterface \v!english \else - - \appendtoks - \expandafter\let\csname\v!item \endcsname\strc_itemgroups_start_do_item - \expandafter\let\csname\v!sub \endcsname\strc_itemgroups_start_subitem - \expandafter\let\csname\v!sym \endcsname\strc_itemgroups_start_symbol - \expandafter\let\csname\v!ran \endcsname\strc_itemgroups_start_edge - \expandafter\let\csname\v!head \endcsname\strc_itemgroups_head - \expandafter\let\csname\v!its \endcsname\strc_itemgroups_start_items - \expandafter\let\csname\v!mar \endcsname\strc_itemgroups_start_margin - \expandafter\let\csname\v!txt \endcsname\strc_itemgroups_start_text - \expandafter\let\csname\e!start\v!item\endcsname\startitemgroupitem - \expandafter\let\csname\e!stop \v!item\endcsname\stopitemgroupitem - \expandafter\let\csname\e!start\v!head\endcsname\startitemgrouphead - \expandafter\let\csname\e!stop \v!head\endcsname\stopitemgrouphead - \to \itemgroupcommands +\ifx\currentinterface \s!english \else + + \def\next#1#2{\ifcsname#1\endcsname\else\let\csname#1\endcsname#2\fi} + + \etoksapp\itemgroupcommands{% + \next{\v!item }\strc_itemgroups_start_do_item + \next{\v!sub }\strc_itemgroups_start_subitem + \next{\v!sym }\strc_itemgroups_start_symbol + \next{\v!ran }\strc_itemgroups_start_edge + \next{\v!head }\strc_itemgroups_head + \next{\v!its }\strc_itemgroups_start_items + \next{\v!mar }\strc_itemgroups_start_margin + \next{\v!txt }\strc_itemgroups_start_text + \next{\e!start\v!item}\startitemgroupitem + \next{\e!stop \v!item}\stopitemgroupitem + \next{\e!start\v!head}\startitemgrouphead + \next{\e!stop \v!head}\stopitemgrouphead + } \fi diff --git a/tex/context/base/mkiv/syst-aux.mkxl b/tex/context/base/mkiv/syst-aux.mkxl index 956d43f89..2c84fe2c6 100644 --- a/tex/context/base/mkiv/syst-aux.mkxl +++ b/tex/context/base/mkiv/syst-aux.mkxl @@ -634,9 +634,9 @@ %D These are normally only used for keywords, i.e.\ strings so we can delegate %D the work to \LUA: -\unexpanded\def\doifelseinset#1#2{\clf_doifelseinset{#1}{#2}} -\unexpanded\def\doifinset #1#2{\clf_doifinset {#1}{#2}} -\unexpanded\def\doifnotinset #1#2{\clf_doifnotinset {#1}{#2}} +%unexpanded\def\doifelseinset#1#2{\clf_doifelseinset{#1}{#2}} +%unexpanded\def\doifinset #1#2{\clf_doifinset {#1}{#2}} +%unexpanded\def\doifnotinset #1#2{\clf_doifnotinset {#1}{#2}} % % \let\firstinset \clf_firstinset % These don't accept spaces after commas: diff --git a/tex/context/base/mkiv/syst-lua.lua b/tex/context/base/mkiv/syst-lua.lua index 77960def7..5976e077f 100644 --- a/tex/context/base/mkiv/syst-lua.lua +++ b/tex/context/base/mkiv/syst-lua.lua @@ -20,11 +20,9 @@ local ctx_secondoftwoarguments = context.secondoftwoarguments local ctx_firstofoneargument = context.firstofoneargument local ctx_gobbleoneargument = context.gobbleoneargument -local two_strings = interfaces.strings[2] - implement { -- will be overloaded later name = "writestatus", - arguments = two_strings, + arguments = "2 strings", actions = logs.status, } @@ -123,7 +121,7 @@ implement { implement { name = "doifelsesame", - arguments = two_strings, + arguments = "2 strings", actions = function(a,b) if a == b then ctx_firstoftwoarguments() @@ -135,7 +133,7 @@ implement { implement { name = "doifsame", - arguments = two_strings, + arguments = "2 strings", actions = function(a,b) if a == b then ctx_firstofoneargument() @@ -147,7 +145,7 @@ implement { implement { name = "doifnotsame", - arguments = two_strings, + arguments = "2 strings", actions = function(a,b) if a == b then ctx_gobbleoneargument() diff --git a/tex/context/base/mkiv/toks-ini.lua b/tex/context/base/mkiv/toks-ini.lua index 0ac5dcc50..184a17489 100644 --- a/tex/context/base/mkiv/toks-ini.lua +++ b/tex/context/base/mkiv/toks-ini.lua @@ -43,6 +43,7 @@ end local scan_toks = token.scan_toks local scan_string = token.scan_string local scan_argument = token.scan_argument +local scan_delimited = token.scan_delimited local scan_tokenlist = token.scan_tokenlist local scan_int = token.scan_int local scan_code = token.scan_code @@ -55,6 +56,7 @@ local scan_keyword_cs = token.scan_keyword_cs or scan_keyword local scan_token = token.scan_token local scan_box = token.scan_box local scan_word = token.scan_word +local scan_letters = token.scan_letters or scan_word -- lmtx local scan_key = token.scan_key local scan_value = token.scan_value local scan_char = token.scan_char @@ -191,11 +193,13 @@ tokens.scanners = { -- these expand count = scan_int, string = scan_string, argument = scan_argument, + delimited = scan_delimited, tokenlist = scan_tokenlist, verbatim = scan_verbatim, -- detokenize code = scan_code, tokencode = scan_token_code, word = scan_word, + letters = scan_letters, key = scan_key, value = scan_value, char = scan_char, diff --git a/tex/context/base/mkiv/toks-scn.lua b/tex/context/base/mkiv/toks-scn.lua index 09c3e13b2..7ef4ce603 100644 --- a/tex/context/base/mkiv/toks-scn.lua +++ b/tex/context/base/mkiv/toks-scn.lua @@ -22,13 +22,16 @@ local tokenbits = tokens.bits local scanstring = scanners.string local scanargument = scanners.argument +local scandelimited = scanners.delimited -- lmtx local scanverbatim = scanners.verbatim local scantokenlist = scanners.tokenlist +local scantoks = scanners.toks local scaninteger = scanners.integer local scannumber = scanners.number local scankeyword = scanners.keyword local scankeywordcs = scanners.keywordcs local scanword = scanners.word +local scanletters = scanners.letters local scankey = scanners.key local scancode = scanners.code local scanboolean = scanners.boolean @@ -113,23 +116,24 @@ local function scantable(t,data) if not data then data = { } end - local wrapped = scanopen() - while true do --- local key = scanword() - local key = scanword(true) - if key then - local get = t[key] - if get then - data[key] = get() + if t then + local wrapped = scanopen() + while true do + local key = scanword(true) + if key then + local get = t[key] + if get then + data[key] = get() + else + -- catch all we can get + end else - -- catch all we can get + break end - else - break end - end - if wrapped then - scanclose() + if wrapped then + scanclose() + end end return data end @@ -166,42 +170,84 @@ function scanners.whd() end end +-- begin lmtx + +local l = utf.byte("[") +local r = utf.byte("]") + +local function scanbracketed() + local s = scandelimited(l, r) + if s then + return s + else + report_scan("missing argument in line %i of %a", status.linenumber, status.filename) + return "" + end +end + +local function scanoptional() + return scandelimited(l, r) or "" +end + +local function scanbracketedasis() + return scandelimited(l, r, false) +end + +local function scanargumentasis() + return scanargument(false) +end + +scanners.bracketed = scanbracketed +scanners.optional = scanoptional +scanners.bracketedasis = scanbracketedasis +scanners.argumentasis = scanargumentasis + +-- end lmtx + local shortcuts = { - tokens = tokens, - bits = tokenbits, - open = open, - close = close, - scanners = scanners, - scanstring = scanstring, - scanargument = scanargument, - scanverbatim = scanverbatim, - scantokenlist = scantokenlist, - scaninteger = scaninteger, - scannumber = scannumber, - scantable = scantable, - scankeyword = scankeyword, - scankeywordcs = scankeywordcs, - scanword = scanword, - -- scankey = scankey, - scancode = scancode, - scanboolean = scanboolean, - scandimen = scandimen, - scandimension = scandimen, - scanbox = scanners.box, - scanhbox = scanners.hbox, - scanvbox = scanners.vbox, - scanvtop = scanners.vtop, - scanconditional = scanconditional, - scanopen = scanopen, - scanclose = scanclose, - scanlist = scanlist, - scancsname = scancsname, - todimen = todimen, - tonumber = tonumber, - tostring = tostring, - toboolean = toboolean, - inspect = inspect, - report = report_scan, + tokens = tokens, + bits = tokenbits, + open = open, + close = close, + scanners = scanners, + scanstring = scanstring, + scanargument = scanargument, + scanverbatim = scanverbatim, + scantokenlist = scantokenlist, + scantoks = scantoks, + scaninteger = scaninteger, + scannumber = scannumber, + scantable = scantable, -- not directly useable + scankeyword = scankeyword, + scankeywordcs = scankeywordcs, + scanword = scanword, + scanletters = scanletters, + -- scankey = scankey, + scancode = scancode, + scanboolean = scanboolean, + scandimen = scandimen, + scandimension = scandimen, + scanbox = scanners.box, + scanhbox = scanners.hbox, + scanvbox = scanners.vbox, + scanvtop = scanners.vtop, + scanconditional = scanconditional, + scanopen = scanopen, + scanclose = scanclose, + scanlist = scanlist, + scancsname = scancsname, + todimen = todimen, + tonumber = tonumber, + tostring = tostring, + toboolean = toboolean, + inspect = inspect, + report = report_scan, + -- lmtx + scandelimited = scandelimited, -- not directly useable + scanbracketed = scanbracketed, + scanoptional = scanoptional, + scanbracketedasis = scanbracketedasis, + scanargumentasis = scanargumentasis, } tokens.shortcuts = shortcuts @@ -222,25 +268,28 @@ tokens.converters = { toglue = "todimen", } --- We could just pickup a keyword but then we really need to make sure --- that no number follows it when that is the assignment and adding --- an optional = defeats the gain in speed. Currently we have sources --- with no spaces (\startcontextdefinitioncode ...) so it fails there. +-- We could just pickup a keyword but then we really need to make sure that no number +-- follows it when that is the assignment and adding an optional = defeats the gain +-- in speed. Currently we have sources with no spaces (\startcontextdefinitioncode +-- ...) so it fails there. -- --- Another drawback is that we then need to use { } instead of ending --- with \relax (as we can do now) but that is no big deal. It's just --- that I then need to check the TeX end. More pain than gain and a bit --- risky too. +-- Another drawback is that we then need to use { } instead of ending with \relax (as +-- we can do now) but that is no big deal. It's just that I then need to check the TeX +-- end. More pain than gain and a bit risky too. Using scanletters works better, but +-- the gain is only some 10 percent but if we don't have keywords with numbers it might +-- make sense in the end, some day. local f_if = formatters[ " if scankeywordcs('%s') then data['%s'] = scan%s()"] local f_elseif = formatters[" elseif scankeywordcs('%s') then data['%s'] = scan%s()"] ------ f_if = formatters[" local key = scanword() if key == '' then break elseif key == '%s' then data['%s'] = scan%s()"] ------ f_elseif = formatters[" elseif key == '%s' then data['%s'] = scan%s()"] - ----- f_if_x = formatters[ " if not data['%s'] and scankeywordcs('%s') then data['%s'] = scan%s()"] ----- f_elseif_x = formatters[" elseif not data['%s'] and scankeywordcs('%s') then data['%s'] = scan%s()"] +-- if CONTEXTLMTXMODE > 0 then +-- f_if = formatters[" local key = scanletters() if key == '' then break elseif key == '%s' then data['%s'] = scan%s()"] +-- f_elseif = formatters[" elseif key == '%s' then data['%s'] = scan%s()"] +-- end + local f_local = formatters["local scan%s = scanners.%s"] local f_scan = formatters["scan%s()"] local f_shortcut = formatters["local %s = scanners.converters.%s"] @@ -250,9 +299,11 @@ local f_elseif_c = formatters[" elseif scankeywordcs('%s') then data['%s'] = %s local f_scan_c = formatters["%s(scan%s())"] -- see above --- ------ f_if_c = formatters[" local key = scanword() if key == '' then break elseif key == '%s' then data['%s'] = %s(scan%s())"] ------ f_elseif_c = formatters[" elseif k == '%s' then data['%s'] = %s(scan%s())"] + +-- if CONTEXTLMTXMODE > 0 then +-- f_if_c = formatters[" local key = scanletters() if key == '' then break elseif key == '%s' then data['%s'] = %s(scan%s())"] +-- f_elseif_c = formatters[" elseif k == '%s' then data['%s'] = %s(scan%s())"] +-- end local f_any = formatters[" else local key = scanword(true) if key then data[key] = scan%s() else break end end"] local f_any_c = formatters[" else local key = scanword(true) if key then data[key] = %s(scan%s()) else break end end"] @@ -270,33 +321,6 @@ local f_action_f = formatters["action%s(%s)"] local f_action_s = formatters["local action%s = tokens._action[%s]"] local f_nested = formatters["local function scan%s()\n local data = { }\n%s\n return data\nend\n"] --- local f_check = formatters[ [[ --- local wrapped = false --- while true do --- local c = scancode(open) --- if c == 123 then --- wrapped = true --- break --- elseif c ~= 32 then --- break --- end --- end --- while true do --- ]] .. "%\nt\n" .. [[ --- %s --- end --- if wrapped then --- while true do --- local c = scancode(close) --- if c == 125 then --- break --- elseif c ~= 32 then --- break --- end --- end --- end --- ]] ] - local f_check = formatters[ [[ local wrapped = scanopen() while true do @@ -319,6 +343,11 @@ local presets = { ["6 strings"] = { "string", "string", "string", "string", "string", "string" }, ["7 strings"] = { "string", "string", "string", "string", "string", "string", "string" }, ["8 strings"] = { "string", "string", "string", "string", "string", "string", "string", "string" }, + + ["1 argument" ] = { "argument" }, + ["2 arguments"] = { "argument", "argument" }, + ["3 arguments"] = { "argument", "argument", "argument" }, + ["4 arguments"] = { "argument", "argument", "argument", "argument" }, } tokens.presets = presets @@ -542,7 +571,7 @@ end -- { "nature", "boolean" }, -- { "escape", "string" }, -- { "escape" }, --- } +-- }, -- "boolean", -- } -- diff --git a/tex/context/base/mkiv/util-str.lua b/tex/context/base/mkiv/util-str.lua index aba7859c3..2d3f4d669 100644 --- a/tex/context/base/mkiv/util-str.lua +++ b/tex/context/base/mkiv/util-str.lua @@ -1057,76 +1057,44 @@ local format_rest = function(s) return format("%q",s) -- catches " and \n and such end --- local format_extension = function(extensions,f,name) --- local extension = extensions[name] or "tostring(%s)" --- local f = tonumber(f) or 1 --- local w = find(extension,"%.%.%.") --- if f == 0 then --- if w then --- extension = gsub(extension,"%.%.%.","") --- end --- return extension --- elseif f == 1 then --- if w then --- extension = gsub(extension,"%.%.%.","%%s") --- end --- n = n + 1 --- local a = "a" .. n --- return format(extension,a,a) -- maybe more times? --- elseif f < 0 then --- local a = "a" .. (n + f + 1) --- return format(extension,a,a) --- else --- if w then --- extension = gsub(extension,"%.%.%.",rep("%%s,",f-1).."%%s") --- end --- -- we could fill an array and then n = n + 1 unpack(t,n,n+f) but as we --- -- cache we don't save much and there are hardly any extensions anyway --- local t = { } --- for i=1,f do --- n = n + 1 --- -- t[#t+1] = "a" .. n --- t[i] = "a" .. n --- end --- return format(extension,unpack(t)) --- end --- end - local format_extension = function(extensions,f,name) local extension = extensions[name] or "tostring(%s)" local f = tonumber(f) or 1 local w = find(extension,"%.%.%.") - if w then - -- we have a wildcard - if f == 0 then + if f == 0 then + if w then extension = gsub(extension,"%.%.%.","") - return extension - elseif f == 1 then + end + return extension + elseif f == 1 then + if w then extension = gsub(extension,"%.%.%.","%%s") - n = n + 1 - local a = "a" .. n - return format(extension,a,a) -- maybe more times? - elseif f < 0 then + end + n = n + 1 + local a = "a" .. n + return format(extension,a,a) -- maybe more times? + elseif f < 0 then + if w then + -- not supported + extension = gsub(extension,"%.%.%.","") + return extension + else local a = "a" .. (n + f + 1) return format(extension,a,a) - else - extension = gsub(extension,"%.%.%.",rep("%%s,",f-1).."%%s") - -- we could fill an array and then n = n + 1 unpack(t,n,n+f) but as we - -- cache we don't save much and there are hardly any extensions anyway - local t = { } - for i=1,f do - n = n + 1 - -- t[#t+1] = "a" .. n - t[i] = "a" .. n - end - return format(extension,unpack(t)) end else - extension = gsub(extension,"%%s",function() + if w then + extension = gsub(extension,"%.%.%.",rep("%%s,",f-1).."%%s") + end + -- we could fill an array and then n = n + 1 unpack(t,n,n+f) but as we + -- cache we don't save much and there are hardly any extensions anyway + local t = { } + for i=1,f do n = n + 1 - return "a" .. n - end) - return extension + -- t[#t+1] = "a" .. n + t[i] = "a" .. n + end + return format(extension,unpack(t)) end end diff --git a/tex/generic/context/luatex/luatex-fonts-merged.lua b/tex/generic/context/luatex/luatex-fonts-merged.lua index 68b47494a..471d32d1b 100644 --- a/tex/generic/context/luatex/luatex-fonts-merged.lua +++ b/tex/generic/context/luatex/luatex-fonts-merged.lua @@ -1,6 +1,6 @@ -- merged file : c:/data/develop/context/sources/luatex-fonts-merged.lua -- parent file : c:/data/develop/context/sources/luatex-fonts.lua --- merge date : 2020-06-20 13:33 +-- merge date : 2020-06-25 10:55 do -- begin closure to overcome local limits and interference @@ -3761,33 +3761,36 @@ local format_extension=function(extensions,f,name) local extension=extensions[name] or "tostring(%s)" local f=tonumber(f) or 1 local w=find(extension,"%.%.%.") - if w then - if f==0 then + if f==0 then + if w then extension=gsub(extension,"%.%.%.","") - return extension - elseif f==1 then + end + return extension + elseif f==1 then + if w then extension=gsub(extension,"%.%.%.","%%s") - n=n+1 - local a="a"..n - return format(extension,a,a) - elseif f<0 then + end + n=n+1 + local a="a"..n + return format(extension,a,a) + elseif f<0 then + if w then + extension=gsub(extension,"%.%.%.","") + return extension + else local a="a"..(n+f+1) return format(extension,a,a) - else - extension=gsub(extension,"%.%.%.",rep("%%s,",f-1).."%%s") - local t={} - for i=1,f do - n=n+1 - t[i]="a"..n - end - return format(extension,unpack(t)) end else - extension=gsub(extension,"%%s",function() + if w then + extension=gsub(extension,"%.%.%.",rep("%%s,",f-1).."%%s") + end + local t={} + for i=1,f do n=n+1 - return "a"..n - end) - return extension + t[i]="a"..n + end + return format(extension,unpack(t)) end end local builder=Cs { "start", |