-
Notifications
You must be signed in to change notification settings - Fork 0
/
lush.lua
195 lines (161 loc) · 4.04 KB
/
lush.lua
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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
local Object = require 'eject'
local Lush = Object:extend 'Lush'
Lush:include( require 'eject.mixins.SubclassIsSubtable' )
--[[do
function Lush:getenv()
local env = _ENV or _G
if self.Env:isInstanceOf( env ) then
return env
else
return nil
end
end
function Lush:commit()
local env = self:getenv()
if env then
env:commit()
end
end
function Lush:begin( cmd )
local env = self:getenv()
if env then
env:push()
end
end
end--]]
local Exception = Lush:extend 'Exception'
do
function Exception:initialize( name )
self.name = name
end
function Exception:__tostring()
return self.name and self.name..'\n'..debug.traceback() or self
end
end
Exception:extend 'StdioName'
local Redirection = Lush:extend 'Redirection'
local RedirectionStep = Redirection:extend 'Step'
local RedirectionChain = Redirection:extend 'Chain'
do
function RedirectionStep:initialize( from, to, append )
self.from = from
self.to = to
self.append = not not append
end
function RedirectionStep:chain( other )
return Lush.Redirection.Chain:new( self, other )
end
function RedirectionChain:initialize( ... )
self.steps = { ... }
end
function RedirectionChain:chain( other )
error 'TODO'
end
end
local AbstractFileDesc = Lush:extend 'AbstractFileDesc'
do
function AbstractFileDesc:appendTo( other )
return Lush.Redirection.Step:new( self, other, true )
end
function AbstractFileDesc:writeTo( other )
return Lush.Redirection.Step:new( self, other, false )
end
AbstractFileDesc.__bxor = AbstractFileDesc.appendTo
AbstractFileDesc.__sub = AbstractFileDesc.writeTo
end
AbstractFileDesc:extend 'FileDesc'
local StdioDesc = AbstractFileDesc:extend 'StdioDesc'
do
function StdioDesc:initialize( name )
local what = name:match '^std(%a+)$'
if what == 'in' or what == 'out' or what == 'err' then
self.name = name
else
error( Lush.Exception.StdioName:new( 'invalid standard io name, should be one of std{in|out|err}' ))
end
end
end
local Command = Lush:extend 'Command'
do
function Command:initialize( name )
local currentenv = loadstring( 'return _ENV' )()
--[[ugh, so, this is necessary because even though _ENV is global variable,
it is actually an upvalue, that gets bound at function definition time,
so we get around that by creating a function in the current env]]
Lush:commit()
Lush:begin( self )
self.name = name
self.redirections = {}
end
function Command:redirect( redirection )
table.insert( self.redirections, redirection )
return self
end
Command.__bxor = Command.redirect
function Command:evaluate()
error 'TODO'
end
function Command:addArgs( ... )
print'TODO: addArgs'
return self
end
function Command:__call( ... )
local x = ...
if x ~= nil then
self:addArgs( ... )
return self
else
return self:evaluate()
end
end
end
local Name = Lush:extend 'Name'
do
function Name:initialize( name )
self.name = name
end
function Name:__bnot()
return StdioDesc:new( self.name )
end
for method in ('__bxor,__call,redirect'):gmatch( '[^,]+' ) do
Name[ method ] = function( self, ... )
local cmd = Command:new( self.name )
return cmd[ method ]( cmd, ... )
end
end
end
local Env = Lush:extend 'Env'
do
function Env:initialize( super )
self.superenv = super--needs to be non-nil, otherwise we'd get a stack overflow in the __index metamethod
self.inprogress = {}
end
local rawget, type = rawget, type
function Env:__index( name )
local classthing = self._class[ name ]
if classthing ~= nil then
return classthing
end
local superenv = rawget( self, 'superenv' )
local superthing = type( superenv ) == 'table' and superenv[ name ]
if superthing ~= nil then
return superthing
else
return Name:new( name )
end
end
function Env:begin( cmd )
table.insert( self.inprogress, cmd )
end
function Env:commit()
for _, cmd in ipairs( self.inprogress ) do
cmd:evaluate()
end
self.inprogress = {}
end
--used to coerce string into file descriptors
function Env:f( ... )
return Lush.AbstractFileDesc.FileDesc:new( ... )
end
end
return Lush