print.js 3.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. /*
  2. Implementation of the Python3 print version. Due to Python2 grammar we have
  3. to mimic the named keywords after *args as kwargs. Though this does not change
  4. anything for the internal implementation
  5. */
  6. var print_f = function function_print(kwa) {
  7. Sk.builtin.pyCheckArgs("print", arguments, 0, Infinity, true, false);
  8. var args = Array.prototype.slice.call(arguments, 1);
  9. var kwargs = new Sk.builtins.dict(kwa);
  10. var _kwargs = Sk.ffi.remapToJs(kwargs);
  11. // defaults, null for None
  12. var kw_list = {
  13. "sep": " ",
  14. "end": "\n",
  15. "file": null
  16. };
  17. var remap_val;
  18. var is_none;
  19. // check for sep; string or None
  20. remap_val = kwargs.mp$lookup(new Sk.builtin.str("sep"));
  21. if(remap_val !== undefined) {
  22. is_none = Sk.builtin.checkNone(remap_val);
  23. if(Sk.builtin.checkString(remap_val) || is_none) {
  24. kw_list["sep"] = is_none ? kw_list["sep"] : Sk.ffi.remapToJs(remap_val); // only reassign for string
  25. } else {
  26. throw new Sk.builtin.TypeError("sep must be None or a string, not " + Sk.abstr.typeName(remap_val));
  27. }
  28. }
  29. // check for end; string or None
  30. remap_val = kwargs.mp$lookup(new Sk.builtin.str("end"));
  31. if(remap_val !== undefined) {
  32. is_none = Sk.builtin.checkNone(remap_val);
  33. if(Sk.builtin.checkString(remap_val) || is_none) {
  34. kw_list["end"] = is_none ? kw_list["end"] : Sk.ffi.remapToJs(remap_val); // only reassign for string
  35. } else {
  36. throw new Sk.builtin.TypeError("end must be None or a string, not " + Sk.abstr.typeName(remap_val));
  37. }
  38. }
  39. // check for file
  40. // allow None, though just keep null or check if value has attribute write
  41. remap_val = kwargs.mp$lookup(new Sk.builtin.str("file"));
  42. if(remap_val !== undefined) {
  43. is_none = Sk.builtin.checkNone(remap_val);
  44. if(is_none || remap_val.tp$getattr("write") !== undefined) {
  45. kw_list["file"] = is_none ? kw_list["file"] : remap_val;
  46. } else {
  47. throw new Sk.builtin.AttributeError("'" + Sk.abstr.typeName(remap_val) + "' object has no attribute 'write'");
  48. }
  49. }
  50. // loop through outputs and create output string
  51. var s = "";
  52. var i;
  53. for(i = 0; i < args.length; i++) {
  54. s += (new Sk.builtin.str(args[i])).v; // get str repr
  55. s += kw_list.sep;
  56. }
  57. if(args.length > 0 && kw_list.sep.length > 0) {
  58. s = s.substring(0, s.length-kw_list.sep.length);
  59. }
  60. s += kw_list.end;
  61. if(kw_list.file !== null) {
  62. // currently not tested, though it seems that we need to see how we should access the write function in a correct manner
  63. return Sk.misceval.callsim(kw_list.file.write, kw_list.file, new Sk.builtin.str(s)); // callsim to write function
  64. } else {
  65. var sys = Sk.importModule("sys");
  66. Sk.misceval.apply(sys["$d"]["stdout"]["write"], undefined, undefined, undefined, [sys["$d"]["stdout"], new Sk.builtin.str(s)]);
  67. return Sk.builtin.none.none$;
  68. }
  69. // ToDo:
  70. // cpython print function may receive another flush kwarg that flushes the output stream immediatelly
  71. };
  72. print_f.co_kwargs = true;
  73. print_f.co_name = new Sk.builtin.str('print');
  74. Sk.builtin.print = new Sk.builtin.func(print_f);
  75. Sk.builtin.print.__doc__ = new Sk.builtin.str("print(value, ..., sep=' ', end='\\n', file=sys.stdout, flush=False)\n\nPrints the values to a stream, or to sys.stdout by default.\nOptional keyword arguments:\nfile: a file-like object (stream); defaults to the current sys.stdout.\nsep: string inserted between values, default a space.\nend: string appended after the last value, default a newline.\nflush: whether to forcibly flush the stream.");
  76. Sk.builtin.input.co_name = new Sk.builtin.str('input');