Re: [Lift] Re: Scala to JavaScript DSL ...
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 ...
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 ...
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 ...
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 ...
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 ...
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 ...
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 ...
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 ...
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