kswoll / WootzJs

C# to Javascript Compiler implemented via Roslyn
MIT License
110 stars 21 forks source link

Support for Code Inlining and JS Injection #3

Closed Danielku15 closed 10 years ago

Danielku15 commented 10 years ago

Code Inlining

Currently the JsAttribute is quite minimal and only allows renaming. It would be useful if some inline-JavaScript expression could be added. When the method or property is accessed, the JS source will be generated. If you put expressions in braces {} they should be evaluated to the actual value in Compile Time

C#

[Js(Name = "Array", Export = false)]
public class StringBuilder
{
    [Js(InlineCode = "[]")]
    public StringBuilder()
    {
    }

    [Js(InlineCode = "{this}.push({s})")]
    public void Append(object s)
    {
    }

    [Js(InlineCode = "{this}.push(String.fromCharCode({i}))")]
    public void AppendChar(int i)
    {
    }

    [JsMethod(InlineCode = "{this}.push('\\r\\n')")]
    public void AppendLine()
    {
    }

    [Js(InlineCode = "{this}.join(''")]
    public override string ToString()
    {
        return "";
    }
}
var sb = new StringBuilder();
sb.Append("asdf");
sb.AppendChar(4711);
sb.ToString(); // asdf4711

JavaScript

var test = [];
test.push("asdf");
test.push(String.fromCharCode(4711));
test.join('');

Code Injection

In some cases you might inject some raw JavaScript code as a statement into your code. A Jsni.Code() could result in a raw string injection. If there are features missing in WootzJs you can at least use raw JavaScript as a fallback. Again some braces parsing for references would be handy here.

void Jsni.Code(string jsCode, bool appendSemicolon = true); TReturn Jsni.Code(string jsCode, bool appendSemicolon = true);

[Js(Name="test")]
private void Foo() { }
private void Test() {
    var x = this.Test2();
    Jsni.Code("console.warn('test', {x})");
    if(x > 10) {
        Jsni.Code("throw { value: {x}, data: {this.Foo}() }");
    }
    while(Jsni.Code<bool>("{x} === 100", false)) { }
    this.Test3();
}

will result in

var x = this.Test2();
console.warn('test', x);
if(x > 10) {
    throw { value: x, data: this.test() };
}
while(x === 100)  { }
this.Test3()
kirksqor commented 10 years ago

This is a terrific suggestion! Thanks for your feedback. I will look into implementing this this weekend.

kswoll commented 10 years ago

Daniel, thanks again for the suggestion. I've implemented this mostly as you've described:

I've mostly implemented your samples in the unit test JsCodeTests. Let me know if you have any feedback on the implementation or further questions.

Danielku15 commented 10 years ago

Wow, that was fast. Sadly the weekend is over and I probably will have until next weekend I can test the features in my project.

FYI: I am currently investigating several C# to JavaScript compilers for AlphaTab and I'll let you know if I'm able to implement all JavaScript specific classes. I tested Saltarelle Compiler and SharpKit yet WootzJs is the last one I am evaluating. Since it uses Roslyn, its currently my preferred choice.

kswoll commented 10 years ago

Daniel, that sounds like a fun project. I'm at your disposal in any way I can help vis a vis WootzJs improvements. Currently in the process of converting my fantasy basketball site (xohoops.com) over to using WootzJs, my favorite feature so far has been using async/await. Try doing that in native Javascript. :)