1 /* lnewtokenlib.c
2 
3    Copyright 2006-2012 Taco Hoekwater <taco@luatex.org>
4 
5    This file is part of LuaTeX.
6 
7    LuaTeX is free software; you can redistribute it and/or modify it under
8    the terms of the GNU General Public License as published by the Free
9    Software Foundation; either version 2 of the License, or (at your
10    option) any later version.
11 
12    LuaTeX is distributed in the hope that it will be useful, but WITHOUT
13    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
15    License for more details.
16 
17    You should have received a copy of the GNU General Public License along
18    with LuaTeX; if not, see <http://www.gnu.org/licenses/>. */
19 
20 
21 /*
22     This module is unfinished and an intermediate step to removal of the old
23     token lib. Between version 0.80 and 0.85 the transition will be complete
24     and at the same time the input (buffer) handling will be cleaned up and
25     simplified. At that moment we can feed back tokens into the input.
26 
27     The code can be optimized a bit by faster key checking. The scan functions
28     implemented here will stay functionally the same but can be improved if
29     needed. The old triplet model will disappear.
30 
31 */
32 
33 #include "ptexlib.h"
34 #include "lua/luatex-api.h"
35 
36 typedef struct lua_token {
37     int token;
38     int origin;
39 } lua_token;
40 
41 typedef struct saved_tex_scanner {
42     int token;
43     int origin;
44     int save_cmd, save_chr, save_cs, save_tok;
45 } saved_tex_scanner;
46 
47 #define save_tex_scanner(a) do {		  \
48 	a.save_cmd = cur_cmd;			  \
49 	a.save_chr = cur_chr;			  \
50 	a.save_cs  = cur_cs;			  \
51 	a.save_tok = cur_tok;			  \
52     } while (0)
53 
54 #define unsave_tex_scanner(a) do {		  \
55 	cur_cmd = a.save_cmd;			  \
56 	cur_chr = a.save_chr;			  \
57 	cur_cs = a.save_cs;			  \
58 	cur_tok = a.save_tok;			  \
59     } while (0)
60 
61 
62 #define TEX_ORIGIN 0 /* not used yet */
63 #define LUA_ORIGIN 1
64 
65 static lua_token *check_istoken(lua_State * L, int ud);
66 
67 #define TOKEN_METATABLE  "luatex_newtoken"
68 
69 #define DEBUG 0
70 #define DEBUG_OUT stdout
71 
72 
73 #define DEFAULT_SCAN_CODE_SET 2048 + 4096 /* default: letter and other */
74 
75 
76 /* two core helpers */
77 #define  is_active_string(s) (strlen((char *)s)>3 && *s==0xEF && *(s+1)==0xBF && *(s+2)==0xBF)
78 
get_cs_text(int cs)79 static unsigned char *get_cs_text(int cs)
80 {
81     if (cs == null_cs)
82         return (unsigned char *) xstrdup("\\csname\\endcsname");
83     else if ((cs_text(cs) < 0) || (cs_text(cs) >= str_ptr))
84         return (unsigned char *) xstrdup("");
85     else
86         return (unsigned char *) makecstring(cs_text(cs));
87 }
88 
89 
90 
91 /* maybe this qualify as  a macro, not function */
92 
maybe_istoken(lua_State * L,int ud)93 static lua_token *maybe_istoken(lua_State * L, int ud)
94 {
95     lua_token *p = lua_touserdata(L, ud);
96     if (p != NULL) {
97         if (lua_getmetatable(L, ud)) {
98             lua_rawgeti(L, LUA_REGISTRYINDEX, luaS_index(luatex_newtoken));
99             lua_gettable(L, LUA_REGISTRYINDEX);
100             if (!lua_rawequal(L, -1, -2))
101                 p = NULL;
102             lua_pop(L, 2);
103         }
104     }
105     return p;
106 }
107 
108 /* we could make the message a function and just inline the rest (via a macro) */
109 
check_istoken(lua_State * L,int ud)110 lua_token *check_istoken(lua_State * L, int ud)
111 {
112     lua_token *p = maybe_istoken(L, ud);
113     if (p != NULL)
114         return p;
115     luatex_fail("There should have been a lua <token> here, not an object with type %s!", luaL_typename(L, ud));
116     return NULL;
117 }
118 
119 /* token library functions */
120 
make_new_token(lua_State * L,int cmd,int chr,int cs)121 static void make_new_token(lua_State * L, int cmd, int chr, int cs)
122 {
123     int tok = 0;
124     lua_token *thetok = lua_newuserdata(L, sizeof(lua_token));
125     thetok->origin = LUA_ORIGIN;
126     fast_get_avail(thetok->token);
127     tok = (cs ? cs_token_flag + cs : token_val(cmd, chr));
128     set_token_info(thetok->token, tok);
129     lua_rawgeti(L, LUA_REGISTRYINDEX, luaS_index(luatex_newtoken));
130     lua_gettable(L, LUA_REGISTRYINDEX);
131     lua_setmetatable(L, -2);
132 }
133 
push_token(lua_State * L,int tok)134 static void push_token(lua_State * L, int tok)
135 {
136     lua_token *thetok = lua_newuserdata(L, sizeof(lua_token));
137     thetok->origin = LUA_ORIGIN;
138     thetok->token = tok;
139     lua_rawgeti(L, LUA_REGISTRYINDEX, luaS_index(luatex_newtoken));
140     lua_gettable(L, LUA_REGISTRYINDEX);
141     lua_setmetatable(L, -2);
142 }
143 
144 
145 /* static int run_get_cs_offset(lua_State * L) */
146 /* { */
147 /*     lua_pushnumber(L, cs_token_flag); */
148 /*     return 1; */
149 /* } */
150 
151 /* static int run_get_command_id(lua_State * L) */
152 /* { */
153 /*     int cs = -1; */
154 /*     if (lua_isstring(L, -1)) { */
155 /*         cs = get_command_id(lua_tostring(L, -1)); */
156 /*     } */
157 /*     lua_pushnumber(L, cs); */
158 /*     return 1; */
159 /* } */
160 
161 /* static int run_get_csname_id(lua_State * L) */
162 /* { */
163 /*     const char *s; */
164 /*     size_t k, cs = 0; */
165 /*     if (lua_isstring(L, -1)) { */
166 /*         s = lua_tolstring(L, -1, &k); */
167 /*         cs = (size_t) string_lookup(s, k); */
168 /*     } */
169 /*     lua_pushnumber(L, (lua_Number) cs); */
170 /*     return 1; */
171 /* } */
172 
run_get_next(lua_State * L)173 static int run_get_next(lua_State * L)
174 {
175     saved_tex_scanner texstate;
176     save_tex_scanner(texstate);
177     get_next();
178     make_new_token(L, cur_cmd, cur_chr, cur_cs);
179     unsave_tex_scanner(texstate);
180     return 1;
181 }
182 
run_scan_keyword(lua_State * L)183 static int run_scan_keyword(lua_State * L)
184 {
185     saved_tex_scanner texstate;
186     const char *s = luaL_checkstring(L, -1);
187     int v = 0;
188     if (s) {
189         save_tex_scanner(texstate);
190         if (scan_keyword(s)) {
191             v = 1;
192         }
193         unsave_tex_scanner(texstate);
194     }
195     lua_pushboolean(L,v);
196     return 1;
197 }
198 
run_scan_int(lua_State * L)199 static int run_scan_int(lua_State * L)
200 {
201     saved_tex_scanner texstate;
202     int v = 0;
203     save_tex_scanner(texstate);
204     scan_int();
205     v = cur_val;
206     unsave_tex_scanner(texstate);
207     lua_pushnumber(L,(lua_Number)v);
208     return 1;
209 }
210 
211 
run_scan_dimen(lua_State * L)212 static int run_scan_dimen(lua_State * L)
213 {
214     saved_tex_scanner texstate;
215     int v = 0, o = 0;
216     int inf = false, mu = false;
217     int t = lua_gettop(L);
218     if (t>0)
219       inf = lua_toboolean(L,1); /* inf values allowed ?*/
220     if (t>1)
221       mu = lua_toboolean(L,2);  /* mu units required ?*/
222     save_tex_scanner(texstate);
223     scan_dimen( mu,inf, false); /* arg3 = shortcut */
224     v = cur_val;
225     o = cur_order;
226     unsave_tex_scanner(texstate);
227     lua_pushnumber(L,(lua_Number)v);
228     if (inf) {
229         lua_pushnumber(L,(lua_Number)o);
230         return 2;
231     } else {
232         return 1;
233     }
234 }
235 
236 
237 
238 
run_scan_glue(lua_State * L)239 static int run_scan_glue(lua_State * L)
240 {
241     saved_tex_scanner texstate;
242     int v = 0;
243     int mu = false;
244     int t = lua_gettop(L);
245     if (t>0)
246       mu = lua_toboolean(L,1); /* mu units required ?*/
247     save_tex_scanner(texstate);
248     scan_glue((mu ? mu_val_level : glue_val_level));
249     v = cur_val; /* which is a glue_spec node */
250     unsave_tex_scanner(texstate);
251     lua_nodelib_push_fast(L,(halfword)v);
252     return 1;
253 }
254 
255 
run_scan_toks(lua_State * L)256 static int run_scan_toks(lua_State * L)
257 {
258     saved_tex_scanner texstate;
259     int macro_def = false, xpand = false;
260     halfword t, saved_defref;
261     int i = 1;
262     int top = lua_gettop(L);
263     if (top>0)
264       macro_def = lua_toboolean(L,1); /* \\def ? */
265     if (top>1)
266       xpand = lua_toboolean(L,2); /* expand ? */
267     save_tex_scanner(texstate);
268     saved_defref = def_ref;
269     (void) scan_toks(macro_def, xpand);
270     t = def_ref;
271     unsave_tex_scanner(texstate);
272     def_ref = saved_defref;
273     /* This function returns a pointer to the tail of a new token
274        list, and it also makes |def_ref| point to the reference count at the
275        head of that list. */
276     lua_newtable(L);
277     while (token_link(t)) {
278         t = token_link(t);
279         push_token(L,t);
280         lua_rawseti(L,-2,i++);
281     }
282     return 1;
283 }
284 
run_scan_string(lua_State * L)285 static int run_scan_string(lua_State * L) /* HH */
286 {   /* can be simplified, no need for intermediate list */
287     saved_tex_scanner texstate;
288     halfword t, saved_defref;
289     save_tex_scanner(texstate);
290     do {
291         get_x_token();
292     } while ((cur_cmd == spacer_cmd) || (cur_cmd == relax_cmd));
293     if (cur_cmd == left_brace_cmd) {
294         back_input();
295         saved_defref = def_ref;
296         (void) scan_toks(false, true);
297         t = def_ref;
298         def_ref = saved_defref;
299         tokenlist_to_luastring(L,t);
300     } else if (cur_cmd == call_cmd) {
301         t = token_link(cur_chr);
302         tokenlist_to_luastring(L,t);
303     } else {
304         if (cur_cmd == 11 || cur_cmd == 12 ) {
305             char * str ;
306             luaL_Buffer b ;
307             luaL_buffinit(L,&b) ;
308             while (1) {
309                 str = (char *) uni2str(cur_chr);
310                 luaL_addstring(&b,(char *) str);
311                 get_x_token();
312                 if (cur_cmd != 11 && cur_cmd != 12 ) {
313                     break ;
314                 }
315             }
316             back_input();
317             luaL_pushresult(&b);
318         } else {
319             back_input();
320             lua_pushnil(L);
321         }
322     }
323     unsave_tex_scanner(texstate);
324     return 1;
325 }
326 
run_scan_word(lua_State * L)327 static int run_scan_word(lua_State * L) /* HH */
328 {
329     saved_tex_scanner texstate;
330     save_tex_scanner(texstate);
331     do {
332         get_x_token();
333     } while ((cur_cmd == spacer_cmd) || (cur_cmd == relax_cmd));
334     if (cur_cmd == 11 || cur_cmd == 12 ) {
335         char *str ;
336         luaL_Buffer b ;
337         luaL_buffinit(L,&b) ;
338         while (1) {
339             str = (char *) uni2str(cur_chr);
340             luaL_addstring(&b,str);
341             xfree(str);
342             get_x_token();
343             if (cur_cmd != 11 && cur_cmd != 12 ) {
344                 break ;
345             }
346         }
347         back_input();
348         luaL_pushresult(&b);
349     } else {
350         back_input();
351         lua_pushnil(L);
352     }
353     unsave_tex_scanner(texstate);
354     return 1;
355 }
356 
357 
358 
run_scan_code(lua_State * L)359 static int run_scan_code(lua_State * L) /* HH */
360 {
361     saved_tex_scanner texstate;
362     int cc = DEFAULT_SCAN_CODE_SET ;
363     save_tex_scanner(texstate);
364     get_x_token();
365     if (cur_cmd < 16) {
366         if (lua_gettop(L)>0) {
367             cc = (int) lua_tointeger(L,-1);
368             if (cc == null) {
369                 /* todo: message that we choose a default */
370                 cc = DEFAULT_SCAN_CODE_SET ;
371             }
372         }
373         if (cc & (1<<(cur_cmd))) {
374             lua_pushnumber(L,(lua_Number)cur_chr);
375         } else {
376             lua_pushnil(L);
377             back_input();
378         }
379     } else {
380         lua_pushnil(L);
381         back_input();
382     }
383     unsave_tex_scanner(texstate);
384     return 1;
385 }
386 
387 
lua_tokenlib_is_token(lua_State * L)388 static int lua_tokenlib_is_token(lua_State * L) /* HH */
389 {
390     lua_pushboolean(L,maybe_istoken(L,1)==NULL ? 0 : 1);
391     return 1;
392 }
393 
394 
395 /* static int run_expand(lua_State * L) */
396 /* { */
397 /*     (void) L; */
398 /*     expand(); */
399 /*     return 0; */
400 /* } */
401 
402 
run_lookup(lua_State * L)403 static int run_lookup(lua_State * L)
404 {
405     const char *s;
406     size_t l;
407     int cs, cmd, chr;
408     if (lua_isstring(L, -1)) {
409         s = lua_tolstring(L, -1, &l);
410         if (l > 0) {
411             cs = string_lookup(s, l);
412             cmd = eq_type(cs);
413             chr = equiv(cs);
414             make_new_token(L, cmd, chr, cs);
415             return 1;
416         }
417     }
418     lua_pushnil(L);
419     return 1;
420 }
421 
run_build(lua_State * L)422 static int run_build(lua_State * L)
423 {
424     int cmd, chr, cs;
425     if (lua_isnumber(L, 1)) {
426         cs = 0;
427         chr = (int) lua_tointeger(L, 1);
428         cmd = (int) luaL_optinteger(L, 2, get_cat_code(int_par(cat_code_table_code),chr));
429         if (cmd == 0 || cmd == 9 || cmd == 14 || cmd == 15) {
430             fprintf(stdout,
431                     "\n\nluatex error: not a good token.\nCatcode %i can not be returned, so I replaced it by 12 (other)",
432                     (int) cmd);
433             error();
434             cmd = 12;
435         } else if (cmd == 13) {
436             cs = active_to_cs(chr, false);
437             cmd = eq_type(cs);
438             chr = equiv(cs);
439         }
440         make_new_token(L, cmd, chr, cs);
441         return 1;
442     } else {
443         return run_lookup(L);
444     }
445 }
446 
447 /* token instance functions */
448 
lua_tokenlib_free(lua_State * L)449 static int lua_tokenlib_free(lua_State * L)
450 {
451     lua_token *n;
452     n = check_istoken(L, 1);
453     if (n->origin == LUA_ORIGIN) {
454         free_avail(n->token);
455     }
456     return 1;
457 }
458 
lua_tokenlib_getfield(lua_State * L)459 static int lua_tokenlib_getfield(lua_State * L)
460 {
461     lua_token *n;
462     const char *s;
463     halfword t ;
464     n = check_istoken(L, 1);
465     s = lua_tostring(L, 2);
466     t = token_info(n->token);
467     if (lua_key_eq(s, command)) {
468         if (t >= cs_token_flag) {
469             lua_pushnumber(L, eq_type((t - cs_token_flag)));
470         } else {
471             lua_pushnumber(L, token_cmd(t));
472         }
473     } else if (lua_key_eq(s, mode)) {
474         if (t >= cs_token_flag) {
475             lua_pushnumber(L, equiv((t - cs_token_flag)));
476         } else {
477             lua_pushnumber(L, token_chr(t));
478         }
479     } else if (lua_key_eq(s, cmdname)) {
480         int cmd = (t >= cs_token_flag ? eq_type(t - cs_token_flag) : token_cmd(t));
481         lua_pushstring(L, command_names[cmd].cmd_name); /* can be sped up */
482     } else if (lua_key_eq(s, csname)) {
483         unsigned char *s;
484         if (t >= cs_token_flag && ((s = get_cs_text(t - cs_token_flag)) != (unsigned char *) NULL)) {
485             if (is_active_string(s))
486                 lua_pushstring(L, (char *) (s + 3));
487             else
488                 lua_pushstring(L, (char *) s);
489         } else {
490             lua_pushstring(L, "");
491         }
492     } else if (lua_key_eq(s, id)) {
493        lua_pushnumber(L, n->token);
494     } else if (lua_key_eq(s, tok)) {
495        lua_pushnumber(L, t);
496     } else if (lua_key_eq(s, active)) {
497         unsigned char *s;
498         if (t >= cs_token_flag && ((s = get_cs_text(t - cs_token_flag)) != (unsigned char *) NULL)) {
499             if (is_active_string(s))
500                 lua_pushboolean(L,1);
501             else
502                 lua_pushboolean(L,0);
503             free(s);
504         } else {
505             lua_pushboolean(L,0);
506         }
507     } else if (lua_key_eq(s, expandable)) {
508         int cmd = (t >= cs_token_flag ? eq_type(t - cs_token_flag) : token_cmd(t));
509         if (cmd > max_command_cmd) {
510             lua_pushboolean(L, 1);
511         } else {
512             lua_pushboolean(L, 0);
513         }
514     } else if (lua_key_eq(s, protected)) {
515         int cmd = (t >= cs_token_flag ? eq_type(t - cs_token_flag) : token_cmd(t));
516         int chr = (t >= cs_token_flag ? equiv(t - cs_token_flag) : token_chr(t));
517         if (cmd > max_command_cmd && ((cmd >= call_cmd) && (cmd < end_template_cmd)) &&
518             token_info(token_link(chr)) == protected_token) {
519             lua_pushboolean(L, 1);
520         } else {
521             lua_pushboolean(L, 0);
522         }
523     }
524     return 1;
525 }
526 
lua_tokenlib_equal(lua_State * L)527 static int lua_tokenlib_equal(lua_State * L)
528 {
529     lua_token *n, *m;
530     n = check_istoken(L, 1);
531     m = check_istoken(L, 2);
532     if (token_info(n->token) == token_info(m->token)) {
533 	lua_pushboolean(L,1);
534         return 1;
535     }
536     lua_pushboolean(L,0);
537     return 1;
538 }
539 
lua_tokenlib_tostring(lua_State * L)540 static int lua_tokenlib_tostring(lua_State * L)
541 {
542     char *msg;
543     lua_token *n;
544     n = check_istoken(L, 1);
545     msg = xmalloc(256);
546     snprintf(msg, 255, "<%s token %d: %d>", (n->origin==LUA_ORIGIN?"lua":"tex"), n->token , token_info(n->token));
547     lua_pushstring(L, msg);
548     free(msg);
549     return 1;
550 }
551 
lua_tokenlib_type(lua_State * L)552 static int lua_tokenlib_type(lua_State * L)
553 {
554     if (maybe_istoken(L,1)!=NULL) {
555         lua_pushstring(L,"token");
556     } else {
557         lua_pushnil(L);
558     }
559     return 1;
560 }
561 
562 
run_scan_token(lua_State * L)563 static int run_scan_token(lua_State * L)
564 {
565     saved_tex_scanner texstate;
566     save_tex_scanner(texstate);
567     get_x_token();
568     make_new_token(L, cur_cmd, cur_chr, cur_cs);
569     unsave_tex_scanner(texstate);
570     return 1;
571 }
572 
573 /* experiment */
574 
575 /* [catcodetable] csname content        : \def\csname{content}  */
576 /* [catcodetable] csname content global : \gdef\csname{content} */
577 /* [catcodetable] csname                : \def\csname{}         */
578 
579 /* TODO: check for a quick way to set a macro to empty (HH) */
set_macro(lua_State * L)580 static int set_macro(lua_State * L)
581 {
582     const char *name = null;
583     const char *str = null;
584     const char *s  = null;
585     size_t lname = 0;
586     size_t lstr = 0;
587     int cs, cc, ct;
588     int n = lua_gettop(L);
589     int a = 0 ; /* global state */
590     int nncs = no_new_control_sequence;
591     if (n == 0) {
592         return 0 ;
593     }
594     if (lua_isnumber(L, 1)) {
595         if (n == 1)
596             return 0;
597         ct = (int) lua_tointeger(L, 1);
598         name = lua_tolstring(L, 2, &lname);
599         if (n > 2)
600             str = lua_tolstring(L, 3, &lstr);
601         if (n > 3)
602             s = lua_tostring(L, 4);
603     } else {
604         ct = int_par(cat_code_table_code) ;
605         name = lua_tolstring(L, 1, &lname);
606         if (n > 1)
607             str = lua_tolstring(L, 2, &lstr);
608         if (n > 2)
609             s = lua_tostring(L, 3);
610     }
611     if (name == null) {
612         return 0 ;
613     }
614     if (s && (lua_key_eq(s, global))) {
615         a = 4;
616     }
617     no_new_control_sequence = false ;
618     cs = string_lookup(name, lname);
619     no_new_control_sequence = nncs;
620     if (lstr > 0) {
621         halfword p; /* tail of the token list */
622         halfword q; /* new node being added to the token list via |store_new_token| */
623         halfword t; /* token being appended */
624         const char *se = str + lstr;
625         p = temp_token_head;
626         set_token_link(p, null);
627         /* this left brace is used to store the number of arguments */
628         fast_store_new_token(left_brace_token);
629         /* and this ends the not present arguments, and no: we will not support arguments here*/
630         fast_store_new_token(end_match_token);
631         while (str < se) {
632             /* hh: str2uni could return len too (also elsewhere) */
633             t = (halfword) str2uni((const unsigned char *) str);
634             str += utf8_size(t);
635             cc = get_cat_code(ct,t);
636             /* this is a relating simple converter; if more is needed one can just use     */
637             /* tex.print with a regular \def or \gdef and feed the string into the regular */
638             /* scanner;                                                                    */
639             if (cc == 0) {
640                 /* we have a potential control sequence so we check for it */
641                 int _lname = 0 ;
642                 int _s = 0 ;
643                 int _c = 0 ;
644                 halfword _cs = null ;
645                 const char *_name  = str ;
646                 while (str < se) {
647                     t = (halfword) str2uni((const unsigned char *) str);
648                     _s = utf8_size(t);
649                     _c = get_cat_code(ct,t);
650                     if (_c == 11) {
651                         str += _s ;
652                         _lname = _lname + _s ;
653                     } else if (_c == 10) {
654                         /* we ignore a trailing space like normal scanning does */
655                         str += _s ;
656                         break ;
657                     } else {
658                         break ;
659                     }
660                 }
661                 if (_s > 0) {
662                     /* we havea potential \cs */
663                     _cs = string_lookup(_name, _lname);
664                     if (_cs == undefined_control_sequence) {
665                         /* let's play safe and backtrack */
666                         t = cc * (1<<21) + t ;
667                         str = _name ;
668                     } else {
669                         t = cs_token_flag + _cs;
670                     }
671                 } else {
672                     /* just a character with some meaning, so \unknown becomes effectively */
673                     /* \\unknown assuming that \\ has some useful meaning of course        */
674                     t = cc * (1<<21) + t ;
675                     str = _name ;
676                 }
677 
678             } else {
679                 /* whatever token, so for instance $x^2$ just works given a tex */
680                 /* catcode regime */
681                 t = cc * (1<<21) + t ;
682             }
683             fast_store_new_token(t);
684         }
685         /* there is no fast_store_new_token(right_brace_token) needed */
686         define(cs, call_cmd + (a % 4), token_link(temp_token_head));
687     } else {
688         halfword p ;
689         halfword q; /* new node being added to the token list via |store_new_token| */
690         p = temp_token_head;
691         set_token_info(p,null);
692         fast_store_new_token(left_brace_token);
693         fast_store_new_token(end_match_token);
694         define(cs, call_cmd + (a % 4), token_link(temp_token_head));
695     }
696     return 0;
697 }
698 
699 
700 static const struct luaL_Reg tokenlib[] = {
701     {"is_token", lua_tokenlib_is_token},
702     {"get_next", run_get_next},
703     {"scan_keyword", run_scan_keyword},
704     {"scan_int", run_scan_int},
705     {"scan_dimen", run_scan_dimen},
706     {"scan_glue", run_scan_glue},
707     {"scan_toks", run_scan_toks},
708     {"scan_code", run_scan_code},
709     {"scan_string", run_scan_string},
710     {"scan_word", run_scan_word},
711     {"type", lua_tokenlib_type},
712     {"create", run_build},
713     {"scan_token", run_scan_token}, /* expands next token if needed */
714     {"set_macro", set_macro},
715  /* {"expand", run_expand},               */ /* does not work yet! */
716  /* {"csname_id", run_get_csname_id},     */ /* yes or no */
717  /* {"command_id", run_get_command_id},   */ /* yes or no */
718  /* {"cs_offset", run_get_cs_offset},     */ /* not that useful */
719     {NULL, NULL} /* sentinel */
720 };
721 
722 static const struct luaL_Reg tokenlib_m[] = {
723     {"__index", lua_tokenlib_getfield},
724     {"__tostring", lua_tokenlib_tostring},
725     {"__eq", lua_tokenlib_equal},
726     {"__gc", lua_tokenlib_free},
727     {NULL, NULL} /* sentinel */
728 };
729 
730 
731 
luaopen_newtoken(lua_State * L)732 int luaopen_newtoken(lua_State * L)
733 {
734     /* the main metatable of token userdata */
735     luaL_newmetatable(L, TOKEN_METATABLE);
736     luaL_register(L, NULL, tokenlib_m);
737     luaL_register(L, "newtoken", tokenlib);
738     return 1;
739 }
740