diff options
author | Case Duckworth | 2024-02-21 09:28:49 -0600 |
---|---|---|
committer | Case Duckworth | 2024-02-21 09:28:49 -0600 |
commit | 70ec5254814f9531e5ca2024465d0e01130306b7 (patch) | |
tree | 45a4d49115eca436a8467ce4cebfc8cee1f6f9c6 /read.lua | |
download | lam-70ec5254814f9531e5ca2024465d0e01130306b7.tar.gz lam-70ec5254814f9531e5ca2024465d0e01130306b7.zip |
Initial commit
Diffstat (limited to 'read.lua')
-rw-r--r-- | read.lua | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/read.lua b/read.lua new file mode 100644 index 0000000..72bbd4d --- /dev/null +++ b/read.lua | |||
@@ -0,0 +1,74 @@ | |||
1 | --- lam.read | ||
2 | |||
3 | local read = {} | ||
4 | |||
5 | local types = require "types" | ||
6 | local util = require "util" | ||
7 | |||
8 | function read.tokenize (str) | ||
9 | --[[ Convert a string of characters into a list of tokens ]] | ||
10 | assert(str, "No program given") | ||
11 | local tbl = {} | ||
12 | local word = "" | ||
13 | local push_word = | ||
14 | function () | ||
15 | if word:len() > 0 then | ||
16 | table.insert(tbl, word) | ||
17 | word = "" | ||
18 | end | ||
19 | end | ||
20 | |||
21 | for c = 1, #str do | ||
22 | char = string.char(str:byte(c)) | ||
23 | if char == " " or char == "\t" or char == "\n" then | ||
24 | push_word() | ||
25 | elseif char == "(" then | ||
26 | push_word() | ||
27 | table.insert(tbl, "(") | ||
28 | elseif char == ")" then | ||
29 | push_word() | ||
30 | table.insert(tbl, ")") | ||
31 | else | ||
32 | word = word .. char | ||
33 | end | ||
34 | end | ||
35 | push_word() | ||
36 | return tbl | ||
37 | end | ||
38 | |||
39 | function read.read (str) | ||
40 | -- [[ Read a scheme expression from a string ]] | ||
41 | |||
42 | local function Atom (token) | ||
43 | local n = tonumber(token) | ||
44 | if n then return n | ||
45 | else return tostring(token) | ||
46 | end | ||
47 | end | ||
48 | |||
49 | local function read_tokens (tokens) | ||
50 | --[[ Read a list of tokens from `tokenize' ]] | ||
51 | assert(next(tokens), "Unexpected EOF") | ||
52 | token = util.pop(tokens) | ||
53 | if token == "(" then | ||
54 | local L = {} | ||
55 | while tokens[1] ~= ")" do | ||
56 | table.insert(L, read_tokens(tokens)) | ||
57 | end | ||
58 | util.pop(tokens) -- remove ")" | ||
59 | return L | ||
60 | elseif token == ")" then | ||
61 | error("Unexpected ')'") | ||
62 | else | ||
63 | return Atom(token) | ||
64 | end | ||
65 | end | ||
66 | |||
67 | return read_tokens(read.tokenize(str)) | ||
68 | end | ||
69 | |||
70 | return setmetatable(read, { __call = | ||
71 | function(_, str) | ||
72 | return read.read(str) | ||
73 | end, | ||
74 | }) | ||