ada.2: typo
[jackhill/mal.git] / docs / Hints.md
1 # Mal/Make-a-Lisp Implementation Hints
2
3 <a name="milliseconds"></a>
4
5 ### How do I get milliseconds since epoch for the "time-ms" function?
6 ### Does the "time-ms" function have to return millisecond since epoch?
7
8 Most languages usually have some way to do this natively even though
9 it might be buried deeply in the language. If you are having trouble
10 finding how to do this in your target language, consider asking the
11 question on stackoverflow (if it has not been asked already) or asking
12 on a discussion channel for your language because there is a good
13 chance somebody there knows how and will answer quickly (if there is
14 a native way at all).
15
16 As a last resort you can always shell out and call the date command
17 like this:
18
19 ```
20 date +%s%3N
21 ```
22
23 There are currently two implementations where this method was
24 necessary (probably): bash and make. Unfortunately this method is
25 limited to Linux/UNIX.
26
27 Also, "time-ms" technically just needs to return accurate milliseconds
28 since some arbitrary point in time (even program start) in order to be
29 used correctly for timing/benchmarking. For consistency it is best if
30 it returns epoch milliseconds, but this is not strictly required if
31 you language limitations make it difficult (e.g. size limit of
32 integers).
33
34
35 <a name="function_references"></a>
36
37 ### How do I implement core/native functions if my language does not have any sort of function references (function pointers, closures, lambdas, etc)?
38 ### How do I implement mal functions in step4 if I do not have function references?
39
40 There are very few language that do not have any sort of function
41 references so I suggest asking about the specific problem you are
42 having on stackoverflow or a discussion channel for your language. In
43 the rare case where you have a language without some sort of function
44 reference abstraction, then you may have to implement a single
45 function with a large switch statement (or equivalent) that calls out
46 to the appropriate native core function ("+", "list", "throw", etc).
47 In other words, you create a function that implements "function
48 references" rather than using a feature of your language. You will
49 still need to store the symbol names for those function in the base
50 REPL environment but you will have some sort of tagging or marker that
51 will indicate to the `EVAL` function that it should call your "big
52 switch" function.
53
54 In addition, if your language has no sort of closure/anonymous
55 function capability (note that with sufficient object oriented
56 features you can implement closure like functionality), then in step4
57 you will need to borrow the way that functions are implemented from
58 step5. In other words, functions become a normal data type that stores
59 the function body (AST), the parameter list and the environment at the
60 time the function is defined. When the function is invoked, `EVAL`
61 will then evaluate these stored items rather than invoking a function
62 closure. It is less convenient to have to do this at step4, but the
63 bright side is that step5 will be simpler because you just have to
64 implement the TCO loop because you have already refactored how
65 functions are stored in step4.
66
67 <a name="IO"></a>
68
69 ### How do I implement terminal input and output in a language which does not have standard I/O capabilities?
70
71 If your target language has some way to get data in and out while it
72 is running (even if it is not standard terminal or file I/O) then you
73 will need to create some sort of wrapper script (see
74 `vimscript/run_vimscript.sh`) or call out to a shell script (see
75 `make/readline.mk` and `make/util.mk`) or implement some other
76 "appropriate" hack to to get the data in and out. As long
77 as your implementation can be used with the test runner and the hack
78 is just for working around I/O limitations in your target language,
79 it is considered legitimate for upstream inclusion.
80
81 ### How do I read the command-line arguments if my language runtime doesn't support access to them?
82
83 Most languages give access to the command-line arguments that were passed to
84 the program, either as an argument to the `main` function (like `argc` and
85 `argv` in C) or as a global variable (like `sys.argv` in Python). If your
86 target language doesn't have such mechanisms, consider adding a wrapper script
87 that will read the command-line arguments that were passed to the script and
88 pass them to the program in a way that the program can read. This might be
89 through an environment variable (if the target language allows reading from
90 environment variables) or through a temporary file.
91
92
93 <a name="no_reader_object">
94
95 ### How can I implement the reader without using a mutable object?
96
97 You do not need a mutable object, but you do need someway of keeping
98 track of the current position in the token list. One way to implement
99 this is to pass both the token list and the current position to the
100 reader functions (read_form, read_list, read_atom, etc) and return
101 both the parsed AST and the new token list position. If your language
102 does not allow multiple values to be returned from functions then you
103 may need to define a data structure to return both the new position
104 and the parsed AST together. In other words, the pseudo-code would
105 look something like this:
106
107 ```
108 ast, position = read_list(tokens, position)
109 ```
110
111 ---
112
113 Answers for the following questions are TBD.
114
115 ### How do I implement slurp in a language without the ability to read raw file data?
116
117 <a name="exceptions">
118
119 ### How do I support raising/throwing arbitrary objects in a language that does not support that?
120 ### What do I do if my implementation language only supports string exceptions?
121
122
123