[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Some syntax troubles
- From: "Alexander Gladysh" <agladysh@...>
- Date: Fri, 17 Mar 2006 19:03:59 +0300
> -- Syntax is a bit more complicated that what you exacly want
> local Foo = in_context_of(my_dsl)
> {
> ["Alpha"] = { 'op1', "a", 'op2', "b" };
> ["Beta"] = { 'op2', "a", 'op1', "b", 'op3', "c" };
> };
Hey, this is an interesting idea for implementation of some kind of
virtual machine-interpreted DSL:
Silly example:
-- Should print 3.
interprete(make_vm()) 'add' '1 '2' 'prn'
Code follows.
Alexander.
=======
assert_is_function = function(val, msg)
assert(type(val) == "function", msg)
return val
end
assert_is_table = function(val, msg)
assert(type(val) == "table", msg)
return val
end
assert_is_string = function(val, msg)
assert(type(val) == "string", msg)
return val
end
in_context_of = function(t)
assert_is_table(t)
return function(func)
assert_is_function(func)
-- TODO: Get the original environment of the function!
setfenv(func, t)
return func(), setfenv(func, _G) -- Assuming setfenv returns nil.
end
end
local make_nary = function(num)
assert(num >= 0)
local wrapper = function(func)
assert_is_function(func)
-- Instruction parameter is for error reporting only.
-- TODO: These should be implemented more effectively,
-- removing table creation and function creation
-- on each operand call.
local brancher = function(callback, instruction_name)
assert_is_function(callback)
assert_is_string(instruction_name)
if num == 0 then
func()
return callback
else
local n = num
local operands = { }
local operand_collector
operand_collector = function(operand)
assert(operand, instruction_name .. " : " .. num .. "
operands required.")
table.insert(operands, operand)
n = n - 1
if n > 0 then
return operand_collector
else
func(unpack(operands))
return callback
end
end
return operand_collector
end
end
return brancher
end
return wrapper
end
interprete = function(vm_instructions)
assert(vm_instructions)
local interpreter
interpreter = function(op)
assert(op)
local handler = vm_instructions[op]
assert_is_function(handler, "Unknown instruction, " .. op)
return handler(interpreter, op)
end
return interpreter
end
interpreter_util =
{
-- TODO: Would benefit from optimized version of each!
nullary = make_nary(0);
unary = make_nary(1);
binary = make_nary(2);
nary = make_nary;
}
-- All VM API should be mentioned here due to in_context_of's setfenv call.
-- If this is not what you want, you can move implementation of instruction
-- handling functions outside of the instruction table declaration.
-- Or just remove that in_context_of call.
local my_vm_api =
{
print = print;
}
local make_vm_1 = function()
local vm = my_vm_api
return in_context_of(interpreter_util) (function()
return
{
op0 = nullary (function() vm.print("op0") end);
op1 = unary (function(var) vm.print("op1", var) end);
op2 = binary (function(var1, var2) vm.print("op2", var1, var2) end);
op3 = nary(3) (function(var1, var2, var3) vm.print("op3", var1,
var2, var3) end);
}
end)
end
-- Silly example for VM with state.
local make_vm_2 = function()
local op1 = 0
local op2 = 0
local result = 0
local vm = my_vm_api
return in_context_of(interpreter_util) (function()
return
{
add = binary (function(var1, var2) result = var1 + var2 end);
prn = nullary (function() vm.print(result) end);
}
end)
end
interprete(make_vm_1()) 'op0' 'op1' 'a' 'op0' 'op3' 'b' 'c' 'd' 'op2' 'e' 'f'
-- TODO: Handle "hanging" instructions with not enough parameters at
the end of the stream.
-- like "interprete(make_my_vm()) 'inc'". For example, it can
be done by passing
-- special 'end' opcode at the end of the stream.
interprete(make_vm_2()) 'prn' 'add' '1' '2' 'prn'
-- Note states of VMs are separate
interprete(make_vm_2()) 'prn'