21 |
22 |

My To Do List

23 |
24 |
25 |
26 |

Not Started

27 |
28 |
29 |
30 |
31 |
32 |
33 |

Done

34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 | 42 |
43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /tests/FunScript.Tests/app.config: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /src/main/FunScript/Tuples.fs: -------------------------------------------------------------------------------- 1 | module internal FunScript.Tuples 2 | 3 | open AST 4 | open Microsoft.FSharp.Quotations 5 | open Microsoft.FSharp.Reflection 6 | 7 | let itemsPropName = "Items" 8 | let getItem i ref = IndexGet(PropertyGet(ref, itemsPropName), Number(float i)) 9 | 10 | let private creation = 11 | CompilerComponent.create <| fun (|Split|) compiler returnStrategy -> 12 | function 13 | | Patterns.NewTuple(exprs) -> 14 | let decls, refs = Reflection.getDeclarationAndReferences (|Split|) exprs 15 | let typeArgs = exprs |> List.map (fun x -> x.Type) 16 | let cons = Reflection.getTupleConstructorVar compiler typeArgs 17 | [ yield! decls |> Seq.concat 18 | yield returnStrategy.Return <| New(cons, refs) ] 19 | | _ -> [] 20 | 21 | let private getIndex = 22 | CompilerComponent.create <| fun (|Split|) _ returnStrategy -> 23 | function 24 | | Patterns.TupleGet(Split(valDecl, valRef), i) -> 25 | [ yield! valDecl 26 | yield returnStrategy.Return (valRef |> getItem i) 27 | ] 28 | | _ -> [] 29 | 30 | let components = [ 31 | creation 32 | getIndex 33 | CompilerComponent.unary <@ fst @> (fun arg -> arg |> getItem 0) 34 | CompilerComponent.unary <@ snd @> (fun arg -> arg |> getItem 1) 35 | CompilerComponent.unary 36 | <@ Microsoft.FSharp.Reflection.FSharpValue.GetTupleFields @> 37 | (fun arg -> PropertyGet(arg, itemsPropName)) 38 | CompilerComponent.binary 39 | <@ fun obj i -> Microsoft.FSharp.Reflection.FSharpValue.GetTupleField(obj, i) @> 40 | (fun arg i -> IndexGet(PropertyGet(arg, itemsPropName), i)) 41 | ] -------------------------------------------------------------------------------- /tests/FunScript.Tests/LetBindingTests.fs: -------------------------------------------------------------------------------- 1 | [] 2 | module FunScript.Tests.LetBindings 3 | 4 | open NUnit.Framework 5 | 6 | 7 | [] 8 | let ``Let bindings can be generated``() = 9 | check 10 | <@@ 11 | let x = true 12 | x 13 | @@> 14 | 15 | [] 16 | let ``Let bindings inline can be generated``() = 17 | check 18 | <@@ 19 | let f (x:string) = x 20 | f (let y = "foo" in y) 21 | @@> 22 | 23 | [] 24 | let ``Recursive let bindings can be generated``() = 25 | check 26 | <@@ 27 | let rec even i = 28 | if i < 10. then 29 | odd (i+1.) 30 | else i 31 | and odd i = 32 | even (i+1.) 33 | even 0. 34 | @@> 35 | 36 | 37 | [] 38 | let ``Mutable let bindings can be generated``() = 39 | check 40 | <@@ 41 | let mutable x = true 42 | x 43 | @@> 44 | 45 | [] 46 | let ``Mutations of let bindings can be generated``() = 47 | checkAreEqual 48 | false 49 | <@@ 50 | let mutable x = true 51 | x <- false 52 | x 53 | @@> 54 | 55 | 56 | [] // see: http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting 57 | let ``Inner-scope let-bindings do not destroy outer-scope let-bindings``() = 58 | check 59 | <@@ 60 | let x = 10. 61 | let y = 62 | let x = 1. 63 | x * 1. 64 | y * x 65 | @@> 66 | 67 | 68 | [] 69 | let ``key/reserved words are protected``() = 70 | check 71 | <@@ 72 | let ``for`` = true 73 | ``for`` 74 | @@> -------------------------------------------------------------------------------- /examples/EasyGettingStarted/HtmlCanvasExample.fs: -------------------------------------------------------------------------------- 1 | (* 2 | Based on Zach Bary's "Canavas" example (see GitHub examples). 3 | The TS draws 2 rectangles and we inject the compiled JS code into an HTML page. 4 | The Project.fs then creates an index file with the HTML contents and opens it using the default brower. 5 | 6 | Recommended as your first FunScript example (hello world alternative) 7 | *) 8 | 9 | [] 10 | module HtmlCanvasExample 11 | 12 | open FunScript 13 | open FSharp.Data 14 | open System.IO 15 | 16 | // Create a function that will be compiled into JavaScript... 17 | let htmlCanvasTS()= 18 | let canvas = Globals.document.getElementsByTagName_canvas().[0] 19 | canvas.width <- 1000. 20 | canvas.height <- 800. 21 | let ctx = canvas.getContext_2d() 22 | ctx.fillStyle <- "rgb(200,0,0)" 23 | ctx.fillRect (10., 10., 55., 50.); 24 | ctx.fillStyle <- "rgba(0, 0, 200, 0.5)" 25 | ctx.fillRect (30., 30., 55., 50.) 26 | 27 | let htmlCanvasCode = 28 | Compiler.Compiler.Compile( 29 | // This argument is the quotation to compile 30 | <@ htmlCanvasTS() @>, 31 | // This argument tells the compiler not to wrap 32 | // the result in a return statement 33 | noReturn=true) 34 | 35 | // Here we define the page we'll create... 36 | let htmlCanvasPage = 37 | sprintf """ 38 | 39 | 40 | 41 | 42 |

Using HTML5 Canvas (HtmlCanvasExample)

