Commit | Line | Data |
---|---|---|
0198b7a2 | 1 | # Mal/Make-a-Lisp Implementation Hints |
df5589d9 JM |
2 | |
3 | <a name="milliseconds"></a> | |
4 | ||
5 | ### How do I get milliseconds since epoch for the "time-ms" function? | |
ae964c68 | 6 | ### Does the "time-ms" function have to return millisecond since epoch? |
df5589d9 JM |
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 | ||
ae964c68 JM |
19 | ``` |
20 | date +%s%3N | |
21 | ``` | |
df5589d9 | 22 | |
c19139e1 DM |
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. | |
df5589d9 JM |
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 | ||
ae964c68 JM |
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? | |
df5589d9 JM |
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 | ||
ae964c68 | 69 | ### How do I implement terminal input and output in a language which does not have standard I/O capabilities? |
df5589d9 JM |
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 | ||
817316df DM |
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 | |
0198b7a2 | 84 | the program, either as an argument to the `main` function (like `argc` and |
817316df DM |
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 | ||
df5589d9 JM |
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 |