Re: [Lift] Re: Scala to JavaScript DSL ...

2009-12-21 Thread Naftoli Gugenheim
Inlined

2009/12/19 Marius marius.dan...@gmail.com

 If I may a few notes:

 Syntactically it doesn't seem to me that there are much differences
 between this and the initial proposal. Probably the most noticeable
 diffs are in algebraic expressions like

 Var(y) := (2:Expr) * x * 2

 which probably looks more appealing than

 Var(y) := 2 __* x __* 2


First, I should confess that I didn't look at your source code before I
wrote my approach, although I saw it now. That said, I agree that there is
plenty in common between the two approaches, and also a couple of
differences. Feel free to use whatever blend you like!


 The other thing is that you don't end JS statements with ;  ... I
 don't think this is a good JS practice. I added `;` function to allow
 user to specify this terminator when needed.


It would be trivial to have my implementation add semicolons in the
generated code without requiring any change in the DSL's usage.




I'm also not at all in favor of function names starting with capital
 letter.


Please rename them to whatever you like!



 I was also running into a Scala compiler crash when using constructs
 like: case class Fnc(name: String)(params: String*)(body : = String)
 {} :D


Then possibly functions are better suited than case classes for providing
the names of the DSL syntax. If that means you prefer lowercase names please
change them!



I'm not sure why in things like: def Function()(argNames: String*)
 (body: PartialFunction[List[JSIdent], Unit]): JSAnonFunc you used
 PartialFunctions ... you are callin gthe PF without checking if the
 function is defined for its parameter which could lead to MachError.


What would it help to intercept such a situation--to provide a more
descriptive error message? It's an error either way.
In any case, I realized after I wrote it (as I mentioned) that the signature
could be changed to
def Function(numParams: Int)(body: PartialFunction[List[JSIdent], Unit])
that is, there is no reason to specify names for the parameters. Since the
PF format binds scala identifiers to represent the arguments, names could be
autogenerated. Similarly,
val x = Var(x)
could be changed to
val x = Var()
and x would represent a JS var whose name is autogenerated.
I could be totally wrong but it seems to me that the ability to have Scala
identifiers and not just implicitly converted symbols provides more
scalability. For instance you could have utility functions in Scala that
help build the javascript but don't need the implicits in scope.




 I see you took a different approach of building JS code in a more
 imperative manner where generated code is kept in the ThreadGlobal
 state. My initial approach and actually my design intent was to use
 functional composition to write the code which tremendously simplifies
 the library code.


Could you elaborate? What makes your code more functional?