43 | 44 | 45 | 46 | 47 | 50 | 51 | """ htmlCanvasCode 52 | -------------------------------------------------------------------------------- /examples/Twitter/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | FunScript Demo 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 18 | 19 | 20 | 21 | 33 | 34 |
35 |
36 |
37 | 38 | 39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | 47 | 48 | -------------------------------------------------------------------------------- /src/docs/static/custom/tooltips.css: -------------------------------------------------------------------------------- 1 | @import url(http://fonts.googleapis.com/css?family=Droid+Sans+Mono); 2 | @import url(http://fonts.googleapis.com/css?family=Arimo); 3 | 4 | /* identifier */ 5 | span.i { color:#d1d1d1; } 6 | /* string */ 7 | span.s { color:#d4943c; } 8 | /* keywords */ 9 | span.k { color:#4e98dc; } 10 | /* comment */ 11 | span.c { color:#96C71D; } 12 | /* operators */ 13 | span.o { color:#af75c1; } 14 | /* numbers */ 15 | span.n { color:#96C71D; } 16 | /* line number */ 17 | span.l { color:#80b0b0; } 18 | 19 | 20 | /* inactive code */ 21 | span.inactive { color:#808080; } 22 | /* preprocessor */ 23 | span.prep { color:#800080; } 24 | /* fsi output */ 25 | span.fsi { font-style:italic; color:#606060; } 26 | 27 | /* omitted */ 28 | span.omitted { 29 | background:#3c4e52; 30 | border-radius:5px; 31 | color:#808080; 32 | padding:0px 0px 1px 0px; 33 | } 34 | /* tool tip */ 35 | div.tip { 36 | background:#475b5f; 37 | border-radius:4px; 38 | font:11pt Arimo, arial, sans-serif; 39 | padding:6px 8px 6px 8px; 40 | display:none; 41 | color:#d1d1d1; 42 | } 43 | 44 | code { 45 | font: 10pt 'Droid Sans Mono',consolas,monospace; 46 | border:1px solid #e8e8e8; 47 | background-color:#f8f8f8; 48 | border-radius:2px; 49 | border-radius:3px; 50 | padding:1px 3px 1px 3px; 51 | color:#c31515; 52 | } 53 | table.pre td { 54 | padding:0px; 55 | } 56 | table.pre td.lines { 57 | width:20px; 58 | } 59 | table.pre pre { 60 | padding:0px; 61 | margin:0px; 62 | border-radius:0px; 63 | } 64 | table.pre, pre.fssnip, pre { 65 | font: 10pt 'Droid Sans Mono',consolas,monospace; 66 | width:90%; 67 | margin:10px 20px 20px 20px; 68 | background-color:#212d30; 69 | padding:10px; 70 | border-radius:5px; 71 | color:#d1d1d1; 72 | } -------------------------------------------------------------------------------- /paket.lock: -------------------------------------------------------------------------------- 1 | NUGET 2 | remote: https://nuget.org/api/v2 3 | specs: 4 | ApiaryProvider (1.0.2) - framework: >= net45 5 | DotNetZip (1.9.3) 6 | Edge.js (0.9.2) - framework: >= net45 7 | FAKE (3.35.0) 8 | FParsec (1.0.1) 9 | FSharp.Compiler.CodeDom (0.9.2) 10 | FSharp.Compiler.Service (0.0.89) 11 | FSharp.Control.Reactive (2.4.0) - framework: >= net45 12 | Rx-Core (>= 2.2.5) 13 | Rx-Interfaces (>= 2.2.5) 14 | Rx-Linq (>= 2.2.5) 15 | FSharp.Data (2.0.9) - framework: >= net45 16 | FSharp.Formatting (2.9.6) 17 | FSharp.Compiler.Service (>= 0.0.87) 18 | FSharpVSPowerTools.Core (1.8.0) 19 | FSharpVSPowerTools.Core (1.8.0) 20 | FSharp.Compiler.Service (>= 0.0.87) 21 | FunScript.TypeScript.Binding.google_maps (1.1.0.37) - framework: >= net45 22 | FunScript.TypeScript.Binding.lib (>= 1.1.0.37) 23 | FunScript.TypeScript.Binding.highcharts (1.1.0.37) - framework: >= net45 24 | FunScript.TypeScript.Binding.jquery (>= 1.1.0.37) 25 | FunScript.TypeScript.Binding.lib (>= 1.1.0.37) 26 | FunScript.TypeScript.Binding.jquery (1.1.0.37) 27 | FunScript.TypeScript.Binding.lib (>= 1.1.0.37) 28 | FunScript.TypeScript.Binding.jqueryui (1.1.0.37) - framework: >= net45 29 | FunScript.TypeScript.Binding.jquery (>= 1.1.0.37) 30 | FunScript.TypeScript.Binding.lib (>= 1.1.0.37) 31 | FunScript.TypeScript.Binding.lib (1.1.0.37) 32 | NuGet.CommandLine (2.8.5) 33 | NUnit (2.6.4) 34 | NUnit.Runners (2.6.4) 35 | Rx-Core (2.2.5) 36 | Rx-Interfaces (>= 2.2.5) 37 | Rx-Interfaces (2.2.5) 38 | Rx-Linq (2.2.5) 39 | Rx-Core (>= 2.2.5) 40 | Rx-Interfaces (>= 2.2.5) 41 | GITHUB 42 | remote: Reactive-Extensions/RxJS 43 | specs: 44 | dist/rx.all.js (7c0b4214cdc429f39693af7407536cc13d791dff) -------------------------------------------------------------------------------- /src/main/FunScript/Objects.fs: -------------------------------------------------------------------------------- 1 | module (*internal*) FunScript.Objects 2 | 3 | open AST 4 | open Microsoft.FSharp.Quotations 5 | open Microsoft.FSharp.Reflection 6 | open System.Reflection 7 | open System 8 | 9 | let rec private isAvailable (compiler : InternalCompiler.ICompiler) (mb : MethodBase) = 10 | mb <> null && ( 11 | let t = mb.DeclaringType 12 | FSharpType.IsUnion(t, BindingFlags.Public ||| BindingFlags.NonPublic) || 13 | FSharpType.IsRecord(t, BindingFlags.Public ||| BindingFlags.NonPublic) || 14 | Expr.tryGetReflectedDefinition(mb).IsSome || 15 | compiler.ReplacementFor mb Quote.CallType.MethodCall |> Option.exists (isAvailable compiler)) 16 | 17 | let private propertyGetter = 18 | CompilerComponent.create <| fun (|Split|) compiler returnStrategy -> 19 | function 20 | | Patterns.PropertyGet(Some(Split(objDecl, objRef)), pi, []) 21 | when isAvailable compiler (pi.GetGetMethod(true)) 22 | -> 23 | [ yield! objDecl 24 | yield returnStrategy.Return <| PropertyGet(objRef, JavaScriptNameMapper.sanitizeAux pi.Name) 25 | ] 26 | | _ -> [] 27 | 28 | let private propertySetter = 29 | CompilerComponent.create <| fun (|Split|) compiler returnStrategy -> 30 | function 31 | | Patterns.PropertySet(Some(Split(objDecl, objRef)), pi, [], Split(valDecl, valRef)) 32 | when isAvailable compiler (pi.GetSetMethod(true)) 33 | -> 34 | [ yield! objDecl 35 | yield! valDecl 36 | yield Assign(PropertyGet(objRef, JavaScriptNameMapper.sanitizeAux pi.Name), valRef) 37 | if returnStrategy = ReturnStrategies.inplace then 38 | yield returnStrategy.Return Null 39 | ] 40 | | _ -> [] 41 | 42 | 43 | let components = [ 44 | propertyGetter 45 | propertySetter 46 | ] -------------------------------------------------------------------------------- /examples/SimpleAsync/Page.fs: -------------------------------------------------------------------------------- 1 | // --- 2 | // header: Asynchronous programming 3 | // tagline: Use the full power of F# asynchronous workflows 4 | // --- 5 | 6 | [] 7 | module Program 8 | 9 | open FunScript 10 | open FunScript.TypeScript 11 | open System.Threading 12 | 13 | // ---------------------------------------------------------------------------- 14 | // Mini implementation of some F# async primitives 15 | 16 | type Async = 17 | static member AwaitJQueryEvent(f : ('T -> obj) -> JQuery) : Async<'T> = 18 | Async.FromContinuations(fun (cont, econt, ccont) -> 19 | let named = ref None 20 | named := Some (f (fun v -> 21 | (!named).Value.off() |> ignore 22 | cont v 23 | obj() ))) 24 | 25 | // ---------------------------------------------------------------------------- 26 | // Demo using mini F# async 27 | 28 | let j (selector : string) = Globals.Dollar.Invoke(selector) 29 | let (?) jq name = jq("#" + name) 30 | 31 | let log(msg:string) = 32 | let tag = "

" + msg + "

" 33 | j?results.append [| tag :> obj |] 34 | |> ignore 35 | 36 | let increment(n) = 37 | async { 38 | do! Async.Sleep(1000) 39 | return n + 1 40 | } 41 | 42 | let rec worker(n) = 43 | async { 44 | let! v = Async.AwaitJQueryEvent(fun f -> j?next.click(fun x -> f x)) 45 | let! n = increment(n) 46 | do log ("Count: " + n.ToString()) 47 | return! worker(n) 48 | } 49 | 50 | let main() = 51 | async { 52 | let! x = Async.AwaitJQueryEvent(fun o -> j?document.ready(unbox o)) 53 | let cts = new CancellationTokenSource() 54 | Async.StartImmediate(worker 0, cts.Token) 55 | j?stop.click(fun _ -> box <| cts.Cancel()) |> ignore 56 | } |> Async.StartImmediate 57 | 58 | 59 | // ---------------------------------------------------------------------------- 60 | 61 | do Runtime.Run() -------------------------------------------------------------------------------- /tests/FunScript.Tests/ControlFlowTests.fs: -------------------------------------------------------------------------------- 1 | [] 2 | module FunScript.Tests.ControlFlow 3 | 4 | open NUnit.Framework 5 | 6 | 7 | [] 8 | let ``If then else expressions work``() = 9 | check 10 | <@@ 11 | let x = true 12 | if x then false 13 | else true 14 | @@> 15 | 16 | [] 17 | let ``If then else expressions work inline``() = 18 | check 19 | <@@ 20 | let f (x:string) = x 21 | let y = true 22 | f (if y then "foo" else "bar") 23 | @@> 24 | 25 | [] 26 | let ``While expressions work``() = 27 | checkAreEqual 28 | 10. 29 | <@@ 30 | let mutable x = 1. 31 | while x < 10. do 32 | x <- x + 1. 33 | x 34 | @@> 35 | 36 | [] 37 | let ``For i = 0 to N expressions work``() = 38 | checkAreEqual 39 | 10. 40 | <@@ 41 | let mutable x = 0. 42 | for i = 1 to 10 do 43 | x <- x + 1. 44 | x 45 | @@> 46 | 47 | [] 48 | let ``Lambdas inside for loops create closures``() = 49 | checkAreEqual 50 | 1. 51 | <@@ 52 | let mutable f = fun () -> 0. 53 | for i = 1 to 10 do 54 | if i = 1 then f <- fun () -> float i 55 | f() 56 | @@> 57 | 58 | [] 59 | let ``Matching when the matched variable name is re-used in the case works``() = 60 | check 61 | <@@ 62 | let xs = [1.; 2.; 3.] 63 | match xs with 64 | | x::xs -> x 65 | | _ -> failwith "never" 66 | @@> 67 | 68 | [] 69 | let ``Catching any exception works``() = 70 | checkAreEqual 100. 71 | <@@ 72 | let f x = 73 | try 74 | if x then raise (exn()) 75 | else 1.0 76 | with _ -> 99.0 77 | f true + f false 78 | @@> -------------------------------------------------------------------------------- /tests/FunScript.Tests/edge/double_edge.js: -------------------------------------------------------------------------------- 1 | // Fix #176 for GUI applications on Windows 2 | try { 3 | var stdout = process.stdout; 4 | } 5 | catch (e) { 6 | // This is a Windows GUI application without stdout and stderr defined. 7 | // Define process.stdout and process.stderr so that all output is discarded. 8 | (function () { 9 | var stream = require('stream'); 10 | var NullStream = function (o) { 11 | stream.Writable.call(this); 12 | this._write = function (c, e, cb) { cb && cb(); }; 13 | } 14 | require('util').inherits(NullStream, stream.Writable); 15 | var nullStream = new NullStream(); 16 | process.__defineGetter__('stdout', function () { return nullStream; }); 17 | process.__defineGetter__('stderr', function () { return nullStream; }); 18 | })(); 19 | } 20 | 21 | process.env['EDGE_NATIVE'] = process.env['EDGE_NATIVE'] || 22 | __dirname + (process.arch === 'x64' ? '\\x64\\edge.node' : '\\x86\\edge.node'); 23 | 24 | var edge = require('./edge.js'); 25 | 26 | var initialize = edge.func({ 27 | assemblyFile: __dirname + '\\..\\EdgeJs.dll', 28 | typeName: 'EdgeJs.Edge', 29 | methodName: 'InitializeInternal' 30 | }); 31 | 32 | var compileFunc = function (data, callback) { 33 | var wrapper = '(function () { ' + data + ' })'; 34 | var funcFactory = eval(wrapper); 35 | var func = funcFactory(); 36 | if (typeof func !== 'function') { 37 | throw new Error('Node.js code must return an instance of a JavaScript function. ' 38 | + 'Please use `return` statement to return a function.'); 39 | } 40 | 41 | callback(null, func); 42 | }; 43 | 44 | initialize(compileFunc, function (error, data) { 45 | if (error) throw error; 46 | }); 47 | 48 | // prevent the V8 thread from exiting for the lifetime of the CLR application 49 | setInterval(function () {}, 3600000); 50 | -------------------------------------------------------------------------------- /examples/Mandelbrot/Page.fs: -------------------------------------------------------------------------------- 1 | // --- 2 | // header: Mandelbrot 3 | // tagline: Using HTML5 canvas 4 | // --- 5 | 6 | [] 7 | module Program 8 | 9 | open FunScript 10 | open FunScript.TypeScript 11 | 12 | type Complex = { r : double; i : double } 13 | type Color = { r : int; g : int; b : int; a : int } 14 | 15 | let maxIter = 512 16 | 17 | let height = 800 18 | let width = 1000 19 | 20 | let minX = -2.1 21 | let maxX = 0.5 22 | let minY = -1.4 23 | let maxY = 1.4 24 | 25 | let iteratePoint (s : Complex) (p : Complex) : Complex = 26 | { r = s.r + p.r*p.r - p.i*p.i; i = s.i + 2.0 * p.i * p.r } 27 | 28 | let getIterationCount (p : Complex) = 29 | let mutable z = p 30 | let mutable i = 0 31 | while i < maxIter && (z.r*z.r + z.i*z.i < 4.0) do 32 | z <- iteratePoint p z 33 | i <- i + 1 34 | i 35 | 36 | let iterCountToColor (i : int) : Color = 37 | let i = maxIter - i 38 | { r = 0; g = i % 256; b = 100 * (i / 256); a = 255 } 39 | 40 | let getCoordColor (x : int, y : int) : Color = 41 | let p = { r = float x * (maxX - minX) / float width + minX 42 | ; i = float y * (maxY - minY) / float height + minY } 43 | let i = getIterationCount p 44 | iterCountToColor i 45 | 46 | let showSet() = 47 | let ctx = Globals.document.getElementsByTagName_canvas().[0].getContext_2d() 48 | 49 | let img = ctx.createImageData(float width, float height) 50 | for y = 0 to height-1 do 51 | for x = 0 to width-1 do 52 | let index = (x + y * width) * 4 53 | let color = getCoordColor (x, y) 54 | img.data.[index+0] <- float color.r 55 | img.data.[index+1] <- float color.g 56 | img.data.[index+2] <- float color.b 57 | img.data.[index+3] <- float color.a 58 | ctx.putImageData(img, 0., 0.) 59 | 60 | let main() = 61 | showSet() 62 | 63 | do Runtime.Run(directory="Web") -------------------------------------------------------------------------------- /examples/EasyGettingStarted/BodyElementsExample.fs: -------------------------------------------------------------------------------- 1 | (* 2 | Modifying the HtmlCanvasExample to represent TS which populates the whole HTML page body part. 3 | The Project.fs then creates an index file with the HTML contents and opens it using the default brower. 4 | *) 5 | 6 | [] 7 | module BodyElementsExample 8 | 9 | open FunScript 10 | open FSharp.Data 11 | open System.IO 12 | 13 | // Just the paint part from the HTMLCanvasExample example 14 | let paintCanvas (canvas: HTMLCanvasElement) = 15 | canvas.width <- 2000. 16 | canvas.height <- 1500. 17 | let ctx = canvas.getContext_2d() 18 | ctx.fillStyle <- "rgb(200,0,0)" 19 | ctx.fillRect (10., 10., 100., 50.); 20 | ctx.fillStyle <- "rgba(0, 0, 200, 0.5)" 21 | ctx.fillRect (30., 30., 55., 100.) 22 | 23 | // Create a function that will be compiled into JavaScript... 24 | // Good reference for JS and HTML: http://www.w3schools.com/jsref/dom_obj_document.asp 25 | let bodyElementsTS()= 26 | //Globals.window.alert("Hello world!") 27 | let document = Globals.document 28 | let body = document.body 29 | let h1 = document.createElement_h1() 30 | h1.innerHTML <- "Using HTML5 Canvas (BodyElementsExample)" 31 | body.appendChild(h1) |> ignore 32 | let canvas = Globals.document.createElement_canvas() 33 | body.appendChild(canvas) |> ignore 34 | paintCanvas canvas 35 | 36 | 37 | let bodyElementsCode = 38 | Compiler.Compiler.Compile( 39 | // This argument is the quotation to compile 40 | <@ bodyElementsTS() @>, 41 | // This argument tells the compiler not to wrap 42 | // the result in a return statement 43 | noReturn=true) 44 | 45 | // Here we define the page we'll create... 46 | let bodyElementsPage = 47 | sprintf """ 48 | 49 | 50 | 51 | 52 | 55 | 56 | """ bodyElementsCode 57 | -------------------------------------------------------------------------------- /examples/EasyGettingStarted/README first notes.txt: -------------------------------------------------------------------------------- 1 | Intended as a reference project for beginners who aim to get up and running and learn the basics. 2 | Moreover, intended to focus on examples leveraging FunScript for Mobile development, especially with 3 | JQueryMobile and PhoneGap (TBD). 4 | 5 | Used with MS Visual Studio 2013 (professional), 6 | with the vanilla "FunScript - Not Hosted" project template (by Zach Bary), 7 | which can be found through the online project search. Plus relevant FunScript binding packages (through NuGet). 8 | 9 | Your todo: 10 | REPLACE the "FunScript - Not Hosted" Project.fs file contents with this file. 11 | ADD relevant FunScript.TypeScript.Binding.? packages 12 | Through NuGet manager for your solution: FunScript.TypeScript.Binding.jquerymobile and FunScript.TypeScript.Binding.phonegap 13 | ADD the rest of the examples *.fs files to the visual studio project. NOTICE: file order matters for MS VS. 14 | SELECT (comment/uncomment the desired line) inside Program.fs, towards the end, which example page you want to write into the index file. 15 | 16 | Available examples (in addition to the main Program.fs module): 17 | 1. HtmlCanvasExample - simply show how to inject canvas drawing into an HTML text 18 | 2. BodyElementsExample - same example as HtmlCanvasExample , but we construct the whole body with Funscript 19 | 3. JQueryMobileExample - showing some Funscript and HTML with jquerymobile 20 | 4. Mazing - a maze game example that is written with jquerymobile. The "goat.jpg" is used for the exit indicator ingame. 21 | 5. Shakeamaze - [TBD] the maze example with Cordova/Phonegap accelerator api 22 | 23 | 24 | Leveraging some examples from the Funscript GitHub directory: 25 | https://github.com/ZachBray/FunScript/tree/master/Examples 26 | Such as the Canvas example (by Zach Bary) - offered as a good first project (hello-world alternative) here. 27 | 28 | Adding examples for JQueryMobile and PhoneGap (TBD). 29 | -------------------------------------------------------------------------------- /examples/Brainfuck/FunScript.Brainfuck.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".paket", ".paket", "{092B9015-D48D-45D3-AF77-08176B85E1A8}" 5 | ProjectSection(SolutionItems) = preProject 6 | ..\..\paket.dependencies = ..\..\paket.dependencies 7 | ..\..\..\paket.dependencies = ..\..\..\paket.dependencies 8 | EndProjectSection 9 | EndProject 10 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FunScript.Brainfuck", "FunScript.Brainfuck.Logic\FunScript.Brainfuck.Logic.fsproj", "{7DF4263D-AD55-4C6A-9998-054E210A2EF6}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FunScript.Brainfuck.Website", "FunScript.Brainfuck.Website\FunScript.Brainfuck.Website.csproj", "{FA9A7393-4CCC-41B7-B001-6DE963EBC2CC}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Any CPU = Debug|Any CPU 17 | Release|Any CPU = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {7DF4263D-AD55-4C6A-9998-054E210A2EF6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {7DF4263D-AD55-4C6A-9998-054E210A2EF6}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {7DF4263D-AD55-4C6A-9998-054E210A2EF6}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {7DF4263D-AD55-4C6A-9998-054E210A2EF6}.Release|Any CPU.Build.0 = Release|Any CPU 24 | {FA9A7393-4CCC-41B7-B001-6DE963EBC2CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {FA9A7393-4CCC-41B7-B001-6DE963EBC2CC}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {FA9A7393-4CCC-41B7-B001-6DE963EBC2CC}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {FA9A7393-4CCC-41B7-B001-6DE963EBC2CC}.Release|Any CPU.Build.0 = Release|Any CPU 28 | EndGlobalSection 29 | GlobalSection(SolutionProperties) = preSolution 30 | HideSolutionNode = FALSE 31 | EndGlobalSection 32 | EndGlobal 33 | -------------------------------------------------------------------------------- /examples/SimpleAsync/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | FunScript Demo 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 24 | 36 | 37 |
38 | 39 |

Simple Async Demo

40 | 41 | 42 | 43 | 44 | 45 |
46 | 47 |
48 | 49 | 50 |
51 | 52 | -------------------------------------------------------------------------------- /src/main/FunScript/LetBindings.fs: -------------------------------------------------------------------------------- 1 | module internal FunScript.LetBindings 2 | 3 | open AST 4 | open Microsoft.FSharp.Quotations 5 | 6 | let private binding = 7 | CompilerComponent.create <| fun (|Split|) compiler returnStrategy -> 8 | let (|Return|) = compiler.Compile 9 | function 10 | | Patterns.Let(var, Split(valDecl, valRef), Return returnStrategy block) -> 11 | [ yield! valDecl 12 | yield DeclareAndAssign(var, valRef) 13 | yield! block 14 | ] 15 | | _ -> [] 16 | 17 | let private recBinding = 18 | CompilerComponent.create <| fun (|Split|) compiler returnStrategy -> 19 | let (|Return|) = compiler.Compile 20 | function 21 | | Patterns.LetRecursive(bindingExprs, Return returnStrategy block) -> 22 | [ yield! bindingExprs |> List.map (fun (var, _) -> Declare [var]) 23 | yield! 24 | bindingExprs 25 | |> Seq.collect (fun (var, Split(valDecl, valRef)) -> 26 | seq { 27 | yield! valDecl 28 | yield Assign(Reference var, valRef) 29 | }) 30 | yield! block 31 | ] 32 | | _ -> [] 33 | 34 | let private reference = 35 | CompilerComponent.create <| fun (|Split|) compiler returnStrategy -> 36 | function 37 | | Patterns.Var(var) -> [ yield returnStrategy.Return <| Reference var ] 38 | | _ -> [] 39 | 40 | let private mutation = 41 | CompilerComponent.create <| fun (|Split|) compiler returnStrategy -> 42 | function 43 | | Patterns.VarSet(var, Split(valDecl, valRef)) -> 44 | [ yield! valDecl 45 | yield Assign(Reference var, valRef) 46 | if returnStrategy = ReturnStrategies.inplace then 47 | yield returnStrategy.Return Null 48 | ] 49 | | _ -> [] 50 | 51 | let components = [ 52 | binding 53 | recBinding 54 | reference 55 | mutation 56 | ] -------------------------------------------------------------------------------- /examples/Brainfuck/FunScript.Brainfuck.Website/sass/screen.sass: -------------------------------------------------------------------------------- 1 | // --------------------------------------------------------------------------- 2 | // Imports 3 | 4 | @import base 5 | @import sassy-buttons 6 | 7 | /* ------------------------------------------------------------------------- 8 | /* Layout 9 | 10 | html 11 | font-family: "CenturyOldStyleFS","Adobe Caslon Pro",Caslon,Baskerville,Palatino,"Palatino Linotype","Hoefler Text",Garamond,"URW Palladio L","Book Antiqua",Georgia,serif 12 | 13 | // Treat border/padding as inside the form controls so they line up with the grid properly 14 | textarea, input:not([type="radio"]) 15 | +box-sizing(border-box) 16 | width: 100% 17 | 18 | body 19 | background-color: #F8F9ED 20 | margin: 0px 0px 0px 0px 21 | 22 | .container 23 | +container 24 | +susy-grid-background 25 | 26 | h1 27 | +span-columns(12 omega) 28 | text-align: center 29 | 30 | #code 31 | +span-columns(12 omega) 32 | height: 5 * $base-line-height 33 | 34 | #console 35 | padding-top: 1em 36 | +span-columns(12 omega) 37 | height: 10 * $base-line-height 38 | 39 | #waiting-for-input 40 | text-align: center 41 | color: green 42 | font-weight: bold 43 | display: none 44 | 45 | #console-text 46 | height: 5 * $base-line-height 47 | 48 | #inputs 49 | +span-columns(8) 50 | height: 3em 51 | padding-top: 1em 52 | 53 | input 54 | +span-columns(1) 55 | height: 3em 56 | display: block 57 | font-weight: bold 58 | +sassy-button("matte", 5px, 1em, #4ba3cc) 59 | 60 | #execute-code-container 61 | +span-columns(2 omega) 62 | padding-top: 1em 63 | 64 | #execute-code 65 | +sassy-button("matte", 10px, 19px, #4ba3cc) 66 | width: 100% 67 | 68 | #footer 69 | +span-columns(12 omega) 70 | padding-top: 3em 71 | text-align: center -------------------------------------------------------------------------------- /examples/Tutorial/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | FunJS Demo 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 24 | 36 | 37 |
38 | 39 |

Hello world

40 | 41 | 42 |
43 |

Click the following button to say hello to the world.

44 | Say hello! 45 |
46 | 47 | 48 |
49 | 50 | -------------------------------------------------------------------------------- /examples/jQueryUI/Program.fs: -------------------------------------------------------------------------------- 1 | [] // Placing this attribute on the module allows all functions to be translated to JS. It's just an alias for the ReflectedDefinition F# attribute. 2 | module Program 3 | 4 | open FunScript 5 | open FunScript.TypeScript 6 | 7 | // loop through the provided array of tasks and create a div for each 8 | let addTasksToElement (elementSelector:string) tasks = 9 | let tasks = tasks 10 | |> Array.mapi (fun index task -> "
" + task + "
" |> box) 11 | Globals.Dollar.Invoke(elementSelector).append(tasks) |> ignore 12 | 13 | // Create the initial array of To Do tasks and tasks that are already complete. 14 | let populateTasks () = 15 | let tasksToDo = 16 | [| "Persist the tasks to a data store." 17 | "Add new tasks." 18 | "Remove a task." |] 19 | let tasksDone = 20 | [| "Allow tasks to be moved to done." 21 | "Add dynamic population of tasks." |] 22 | addTasksToElement ".tasksNotStarted" tasksToDo 23 | addTasksToElement ".tasksDone" tasksDone 24 | 25 | let initDragAndDrop () = 26 | // Setup the draggable elements with the desired draggable settings 27 | let draggable = createEmpty() 28 | draggable.revert <- "invalid" 29 | draggable.cursor <- "move" 30 | draggable.helper <- "clone" 31 | Globals.Dollar.Invoke(".draggable").draggable(draggable) |> ignore 32 | 33 | // Setup the drop zone elements 34 | let dropSettings = createEmpty() 35 | dropSettings.hoverClass <- "ui-state-active" 36 | dropSettings.accept <- ".draggable" 37 | dropSettings.drop <- fun e ui -> ui.draggable.appendTo(e.target :?> Element) |> ignore 38 | // The Drop related settings are now tied to the element(s) that have a class named "droppable". 39 | Globals.Dollar.Invoke(".droppable").droppable(dropSettings) |> ignore 40 | 41 | let main() = 42 | populateTasks() 43 | initDragAndDrop() 44 | 45 | do FunScript.Runtime.Run() 46 | 47 | -------------------------------------------------------------------------------- /src/docs/get.md: -------------------------------------------------------------------------------- 1 | --- 2 | header: Download 3 | tagline: Get FunScript today 4 | --- 5 | 6 |
7 |
8 | 9 | ## From inside Visual Studio 2012/2013 10 | 11 | FunScript is available via a project template in Visual Studio. 12 | 13 | 1. Open the "New Project" dialog. 14 | 2. Open the "Online" tab. 15 | 3. Search for "FunScript". 16 | 4. Select the [FunScript - Not Hosted](http://visualstudiogallery.msdn.microsoft.com/4688fe33-a41a-4c62-8322-4a7dccffa97c) template. 17 | 5. Name your project and click "OK". 18 | 19 |
20 | 21 |
22 | 23 | ## Using NuGet 24 | 25 | FunScript is available [on NuGet](http://www.nuget.org/packages/FunScript). To reference 26 | FunScript library in Visual Studio project, just run the following command in the 27 | [Package Manager Console](http://docs.nuget.org/docs/start-here/using-the-package-manager-console): 28 | 29 |
30 | PM> Install-Package FunScript
31 | 
32 | 33 |
34 |
35 | 36 |
37 |
38 | 39 | ## Direct download 40 | 41 | Alternatively, you can download the FunScript libraries in a single ZIP file. 42 | Before extracting the file, make sure to [Unblock it](http://blogs.msdn.com/b/brada/archive/2009/12/11/visual-studio-project-sample-loading-error-assembly-could-not-be-loaded-and-will-be-ignored-could-not-load-file-or-assembly-or-one-of-its-dependencies-operation-is-not-supported-exception-from-hresult-0x80131515.aspx) 43 | to avoid loading errors. 44 | 45 |
46 | Download ZIP file 47 |
48 | 49 |
50 | 51 |
52 | 53 | ## Build from source 54 | 55 | If you want to get the latest version or if you're considering contributing to FunScript, then 56 | you can get the [source code from GitHub](https://github.com/ZachBray/FunScript). For more information, 57 | see also [our contributor guide](contribute.html)! 58 | 59 |
60 |
61 | -------------------------------------------------------------------------------- /examples/Twitter/Program.fs: -------------------------------------------------------------------------------- 1 | [] 2 | module Program 3 | 4 | open FunScript 5 | open FunScript.TypeScript 6 | 7 | type Tweet = 8 | { from_user: string 9 | text: string } 10 | 11 | type TwitterSearch = 12 | { results: Tweet[] } 13 | 14 | type Program() = 15 | 16 | // Allows writing jq?name for element access 17 | let jq(selector : string) = Globals.Dollar.Invoke selector 18 | let (?) jq name = jq("#" + name) 19 | 20 | let map = 21 | let mapElement = jq?map 22 | google.maps.Map.Create(mapElement.[0]) 23 | 24 | let mutable markers = List.empty 25 | 26 | let showTweets (search:TwitterSearch) = 27 | let tweetList = 28 | search.results |> Array.map (fun tweet -> 29 | "

" + tweet.from_user + " " + tweet.text + "

") 30 | |> Array.map box 31 | jq?tweets.children().remove() |> ignore 32 | jq?tweets.append tweetList |> ignore 33 | 34 | let clearMap() = 35 | markers |> List.iter (fun (marker:google.maps.Marker) -> 36 | marker.setMap(unbox null)) 37 | markers <- List.empty 38 | 39 | let query searchText (callback:'a -> unit) = 40 | let settings = createEmpty() 41 | settings.``success <-``(fun data _ _ -> callback(unbox data); null) 42 | settings.dataType <- "jsonp" 43 | Globals.jQuery.ajax("http://search.twitter.com/search.json?q=" + searchText, settings) 44 | 45 | let updateTweets map = 46 | clearMap() 47 | query (unbox <| jq?searchText._val()) showTweets 48 | 49 | member __.Setup() = 50 | //Doesn't work under localhost... might work when hosted? 51 | map.setCenter(google.maps.LatLng.Create(51.5171,0.1026)) 52 | 53 | let initialQuery = "%23fsharp" 54 | let t = jq?searchText._val initialQuery |> ignore 55 | let searchButton = jq?searchButton 56 | let result = searchButton.click (fun _ -> updateTweets map |> ignore; null) 57 | ignore result 58 | updateTweets map 59 | 60 | let main() = 61 | Globals.onload <- fun _ -> Program().Setup() :> obj 62 | 63 | do Runtime.Run() 64 | -------------------------------------------------------------------------------- /src/main/FunScript/PrimitiveTypes.fs: -------------------------------------------------------------------------------- 1 | module internal FunScript.PrimitiveTypes 2 | 3 | open AST 4 | open Microsoft.FSharp.Quotations 5 | 6 | let private primitiveValues = 7 | CompilerComponent.create <| fun _ _ returnStrategy -> 8 | function 9 | | DerivedPatterns.Unit x -> [ Empty ] 10 | | DerivedPatterns.Bool x -> [ yield returnStrategy.Return <| Boolean x ] 11 | | DerivedPatterns.Char x -> [ yield returnStrategy.Return <| String (string x) ] 12 | | DerivedPatterns.String x -> [ yield returnStrategy.Return <| String x ] 13 | | DerivedPatterns.SByte x -> [ yield returnStrategy.Return <| Integer(int x) ] 14 | | DerivedPatterns.Byte x -> [ yield returnStrategy.Return <| Integer(int x) ] 15 | | DerivedPatterns.Int16 x -> [ yield returnStrategy.Return <| Integer(int x) ] 16 | | DerivedPatterns.Int32 x -> [ yield returnStrategy.Return <| Integer(x) ] 17 | | DerivedPatterns.Int64 x -> [ yield returnStrategy.Return <| Number(float x) ] 18 | | DerivedPatterns.UInt16 x -> [ yield returnStrategy.Return <| Number(float x) ] 19 | | DerivedPatterns.UInt32 x -> [ yield returnStrategy.Return <| Number(float x) ] 20 | | DerivedPatterns.UInt64 x -> [ yield returnStrategy.Return <| Number(float x) ] 21 | | DerivedPatterns.Single x -> [ yield returnStrategy.Return <| Number(float x) ] 22 | | DerivedPatterns.Double x -> [ yield returnStrategy.Return <| Number(x) ] 23 | // TODO: our own decimal type? 24 | | Patterns.Value(null, _) -> [ yield returnStrategy.Return <| Null ] 25 | | Patterns.Value(x, t) -> 26 | if t.IsEnum then 27 | // TODO: Remove this hack. Replace with Attribute. 28 | if t.Assembly.GetName().Name.StartsWith("FunScript.TypeScript.Binding.") then 29 | // TODO: Add attribute for this too. It could be sanitized by this point! 30 | let name = System.Enum.GetName(t, x) 31 | [ yield returnStrategy.Return <| JSExpr.EmitExpr(fun (_, _) -> t.FullName + "." + name) ] 32 | else [ yield returnStrategy.Return <| Integer(unbox x) ] 33 | else [] 34 | | _ -> [] 35 | 36 | let components = [ 37 | primitiveValues 38 | ] -------------------------------------------------------------------------------- /examples/Program.fs: -------------------------------------------------------------------------------- 1 | [] 2 | module Program 3 | 4 | open FunScript 5 | open FSharp.Data 6 | open System.IO 7 | 8 | // Create a function that will be compiled into JavaScript... 9 | let main () = 10 | let canvas = Globals.document.getElementsByTagName_canvas().[0] 11 | canvas.width <- 1000. 12 | canvas.height <- 800. 13 | let ctx = canvas.getContext_2d() 14 | ctx.fillStyle <- "rgb(200,0,0)" 15 | ctx.fillRect (10., 10., 55., 50.); 16 | ctx.fillStyle <- "rgba(0, 0, 200, 0.5)" 17 | ctx.fillRect (30., 30., 55., 50.) 18 | 19 | // Compile the main() function into javascript code... 20 | let code = 21 | Compiler.Compiler.Compile( 22 | // This argument is the quotation to compile 23 | <@ main() @>, 24 | // This argument tells the compiler not to wrap 25 | // the result in a return statement 26 | noReturn=true//, 27 | // This tells the compiler about the additional components 28 | // that are needed to compile the code. In this case, 29 | // these are the components that provide mappings for the 30 | // FSharp.Data type providers (incl. the WorldBank provider). 31 | //components = FunScript.Data.Components.DataProviders 32 | ) 33 | 34 | // Here we define the page we'll create... 35 | // Note: You have to manually include references to the JavaScript dependencies. 36 | let page = sprintf """ 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 |

