Skip to content

Commit 65c287f

Browse files
committed
docs: add first skeleton of API docs
...with a test ensuring the code works!
1 parent 6810313 commit 65c287f

3 files changed

Lines changed: 151 additions & 0 deletions

File tree

docs/src/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636

3737
## Tooling
3838

39+
- [The Teal API](./the_teal_api.md)
3940
- [Using tl with Lua](./using_tl_with_lua.md)
4041
- [Type definitions for third party libraries](./declaration_files.md)
4142
- [The Teal Standard Library and Lua compatibility](./teal_standard_library_and_lua_compatibility.md)

docs/src/the_teal_api.md

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
# The Teal API
2+
3+
If you have Lua application, you can load the Teal compiler API and use it to convert
4+
Teal source code into Lua source code on the fly. This is useful, for example, for
5+
adding Teal support to a Lua-based plugin system.
6+
7+
## Before we begin: getting the API
8+
9+
Before we `require` any code, let's consider how to integrate the Teal compiler
10+
in your application. As it is typical in the Lua ecosystem, there are a few
11+
ways to do it.
12+
13+
### An application which embeds Lua sources
14+
15+
If you have an application (let's say, written in C, C++ or Rust), which embeds Lua
16+
sources, the simplest way to do it is to embed the amalgamated Teal
17+
sources, `tl.lua`, into your application's Lua sources the same way you embed
18+
any other Lua modules. `tl.lua` is included in the Teal source distribution,
19+
and it is a single file which encapsulates all `teal.*` modules that comprise
20+
the Lua compiler.
21+
22+
### Using the `teal` modules directly
23+
24+
You might want to go this route if you are building a pure-Lua application,
25+
and you want to integrate dependencies using a package manager ecosystem such
26+
as LuaRocks or Lux. You can register a dependency on the `tl` package using
27+
your package manager of choice and require `teal` like you require any other
28+
module.
29+
30+
## The entry point
31+
32+
Now we can start by requiring the `teal` module, and getting a compiler instance:
33+
34+
```lua
35+
local teal = require("teal")
36+
37+
local compiler = teal.compiler()
38+
```
39+
40+
We then need to give the compiler some input, which can be a filename, or some
41+
Teal code as a string. This will produce an input handle.
42+
43+
To read from a file, you can use `open`:
44+
45+
```lua
46+
-- Let's create a simple .tl file:
47+
local fd = io.open("my_file.tl", "w")
48+
fd:write("print('hello')")
49+
fd:close()
50+
51+
-- We can load the file using the `open` method of the API:
52+
local handle1 = compiler:open("my_file.tl")
53+
54+
-- We don't need the file anymore
55+
os.remove("my_file.tl")
56+
```
57+
58+
To read from a string, use `input`. The optional second argument is
59+
a filename to be used in error messages.
60+
61+
```
62+
-- We can read Teal code directly as a string using `input`:
63+
local handle2 = compiler:input([[
64+
local x = 1
65+
local y = "oh-oh"
66+
print(x + y)
67+
]])
68+
```
69+
70+
We can use those handles to request either one or all steps of the compilation
71+
pipeline to be performed. Here is an example generating code all at once:
72+
73+
74+
```lua
75+
local lua_code = handle1:gen()
76+
assert(type(lua_code) == "string")
77+
```
78+
79+
And here we can see the use of the API generating it step by step, using
80+
the `handle2` example above, which contains a type error:
81+
82+
```lua
83+
-- Lexing the tokens should be fine
84+
local tokens, lex_errs = handle2:lex()
85+
assert(type(tokens) == "table")
86+
assert(#lex_errs == 0)
87+
88+
-- Parsing should be fine as well
89+
local ast, parse_errs = tokens:parse()
90+
assert(type(ast) == "table")
91+
assert(parse_errs == nil)
92+
93+
-- Checking should catch the type error from our example!
94+
local module, check_errs = ast:check()
95+
assert(type(module) == "table")
96+
assert(#check_errs.type_errors == 1)
97+
```
98+
99+
Of course, if the code contains no errors, you can also call `gen`
100+
and generate the Lua output. Both methods will produce the same result:
101+
102+
```
103+
local handle3 = compiler:input([[
104+
local x: integer = 1
105+
local y: integer = 2
106+
print(x + y)
107+
]])
108+
109+
-- Showcasing all steps
110+
local lua_code = handle3:lex():parse():check():gen()
111+
assert(lua_code == "local x = 1\nlocal y = 2\nprint(x + y)")
112+
113+
-- Or going straight to gen
114+
local lua_code2 = handle3:gen()
115+
assert(lua_code == lua_code2)
116+
```

spec/docs/api_spec.lua

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
local function lines(script)
2+
local out = {}
3+
for i, line in ipairs(script) do
4+
table.insert(out, ("%d\t%s"):format(i, line))
5+
end
6+
return table.concat(out, "\n")
7+
end
8+
9+
describe("API doc_nameation", function()
10+
it("works", function()
11+
local script = {}
12+
local doc_name = "docs/src/the_teal_api.md"
13+
local fd = io.open(doc_name)
14+
local store = false
15+
for line in fd:lines() do
16+
if store then
17+
if line:match("^```") then
18+
store = false
19+
else
20+
table.insert(script, line)
21+
end
22+
else
23+
if line:match("^```") then
24+
store = true
25+
end
26+
end
27+
end
28+
local script_text = table.concat(script, "\n")
29+
local code, err = load(script_text)
30+
assert(code, err)
31+
local pok, perr = pcall(code)
32+
assert(pok, "Error running code from " .. doc_name .."\n"..tostring(perr).."\n".."source:\n" .. lines(script))
33+
end)
34+
end)

0 commit comments

Comments
 (0)