fix getsup (HH)
[luatex.git] / source / texk / web2c / luatexdir / lua / lnewtokenlib.c
blob373f2d983820aa5a77ddb81f2775cbe87831e73c
1 /* lnewtokenlib.c
3 Copyright 2006-2012 Taco Hoekwater <taco@luatex.org>
5 This file is part of LuaTeX.
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.
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.
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/>. */
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.
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.
33 #include "ptexlib.h"
34 #include "lua/luatex-api.h"
36 typedef struct lua_token {
37 int token;
38 int origin;
39 } lua_token;
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;
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)
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)
61 #define TEX_ORIGIN 0 /* not used yet */
62 #define LUA_ORIGIN 1
64 static lua_token *check_istoken(lua_State * L, int ud);
66 #define TOKEN_METATABLE "luatex.token"
68 #define DEBUG 0
69 #define DEBUG_OUT stdout
71 #define DEFAULT_SCAN_CODE_SET 2048 + 4096 /* default: letter and other */
73 /* two core helpers */
75 #define is_active_string(s) (strlen((char *)s)>3 && *s==0xEF && *(s+1)==0xBF && *(s+2)==0xBF)
77 void make_token_table(lua_State * L, int cmd, int chr, int cs)
79 lua_createtable(L, 3, 0);
80 lua_pushinteger(L, cmd);
81 lua_rawseti(L, -2, 1);
82 lua_pushinteger(L, chr);
83 lua_rawseti(L, -2, 2);
84 lua_pushinteger(L, cs);
85 lua_rawseti(L, -2, 3);
88 static unsigned char *get_cs_text(int cs)
90 if (cs == null_cs)
91 return (unsigned char *) xstrdup("\\csname\\endcsname");
92 else if ((cs_text(cs) < 0) || (cs_text(cs) >= str_ptr))
93 return (unsigned char *) xstrdup("");
94 else
95 return (unsigned char *) makecstring(cs_text(cs));
98 /* maybe this qualify as a macro, not function */
100 static lua_token *maybe_istoken(lua_State * L, int ud)
102 lua_token *p = lua_touserdata(L, ud);
103 if (p != NULL) {
104 if (lua_getmetatable(L, ud)) {
105 lua_get_metatablelua(luatex_token);
106 if (!lua_rawequal(L, -1, -2))
107 p = NULL;
108 lua_pop(L, 2);
111 return p;
114 /* we could make the message a function and just inline the rest (via a macro) */
116 lua_token *check_istoken(lua_State * L, int ud)
118 lua_token *p = maybe_istoken(L, ud);
119 if (p != NULL)
120 return p;
121 formatted_error("token lib","lua <token> expected, not an object with type %s", luaL_typename(L, ud));
122 return NULL;
125 /* token library functions */
127 static void make_new_token(lua_State * L, int cmd, int chr, int cs)
129 int tok = 0;
130 lua_token *thetok = lua_newuserdata(L, sizeof(lua_token));
131 thetok->origin = LUA_ORIGIN;
132 fast_get_avail(thetok->token);
133 tok = (cs ? cs_token_flag + cs : token_val(cmd, chr));
134 set_token_info(thetok->token, tok);
135 lua_get_metatablelua(luatex_token);
136 lua_setmetatable(L, -2);
139 static void push_token(lua_State * L, int tok)
141 lua_token *thetok = lua_newuserdata(L, sizeof(lua_token));
142 thetok->origin = LUA_ORIGIN;
143 thetok->token = tok;
144 lua_get_metatablelua(luatex_token);
145 lua_setmetatable(L, -2);
148 /* static int run_get_cs_offset(lua_State * L) */
149 /* { */
150 /* lua_pushinteger(L, cs_token_flag); */
151 /* return 1; */
152 /* } */
154 /* static int run_get_command_id(lua_State * L) */
155 /* { */
156 /* int cs = -1; */
157 /* if (lua_type(L, -1) == LUA_TSTRING) { */
158 /* cs = get_command_id(lua_tostring(L, -1)); */
159 /* } */
160 /* lua_pushinteger(L, cs); */
161 /* return 1; */
162 /* } */
164 /* static int run_get_csname_id(lua_State * L) */
165 /* { */
166 /* const char *s; */
167 /* size_t k, cs = 0; */
168 /* if (lua_type(L, -1) == LUA_TSTRING) { */
169 /* s = lua_tolstring(L, -1, &k); */
170 /* cs = (size_t) string_lookup(s, k); */
171 /* } */
172 /* lua_pushinteger(L, (lua_Number) cs); */
173 /* return 1; */
174 /* } */
176 static int run_get_next(lua_State * L)
178 saved_tex_scanner texstate;
179 save_tex_scanner(texstate);
180 get_next();
181 make_new_token(L, cur_cmd, cur_chr, cur_cs);
182 unsave_tex_scanner(texstate);
183 return 1;
187 This is experimental code:
189 local t1 = token.get_next()
190 local t2 = token.get_next()
191 local t3 = token.get_next()
192 local t4 = token.get_next()
193 -- watch out, we flush in sequence
194 token.put_next { t1, t2 }
195 -- but this one gets pushed in front
196 token.put_next ( t3, t4 )
197 -- so when we get wxyz we put yzwx!
199 At some point we can consider a token.print that delays and goes via
200 the same rope mechanism as texio.prints and friends but then one can
201 as well serialize the tokens and do a normal print so there is no real
202 gain in it. After all, the tokenlib operates at the input level so we
203 might as well keep it there.
207 inline static int run_put_next(lua_State * L)
209 int n = lua_gettop(L);
210 int m = 0;
211 int i = 0;
212 halfword h = null;
213 halfword t = null;
214 halfword x = null;
215 lua_token *p ;
216 if (n == 0) {
217 /* we accept a single nil argument */
218 return 0;
220 lua_get_metatablelua(luatex_token);
221 m = lua_gettop(L);
222 if (lua_type(L,1) == LUA_TTABLE) {
223 if (n>1) {
224 normal_error("token lib","only one table permitted in put_next");
225 } else {
226 for (i = 1;; i++) {
227 lua_rawgeti(L, 1, i); /* table mt token */
228 if (lua_type(L,-1) == LUA_TNIL) {
229 break;
230 } else {
231 p = lua_touserdata(L, -1);
232 if (p == NULL) {
233 normal_error("token lib","lua <token> expected in put_next (1)");
234 } else if (!lua_getmetatable(L, -1)) { /* table mt token mt */
235 normal_error("token lib","lua <token> expected in put_next (2)");
236 } else if (!lua_rawequal(L, m, -1)) {
237 normal_error("token lib","lua <token> expected in put_next (3)");
238 } else {
239 fast_get_avail(x) ;
240 token_info(x) = token_info(p->token);
241 if (h == null) {
242 h = x;
243 } else {
244 token_link(t) = x;
246 t = x;
248 lua_pop(L, 1);
252 } else {
253 for (i = 1; i <= n; i++) {
254 p = lua_touserdata(L,i);
255 if (p == NULL) {
256 normal_error("token lib","lua <token> expected in put_next (4)");
257 } else if (!lua_getmetatable(L, i)) { /* table mt token mt */
258 normal_error("token lib","lua <token> expected in put_next (5)");
259 } else if (!lua_rawequal(L, m, -1)) {
260 normal_error("token lib","lua <token> expected in put_next (6)");
261 } else {
262 fast_get_avail(x) ;
263 token_info(x) = token_info(p->token);
264 if (h == null) {
265 h = x;
266 } else {
267 token_link(t) = x;
269 t = x;
271 lua_pop(L, 1);
274 if (h == null) {
275 /* can't happen */
276 } else {
277 begin_token_list(h,0);
279 lua_settop(L,n);
280 return 0;
283 static int run_scan_keyword(lua_State * L)
285 saved_tex_scanner texstate;
286 const char *s = luaL_checkstring(L, -1);
287 int v = 0;
288 if (s) {
289 save_tex_scanner(texstate);
290 if (scan_keyword(s)) {
291 v = 1;
293 unsave_tex_scanner(texstate);
295 lua_pushboolean(L,v);
296 return 1;
299 static int run_scan_csname(lua_State * L)
301 unsigned char *s;
302 int t;
303 saved_tex_scanner texstate;
304 save_tex_scanner(texstate);
305 get_next();
306 t = (cur_cs ? cs_token_flag + cur_cs : token_val(cur_cmd, cur_chr));
307 if (t >= cs_token_flag && ((s = get_cs_text(t - cs_token_flag)) != (unsigned char *) NULL)) {
308 if (is_active_string(s))
309 lua_pushstring(L, (char *) (s + 3));
310 else
311 lua_pushstring(L, (char *) s);
312 } else {
313 lua_pushnil(L);
315 unsave_tex_scanner(texstate);
316 return 1;
319 static int run_scan_int(lua_State * L)
321 saved_tex_scanner texstate;
322 int v = 0;
323 save_tex_scanner(texstate);
324 scan_int();
325 v = cur_val;
326 unsave_tex_scanner(texstate);
327 lua_pushinteger(L,(int)v);
328 return 1;
331 static int run_scan_dimen(lua_State * L)
333 saved_tex_scanner texstate;
334 int v = 0, o = 0;
335 int inf = false, mu = false;
336 int t = lua_gettop(L);
337 if (t>0)
338 inf = lua_toboolean(L,1); /* inf values allowed ?*/
339 if (t>1)
340 mu = lua_toboolean(L,2); /* mu units required ?*/
341 save_tex_scanner(texstate);
342 scan_dimen( mu,inf, false); /* arg3 = shortcut */
343 v = cur_val;
344 o = cur_order;
345 unsave_tex_scanner(texstate);
346 lua_pushinteger(L,v);
347 if (inf) {
348 lua_pushinteger(L,(lua_Number)o);
349 return 2;
350 } else {
351 return 1;
355 static int run_scan_glue(lua_State * L)
357 saved_tex_scanner texstate;
358 int v = 0;
359 int mu = false;
360 int t = lua_gettop(L);
361 if (t>0)
362 mu = lua_toboolean(L,1); /* mu units required ?*/
363 save_tex_scanner(texstate);
364 scan_glue((mu ? mu_val_level : glue_val_level));
365 v = cur_val; /* which is a glue_spec node */
366 unsave_tex_scanner(texstate);
367 lua_nodelib_push_fast(L,(halfword)v);
368 return 1;
371 static int run_scan_toks(lua_State * L)
373 saved_tex_scanner texstate;
374 int macro_def = false, xpand = false;
375 halfword t, saved_defref;
376 int i = 1;
377 int top = lua_gettop(L);
378 if (top>0)
379 macro_def = lua_toboolean(L,1); /* \\def ? */
380 if (top>1)
381 xpand = lua_toboolean(L,2); /* expand ? */
382 save_tex_scanner(texstate);
383 saved_defref = def_ref;
384 (void) scan_toks(macro_def, xpand);
385 t = def_ref;
386 unsave_tex_scanner(texstate);
387 def_ref = saved_defref;
388 /* This function returns a pointer to the tail of a new token
389 list, and it also makes |def_ref| point to the reference count at the
390 head of that list. */
391 lua_newtable(L);
392 while (token_link(t)) {
393 t = token_link(t);
394 push_token(L,t);
395 lua_rawseti(L,-2,i++);
397 return 1;
400 static int run_scan_string(lua_State * L) /* HH */
401 { /* can be simplified, no need for intermediate list */
402 saved_tex_scanner texstate;
403 halfword t, saved_defref;
404 save_tex_scanner(texstate);
405 do {
406 get_x_token();
407 } while ((cur_cmd == spacer_cmd) || (cur_cmd == relax_cmd));
408 if (cur_cmd == left_brace_cmd) {
409 back_input();
410 saved_defref = def_ref;
411 (void) scan_toks(false, true);
412 t = def_ref;
413 def_ref = saved_defref;
414 tokenlist_to_luastring(L,t);
415 } else if (cur_cmd == call_cmd) {
416 t = token_link(cur_chr);
417 tokenlist_to_luastring(L,t);
418 } else {
419 if (cur_cmd == 11 || cur_cmd == 12 ) {
420 char * str ;
421 luaL_Buffer b ;
422 luaL_buffinit(L,&b) ;
423 while (1) {
424 str = (char *) uni2str(cur_chr);
425 luaL_addstring(&b,(char *) str);
426 get_x_token();
427 if (cur_cmd != 11 && cur_cmd != 12 ) {
428 break ;
431 back_input();
432 luaL_pushresult(&b);
433 } else {
434 back_input();
435 lua_pushnil(L);
438 unsave_tex_scanner(texstate);
439 return 1;
442 static int run_scan_word(lua_State * L) /* HH */
444 saved_tex_scanner texstate;
445 save_tex_scanner(texstate);
446 do {
447 get_x_token();
448 } while ((cur_cmd == spacer_cmd) || (cur_cmd == relax_cmd));
449 if (cur_cmd == 11 || cur_cmd == 12 ) {
450 char *str ;
451 luaL_Buffer b ;
452 luaL_buffinit(L,&b) ;
453 while (1) {
454 str = (char *) uni2str(cur_chr);
455 luaL_addstring(&b,str);
456 xfree(str);
457 get_x_token();
458 if (cur_cmd != 11 && cur_cmd != 12 ) {
459 break ;
462 back_input();
463 luaL_pushresult(&b);
464 } else {
465 back_input();
466 lua_pushnil(L);
468 unsave_tex_scanner(texstate);
469 return 1;
472 static int run_scan_code(lua_State * L) /* HH */
474 saved_tex_scanner texstate;
475 int cc = DEFAULT_SCAN_CODE_SET ;
476 save_tex_scanner(texstate);
477 get_x_token();
478 if (cur_cmd < 16) {
479 if (lua_gettop(L)>0) {
480 cc = (int) lua_tointeger(L,-1);
481 if (cc == null) {
482 /* todo: message that we choose a default */
483 cc = DEFAULT_SCAN_CODE_SET ;
486 if (cc & (1<<(cur_cmd))) {
487 lua_pushinteger(L,(int)cur_chr);
488 } else {
489 lua_pushnil(L);
490 back_input();
492 } else {
493 lua_pushnil(L);
494 back_input();
496 unsave_tex_scanner(texstate);
497 return 1;
500 static int lua_tokenlib_is_token(lua_State * L) /* HH */
502 lua_pushboolean(L,maybe_istoken(L,1)==NULL ? 0 : 1);
503 return 1;
506 /* static int run_expand(lua_State * L) */
507 /* { */
508 /* (void) L; */
509 /* expand(); */
510 /* return 0; */
511 /* } */
513 static int run_lookup(lua_State * L)
515 const char *s;
516 size_t l;
517 int cs, cmd, chr;
518 if (lua_type(L, -1) == LUA_TSTRING) {
519 s = lua_tolstring(L, -1, &l);
520 if (l > 0) {
521 cs = string_lookup(s, l);
522 cmd = eq_type(cs);
523 chr = equiv(cs);
524 make_new_token(L, cmd, chr, cs);
525 return 1;
528 lua_pushnil(L);
529 return 1;
532 static int run_build(lua_State * L)
534 if (lua_type(L, 1) == LUA_TNUMBER) {
535 int cs = 0;
536 int chr = (int) lua_tointeger(L, 1);
537 int cmd = (int) luaL_optinteger(L, 2, get_cat_code(cat_code_table_par,chr));
538 if (cmd == 0 || cmd == 9 || cmd == 14 || cmd == 15) {
539 formatted_warning("token lib","not a good token, catcode %i can not be returned, so 12 will be used",(int) cmd);
540 cmd = 12;
541 } else if (cmd == 13) {
542 cs = active_to_cs(chr, false);
543 cmd = eq_type(cs);
544 chr = equiv(cs);
546 make_new_token(L, cmd, chr, cs);
547 return 1;
548 } else {
549 return run_lookup(L);
553 /* token instance functions */
555 static int lua_tokenlib_free(lua_State * L)
557 lua_token *n;
558 n = check_istoken(L, 1);
559 if (n->origin == LUA_ORIGIN) {
560 free_avail(n->token);
562 return 1;
565 /* fast accessors */
567 inline static int lua_tokenlib_get_command(lua_State * L)
569 lua_token *n = check_istoken(L, 1);
570 halfword t = token_info(n->token);
571 if (t >= cs_token_flag) {
572 lua_pushinteger(L,(int) eq_type((t - cs_token_flag)));
573 } else {
574 lua_pushinteger(L, token_cmd(t));
576 return 1;
579 inline static int lua_tokenlib_get_index(lua_State * L)
581 lua_token *n = check_istoken(L, 1);
582 halfword t = token_info(n->token);
583 int cmd = (t >= cs_token_flag ? eq_type(t - cs_token_flag) : token_cmd(t));
584 halfword e = equiv(t - cs_token_flag);
585 switch (cmd) {
586 case assign_int_cmd:
587 e -= count_base;
588 break;
589 case assign_attr_cmd:
590 e -= attribute_base;
591 break;
592 case assign_dimen_cmd:
593 e -= dimen_base;
594 break;
595 case assign_glue_cmd:
596 e -= skip_base;
597 break;
598 case assign_mu_glue_cmd:
599 e -= mu_skip_base;
600 break;
601 case assign_toks_cmd:
602 e -= toks_base;
603 break;
604 default:
605 e = -1;
606 break;
608 if ((e >= 0) && (e <= 65535)) {
609 lua_pushinteger(L, e);
610 } else {
611 lua_pushnil(L);
613 return 1;
616 inline static int lua_tokenlib_get_mode(lua_State * L)
618 lua_token *n = check_istoken(L, 1);
619 halfword t = token_info(n->token);
620 if (t >= cs_token_flag) {
621 lua_pushinteger(L, equiv(t - cs_token_flag));
622 } else {
623 lua_pushinteger(L, token_chr(t));
625 return 1;
628 inline static int lua_tokenlib_get_cmdname(lua_State * L)
630 lua_token *n = check_istoken(L, 1);
631 halfword t = token_info(n->token);
632 int cmd = (t >= cs_token_flag ? eq_type(t - cs_token_flag) : token_cmd(t));
633 lua_pushstring(L, command_names[cmd].cmd_name); /* can be sped up */
634 return 1;
637 inline static int lua_tokenlib_get_csname(lua_State * L)
639 lua_token *n = check_istoken(L, 1);
640 halfword t = token_info(n->token);
641 unsigned char *s;
642 if (t >= cs_token_flag && ((s = get_cs_text(t - cs_token_flag)) != (unsigned char *) NULL)) {
643 if (is_active_string(s))
644 lua_pushstring(L, (char *) (s + 3));
645 else
646 lua_pushstring(L, (char *) s);
647 } else {
648 lua_pushnil(L);
650 return 1;
653 inline static int lua_tokenlib_get_id(lua_State * L)
655 lua_token *n = check_istoken(L, 1);
656 lua_pushinteger(L, n->token);
657 return 1;
660 inline static int lua_tokenlib_get_tok(lua_State * L)
662 lua_token *n = check_istoken(L, 1);
663 halfword t = token_info(n->token);
664 lua_pushinteger(L, t);
665 return 1;
668 inline static int lua_tokenlib_get_active(lua_State * L)
670 lua_token *n = check_istoken(L, 1);
671 halfword t = token_info(n->token);
672 unsigned char *s;
673 if (t >= cs_token_flag && ((s = get_cs_text(t - cs_token_flag)) != (unsigned char *) NULL)) {
674 if (is_active_string(s))
675 lua_pushboolean(L,1);
676 else
677 lua_pushboolean(L,0);
678 free(s);
679 } else {
680 lua_pushboolean(L,0);
682 return 1;
685 inline static int lua_tokenlib_get_expandable(lua_State * L)
687 lua_token *n = check_istoken(L, 1);
688 halfword t = token_info(n->token);
689 int cmd = (t >= cs_token_flag ? eq_type(t - cs_token_flag) : token_cmd(t));
690 if (cmd > max_command_cmd) {
691 lua_pushboolean(L, 1);
692 } else {
693 lua_pushboolean(L, 0);
695 return 1;
698 inline static int lua_tokenlib_get_protected(lua_State * L)
700 lua_token *n = check_istoken(L, 1);
701 halfword t = token_info(n->token);
702 int cmd = (t >= cs_token_flag ? eq_type(t - cs_token_flag) : token_cmd(t));
703 if (cmd > max_command_cmd && (cmd >= call_cmd) && (cmd < end_template_cmd)) {
704 int chr = (t >= cs_token_flag ? equiv(t - cs_token_flag) : token_chr(t));
705 if (token_info(token_link(chr)) == protected_token) {
706 lua_pushboolean(L, 1);
707 } else {
708 lua_pushboolean(L, 0);
710 } else {
711 lua_pushboolean(L, 0);
713 return 1;
716 static int lua_tokenlib_getfield(lua_State * L)
718 const char *s = lua_tostring(L, 2);
719 if (lua_key_eq(s, command)) {
720 return lua_tokenlib_get_command(L);
721 } else if (lua_key_eq(s, index)) {
722 return lua_tokenlib_get_index(L);
723 } else if (lua_key_eq(s, mode)) {
724 return lua_tokenlib_get_mode(L);
725 } else if (lua_key_eq(s, cmdname)) {
726 return lua_tokenlib_get_cmdname(L);
727 } else if (lua_key_eq(s, csname)) {
728 return lua_tokenlib_get_csname(L);
729 } else if (lua_key_eq(s, id)) {
730 return lua_tokenlib_get_id(L);
731 } else if (lua_key_eq(s, tok)) {
732 return lua_tokenlib_get_tok(L);
733 } else if (lua_key_eq(s, active)) {
734 return lua_tokenlib_get_active(L);
735 } else if (lua_key_eq(s, expandable)) {
736 return lua_tokenlib_get_expandable(L);
737 } else if (lua_key_eq(s, protected)) {
738 return lua_tokenlib_get_protected(L);
739 } else {
740 lua_pushnil(L);
742 return 1;
745 /* end */
747 static int lua_tokenlib_equal(lua_State * L)
749 lua_token *n, *m;
750 n = check_istoken(L, 1);
751 m = check_istoken(L, 2);
752 if (token_info(n->token) == token_info(m->token)) {
753 lua_pushboolean(L,1);
754 return 1;
756 lua_pushboolean(L,0);
757 return 1;
760 static int lua_tokenlib_tostring(lua_State * L)
762 char *msg;
763 lua_token *n;
764 n = check_istoken(L, 1);
765 msg = xmalloc(256);
766 snprintf(msg, 255, "<%s token %d: %d>", (n->origin==LUA_ORIGIN?"lua":"tex"), n->token , token_info(n->token));
767 lua_pushstring(L, msg);
768 free(msg);
769 return 1;
772 static int lua_tokenlib_type(lua_State * L)
774 if (maybe_istoken(L,1)!=NULL) {
775 lua_pushstring(L,"token");
776 } else {
777 lua_pushnil(L);
779 return 1;
782 static int run_scan_token(lua_State * L)
784 saved_tex_scanner texstate;
785 save_tex_scanner(texstate);
786 get_x_token();
787 make_new_token(L, cur_cmd, cur_chr, cur_cs);
788 unsave_tex_scanner(texstate);
789 return 1;
792 /* experiment */
794 /* [catcodetable] csname content : \def\csname{content} */
795 /* [catcodetable] csname content global : \gdef\csname{content} */
796 /* [catcodetable] csname : \def\csname{} */
798 /* TODO: check for a quick way to set a macro to empty (HH) */
800 static int set_macro(lua_State * L)
802 const char *name = null;
803 const char *str = null;
804 const char *s = null;
805 size_t lname = 0;
806 size_t lstr = 0;
807 int cs, cc, ct;
808 int n = lua_gettop(L);
809 int a = 0 ; /* global state */
810 int nncs = no_new_control_sequence;
811 if (n == 0) {
812 return 0 ;
814 if (lua_type(L, 1) == LUA_TNUMBER) {
815 if (n == 1)
816 return 0;
817 ct = (int) lua_tointeger(L, 1);
818 name = lua_tolstring(L, 2, &lname);
819 if (n > 2)
820 str = lua_tolstring(L, 3, &lstr);
821 if (n > 3)
822 s = lua_tostring(L, 4);
823 } else {
824 ct = cat_code_table_par;
825 name = lua_tolstring(L, 1, &lname);
826 if (n > 1)
827 str = lua_tolstring(L, 2, &lstr);
828 if (n > 2)
829 s = lua_tostring(L, 3);
831 if (name == null) {
832 return 0 ;
834 if (s && (lua_key_eq(s, global))) {
835 a = 4;
837 no_new_control_sequence = false ;
838 cs = string_lookup(name, lname);
839 no_new_control_sequence = nncs;
840 if (lstr > 0) {
841 halfword p; /* tail of the token list */
842 halfword q; /* new node being added to the token list via |store_new_token| */
843 halfword t; /* token being appended */
844 const char *se = str + lstr;
845 p = temp_token_head;
846 set_token_link(p, null);
847 /* this left brace is used to store the number of arguments */
848 fast_store_new_token(left_brace_token);
849 /* and this ends the not present arguments, and no: we will not support arguments here*/
850 fast_store_new_token(end_match_token);
851 while (str < se) {
852 /* hh: str2uni could return len too (also elsewhere) */
853 t = (halfword) str2uni((const unsigned char *) str);
854 str += utf8_size(t);
855 cc = get_cat_code(ct,t);
856 /* this is a relating simple converter; if more is needed one can just use */
857 /* tex.print with a regular \def or \gdef and feed the string into the regular */
858 /* scanner; */
859 if (cc == 0) {
860 /* we have a potential control sequence so we check for it */
861 int _lname = 0 ;
862 int _s = 0 ;
863 int _c = 0 ;
864 halfword _cs = null ;
865 const char *_name = str ;
866 while (str < se) {
867 t = (halfword) str2uni((const unsigned char *) str);
868 _s = utf8_size(t);
869 _c = get_cat_code(ct,t);
870 if (_c == 11) {
871 str += _s ;
872 _lname = _lname + _s ;
873 } else if (_c == 10) {
874 /* we ignore a trailing space like normal scanning does */
875 str += _s ;
876 break ;
877 } else {
878 break ;
881 if (_s > 0) {
882 /* we have a potential \cs */
883 _cs = string_lookup(_name, _lname);
884 if (_cs == undefined_control_sequence) {
885 /* let's play safe and backtrack */
886 t = cc * (1<<21) + t ;
887 str = _name ;
888 } else {
889 t = cs_token_flag + _cs;
891 } else {
892 /* just a character with some meaning, so \unknown becomes effectively */
893 /* \\unknown assuming that \\ has some useful meaning of course */
894 t = cc * (1<<21) + t ;
895 str = _name ;
898 } else {
899 /* whatever token, so for instance $x^2$ just works given a tex */
900 /* catcode regime */
901 t = cc * (1<<21) + t ;
903 fast_store_new_token(t);
905 /* there is no fast_store_new_token(right_brace_token) needed */
906 define(cs, call_cmd + (a % 4), token_link(temp_token_head));
907 } else {
908 halfword p ;
909 halfword q; /* new node being added to the token list via |store_new_token| */
910 p = temp_token_head;
911 set_token_info(p,null);
912 fast_store_new_token(left_brace_token);
913 fast_store_new_token(end_match_token);
914 define(cs, call_cmd + (a % 4), token_link(temp_token_head));
916 return 0;
919 static const struct luaL_Reg tokenlib[] = {
920 { "type", lua_tokenlib_type },
921 { "create", run_build },
922 { "is_token", lua_tokenlib_is_token },
923 /* scanners */
924 { "get_next", run_get_next },
925 { "put_next", run_put_next },
926 { "scan_keyword", run_scan_keyword },
927 { "scan_int", run_scan_int },
928 { "scan_dimen", run_scan_dimen },
929 { "scan_glue", run_scan_glue },
930 { "scan_toks", run_scan_toks },
931 { "scan_code", run_scan_code },
932 { "scan_string", run_scan_string },
933 { "scan_word", run_scan_word },
934 { "scan_csname", run_scan_csname },
935 { "scan_token", run_scan_token }, /* expands next token if needed */
936 /* push into input stream */
938 { "write",luatwrite },
940 /* getters */
941 { "get_command", lua_tokenlib_get_command },
942 { "get_index", lua_tokenlib_get_index },
943 { "get_mode", lua_tokenlib_get_mode },
944 { "get_cmdname", lua_tokenlib_get_cmdname },
945 { "get_csname", lua_tokenlib_get_csname },
946 { "get_id", lua_tokenlib_get_id },
947 { "get_tok", lua_tokenlib_get_tok },
948 { "get_active", lua_tokenlib_get_active },
949 { "get_expandable", lua_tokenlib_get_expandable },
950 { "get_protected", lua_tokenlib_get_protected },
951 /* maybe more setters */
952 { "set_macro", set_macro },
953 /* probably never */
954 /* {"expand", run_expand}, */ /* does not work yet! */
955 /* {"csname_id", run_get_csname_id}, */ /* yes or no */
956 /* {"command_id", run_get_command_id}, */ /* yes or no */
957 /* {"cs_offset", run_get_cs_offset}, */ /* not that useful */
958 {NULL, NULL}
961 static const struct luaL_Reg tokenlib_m[] = {
962 {"__index", lua_tokenlib_getfield},
963 {"__tostring", lua_tokenlib_tostring},
964 {"__eq", lua_tokenlib_equal},
965 {"__gc", lua_tokenlib_free},
966 {NULL, NULL} /* sentinel */
969 int luaopen_token(lua_State * L)
971 /* the main metatable of token userdata */
972 luaL_newmetatable(L, TOKEN_METATABLE);
973 luaL_register(L, NULL, tokenlib_m);
974 luaL_register(L, "token", tokenlib);
975 return 1;