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