00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include <basix/string.hpp>
00014 #include <basix/table.hpp>
00015 #include <basix/literal.hpp>
00016 #include <basix/compound.hpp>
00017 #include <basix/row_tuple.hpp>
00018 #include <basix/lisp_syntax.hpp>
00019 namespace mmx {
00020
00021 #define DATA_BEGIN ((char) 2)
00022 #define DATA_END ((char) 5)
00023 #define DATA_ESCAPE ((char) 27)
00024 #define DATA_COMMAND '\20'
00025
00026 generic print_mmx (const generic& g);
00027 string as_texmacs_snippet (const generic& g);
00028
00029
00030
00031
00032
00033 static string texmacs_pending= "";
00034
00035 void
00036 texmacs_command (const string& cmd) {
00037 texmacs_pending << " " << cmd << "\n";
00038 }
00039
00040 string
00041 texmacs_flush_commands () {
00042 if (texmacs_pending == "") return "";
00043 string s=
00044 string (DATA_BEGIN) *
00045 "command:(begin" * texmacs_pending * ")" *
00046 string (DATA_END);
00047 texmacs_pending= "";
00048 return s;
00049 }
00050
00051 void
00052 texmacs_dynamic_event (const string& id, const generic& val) {
00053 string v= as_texmacs_snippet (as_generic (flatten (val)));
00054 texmacs_command ("(locus-set \"" * id * "\" '" * v * ")");
00055 mmout << texmacs_flush_commands ();
00056 }
00057
00058
00059
00060
00061
00062 generic add_modes (const generic& g, int mode);
00063
00064 generic
00065 add_modes (const generic& g, int mode, int new_mode) {
00066
00067 generic r= add_modes (g, new_mode);
00068 if (is_func (r, "$concat", 1)) r= r[1];
00069 if (mode == new_mode) return r;
00070 else if (is_func (r, "$math", 1)) return r;
00071 else if (is_func (r, "$text", 1)) return r;
00072 else if (new_mode == 1) return gen ("$math", r);
00073 else if (new_mode == 2) return gen ("$text", r);
00074 else return r;
00075 }
00076
00077 generic
00078 add_modes (const generic& g, int mode) {
00079
00080 if (!is<compound> (g) || !is<literal> (g[0])) return g;
00081 if (is_func (g, "$math", 1)) return add_modes (g[1], mode, 1);
00082 if (is_func (g, "$text", 1)) return add_modes (g[1], mode, 2);
00083 if (is_func (g, "$inmath", 1)) return add_modes (g[1], 1);
00084 if (is_func (g, "$intext", 1)) return add_modes (g[1], 2);
00085 vector<generic> v= copy (compound_to_vector (g));
00086 for (nat i=1; i<N(v); i++) v[i]= add_modes (v[i], mode);
00087 return vector_to_compound (v);
00088 }
00089
00090
00091
00092
00093
00094 static void
00095 init (table<generic,generic>& t, const generic& key, const generic& val) {
00096 t[key]= val;
00097 }
00098
00099 static table<generic,generic>
00100 texmacs_symbol_table () {
00101 table<generic,generic> t;
00102
00103 init (t, "/\\", "tm$wedge");
00104 init (t, "mathcatalan", "tm$mathcatalan");
00105 init (t, "@", "tm$circ");
00106 init (t, "><", "tm$join");
00107 init (t, "derivative", "D");
00108 init (t, "mathe", "tm$mathe");
00109 init (t, "<=>", "tm$Leftrightarrow");
00110 init (t, "matheuler", "tm$matheuler");
00111 init (t, ">", "tm$gtr");
00112 init (t, ">=", "tm$geqslant");
00113 init (t, ">>", "tm$gg");
00114 init (t, "mathi", "tm$mathi");
00115 init (t, "=>", "tm$Rightarrow");
00116 init (t, "Infty", "tm$infty");
00117 init (t, "->", "tm$rightarrow");
00118 init (t, "<", "tm$less");
00119 init (t, "<=", "tm$leqslant");
00120 init (t, "<<", "tm$ll");
00121 init (t, ":->", "tm$mapsto");
00122 init (t, ".!", "!");
00123 init (t, "!", "tm$neg");
00124 init (t, "\\/", "tm$vee");
00125 init (t, "partial", "tm$partial");
00126 init (t, "mathpi", "tm$mathpi");
00127 init (t, ".'", "'");
00128 init (t, ".`", "`");
00129 init (t, "..", "tm$ldots");
00130 init (t, "::", "tm$colons");
00131 init (t, ":>", "tm$transtype");
00132 init (t, "!=", "tm$neq");
00133 init (t, "|", "|");
00134 init (t, "||", "tm$||");
00135 init (t, "xor", "tm$veebar");
00136 init (t, ":=", "tm$assign");
00137 init (t, "+=", "tm$plusassign");
00138 init (t, "-=", "tm$minusassign");
00139 init (t, "*=", "tm$astassign");
00140 init (t, "/=", "tm$overassign");
00141
00142 init (t, "alpha", "tm$alpha");
00143 init (t, "beta", "tm$beta");
00144 init (t, "gamma", "tm$gamma");
00145 init (t, "delta", "tm$delta");
00146 init (t, "epsilon", "tm$varepsilon");
00147 init (t, "zeta", "tm$zeta");
00148 init (t, "eta", "tm$eta");
00149 init (t, "theta", "tm$theta");
00150 init (t, "iota", "tm$iota");
00151 init (t, "kappa", "tm$kappa");
00152 init (t, "lambda", "tm$lambda");
00153 init (t, "mu", "tm$mu");
00154 init (t, "nu", "tm$nu");
00155 init (t, "xi", "tm$xi");
00156 init (t, "omicron", "tm$omicron");
00157 init (t, "pi", "tm$pi");
00158 init (t, "rho", "tm$rho");
00159 init (t, "sigma", "tm$sigma");
00160 init (t, "tau", "tm$tau");
00161 init (t, "upsilon", "tm$upsilon");
00162 init (t, "phi", "tm$varphi");
00163 init (t, "chi", "tm$chi");
00164 init (t, "psi", "tm$psi");
00165 init (t, "omega", "tm$omega");
00166
00167 init (t, "Alpha", "tm$Alpha");
00168 init (t, "Beta", "tm$Beta");
00169 init (t, "Gamma", "tm$Gamma");
00170 init (t, "Delta", "tm$Delta");
00171 init (t, "Epsilon", "tm$Epsilon");
00172 init (t, "Zeta", "tm$Zeta");
00173 init (t, "Eta", "tm$Eta");
00174 init (t, "Theta", "tm$Theta");
00175 init (t, "Iota", "tm$Iota");
00176 init (t, "Kappa", "tm$Kappa");
00177 init (t, "Lambda", "tm$Lambda");
00178 init (t, "Mu", "tm$Mu");
00179 init (t, "Nu", "tm$Nu");
00180 init (t, "Xi", "tm$Xi");
00181 init (t, "Omicron", "tm$Omicron");
00182 init (t, "Pi", "tm$Pi");
00183 init (t, "Rho", "tm$Rho");
00184 init (t, "Sigma", "tm$Sigma");
00185 init (t, "Tau", "tm$Tau");
00186 init (t, "Upsilon", "tm$Upsilon");
00187 init (t, "Phi", "tm$Phi");
00188 init (t, "Chi", "tm$Chi");
00189 init (t, "Psi", "tm$Psi");
00190 init (t, "Omega", "tm$Omega");
00191
00192 return t;
00193 }
00194
00195
00196
00197
00198
00199 bool
00200 is_infix (const generic& g, const generic& op) {
00201 return is_func (g, "$infix", 3) && g[2] == op;
00202 }
00203
00204 generic
00205 unbracket (const generic& g) {
00206 if (is_func (g, "$bracket", 3)) return g[2];
00207 else return g;
00208 }
00209
00210 bool
00211 is_alpha (const generic& g) {
00212 if (!is<literal> (g)) return false;
00213 string s= literal_to_string (g);
00214 for (nat i=0; i<N(s); i++)
00215 if ((s[i] < 'a' || s[i] > 'z') &&
00216 (s[i] < 'A' || s[i] > 'Z'))
00217 return false;
00218 return true;
00219 }
00220
00221 void
00222 concat_append (vector<generic>& v, const generic& g) {
00223 if (g == "");
00224 else if (is_func (g, "$concat")) {
00225 vector<generic> w= compound_to_vector (g);
00226 for (nat i=1; i<N(w); i++) concat_append (v, w[i]);
00227 }
00228 else if (N(v) == 0) v << g;
00229 else if (is<literal> (v[N(v)-1]) && is<literal> (g))
00230 v[N(v)-1]= generic (literal_to_string (v[N(v)-1]) * literal_to_string (g));
00231 else if (is_func (v[N(v)-1], "$lprime", 1) && is_func (g, "$lprime", 1)) {
00232 generic p (literal_to_string (v[N(v)-1][1]) * literal_to_string (g[1]));
00233 v[N(v)-1]= gen ("$lprime", p);
00234 }
00235 else if (is_func (v[N(v)-1], "$rprime", 1) && is_func (g, "$rprime", 1)) {
00236 generic p (literal_to_string (v[N(v)-1][1]) * literal_to_string (g[1]));
00237 v[N(v)-1]= gen ("$rprime", p);
00238 }
00239 else v << g;
00240 }
00241
00242 generic
00243 as_texmacs (const generic& g) {
00244 if (is<literal> (g)) {
00245 if (g == "$lf") return gen ("$lf");
00246 if (g == "$cr") return gen ("$cr");
00247 if (g == "$spc") return gen (" ");
00248 static table<generic,generic> t= texmacs_symbol_table ();
00249 generic h= g;
00250 if (contains (t, h)) h= t[h];
00251 if (!is<literal> (h)) return h;
00252 string s= literal_to_string (h);
00253 if (starts (s, "tm$"))
00254 return generic ("<" * s (3, N(s)) * ">");
00255 string r;
00256 for (nat i=0; i<N(s); i++)
00257 if (s[i] == '<') r << "<less>";
00258 else if (s[i] == '>') r << "<gtr>";
00259 else r << s[i];
00260 return r;
00261 }
00262 else if (is_func (g, "$concat")) {
00263 vector<generic> v;
00264 for (nat i=1; i<N(g); i++)
00265 concat_append (v, as_texmacs (g[i]));
00266 if (N(v) == 0) return generic ("");
00267 else if (N(v) == 1) return v[0];
00268 else return gen ("$concat", v);
00269 }
00270 else if (is_func (g, "$keyword", 1))
00271 return as_texmacs (gen ("$strong", g[1]));
00272 else if (is_func (g, "$keyword", 2))
00273 return as_texmacs (gen ("$concat", gen ("$strong", g[1]), "$spc", g[2]));
00274 else if (is_func (g, "$bracket", 3))
00275 return as_texmacs (gen ("$around*", g[1], g[2], g[3]));
00276 else if (is_func (g, "$prefix", 2)) {
00277 if (g[1] == "'" || g[1] == "`")
00278 return as_texmacs (gen ("$concat", gen ("$lprime", g[1]), g[2]));
00279 else return as_texmacs (gen ("$concat", g[1], g[2]));
00280 }
00281 else if (is_func (g, "$postfix", 2)) {
00282 if (g[2] == "'" || g[2] == "`")
00283 return as_texmacs (gen ("$concat", g[1], gen ("$lprime", g[2])));
00284 else return as_texmacs (gen ("$concat", g[1], g[2]));
00285 }
00286 else if (is_func (g, "$infix", 3)) {
00287 if (g[2] == "/")
00288 return as_texmacs (gen ("$frac", unbracket (g[1]), unbracket (g[3])));
00289 else if (g[2] == "^")
00290 return as_texmacs (gen ("$concat",
00291 g[1], gen ("$rsup", unbracket (g[3]))));
00292 else if (g[2] == "|" || g[2] == "||")
00293 return as_texmacs (gen ("$concat", g[1], gen ("$mid", g[2]), g[3]));
00294 else {
00295 generic op= as_texmacs (g[2]);
00296 if (is_alpha (op))
00297 op= gen ("$concat", "$spc", gen ("$strong", op), "$spc");
00298 return as_texmacs (gen ("$concat", g[1], g[2], g[3]));
00299 }
00300 }
00301 else if (is_func (g, "$bigop") && N(g) >= 3) {
00302 vector<generic> v;
00303 if (g[1] == GEN_PLUS && is_func (g[2], GEN_MINUS, 1))
00304 v << generic ("-") << g[2][1];
00305 else v << g[2];
00306 for (nat i=3; i<N(g); i++) {
00307 if (g[1] == GEN_PLUS && is_func (g[i], GEN_MINUS, 1))
00308 v << generic ("-") << g[i][1];
00309 else
00310 v << g[1] << g[i];
00311 }
00312 return as_texmacs (gen ("$concat", v));
00313 }
00314 else if (is_func (g, "$operate", 2)) {
00315 if (is_func (g[2], "$bracket", 3) && g[2][1] == "[")
00316 return as_texmacs (gen ("$concat",
00317 g[1], gen ("$rsub", unbracket (g[2]))));
00318 else return as_texmacs (gen ("$concat", g[1], g[2]));
00319 }
00320 else if (is_func (g, "$hlist")) {
00321 if (N(g) == 1) return generic ("");
00322 vector<generic> v= vec (g[1]);
00323 for (nat i=2; i<N(g); i++) v << generic (",") << g[i];
00324 return as_texmacs (gen ("$concat", v));
00325 }
00326 else if (is_func (g, "$vlist")) {
00327 vector<generic> v;
00328 for (nat i=1; i<N(g); i++)
00329 if (is_func (g[i], "$hlist"))
00330 v << gen ("$row", cdr (compound_to_vector (g[i])));
00331 if (N(v) == 0) return generic ("");
00332 return as_texmacs (gen ("$tabular*", gen ("$table", v)));
00333 }
00334 else if (is_func (g, "$indent")) {
00335 vector<generic> v;
00336 for (nat i=1; i<N(g); i++)
00337 concat_append (v, as_texmacs (g[i]));
00338 return gen ("$concat", gen ("$indent", gen ("$concat", v)), gen ("$lf"));
00339 }
00340 else if (is_func (g, "$text", 1))
00341 return gen ("$text", as_texmacs (g[1]));
00342 else if (is_func (g, "$math", 1))
00343 return gen ("$math", as_texmacs (g[1]));
00344 else if (is_func (g, "$dynamic"))
00345 return gen ("$locus", gen ("$id", as_texmacs (g[1])), as_texmacs (g[2]));
00346 else if (is<compound> (g)) {
00347 vector<generic> v;
00348 for (nat i=1; i<N(g); i++)
00349 v << as_texmacs (g[i]);
00350 return gen (g[0], v);
00351 }
00352 else ERROR ("not implemented");
00353 }
00354
00355
00356
00357
00358
00359 generic
00360 replace_lf (const generic& g) {
00361 if (is<literal> (g)) return g;
00362 else if (is_func (g, "$concat")) {
00363 bool block= false;
00364 vector<generic> d;
00365 vector<generic> c;
00366 for (nat i=1; i<N(g); i++) {
00367 if (is_func (g[i], "$lf", 0)) {
00368 if (N(c) == 0) d << generic ("");
00369 else if (N(c) == 1) d << c;
00370 else if (N(c) > 1) d << gen ("$concat", c);
00371 c= vector<generic> ();
00372 }
00373 else if (is_func (g[i], "$cr", 0)) block= true;
00374 else c << replace_lf (g[i]);
00375 }
00376 if (N(c) == 1) d << c;
00377 else if (N(c) != 0) d << gen ("$concat", c);
00378 if (N(d) != 1 || block) return gen ("$document", d);
00379 return d[0];
00380 }
00381 else if (is<compound> (g)) {
00382 vector<generic> v;
00383 for (nat i=1; i<N(g); i++)
00384 v << replace_lf (g[i]);
00385 return gen (g[0], v);
00386 }
00387 else {
00388 mmout << "g= " << g << ": " << type_name (g) << "\n";
00389 ERROR ("TeXmacs document expected");
00390 }
00391 }
00392
00393
00394
00395
00396
00397 generic
00398 texmacs_expand (const generic& g) {
00399 if (is_func (g, "tm$with"))
00400 return texmacs_expand (g[N(g)-1]);
00401 else if (is_func (g, "tm$itemize", 1) || is_func (g, "tm$enumerate", 1))
00402 return gen ("$indent", texmacs_expand (g[1]));
00403 else if (is_func (g, "tm$item", 0))
00404 return generic ("* ");
00405 else if (is_func (g, "tm$folded", 2))
00406 return gen ("$varindent",
00407 gen ("$concat",
00408 generic ("o "), texmacs_expand (g[1])));
00409 else if (is_func (g, "tm$unfolded", 2))
00410 return gen ("$varindent",
00411 gen ("$concat",
00412 generic ("* "), texmacs_expand (g[1]),
00413 generic ("$lf"), texmacs_expand (g[2])));
00414 else if (is_func (g, "tm$folded-explain", 2))
00415 return texmacs_expand (g[1]);
00416 else if (is_func (g, "tm$unfolded-explain", 2))
00417 return gen ("$concat", texmacs_expand (g[1]),
00418 generic ("$lf"), generic ("$lf"), texmacs_expand (g[2]));
00419 else if (is_func (g, "tm$explain", 2))
00420 return gen ("$concat", texmacs_expand (g[1]), generic ("$lf"),
00421 gen ("$indent", texmacs_expand (g[2])));
00422 else if (is_func (g, "tm$explain-synopsis", 1))
00423 return gen ("$concat", generic (" --- "), texmacs_expand (g[1]));
00424 else if (is<compound> (g)) {
00425 vector<generic> v;
00426 for (nat i=1; i<N(g); i++) v << texmacs_expand (g[i]);
00427 if (is<literal> (g[0]) && starts (literal_to_string (g[0]), "tm$")) {
00428 if (N(v) == 1) return v[0];
00429 else return gen ("$concat", v);
00430 }
00431 else return gen (g[0], v);
00432 }
00433 else return g;
00434 }
00435
00436
00437
00438
00439
00440 static void
00441 texmacs_to_scheme (string& s, const generic& g) {
00442
00443 if (is<literal> (g)) s << quote (literal_to_string (g));
00444 else if (is<compound> (g) && is<literal> (g[0]) &&
00445 literal_to_string (g[0]) == " ")
00446 s << "\" \"";
00447 else if (is<compound> (g) && is<literal> (g[0])) {
00448 string op= literal_to_string (g[0]);
00449 if (starts (op, "tm$")) op= op (2, N(op));
00450 if (!starts (op, "$")) {
00451 mmerr << "op = " << op << "\n";
00452 mmerr << "args= " << compound_to_vector (g) << "\n";
00453 }
00454 ASSERT (starts (op, "$"), "invalid TeXmacs markup");
00455 s << "(" << op (1, N(op));
00456 for (nat i=1; i<N(g); i++) {
00457 s << " ";
00458 texmacs_to_scheme (s, g[i]);
00459 }
00460 s << ")";
00461 }
00462 else ERROR ("invalid TeXmacs markup");
00463 }
00464
00465 string
00466 as_texmacs_snippet (const generic& g) {
00467 string r= "";
00468 generic h= print_mmx (g);
00469 generic m= add_modes (h, 0, 1);
00470 generic t= as_texmacs (m);
00471 generic l= replace_lf (t);
00472 texmacs_to_scheme (r, l);
00473 return r;
00474 }
00475
00476 string
00477 as_texmacs_scheme (const generic& g) {
00478 string r= "(document ";
00479 generic h= print_mmx (g);
00480 generic m= add_modes (h, 0, 1);
00481 generic t= as_texmacs (m);
00482 generic l= replace_lf (t);
00483 texmacs_to_scheme (r, l);
00484 r << ")";
00485 return r;
00486 }
00487
00488
00489
00490
00491
00492 static string
00493 spaces (nat indent) {
00494 string s;
00495 for (nat i=0; i<indent; i++)
00496 s << " ";
00497 return s;
00498 }
00499
00500 static void
00501 write (string& r, const string& s) {
00502 nat i, n=N(s);
00503 for (i=0; i<n; i++) {
00504 char c= s[i];
00505 if (c == ' ' && ends (r, " ")) r << "\\ ";
00506 else if (c == '\n') r << "\\n";
00507 else if (c == '\t') r << "\\t";
00508 else if (c == '\0') r << "\\0";
00509 else if (c == '\\') r << "\\\\";
00510 else if (c == '<') r << "\\<";
00511 else if (c == '|') r << "\\|";
00512 else if (c == '>') r << "\\>";
00513 else if (c == '\34') r << c;
00514 else if (((unsigned char) c) < ' ') r << '\\' << (c+'@');
00515 else r << c;
00516 }
00517 }
00518
00519 static void
00520 scheme_to_tm (string& s, const generic& g, int indent) {
00521
00522 if (is<literal> (g))
00523 write (s, unquote (literal_to_string (g)));
00524 else if (is_func (g, "concat")) {
00525 for (nat i=1; i<N(g); i++)
00526 scheme_to_tm (s, g[i], indent);
00527 }
00528 else if (is_func (g, "document")) {
00529 for (nat i=1; i<N(g); i++) {
00530 if (i>1) {
00531 if (ends (s, "\n")) s << "\\;";
00532 s << "\n\n" << spaces (indent);
00533 }
00534 scheme_to_tm (s, g[i], indent);
00535 }
00536 }
00537 else if (is<compound> (g) && N(g) > 0 && is<literal> (g[0])) {
00538 string func= literal_to_string (g[0]);
00539 vector<generic> args= cdr (compound_to_vector (g));
00540 int i, last, n=N(args);
00541 for (i=n-1; i>=0; i--)
00542 if (is_func (args[i], "document"))
00543 break;
00544 last= i;
00545 if (last >= 0) {
00546 for (i=0; i<=n; i++) {
00547 bool flag= (i<n) && is_func (args[i], "document");
00548 if (i==0) s << "<\\" << func;
00549 else if (i==last+1) s << "</" << func;
00550 else if (is_func (args[i-1], "document")) s << "<|" << func;
00551 if (i==n) { s << ">"; break; }
00552
00553 if (flag) {
00554 s << ">";
00555 if (!ends (s, "\n")) s << "\n" << spaces (indent + 2);
00556 scheme_to_tm (s, args[i], indent + 2);
00557 if (!ends (s, "\n")) s << "\n" << spaces (indent);
00558 }
00559 else {
00560 s << "|";
00561 scheme_to_tm (s, args[i], indent);
00562 }
00563 }
00564 }
00565 else {
00566 s << "<" << func;
00567 for (i=0; i<n; i++) {
00568 s << "|";
00569 scheme_to_tm (s, args[i], indent);
00570 }
00571 s << ">";
00572 }
00573 }
00574 else ERROR ("invalid scheme markup");
00575 }
00576
00577 static string
00578 as_snippet (const generic& g) {
00579 string r= "";
00580 generic h= print_mmx (g);
00581 generic m= h;
00582 generic t= as_texmacs (m);
00583 generic l= replace_lf (t);
00584 texmacs_to_scheme (r, l);
00585 return r;
00586 }
00587
00588 string
00589 flatten_as_tm (const generic& x) {
00590 string r;
00591 generic g= as_generic (flatten (x));
00592 g= parse_lisp (as_snippet (g), true);
00593 if (is_func (g, "text", 1)) g= g[1];
00594 scheme_to_tm (r, g, 0);
00595 return r;
00596 }
00597
00598 string
00599 flatten_as_tm (const generic& x, const string& style) {
00600 string r;
00601 generic g= as_generic (flatten (x));
00602 g= parse_lisp (as_snippet (g), true);
00603 if (is_func (g, "text", 1)) g= g[1];
00604 if (!is_func (g, "document")) g= gen ("document", g);
00605 g= gen ("document", gen ("TeXmacs", string ("1.0.7.8")),
00606 gen ("style", style), gen ("body", g));
00607 scheme_to_tm (r, g, 0);
00608 return r;
00609 }
00610
00611 }