Using HTML5 Canvas

45 | 46 | 47 | 48 | 49 | 52 | 53 | """ code 54 | 55 | // We write the page to a file... 56 | let filePath = Path.Combine(System.Environment.CurrentDirectory, "index.html") 57 | File.WriteAllText(filePath, page) 58 | // We open the file in the default web browser... 59 | System.Diagnostics.Process.Start(filePath) |> ignore 60 | -------------------------------------------------------------------------------- /examples/Brainfuck/FunScript.Brainfuck.Website/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Try Brainfuck 5 | 6 | 7 | 8 |
9 |

Try Brainfuck!

10 | 11 |
12 |

Brainfuck is an esoteric programming language noted for its extreme minimalism. It is a Turing tarpit, designed to challenge and amuse programmers, and was not made to be suitable for practical use. It was created in 1993 by Urban Müller.

13 | 14 |
15 | 16 |
17 |

Brainfuck Input

18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 |
30 | 31 |
32 |
33 | 34 |
35 |

Console

36 | 37 |

Waiting for keyboard input...

38 |
39 | 40 | 43 | 44 | 45 | 46 |
47 | 48 | 49 | -------------------------------------------------------------------------------- /src/main/FunScript/LambdaApplication.fs: -------------------------------------------------------------------------------- 1 | module internal FunScript.LambdaApplication 2 | 3 | open AST 4 | open Microsoft.FSharp.Quotations 5 | 6 | let private application = 7 | CompilerComponent.create <| fun (|Split|) compiler returnStrategy -> 8 | function 9 | 10 | // TODO: Implement these two optimizations directly in the pipe operator? 11 | | Patterns.Application(Patterns.Lambda(var, (Patterns.Call _ as call)), lambdaArg) -> 12 | compiler.Compile returnStrategy <| call.Substitute(fun v -> 13 | if v.Name = var.Name then Some lambdaArg else None) 14 | 15 | | Patterns.Application(Patterns.Let(letVar, letVarValue, Patterns.Lambda(lambdaVar, (Patterns.Call _ as call))), lambdaArg) -> 16 | compiler.Compile returnStrategy <| call.Substitute(fun v -> 17 | if v.Name = letVar.Name then Some letVarValue 18 | elif v.Name = lambdaVar.Name then Some lambdaArg 19 | else None) 20 | 21 | | Patterns.Application(Split(lambdaDecl, lambdaRef), Split(argDecl, argRef)) -> 22 | [ yield! lambdaDecl 23 | yield! argDecl 24 | yield returnStrategy.Return <| Apply(lambdaRef, [argRef]) 25 | ] 26 | 27 | | Patterns.Call(Some (Split(delDecl, delRef)), mi, argExprs) 28 | when typeof.IsAssignableFrom mi.DeclaringType -> 29 | let argDecls, argRefs = 30 | Reflection.getDeclarationAndReferences (|Split|) argExprs 31 | [ yield! delDecl 32 | yield! argDecls |> List.concat 33 | yield returnStrategy.Return <| Apply(delRef, argRefs) 34 | ] 35 | | _ -> [] 36 | 37 | let private definition = 38 | CompilerComponent.create <| fun (|Split|) compiler returnStrategy -> 39 | let (|Return|) = compiler.Compile 40 | function 41 | | Patterns.Lambda(var, expr) -> 42 | let block = compiler.Compile ReturnStrategies.returnFrom expr 43 | [ yield returnStrategy.Return <| Lambda([var], Block block) ] 44 | | Patterns.NewDelegate(_, vars, expr) -> 45 | let block = compiler.Compile ReturnStrategies.returnFrom expr 46 | [ yield returnStrategy.Return <| Lambda(vars, Block block) ] 47 | | _ -> [] 48 | 49 | let components = [ 50 | application 51 | definition 52 | ] -------------------------------------------------------------------------------- /src/docs/static/js/foundation/foundation.cookie.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * jQuery Cookie Plugin v1.3 3 | * https://github.com/carhartl/jquery-cookie 4 | * 5 | * Copyright 2011, Klaus Hartl 6 | * Dual licensed under the MIT or GPL Version 2 licenses. 7 | * http://www.opensource.org/licenses/mit-license.php 8 | * http://www.opensource.org/licenses/GPL-2.0 9 | * 10 | * Modified to work with Zepto.js by ZURB 11 | */ 12 | (function ($, document, undefined) { 13 | 14 | var pluses = /\+/g; 15 | 16 | function raw(s) { 17 | return s; 18 | } 19 | 20 | function decoded(s) { 21 | return decodeURIComponent(s.replace(pluses, ' ')); 22 | } 23 | 24 | var config = $.cookie = function (key, value, options) { 25 | 26 | // write 27 | if (value !== undefined) { 28 | options = $.extend({}, config.defaults, options); 29 | 30 | if (value === null) { 31 | options.expires = -1; 32 | } 33 | 34 | if (typeof options.expires === 'number') { 35 | var days = options.expires, t = options.expires = new Date(); 36 | t.setDate(t.getDate() + days); 37 | } 38 | 39 | value = config.json ? JSON.stringify(value) : String(value); 40 | 41 | return (document.cookie = [ 42 | encodeURIComponent(key), '=', config.raw ? value : encodeURIComponent(value), 43 | options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE 44 | options.path ? '; path=' + options.path : '', 45 | options.domain ? '; domain=' + options.domain : '', 46 | options.secure ? '; secure' : '' 47 | ].join('')); 48 | } 49 | 50 | // read 51 | var decode = config.raw ? raw : decoded; 52 | var cookies = document.cookie.split('; '); 53 | for (var i = 0, l = cookies.length; i < l; i++) { 54 | var parts = cookies[i].split('='); 55 | if (decode(parts.shift()) === key) { 56 | var cookie = decode(parts.join('=')); 57 | return config.json ? JSON.parse(cookie) : cookie; 58 | } 59 | } 60 | 61 | return null; 62 | }; 63 | 64 | config.defaults = {}; 65 | 66 | $.removeCookie = function (key, options) { 67 | if ($.cookie(key) !== null) { 68 | $.cookie(key, null, options); 69 | return true; 70 | } 71 | return false; 72 | }; 73 | 74 | })(Foundation.zj, document); 75 | -------------------------------------------------------------------------------- /src/main/FunScript/Times.fs: -------------------------------------------------------------------------------- 1 | module internal FunScript.Times 2 | 3 | open AST 4 | open System 5 | open Microsoft.FSharp.Quotations 6 | 7 | let private maxmin = 8 | CompilerComponent.create <| fun (|Split|) compiler returnStrategy -> 9 | function 10 | | Patterns.FieldGet(None, fi) when fi.DeclaringType.Name = "DateTime" -> 11 | let compile = fun quote -> let mi, _ = Quote.toMethodInfoFromLambdas quote 12 | compiler.Compile returnStrategy (ExpressionReplacer.buildCall mi []) 13 | match fi.Name with 14 | | "MaxValue" -> compile <@ Core.Time.DateTime.MaxValue @> 15 | | "MinValue" -> compile <@ Core.Time.DateTime.MinValue @> 16 | | _ -> [] 17 | | _ -> [] 18 | 19 | let components = 20 | [ 21 | [ 22 | maxmin 23 | ExpressionReplacer.createUnsafe <@ fun (y, m, d) -> DateTime(y, m, d) @> <@ Core.Time.DateTime.FromYMD @> 24 | ExpressionReplacer.createUnsafe <@ fun (y, m, d, h, min, s) -> DateTime(y, m, d, h, min, s) @> <@ Core.Time.DateTime.FromYMDHMS @> 25 | ExpressionReplacer.createUnsafe <@ fun (y, m, d, h, min, s, kind: DateTimeKind) -> DateTime(y, m, d, h, min, s, kind) @> <@ Core.Time.DateTime.FromYMDHMSwithKind @> 26 | ExpressionReplacer.createUnsafe <@ fun (y, m, d, h, min, s, ms: int) -> DateTime(y, m, d, h, min, s, ms) @> <@ Core.Time.DateTime.FromYMDHMSM @> 27 | ExpressionReplacer.createUnsafe <@ fun (y, m, d, h, min, s, ms: int, kind: DateTimeKind) -> DateTime(y, m, d, h, min, s, ms, kind) @> <@ Core.Time.DateTime.FromYMDHMSMwithKind @> 28 | 29 | ExpressionReplacer.createUnsafe <@ fun (t) -> TimeSpan(t) @> <@ Core.Time.TimeSpan.FromTicks @> 30 | ExpressionReplacer.createUnsafe <@ fun (h,m,s) -> TimeSpan(h,m,s) @> <@ Core.Time.TimeSpan.FromHMS @> 31 | ExpressionReplacer.createUnsafe <@ fun (d,h,m,s) -> TimeSpan(d,h,m,s) @> <@ Core.Time.TimeSpan.FromDHMS @> 32 | ExpressionReplacer.createUnsafe <@ fun (d,h,m,s,ms) -> TimeSpan(d,h,m,s,ms) @> <@ Core.Time.TimeSpan.FromDHMSM @> 33 | ] 34 | ExpressionReplacer.createTypeMethodMappings 35 | typeof 36 | typeof 37 | 38 | ExpressionReplacer.createTypeMethodMappings 39 | typeof 40 | typeof 41 | ] |> List.concat 42 | -------------------------------------------------------------------------------- /src/extra/FunScript.Compiler/Program.fs: -------------------------------------------------------------------------------- 1 | open System 2 | open System.IO 3 | open System.Reflection 4 | open FunScript 5 | open Microsoft.FSharp.Quotations 6 | open Microsoft.FSharp.Core; 7 | open Microsoft.FSharp.Text; 8 | 9 | let compile assemblyPath filename components = 10 | 11 | // loading the assembly from a file maybe problematic if 12 | // the assembly as dependcies on non-BCL stuff, consider 13 | // otherways of doing this 14 | let asm = Assembly.LoadFile(assemblyPath) 15 | 16 | // Find the main method in this assembly 17 | // Could offer lot more flexiblity here ... 18 | let mainCompileExpr = 19 | printfn "Searching for main function..." 20 | let types = asm.GetTypes() 21 | let flags = BindingFlags.NonPublic ||| BindingFlags.Public ||| BindingFlags.Static 22 | let mains = 23 | [ for typ in types do 24 | for mi in typ.GetMethods(flags) do 25 | if mi.Name = "main" then yield mi ] 26 | let main = 27 | match mains with 28 | | [it] -> it 29 | | _ -> failwith "Main function not found!" 30 | printfn "Found entry point..." 31 | Expr.Call(main, []) 32 | 33 | 34 | // Compile the main function into a script 35 | let sw = System.Diagnostics.Stopwatch.StartNew() 36 | let source = FunScript.Compiler.Compiler.Compile(mainCompileExpr, components=components) 37 | let sourceWrapped = sprintf "$(document).ready(function () {\n%s\n});" source 38 | printfn "Generated JavaScript in %f sec..." (float sw.ElapsedMilliseconds / 1000.0) 39 | File.Delete filename 40 | File.WriteAllText(filename, sourceWrapped) 41 | 42 | 43 | let assemPath = ref "" 44 | let outPath = ref "" 45 | let args = 46 | [ ArgInfo("--assembly-path", ArgType.String(fun x -> assemPath := x), 47 | "Path to the assembly you want fun script to compile") 48 | ArgInfo("--out-path", ArgType.String(fun x -> outPath := x), 49 | "Path of the resulting javascript file") ] 50 | 51 | let usageText = "FunScript Compiler - usage: funsc " 52 | 53 | [] 54 | let main argv = 55 | ArgParser.Parse(args, usageText = usageText) 56 | if String.IsNullOrWhiteSpace(!assemPath) || String.IsNullOrWhiteSpace(!outPath) then 57 | printfn "error: both --assembly-path and --out-path are required" 58 | ArgParser.Usage(args, usage = usageText) 59 | else 60 | // need to give more control of the components? 61 | compile !assemPath !outPath []//Interop.Components.all 62 | 0 63 | -------------------------------------------------------------------------------- /tests/FunScript.Tests/UnionTypeTests.fs: -------------------------------------------------------------------------------- 1 | [] 2 | module FunScript.Tests.UnionTypes 3 | 4 | open NUnit.Framework 5 | 6 | type Gender = Male | Female 7 | 8 | [] 9 | let ``Union case constructions with no arguments can be generated (user)``() = 10 | check 11 | <@@ 12 | let x = Male 13 | let y = Female 14 | true 15 | @@> 16 | 17 | [] 18 | let ``Union cases matches with no arguments can be generated (user)``() = 19 | check 20 | <@@ 21 | let x = Male 22 | match x with 23 | | Female -> true 24 | | Male -> false 25 | @@> 26 | 27 | 28 | [] 29 | let ``Union case constructions with no arguments can be generated (option)``() = 30 | check 31 | <@@ 32 | let x: unit Option = None 33 | true 34 | @@> 35 | 36 | [] 37 | let ``Union cases matches with no arguments can be generated (option)``() = 38 | check 39 | <@@ 40 | let x: bool Option = None 41 | match x with 42 | | None -> true 43 | | Some y -> y 44 | @@> 45 | 46 | [] 47 | let ``Union case constructions with one argument can be generated``() = 48 | check 49 | <@@ 50 | let x = Some "" 51 | true 52 | @@> 53 | 54 | [] 55 | let ``Union cases matches with one argument can be generated``() = 56 | check 57 | <@@ 58 | let x = Some false 59 | match x with 60 | | None -> true 61 | | Some y -> y 62 | @@> 63 | 64 | 65 | type TestUnion = 66 | | Case0 67 | | Case1 of string 68 | | Case2 of string * string 69 | | Case3 of string * string * string 70 | 71 | 72 | [] 73 | let ``Union case constructions with many arguments can be generated``() = 74 | check 75 | <@@ 76 | let x = Case2("", "") 77 | true 78 | @@> 79 | 80 | [] 81 | let ``Union cases matches with many arguments can be generated``() = 82 | check 83 | <@@ 84 | let x = Case3("a", "b", "c") 85 | match x with 86 | | Case3(a, b, c) -> a + b + c 87 | | _ -> "" 88 | @@> 89 | 90 | type TestUnion2 = 91 | | Tag of string 92 | | NewTag of string 93 | 94 | [] 95 | let ``Union cases called Tag still work (bug due to Tag field)``() = 96 | check 97 | <@@ 98 | let x = Tag "abc" 99 | match x with 100 | | Tag x -> x 101 | | _ -> "" 102 | @@> -------------------------------------------------------------------------------- /examples/EasyGettingStarted/Program.fs: -------------------------------------------------------------------------------- 1 | (* 2 | Main module. 3 | ============ 4 | Intended as a reference project for beginners who aim to get up and running and learn the basics. 5 | Moreover, intended to focus on examples leveraging FunScript for Mobile development, especially with 6 | JQueryMobile and PhoneGap. 7 | 8 | Used with MS Visual Studio 2013 (professional), 9 | with the vanilla "FunScript - Not Hosted" project template (by Zach Bary), 10 | which can be found through the online project search. Plus relevant FunScript binding packages (through NuGet). 11 | 12 | Your todo: 13 | REPLACE the "FunScript - Not Hosted" Project.fs file contents with this file. 14 | ADD relevant FunScript.TypeScript.Binding.? packages 15 | Through NuGet manager for your solution: FunScript.TypeScript.Binding.jquerymobile and FunScript.TypeScript.Binding.phonegap 16 | ADD the rest of the examples *.fs files to the visual studio project. NOTICE: file order matters for MS VS. 17 | SELECT below which example page you want to write into the index file. 18 | 19 | Leveraging some examples from the Funscript GitHub directory: 20 | https://github.com/ZachBray/FunScript/tree/master/Examples 21 | Such as the Canvas example (by Zach Bary) - offered as a good first project (hello-world alternative) here. 22 | 23 | Adding examples for JQueryMobile and PhoneGap (TBD). 24 | *) 25 | 26 | [] 27 | module Program 28 | 29 | open FunScript 30 | open FSharp.Data 31 | open System.IO 32 | 33 | // Each file contains a different example 34 | open HtmlCanvasExample // Zach Bary's example, the FS TS code draws 2 rectangles and inject them into the html file that does the rest 35 | open BodyElementsExample // Modifying the HtmlCanvasExample to represent TS which populates the whole HTML body 36 | open JQueryMobileExample // Modifying the BodyElementsExample to work with the JQueryMobile library. 37 | open Mazing // Simple "maze" mobile application, leveraging DOM, js, jquerymobile, cordova/phonegap 38 | 39 | // Create a file... 40 | let filePath = Path.Combine(System.Environment.CurrentDirectory, "index.html") 41 | 42 | // Write the page 43 | // ------------------------------------------ 44 | // SELECT which example you would like to use 45 | // ------------------------------------------ 46 | //File.WriteAllText(filePath, htmlCanvasPage) 47 | //File.WriteAllText(filePath, bodyElementsPage) 48 | //File.WriteAllText(filePath, jQueryMobilePage) 49 | File.WriteAllText(filePath, mazingPage) 50 | 51 | // Open the file in the default web browser... 52 | System.Diagnostics.Process.Start(filePath) |> ignore -------------------------------------------------------------------------------- /examples/WorldBank/Web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Charting World Bank data with F# 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 24 | 25 |
26 |
27 |
28 |

Charting World Bank data with F#

29 |
30 |
31 |
32 | 33 | 34 | 43 |
44 |

45 | Comparing university enrollment using F# type provider for the WorldBank data, 46 | FunScript F# to JavaScript compiler with a type provider for TypeScript definitions 47 | and Highcharts charting library for JavaScript. 48 | Select countries you want to compare: 49 |

50 |
51 | 52 |
53 |
 
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
 
65 |
66 | 67 | 68 |
69 | 70 |

Chart updates automatically

71 |
72 |
73 | 74 |
75 | 76 | 77 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /src/data/FunScript.Data/Utils.fs: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------- 2 | // Helper functions & JavaScript runtime for Type Provider mappings 3 | // -------------------------------------------------------------------------------------- 4 | 5 | module private FunScript.Data.Utils 6 | 7 | open FunScript 8 | open Microsoft.FSharp.Quotations 9 | 10 | let undef() = failwith "!" 11 | 12 | let (|SpecificConstructor|_|) templateParameter = 13 | match templateParameter with 14 | | Patterns.NewObject(cinfo1, _) -> (function 15 | | Patterns.NewObject(cinfo2, args) 16 | when cinfo1.DeclaringType.FullName = cinfo2.DeclaringType.FullName -> 17 | // when cinfo1.MetadataToken = cinfo2.MetadataToken -> 18 | Some(cinfo1, args) 19 | | _ -> None) 20 | | _ -> invalidArg "templateParameter" "Unrecognized quotation: Must be NewObject." 21 | 22 | [] 23 | let isNull x : bool = false 24 | 25 | [] 26 | let emptyIfNull (list:_ list) = 27 | if isNull list then List.empty 28 | else list 29 | 30 | type XMLHttpRequest = 31 | abstract ``open`` : string * string -> unit 32 | abstract setRequestHeader : string * string -> unit 33 | abstract send : string -> unit 34 | 35 | abstract onreadystatechange : (unit -> unit) with get, set 36 | abstract readyState : float 37 | abstract responseText : string 38 | 39 | [] 59 | let newXMLHttpRequest() : XMLHttpRequest = failwith "never" 60 | 61 | [] 62 | let encodeURIComponent(s:string) : string = failwith "never" 63 | 64 | [] 78 | let getJSONPrefix (url:string, callback : string -> unit) : unit = failwith "never" -------------------------------------------------------------------------------- /src/main/FunScript/Sets.fs: -------------------------------------------------------------------------------- 1 | module internal FunScript.Sets 2 | 3 | open AST 4 | open System.Collections 5 | open Microsoft.FSharp.Quotations 6 | 7 | 8 | let components = 9 | [ 10 | [ 11 | // ExpressionReplacer.createUnsafe 12 | // <@ fun xs ys -> Set.op_Addition(xs, ys) @> 13 | // <@ fun xs ys -> Core.Set.Set<_>.op_Addition(xs, ys) @> 14 | // ExpressionReplacer.createUnsafe 15 | // <@ fun xs ys -> Set.op_Subtraction(xs, ys) @> 16 | // <@ fun xs ys -> Core.Set.Set<_>.op_Subtraction(xs, ys) @> 17 | // ExpressionReplacer.createUnsafe 18 | // <@ fun (xs:_ Set) -> xs.Add @> 19 | // <@ fun (xs:_ Core.Set.Set) -> xs.Add @> 20 | // ExpressionReplacer.createUnsafe 21 | // <@ fun (xs:_ Set) -> xs.Contains @> 22 | // <@ fun (xs:_ Core.Set.Set) -> xs.Contains @> 23 | // ExpressionReplacer.createUnsafe 24 | // <@ fun (xs:_ Set) -> xs.Count @> 25 | // <@ fun (xs:_ Core.Set.Set) -> xs.Count @> 26 | // ExpressionReplacer.createUnsafe 27 | // <@ fun (xs:_ Set) -> xs.IsEmpty @> 28 | // <@ fun (xs:_ Core.Set.Set) -> xs.IsEmpty @> 29 | // ExpressionReplacer.createUnsafe 30 | // <@ fun (xs:_ Set) -> xs.IsProperSubsetOf @> 31 | // <@ fun (xs:_ Core.Set.Set) -> xs.IsProperSubsetOf @> 32 | // ExpressionReplacer.createUnsafe 33 | // <@ fun (xs:_ Set) -> xs.IsProperSupersetOf @> 34 | // <@ fun (xs:_ Core.Set.Set) -> xs.IsProperSupersetOf @> 35 | // ExpressionReplacer.createUnsafe 36 | // <@ fun (xs:_ Set) -> xs.IsSubsetOf @> 37 | // <@ fun (xs:_ Core.Set.Set) -> xs.IsSubsetOf @> 38 | // ExpressionReplacer.createUnsafe 39 | // <@ fun (xs:_ Set) -> xs.IsSupersetOf @> 40 | // <@ fun (xs:_ Core.Set.Set) -> xs.IsSupersetOf @> 41 | // ExpressionReplacer.createUnsafe 42 | // <@ fun (xs:_ Set) -> xs.MaximumElement @> 43 | // <@ fun (xs:_ Core.Set.Set) -> xs.MaximumElement @> 44 | // ExpressionReplacer.createUnsafe 45 | // <@ fun (xs:_ Set) -> xs.MinimumElement @> 46 | // <@ fun (xs:_ Core.Set.Set) -> xs.MinimumElement @> 47 | // ExpressionReplacer.createUnsafe 48 | // <@ fun (xs:_ Set) -> xs.Remove @> 49 | // <@ fun (xs:_ Core.Set.Set) -> xs.Remove @> 50 | ExpressionReplacer.createUnsafe <@ fun xs -> set xs @> <@ fun xs -> FunScript.Core.Set.ofSeq xs @> 51 | ] 52 | 53 | ExpressionReplacer.createTypeMethodMappings 54 | typeof> 55 | typeof> 56 | 57 | ExpressionReplacer.createModuleMapping 58 | "FSharp.Core" "Microsoft.FSharp.Collections.SetModule" 59 | "FunScript" "FunScript.Core.Set" 60 | ] |> List.concat -------------------------------------------------------------------------------- /examples/Brainfuck/FunScript.Brainfuck.Website/FunScript.Brainfuck.Website.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {FA9A7393-4CCC-41B7-B001-6DE963EBC2CC} 8 | Library 9 | Properties 10 | FunScript.Brainfuck.Website 11 | FunScript.Brainfuck.Website 12 | v4.5 13 | 512 14 | 15 | 16 | AnyCPU 17 | true 18 | full 19 | false 20 | ..\bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | AnyCPU 27 | pdbonly 28 | true 29 | ..\bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | 37 | 38 | 39 | PreserveNewest 40 | 41 | 42 | PreserveNewest 43 | 44 | 45 | PreserveNewest 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 61 | -------------------------------------------------------------------------------- /src/main/FunScript/Arrays.fs: -------------------------------------------------------------------------------- 1 | module internal FunScript.Arrays 2 | 3 | open AST 4 | open System.Collections.Generic 5 | open Microsoft.FSharp.Quotations 6 | 7 | let private creation = 8 | CompilerComponent.create <| fun (|Split|) _ returnStrategy -> 9 | function 10 | | Patterns.NewArray(arrayType, exprs) -> 11 | let decls, refs = Reflection.getDeclarationAndReferences (|Split|) exprs 12 | [ yield! decls |> Seq.concat 13 | yield returnStrategy.Return <| Array refs 14 | ] 15 | | _ -> [] 16 | 17 | let private getIndex = 18 | CompilerComponent.binary 19 | <@ fun (xs:_ []) i -> xs.[i] @> 20 | (fun array index -> IndexGet(array, index)) 21 | 22 | let private setIndex = 23 | CompilerComponent.ternaryStatement 24 | <@ fun (xs:_ []) i v -> xs.[i] <- v @> 25 | (fun array index value -> Assign(IndexGet(array, index), value)) 26 | 27 | let private getIndexBoxed = 28 | CompilerComponent.binary 29 | <@ fun (xs:System.Array) (i : int) -> xs.GetValue i @> 30 | (fun array index -> IndexGet(array, index)) 31 | 32 | let private setIndexBoxed = 33 | CompilerComponent.ternaryStatement 34 | <@ fun (xs:System.Array) (v : obj) (i : int) -> xs.SetValue(v, i) @> 35 | (fun array value index -> Assign(IndexGet(array, index), value)) 36 | 37 | [] 38 | module Extensions = 39 | let getEnumeratorBoxed(xs : System.Array) = 40 | (unbox xs |> Array.toSeq).GetEnumerator() 41 | 42 | let components = 43 | [ 44 | [ 45 | creation 46 | getIndex 47 | setIndex 48 | ExpressionReplacer.createUnsafe <@ fun (xs:_ IList) i -> xs.[i] @> <@ fun (xs:_[]) i -> xs.[i] @> 49 | ExpressionReplacer.createUnsafe <@ fun (xs:_ IList) i v -> xs.[i] <- v @> <@ fun (xs:_[]) i v -> xs.[i] <- v @> 50 | ExpressionReplacer.createUnsafe <@ fun (xs:_ IList) -> xs.Count @> <@ fun (xs:_[]) -> xs.Length @> 51 | ExpressionReplacer.create <@ fun (xs:_ []) -> xs.Length @> <@ Core.Array.BoxedLength @> 52 | ExpressionReplacer.createUnsafe <@ Array.toList @> <@ Core.List.OfArray @> 53 | ExpressionReplacer.createUnsafe <@ Array.ofList @> <@ Core.List.ToArray @> 54 | ExpressionReplacer.createUnsafe 55 | <@ fun (t, s:int) -> System.Array.CreateInstance(t, s) @> 56 | <@ fun (t, s:int) -> Core.Array.CreateInstance(t, s) @> 57 | ExpressionReplacer.createUnsafe <@ fun (xs : System.Array) -> xs.GetEnumerator() @> <@ Extensions.getEnumeratorBoxed @> 58 | getIndexBoxed 59 | setIndexBoxed 60 | ExpressionReplacer.create <@ Array.toSeq @> <@ Core.Seq.OfArray @> 61 | ExpressionReplacer.create <@ Array.ofSeq @> <@ Core.Seq.ToArray @> 62 | ] 63 | ExpressionReplacer.createModuleMapping 64 | "FSharp.Core" "Microsoft.FSharp.Collections.ArrayModule" 65 | "FunScript" "FunScript.Core.Array" 66 | ] |> List.concat -------------------------------------------------------------------------------- /src/main/FunScript/Compiler.fs: -------------------------------------------------------------------------------- 1 | module FunScript.Compiler 2 | 3 | open FunScript 4 | 5 | //TODO: Use IoC here. MiniIoC perhaps? 6 | let createComponents(isEventMappingEnabled) = 7 | [ //NOTE: ORDER MATTERS! 8 | yield! Options.components 9 | yield! Seqs.components 10 | yield! Sets.components 11 | yield! Maps.components 12 | yield! Lists.components 13 | yield! Strings.components 14 | yield! Regexs.components 15 | yield! Times.components 16 | yield! Asyncs.components 17 | yield! ReflectedDefinitions.components 18 | yield! Arrays.components 19 | yield! ResizeArrays.components 20 | yield! Dictionaries.components 21 | yield! RecordTypes.components 22 | yield! UnionTypes.components 23 | yield! Tuples.components 24 | yield! Logic.components 25 | yield! LambdaApplication.components 26 | yield! LetBindings.components 27 | yield! Arithmetic.components 28 | yield! Comparison.components 29 | yield! PrimitiveTypes.components 30 | yield! ControlFlow.components 31 | yield! Objects.components 32 | yield! Reflection.components 33 | yield! TypeConversions.components 34 | yield! OtherMappings.components 35 | if isEventMappingEnabled then 36 | yield! OtherMappings.eventComponents 37 | yield! CommonOperators.components 38 | ] 39 | 40 | type Compiler = 41 | static member private CompileImpl(expression, adjustComponents, noReturn, shouldCompress, isEventMappingEnabled) = 42 | let shouldCompress = defaultArg shouldCompress false 43 | let isEventMappingEnabled = defaultArg isEventMappingEnabled true 44 | let returnStrat = 45 | if defaultArg noReturn false then ReturnStrategies.inplace 46 | else ReturnStrategies.returnFrom 47 | let components = createComponents isEventMappingEnabled 48 | let compiler = InternalCompiler.Compiler(adjustComponents components) 49 | let program = compiler.Compile returnStrat expression 50 | let reflectedDefs = compiler.Globals 51 | let block = List.append reflectedDefs program 52 | if shouldCompress then (AST.Block block).PrintCompressed() 53 | else (AST.Block block).Print() 54 | 55 | static member Compile(expression, adjustComponents, ?noReturn, ?shouldCompress, ?isEventMappingEnabled) = 56 | Compiler.CompileImpl(expression, adjustComponents, noReturn, shouldCompress, isEventMappingEnabled) 57 | 58 | static member Compile(expression, ?components, ?noReturn, ?shouldCompress, ?isEventMappingEnabled) = 59 | let components = defaultArg components [] 60 | Compiler.CompileImpl(expression, (fun existingComponents -> existingComponents @ components), noReturn, shouldCompress, isEventMappingEnabled) 61 | 62 | let compile expr = Compiler.Compile(expr) 63 | let compileWithoutReturn expr = Compiler.Compile(expr, noReturn=true) 64 | -------------------------------------------------------------------------------- /src/main/FunScript/UnionTypes.fs: -------------------------------------------------------------------------------- 1 | module internal FunScript.UnionTypes 2 | 3 | open AST 4 | open System.Reflection 5 | open Microsoft.FSharp.Quotations 6 | open Microsoft.FSharp.Reflection 7 | 8 | let private ignoredUnions = 9 | set [ 10 | //typeof.Name 11 | typeof.Name 12 | ] 13 | 14 | let private creation = 15 | CompilerComponent.create <| fun (|Split|) compiler returnStrategy -> 16 | function 17 | | Patterns.NewUnionCase(uci, exprs) -> 18 | let decls, refs = Reflection.getDeclarationAndReferences (|Split|) exprs 19 | if ignoredUnions.Contains uci.DeclaringType.Name then 20 | let propNames = Reflection.getCaseVars uci |> List.map (fun (var,_) -> var.Name) 21 | let fields = 22 | ("Tag", Number(float uci.Tag)) :: 23 | (List.zip propNames refs) 24 | // TODO: What about comparison? 25 | [ yield! decls |> Seq.concat 26 | yield returnStrategy.Return <| Object fields ] 27 | else 28 | let cons = Reflection.getUnionCaseConstructorVar compiler uci 29 | [ yield! decls |> Seq.concat 30 | yield returnStrategy.Return <| New(cons, refs) ] 31 | | _ -> [] 32 | 33 | let private matching = 34 | CompilerComponent.create <| fun (|Split|) compiler returnStrategy -> 35 | function 36 | | Patterns.UnionCaseTest(Split(objDecl, objRef), uci) -> 37 | [ yield! objDecl 38 | yield returnStrategy.Return <| BinaryOp(PropertyGet(objRef, "Tag"), "==", Number(float uci.Tag)) 39 | ] 40 | | Patterns.Call(None, mi, [Split(objDecl, objRef)]) when 41 | FSharpType.IsUnion mi.DeclaringType && 42 | mi.Name = "GetTag" && 43 | mi.ReturnType = typeof -> 44 | [ yield! objDecl 45 | yield returnStrategy.Return <| PropertyGet(objRef, "Tag") 46 | ] 47 | | Patterns.Call(None, mi, [arg]) as e when 48 | mi.DeclaringType.Name.Contains "FSharpOption" && 49 | mi.Name = "Some" -> 50 | let cases = FSharpType.GetUnionCases e.Type 51 | let someCase = cases.[1] 52 | compiler.Compile returnStrategy (Expr.NewUnionCase(someCase, [arg])) 53 | | Patterns.Call(None, mi, []) as e when 54 | mi.DeclaringType.Name.Contains "FSharpOption" && 55 | mi.Name = "get_None" -> 56 | let cases = FSharpType.GetUnionCases e.Type 57 | let noneCase = cases.[0] 58 | compiler.Compile returnStrategy (Expr.NewUnionCase(noneCase, [])) 59 | | Patterns.PropertyGet(None, pi, []) as e when 60 | pi.DeclaringType.Name.Contains "FSharpOption" && 61 | pi.Name = "None" -> 62 | let cases = FSharpType.GetUnionCases e.Type 63 | let noneCase = cases.[0] 64 | compiler.Compile returnStrategy (Expr.NewUnionCase(noneCase, [])) 65 | | _ -> [] 66 | 67 | let components = [ 68 | creation 69 | matching 70 | ] -------------------------------------------------------------------------------- /.paket/paket.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | true 6 | 7 | true 8 | $(MSBuildThisFileDirectory) 9 | $(MSBuildThisFileDirectory)..\ 10 | 11 | 12 | 13 | $(PaketToolsPath)paket.exe 14 | $(PaketToolsPath)paket.bootstrapper.exe 15 | "$(PaketExePath)" 16 | mono --runtime=v4.0.30319 $(PaketExePath) 17 | "$(PaketBootStrapperExePath)" 18 | mono --runtime=v4.0.30319 $(PaketBootStrapperExePath) 19 | 20 | $(MSBuildProjectDirectory)\paket.references 21 | $(MSBuildProjectFullPath).paket.references 22 | $(PaketCommand) restore --references-files "$(PaketReferences)" 23 | $(PaketBootStrapperCommand) 24 | 25 | RestorePackages; $(BuildDependsOn); 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/main/FunScript/Core/ResizeArray.fs: -------------------------------------------------------------------------------- 1 | [] 2 | module FunScript.Core.ResizeArray 3 | 4 | open FunScript 5 | open System.Collections.Generic 6 | 7 | let ToSeq(xs: ResizeArray<'T>) = 8 | Seq.unfold (fun i -> if i < xs.Count then Some(xs.[i], i+1) else None) 0 9 | 10 | type ResizeArray<'T> = 11 | [] 12 | static member private getCount(xs: ResizeArray<'T>): int = failwith "never" 13 | 14 | [] 15 | static member private getItem(xs: ResizeArray<'T>, index: int): 'T = failwith "never" 16 | 17 | // NOTE: Some JS MVC frameworks override the Array.splice method to hook on array updates 18 | [] 19 | static member private setItem(xs: ResizeArray<'T>, index: int, item: 'T): unit = failwith "never" 20 | 21 | [] 22 | static member ZeroCreate(): ResizeArray<'T> = failwith "never" 23 | 24 | // NOTE: If we use 'new Array(size)' the array is automatically filled with undefined values which is not 25 | // the expected behaviour in .NET so we just create empty arrays no matter the given initial capacity. 26 | static member ZeroCreateWithSize(size: int) = ResizeArray<_>.ZeroCreate() 27 | 28 | static member OfSeq(items: seq<'T>) = 29 | let ra = ResizeArray<'T>.ZeroCreate() 30 | ra.AddRange(items) 31 | ra 32 | 33 | member xs.Count with get() = ResizeArray<'T>.getCount(xs) 34 | 35 | member xs.Item 36 | with get(index: int) = ResizeArray<'T>.getItem(xs, index) 37 | and set(index: int) (item: 'T) = ResizeArray<'T>.setItem(xs, index, item) 38 | 39 | [] 40 | member xs.Clear(): unit = failwith "never" 41 | 42 | [] 43 | member xs.Add(item: 'T): unit = failwith "never" 44 | 45 | member xs.AddRange(items: seq<'T>): unit = 46 | for item in items do xs.Add(item) 47 | 48 | [ -1)")>] 49 | member xs.Contains(searchElement: 'T): bool = failwith "never" 50 | 51 | [] 52 | member xs.IndexOf(searchElement: 'T): int = failwith "never" 53 | 54 | [ -1) { {0}.splice(i, 1); return true; } else { return false; }")>] 55 | member xs.Remove(item: 'T): bool = failwith "never" 56 | 57 | [] 58 | member xs.RemoveAt(index: int): unit = failwith "never" 59 | 60 | [] 61 | member xs.Insert(index: int, item: 'T): unit = failwith "never" 62 | 63 | [] 64 | member xs.Reverse(): unit = failwith "never" 65 | 66 | [] 67 | member xs.SortInPlace(): unit = failwith "never" 68 | 69 | [] 70 | member xs.SortInPlaceWith(comparison: System.Comparison<'T>): unit = failwith "never" 71 | 72 | // member xs.GetEnumerator(): System.Collections.Generic.IEnumerator<'T> = 73 | // upcast new Seq.UnfoldEnumerator<_,_>(-1, fun i -> if i < xs.Count then Some(xs.[i], i+1) else None) 74 | -------------------------------------------------------------------------------- /src/docs/static/live/worldbank.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Charting World Bank data with F# 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 22 | 23 | 24 | 25 | 26 |
27 | 28 |
29 | 35 |

World Bank

36 |
37 | 38 |
39 | 40 |
41 |

Charting World Bank data with F#

42 |

43 | Comparing university enrollment using F# type provider for the WorldBank data, 44 | FunScript F# to JavaScript compiler with a type provider for TypeScript definitions 45 | and Highcharts charting library for JavaScript. 46 | Select countries you want to compare: 47 |

48 |
49 | 50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | 67 | 68 |

Chart updates automatically

69 |
70 | 71 |
72 |
73 | 74 |
75 |
76 | 77 | 80 | 81 |
82 | 83 | 84 | -------------------------------------------------------------------------------- /src/main/FunScript/Dictionaries.fs: -------------------------------------------------------------------------------- 1 | module internal FunScript.Dictionaries 2 | 3 | open AST 4 | open Microsoft.FSharp.Quotations 5 | open System.Collections.Generic 6 | 7 | let components = 8 | [ 9 | ExpressionReplacer.createUnsafe <@ fun () -> Dictionary<_,_>() @> <@ Core.Dictionaries.MutableDic.Create @> 10 | ExpressionReplacer.createUnsafe <@ fun (size: int) -> Dictionary<_,_>(size) @> <@ Core.Dictionaries.MutableDic.CreateWithSize @> 11 | ExpressionReplacer.createUnsafe <@ fun (xs: seq<_*_>) -> dict xs @> <@ Core.Dictionaries.MutableDic.OfSeq @> 12 | ExpressionReplacer.createUnsafe <@ fun (xs: IDictionary<_,_>) -> Dictionary<_,_>(xs) @> <@ Core.Dictionaries.MutableDic.OfIDictionary @> 13 | 14 | ExpressionReplacer.createUnsafe <@ fun (xs: Dictionary<_,_>.KeyCollection) -> xs.Count @> <@ Core.Dictionaries.MutableDic.KeysCount @> 15 | ExpressionReplacer.createUnsafe <@ fun (xs: Dictionary<_,_>.ValueCollection) -> xs.Count @> <@ Core.Dictionaries.MutableDic.ValuesCount @> 16 | 17 | // Interface members 18 | ExpressionReplacer.createUnsafe <@ fun (xs: IDictionary<_,_>) -> xs.Count @> <@ Core.Dictionaries.MutableDic.EnumCount @> 19 | ExpressionReplacer.createUnsafe <@ fun (xs: IDictionary<_,_>) -> xs.IsReadOnly @> <@ Core.Dictionaries.MutableDic.IsReadOnly @> 20 | ExpressionReplacer.createUnsafe <@ fun (xs: IDictionary<_,_>, key: _) -> xs.Item(key) @> <@ Core.Dictionaries.MutableDic.GetItem @> 21 | ExpressionReplacer.createUnsafe <@ fun (xs: IDictionary<_,_>) -> xs.Keys @> <@ Core.Dictionaries.MutableDic.Keys @> 22 | ExpressionReplacer.createUnsafe <@ fun (xs: IDictionary<_,_>) -> xs.Values @> <@ Core.Dictionaries.MutableDic.Values @> 23 | ExpressionReplacer.createUnsafe <@ fun (xs: IDictionary<_,_>, key: _) -> xs.ContainsKey(key) @> <@ Core.Dictionaries.MutableDic.ContainsKey @> 24 | 25 | // Implementation members 26 | ExpressionReplacer.createUnsafe <@ fun (xs: Dictionary<_,_>) -> xs.Count @> <@ Core.Dictionaries.MutableDic.DicCount @> 27 | ExpressionReplacer.createUnsafe <@ fun (xs: Dictionary<_,_>, key: _) -> xs.Item(key) @> <@ Core.Dictionaries.MutableDic.GetItem @> 28 | ExpressionReplacer.createUnsafe <@ fun (xs: Dictionary<_,_>, key: _, value: _) -> xs.Item(key) <- value @> <@ Core.Dictionaries.MutableDic.SetItem @> 29 | ExpressionReplacer.createUnsafe <@ fun (xs: Dictionary<_,_>) -> xs.Keys @> <@ Core.Dictionaries.MutableDic.Keys @> 30 | ExpressionReplacer.createUnsafe <@ fun (xs: Dictionary<_,_>) -> xs.Values @> <@ Core.Dictionaries.MutableDic.Values @> 31 | 32 | ExpressionReplacer.createUnsafe <@ fun (xs: Dictionary<_,_>, key: _, value: _) -> xs.Add(key, value) @> <@ Core.Dictionaries.MutableDic.Add @> 33 | ExpressionReplacer.createUnsafe <@ fun (xs: Dictionary<_,_>) -> xs.Clear() @> <@ Core.Dictionaries.MutableDic.Clear @> 34 | ExpressionReplacer.createUnsafe <@ fun (xs: Dictionary<_,_>, key: _) -> xs.ContainsKey(key) @> <@ Core.Dictionaries.MutableDic.ContainsKey @> 35 | ExpressionReplacer.createUnsafe <@ fun (xs: Dictionary<_,_>, value: _) -> xs.ContainsValue(value) @> <@ Core.Dictionaries.MutableDic.ContainsValue @> 36 | ExpressionReplacer.createUnsafe <@ fun (xs: Dictionary<_,_>, key: _) -> xs.Remove(key) @> <@ Core.Dictionaries.MutableDic.Remove @> 37 | ] 38 | -------------------------------------------------------------------------------- /src/docs/template/page-template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | {header} - {tagline} 8 | 9 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 42 | 43 |
44 |
45 |
46 |

{header}

47 |

{tagline}

48 |
49 |
50 |
51 | 52 | {document} 53 | {tooltips} 54 | 55 |
58 | 59 | 60 | Fork me on GitHub 61 | 62 | 63 | 68 | 69 | 70 | 73 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /src/main/FunScript.Interop/FunScript.Interop.fsproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | 2.0 8 | 1397ecef-2a65-49ce-afa1-b9884671bbb9 9 | Library 10 | FunScript.Interop 11 | FunScript.Interop 12 | v4.5 13 | FunScript.Interop 14 | 15 | 4.3.1.0 16 | 17 | 18 | true 19 | full 20 | false 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | 3 25 | bin\Debug\FunScript.Interop.XML 26 | 27 | 28 | pdbonly 29 | true 30 | true 31 | bin\Release\ 32 | TRACE 33 | 3 34 | bin\Release\FunScript.Interop.XML 35 | 36 | 37 | 38 | True 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 11 51 | 52 | 53 | 54 | 55 | $(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets 56 | 57 | 58 | 59 | 60 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets 61 | 62 | 63 | 64 | 65 | 72 | -------------------------------------------------------------------------------- /tests/FunScript.Tests/CommonFixture.fs: -------------------------------------------------------------------------------- 1 | [] 2 | module FunScript.Tests.Common 3 | 4 | open FunScript 5 | open NUnit.Framework 6 | open Microsoft.FSharp.Linq.QuotationEvaluation 7 | 8 | let defaultCompile quote = 9 | Compiler.Compiler.Compile(quote, noReturn = false, shouldCompress = true) 10 | 11 | let compileWithComponents components quote = 12 | Compiler.Compiler.Compile(quote, components = components, noReturn = false, shouldCompress = true) 13 | 14 | let compileWithRx quote = 15 | Compiler.Compiler.Compile(quote, components = Rx.Interop.components(), noReturn = false, isEventMappingEnabled = false, shouldCompress = true) 16 | 17 | let checkAreEqualWith prerequisiteJS compile (expectedResult : obj) quote = 18 | let code : string = compile quote 19 | try 20 | let result = 21 | let code = 22 | "return function (data, callback) {" 23 | + "callback(null, (function () {" 24 | + System.Environment.NewLine 25 | + prerequisiteJS 26 | + System.Environment.NewLine 27 | + code + ";" 28 | + System.Environment.NewLine 29 | + " })());" 30 | + "};" 31 | Async.AwaitTask(EdgeJs.Edge.Func(code).Invoke("")) 32 | |> Async.RunSynchronously 33 | let result = 34 | match expectedResult with 35 | | :? float -> 36 | match result with 37 | | :? int as x -> box(float x) 38 | | x -> x 39 | | _ -> result 40 | let message (ex: 'a) (re: 'b) = sprintf "%sExpected: %A%sBut was: %A" System.Environment.NewLine ex System.Environment.NewLine re 41 | Assert.That((result = expectedResult), (message expectedResult result)) 42 | // Wrap xUnit exceptions to stop pauses. 43 | with 44 | | :? System.AggregateException as e -> 45 | let ex = e.InnerException 46 | printfn "// Code:\n%s" code 47 | if ex.GetType().Namespace.StartsWith "FunScript" then raise ex 48 | else failwithf "Message: %s\n" ex.Message 49 | | ex -> 50 | printfn "// Code:\n%s" code 51 | if ex.GetType().Namespace.StartsWith "FunScript" then raise ex 52 | else failwithf "Message: %s\n" ex.Message 53 | 54 | let checkAreEqualWithComponents components expectedResult quote = 55 | checkAreEqualWith "" (compileWithComponents components) expectedResult quote 56 | 57 | let checkAreEqual expectedResult quote = 58 | checkAreEqualWithComponents [] expectedResult quote 59 | 60 | /// Bootstrapping: 61 | /// Generates code. Runs it through a JS interpreter. 62 | /// Checks the result against the compiled expression. 63 | let check (quote:Quotations.Expr) = 64 | let expectedResult = quote.EvalUntyped() 65 | checkAreEqual expectedResult quote 66 | 67 | let checkRx (quote:Quotations.Expr) = 68 | let expectedResult = quote.EvalUntyped() 69 | checkAreEqualWith(sprintf "var Rx = require('%s../../paket-files/Reactive-Extensions/RxJS/dist/rx.all.js');" __SOURCE_DIRECTORY__) 70 | compileWithRx expectedResult quote 71 | 72 | let checkAsync (quote:Quotations.Expr<'a Async>) = 73 | let expectedResult = <@ Async.RunSynchronously %quote @>.Eval() 74 | let immediateQuote = 75 | <@ 76 | let result = ref None 77 | async { 78 | let! v = %quote 79 | result := Some v 80 | } |> Async.StartImmediate 81 | !result |> Option.get 82 | @> 83 | checkAreEqual expectedResult immediateQuote -------------------------------------------------------------------------------- /examples/MovieDatabase/Page.fs: -------------------------------------------------------------------------------- 1 | // --- 2 | // header: Movie Database 3 | // tagline: Calling REST API using Apiary.io 4 | // --- 5 | 6 | [] 7 | module Program 8 | 9 | open FunScript 10 | open FunScript.TypeScript 11 | open ApiaryProvider 12 | 13 | // ------------------------------------------------------------------ 14 | // Initializataion 15 | 16 | type MovieDb = ApiaryProvider<"themoviedb"> 17 | 18 | // Allows writing jq?name for element access 19 | let jq(selector : string) = Globals.Dollar.Invoke selector 20 | let (?) jq name = jq("#" + name) 21 | 22 | // ------------------------------------------------------------------ 23 | // Main function 24 | 25 | let main() = 26 | 27 | let db = new MovieDb("http://api.themoviedb.org") 28 | db.AddQueryParam("api_key", "6ce0ef5b176501f8c07c634dfa933cff") 29 | let root = "http://cf2.imgobject.com/t/p/w92/" 30 | 31 | // ---------------------------------------------------------------- 32 | // Show details 33 | 34 | let showDetails (id:int) = async { 35 | let! movie = db.Movie.AsyncGetMovie(id.ToString()) 36 | jq?dialogOverview.text(movie.Overview) |> ignore 37 | jq?dialogTitle.text(movie.Title) |> ignore 38 | jq?dialogImage.attr("src", root + movie.PosterPath) |> ignore 39 | 40 | let! credits = movie.AsyncCredits() 41 | let sorted = credits.Cast |> Array.sortBy (fun c -> c.Order) 42 | let sorted = 43 | if sorted.Length <= 10 then sorted |> Seq.ofArray 44 | else sorted |> Seq.ofArray |> Seq.take 10 45 | 46 | jq?dialogCast.html("") |> ignore 47 | for cast in credits.Cast do 48 | let html = "" + cast.Name + " (" + cast.Character + ")" 49 | let li = jq("
  • ") 50 | li.html(html) |> ignore 51 | li.appendTo(jq?dialogCast) |> ignore } 52 | 53 | // ---------------------------------------------------------------- 54 | // Movie search 55 | 56 | let search term = async { 57 | let! res = db.Search.AsyncMovie(query=["query", term]) 58 | jq?results.html("") |> ignore 59 | 60 | res.Results 61 | |> Seq.ofArray 62 | |> Seq.iteri (fun index item -> 63 | 64 | let link = 65 | jq("").attr("data-toggle", "modal"). 66 | attr("href", "#detailsDialog").text(item.Title). 67 | click(fun e -> showDetails item.Id |> Async.StartImmediate; null) 68 | 69 | let details = jq("