With your approach,
 JsIf('param1  30) {
   Var ('home) :=  (234: Js) + 3 / 3 `;`
   println(Hi there)
   Var ('someArray) := JsArray(1, 2, 3, 4, 5) `;`
   'myFunc(1, 2, do it, 'home) `;`
   $(#myID)  'attr(value, 123) `;`
 } ~
would not work, because JsIf's second parameter list takes a =Js, that is,
it only uses on the expression returned. In the above example, the
Var('home) ... line goes into a black hole.
In my case you have much more flexibility because the entire code block does
not have to be one long expression. All DSL invocations are captured.
This is also the reason my approach does not require using semicolons.
Also, it would be advantageous if the result of executing the DSL was the
regular Lift JavaScript AST. This would avoid code duplication in terms of
the algorithm that generates the output javascript text (which if it does
not already could have shared features like whitespace compression or pretty
printing), while at the same time allowing the generated AST to be processed
by code that can also work with plain Lift JavaScript AST objects. I'm not
clear how that would work with your approach, but with mine it's trivial.

I should mention that much of the inspiration for this builder approach came
from the SWT DSL, by Rodant.


 I made some adjustments to my initial approach and something like:

val js = JsFunc('myFunc, 'param1, 'param2) {
  JsIf('param1  30) {
 Var ('home) :=  (234: Js) + 3 / 3 `;`
 Var ('someArray) := JsArray(1, 2, 3, 4, 5) `;`
'myFunc(1, 2, do it, 'home) `;`
$(#myID)  'attr(value, 123) `;`
  } ~
  JsForEach(Var('i) in 'someArray) {
'console  'log(Hi there  + 'i) `;`
  } ~
  JsAnonFunc('arg1, 'arg2) {
   'alert(Anonymous function  + 'arg1 + 'arg2)
  }(1, 2) `;`
}
println(js.toJs)

 generates

 function myFunc( param1, param2 ) {
 if (param1  30) {
 var home = 234 + 3 / 3;
 var someArray = [ 1, 2, 3, 4, 5 ];
 myFunc(1, 2, do it, home);
 $(#myID).attr(value, 123);
 }
 for (var i in someArray) {
 console.log(Hi there 'i);
 }
 function ( 

Re: [Lift] Re: Scala to JavaScript DSL ...

2009-12-17 Thread Naftoli Gugenheim
I think I'm nearly there (that is a working equivalent of your sample) with 
G-d's help...

-
Mariusmarius.dan...@gmail.com wrote:

Let me know when you have something.

Br's,
Marius

On Dec 17, 8:58 am, Naftoli Gugenheim naftoli...@gmail.com wrote:
 I'm thinking of an approach to writing a DSL with a much cleaner syntax. I'll 
 try to put something together.

 -

 Marius Danciumarius.dan...@gmail.com wrote:

 All,

 I just want to see if there is any interest in the approach discussed here.
 As you know Lift has some interesting support for building JavaScript
 constructs from Scala code usig JsExp, JsCmd etc classes. I used quite a lot
 this support and it's great but if your JS code that you want to send down
 to the browser (say as an Ajax or Comet partial update response) gets a bit
 more complicated then constructing the JS fragment leads IMO to some
 cumbersome Scala code. I found myselft in quite a few situation to use JsRaw
 to write the JavaScript fragment in order for the code reader to understand
 what JavaScript code will be generated. But of course with JsRaw we put
 everything into a String so I'm not a big fan of this approach. So I started
 to define a JavaScript like DSL that IMO is closer to JavaScript form.
 Attached is a source code smaple of how this looks like, so for instance we
 can have something like:

 val js = JsFunc('myFunc, 'param1, 'param2) {
     JsIf('param1 __ 30) {
         Var('home) := Wrap(234 __- 3) __/ 2 `;`
         Var('someArray) := JsArray(1, 2, 3, 4, 5) `;`
         'myFunc(1, 2, do it, 'home) `;`
         $(#myID)  'attr(value, 123) `;`
       } ~
       JsForEach(Var('i) in 'someArray) {
         'console  'log(Hi there  __+ 'i) `;`
       } ~
       JsAnonFunc('arg1, 'arg2) {
        'alert(Anonymous function  __+ 'arg1 __+ 'arg2)
       }(1, 2) `;`
     }

     println(js.toJs)

 this yields the following JavaScript code:

 function myFunc( param1, param2 ) {
 if (param1  30) {
 var home = ( 234 - 3 ) / 2;
 var someArray = [ 1, 2, 3, 4, 5 ];
 myFunc(1, 2, do it, home);
 $(#myID).attr(value, 123);}

 for (var i in someArray) {
 console.log(Hi there  + i);}

 function ( arg1, arg2 ) {
 alert(Anonymous function  + arg1 + arg2)

 }(1, 2);
 }

 ... ok I just droped nonsense code in there for exemplification. A few
 words:

 1. JsIf, JsForEach describe JavaScript if and for(each) statements
 2. Functions like __, __, ... __+, __- are function that alows definition
 of boolean and/or algebraic expressions.
 3. Wrap just wraps an expression into ()
 4. Var defined a variable
 5 := defines an assignment
 6. JsFunc declares a JS function
 7. JsAnonFunc declares an anonymous function
 8. 'myFunc(1, 2, do it, 'home)  is simply a javascript function invocation
 by providing 4 parameter.
 9. ~ is just a function that chains statements that don;t necessarily end in
 ;

 Do you think that something like this would be usable in Lift?

 Br's,
 Marius

 --

 You received this message because you are subscribed to the Google Groups 
 Lift group.
 To post to this group, send email to lift...@googlegroups.com.
 To unsubscribe from this group, send email to 
 liftweb+unsubscr...@googlegroups.com.
 For more options, visit this group 
 athttp://groups.google.com/group/liftweb?hl=en.

--

You received this message because you are subscribed to the Google Groups 
Lift group.
To post to this group, send email to lift...@googlegroups.com.
To unsubscribe from this group, send email to 
liftweb+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/liftweb?hl=en.


--

You received this message because you are subscribed to the Google Groups 
Lift group.
To post to this group, send email to lift...@googlegroups.com.
To unsubscribe from this group, send email to 
liftweb+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/liftweb?hl=en.




Re: [Lift] Re: Scala to JavaScript DSL ...

2009-12-17 Thread Naftoli Gugenheim
Current state attached.


2009/12/17 Marius marius.dan...@gmail.com

 Let me know when you have something.

 Br's,
 Marius

 On Dec 17, 8:58 am, Naftoli Gugenheim naftoli...@gmail.com wrote:
  I'm thinking of an approach to writing a DSL with a much cleaner syntax.
 I'll try to put something together.
 
  -
 
  Marius Danciumarius.dan...@gmail.com wrote:
 
  All,
 
  I just want to see if there is any interest in the approach discussed
 here.
  As you know Lift has some interesting support for building JavaScript
  constructs from Scala code usig JsExp, JsCmd etc classes. I used quite a
 lot
  this support and it's great but if your JS code that you want to send
 down
  to the browser (say as an Ajax or Comet partial update response) gets a
 bit
  more complicated then constructing the JS fragment leads IMO to some
  cumbersome Scala code. I found myselft in quite a few situation to use
 JsRaw
  to write the JavaScript fragment in order for the code reader to
 understand
  what JavaScript code will be generated. But of course with JsRaw we put
  everything into a String so I'm not a big fan of this approach. So I
 started
  to define a JavaScript like DSL that IMO is closer to JavaScript form.
  Attached is a source code smaple of how this looks like, so for instance
 we
  can have something like:
 
  val js = JsFunc('myFunc, 'param1, 'param2) {
  JsIf('param1 __ 30) {
  Var('home) := Wrap(234 __- 3) __/ 2 `;`
  Var('someArray) := JsArray(1, 2, 3, 4, 5) `;`
  'myFunc(1, 2, do it, 'home) `;`
  $(#myID)  'attr(value, 123) `;`
} ~
JsForEach(Var('i) in 'someArray) {
  'console  'log(Hi there  __+ 'i) `;`
} ~
JsAnonFunc('arg1, 'arg2) {
 'alert(Anonymous function  __+ 'arg1 __+ 'arg2)
}(1, 2) `;`
  }
 
  println(js.toJs)
 
  this yields the following JavaScript code:
 
  function myFunc( param1, param2 ) {
  if (param1  30) {
  var home = ( 234 - 3 ) / 2;
  var someArray = [ 1, 2, 3, 4, 5 ];
  myFunc(1, 2, do it, home);
  $(#myID).attr(value, 123);}
 
  for (var i in someArray) {
  console.log(Hi there  + i);}
 
  function ( arg1, arg2 ) {
  alert(Anonymous function  + arg1 + arg2)
 
  }(1, 2);
  }
 
  ... ok I just droped nonsense code in there for exemplification. A few
  words:
 
  1. JsIf, JsForEach describe JavaScript if and for(each) statements
  2. Functions like __, __, ... __+, __- are function that alows
 definition
  of boolean and/or algebraic expressions.
  3. Wrap just wraps an expression into ()
  4. Var defined a variable
  5 := defines an assignment
  6. JsFunc declares a JS function
  7. JsAnonFunc declares an anonymous function
  8. 'myFunc(1, 2, do it, 'home)  is simply a javascript function
 invocation
  by providing 4 parameter.
  9. ~ is just a function that chains statements that don;t necessarily end
 in
  ;
 
  Do you think that something like this would be usable in Lift?
 
  Br's,
  Marius
 
  --
 
  You received this message because you are subscribed to the Google Groups
 Lift group.
  To post to this group, send email to lift...@googlegroups.com.
  To unsubscribe from this group, send email to
 liftweb+unsubscr...@googlegroups.comliftweb%2bunsubscr...@googlegroups.com
 .
  For more options, visit this group athttp://
 groups.google.com/group/liftweb?hl=en.

 --

 You received this message because you are subscribed to the Google Groups
 Lift group.
 To post to this group, send email to lift...@googlegroups.com.
 To unsubscribe from this group, send email to
 liftweb+unsubscr...@googlegroups.comliftweb%2bunsubscr...@googlegroups.com
 .
 For more options, visit this group at
 http://groups.google.com/group/liftweb?hl=en.




--

You received this message because you are subscribed to the Google Groups 
Lift group.
To post to this group, send email to lift...@googlegroups.com.
To unsubscribe from this group, send email to 
liftweb+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/liftweb?hl=en.




DSL.scala
Description: Binary data


Re: [Lift] Re: Scala to JavaScript DSL ...

2009-12-17 Thread Naftoli Gugenheim
Okay!
The following code:

 val jsFunc: JSFunc = Function(myFunc)(param1, param2) {case
 param1 :: param2 :: Nil =

Var(someArray) := Array(1, 2, 3, 4, 5)

If(param1  30) {

  val x = Var(x)   // now we can use either x or 'x

  x := (234 - 3) / 2 // calculation happens in scala

  Var(y) := (2:Expr) * x * 2   // calculation happens in
 javascript

  'jsFunc(1, 2, do it, 'y)

  val $ = JSIdent($)

  $(#myID)  'attr(value, 123)

} Else {

  'console  'log(=30)

}

ForEach(Var(i) In 'someArray) {

  'console  'log(Hi there   'i)

}

Function()(arg1, arg2) { case arg1 :: arg2 :: Nil =

  'alert(Anonymous function (  arg1  ,   arg2  ))

}(1,2)

}

println(jsFunc.toCode)


Produces:

function myFunc(param1, param2) {

var someArray

someArray = [1.0, 2.0, 3.0, 4.0, 5.0]

if((param1  30.0)) {

var x

x = 115.0

var y

y = ((2.0 * x) * 2.0)

jsFunc(1.0, 2.0, do it, y)

($(#myID)).attr(value, 123)

} else {

(console).log(=30)

}

var i

for(i in someArray) {

(console).log((Hi there  + i))

}

function (arg1, arg2) {

alert(Anonymous function ( + arg1) + , )  arg2) + )))

}(1.0, 2.0)

}


It may be desirable that instead of defining your own names for Vars and
function parameters, names are auto-generated, since you can anyway use
typesafe scala identifiers. This would save boilerplate and produce more
obfuscated code, and other than the name generating algorithm is a trivial
change to make.
Note that since I am not familiar with Lift's JavaScript APIs I just wrote
my own AST, which consists of case classes that contain their data
parameters and a toCode method. Feel free to delete them and plug Lift's
classes instead--there is no dependency on anything unique about them.
Also note that to prevent string + ident from compiling as a string to be
outputted and instead output a + operation, you have two choices: use the 
operator instead, which is replaced with + when either operand is a string,
or write (string:Expr) + ident.


2009/12/17 Naftoli Gugenheim naftoli...@gmail.com

 Current state attached.


 2009/12/17 Marius marius.dan...@gmail.com

 Let me know when you have something.

 Br's,
 Marius

 On Dec 17, 8:58 am, Naftoli Gugenheim naftoli...@gmail.com wrote:
  I'm thinking of an approach to writing a DSL with a much cleaner syntax.
 I'll try to put something together.
 
  -
 
  Marius Danciumarius.dan...@gmail.com wrote:
 
  All,
 
  I just want to see if there is any interest in the approach discussed
 here.
  As you know Lift has some interesting support for building JavaScript
  constructs from Scala code usig JsExp, JsCmd etc classes. I used quite a
 lot
  this support and it's great but if your JS code that you want to send
 down
  to the browser (say as an Ajax or Comet partial update response) gets a
 bit
  more complicated then constructing the JS fragment leads IMO to some
  cumbersome Scala code. I found myselft in quite a few situation to use
 JsRaw
  to write the JavaScript fragment in order for the code reader to
 understand
  what JavaScript code will be generated. But of course with JsRaw we put
  everything into a String so I'm not a big fan of this approach. So I
 started
  to define a JavaScript like DSL that IMO is closer to JavaScript form.
  Attached is a source code smaple of how this looks like, so for instance
 we
  can have something like:
 
  val js = JsFunc('myFunc, 'param1, 'param2) {
  JsIf('param1 __ 30) {
  Var('home) := Wrap(234 __- 3) __/ 2 `;`
  Var('someArray) := JsArray(1, 2, 3, 4, 5) `;`
  'myFunc(1, 2, do it, 'home) `;`
  $(#myID)  'attr(value, 123) `;`
} ~
JsForEach(Var('i) in 'someArray) {
  'console  'log(Hi there  __+ 'i) `;`
} ~
JsAnonFunc('arg1, 'arg2) {
 'alert(Anonymous function  __+ 'arg1 __+ 'arg2)
}(1, 2) `;`
  }
 
  println(js.toJs)
 
  this yields the following JavaScript code:
 
  function myFunc( param1, param2 ) {
  if (param1  30) {
  var home = ( 234 - 3 ) / 2;
  var someArray = [ 1, 2, 3, 4, 5 ];
  myFunc(1, 2, do it, home);
  $(#myID).attr(value, 123);}
 
  for (var i in someArray) {
  console.log(Hi there  + i);}
 
  function ( arg1, arg2 ) {
  alert(Anonymous function  + arg1 + arg2)
 
  }(1, 2);
  }
 
  ... ok I just droped nonsense code in there for exemplification. A few
  words:
 
  1. JsIf, JsForEach describe JavaScript if and for(each) statements
  2. Functions like __, __, ... __+, __- are function that alows
 definition
  of boolean and/or algebraic expressions.
  3. Wrap just wraps an expression into ()
  4. Var defined a variable
  5 := defines an assignment
  6. JsFunc declares a JS function
  7. JsAnonFunc declares an anonymous function
  8. 'myFunc(1, 2, do it, 'home)  is simply a javascript function
 invocation
  by providing 

Re: [Lift] Re: Scala to JavaScript DSL ...

2009-12-17 Thread Ross Mellgren
I like the source for the DSL very much, I think it's very well written. Thanks 
for sharing it.

-Ross

On Dec 17, 2009, at 9:34 PM, Naftoli Gugenheim wrote:

 Okay!
 The following code:
 val jsFunc: JSFunc = Function(myFunc)(param1, param2) {case param1 
 :: param2 :: Nil =
 Var(someArray) := Array(1, 2, 3, 4, 5)
 If(param1  30) {
   val x = Var(x)   // now we can use either x or 'x
   x := (234 - 3) / 2 // calculation happens in scala
   Var(y) := (2:Expr) * x * 2   // calculation happens in javascript
   'jsFunc(1, 2, do it, 'y)
   val $ = JSIdent($)
   $(#myID)  'attr(value, 123)
 } Else {
   'console  'log(=30)
 }
 ForEach(Var(i) In 'someArray) {
   'console  'log(Hi there   'i)
 }
 Function()(arg1, arg2) { case arg1 :: arg2 :: Nil =
   'alert(Anonymous function (  arg1  ,   arg2  ))
 }(1,2)
 }
 println(jsFunc.toCode)
 
 Produces:
 
 function myFunc(param1, param2) {
 var someArray
 someArray = [1.0, 2.0, 3.0, 4.0, 5.0]
 if((param1  30.0)) {
 var x
 x = 115.0
 var y
 y = ((2.0 * x) * 2.0)
 jsFunc(1.0, 2.0, do it, y)
 ($(#myID)).attr(value, 123)
 } else {
 (console).log(=30)
 }
 var i
 for(i in someArray) {
 (console).log((Hi there  + i))
 }
 function (arg1, arg2) {
 alert(Anonymous function ( + arg1) + , )  arg2) + )))
 }(1.0, 2.0)
 }
 
 It may be desirable that instead of defining your own names for Vars and 
 function parameters, names are auto-generated, since you can anyway use 
 typesafe scala identifiers. This would save boilerplate and produce more 
 obfuscated code, and other than the name generating algorithm is a trivial 
 change to make.
 Note that since I am not familiar with Lift's JavaScript APIs I just wrote my 
 own AST, which consists of case classes that contain their data parameters 
 and a toCode method. Feel free to delete them and plug Lift's classes 
 instead--there is no dependency on anything unique about them.
 Also note that to prevent string + ident from compiling as a string to be 
 outputted and instead output a + operation, you have two choices: use the  
 operator instead, which is replaced with + when either operand is a string, 
 or write (string:Expr) + ident.
 
 
 2009/12/17 Naftoli Gugenheim naftoli...@gmail.com
 Current state attached.
 
 
 2009/12/17 Marius marius.dan...@gmail.com
 
 Let me know when you have something.
 
 Br's,
 Marius
 
 On Dec 17, 8:58 am, Naftoli Gugenheim naftoli...@gmail.com wrote:
  I'm thinking of an approach to writing a DSL with a much cleaner syntax. 
  I'll try to put something together.
 
  -
 
  Marius Danciumarius.dan...@gmail.com wrote:
 
  All,
 
  I just want to see if there is any interest in the approach discussed here.
  As you know Lift has some interesting support for building JavaScript
  constructs from Scala code usig JsExp, JsCmd etc classes. I used quite a lot
  this support and it's great but if your JS code that you want to send down
  to the browser (say as an Ajax or Comet partial update response) gets a bit
  more complicated then constructing the JS fragment leads IMO to some
  cumbersome Scala code. I found myselft in quite a few situation to use JsRaw
  to write the JavaScript fragment in order for the code reader to understand
  what JavaScript code will be generated. But of course with JsRaw we put
  everything into a String so I'm not a big fan of this approach. So I started
  to define a JavaScript like DSL that IMO is closer to JavaScript form.
  Attached is a source code smaple of how this looks like, so for instance we
  can have something like:
 
  val js = JsFunc('myFunc, 'param1, 'param2) {
  JsIf('param1 __ 30) {
  Var('home) := Wrap(234 __- 3) __/ 2 `;`
  Var('someArray) := JsArray(1, 2, 3, 4, 5) `;`
  'myFunc(1, 2, do it, 'home) `;`
  $(#myID)  'attr(value, 123) `;`
} ~
JsForEach(Var('i) in 'someArray) {
  'console  'log(Hi there  __+ 'i) `;`
} ~
JsAnonFunc('arg1, 'arg2) {
 'alert(Anonymous function  __+ 'arg1 __+ 'arg2)
}(1, 2) `;`
  }
 
  println(js.toJs)
 
  this yields the following JavaScript code:
 
  function myFunc( param1, param2 ) {
  if (param1  30) {
  var home = ( 234 - 3 ) / 2;
  var someArray = [ 1, 2, 3, 4, 5 ];
  myFunc(1, 2, do it, home);
  $(#myID).attr(value, 123);}
 
  for (var i in someArray) {
  console.log(Hi there  + i);}
 
  function ( arg1, arg2 ) {
  alert(Anonymous function  + arg1 + arg2)
 
  }(1, 2);
  }
 
  ... ok I just droped nonsense code in there for exemplification. A few
  words:
 
  1. JsIf, JsForEach describe JavaScript if and for(each) statements
  2. Functions like __, __, ... __+, __- are function that alows definition
  of boolean and/or algebraic expressions.
  3. Wrap just wraps an expression into ()
  4. Var defined a variable
  5 := defines an 

Re: [Lift] Re: Scala to JavaScript DSL ...

2009-12-17 Thread Naftoli Gugenheim
You're welcome. There's still some work to do; I would call it a proof of
concept. But I'll let Marius finish it up. :)


On Thu, Dec 17, 2009 at 10:18 PM, Ross Mellgren dri...@gmail.com wrote:

 I like the source for the DSL very much, I think it's very well written.
 Thanks for sharing it.

 -Ross

 On Dec 17, 2009, at 9:34 PM, Naftoli Gugenheim wrote:

 Okay!
 The following code:

 val jsFunc: JSFunc = Function(myFunc)(param1, param2) {case
 param1 :: param2 :: Nil =

 Var(someArray) := Array(1, 2, 3, 4, 5)

 If(param1  30) {

   val x = Var(x)   // now we can use either x or 'x

   x := (234 - 3) / 2 // calculation happens in scala

   Var(y) := (2:Expr) * x * 2   // calculation happens in
 javascript

   'jsFunc(1, 2, do it, 'y)

   val $ = JSIdent($)

   $(#myID)  'attr(value, 123)

 } Else {

   'console  'log(=30)

 }

 ForEach(Var(i) In 'someArray) {

   'console  'log(Hi there   'i)

 }

 Function()(arg1, arg2) { case arg1 :: arg2 :: Nil =

   'alert(Anonymous function (  arg1  ,   arg2  ))

 }(1,2)

 }

 println(jsFunc.toCode)


 Produces:

 function myFunc(param1, param2) {

 var someArray

 someArray = [1.0, 2.0, 3.0, 4.0, 5.0]

 if((param1  30.0)) {

 var x

 x = 115.0

 var y

 y = ((2.0 * x) * 2.0)

 jsFunc(1.0, 2.0, do it, y)

 ($(#myID)).attr(value, 123)

 } else {

 (console).log(=30)

 }

 var i

 for(i in someArray) {

 (console).log((Hi there  + i))

 }

 function (arg1, arg2) {

 alert(Anonymous function ( + arg1) + , )  arg2) + )))

 }(1.0, 2.0)

 }


 It may be desirable that instead of defining your own names for Vars and
 function parameters, names are auto-generated, since you can anyway use
 typesafe scala identifiers. This would save boilerplate and produce more
 obfuscated code, and other than the name generating algorithm is a trivial
 change to make.
 Note that since I am not familiar with Lift's JavaScript APIs I just wrote
 my own AST, which consists of case classes that contain their data
 parameters and a toCode method. Feel free to delete them and plug Lift's
 classes instead--there is no dependency on anything unique about them.
 Also note that to prevent string + ident from compiling as a string to be
 outputted and instead output a + operation, you have two choices: use the 
 operator instead, which is replaced with + when either operand is a string,
 or write (string:Expr) + ident.


 2009/12/17 Naftoli Gugenheim naftoli...@gmail.com

 Current state attached.


 2009/12/17 Marius marius.dan...@gmail.com

 Let me know when you have something.

 Br's,
 Marius

 On Dec 17, 8:58 am, Naftoli Gugenheim naftoli...@gmail.com wrote:
  I'm thinking of an approach to writing a DSL with a much cleaner
 syntax. I'll try to put something together.
 
  -
 
  Marius Danciumarius.dan...@gmail.com wrote:
 
  All,
 
  I just want to see if there is any interest in the approach discussed
 here.
  As you know Lift has some interesting support for building JavaScript
  constructs from Scala code usig JsExp, JsCmd etc classes. I used quite
 a lot
  this support and it's great but if your JS code that you want to send
 down
  to the browser (say as an Ajax or Comet partial update response) gets a
 bit
  more complicated then constructing the JS fragment leads IMO to some
  cumbersome Scala code. I found myselft in quite a few situation to use
 JsRaw
  to write the JavaScript fragment in order for the code reader to
 understand
  what JavaScript code will be generated. But of course with JsRaw we put
  everything into a String so I'm not a big fan of this approach. So I
 started
  to define a JavaScript like DSL that IMO is closer to JavaScript
 form.
  Attached is a source code smaple of how this looks like, so for
 instance we
  can have something like:
 
  val js = JsFunc('myFunc, 'param1, 'param2) {
  JsIf('param1 __ 30) {
  Var('home) := Wrap(234 __- 3) __/ 2 `;`
  Var('someArray) := JsArray(1, 2, 3, 4, 5) `;`
  'myFunc(1, 2, do it, 'home) `;`
  $(#myID)  'attr(value, 123) `;`
} ~
JsForEach(Var('i) in 'someArray) {
  'console  'log(Hi there  __+ 'i) `;`
} ~
JsAnonFunc('arg1, 'arg2) {
 'alert(Anonymous function  __+ 'arg1 __+ 'arg2)
}(1, 2) `;`
  }
 
  println(js.toJs)
 
  this yields the following JavaScript code:
 
  function myFunc( param1, param2 ) {
  if (param1  30) {
  var home = ( 234 - 3 ) / 2;
  var someArray = [ 1, 2, 3, 4, 5 ];
  myFunc(1, 2, do it, home);
  $(#myID).attr(value, 123);}
 
  for (var i in someArray) {
  console.log(Hi there  + i);}
 
  function ( arg1, arg2 ) {
  alert(Anonymous function  + arg1 + arg2)
 
  }(1, 2);
  }
 
  ... ok I just droped nonsense code in there for exemplification. A few
  words:
 
  1. JsIf, JsForEach describe JavaScript if and 

Re: [Lift] Re: Scala to JavaScript DSL ...

2009-12-13 Thread Naftoli Gugenheim
Other advantages of a DSL include type safety and typo safety. :)

-
Mariusmarius.dan...@gmail.com wrote:

That is certainly one way to go but personally I'm not at all a fan of
this string literals approach,. For instance if Scala would not have
had built in XML support using XML as string literals Lift would
probably loose some of its attractions... but that's my opinion.
Furthermore a DSL like language allows better compositionality than
concatenating strings when we want to iteratively add JS code ... for
instance calling the same function multiple times with different
arguments, or collecting code fragments generated by different
application components etc.

Also it seems to me that your approach (somehow similar with
Velocity's) is more expensive but I admit that this is not at all a
strong argument because we're talking about small javascript fragments
so the delta is negligible.

Br's,
Marius

On Dec 12, 8:42 pm, Alex Boisvert alex.boisv...@gmail.com wrote:
 Personally, I would rather go with a JavaScript literal and a simple
 templating mechanism for substitution/binding of Javascript literals + Json
 objects that would drive dynamic code (if conditionals, for-loops, ...).

 Taking your example,

 def myFunc = {
   function myFunc( param1, param2 ) {
     if (param1  ${limit}) {
       var home = ( ${max} - 3 ) / 2;
       var someArray = ${array};
       myFunc(1, 2, do it, home);
       $(#myID).attr(value, 123);
     }
     for (var i in ${someArray}) {
       console.log(Hi there  + i);
     }
     function ( arg1, arg2 ) {
       alert(Anonymous function  + arg1 + arg2)
     }(1, 2);
   }.jsBind(
     max - max,
     array - array,
     someArray - someArray,
     ...
   )

 Not a fully fleshed out example but you get the idea.  You'd still be able
 to bind existing JsExp/JsCmds  so some parts could still be abstracted and
 typed checked.

 I would find this more readable and simpler that learning a quirky DSL
 syntax.  And I could still copy/paste Javascript code to/from the browser
 and test it easily.

 alex

 On Sat, Dec 12, 2009 at 2:07 AM, Marius Danciu marius.dan...@gmail.comwrote:

  All,

  I just want to see if there is any interest in the approach discussed here.
  As you know Lift has some interesting support for building JavaScript
  constructs from Scala code usig JsExp, JsCmd etc classes. I used quite a lot
  this support and it's great but if your JS code that you want to send down
  to the browser (say as an Ajax or Comet partial update response) gets a bit
  more complicated then constructing the JS fragment leads IMO to some
  cumbersome Scala code. I found myselft in quite a few situation to use JsRaw
  to write the JavaScript fragment in order for the code reader to understand
  what JavaScript code will be generated. But of course with JsRaw we put
  everything into a String so I'm not a big fan of this approach. So I started
  to define a JavaScript like DSL that IMO is closer to JavaScript form.
  Attached is a source code smaple of how this looks like, so for instance we
  can have something like:

  val js = JsFunc('myFunc, 'param1, 'param2) {
      JsIf('param1 __ 30) {
          Var('home) := Wrap(234 __- 3) __/ 2 `;`
          Var('someArray) := JsArray(1, 2, 3, 4, 5) `;`
          'myFunc(1, 2, do it, 'home) `;`
          $(#myID)  'attr(value, 123) `;`
        } ~
        JsForEach(Var('i) in 'someArray) {
          'console  'log(Hi there  __+ 'i) `;`
        } ~
        JsAnonFunc('arg1, 'arg2) {
         'alert(Anonymous function  __+ 'arg1 __+ 'arg2)
        }(1, 2) `;`
      }

      println(js.toJs)

  this yields the following JavaScript code:

  function myFunc( param1, param2 ) {
  if (param1  30) {
  var home = ( 234 - 3 ) / 2;
  var someArray = [ 1, 2, 3, 4, 5 ];
  myFunc(1, 2, do it, home);
  $(#myID).attr(value, 123);
  }
  for (var i in someArray) {
  console.log(Hi there  + i);
  }
  function ( arg1, arg2 ) {
  alert(Anonymous function  + arg1 + arg2)
  }(1, 2);
  }

  ... ok I just droped nonsense code in there for exemplification. A few
  words:

  1. JsIf, JsForEach describe JavaScript if and for(each) statements
  2. Functions like __, __, ... __+, __- are function that alows definition
  of boolean and/or algebraic expressions.
  3. Wrap just wraps an expression into ()
  4. Var defined a variable
  5 := defines an assignment
  6. JsFunc declares a JS function
  7. JsAnonFunc declares an anonymous function
  8. 'myFunc(1, 2, do it, 'home)  is simply a javascript function
  invocation by providing 4 parameter.
  9. ~ is just a function that chains statements that don;t necessarily end
  in ;

  Do you think that something like this would be usable in Lift?

  Br's,
  Marius

  --
  You received this message because you are subscribed to the Google Groups
  Lift group.
  To post to this group, send email to lift...@googlegroups.com.
  To unsubscribe from this group, send email to
  

Re: [Lift] Re: Scala to JavaScript DSL ...

2009-12-13 Thread Alex Boisvert
On Sat, Dec 12, 2009 at 11:06 AM, Marius marius.dan...@gmail.com wrote:

 That is certainly one way to go but personally I'm not at all a fan of
 this string literals approach,. For instance if Scala would not have
 had built in XML support using XML as string literals Lift would
 probably loose some of its attractions... but that's my opinion.


Agreed, XML is baked-in.  It's not a DSL built on top of other features.


 Furthermore a DSL like language allows better compositionality than
 concatenating strings when we want to iteratively add JS code ... for
 instance calling the same function multiple times with different
 arguments, or collecting code fragments generated by different
 application components etc.


There's no guarantee of compositionality for DSLs.   You have to design it
to be, and it's quite difficult to get right.   And then you pretty much
reinvent another language.  First you have Scala, then you have Javascript,
then you have something in between which is FrankenScalaScript.Just my
opinion :)



 Also it seems to me that your approach (somehow similar with
 Velocity's) is more expensive but I admit that this is not at all a
 strong argument because we're talking about small javascript fragments
 so the delta is negligible.


I would beg to differ but we're so far from any implementation of either to
judge performance at this stage.

alex

--

You received this message because you are subscribed to the Google Groups 
Lift group.
To post to this group, send email to lift...@googlegroups.com.
To unsubscribe from this group, send email to 
liftweb+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/liftweb?hl=en.




Re: [Lift] Re: Scala to JavaScript DSL ...

2009-12-12 Thread Indrajit Raychaudhuri

On 12/12/09 4:39 PM, Marius wrote:
 My notes inline.

 On Dec 12, 12:34 pm, Timothy Perretttimo...@getintheloop.eu  wrote:
 Hey Marius,

 Within this DSL will you be using JsObj under the hood or lift-json?

 I was thinking to use lift-json in this case ... but I'd also of
 prefer having a lift-js project.


 I would be very reluctant about adding new things to lift that don't
 unify our Js and JSON libs.

 Depends what you mean by unify. lift-json is not the same with js
 support, js should utilize lift-json to build json constructs being
 part of the javascript generated but lift-json has nothing to to with
 a potential lift-js project. Therefore I would keep lift-json and lift-
 js separated and have lift-js utilize lift-json whenever possible.

I would be hugely in favor of lift-js. I see lift-json deal with the 
data container related functionality. This would be clearly demarcated 
from lift-js (the scripting, method calls etc.) that is primarily used 
for deeper framework level integration for building (mostly web) 
applications.

In that sense, lift-webkit could also shed some weight in favor of 
lift-js (parts of net.liftweb.http.js, for example). On one hand we 
would have a neatly composed package with focused purpose and on the 
other hand lift-webkit would feel 'lighter' to projects that don't need 
any of the js functionality at all.

The dependency tree could look like (lower components depend on one or 
more above them):

lift-common
lift-actor [1]
lift-json [1]
lift-util [2]
lift-js [2]
lift-webkit [3]

[1] Independent of each other currently.
[2] Can interchange depending on how things go.
[3] In some sense lift-webkit still ends up depending on lift-js 
transitively. But that's better than 2.7M monolith :) It can even create 
opportunity for marking lift-js as 'optional dependency' for lift-webkit.

In any case, this is a derived profit and doesn't have to be the primary 
goal.



 On this note, will this unification take place before 2.0?

 Too soon to tell. I'm not sure yet if people like this proposal so we
 first need acceptance and then talk schedules.


 Cheers, Tim

 Sent from my iPhone

 On 12 Dec 2009, at 10:07, Marius Danciumarius.dan...@gmail.com  wrote:

 All,

 I just want to see if there is any interest in the approach
 discussed here. As you know Lift has some interesting support for
 building JavaScript constructs from Scala code usig JsExp, JsCmd etc
 classes. I used quite a lot this support and it's great but if your
 JS code that you want to send down to the browser (say as an Ajax or
 Comet partial update response) gets a bit more complicated then
 constructing the JS fragment leads IMO to some cumbersome Scala
 code. I found myselft in quite a few situation to use JsRaw to write
 the JavaScript fragment in order for the code reader to understand
 what JavaScript code will be generated. But of course with JsRaw we
 put everything into a String so I'm not a big fan of this approach.
 So I started to define a JavaScript like DSL that IMO is closer to
 JavaScript form. Attached is a source code smaple of how this looks
 like, so for instance we can have something like:

 val js = JsFunc('myFunc, 'param1, 'param2) {
  JsIf('param1 __  30) {
  Var('home) := Wrap(234 __- 3) __/ 2 `;`
  Var('someArray) := JsArray(1, 2, 3, 4, 5) `;`
  'myFunc(1, 2, do it, 'home) `;`
  $(#myID)  'attr(value, 123) `;`
} ~
JsForEach(Var('i) in 'someArray) {
  'console  'log(Hi there  __+ 'i) `;`
} ~
JsAnonFunc('arg1, 'arg2) {
 'alert(Anonymous function  __+ 'arg1 __+ 'arg2)
}(1, 2) `;`
  }

  println(js.toJs)

 this yields the following JavaScript code:

 function myFunc( param1, param2 ) {
 if (param1  30) {
 var home = ( 234 - 3 ) / 2;
 var someArray = [ 1, 2, 3, 4, 5 ];
 myFunc(1, 2, do it, home);
 $(#myID).attr(value, 123);
 }
 for (var i in someArray) {
 console.log(Hi there  + i);
 }
 function ( arg1, arg2 ) {
 alert(Anonymous function  + arg1 + arg2)
 }(1, 2);
 }

 ... ok I just droped nonsense code in there for exemplification. A
 few words:

 1. JsIf, JsForEach describe JavaScript if and for(each) statements
 2. Functions like __, __, ... __+, __- are function that alows
 definition of boolean and/or algebraic expressions.
 3. Wrap just wraps an expression into ()
 4. Var defined a variable
 5 := defines an assignment
 6. JsFunc declares a JS function
 7. JsAnonFunc declares an anonymous function
 8. 'myFunc(1, 2, do it, 'home)  is simply a javascript function
 invocation by providing 4 parameter.
 9. ~ is just a function that chains statements that don;t
 necessarily end in ;

 Do you think that something like this would be usable in Lift?

 Br's,
 Marius
 --

 You received this message because you are subscribed to the Google
 Groups Lift group.
 To post to this group, send email to lift...@googlegroups.com.
 To unsubscribe from this group, send email to