-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathlib.rs
162 lines (136 loc) · 4.88 KB
/
lib.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
use mlua::prelude::*;
const ALICORN: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/alicorn.lua"));
extern "C-unwind" {
fn luaopen_lpeg(L: *mut mlua::lua_State) -> std::ffi::c_int;
fn luaopen_lfs(L: *mut mlua::lua_State) -> std::ffi::c_int;
}
pub struct Alicorn {
lua: Lua,
}
impl Alicorn {
pub fn new(unsafe_lua: Option<Lua>) -> Result<Self, mlua::Error> {
let lua = unsafe_lua.unwrap_or_else(|| unsafe { Lua::unsafe_new() });
// Load C libraries we already linked
unsafe {
let _: mlua::Value =
lua.load_from_function("lpeg", lua.create_c_function(luaopen_lpeg)?)?;
let _: mlua::Value =
lua.load_from_function("lfs", lua.create_c_function(luaopen_lfs)?)?;
}
lua.load(
r#"
jit.opt.start("maxtrace=10000")
jit.opt.start("maxmcode=4096")
jit.opt.start("recunroll=5")
jit.opt.start("loopunroll=60")
"#,
)
.exec()?;
lua.load(ALICORN).exec()?;
lua.load(
r#"
metalanguage = require "metalanguage"
evaluator = require "evaluator"
format = require "format-adapter"
base_env = require "base-env"
terms = require "terms"
exprs = require "alicorn-expressions"
profile = require "profile"
function alc_parse_string(src)
return format.read(src, "<string value>")
end
function alc_parse_file(filename)
local f = io.open(filename)
if not f then
error("Couldn't find " .. filename)
end
local s = format.read(f:read("a"), filename)
f:close()
return s
end
function alc_process(code)
local env = base_env.create()
local shadowed, env = env:enter_block(terms.block_purity.effectful)
local ok, expr, env = code:match(
{ exprs.block(metalanguage.accept_handler, exprs.ExpressionArgs.new(terms.expression_goal.infer, env)) },
metalanguage.failure_handler,
nil
)
if not ok then
print(tostring(expr))
error("inference failed (error printed to stdout)")
end
local env, bound_expr, purity = env:exit_block(expr, shadowed)
return bound_expr
end
function alc_evaluate(bound_expr)
local type, usages, term = evaluator.infer(bound_expr, terms.typechecking_context())
local gen = require "terms-generators"
local set = gen.declare_set
local unique_id = gen.builtin_table
evaluator.typechecker_state:flow(
type,
nil,
terms.value.program_type(
terms.value.effect_row(set(unique_id)(terms.TCState), terms.value.effect_empty),
evaluator.typechecker_state:metavariable(terms.typechecking_context()):as_value()
),
nil,
"final flow check"
)
return evaluator.evaluate(term, terms.runtime_context())
end
function alc_execute(program)
local result_exec = evaluator.execute_program(program)
--print("result_exec: (value term follows)")
--print(result_exec)
return result_exec:unwrap_host_tuple_value():unpack()
end
"#,
)
.exec()?;
Ok(Self { lua })
}
pub fn parse(&self, source: impl AsRef<str>) -> Result<mlua::Value, mlua::Error> {
let alc_parse_string: LuaFunction = self.lua.load("alc_parse_string").eval()?;
alc_parse_string.call(source.as_ref())
}
pub fn parse_file(
&self,
path: impl AsRef<std::path::Path>,
) -> Result<mlua::Value, mlua::Error> {
let alc_parse_file: LuaFunction = self.lua.load("alc_parse_file").eval()?;
alc_parse_file.call(path.as_ref().as_os_str().to_string_lossy())
}
pub fn process<'a>(&'a self, parsed: mlua::Value<'a>) -> Result<mlua::Value<'a>, mlua::Error> {
let alc_process: LuaFunction = self.lua.load("alc_process").eval()?;
alc_process.call(parsed)
}
pub fn evaluate<'a>(&'a self, terms: mlua::Value<'a>) -> Result<mlua::Value<'a>, mlua::Error> {
let alc_evaluate: LuaFunction = self.lua.load("alc_evaluate").eval()?;
alc_evaluate.call(terms)
}
pub fn execute<'a, R: FromLuaMulti<'a>>(
&'a self,
program: mlua::Value<'a>,
) -> Result<R, mlua::Error> {
let execute_program: LuaFunction = self.lua.load("alc_execute").eval()?;
execute_program.call(program)
}
}
#[test]
fn test_runtest_file() {
// set the working directory to some random temporary folder to sabotage loading any of the files from this crate, as a crate including this one wouldn't have access to those files
let old = std::env::current_dir().unwrap();
let temp_dir = std::env::temp_dir();
let root = std::path::Path::new(&temp_dir);
std::env::set_current_dir(&root).unwrap();
let alicorn = Alicorn::new(None).unwrap();
// Restore working dir so we can find testfile.alc
std::env::set_current_dir(&old).unwrap();
let ast = alicorn.parse_file("testfile.alc").unwrap();
let terms = alicorn.process(ast).unwrap();
let program = alicorn.evaluate(terms).unwrap();
let result: LuaValue<'_> = alicorn.execute(program).unwrap();
println!("LUA RESULT: {:?}", result);
}