@@ -2,22 +2,25 @@ package pman.format.pmsh;
22
33import tannus .io .* ;
44import tannus .ds .* ;
5+ import tannus .async .* ;
56import tannus .TSys as Sys ;
67
7- import pman .async . * ;
8+ import pman .format . pmsh . NewParser ;
89import pman .format .pmsh .Token ;
910import pman .format .pmsh .Expr ;
1011import pman .format .pmsh .Cmd ;
1112
12- import electron .Tools .* ;
13+ import edis .Globals .* ;
14+ import pman .Globals .* ;
1315import Slambda .fn ;
1416
1517using StringTools ;
1618using tannus .ds .StringUtils ;
1719using Lambda ;
1820using tannus .ds .ArrayTools ;
1921using Slambda ;
20- using pman .async .VoidAsyncs ;
22+ using tannus .async .Asyncs ;
23+ using pman .format .pmsh .ExprTools ;
2124
2225class Interpreter {
2326 /* Constructor Function */
@@ -92,7 +95,7 @@ class Interpreter {
9295 * execute the given expression
9396 */
9497 public function execute (e : Expr , complete : VoidCb ): Void {
95- async ( e )( complete );
98+ eval ( e , complete );
9699 }
97100
98101 /**
@@ -106,64 +109,147 @@ class Interpreter {
106109 }
107110
108111 /**
109- * build the given expression out into a VoidAsync
110- */
111- private function async (expr : Expr ): VoidAsync {
112- switch ( expr ) {
113- /* multiple expressions in a block */
114- case EBlock ( body ):
115- return ((body .map ( async )).series .bind ());
116-
117- /* variable assignment */
112+ evaluate the given expression, and obtain its return-value
113+ **/
114+ function eval (expr : Expr , complete : VoidCb ): Promise <ExprReturn > {
115+ switch expr {
116+ /* evaluate a word-expression */
117+ case EWord (word ):
118+ // evalWord(word, complete);
119+ complete ();
120+
121+ /* evaluate a variable assignment */
118122 case ESetVar (name , value ):
119- return function (done : VoidCb ): Void {
120- var sname = wordToString ( name );
121- var svalue = wordToString ( value );
122- environment [sname ] = svalue ;
123- done ();
124- };
123+ environment [wordToString (name )] = wordToString (value );
124+ complete ();
125+
126+ /* binary operator */
127+ case EBinaryOperator (op , leftExpr , rightExpr ):
128+ evalBinop (op , leftExpr , rightExpr , complete );
129+
130+ /* unary operator */
131+ case EUnaryOperator (op , expr ):
132+ throw EUnexpected ( expr );
133+
134+ /* block expression */
135+ case EBlock (exprs ), ERoot (exprs ):
136+ exprs .map (e -> (next -> eval (e , next ))).series ( complete );
125137
126138 /* basic command */
127- case ECommand (nameWord , params ):
128- var name = wordToString ( nameWord );
129- return function (done : VoidCb ): Void {
130- expand (params , function (? error , ? paramWords ) {
131- if (error != null ) {
132- done ( error );
133- }
134- else {
135- resolve (name , function (? error , ? command ) {
136- if (error != null ) {
137- done ( error );
138- }
139- else {
140- if (command != null ) {
141- resolveArgValues (paramWords , function (? error , ? args ) {
142- if (error != null )
143- done ( error );
144- else {
145- var commandArgs = paramWords .zipmap (args , fn ([word , value ] => new CmdArg (EWord (word ), value )));
146- command .execute (this , commandArgs , done .wrap (function (_ , ? err ) {
147- trace (' command exited' );
148- _ ( err );
149- }));
150- }
151- });
152- }
153- else {
154- done (' Error: No command " $name " found' );
155- }
156- }
157- });
158- }
159- });
160- };
139+ case ECommand (cmd ):
140+ evalCmd (cmd , complete );
161141
162- default :
163- throw ' Error: Unexpected $expr ' ;
142+ /* function declaration */
143+ case EFunc (name , expr ):
144+ commands [name ] = new FuncCmd (this , name , expr );
145+ complete ();
146+
147+ /* for-loop statement */
148+ case EFor (id , iter , expr ):
149+ complete ();
150+ }
151+
152+ return Promise .resolve (ERVoid );
153+ }
154+
155+ function evalBinop (op : Binop , left : Expr , right : Expr , complete : VoidCb ) {
156+ switch op {
157+ case OpAnd :
158+ evalAndOp (left , right , complete );
159+
160+ case OpOr :
161+ evalOrOp (left , right , complete );
162+
163+ case OpPipe :
164+ evalPipeOp (left , right , complete );
165+
166+ case _ :
167+ throw PmShError . EUnexpected (op );
164168 }
165169 }
166170
171+ function evalPipeOp (left : Expr , right : Expr , complete : VoidCb ) {
172+ eval (left , function (? error ) {
173+ if (error != null )
174+ complete ( error );
175+ else {
176+ trace (' TODO: Piping not yet working' );
177+ eval (right , complete );
178+ }
179+ });
180+ }
181+
182+ function evalAndOp (left : Expr , right : Expr , complete : VoidCb ) {
183+ eval (left , function (? error ) {
184+ if (error != null )
185+ complete ( error );
186+ else {
187+ eval (right , complete );
188+ }
189+ });
190+ }
191+
192+ function evalOrOp (left : Expr , right : Expr , complete : VoidCb ) {
193+ eval (left , function (? error ) {
194+ if (error == null )
195+ complete ();
196+ else {
197+ eval (right , complete );
198+ }
199+ });
200+ }
201+
202+ /**
203+ evaluate a Command expression
204+ **/
205+ function evalCmd (cmd : CommandExpr , complete : VoidCb ) {
206+ var name = resolve .bind (wordToString (cmd .command ), _ ).toPromise ();
207+ name .then (function (cmd : Cmd ) {
208+ this .currentCmd = cmd ;
209+ });
210+ var pwp : Promise <Array <Word >> = expand .bind (cmd .parameters , _ ).toPromise ();
211+ var pwvp : Promise <Array <Dynamic >> = pwp .derive (function (p , resolve , reject ) {
212+ p .then (function (words ) {
213+ resolveArgValues (words , function (? error , ? values ) {
214+ if (error != null ) {
215+ reject ( error );
216+ }
217+ else {
218+ resolve ( values );
219+ }
220+ });
221+ }, reject );
222+ });
223+ var pwpp : Promise <Pair <Array <Word >, Array <Dynamic >>> = Promise .pair (new Pair (pwvp , pwp ));
224+ var cap : Promise <Array <CmdArg >> = pwpp .transform (function (pair ) {
225+ return pair .left .zipmap (pair .right , fn ([word , value ] => new CmdArg (EWord (word ), value )));
226+ });
227+ var cmdt : Promise <Pair <Cmd , Array <CmdArg >>> = Promise .pair (new Pair (cap , name ));
228+ var cmdExpr : CommandExpr = cmd ;
229+ cmdt .then (function (pair ) {
230+ var cmd : Null <Cmd > = pair .left ,
231+ argv : Array <CmdArg > = pair .right ;
232+
233+ if (cmd == null ) {
234+ return complete (ECommandNotFound ( cmdExpr .command ));
235+ }
236+ else {
237+ cmd .execute (this , argv , complete .wrap (function (_ , ? error ) {
238+ _ (error );
239+
240+ currentCmd = null ;
241+ }));
242+ }
243+ }, complete .raise ());
244+ }
245+
246+ /**
247+ * build the given expression out into a VoidAsync
248+ */
249+ private function async (expr : Expr ): VoidAsync {
250+ return eval .bind (expr , _ );
251+ }
252+
167253 /**
168254 * resolve a Cmd from name
169255 */
@@ -229,23 +315,65 @@ class Interpreter {
229315 switch ( word ) {
230316 case Ident (s ), String (s , _ ):
231317 return s ;
318+
232319 case Ref (name ):
233320 if (environment .exists ( name )) {
234321 return environment [name ];
235322 }
236323 else {
237324 return ' ' ;
238325 }
326+
327+ case Interpolate (e ):
328+ throw EWhatTheFuck (' aww, poor design, sha' , e );
329+
330+ case Substitution (type , name , value ):
331+ return wordToString (Ref (name ));
239332 }
240333 }
241334
335+ /**
336+ obtain a value from a Word instance
337+ **/
338+ function evalWord (word : Word ): Promise <Dynamic > {
339+ return new Promise (function (resolve , reject ) {
340+ switch word {
341+ case Ident (ident ):
342+ return resolve ( ident );
343+
344+ case String (str , delimiter ):
345+ switch delimiter {
346+ case 0 , 1 :
347+ return resolve ( str );
348+
349+ case _ :
350+ return reject (EUnexpected ( delimiter ));
351+ }
352+
353+ case Ref (name ):
354+ return resolve (getenv (name ));
355+
356+ case Interpolate (e ):
357+ return reject (EWhatTheFuck (' command return-values need to be implemented before interpolation can be' , e ));
358+
359+ case Substitution (type , name , valueExpr ):
360+ return resolve (untyped evalSubstitution (type , evalWord (Ident (name )), valueExpr ));
361+ }
362+ });
363+ }
364+
365+ function evalSubstitution (type : SubstitutionType , left : Promise <Dynamic >, right : Expr ): Promise <Dynamic > {
366+ trace (' TODO: properly implement value substitution in pmbash' );
367+ return left ;
368+ }
369+
242370 /**
243371 * creates a 'partial'
244372 */
245373 public function createPartialFromExpr (e : Expr ): PmshPartial {
246374 switch ( e ) {
247- case ECommand (nameWord , params ), EBlock ([ECommand (nameWord , params )]):
248- return new PmshPartial (nameWord , params );
375+ case ECommand (cmd ), EBlock ([ECommand (cmd )]), ERoot ([ ECommand ( cmd )]):
376+ return new PmshPartial (cmd . command , cmd . parameters );
249377
250378 default :
251379 throw ' TypeError: partials may only be created from command-invokation expressions' ;
@@ -256,15 +384,20 @@ class Interpreter {
256384 * create a partial from a String
257385 */
258386 public function parsePartial (exprString : String ): PmshPartial {
259- return createPartialFromExpr (Parser .runString ( exprString ));
387+ return createPartialFromExpr (NewParser .runString ( exprString ));
260388 }
261389
262390/* === Instance Fields === */
263391
264392 public var commands : Map <String , Cmd >;
265393 public var environment : Dict <String , String >;
394+
395+ var currentCmd : Null <Cmd > = null ;
266396}
267397
398+ /**
399+ betty
400+ **/
268401@:access ( pman.format.pmsh. Interpreter )
269402@:structInit
270403class PmshPartial {
@@ -283,7 +416,7 @@ class PmshPartial {
283416 var fullParams = params ;
284417 if (additionalParams != null )
285418 fullParams = fullParams .concat ( additionalParams );
286- return ECommand (cmd , fullParams );
419+ return ECommand (new CommandExpr ( cmd , fullParams ) );
287420 }
288421
289422 /**
@@ -337,3 +470,22 @@ class PmshPartial {
337470 });
338471 }
339472}
473+
474+ /**
475+ values that evaluating an expression can yield
476+ **/
477+ enum ExprReturn {
478+ // no return value
479+ ERVoid ;
480+
481+ // the 'return' value from executing a command
482+ ERCommand (out : CmdReturn <Dynamic , Dynamic >);
483+
484+ // the 'return' value from evaluating a word-expression
485+ ERWord (wval : EValue <Dynamic >);
486+ }
487+
488+ enum CmdReturn <Val , Err > {
489+ CRReturn (value : EValue <Val >, error : Err ):CmdReturn <Val , Err >;
490+ CROutput (stdOut : ByteArray , stdErr : ByteArray ):CmdReturn <ByteArray , ByteArray >;
491+ }
0 commit comments