├── .gitignore ├── Dependencies ├── Jint.dll ├── IronJS.dll ├── Rhino.Mocks.dll ├── Antlr3.Runtime.dll ├── IronJS.Runtime.dll ├── FSharp.PowerPack.dll ├── nunit.framework.dll ├── FSharp.PowerPack.Linq.dll ├── FSharp.Compiler.CodeDom.dll ├── IronJS.LICENSE.txt └── FSharp.PowerPack.Linq.xml ├── FSharp.Javascript.Tests ├── Test1.txt ├── Tests.js ├── LibraryTests.fs ├── RegexTests.fs ├── TestHelper.fs ├── ComputationModule.fs ├── TestModule.fs ├── ComputationExpressionTests.fs ├── QuotationsTestHelper.fs ├── DateTimeTests.fs ├── FSharp.Javascript.Tests.fsproj ├── MapModuleTests.fs ├── PrintingTests.fs ├── ListModuleTests.fs ├── ArrayModuleTests.fs └── SeqModuleTests.fs ├── FSharp.Javascript ├── FSharp.Javascript.Jquery.js ├── Converter.fs ├── FSharp.Javascript.Dom.js ├── Ast.fs ├── Library.fs ├── FSharp.Javascript.fsproj ├── FSharp.Javascript.Library.js ├── Canvas.fs ├── Printer.fs ├── ModuleCompiler.fs └── Dom.fs ├── README.txt ├── JavascriptParser ├── Properties │ └── AssemblyInfo.cs ├── ES3Parser-and-ES3Lexer-LICENSE.txt ├── JavascriptParser.csproj ├── ES3Parser.Action.cs └── ES3Lexer.Action.cs ├── FSharp.Javascript.Utilities ├── Compiler.fs ├── FSharp.Javascript.Utilities.fsproj └── Parser.fs ├── FSharp.Javascript.sln └── LICENSE.txt /.gitignore: -------------------------------------------------------------------------------- 1 | *.suo 2 | *.cache 3 | *.user 4 | */bin/* 5 | */obj/* 6 | _ReSharper.* -------------------------------------------------------------------------------- /Dependencies/Jint.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jgreene/FSharp.Javascript/HEAD/Dependencies/Jint.dll -------------------------------------------------------------------------------- /Dependencies/IronJS.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jgreene/FSharp.Javascript/HEAD/Dependencies/IronJS.dll -------------------------------------------------------------------------------- /Dependencies/Rhino.Mocks.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jgreene/FSharp.Javascript/HEAD/Dependencies/Rhino.Mocks.dll -------------------------------------------------------------------------------- /Dependencies/Antlr3.Runtime.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jgreene/FSharp.Javascript/HEAD/Dependencies/Antlr3.Runtime.dll -------------------------------------------------------------------------------- /Dependencies/IronJS.Runtime.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jgreene/FSharp.Javascript/HEAD/Dependencies/IronJS.Runtime.dll -------------------------------------------------------------------------------- /Dependencies/FSharp.PowerPack.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jgreene/FSharp.Javascript/HEAD/Dependencies/FSharp.PowerPack.dll -------------------------------------------------------------------------------- /Dependencies/nunit.framework.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jgreene/FSharp.Javascript/HEAD/Dependencies/nunit.framework.dll -------------------------------------------------------------------------------- /Dependencies/FSharp.PowerPack.Linq.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jgreene/FSharp.Javascript/HEAD/Dependencies/FSharp.PowerPack.Linq.dll -------------------------------------------------------------------------------- /Dependencies/FSharp.Compiler.CodeDom.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jgreene/FSharp.Javascript/HEAD/Dependencies/FSharp.Compiler.CodeDom.dll -------------------------------------------------------------------------------- /FSharp.Javascript.Tests/Test1.txt: -------------------------------------------------------------------------------- 1 | var a = function(){ 2 | return ((value = value.match(/(\d+),\s*(\d+),\s*(\d+)/))) ? [value[1], value[2], value[3]] : false; 3 | } -------------------------------------------------------------------------------- /FSharp.Javascript.Tests/Tests.js: -------------------------------------------------------------------------------- 1 | var QuotationsTestHelper = {} 2 | QuotationsTestHelper.emit = function (x) { 3 | console.log(x.toString()) 4 | return x; 5 | } -------------------------------------------------------------------------------- /FSharp.Javascript/FSharp.Javascript.Jquery.js: -------------------------------------------------------------------------------- 1 | registerNamespace('FSharp.Javascript.Jquery') 2 | 3 | FSharp.Javascript.Jquery.jquery = window.jQuery 4 | 5 | jQuery.fn.value = jQuery.fn.val -------------------------------------------------------------------------------- /FSharp.Javascript/Converter.fs: -------------------------------------------------------------------------------- 1 | module FSharp.Javascript.Converter 2 | 3 | let convert (quote:Microsoft.FSharp.Quotations.Expr) = 4 | let ast = QuotationsConverter.convertToAst quote 5 | Printer.getJavascript ast 6 | 7 | let convertModule (typ:System.Type) = 8 | let ast = ModuleCompiler.getAstFromType typ 9 | Printer.getJavascript ast -------------------------------------------------------------------------------- /FSharp.Javascript/FSharp.Javascript.Dom.js: -------------------------------------------------------------------------------- 1 | 2 | registerNamespace('FSharp.Javascript') 3 | 4 | FSharp.Javascript.Dom = { 5 | get_document: function () { 6 | return window.document; 7 | }, 8 | 9 | get_window: function () { 10 | return window; 11 | }, 12 | 13 | alert: function (x) { 14 | window.alert(x) 15 | }, 16 | 17 | get_Math: function(){ 18 | return Math; 19 | } 20 | } 21 | 22 | FSharp.Javascript.Canvas = { 23 | getCanvasById : function(id){ 24 | return window.document.getElementById(id) 25 | } 26 | } -------------------------------------------------------------------------------- /FSharp.Javascript.Tests/LibraryTests.fs: -------------------------------------------------------------------------------- 1 | #light 2 | namespace FSharp.Javascript.Tests 3 | 4 | open NUnit.Framework 5 | open FSharp.Javascript.Printer 6 | open TestHelper 7 | 8 | [] 9 | type LibraryTests() = 10 | 11 | [] 12 | member this.``Test1``() = 13 | let script = System.IO.File.ReadAllText("Test1.txt") 14 | test script 15 | 16 | [] 17 | member this.``JQuery 1.4``() = 18 | let script = System.IO.File.ReadAllText("jquery-1.4.txt") 19 | testLibrary script 20 | 21 | [] 22 | member this.``JQuery 1.2.6``() = 23 | let script = System.IO.File.ReadAllText("jquery-1.2.6.txt") 24 | testLibrary script 25 | 26 | [] 27 | member this.``Mootools 1.2.4``() = 28 | let script = System.IO.File.ReadAllText("mootools-1.2.4.txt") 29 | testLibrary script -------------------------------------------------------------------------------- /FSharp.Javascript.Tests/RegexTests.fs: -------------------------------------------------------------------------------- 1 | namespace FSharp.Javascript.Tests 2 | 3 | open NUnit.Framework 4 | open FSharp.Javascript.Printer 5 | open TestModule 6 | open QuotationsTestHelper 7 | open System 8 | open System.Text.RegularExpressions 9 | 10 | open FSharp.Javascript.Library 11 | 12 | [] 13 | type RegexTests() = 14 | 15 | [] 16 | member this.``Can match zipcode`` () = 17 | test <@ let regex = System.Text.RegularExpressions.Regex("^(?!0{5})(\d{5})(?!-?0{4})(-?\d{4})?$") 18 | let valueToMatch = "12345-6789" 19 | let result = regex.IsMatch(valueToMatch) 20 | emit result 21 | 22 | @> 23 | 24 | [] 25 | member this.``Will not match invalid zipcode`` () = 26 | test <@ let regex = System.Text.RegularExpressions.Regex("^(?!0{5})(\d{5})(?!-?0{4})(-?\d{4})?$") 27 | let valueToMatch = "123a5-6789" 28 | let result = regex.IsMatch(valueToMatch) 29 | emit result 30 | 31 | @> 32 | 33 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | You can play with the converter at http://fscript.justsimplecode.com 2 | 3 | To get up and running with FSharp.Javascript 4 | 5 | Reference the FSharp.Javascript.dll 6 | For simple quotation conversion use the below code: 7 | 8 | 9 | open FSharp.Javascript.Converter 10 | open FSharp.Javascript.Dom 11 | 12 | let javascript = convert <@ let i = 0 13 | alert(i) @> 14 | 15 | To convert a module to javascript: 16 | 17 | open FSharp.Javascript.Converter 18 | 19 | let javascript = convertModule (System.Type.GetType("MyModule, MyAssembly")) 20 | 21 | The module compiler does not support converting standalone initialization calls, e.g.: 22 | 23 | module MyModule 24 | 25 | [] 26 | let func() = 1 27 | 28 | //this will not show up in the converted javascript 29 | func() 30 | 31 | This is because the F# quotations system does not support this feature. 32 | 33 | Also remember that all function definitions that you want to convert must be decorated with the [] attribute. 34 | 35 | 36 | You can also use jquery with 37 | 38 | open FSharp.Javascript.Jquery -------------------------------------------------------------------------------- /FSharp.Javascript/Ast.fs: -------------------------------------------------------------------------------- 1 | namespace FSharp.Javascript.Ast 2 | 3 | open System.Linq.Expressions 4 | 5 | 6 | type node = 7 | | Assign of node * node 8 | | AutoProperty of obj * node 9 | | BinaryOp of node * node * ExpressionType 10 | | Identifier of string * bool 11 | | Number of int option * float option 12 | | Function of node * node list * string option 13 | | AssignmentBlock of node list * bool 14 | | Block of node list 15 | | Boolean of bool 16 | | BreakNode of string 17 | | ForInNode of node * node * node 18 | | ForStepNode of node * node * node * node 19 | | Call of node * node list 20 | | Catch of node * node 21 | | Continue of string 22 | | Delete of node 23 | | If of node * node * node option * bool 24 | | IndexAccess of node * node 25 | | In of node * node 26 | | InstanceOf of node * node 27 | | Logical of node * node* ExpressionType 28 | | MemberAccess of string * node 29 | | New of node * node list * node list option 30 | | NewArray of node * node list 31 | | Null 32 | | PostfixOperator of node * ExpressionType 33 | | Regex of string * string 34 | | Return of node 35 | | StrictCompare of node * node * ExpressionType 36 | | Switch of node * node * (node * node) list * string 37 | | String of string * char 38 | | Throw of node 39 | | Try of node * node option * node option 40 | | TypeOf of node 41 | | UnaryOp of node * ExpressionType 42 | | UnsignedRightShift of node * node 43 | | Void of node 44 | | While of node * node * bool 45 | | With of node * node 46 | | Ignore 47 | -------------------------------------------------------------------------------- /JavascriptParser/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("JavascriptParser")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Microsoft")] 12 | [assembly: AssemblyProduct("JavascriptParser")] 13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2010")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("5ef00346-b3eb-4ce5-938d-9e721bda6f85")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /JavascriptParser/ES3Parser-and-ES3Lexer-LICENSE.txt: -------------------------------------------------------------------------------- 1 | Software License Agreement (BSD License) 2 | 3 | Copyright (c) 2008-2009, Xebic Research B.V. 4 | All rights reserved. 5 | 6 | Redistribution and use of this software in source and binary forms, with or without modification, are 7 | permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above 10 | copyright notice, this list of conditions and the 11 | following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above 14 | copyright notice, this list of conditions and the 15 | following disclaimer in the documentation and/or other 16 | materials provided with the distribution. 17 | 18 | * Neither the name of Xebic Research B.V. nor the names of its 19 | contributors may be used to endorse or promote products 20 | derived from this software without specific prior 21 | written permission of Xebic Research B.V. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 24 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 25 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 26 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 29 | TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 30 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /FSharp.Javascript.Tests/TestHelper.fs: -------------------------------------------------------------------------------- 1 | #light 2 | module TestHelper 3 | 4 | open FSharp.Javascript.Printer 5 | open FSharp.Javascript.Parser 6 | open NUnit.Framework 7 | 8 | 9 | let print input = 10 | System.Console.WriteLine((sprintf "%A" input)) 11 | 12 | let test input = 13 | print "-------------------- input --------------------" 14 | print input 15 | let ast = getAst input 16 | let javascript = getJavascript ast 17 | print "-------------------- first --------------------" 18 | print javascript 19 | let ast2 = getAst javascript 20 | let javascript2 = getJavascript ast2 21 | print "-------------------- second --------------------" 22 | print javascript2 23 | 24 | let result = (ast = ast2) 25 | 26 | //if result = false then 27 | print ast 28 | print ast2 29 | 30 | Assert.IsTrue(result) 31 | 32 | let output value (name:string) = 33 | use file1 = new System.IO.StreamWriter(name) 34 | file1.WriteLine((sprintf "%A" value)) 35 | 36 | let testLibrary input = 37 | let ast = getAst input 38 | let javascript = getJavascript ast 39 | print "-------------------- first --------------------" 40 | print javascript 41 | let ast2 = getAst javascript 42 | let javascript2 = getJavascript ast2 43 | print "-------------------- second --------------------" 44 | print javascript2 45 | 46 | let result = (ast = ast2) 47 | 48 | if result = false then 49 | output ast "ast1.txt" 50 | output ast2 "ast2.txt" 51 | output javascript "javascript1.txt" 52 | output javascript2 "javascript2.txt" 53 | 54 | Assert.IsTrue(result) 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /FSharp.Javascript.Tests/ComputationModule.fs: -------------------------------------------------------------------------------- 1 | module TestNamespace.ComputationModule 2 | 3 | let test (quote:Microsoft.FSharp.Quotations.Expr) = 4 | let typ = System.Type.GetType("TestNamespace.ComputationModule, FSharp.Javascript.Tests") 5 | QuotationsTestHelper.testWithType [typ] quote 6 | 7 | type MaybeBuilder() = 8 | [] 9 | member this.Bind(x,f) = 10 | match x with 11 | | Some(t) when t >= 0 && t <= 100 -> f(t) 12 | | _ -> None 13 | [] 14 | member this.Delay(f) = f() 15 | [] 16 | member this.Return(x) = Some x 17 | 18 | [] 19 | let maybe = new MaybeBuilder() 20 | 21 | 22 | [] 23 | let print() = System.Console.WriteLine("got here two") 24 | 25 | [] 26 | print() 27 | 28 | 29 | (*State Monad*) 30 | type State<'a, 'state> = State of ('state -> 'a * 'state) 31 | 32 | type StateBuilder() = 33 | [] 34 | member x.YieldFrom m = m 35 | [] 36 | member x.ReturnFrom m = m 37 | [] 38 | member x.Return a = State(fun s -> a, s) 39 | [] 40 | member x.Bind(m, f) = State (fun s -> let v, s2 = let (State f_) = m in f_ s 41 | let (State f2) = f v in f2 s2) 42 | [] 43 | member x.Zero() = x.Return(()) 44 | 45 | [] 46 | let state = new StateBuilder() 47 | [] 48 | let getState = State(fun s -> s, s) 49 | [] 50 | let setState s = State(fun _ -> (), s) 51 | [] 52 | let executeState m s = let (State f) = m in f s 53 | 54 | [] 55 | let addInt t = state { 56 | let! a = state { return t::[] } 57 | return a 58 | } 59 | 60 | type node = 61 | | Directory of string * node list 62 | | File of string -------------------------------------------------------------------------------- /FSharp.Javascript.Utilities/Compiler.fs: -------------------------------------------------------------------------------- 1 | module FSharp.Javascript.Compiler 2 | 3 | open System 4 | open System.IO 5 | open System.Linq 6 | open System.CodeDom.Compiler 7 | open Microsoft.FSharp.Compiler.CodeDom 8 | open System.Reflection 9 | 10 | let CompileFSharpString(str, assemblies, output) = 11 | use pro = new FSharpCodeProvider() 12 | let opt = CompilerParameters() 13 | opt.OutputAssembly <- output 14 | opt.CompilerOptions <- [for a in assemblies do yield "-r:\"" + a + "\""] |> String.concat " " 15 | let res = pro.CompileAssemblyFromSource( opt, [|str|] ) 16 | let errors = [for a in res.Errors -> a] 17 | if errors.Length = 0 then 18 | (errors, Some(FileInfo(res.PathToAssembly))) 19 | else (errors, None) 20 | 21 | let (++) v1 v2 = Path.Combine(v1, v2) 22 | let assemblyDirectory = Path.GetDirectoryName(Assembly.GetCallingAssembly().CodeBase).Remove(0, 6) 23 | let defaultAsms() = [|(assemblyDirectory ++ "FSharp.Javascript.dll")|] 24 | let randomFile directory = directory ++ Path.GetRandomFileName() + ".dll" 25 | 26 | type System.CodeDom.Compiler.CodeCompiler with 27 | static member CompileFSharpString (str, directory, ?assemblies, ?output) = 28 | let assemblies = defaultArg assemblies (defaultAsms()) 29 | let output = defaultArg output (randomFile directory) 30 | CompileFSharpString(str, assemblies, output) 31 | 32 | let compile (input:string) (directory:string) = 33 | let result = CodeCompiler.CompileFSharpString(input, directory) 34 | let errors = fst result 35 | let fileInfo = snd result 36 | if fileInfo.IsSome then 37 | let assemData = File.ReadAllBytes(fileInfo.Value.FullName) 38 | let assem = Assembly.Load(assemData) 39 | let moduleType = assem.GetExportedTypes().[0] 40 | let ast = FSharp.Javascript.ModuleCompiler.getAstFromType moduleType 41 | let javascript = FSharp.Javascript.Printer.getJavascript ast 42 | 43 | File.Delete(fileInfo.Value.FullName) 44 | (errors, Some(javascript)) 45 | else 46 | (errors, None) -------------------------------------------------------------------------------- /FSharp.Javascript.Tests/TestModule.fs: -------------------------------------------------------------------------------- 1 | module TestModule 2 | 3 | let test (quote:Microsoft.FSharp.Quotations.Expr) = 4 | let typ = System.Type.GetType "TestModule, FSharp.Javascript.Tests" 5 | 6 | //let typ2 = System.Type.GetType "FSharp.Javascript.Library, FSharp.Javascript" 7 | QuotationsTestHelper.testWithType [typ] quote 8 | 9 | 10 | type record = { x:int; y:int; } 11 | 12 | type first = { 13 | Prop1 : int; 14 | Prop2 : string; 15 | } 16 | with 17 | [] 18 | member this.GetProp1() = this.Prop1 19 | [] 20 | member this.GetProp2(x) = this.Prop2 + x 21 | 22 | [] 23 | member this.MultipleArgsOnRecord(a,b) = a - b 24 | 25 | type recordWithArrayOfTuples = { 26 | url : string; 27 | arguments : (string * string) array; 28 | } 29 | 30 | type class1(name) = 31 | member this.Name = name 32 | [] 33 | member this.GetName() = this.Name 34 | 35 | 36 | type class2(name, id) = 37 | inherit class1(name) 38 | 39 | let mutable age = 0 40 | 41 | member this.Id = id 42 | member this.Age 43 | with get() = age 44 | and set(value) = age <- value 45 | 46 | [] 47 | let getProp1 (x:first) = x.Prop1 48 | 49 | [] 50 | let testFunction x = x 51 | 52 | [] 53 | type System.Object with 54 | [] 55 | member x.GetValue() = x 56 | 57 | type union = 58 | | First of int 59 | | Second of string 60 | | Third of bool 61 | | Fourth of int * int 62 | 63 | type simpleUnion = 64 | | One 65 | | Two 66 | 67 | [] 68 | let (|TestPattern|_|) input = 69 | match input with 70 | | Some(a) -> Some(a) 71 | | _ -> None 72 | 73 | [] 74 | let (|NullCheckPattern|_|) x = 75 | match x with 76 | | null -> None 77 | | _ -> Some(x) 78 | 79 | [] 80 | let unitResult (x:int) = () 81 | 82 | [] 83 | let (><) a b = a = b 84 | 85 | [] 86 | let multipleArgs a b = a - b 87 | 88 | [] 89 | let tupledArgs (a,b) (c,d) = a + b + c + d 90 | 91 | [] 92 | let mixedTupledArgs a (c,d) = a + c + d 93 | 94 | type Color = 95 | | Red = 0 96 | | Green = 1 97 | | Blue = 2 -------------------------------------------------------------------------------- /FSharp.Javascript/Library.fs: -------------------------------------------------------------------------------- 1 | module FSharp.Javascript.Library 2 | 3 | open System 4 | 5 | type System.DateTime with 6 | static member TryParse2(x:string) = 7 | try 8 | let date = DateTime.Parse(x) 9 | if date = DateTime.MinValue then 10 | None 11 | else 12 | Some(date) 13 | with 14 | | _ -> None 15 | 16 | type System.Int16 with 17 | static member TryParse2(x:string) = 18 | try 19 | let success,result = Int16.TryParse(x) 20 | if success then Some result else None 21 | with 22 | | _ -> None 23 | 24 | type System.Int32 with 25 | static member TryParse2(x:string) = 26 | try 27 | let success,result = Int32.TryParse(x) 28 | if success then Some result else None 29 | with 30 | | _ -> None 31 | 32 | type System.Int64 with 33 | static member TryParse2(x:string) = 34 | try 35 | let success,result = Int64.TryParse(x) 36 | if success then Some result else None 37 | with 38 | | _ -> None 39 | 40 | type System.Decimal with 41 | static member TryParse2(x:string) = 42 | try 43 | let success,result = Decimal.TryParse(x) 44 | if success then Some result else None 45 | with 46 | | _ -> None 47 | 48 | type System.Double with 49 | static member TryParse2(x:string) = 50 | try 51 | let success,result = Double.TryParse(x) 52 | if success then Some result else None 53 | with 54 | | _ -> None 55 | 56 | type System.Single with 57 | static member TryParse2(x:string) = 58 | try 59 | let success,result = Single.TryParse(x) 60 | if success then Some result else None 61 | with 62 | | _ -> None 63 | 64 | type System.Boolean with 65 | static member TryParse2(x:string) = 66 | try 67 | let success,result = Boolean.TryParse(x) 68 | if success then Some result else None 69 | with 70 | | _ -> None 71 | 72 | type JObject() = 73 | let dict = System.Collections.Hashtable() 74 | 75 | member this.Item 76 | with get(i:string) = dict.[i] 77 | and set (i:string) (v:obj) = dict.[i] <- v 78 | 79 | let (?) (this : JObject) (prop : string) = 80 | this.[prop] 81 | 82 | let (?<-) (this : JObject) (property : string) (value : 'Value) = 83 | this.[property] <- value -------------------------------------------------------------------------------- /FSharp.Javascript.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharp.Javascript", "FSharp.Javascript\FSharp.Javascript.fsproj", "{0A58C3B4-4A3D-4DAD-83F7-25016D5B8E36}" 5 | EndProject 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JavascriptParser", "JavascriptParser\JavascriptParser.csproj", "{97EC1A08-1BE8-477C-B45C-2ACF12D2EF1E}" 7 | EndProject 8 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharp.Javascript.Tests", "FSharp.Javascript.Tests\FSharp.Javascript.Tests.fsproj", "{7425F8F3-808D-4308-BC97-73A2C87029D3}" 9 | EndProject 10 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharp.Javascript.Utilities", "FSharp.Javascript.Utilities\FSharp.Javascript.Utilities.fsproj", "{B8D2A6C5-4197-44C7-B2FB-C7D52FA41D20}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Release|Any CPU = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {0A58C3B4-4A3D-4DAD-83F7-25016D5B8E36}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {0A58C3B4-4A3D-4DAD-83F7-25016D5B8E36}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {0A58C3B4-4A3D-4DAD-83F7-25016D5B8E36}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {0A58C3B4-4A3D-4DAD-83F7-25016D5B8E36}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {97EC1A08-1BE8-477C-B45C-2ACF12D2EF1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {97EC1A08-1BE8-477C-B45C-2ACF12D2EF1E}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {97EC1A08-1BE8-477C-B45C-2ACF12D2EF1E}.Release|Any CPU.ActiveCfg = Debug|Any CPU 25 | {97EC1A08-1BE8-477C-B45C-2ACF12D2EF1E}.Release|Any CPU.Build.0 = Debug|Any CPU 26 | {7425F8F3-808D-4308-BC97-73A2C87029D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {7425F8F3-808D-4308-BC97-73A2C87029D3}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {7425F8F3-808D-4308-BC97-73A2C87029D3}.Release|Any CPU.ActiveCfg = Debug|Any CPU 29 | {7425F8F3-808D-4308-BC97-73A2C87029D3}.Release|Any CPU.Build.0 = Debug|Any CPU 30 | {B8D2A6C5-4197-44C7-B2FB-C7D52FA41D20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 31 | {B8D2A6C5-4197-44C7-B2FB-C7D52FA41D20}.Debug|Any CPU.Build.0 = Debug|Any CPU 32 | {B8D2A6C5-4197-44C7-B2FB-C7D52FA41D20}.Release|Any CPU.ActiveCfg = Debug|Any CPU 33 | {B8D2A6C5-4197-44C7-B2FB-C7D52FA41D20}.Release|Any CPU.Build.0 = Debug|Any CPU 34 | EndGlobalSection 35 | GlobalSection(SolutionProperties) = preSolution 36 | HideSolutionNode = FALSE 37 | EndGlobalSection 38 | EndGlobal 39 | -------------------------------------------------------------------------------- /FSharp.Javascript.Tests/ComputationExpressionTests.fs: -------------------------------------------------------------------------------- 1 | namespace FSharp.Javascript.Tests 2 | 3 | open NUnit.Framework 4 | open FSharp.Javascript.Printer 5 | open TestNamespace.ComputationModule 6 | open QuotationsTestHelper 7 | 8 | [] 9 | type ComputationExpressionTests() = 10 | 11 | [] 12 | member this.``Maybe Builder``() = 13 | test <@ let result = maybe { 14 | let! z = Some 30 15 | return z 16 | } 17 | emit (result.Value) @> 18 | 19 | [] 20 | member this.``State Monad``() = 21 | test <@ let (list,state) = executeState (addInt 1) [] 22 | emit ((list).[0]) @> 23 | 24 | [] 25 | member this.``State Monad with two elements``() = 26 | test <@ let myState = state { 27 | let start = [] : int list 28 | let! x = state { return 1::start } 29 | let! b = state { return 2::x } 30 | return b 31 | } 32 | let (list,_) = executeState myState [] 33 | emit ((list).[0] + (list).[1]) @> 34 | 35 | [] 36 | member this.``Sequence expression test1`` () = 37 | test <@ let tree = Directory("home", [File "test.jpg"; Directory("documents", [])]) 38 | 39 | let rec getDirectoryNames x = seq { 40 | match x with 41 | | Directory(name, children) -> 42 | yield name 43 | for c in children do yield! getDirectoryNames c 44 | | File n -> () 45 | } 46 | 47 | let directories = getDirectoryNames tree 48 | let result = (directories |> Seq.skip 1 |> Seq.head) 49 | emit result 50 | 51 | @> 52 | 53 | [] 54 | member this.``Sequence enumeration twice`` () = 55 | test <@ let tree = Directory("home", [File "test.jpg"; Directory("documents", [])]) 56 | 57 | let rec getDirectoryNames x = seq { 58 | match x with 59 | | Directory(name, children) -> 60 | yield name 61 | for c in children do yield! getDirectoryNames c 62 | | File n -> () 63 | } 64 | 65 | let directories = getDirectoryNames tree 66 | let result1 = directories |> Seq.fold (fun acc next -> acc + next) "" 67 | let result2 = directories |> Seq.fold (fun acc next -> acc + next) "" 68 | let result = result1 + result2 69 | emit result 70 | 71 | @> 72 | 73 | 74 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Microsoft Public License (Ms-PL) 2 | 3 | This license governs use of the accompanying software. If you use the software, you 4 | accept this license. If you do not accept the license, do not use the software. 5 | 6 | 1. Definitions 7 | The terms "reproduce," "reproduction," "derivative works," and "distribution" have the 8 | same meaning here as under U.S. copyright law. 9 | 10 | A "contribution" is the original software, or any additions or changes to the software. 11 | A "contributor" is any person that distributes its contribution under this license. 12 | "Licensed patents" are a contributor's patent claims that read directly on its contribution. 13 | 14 | 2. Grant of Rights 15 | (A) Copyright Grant- Subject to the terms of this license, including the license conditions 16 | and limitations in section 3, each contributor grants you a non-exclusive, worldwide, 17 | royalty-free copyright license to reproduce its contribution, prepare derivative works of 18 | its contribution, and distribute its contribution or any derivative works that you create. 19 | 20 | (B) Patent Grant- Subject to the terms of this license, including the license conditions 21 | and limitations in section 3, each contributor grants you a non-exclusive, worldwide, 22 | royalty-free license under its licensed patents to make, have made, use, sell, offer for 23 | sale, import, and/or otherwise dispose of its contribution in the software or derivative 24 | works of the contribution in the software. 25 | 26 | 3. Conditions and Limitations 27 | (A) No Trademark License- This license does not grant you rights to use any contributors' 28 | name, logo, or trademarks. 29 | 30 | (B) If you bring a patent claim against any contributor over patents that you claim are 31 | infringed by the software, your patent license from such contributor to the 32 | software ends automatically. 33 | 34 | (C) If you distribute any portion of the software, you must retain all copyright, patent, 35 | trademark, and attribution notices that are present in the software. 36 | 37 | (D) If you distribute any portion of the software in source code form, you may do so only 38 | under this license by including a complete copy of this license with your distribution. 39 | If you distribute any portion of the software in compiled or object code form, you may only 40 | do so under a license that complies with this license. 41 | 42 | (E) The software is licensed "as-is." You bear the risk of using it. The contributors give 43 | no express warranties, guarantees or conditions. You may have additional consumer rights 44 | under your local laws which this license cannot change. To the extent permitted under your 45 | local laws, the contributors exclude the implied warranties of merchantability, fitness 46 | for a particular purpose and non-infringement. -------------------------------------------------------------------------------- /JavascriptParser/JavascriptParser.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | {97EC1A08-1BE8-477C-B45C-2ACF12D2EF1E} 9 | Library 10 | Properties 11 | JavascriptParser 12 | JavascriptParser 13 | v4.0 14 | 512 15 | 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | ..\Dependencies\Antlr3.Runtime.dll 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 64 | -------------------------------------------------------------------------------- /FSharp.Javascript.Utilities/FSharp.Javascript.Utilities.fsproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | {b8d2a6c5-4197-44c7-b2fb-c7d52fa41d20} 9 | Library 10 | FSharp.Javascript.Utilities 11 | FSharp.Javascript.Utilities 12 | v4.0 13 | FSharp.Javascript.Utilities 14 | 15 | 16 | true 17 | full 18 | false 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | 3 23 | bin\Debug\FSharp.Javascript.Utilities.XML 24 | 25 | 26 | pdbonly 27 | true 28 | true 29 | bin\Release\ 30 | TRACE 31 | 3 32 | bin\Release\FSharp.Javascript.Utilities.XML 33 | 34 | 35 | 36 | ..\Dependencies\Antlr3.Runtime.dll 37 | 38 | 39 | ..\Dependencies\FSharp.Compiler.CodeDom.dll 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | FSharp.Javascript 54 | {0a58c3b4-4a3d-4dad-83f7-25016d5b8e36} 55 | True 56 | 57 | 58 | JavascriptParser 59 | {97ec1a08-1be8-477c-b45c-2acf12d2ef1e} 60 | True 61 | 62 | 63 | 64 | 65 | 72 | -------------------------------------------------------------------------------- /FSharp.Javascript/FSharp.Javascript.fsproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | {0a58c3b4-4a3d-4dad-83f7-25016d5b8e36} 9 | Library 10 | FSharp.Javascript 11 | FSharp.Javascript 12 | v4.0 13 | FSharp.Javascript 14 | 15 | 16 | 17 | true 18 | full 19 | false 20 | true 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | 3 24 | bin\Debug\FSharp.Javascript.XML 25 | 26 | 27 | pdbonly 28 | true 29 | true 30 | bin\Release\ 31 | TRACE 32 | 3 33 | bin\Release\FSharp.Javascript.XML 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | PreserveNewest 49 | 50 | 51 | PreserveNewest 52 | 53 | 54 | PreserveNewest 55 | 56 | 57 | PreserveNewest 58 | 59 | 60 | PreserveNewest 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 78 | -------------------------------------------------------------------------------- /FSharp.Javascript.Tests/QuotationsTestHelper.fs: -------------------------------------------------------------------------------- 1 | #light 2 | module QuotationsTestHelper 3 | 4 | open System.Text 5 | open FSharp.Javascript.QuotationsConverter 6 | open FSharp.Javascript.ModuleCompiler 7 | open FSharp.Javascript.Printer 8 | open FSharp.Javascript.Ast 9 | open NUnit.Framework 10 | 11 | open Microsoft.FSharp.Quotations 12 | open Microsoft.FSharp.Quotations.ExprShape 13 | open Microsoft.FSharp.Quotations.Patterns 14 | open Microsoft.FSharp.Quotations.DerivedPatterns 15 | open Microsoft.FSharp.Linq 16 | open Microsoft.FSharp.Linq.QuotationEvaluation 17 | 18 | open Microsoft.FSharp.Control 19 | 20 | open System.Diagnostics 21 | open System.IO 22 | 23 | open System.Linq 24 | 25 | open IronJS 26 | 27 | let print input = 28 | System.Console.WriteLine((sprintf "%A" input)) 29 | 30 | //[] 31 | let emit x = x 32 | 33 | 34 | 35 | let getRandomFileName () = System.Guid.NewGuid().ToString() + ".js" 36 | 37 | let run (source:string) = 38 | 39 | let fileName = getRandomFileName () 40 | let filePath = "C:\\cygwin\\home\\nephesh\\" + fileName 41 | File.WriteAllText(filePath, source) 42 | 43 | let info = new ProcessStartInfo("C:\\cygwin\\bin\\bash", "--login -i -c \"node " + fileName + "\"") 44 | info.CreateNoWindow <- true 45 | info.UseShellExecute <- false 46 | info.WindowStyle <- ProcessWindowStyle.Hidden 47 | info.RedirectStandardOutput <- true 48 | 49 | use proc = Process.Start(info) 50 | 51 | let testResult = proc.StandardOutput.ReadLine() 52 | proc.WaitForExit() 53 | 54 | File.Delete(filePath) 55 | 56 | testResult 57 | 58 | //let run (source:string) = 59 | // let emitter = new StringBuilder() 60 | // let func x = emitter.Append(x.ToString()) |> ignore 61 | // let ctx = IronJS.Hosting.FSharp.createContext() 62 | // let env = ctx |> IronJS.Hosting.FSharp.env 63 | // let exitFunc = new System.Action(func) |> Native.Utils.createFunction env (Some(1)) 64 | // (IronJS.Hosting.FSharp.execute source ctx) |> ignore 65 | // emitter.ToString() 66 | 67 | //type mydel = delegate of obj -> StringBuilder 68 | // 69 | //let run (source:string) = 70 | // let emitter = new StringBuilder() 71 | // let func x = emitter.Append(x.ToString()) 72 | // let testDel = new mydel(func) 73 | // let engine = new Jurassic.ScriptEngine() 74 | // engine.SetGlobalFunction("test", testDel) 75 | // engine.Execute(source) 76 | // emitter.ToString() 77 | 78 | //type mydel = delegate of obj -> StringBuilder 79 | // 80 | //let run (source:string) = 81 | // let emitter = new StringBuilder() 82 | // let func x = emitter.Append(x.ToString()) 83 | // let testDel = new mydel(func) 84 | // let engine = new JintEngine() 85 | // engine.SetFunction("emit", testDel).Run(source) |> ignore 86 | // emitter.ToString() 87 | 88 | let testWithType (typs:System.Type list) quote = 89 | let testModule = true 90 | print quote 91 | print "--------------------------------------------------------------" 92 | let ast = convertToAst quote 93 | print ast 94 | print "--------------------------------------------------------------" 95 | let j1 = (getJavascript ast) 96 | 97 | let moduleScript = typs |> List.fold (fun acc next -> (FSharp.Javascript.Converter.convertModule next) + System.Environment.NewLine + acc) "" 98 | 99 | let files = ["FSharp.Javascript.js";"tests.js";"FSharp.Javascript.Library.js"] 100 | 101 | let library = files |> List.fold (fun acc next -> System.IO.File.ReadAllText(next) + System.Environment.NewLine + acc) "" 102 | 103 | //let library = System.IO.File.ReadAllText("fsharp.js") + System.Environment.NewLine + System.IO.File.ReadAllText("tests.js") 104 | let javascript = (library + System.Environment.NewLine + moduleScript + System.Environment.NewLine + System.Environment.NewLine + j1) 105 | print moduleScript 106 | print "--------------------------------------------------------------" 107 | print j1 108 | //print javascript 109 | let quoteResult = quote.EvalUntyped(); 110 | let quoteResultString = if quoteResult = null then "null" else quoteResult.ToString().ToLower() 111 | print ("F# Result: " + quoteResultString) 112 | let javascriptResult = run javascript 113 | 114 | let javascriptResult' = if javascriptResult = null then "null" else javascriptResult.ToString().ToLower() 115 | 116 | let result = (quoteResultString = javascriptResult') 117 | 118 | print System.Environment.NewLine 119 | print ("javascript result: " + javascriptResult') 120 | Assert.IsTrue(result) 121 | -------------------------------------------------------------------------------- /FSharp.Javascript.Tests/DateTimeTests.fs: -------------------------------------------------------------------------------- 1 | namespace FSharp.Javascript.Tests 2 | 3 | open NUnit.Framework 4 | open FSharp.Javascript.Printer 5 | open TestModule 6 | open QuotationsTestHelper 7 | open System 8 | 9 | open FSharp.Javascript.Library 10 | 11 | [] 12 | type DateTimeTests() = 13 | 14 | [] 15 | member this.``Get MinTime``() = 16 | test <@ let date = DateTime.MinValue 17 | emit (date.ToString()) @> 18 | 19 | [] 20 | member this.``Can create specific date time``() = 21 | test <@ let date = new DateTime(2010, 6,12) 22 | emit (date.ToString()) @> 23 | 24 | [] 25 | [] 26 | member this.``Can get current DateTime``() = 27 | test <@ let date = DateTime.Now 28 | emit (date.ToString()) @> 29 | 30 | [] 31 | member this.``Can add years``() = 32 | test <@ let date = new DateTime(2010, 6,12) 33 | let date = date.AddYears(-18) 34 | emit (date.ToString()) @> 35 | 36 | [] 37 | member this.``Can add months``() = 38 | test <@ let date = new DateTime(2010, 6,12) 39 | let date = date.AddMonths(-18) 40 | emit (date.ToString()) @> 41 | 42 | [] 43 | member this.``Can add days``() = 44 | test <@ let date = new DateTime(2010, 6,12) 45 | let date = date.AddDays(float -35) 46 | emit (date.ToString()) @> 47 | 48 | [] 49 | member this.``ToShortDateString works``() = 50 | test <@ let date = new DateTime(2010, 6,12) 51 | emit (date.ToShortDateString()) @> 52 | 53 | [] 54 | member this.``Can Parse Date``() = 55 | test <@ let input = "06/12/1980" 56 | let date = DateTime.Parse(input) 57 | emit (date.ToString()) @> 58 | 59 | [] 60 | member this.``Date greater than works``() = 61 | test <@ let date1 = new DateTime(2010, 6, 12) 62 | let date2 = new DateTime(2010, 7, 12) 63 | let result = date1 > date2 64 | emit result 65 | @> 66 | 67 | [] 68 | member this.``Date less than works``() = 69 | test <@ let date1 = new DateTime(2010, 6, 12) 70 | let date2 = new DateTime(2010, 7, 12) 71 | let result = date1 < date2 72 | emit result 73 | @> 74 | 75 | [] 76 | member this.``Date greater than equal works``() = 77 | test <@ let date1 = new DateTime(2010, 6, 12, 4, 40, 33) 78 | let date2 = new DateTime(2010, 7, 12, 2, 20, 10) 79 | let result = date1 >= date2 80 | emit result 81 | @> 82 | 83 | [] 84 | member this.``Date less than equal works``() = 85 | test <@ let date1 = new DateTime(2010, 6, 12, 4, 40, 33) 86 | let date2 = new DateTime(2010, 7, 12, 2, 20, 10) 87 | let result = date1 <= date2 88 | emit result 89 | @> 90 | 91 | [] 92 | member this.``Date equals works``() = 93 | test <@ let date1 = new DateTime(2010, 6, 12) 94 | let date2 = new DateTime(2010, 7, 12) 95 | let result = date1 = date2 96 | emit result 97 | @> 98 | 99 | [] 100 | member this.``Date not equals works``() = 101 | test <@ let date1 = new DateTime(2010, 6, 12) 102 | let date2 = new DateTime(2010, 7, 12) 103 | let result = date1 <> date2 104 | emit result 105 | @> 106 | 107 | [] 108 | member this.``TryParse2 works``() = 109 | test <@ let input = "06/12/1980" 110 | let date = DateTime.TryParse2(input) 111 | emit date.IsSome 112 | @> 113 | 114 | [] 115 | member this.``Date equals Now - 18 years``() = 116 | test <@ let date = DateTime.Parse("06/12/2005") 117 | if date >= DateTime.Now.AddYears(-18) then 118 | emit "You must be eighteen years or older." 119 | else 120 | emit "You are older than 18 years" @> 121 | 122 | [] 123 | member this.``TryParse2 with invalid data returns None``() = 124 | test <@ let input = "asfd" 125 | let date = DateTime.TryParse2(input) 126 | emit date.IsSome @> -------------------------------------------------------------------------------- /FSharp.Javascript/FSharp.Javascript.Library.js: -------------------------------------------------------------------------------- 1 | registerNamespace('FSharp.Javascript') 2 | 3 | 4 | FSharp.Javascript.Library = { 5 | IsNumber: function (n) { 6 | return !isNaN(parseFloat(n)) && isFinite(n); 7 | }, 8 | 9 | DateTime: { 10 | TryParse2: { 11 | Static: function (x) { 12 | try { 13 | var d = new Date(x) 14 | if (d == null || isNaN(d.getYear())) { 15 | return new Microsoft.FSharp.Core.FSharpOption.None(); 16 | } 17 | 18 | 19 | var dateTime = new System.DateTime(d.getFullYear(), d.getMonth() + 1, d.getDate(), d.getHours(), d.getMinutes(), d.getSeconds()) 20 | return new Microsoft.FSharp.Core.FSharpOption.Some(dateTime); 21 | } 22 | catch (err) { 23 | return new Microsoft.FSharp.Core.FSharpOption.None(); 24 | } 25 | } 26 | } 27 | }, 28 | 29 | Int32: { 30 | TryParse2: { 31 | Static: function (x) { 32 | 33 | if (FSharp.Javascript.Library.IsNumber(x) == false) 34 | return new Microsoft.FSharp.Core.FSharpOption.None(); 35 | 36 | var value = new System.Int32(x) 37 | return new Microsoft.FSharp.Core.FSharpOption.Some(value); 38 | } 39 | } 40 | }, 41 | 42 | Int16: { 43 | TryParse2: { 44 | Static: function (x) { 45 | if (FSharp.Javascript.Library.IsNumber(x) == false) 46 | return new Microsoft.FSharp.Core.FSharpOption.None(); 47 | 48 | var value = new System.Int32(x) 49 | return new Microsoft.FSharp.Core.FSharpOption.Some(value); 50 | } 51 | } 52 | }, 53 | 54 | Int64: { 55 | TryParse2: { 56 | Static: function (x) { 57 | if (FSharp.Javascript.Library.IsNumber(x) == false) 58 | return new Microsoft.FSharp.Core.FSharpOption.None(); 59 | 60 | var value = new System.Int32(x) 61 | return new Microsoft.FSharp.Core.FSharpOption.Some(value); 62 | } 63 | } 64 | }, 65 | 66 | Decimal: { 67 | TryParse2: { 68 | Static: function (x) { 69 | if (FSharp.Javascript.Library.IsNumber(x) == false) 70 | return new Microsoft.FSharp.Core.FSharpOption.None(); 71 | 72 | var value = parseFloat(x) 73 | return new Microsoft.FSharp.Core.FSharpOption.Some(value); 74 | } 75 | } 76 | }, 77 | 78 | Double: { 79 | TryParse2: { 80 | Static: function (x) { 81 | if (FSharp.Javascript.Library.IsNumber(x) == false) 82 | return new Microsoft.FSharp.Core.FSharpOption.None(); 83 | 84 | var value = parseFloat(x) 85 | return new Microsoft.FSharp.Core.FSharpOption.Some(value); 86 | } 87 | } 88 | }, 89 | 90 | Single: { 91 | TryParse2: { 92 | Static: function (x) { 93 | if (FSharp.Javascript.Library.IsNumber(x) == false) 94 | return new Microsoft.FSharp.Core.FSharpOption.None(); 95 | 96 | var value = parseFloat(x) 97 | return new Microsoft.FSharp.Core.FSharpOption.Some(value); 98 | } 99 | } 100 | }, 101 | 102 | Boolean: { 103 | TryParse2: { 104 | Static: function (x) { 105 | try { 106 | var value = x == "true" 107 | var value2 = x == "false" 108 | if (value) { 109 | return new Microsoft.FSharp.Core.FSharpOption.Some(true); 110 | } 111 | else if (value2) { 112 | return new Microsoft.FSharp.Core.FSharpOption.Some(false); 113 | } 114 | else { 115 | return new Microsoft.FSharp.Core.FSharpOption.None(); 116 | } 117 | } catch (err) { 118 | return new Microsoft.FSharp.Core.FSharpOption.None(); 119 | } 120 | } 121 | } 122 | }, 123 | 124 | JObject : function(){ 125 | 126 | }, 127 | 128 | op_Dynamic: function (obj) { 129 | return function (name) { 130 | return obj[name] 131 | } 132 | }, 133 | 134 | op_DynamicAssignment: function (obj) { 135 | return function (name) { 136 | return function (value) { 137 | obj[name] = value; 138 | } 139 | } 140 | } 141 | } -------------------------------------------------------------------------------- /FSharp.Javascript.Tests/FSharp.Javascript.Tests.fsproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | {7425f8f3-808d-4308-bc97-73a2c87029d3} 9 | Library 10 | FSharp.Javascript.Tests 11 | FSharp.Javascript.Tests 12 | v4.0 13 | FSharp.Javascript.Tests 14 | 15 | 16 | true 17 | full 18 | false 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | 3 23 | bin\Debug\FSharp.Javascript.Tests.XML 24 | 25 | 26 | pdbonly 27 | true 28 | true 29 | bin\Release\ 30 | TRACE 31 | 3 32 | bin\Release\FSharp.Javascript.Tests.XML 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | PreserveNewest 47 | 48 | 49 | PreserveNewest 50 | 51 | 52 | PreserveNewest 53 | 54 | 55 | PreserveNewest 56 | 57 | 58 | PreserveNewest 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | ..\Dependencies\FSharp.PowerPack.Linq.dll 70 | 71 | 72 | ..\Dependencies\IronJS.dll 73 | 74 | 75 | 76 | 77 | ..\Dependencies\nunit.framework.dll 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | FSharp.Javascript.Utilities 86 | {b8d2a6c5-4197-44c7-b2fb-c7d52fa41d20} 87 | True 88 | 89 | 90 | FSharp.Javascript 91 | {0a58c3b4-4a3d-4dad-83f7-25016d5b8e36} 92 | True 93 | 94 | 95 | 102 | -------------------------------------------------------------------------------- /JavascriptParser/ES3Parser.Action.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Text.RegularExpressions; 5 | 6 | using Antlr.Runtime; 7 | using Antlr.Runtime.Tree; 8 | 9 | namespace JavascriptParser 10 | { 11 | using IToken = Antlr.Runtime.IToken; 12 | 13 | /// 14 | /// This partial class is complementary to the parser generated with ANTLR from the JavaScript.g grammar. 15 | /// It implements the actions used in the parser. 16 | /// 17 | partial class ES3Parser 18 | { 19 | /// 20 | /// Is a RuleReturnScope node candidate for the left-hand-side of an assignment expression? 21 | /// 22 | /// The RuleReturnScope node 23 | /// The cached result of a former call to this method 24 | /// True if so, false otherwise 25 | public bool IsLeftHandSideAssign(RuleReturnScope lhs, ref bool? cached) 26 | { 27 | if (cached.HasValue) 28 | { 29 | return cached.Value; 30 | } 31 | 32 | bool result; 33 | if (IsLeftHandSideExpression(lhs)) 34 | { 35 | switch (input.LA(1)) 36 | { 37 | case ASSIGN: 38 | case MULASS: 39 | case DIVASS: 40 | case MODASS: 41 | case ADDASS: 42 | case SUBASS: 43 | case SHLASS: 44 | case SHRASS: 45 | case SHUASS: 46 | case ANDASS: 47 | case XORASS: 48 | case ORASS: 49 | result = true; 50 | break; 51 | 52 | default: 53 | result = false; 54 | break; 55 | } 56 | } 57 | else 58 | { 59 | result = false; 60 | } 61 | 62 | cached = result; 63 | return result; 64 | } 65 | 66 | /// 67 | /// Is a RuleReturnScope node candidate a left-hand-side expression? 68 | /// 69 | /// The RuleReturnScope node 70 | /// True if so, false otherwise 71 | private bool IsLeftHandSideExpression(RuleReturnScope lhs) 72 | { 73 | if (lhs.Tree == null) // e.g. during backtracking 74 | { 75 | return true; 76 | } 77 | else 78 | { 79 | switch (((ITree)lhs.Tree).Type) 80 | { 81 | // primaryExpression 82 | case THIS: 83 | case Identifier: 84 | case NULL: 85 | case TRUE: 86 | case FALSE: 87 | case DecimalLiteral: 88 | case OctalIntegerLiteral: 89 | case HexIntegerLiteral: 90 | case StringLiteral: 91 | case RegularExpressionLiteral: 92 | case ARRAY: 93 | case OBJECT: 94 | case PAREXPR: 95 | // functionExpression 96 | case FUNCTION: 97 | // newExpression 98 | case NEW: 99 | // leftHandSideExpression 100 | case CALL: 101 | case BYFIELD: 102 | case BYINDEX: 103 | return true; 104 | 105 | default: 106 | return false; 107 | } 108 | } 109 | } 110 | 111 | /// 112 | /// Is a RuleReturnScope node candidate for the left-hand-side of an in expression? 113 | /// 114 | /// The RuleReturnScope node 115 | /// The cached result of a former call to this method 116 | /// True if so, false otherwise 117 | public bool IsLeftHandSideIn(RuleReturnScope lhs, ref bool? cached) 118 | { 119 | if (cached.HasValue) 120 | { 121 | return cached.Value; 122 | } 123 | 124 | bool result = IsLeftHandSideExpression(lhs) && (input.LA(1) == IN); 125 | 126 | cached = result; 127 | return result; 128 | } 129 | 130 | /// 131 | /// This method handles promotion of an EOL token to on channel in situations where the ECMA 3 specification 132 | /// states there should be a semicolon inserted because of an EOL between the current (offending) token 133 | /// and the previous token. 134 | /// So an semicolon is not actually inserted but the EOL present is switched from off to on channel. In this 135 | /// way that EOL gets the notion of an "virtual" semicolon. 136 | /// As a side effect a given rule's return scope starting point is set to the found EOL and the input stream is repositioned on it. 137 | /// A multi line comment with an EOL is also promoted. 138 | /// 139 | /// The invoking rule's return scope 140 | public void PromoteEOL(ParserRuleReturnScope rule) 141 | { 142 | // Get current token and its type (the possibly offending token). 143 | IToken lt = input.LT(1); 144 | int la = lt.Type; 145 | 146 | // We only need to promote an EOL when the current token is offending (not a SEMIC, EOF, RBRACE or EOL). 147 | // Promoting an EOL means switching it from off channel to on channel. 148 | if (!(la == SEMIC || la == EOF || la == RBRACE || la == EOL)) 149 | { 150 | // Start on the possition before the current token and scan backwards off channel tokens until the previous on channel token. 151 | for (int ix = lt.TokenIndex - 1; ix > 0; ix--) 152 | { 153 | lt = input.Get(ix); 154 | if (lt.Channel == Token.DEFAULT_CHANNEL) 155 | { 156 | // On channel token found: stop scanning. 157 | break; 158 | } 159 | else if (lt.Type == EOL || (lt.Type == MultiLineComment && Regex.IsMatch(lt.Text, "/.*\r\n|\r|\n"))) 160 | { 161 | // We found our EOL: promote it to on channel, position the input on it and reset the rule start. 162 | lt.Channel = Token.DEFAULT_CHANNEL; 163 | input.Seek(lt.TokenIndex); 164 | if (rule != null) 165 | { 166 | rule.Start = lt; 167 | } 168 | break; 169 | } 170 | } 171 | } 172 | } 173 | } 174 | } -------------------------------------------------------------------------------- /JavascriptParser/ES3Lexer.Action.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.Text; 5 | 6 | using Antlr.Runtime; 7 | 8 | namespace JavascriptParser 9 | { 10 | using IToken = Antlr.Runtime.IToken; 11 | 12 | /// 13 | /// This partial class is complementary to the lexer generated with ANTLR from the JavaScript.g grammar. 14 | /// It implements the actions used in the lexer. 15 | /// 16 | partial class ES3Lexer 17 | { 18 | /// 19 | /// Containts the last on channel token. 20 | /// 21 | protected IToken last; 22 | 23 | /// 24 | /// Indicates whether regular expression (yields true) or division expression recognition (false) in the lexer is enabled. 25 | /// These are mutual exclusive and the decision which is active in the lexer is based on the previous on channel token. 26 | /// When the previous token can be identified as a possible left operand for a division this results in false, otherwise true. 27 | /// 28 | private bool AreRegularExpressionsEnabled 29 | { 30 | get 31 | { 32 | if (last == null) 33 | { 34 | return true; 35 | } 36 | 37 | switch (last.Type) 38 | { 39 | // identifier 40 | case Identifier: 41 | // literals 42 | case NULL: 43 | case TRUE: 44 | case FALSE: 45 | case THIS: 46 | case OctalIntegerLiteral: 47 | case DecimalLiteral: 48 | case HexIntegerLiteral: 49 | case StringLiteral: 50 | // member access ending 51 | case RBRACK: 52 | // function call or nested expression ending 53 | case RPAREN: 54 | return false; 55 | 56 | // otherwise OK 57 | default: 58 | return true; 59 | } 60 | } 61 | } 62 | 63 | /// 64 | /// Consumes an unicode identifier after validating that the first character can be the starting character. 65 | /// This method is called by the lexer logic as fallback alternative when a character can not be considered as start of an identifier in the ASCII range. 66 | /// See the Identfier lexer rule for more details. 67 | /// 68 | private void ConsumeIdentifierUnicodeStart() 69 | { 70 | int ch = (char)input.LA(1); 71 | if (IsIdentifierStartUnicode(ch)) 72 | { 73 | MatchAny(); 74 | do 75 | { 76 | ch = (char)input.LA(1); 77 | if (ch == '$' || (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || ch == '\\' || ch == '_' || (ch >= 'a' && ch <= 'z') || IsIdentifierPartUnicode(ch)) 78 | { 79 | mIdentifierPart(); 80 | } 81 | else 82 | { 83 | return; 84 | } 85 | } 86 | while (true); 87 | } 88 | else 89 | { 90 | throw new NoViableAltException(); 91 | } 92 | } 93 | 94 | /// 95 | /// Indicates whether a given character can be a part of an unicode identifier. 96 | /// This method doesn't consider ASCII characters that can be a part of an identifier, that is left to the mIdentifierPart method. 97 | /// The latter method will call this method to check other characters in the unicode range after evaluating those in the ASCII range. 98 | /// 99 | /// The character to check. 100 | /// True when the character matches, false otherwise. 101 | public static bool IsIdentifierPartUnicode(int ch) 102 | { 103 | switch (Char.GetUnicodeCategory((char)ch)) 104 | { 105 | // UnicodeLetter 106 | case UnicodeCategory.UppercaseLetter: // Lu 107 | case UnicodeCategory.LowercaseLetter: // Ll 108 | case UnicodeCategory.TitlecaseLetter: // Lt 109 | case UnicodeCategory.ModifierLetter: // Lm 110 | case UnicodeCategory.OtherLetter: // Lo 111 | case UnicodeCategory.LetterNumber: // Nl 112 | // UnicodeCombiningMark 113 | case UnicodeCategory.NonSpacingMark: // Mn 114 | case UnicodeCategory.SpacingCombiningMark: // Mc 115 | // UnicodeDigit 116 | case UnicodeCategory.DecimalDigitNumber: // Nd 117 | // UnicodeConnectorPuntuation 118 | case UnicodeCategory.ConnectorPunctuation: // Pc 119 | return true; 120 | 121 | // Not matching 122 | default: 123 | return false; 124 | } 125 | } 126 | 127 | /// 128 | /// Indicates whether a given character can be the first character of an unicode identifier. 129 | /// This method doesn't consider ASCII characters as it is used in a fallback scenario after the ASCII range is evaluated. 130 | /// 131 | /// The character to check. 132 | /// True when the character matches, false otherwise. 133 | public static bool IsIdentifierStartUnicode(int ch) 134 | { 135 | switch (Char.GetUnicodeCategory((char)ch)) 136 | { 137 | // UnicodeLetter 138 | case UnicodeCategory.UppercaseLetter: // Lu 139 | case UnicodeCategory.LowercaseLetter: // Ll 140 | case UnicodeCategory.TitlecaseLetter: // Lt 141 | case UnicodeCategory.ModifierLetter: // Lm 142 | case UnicodeCategory.OtherLetter: // Lo 143 | case UnicodeCategory.LetterNumber: // Nl 144 | return true; 145 | 146 | // Not matching 147 | default: 148 | return false; 149 | } 150 | } 151 | 152 | /// 153 | /// Override of base to track previous on channel token. 154 | /// This token is needed as input to decide whether regular expression or division expression recognition is enabled. 155 | /// 156 | public override IToken NextToken() 157 | { 158 | IToken result = base.NextToken(); 159 | if (result.Channel == Token.DEFAULT_CHANNEL) 160 | { 161 | last = result; 162 | } 163 | return result; 164 | } 165 | } 166 | } -------------------------------------------------------------------------------- /FSharp.Javascript/Canvas.fs: -------------------------------------------------------------------------------- 1 | module FSharp.Javascript.Canvas 2 | 3 | open FSharp.Javascript.Dom 4 | 5 | type HtmlCanvasElement() = 6 | inherit HtmlElement() 7 | 8 | [] 9 | val mutable width : float 10 | [] 11 | val mutable height : float 12 | 13 | member this.toDataURL() = "" 14 | 15 | member this.getContext(contextId:string) = CanvasRenderingContext2d() 16 | 17 | and Context() = class end 18 | 19 | and CanvasRenderingContext2d() = 20 | inherit Context() 21 | 22 | [] 23 | val mutable canvas : HtmlCanvasElement 24 | [] 25 | val mutable globalAlpha : float 26 | [] 27 | val mutable globalCompositeOperation : string 28 | [] 29 | val mutable strokeStyle : obj 30 | [] 31 | val mutable fillStyle : obj 32 | [] 33 | val mutable lineWidth : float 34 | [] 35 | val mutable lineCap : string 36 | [] 37 | val mutable lineJoin : string 38 | [] 39 | val mutable miterLimit : float 40 | [] 41 | val mutable shadowOffsetX : float 42 | [] 43 | val mutable shadowOffsetY : float 44 | [] 45 | val mutable shadowBlur : float 46 | [] 47 | val mutable shadowColor : string 48 | [] 49 | val mutable font : string 50 | [] 51 | val mutable textAlign : string 52 | [] 53 | val mutable textBaseline : string 54 | 55 | 56 | member this.save() = () 57 | member this.restore() = () 58 | member this.scale(x:float, y:float) = () 59 | member this.rotate(angle:float) = () 60 | member this.translate(x:float, y:float) = () 61 | member this.transform(a:float, b: float, c:float, d:float, e:float, f:float) = () 62 | member this.setTransform(a:float, b: float, c:float, d:float, e:float, f:float) = () 63 | 64 | member this.createLinearGradient(x0:float, y0:float, x1:float, y1:float) = CanvasGradient() 65 | member this.createRadialGradient(x0:float, y0:float, r0:float, x1:float, y1:float, r1:float) = CanvasGradient() 66 | member this.createPattern(image:HtmlImageElement, repitition:string) = CanvasPattern() 67 | member this.createPattern(image:HtmlCanvasElement, repitition:string) = CanvasPattern() 68 | member this.createPattern(image:HtmlVideoElement, repitition:string) = CanvasPattern() 69 | 70 | member this.clearRect(x:float, y:float, w:float, h:float) = () 71 | member this.fillRect(x:float, y:float, w:float, h:float) = () 72 | member this.strokeRect(x:float, y:float, w:float, h:float) = () 73 | 74 | member this.beginPath() = () 75 | member this.closePath() = () 76 | member this.moveTo(x:float, y:float) = () 77 | member this.lineTo(x:float, y:float) = () 78 | member this.quadraticCurveTo(cpx:float, cpy:float, x:float, y:float) = () 79 | member this.bezierCurveTo(cp1x:float, cp1y:float, cp2x:float, cp2y:float, x:float, y:float) = () 80 | member this.arcTo(x1:float, y1:float, x2:float, y2:float, radius:float) = () 81 | member this.rect(x:float, y:float, w:float, h:float) = () 82 | member this.arc(x:float, y:float, radius:float, startAngle:float, endAngle:float) = () 83 | member this.arc(x:float, y:float, radius:float, startAngle:float, endAngle:float, anticlockwise:bool) = () 84 | member this.fill() = () 85 | member this.stroke() = () 86 | member this.clip() = () 87 | member this.isPointInPath(x:float, y:float) = () 88 | member this.drawFocusRing(element:Element, xCaret:float, yCaret:float) = true 89 | member this.drawFocusRing(element:Element, xCaret:float, yCaret:float, canDrawCustom:bool) = true 90 | member this.fillText(text:string, x:float, y:float) = () 91 | member this.fillText(text:string, x:float, y:float, maxWidth:float) = () 92 | member this.strokeText(text:string, x:float, y:float) = () 93 | member this.strokeText(text:string, x:float, y:float, maxWidth:float) = () 94 | member this.measureText(text:string) = TextMetrics() 95 | member this.drawImage(image:HtmlImageElement, dx:float, dy:float) = () 96 | member this.drawImage(image:HtmlImageElement, dx:float, dy:float, dw:float, dh:float) = () 97 | member this.drawImage(image:HtmlImageElement, sx:float, sy:float, sw:float, sh:float, dx:float, dy:float, dw:float, dh:float) = () 98 | 99 | member this.drawImage(image:HtmlCanvasElement, dx:float, dy:float) = () 100 | member this.drawImage(image:HtmlCanvasElement, dx:float, dy:float, dw:float, dh:float) = () 101 | member this.drawImage(image:HtmlCanvasElement, sx:float, sy:float, sw:float, sh:float, dx:float, dy:float, dw:float, dh:float) = () 102 | 103 | member this.drawImage(image:HtmlVideoElement, dx:float, dy:float) = () 104 | member this.drawImage(image:HtmlVideoElement, dx:float, dy:float, dw:float, dh:float) = () 105 | member this.drawImage(image:HtmlVideoElement, sx:float, sy:float, sw:float, sh:float, dx:float, dy:float, dw:float, dh:float) = () 106 | 107 | member this.createImageData(sw:float, sh:float) = ImageData() 108 | member this.createImageData(imagedata:ImageData) = ImageData() 109 | member this.getImageData(sx:float, sy:float, sw:float, sh:float) = ImageData() 110 | member this.putImageData(imagedata:ImageData, dx:float, dy:float, dirtyX:float, dirtyY:float, dirtyWidth:float, dirtyHeight:float) = () 111 | 112 | 113 | and TextMetrics() = 114 | [] 115 | val mutable width : float 116 | 117 | and CanvasGradient() = 118 | member this.addColorStop(offset:float, color:string) = () 119 | 120 | and CanvasPattern() = class end 121 | 122 | and ImageData() = 123 | [] 124 | val mutable width : float 125 | [] 126 | val mutable height : float 127 | [] 128 | val mutable data : float array 129 | 130 | let getCanvasById (id:string) = HtmlCanvasElement() 131 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /FSharp.Javascript.Tests/MapModuleTests.fs: -------------------------------------------------------------------------------- 1 | namespace FSharp.Javascript.Tests 2 | 3 | open NUnit.Framework 4 | open FSharp.Javascript.Printer 5 | open QuotationsTestHelper 6 | 7 | [] 8 | type MapModuleTests() = 9 | let test quote = QuotationsTestHelper.testWithType [] quote 10 | 11 | [] 12 | member this.empty() = 13 | test <@ let map = Map.empty: Map 14 | emit map.Count @> 15 | 16 | [] 17 | member this.index() = 18 | test <@ let map = Map.empty |> Map.add 1 2 19 | emit map.[1] @> 20 | 21 | [] 22 | member this.add() = 23 | test <@ let map = Map.empty |> Map.add 1 2 24 | let result = map |> Map.fold (fun acc key value -> acc + "{" + key.ToString() + " : " + value.ToString() + "}") "" 25 | emit result @> 26 | 27 | [] 28 | member this.filter() = 29 | test <@ let map = [(1,2);(3,4);(5,6)] |> Map.ofList 30 | let filtered = map |> Map.filter(fun key value -> key >= 3) 31 | let result = map |> Map.fold (fun acc key value -> acc + "{" + key.ToString() + " : " + value.ToString() + "}") "" 32 | emit result @> 33 | 34 | [] 35 | member this.ofList() = 36 | test <@ let map = [(1,2);(3,4);(5,6)] |> Map.ofList 37 | let result = map |> Map.fold (fun acc key value -> acc + "{" + key.ToString() + " : " + value.ToString() + "}") "" 38 | emit result @> 39 | 40 | [] 41 | member this.findKey() = 42 | test <@ let map = [(1,2);(3,4);(5,6)] |> Map.ofList 43 | let result = map |> Map.findKey(fun key value -> value > 5) 44 | emit result @> 45 | 46 | [] 47 | member this.foldBack() = 48 | test <@ let map1 = Map.ofList [ (1, "one"); (2, "two"); (3, "three") ] 49 | let result = Map.foldBack (fun key value state -> state + key) map1 0 50 | emit result @> 51 | 52 | [] 53 | member this.forall() = 54 | test <@ let map1 = Map.ofList [ (1, "one"); (2, "two"); (3, "three") ] 55 | let allPositive = Map.forall (fun key value -> key > 0) 56 | let result = allPositive map1 57 | emit result @> 58 | 59 | [] 60 | member this.isEmpty() = 61 | test <@ emit (Map.empty |> Map.isEmpty) @> 62 | 63 | [] 64 | member this.iter() = 65 | test <@ let map = Map.ofList [ (1, "one"); (2, "two"); (3, "three") ] 66 | let result = ref "" 67 | map |> Map.iter (fun key value -> result := (!result) + (key.ToString() + ":" + value.ToString())) 68 | 69 | emit !result @> 70 | 71 | [] 72 | member this.map() = 73 | test <@ let map = Map.ofList [ (1, "one"); (2, "two"); (3, "three") ] 74 | let newMap = map |> Map.map(fun key value -> value.ToUpper()) 75 | let result = newMap |> Map.fold (fun acc key value -> acc + "{" + key.ToString() + " : " + value.ToString() + "}") "" 76 | emit result @> 77 | 78 | [] 79 | member this.partition() = 80 | test <@ let map1 = [ for i in 1..10 -> (i, i*i)] |> Map.ofList 81 | let (mapEven, mapOdd) = Map.partition (fun key value -> key % 2 = 0) map1 82 | let mapEvenResult = mapEven |> Map.fold (fun acc key value -> acc + "{" + key.ToString() + " : " + value.ToString() + "}") "" 83 | let mapOddResult = mapOdd |> Map.fold (fun acc key value -> acc + "{" + key.ToString() + " : " + value.ToString() + "}") "" 84 | let result = mapEvenResult + mapOddResult 85 | emit result @> 86 | 87 | [] 88 | member this.pick() = 89 | test <@ let map1 = [ for i in 1 .. 100 -> (i, 100 - i) ] |> Map.ofList 90 | let result = Map.pick (fun key value -> if key = value then Some(key) else None) map1 91 | emit result @> 92 | 93 | [] 94 | member this.remove() = 95 | test <@ let map1 = [(1,2);(3,4);(5,6);(7,8)] |> Map.ofList 96 | let mapResult = map1 |> Map.remove 3 97 | let result = mapResult |> Map.fold (fun acc key value -> acc + "{" + key.ToString() + " : " + value.ToString() + "}") "" 98 | emit result @> 99 | 100 | [] 101 | member this.toArray() = 102 | test <@ let map1 = [(1,2);(3,4);(5,6);(7,8)] |> Map.ofList 103 | let arr = map1 |> Map.toArray 104 | let result = arr |> Array.fold(fun acc next -> acc + " " + next.ToString()) "" 105 | emit result @> 106 | 107 | [] 108 | member this.toList() = 109 | test <@ let map1 = [(1,2);(3,4);(5,6);(7,8)] |> Map.ofList 110 | let list = map1 |> Map.toList 111 | let result = list |> List.fold(fun acc next -> acc + " " + next.ToString()) "" 112 | emit result @> 113 | 114 | [] 115 | member this.toSeq() = 116 | test <@ let map1 = [(1,2);(3,4);(5,6);(7,8)] |> Map.ofList 117 | let seq1 = map1 |> Map.toSeq 118 | let result = seq1 |> Seq.fold(fun acc next -> acc + " " + next.ToString()) "" 119 | emit result @> 120 | 121 | [] 122 | member this.tryFind() = 123 | test <@ let map1 = [ for i in 1 .. 100 -> (i, i*i) ] |> Map.ofList 124 | let result = Map.tryFind 50 map1 125 | if result.IsSome then 126 | emit result.Value 127 | else emit 0 @> 128 | 129 | [] 130 | member this.tryFindKey() = 131 | test <@ let map1 = [ for i in 1 .. 100 -> (i, i*i) ] |> Map.ofList 132 | let result = Map.tryFindKey (fun key value -> key = value) map1 133 | match result with 134 | | Some key -> emit true 135 | | None -> emit false @> 136 | 137 | [] 138 | member this.tryPick() = 139 | test <@ let map1 = [ for i in 1 .. 100 -> (i, 100 - i) ] |> Map.ofList 140 | let result = Map.tryPick (fun key value -> if key = value then Some(key) else None) map1 141 | match result with 142 | | Some x -> emit true 143 | | None -> emit false @> 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | -------------------------------------------------------------------------------- /Dependencies/IronJS.LICENSE.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 10 | through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. 13 | 14 | "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or 15 | are under common control with that entity. For the purposes of this definition, "control" means (i) the power, 16 | direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) 17 | ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. 18 | 19 | "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. 20 | 21 | "Source" form shall mean the preferred form for making modifications, including but not limited to software source 22 | code, documentation source, and configuration files. 23 | 24 | "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, 25 | including but not limited to compiled object code, generated documentation, and conversions to other media types. 26 | 27 | "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as 28 | indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix 29 | below). 30 | 31 | "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the 32 | Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, 33 | an original work of authorship. For the purposes of this License, Derivative Works shall not include works that 34 | remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. 35 | 36 | "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications 37 | or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in 38 | the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright 39 | owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written 40 | communication sent to the Licensor or its representatives, including but not limited to communication on electronic 41 | mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the 42 | Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously 43 | marked or otherwise designated in writing by the copyright owner as "Not a Contribution." 44 | 45 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been 46 | received by Licensor and subsequently incorporated within the Work. 47 | 48 | 2. Grant of Copyright License. 49 | 50 | Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, 51 | non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, 52 | publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or 53 | Object form. 54 | 55 | 3. Grant of Patent License. 56 | 57 | Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, 58 | non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have 59 | made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those 60 | patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by 61 | combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute 62 | patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work 63 | or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any 64 | patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is 65 | filed. 66 | 67 | 4. Redistribution. 68 | 69 | You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without 70 | modifications, and in Source or Object form, provided that You meet the following conditions: 71 | 72 | 1. You must give any other recipients of the Work or Derivative Works a copy of this License; and 73 | 74 | 2. You must cause any modified files to carry prominent notices stating that You changed the files; and 75 | 76 | 3. You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, 77 | trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to 78 | any part of the Derivative Works; and 79 | 80 | 4. If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You 81 | distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding 82 | those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: 83 | within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if 84 | provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever 85 | such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do 86 | not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, 87 | alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices 88 | cannot be construed as modifying the License. 89 | 90 | You may add Your own copyright statement to Your modifications and may provide additional or different license terms 91 | and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a 92 | whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated 93 | in this License. 94 | 95 | 5. Submission of Contributions. 96 | 97 | Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to 98 | the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. 99 | Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you 100 | may have executed with Licensor regarding such Contributions. 101 | 102 | 6. Trademarks. 103 | 104 | This License does not grant permission to use the trade names, trademarks, service marks, or product names of the 105 | Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing 106 | the content of the NOTICE file. 107 | 108 | 7. Disclaimer of Warranty. 109 | 110 | Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides 111 | its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, 112 | including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS 113 | FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing 114 | the Work and assume any risks associated with Your exercise of permissions under this License. 115 | 116 | 8. Limitation of Liability. 117 | 118 | In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless 119 | required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any 120 | Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential 121 | damages of any character arising as a result of this License or out of the use or inability to use the Work 122 | (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any 123 | and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such 124 | damages. 125 | 126 | 9. Accepting Warranty or Additional Liability. 127 | 128 | While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance 129 | of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, 130 | in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of 131 | any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any 132 | liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or 133 | additional liability. -------------------------------------------------------------------------------- /Dependencies/FSharp.PowerPack.Linq.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | FSharp.PowerPack.Linq 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 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | Convert the quotation expression to LINQ expression trees 59 | 60 | This operation will only succeed for a subset of quotation expressions. 61 | 62 | Exceptions: InvalidArgumentException will be raised if the input expression is 63 | not in the subset that can be converted to a LINQ expression tree 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | Compile the quotation expression by first converting to LINQ expression trees 72 | 73 | Exceptions: InvalidArgumentException will be raised if the input expression is 74 | not in the subset that can be converted to a LINQ expression tree 75 | 76 | 77 | 78 | 79 | Evaluate the quotation expression by first converting to LINQ expression trees 80 | 81 | Exceptions: InvalidArgumentException will be raised if the input expression is 82 | not in the subset that can be converted to a LINQ expression tree 83 | 84 | 85 | 86 | 87 | Compile the quotation expression by first converting to LINQ expression trees 88 | 89 | Exceptions: InvalidArgumentException will be raised if the input expression is 90 | not in the subset that can be converted to a LINQ expression tree 91 | 92 | 93 | 94 | 95 | Compile the quotation expression by first converting to LINQ expression trees 96 | 97 | Exceptions: InvalidArgumentException will be raised if the input expression is 98 | not in the subset that can be converted to a LINQ expression tree 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | An intrinsic for compiling <c>&lt;@ x <> y @&gt;</c> to expression trees 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | This join operator implements the LINQ GroupJoin operator and the <c>query</c> convertor recognises it as such 115 | 116 | 117 | 118 | 119 | This join operator corresponds to the LINQ Join operator and the <c>query</c> convertor recognises it as such 120 | 121 | 122 | 123 | 124 | When used in queries, this operator corresponds to the LINQ Join operator and the <c>query</c> convertor recognises it as such 125 | 126 | 127 | 128 | 129 | When used in queries, this operator corresponds to the LINQ Max operator and the <c>query</c> convertor recognises it as such 130 | It differs in return type from <c>Seq.maxBy</c> 131 | 132 | 133 | 134 | 135 | When used in queries, this operator corresponds to the LINQ Min operator and the <c>query</c> convertor recognises it as such 136 | It differs in return type from <c>Seq.minBy</c> 137 | 138 | 139 | 140 | 141 | When used in queries, this operator corresponds to the LINQ Contains operator and the <c>query</c> convertor recognises it as such 142 | 143 | 144 | 145 | 146 | Evaluate the quotation expression by first converting to a LINQ expression tree 147 | making use of IQueryable operators and then executing expression tree 148 | 149 | Exceptions: <c>InvalidArgumentException</c> will be raised if the input expression is 150 | not in the subset that can be converted to a LINQ expression tree 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | This function should not be called directly. 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | A set of types used for implementing quotation conversions. 356 | These are public only because targets of Linq Lambda expressions require them to be so 357 | 358 | 359 | 360 | 361 | This module provides Compile and Eval extension members 362 | for F# quotation values, implemented by translating to LINQ 363 | expression trees and using the LINQ dynamic compiler. 364 | 365 | 366 | 367 | 368 | -------------------------------------------------------------------------------- /FSharp.Javascript.Tests/PrintingTests.fs: -------------------------------------------------------------------------------- 1 | #light 2 | namespace FSharp.Javascript.Tests 3 | 4 | open NUnit.Framework 5 | open FSharp.Javascript.Printer 6 | open TestHelper 7 | 8 | [] 9 | type PrintingTests() = 10 | 11 | [] 12 | member this.``Single Assignment With PlusOp``() = 13 | let script = "var a = 1 + 1"; 14 | test script 15 | 16 | [] 17 | member this.``Double Assignment With Plus and Minus Ops``() = 18 | let script = "var a = 1 + 2; 19 | var b = 3 + 4;" 20 | test script 21 | 22 | [] 23 | member this.``Function with multiple statements``() = 24 | let script = "function Name(){ 25 | var a = 1 + 2; 26 | var b = 3 + 4; 27 | }" 28 | test script 29 | 30 | [] 31 | member this.``Function``() = 32 | let script = "var a = function(){ 1 + 1 }" 33 | test script 34 | 35 | [] 36 | member this.``Global Function``() = 37 | test "a = function() { 1 + 1 }" 38 | 39 | [] 40 | member this.``Function with arguments``() = 41 | let script = "var a = function(x,y) { }" 42 | test script 43 | 44 | [] 45 | member this.``BooleanNode``() = 46 | test "var a = true;" 47 | 48 | [] 49 | member this.``Global assign``() = 50 | test "a = true;" 51 | 52 | [] 53 | member this.``Identifier with operations``() = 54 | let script = "var a = 1; 55 | var b = a + 2" 56 | test script 57 | 58 | [] 59 | member this.``ForInNode with body``() = 60 | let script = "for(var i in array){ 61 | 1 + 1 62 | };" 63 | test script 64 | 65 | [] 66 | member this.``ForStepNode with body``() = 67 | let script = "for(var i = 0; i < array.length; i = i + 1){ 68 | 1 + 1 69 | }" 70 | test script 71 | 72 | [] 73 | member this.``ForStepNode with AssignmentBlock``() = 74 | test "for(var i = 0, l = this.length; i] 79 | member this.``Call test with arguments``() = 80 | let script = "var a = function(x,y){ 81 | 82 | } 83 | 84 | var b = a(1,2);" 85 | test script 86 | 87 | [] 88 | member this.``Nested functions``() = 89 | let script = "var a = function(){ 90 | var b = function(){ 91 | 92 | } 93 | }" 94 | test script 95 | 96 | [] 97 | member this.``Call test without arguments``() = 98 | let script = "var a = function(){ 99 | 100 | } 101 | var b = a()" 102 | test script 103 | 104 | [] 105 | member this.``TryCatchFinally``() = 106 | let script = "try{ 107 | 3 + 3 108 | } 109 | catch(ex){ 110 | 2 + 2 111 | } 112 | finally{ 113 | 1 + 1 114 | }" 115 | test script 116 | 117 | [] 118 | member this.``TryCatchFinally inside function``() = 119 | let script = "var a = function(){ 120 | try{ 121 | 3 + 3 122 | } 123 | catch(ex){ 124 | 2 + 2 125 | } 126 | finally{ 127 | 1 + 1 128 | } 129 | }" 130 | test script 131 | 132 | [] 133 | member this.``For loop with continue and break``() = 134 | let script = "for(var i = 0; i < array.length; i = i + 1){ 135 | continue; 136 | break; 137 | }" 138 | test script 139 | 140 | [] 141 | member this.``Delete property``() = 142 | let script = "var a = { b : 1 }; 143 | delete a.b;" 144 | test script 145 | 146 | [] 147 | member this.``New``() = 148 | test "var a = new Object()" 149 | 150 | [] 151 | member this.``New with args``() = 152 | test "var a = new Object(1,2,3)" 153 | 154 | [] 155 | member this.``New with properties inside function``() = 156 | test "var a = function(){ 157 | var b = { c : 1, d : 2, e : function() { 1 + 1 } } 158 | }" 159 | 160 | [] 161 | member this.``IfElse``() = 162 | test "if(true){ 163 | 1 + 1 164 | }else { 165 | 2 + 2 166 | }" 167 | 168 | [] 169 | member this.``If``() = 170 | test "if(true) { 1 + 1 }" 171 | 172 | [] 173 | member this.``IfThen ElseIf Else``() = 174 | test "if(true) { 1 + 1 } else if(false) { 2 + 2 } else { 3 + 3 }" 175 | 176 | [] 177 | member this.``IfThen ElseIf ElseIf Else``() = 178 | test "if(true) { 1 + 1 } else if(false) { 2 + 2 } else if(true) { 3 + 3 } else { 4 + 4 }" 179 | 180 | [] 181 | member this.``TernaryOp``() = 182 | test "true ? 1 : 2" 183 | 184 | [] 185 | member this.``IndexAccess``() = 186 | test "array[0]" 187 | 188 | [] 189 | member this.``Property with IndexAccess``() = 190 | test "a.b[0]" 191 | 192 | [] 193 | member this.``IndexAccess with multi dimensional array``() = 194 | test "array[0,0]" 195 | 196 | [] 197 | member this.``In``() = 198 | test "x in { x : 1 }" 199 | 200 | [] 201 | member this.``InstanceOf``() = 202 | test "'string' instanceof String" 203 | 204 | [] 205 | member this.``Logical Operator``() = 206 | test "1 < 2" 207 | 208 | [] 209 | member this.``Null``() = 210 | test "null" 211 | 212 | [] 213 | member this.``Postfix operators``() = 214 | test "a++" 215 | 216 | [] 217 | member this.``Regex with modifier``() = 218 | test "/t/g" 219 | 220 | [] 221 | member this.``StrictCompare``() = 222 | test "1 !== 1" 223 | 224 | [] 225 | member this.``Switch``() = 226 | test "switch(true){ 227 | case false: 228 | 1 + 1 229 | break; 230 | default: 231 | 2 + 2 232 | }" 233 | [] 234 | member this.``Switch inside function``() = 235 | test "var a = function(){ 236 | switch(true){ 237 | case true: 238 | 3 + 3 239 | case false: 240 | 1 + 1 241 | break; 242 | default: 243 | 2 + 2 244 | } 245 | }" 246 | 247 | [] 248 | member this.``Throw``() = 249 | test "throw 'fail!'" 250 | 251 | [] 252 | member this.``TypeOf``() = 253 | test "typeof a" 254 | 255 | [] 256 | member this.``UnaryOp``() = 257 | test "-a" 258 | 259 | [] 260 | member this.``UnsignedRightShift``() = 261 | test "1 >>> 2" 262 | 263 | [] 264 | member this.``Void``() = 265 | test "void(0)" 266 | 267 | [] 268 | member this.``While loop``() = 269 | test "while(true){ 270 | 1 + 1; 271 | }" 272 | 273 | [] 274 | member this.``DoWhile loop``() = 275 | test "do{ 276 | 1 + 1 277 | } while(true)" 278 | 279 | [] 280 | member this.``With``() = 281 | test "with(a) { 282 | b = 1; 283 | }" 284 | 285 | [] 286 | member this.``Return``() = 287 | test "var a = function(){ 288 | return 1; 289 | }; 290 | 291 | a();" 292 | 293 | [] 294 | member this.``Anonymous function called``() = 295 | test "(function(){ return 1; })();" 296 | 297 | [] 298 | member this.``Empty array``() = 299 | test "var a = []" 300 | 301 | [] 302 | member this.``Array with values``() = 303 | test "var a = [1,2,3,4]" 304 | 305 | [] 306 | member this.``Grouping works properly``() = 307 | test "var a = true && (false || b)" 308 | 309 | [] 310 | member this.``Grouping with functioncall works properly``() = 311 | test "(\" \" + this[i].className + \" \").replace(rclass, \" \")" 312 | 313 | [] 314 | member this.``For statement with null``()= 315 | test "for(null; (i < length); i++){ 316 | 1 + 1 317 | }" 318 | 319 | [] 320 | member this.``array access with PostfixOperator``() = 321 | test "object[++i]" 322 | 323 | [] 324 | member this.``AssignmentBlock with new RegExp``() = 325 | test "var a = 1, namespace = new RegExp(\"(^|\\.)\" + cleaned.join(\"\\.(?:.*\\.)?\") + \"(\\.|$)\")" 326 | 327 | [] 328 | member this.``For loop with global assignment``() = 329 | test "for ( i = 0, l = match.length; i < l; i++ ) { 330 | 1 + 1 331 | }" 332 | 333 | [] 334 | member this.``Global assign multiple``() = 335 | test "(a = 1, b = 2, c =3)" 336 | 337 | [] 338 | member this.``While grouping``() = 339 | test "while ( (chunker.exec(\"\"), m = chunker.exec(soFar)) !== null ) { 340 | 1 + 1 341 | }" 342 | 343 | [] 344 | member this.``PreDecrementOperator with BooleanReversal``() = 345 | test "!--jQuery.active" 346 | 347 | [] 348 | member this.``New Date without constructor``() = 349 | test "var a = (new Date).getTime()" 350 | 351 | [] 352 | member this.``New Date no args``() = 353 | test "var a = new Date().getTime()" 354 | 355 | [] 356 | member this.``New Date with args``() = 357 | test "var a = new Date(1).getTime()" 358 | 359 | [] 360 | member this.``Local assign without value``() = 361 | test "var sortOrder;" 362 | 363 | [] 364 | member this.``Function with name``() = 365 | test "function Name() { }" 366 | 367 | [] 368 | member this.``Function argument with name``() = 369 | test "div.attachEvent(\"onclick\", function click() { 370 | div.detachEvent(\"onclick\", click); 371 | });" 372 | 373 | [] 374 | member this.``Array creation with multiple elements``() = 375 | test "var a = ['one','two','three']" 376 | 377 | [] 378 | member this.``Object method call``() = 379 | test "var a = { SomeMethod : function(){ return 1 + 1; } }; a.SomeMethod();" 380 | 381 | [] 382 | member this.``IndexAccess with parenthesis``() = 383 | test "(opt.specialEasing = opt.specialEasing || {})[p] = prop[p][1];" -------------------------------------------------------------------------------- /FSharp.Javascript.Tests/ListModuleTests.fs: -------------------------------------------------------------------------------- 1 | namespace FSharp.Javascript.Tests 2 | 3 | open NUnit.Framework 4 | open FSharp.Javascript.Printer 5 | open QuotationsTestHelper 6 | 7 | [] 8 | type ListModuleTests() = 9 | let test quote = QuotationsTestHelper.testWithType [] quote 10 | 11 | [] 12 | member this.append() = 13 | test <@ let list1 = [1..5] 14 | let list2 = [5..10] 15 | let final = List.append list1 list2 16 | let result = final |> List.fold (fun acc next -> acc + next.ToString() + ",") "" 17 | emit result @> 18 | 19 | [] 20 | member this.choose() = 21 | test <@ let numbers = [1..20] 22 | let evens = List.choose(fun x -> 23 | match x with 24 | | x when x % 2=0 -> match x with 25 | | x -> Some(x) 26 | | _ -> None ) numbers 27 | 28 | let result = evens |> List.fold (fun acc next -> acc + next.ToString()) "" 29 | emit result @> 30 | 31 | [] 32 | member this.collect() = 33 | test <@ let list1 = [10; 20; 30] 34 | let collectList = List.collect (fun x -> [for i in 1..3 -> x * i]) list1 35 | let result = collectList |> List.fold (fun acc next -> acc + next.ToString()) "" 36 | emit result @> 37 | 38 | [] 39 | member this.concat() = 40 | test <@ let list1to10 = List.append [1; 2; 3] [4; 5; 6; 7; 8; 9; 10] 41 | let listResult = List.concat [ [1; 2; 3]; [4; 5; 6]; [7; 8; 9] ] 42 | let result = listResult |> List.fold (fun acc next -> acc + next.ToString()) "" 43 | emit result @> 44 | 45 | [] 46 | member this.filter() = 47 | test <@ let data = [("Cats",4); 48 | ("Dogs",5); 49 | ("Mice",3); 50 | ("Elephants",2)] 51 | let res = data |> List.filter (fun (nm,x) -> nm.Length <= 4) 52 | let result = res |> List.fold(fun acc x -> acc + x.ToString()) "" 53 | emit result @> 54 | 55 | [] 56 | member this.fold2() = 57 | test <@ let result = List.fold2 (fun acc elem1 elem2 -> acc + max elem1 elem2) 0 [ 1; 2; 3 ] [ 3; 2; 1 ] 58 | emit result @> 59 | 60 | [] 61 | member this.foldBack() = 62 | test <@ let result = List.foldBack (fun acc elem -> acc - elem) [ 1; 2; 3 ] 0 63 | emit result @> 64 | 65 | [] 66 | member this.foldBack2() = 67 | test <@ let transactionTypes = [ "Deposit"; "Deposit"; "Withdrawal" ] 68 | let transactionAmounts = [ 100.00; 1000.00; 95.00 ] 69 | let initialBalance = 200.00 70 | let endingBalance = List.foldBack2 (fun elem1 elem2 acc -> 71 | match elem1 with 72 | | "Deposit" -> acc + elem2 73 | | "Withdrawal" -> acc - elem2 74 | | _ -> acc) 75 | transactionTypes 76 | transactionAmounts 77 | initialBalance 78 | 79 | emit endingBalance @> 80 | 81 | [] 82 | member this.map() = 83 | test <@ let arr = [ 1; 2; 3 ] |> List.map (fun x -> x + 10) 84 | let result = arr |> List.fold(fun acc next -> acc + next.ToString() + ",") "" 85 | emit result @> 86 | 87 | [] 88 | member this.map2() = 89 | test <@ let list1 = [ 1; 2; 3 ] 90 | let list2 = [ 4; 5; 6 ] 91 | let listOfSums = List.map2 (fun x y -> x + y) list1 list2 92 | let result = listOfSums |> List.fold(fun acc next -> acc + next.ToString() + ",") "" 93 | emit result @> 94 | 95 | [] 96 | member this.map3() = 97 | test <@ let list1 = [ 1; 2; 3 ] 98 | let list2 = [ 4; 5; 6 ] 99 | let list3 = [ 7; 8; 9 ] 100 | let listOfSums = List.map3 (fun x y z -> x + y + z) list1 list2 list3 101 | let result = listOfSums |> List.fold(fun acc next -> acc + next.ToString() + ",") "" 102 | emit result @> 103 | 104 | [] 105 | member this.mapi() = 106 | test <@ let array1 = [ 1; 2; 3 ] 107 | let arrayAddTimesIndex = List.mapi (fun i x -> (x) * i) array1 108 | let result = arrayAddTimesIndex |> List.fold(fun acc next -> acc + next.ToString() + ",") "" 109 | emit result @> 110 | 111 | [] 112 | member this.mapi2() = 113 | test <@ let array1 = [ 1; 2; 3 ] 114 | let array2 = [ 4; 5; 6 ] 115 | let arrayAddTimesIndex = List.mapi2 (fun i x y -> (x + y) * i) array1 array2 116 | let result = arrayAddTimesIndex |> List.fold(fun acc next -> acc + next.ToString() + ",") "" 117 | emit result @> 118 | 119 | [] 120 | member this.nth() = 121 | test <@ let list = [1..10] 122 | let result = List.nth list 3 123 | emit result @> 124 | 125 | [] 126 | member this.partition() = 127 | test <@ let (l,r) = List.partition (fun elem -> elem > 50 && elem < 60) [ 1 .. 100 ] 128 | let result1 = l |> List.fold (fun acc next -> acc + next.ToString() + ",") "" 129 | let result2 = r |> List.fold (fun acc next -> acc + next.ToString() + ",") "" 130 | let result = result1 + result2 131 | emit result @> 132 | 133 | [] 134 | member this.reduceBack() = 135 | test <@ let result = List.reduceBack (fun elem acc -> elem - acc) [ 1; 2; 3; 4 ] 136 | emit result @> 137 | 138 | [] 139 | member this.replicate() = 140 | test <@ let list = List.replicate 10 1 141 | let result = list |> List.fold (fun acc next -> acc + next.ToString() + ",") "" 142 | emit result @> 143 | 144 | [] 145 | member this.scan() = 146 | test <@ let initialBalance = 1122.73 147 | let transactions = [ -100.00; +450.34; -62.34; -127.00; -13.50; -12.92 ] 148 | let balances = List.scan (fun balance transactionAmount -> balance + transactionAmount) initialBalance transactions 149 | let result = balances |> List.fold (fun acc next -> acc + next.ToString() + ",") "" 150 | emit result @> 151 | 152 | [] 153 | member this.scanBack() = 154 | test <@ let ops1 = 155 | [ fun x -> x + 1 156 | fun x -> x + 2 157 | fun x -> x - 5 ] 158 | 159 | let arr = List.scanBack (fun op x -> op x) ops1 10 160 | let result = arr |> List.fold (fun acc next -> acc + next.ToString() + ",") "" 161 | emit result @> 162 | 163 | [] 164 | member this.sort() = 165 | test <@ let arr = List.sort [1; 4; 8; -2; 5] 166 | let result = arr |> List.fold (fun acc next -> acc + next.ToString() + ",") "" 167 | emit result @> 168 | 169 | [] 170 | member this.sortBy() = 171 | test <@ let arr = List.sortBy (fun elem -> abs elem) [1; 4; 8; -2; 5] 172 | let result = arr |> List.fold (fun acc next -> acc + next.ToString() + ",") "" 173 | emit result @> 174 | 175 | [] 176 | member this.sortWith() = 177 | test <@ let arr = [1; 4; 8; -2; 5] 178 | let arr1 = List.sortWith (fun elem1 elem2 -> elem1 - elem2) arr 179 | let result = arr1 |> List.fold (fun acc next -> acc + next.ToString() + ",") "" 180 | emit result @> 181 | 182 | [] 183 | member this.tail() = 184 | test <@ let list = [1..10] 185 | let tail = list |> List.tail 186 | let result = tail |> List.fold (fun acc next -> acc + next.ToString() + ",") "" 187 | emit result @> 188 | 189 | [] 190 | member this.unzip() = 191 | test <@ let array1, array2 = List.unzip [ (1, 2); (3, 4) ] 192 | let result1 = array1 |> List.fold (fun acc next -> acc + next.ToString() + ",") "" 193 | let result2 = array2 |> List.fold (fun acc next -> acc + next.ToString() + ",") "" 194 | let result = result1 + result2 195 | emit result @> 196 | 197 | [] 198 | member this.unzip3() = 199 | test <@ let array1, array2, array3 = List.unzip3 [ (1, 2, 5); (3, 4, 10) ] 200 | let result1 = array1 |> List.fold (fun acc next -> acc + next.ToString() + ",") "" 201 | let result2 = array2 |> List.fold (fun acc next -> acc + next.ToString() + ",") "" 202 | let result3 = array3 |> List.fold (fun acc next -> acc + next.ToString() + ",") "" 203 | let result = result1 + result2 + result3 204 | emit result @> 205 | 206 | [] 207 | member this.``zip`` () = 208 | test <@ let seq1 = [1..10] 209 | let seq2 = [10.. -1 .. 1] 210 | let zip = List.zip seq1 seq2 211 | let result = zip |> List.fold (fun acc (l,r) -> acc + "(" + l.ToString() + ", " + r.ToString() + ") ") "" 212 | emit result @> 213 | 214 | [] 215 | member this.``zip3`` () = 216 | test <@ let seq1 = [1..10] 217 | let seq2 = [10.. -1 .. 1] 218 | let seq3 = [20 .. -1 .. 11] 219 | let zip = List.zip3 seq1 seq2 seq3 220 | let result = zip |> List.fold (fun acc (l,m,r) -> acc + "(" + l.ToString() + ", " + m.ToString() + ", " + r.ToString() + ") ") "" 221 | emit result @> 222 | 223 | 224 | -------------------------------------------------------------------------------- /FSharp.Javascript/Printer.fs: -------------------------------------------------------------------------------- 1 | #light 2 | module FSharp.Javascript.Printer 3 | 4 | open FSharp.Javascript.Ast 5 | open System.Linq.Expressions 6 | 7 | let getOp (op:System.Linq.Expressions.ExpressionType) = 8 | match op with 9 | | ExpressionType.Add -> "+" 10 | | ExpressionType.And -> "&" 11 | | ExpressionType.AndAlso -> "&&" 12 | | ExpressionType.Subtract -> "-" 13 | | ExpressionType.Multiply -> "*" 14 | | ExpressionType.Divide -> "/" 15 | | ExpressionType.Modulo -> "%" 16 | | ExpressionType.Equal -> "==" 17 | | ExpressionType.NotEqual -> "!=" 18 | | ExpressionType.LessThan -> "<" 19 | | ExpressionType.GreaterThan -> ">" 20 | | ExpressionType.GreaterThanOrEqual -> ">=" 21 | | ExpressionType.LessThanOrEqual -> "<=" 22 | | ExpressionType.Or -> "|" 23 | | ExpressionType.ExclusiveOr -> "^" 24 | | ExpressionType.LeftShift -> "<<" 25 | | ExpressionType.RightShift -> ">>" 26 | | ExpressionType.OrElse -> "||" 27 | | ExpressionType.PostIncrementAssign -> "++" 28 | | ExpressionType.PostDecrementAssign -> "--" 29 | | ExpressionType.PreIncrementAssign -> "++" 30 | | ExpressionType.PreDecrementAssign -> "--" 31 | | ExpressionType.Negate -> "-" 32 | | ExpressionType.Not -> "!" 33 | | ExpressionType.OnesComplement -> "~" 34 | | ExpressionType.UnaryPlus -> "+" 35 | | _ -> failwith "unsuported operator" 36 | 37 | let getStrictOp (op:ExpressionType) = 38 | match op with 39 | | ExpressionType.Equal -> "===" 40 | | ExpressionType.NotEqual -> "!==" 41 | | _ -> failwith "unsupported strict operator" 42 | 43 | let getTab indent = ({0..indent} |> Seq.filter (fun x -> x <> 0) |> Seq.map (fun x -> " ") |> String.concat "") 44 | 45 | let trim (x:string) = 46 | x.Trim([|' '; '\n'; '\t'; '\r'; ','|]) 47 | 48 | let compactBlock block = 49 | let rec loop node acc = 50 | match node with 51 | | Block(list) -> [for l in list do yield! loop l acc] 52 | | _ -> node::acc 53 | 54 | loop block [] 55 | 56 | let getJavascript ast = 57 | let getLine = System.Environment.NewLine 58 | let rec getBody (nodes:node list) char indent = 59 | let getIndent = getTab (indent) 60 | let getDedent = getTab (indent - 1) 61 | let result = [for n in nodes do yield! getLine::char::(traverse n [] (indent + 1))@[getIndent]] 62 | result 63 | 64 | and traverseReturnOrBody (node:node) indent = 65 | let getIndent = getTab (indent) 66 | let getDedent = getTab (indent - 1) 67 | match node with 68 | | Return x -> (traverse node [] indent)@[getIndent] 69 | | _ -> traverse node [] (indent) 70 | and traverse (node:node) acc indent = 71 | let getIndent = getTab (indent) 72 | let getDedent = getTab (indent - 1) 73 | match node with 74 | | Ignore -> acc 75 | | Assign(l,r) -> 76 | let left = traverse l [] indent 77 | let right = traverse r [] (indent) 78 | right@(" = "::left)@(acc) 79 | | AutoProperty(n,v) -> 80 | let value = traverse v [] indent 81 | value@("\"" + n.ToString() + "\"" + " : "::acc) 82 | | BinaryOp(l,r,o) -> 83 | let left = traverse l [] indent 84 | let right = traverse r [] indent 85 | let op = getOp o 86 | "))"::right@("("::" " + op + " "::")"::left)@("(("::acc) 87 | | Identifier(n,l) -> if l then "var " + n::acc else n::acc 88 | | Number(i,f) -> if i.IsSome then ")"::(i.Value.ToString())::"("::acc else ")"::(sprintf "%f" f.Value)::"("::acc 89 | | Function(b,args, n) -> 90 | let body = traverseReturnOrBody b indent 91 | let arguments = [for a in args do yield! (traverse a [] 0)] |> String.concat "," 92 | 93 | if n.IsSome then 94 | getLine + getDedent + "}"::body@(getLine::"){"::arguments::"function " + n.Value + "("::acc) 95 | else 96 | getLine + getDedent + "}"::body@(getLine::"){"::arguments::"function("::acc) 97 | | Block(nodes) -> 98 | let compactedNodes = compactBlock node 99 | 100 | let body = (getBody compactedNodes ";" indent) |> List.rev |> String.concat "" 101 | body::acc 102 | | AssignmentBlock(nodes, l) -> 103 | let result = ((getBody nodes "," indent) |> List.rev |> String.concat "") |> trim 104 | 105 | //is local 106 | if l then 107 | result::"var "::acc 108 | //is global 109 | else 110 | result::acc 111 | | Boolean(b) -> 112 | b.ToString().ToLower()::acc 113 | | BreakNode(l) -> 114 | "break"::acc 115 | | ForInNode(l,r,b) -> 116 | let left = traverse l [] 0 117 | let right = traverse r [] 0 118 | let body = traverse b [] indent 119 | 120 | getIndent + "}"::body@("){" + getLine::right)@(" in "::left)@("for("::acc) 121 | | ForStepNode(s,t,i,b) -> 122 | let step = ((traverse s [] 0) |> List.rev |> String.concat "").Replace("\n", "").Replace("\t", "").Replace("\r", "").Replace(";", "") 123 | let test = traverse t [] 0 124 | let inc = traverse i [] 0 125 | let body = traverse b [] indent 126 | 127 | getIndent + "}"::body@("){" + getLine::inc)@("; "::test)@("; "::step::"for("::acc) 128 | | MemberAccess(name,node) -> 129 | let n = traverse node [] 0 130 | name::"."::n@acc 131 | | Call(n,args) -> 132 | let node = match n with 133 | //this handles calling an anonymous function 134 | | Function(_,_,_) -> ")"::(traverse n [] (indent))@("("::[]) 135 | | _ -> traverse n [] indent 136 | let arguments = ([for a in args do yield! ","::(traverse a [] indent)] |> List.rev |> String.concat "").Trim([|','|]) 137 | ")"::arguments::"("::node@acc 138 | | Catch(t,b) -> 139 | let target = traverse t [] 0 140 | let body = traverse b [] indent 141 | getIndent + "}"::body@("){" + getLine::target)@(getLine + getIndent + "catch("::acc) 142 | | Continue(l) -> "continue"::acc 143 | | Delete(n) -> 144 | let node = traverse n [] 0 145 | node@("delete "::acc) 146 | | Try(b,c,f) -> 147 | let body = traverse b [] indent 148 | let catch = if c.IsSome then traverse c.Value [] indent else [] 149 | let fin = if f.IsSome then getIndent + "}"::(traverse f.Value (getLine + getIndent + "finally{" + getLine::[]) indent) else [] 150 | 151 | fin@catch@(getIndent + "}"::body)@("try {" + getLine::acc) 152 | | New(t,args,props) -> 153 | if props.IsSome then 154 | let properties = [for p in props.Value do yield! "," + getLine + getTab (indent + 1)::(traverse p [] (indent + 1))] |> List.rev |> String.concat "" |> trim 155 | getIndent + "}"::getLine::properties::("{" + getLine + getTab (indent + 1)::acc) 156 | else 157 | let targ = traverse t [] 0 158 | let args = ([for a in args do yield! ","::(traverse a [] 0)] |> List.rev |> String.concat "").Trim([|','|]) 159 | ")"::args::("("::targ)@("new "::acc) 160 | | NewArray(t,args) -> 161 | let target = traverse t [] 0 162 | let arguments = ([for a in args do yield! ","::(traverse a [] indent)] |> List.rev |> String.concat "").Trim([|','|]) 163 | "]"::arguments::("["::acc) 164 | | If(t,b,e,it) -> 165 | let test = traverse t [] indent 166 | let trueBranch = traverseReturnOrBody b indent 167 | let elseBranch = if e.IsSome then traverseReturnOrBody e.Value (indent) else [] 168 | 169 | //ternary op 170 | if it then 171 | "))"::elseBranch@(") : ("::trueBranch)@(") ? ("::test)@("(("::acc) 172 | else 173 | let result = (getLine + getDedent + "}"::trueBranch)@("){" + getLine::test)@("if("::acc) 174 | if e.IsNone then 175 | result 176 | else 177 | match e.Value with 178 | // else if 179 | | If(_,_,_,_) -> elseBranch@("else "::getLine + getIndent::result) 180 | | _ -> getLine + getDedent + "}"::elseBranch@("else{" + getLine::result) 181 | | IndexAccess(t,i) -> 182 | let target = traverse t [] 0 183 | let index = traverse i [] 0 184 | match t with 185 | | Assign(l,r) -> 186 | "]"::index@("["::")"::target)@("("::acc) 187 | | _ -> 188 | "]"::index@("["::target)@(acc) 189 | | In(t,p) -> 190 | let target = traverse t [] 0 191 | let prop = traverse p [] 0 192 | target@(" in "::prop)@acc 193 | | InstanceOf(t,f) -> 194 | let target = traverse t [] 0 195 | let func = traverse f [] 0 196 | func@(" instanceof "::target)@acc 197 | | Logical(l,r,o) -> 198 | let left = traverse l [] 0 199 | let right = traverse r [] 0 200 | let op = getOp o 201 | "))"::right@("("::" " + op + " "::")"::left)@("(("::acc) 202 | | Null -> "null"::acc 203 | | PostfixOperator(t,o) -> 204 | let target = traverse t [] 0 205 | let op = getOp o 206 | op::target@acc 207 | | Regex(r,m) -> "/" + r + "/" + m::acc 208 | | Return(v) -> (traverse v [] (indent + 1))@("return "::acc) 209 | | StrictCompare(l,r,o) -> 210 | let left = traverse l [] 0 211 | let right = traverse r [] 0 212 | let op = getStrictOp o 213 | "))"::right@("("::[])@(" " + op + " "::")"::left)@("(("::acc) 214 | | String(s,c) -> c.ToString() + s + c.ToString()::acc 215 | | Switch(t,d,c,label) -> 216 | let target = traverse t [] 0 217 | let def = ";"::(traverse d [] (indent + 1)) 218 | let cases = [for (l,r) in c do yield! (traverse r [] (indent + 1))@(":" + getLine::(traverse l (getTab (indent + 1) + "case "::[]) (indent + 1)))] 219 | getLine + getIndent + "}"::def@(getTab (indent + 1) + "default:" + getLine + (getTab (indent + 2))::cases)@("){" + getLine::target)@("switch("::acc) 220 | | Throw(b) -> (traverse b [] 0)@("throw "::acc) 221 | | TypeOf(n) -> (traverse n [] 0)@("typeof "::acc) 222 | | UnaryOp(t,o) -> 223 | let target = traverse t [] 0 224 | let op = getOp o 225 | ")"::target@("("::op::acc) 226 | | UnsignedRightShift(l,r) -> 227 | let left = traverse l [] 0 228 | let right = traverse r [] 0 229 | right@(" >>> "::left)@acc 230 | | Void(n) -> 231 | let node = traverse n [] 0 232 | ")"::node@("void("::acc) 233 | | While(t,b,l) -> 234 | let test = traverse t [] 0 235 | let body = traverse b [] indent 236 | //while loop 237 | if l then 238 | getIndent + "}"::body@("){" + getLine::test)@("while("::acc) 239 | //do while 240 | else 241 | ")"::test@(getIndent + "while("::getIndent + "}"::body)@("do{" + getLine::acc) 242 | | With(t,b) -> 243 | let target = traverse t [] 0 244 | let body = traverse b [] indent 245 | getIndent + "}"::body@("){" + getLine::target)@("with("::acc) 246 | 247 | let result = [for a in ast do yield! ";" + System.Environment.NewLine::(traverse a [] 0)] 248 | result |> List.rev |> String.concat "" -------------------------------------------------------------------------------- /FSharp.Javascript.Tests/ArrayModuleTests.fs: -------------------------------------------------------------------------------- 1 | namespace FSharp.Javascript.Tests 2 | 3 | open NUnit.Framework 4 | open FSharp.Javascript.Printer 5 | open QuotationsTestHelper 6 | 7 | [] 8 | type ArrayModuleTests() = 9 | let test quote = QuotationsTestHelper.testWithType [] quote 10 | 11 | [] 12 | member this.``append`` () = 13 | test <@ let arr1 = [|1;2;3;4|] 14 | let arr2 = [|5;6;7;8|] 15 | let final = Array.append arr1 arr2 16 | let result = final |> Array.fold (fun acc next -> acc + next.ToString() + ",") "" 17 | emit result 18 | @> 19 | 20 | [] 21 | member this.average () = 22 | test <@ let arr1 = [|1.0..10.0|] 23 | let result = arr1 |> Array.average 24 | emit result @> 25 | 26 | [] 27 | member this.``averageBy`` () = 28 | test <@ 29 | let values = [|1..10|] 30 | let result = values |> Array.averageBy (fun elem -> float elem) 31 | emit result 32 | 33 | @> 34 | 35 | [] 36 | member this.``zeroCreate``() = 37 | test <@ let arr = Array.zeroCreate 4 38 | emit (arr.Length = 4) @> 39 | 40 | [] 41 | member this.``blit`` () = 42 | test <@ let array1 = [| 1 .. 10 |] 43 | let array2 = Array.zeroCreate 20 44 | // Copy 4 elements from index 3 of array1 to index 5 of array2. 45 | Array.blit array1 3 array2 5 4 46 | let result = array2 |> Array.fold(fun acc next -> acc + next.ToString() + ",") "" 47 | emit result @> 48 | 49 | [] 50 | member this.``choose`` () = 51 | test <@ let numbers = seq { 1..20 } |> Array.ofSeq 52 | let evens = Array.choose(fun x -> 53 | match x with 54 | | z when z % 2=0 -> Some(z) 55 | | _ -> None ) numbers 56 | 57 | let result = evens |> Array.fold (fun acc next -> acc + next.ToString()) "" 58 | emit result @> 59 | 60 | [] 61 | member this.``collect`` () = 62 | test <@ let arr = (Array.collect (fun elem -> [| 0 .. elem |]) [| 1; 5; 10|]) 63 | let result = arr |> Array.fold(fun acc next -> acc + next.ToString() + ",") "" 64 | emit result @> 65 | 66 | [] 67 | member this.``concat`` () = 68 | test <@ let multiplicationTable max = seq { for i in 1 .. max -> [| for j in 1 .. max -> (i, j, i*j) |] } 69 | let arr = (Array.concat (multiplicationTable 3)) 70 | let result = arr |> Array.fold(fun acc next -> acc + next.ToString() + ",") "" 71 | emit result @> 72 | 73 | [] 74 | member this.``copy`` () = 75 | test <@ let array1 = [| 1 .. 10 |] 76 | let array2 = Array.copy array1 77 | let result = array2 |> Array.fold(fun acc next -> acc + next.ToString() + ",") "" 78 | emit result @> 79 | 80 | [] 81 | member this.create () = 82 | test <@ let arr = Array.create 10 1 83 | let result = arr |> Array.fold(fun acc next -> acc + next.ToString() + ",") "" 84 | emit result @> 85 | 86 | [] 87 | member this.fill() = 88 | test <@ let arrayFill1 = [| 1 .. 25 |] 89 | Array.fill arrayFill1 2 20 0 90 | let result = arrayFill1 |> Array.fold(fun acc next -> acc + next.ToString() + ",") "" 91 | emit result @> 92 | 93 | [] 94 | member this.filter() = 95 | test <@ let names = [|"Bob"; "Ann"; "Stephen"; "Vivek"; "Fred"; "Kim"; "Brian"; "Ling"; "Jane"; "Jonathan"|] 96 | let longNames = names |> Array.filter (fun x -> x.Length > 4) 97 | let result = longNames |> Array.fold(fun acc next -> acc + next.ToString() + ",") "" 98 | emit result @> 99 | 100 | [] 101 | member this.fold2() = 102 | test <@ let result = Array.fold2 (fun acc elem1 elem2 -> acc + max elem1 elem2) 0 [| 1; 2; 3 |] [| 3; 2; 1 |] 103 | emit result @> 104 | 105 | [] 106 | member this.foldBack() = 107 | test <@ let result = Array.foldBack (fun acc elem -> acc - elem) [| 1; 2; 3 |] 0 108 | emit result @> 109 | 110 | [] 111 | member this.foldBack2() = 112 | test <@ let transactionTypes = [| "Deposit"; "Deposit"; "Withdrawal" |] 113 | let transactionAmounts = [| 100.00; 1000.00; 95.00 |] 114 | let initialBalance = 200.00 115 | let endingBalance = Array.foldBack2 (fun elem1 elem2 acc -> 116 | match elem1 with 117 | | "Deposit" -> acc + elem2 118 | | "Withdrawal" -> acc - elem2 119 | | _ -> acc) 120 | transactionTypes 121 | transactionAmounts 122 | initialBalance 123 | 124 | emit endingBalance @> 125 | 126 | [] 127 | member this.init() = 128 | test <@ let arr = (Array.init 10 (fun index -> index * index)) 129 | let result = arr |> Array.fold(fun acc next -> acc + next.ToString() + ",") "" 130 | emit result @> 131 | 132 | [] 133 | member this.isEmpty() = 134 | test <@ let arr = [||] : int array 135 | let result = arr |> Array.isEmpty 136 | emit result @> 137 | 138 | [] 139 | member this.iteri2() = 140 | test <@ let array1 = [| 1; 2; 3 |] 141 | let array2 = [| 4; 5; 6 |] 142 | let result = ref "" 143 | Array.iteri2 (fun i elem1 elem2 -> result := (!result) + i.ToString() + ":(" + elem1.ToString() + ", " + elem2.ToString() + ")") array1 array2 144 | 145 | emit (!result) @> 146 | 147 | [] 148 | member this.map() = 149 | test <@ let arr = [| 1; 2; 3 |] |> Array.map (fun x -> x + 10) 150 | let result = arr |> Array.fold(fun acc next -> acc + next.ToString() + ",") "" 151 | emit result @> 152 | 153 | [] 154 | member this.map2() = 155 | test <@ let array1 = [| 1; 2; 3 |] 156 | let array2 = [| 4; 5; 6 |] 157 | let arrayOfSums = Array.map2 (fun x y -> x + y) array1 array2 158 | let result = arrayOfSums |> Array.fold(fun acc next -> acc + next.ToString() + ",") "" 159 | emit result @> 160 | 161 | [] 162 | member this.mapi2() = 163 | test <@ let array1 = [| 1; 2; 3 |] 164 | let array2 = [| 4; 5; 6 |] 165 | let arrayAddTimesIndex = Array.mapi2 (fun i x y -> (x + y) * i) array1 array2 166 | let result = arrayAddTimesIndex |> Array.fold(fun acc next -> acc + next.ToString() + ",") "" 167 | emit result @> 168 | 169 | [] 170 | member this.partition() = 171 | test <@ let (l,r) = Array.partition (fun elem -> elem > 50 && elem < 60) [| 1 .. 100 |] 172 | let result1 = l |> Array.fold (fun acc next -> acc + next.ToString() + ",") "" 173 | let result2 = r |> Array.fold (fun acc next -> acc + next.ToString() + ",") "" 174 | let result = result1 + result2 175 | emit result @> 176 | 177 | [] 178 | member this.permute() = 179 | test <@ let reverse len orig = len - orig - 1 180 | let arr = Array.permute (reverse 10) [|1..10|] 181 | let result = arr |> Array.fold (fun acc next -> acc + next.ToString() + ",") "" 182 | emit result @> 183 | 184 | [] 185 | member this.reduceBack() = 186 | test <@ let result = Array.reduceBack (fun elem acc -> elem - acc) [| 1; 2; 3; 4 |] 187 | emit result @> 188 | 189 | [] 190 | member this.reverse() = 191 | test <@ let arr = [|1..10|] |> Array.rev 192 | let result = arr |> Array.fold (fun acc next -> acc + next.ToString() + ",") "" 193 | emit result @> 194 | 195 | [] 196 | member this.scan() = 197 | test <@ let initialBalance = 1122.73 198 | let transactions = [| -100.00; +450.34; -62.34; -127.00; -13.50; -12.92 |] 199 | let balances = Array.scan (fun balance transactionAmount -> balance + transactionAmount) initialBalance transactions 200 | let result = balances |> Array.fold (fun acc next -> acc + next.ToString() + ",") "" 201 | emit result @> 202 | 203 | [] 204 | member this.scanBack() = 205 | test <@ let ops1 = 206 | [| fun x -> x + 1 207 | fun x -> x + 2 208 | fun x -> x - 5 |] 209 | 210 | let arr = Array.scanBack (fun op x -> op x) ops1 10 211 | let result = arr |> Array.fold (fun acc next -> acc + next.ToString() + ",") "" 212 | emit result @> 213 | 214 | [] 215 | member this.set() = 216 | test <@ let arr = [|1..10|] 217 | Array.set arr 4 12 218 | let result = arr |> Array.fold (fun acc next -> acc + next.ToString() + ",") "" 219 | emit result @> 220 | 221 | [] 222 | member this.sort() = 223 | test <@ let arr = Array.sort [|1; 4; 8; -2; 5|] 224 | let result = arr |> Array.fold (fun acc next -> acc + next.ToString() + ",") "" 225 | emit result @> 226 | 227 | [] 228 | member this.sortBy() = 229 | test <@ let arr = Array.sortBy (fun elem -> abs elem) [|1; 4; 8; -2; 5|] 230 | let result = arr |> Array.fold (fun acc next -> acc + next.ToString() + ",") "" 231 | emit result @> 232 | 233 | [] 234 | member this.sortInPlace() = 235 | test <@ let arr = [|1; 4; 8; -2; 5|] 236 | Array.sortInPlace arr 237 | let result = arr |> Array.fold (fun acc next -> acc + next.ToString() + ",") "" 238 | emit result @> 239 | 240 | [] 241 | member this.sortInPlaceBy() = 242 | test <@ let arr = [|1; 4; 8; -2; 5|] 243 | Array.sortInPlaceBy (fun elem -> abs elem) arr 244 | let result = arr |> Array.fold (fun acc next -> acc + next.ToString() + ",") "" 245 | emit result @> 246 | 247 | [] 248 | member this.sortInPlaceWith() = 249 | //5, 12, 6, 3 250 | test <@ let arr = [|1; 4; 8; -2; 5|] 251 | Array.sortInPlaceWith (fun elem1 elem2 -> elem1 - elem2) arr 252 | let result = arr |> Array.fold (fun acc next -> acc + next.ToString() + ",") "" 253 | emit result @> 254 | 255 | [] 256 | member this.sortWith() = 257 | test <@ let arr = [|1; 4; 8; -2; 5|] 258 | let arr1 = Array.sortWith (fun elem1 elem2 -> elem1 - elem2) arr 259 | let result = arr1 |> Array.fold (fun acc next -> acc + next.ToString() + ",") "" 260 | emit result @> 261 | 262 | [] 263 | member this.sub() = 264 | test <@ let arr = Array.sub [|1..10|] 3 5 265 | let result = arr |> Array.fold (fun acc next -> acc + next.ToString() + ",") "" 266 | emit result @> 267 | 268 | [] 269 | member this.sum() = 270 | test <@ let result = [| 1 .. 10 |] |> Array.sum 271 | emit result @> 272 | 273 | [] 274 | member this.sumBy() = 275 | test <@ let result = [| 1 .. 10 |] |> Array.sumBy (fun x -> x * x) 276 | emit result @> 277 | 278 | [] 279 | member this.unzip() = 280 | test <@ let array1, array2 = Array.unzip [| (1, 2); (3, 4) |] 281 | let result1 = array1 |> Array.fold (fun acc next -> acc + next.ToString() + ",") "" 282 | let result2 = array2 |> Array.fold (fun acc next -> acc + next.ToString() + ",") "" 283 | let result = result1 + result2 284 | emit result @> 285 | 286 | [] 287 | member this.unzip3() = 288 | test <@ let array1, array2, array3 = Array.unzip3 [| (1, 2, 5); (3, 4, 10) |] 289 | let result1 = array1 |> Array.fold (fun acc next -> acc + next.ToString() + ",") "" 290 | let result2 = array2 |> Array.fold (fun acc next -> acc + next.ToString() + ",") "" 291 | let result3 = array3 |> Array.fold (fun acc next -> acc + next.ToString() + ",") "" 292 | let result = result1 + result2 + result3 293 | emit result @> 294 | 295 | -------------------------------------------------------------------------------- /FSharp.Javascript.Tests/SeqModuleTests.fs: -------------------------------------------------------------------------------- 1 | namespace FSharp.Javascript.Tests 2 | 3 | open NUnit.Framework 4 | open FSharp.Javascript.Printer 5 | open QuotationsTestHelper 6 | 7 | [] 8 | type SeqModuleTests() = 9 | let test quote = QuotationsTestHelper.testWithType [] quote 10 | 11 | [] 12 | member this.``Sequence average`` () = 13 | test <@ 14 | let values = [1.0..10.0] 15 | let result = values |> Seq.average 16 | emit result 17 | 18 | @> 19 | 20 | [] 21 | member this.``Sequence average by`` () = 22 | test <@ 23 | let values = [1..10] 24 | let result = values |> Seq.averageBy (fun elem -> float elem) 25 | emit result 26 | 27 | @> 28 | 29 | [] 30 | member this.``Sequence cache`` () = 31 | test <@ let isPrime n = 32 | let rec check i = 33 | i > n/2 || (n % i <> 0 && check (i + 1)) 34 | check 2 35 | 36 | let seqPrimes = seq { for n in 2 .. 10000 do if isPrime n then yield n } 37 | // Cache the sequence to avoid recomputing the sequence elements. 38 | let cachedSeq = Seq.cache seqPrimes 39 | let tempSeq = seq { 40 | for index in 1..5 do yield ((Seq.nth (Seq.length cachedSeq - index) cachedSeq).ToString() + " is Prime") 41 | } 42 | 43 | let result = tempSeq |> Seq.fold (fun acc next -> acc + next) "" 44 | 45 | emit result 46 | @> 47 | 48 | [] 49 | member this.``Sequence choose`` () = 50 | test <@ let numbers = seq { 1..20 } 51 | let evens = Seq.choose(fun x -> 52 | match x with 53 | | z when z % 2=0 -> Some(z) 54 | | _ -> None ) numbers 55 | 56 | let result = evens |> Seq.fold (fun acc next -> acc + next.ToString()) "" 57 | emit result @> 58 | 59 | [] 60 | member this.``Sequence compareWith`` () = 61 | test <@ let sequence1 = seq { 1 .. 10 } 62 | let sequence2 = seq { 10 .. -1 .. 1 } 63 | let compareSequences = Seq.compareWith (fun elem1 elem2 -> 64 | if elem1 > elem2 then 1 65 | elif elem1 < elem2 then -1 66 | else 0) 67 | 68 | let compareResult1 = compareSequences sequence1 sequence2 69 | match compareResult1 with 70 | | 1 -> emit "Sequence1 is greater than sequence2." 71 | | -1 -> emit "Sequence1 is less than sequence2." 72 | | 0 -> emit "Sequence1 is equal to sequence2." 73 | | _ -> emit "Invalid comparison result." 74 | @> 75 | 76 | [] 77 | member this.``Sequence countBy`` () = 78 | test <@ let mySeq1 = seq { 1.. 100 } 79 | let seqResult = Seq.countBy (fun elem -> 80 | if (elem % 2 = 0) then 0 else 1) mySeq1 81 | 82 | let result = seqResult |> Seq.fold (fun acc (x,y) -> acc + " (" + x.ToString() + ", " + y.ToString() + ")") "" 83 | emit result 84 | @> 85 | 86 | [] 87 | member this.``Sequence find`` () = 88 | test <@ let isDivisibleBy number elem = elem % number = 0 89 | let result = Seq.find (isDivisibleBy 5) [ 1 .. 100 ] 90 | emit result 91 | @> 92 | 93 | [] 94 | member this.``Sequence tryFind`` () = 95 | test <@ let isDivisibleBy number elem = elem % number = 0 96 | let result = Seq.tryFind (isDivisibleBy 5) [ 1 .. 100 ] 97 | emit result.IsSome 98 | 99 | @> 100 | 101 | [] 102 | member this.``Sequence distinct`` () = 103 | test <@ let resultSequence = Seq.distinct [1;2;1;3;4;5;23;453;1;2;45;2] 104 | 105 | let result = resultSequence |> Seq.fold (fun acc next -> acc + next.ToString() + ",") "" 106 | emit result @> 107 | 108 | [] 109 | member this.``Sequence distinctBy`` () = 110 | test <@ 111 | let inputSequence = { -5 .. 10 } 112 | let absoluteSeq = Seq.distinctBy (fun elem -> abs elem) inputSequence 113 | let result = absoluteSeq |> Seq.fold (fun acc next -> acc + next.ToString() + ",") "" 114 | emit result @> 115 | 116 | [] 117 | member this.``Sequence exists2`` () = 118 | test <@ let seq1to5 = seq { 1 .. 5 } 119 | let seq5to1 = seq { 5 .. -1 .. 1 } 120 | emit (Seq.exists2 (fun elem1 elem2 -> elem1 = elem2) seq1to5 seq5to1) 121 | @> 122 | 123 | [] 124 | member this.``Sequence findIndex``() = 125 | test <@ let seq1 = seq { 1..5 } 126 | let result = seq1 |> Seq.findIndex (fun x -> x = 3) 127 | emit result @> 128 | 129 | [] 130 | member this.``Sequence forAll`` () = 131 | test <@ let seq1 = seq { 1..5 } 132 | let result = seq1 |> Seq.forall (fun x -> x < 10) 133 | emit result @> 134 | 135 | [] 136 | member this.``Sequence forAll2`` () = 137 | test <@ let seq1to5 = seq { 1 .. 5 } 138 | let seq5to1 = seq { 5 .. -1 .. 1 } 139 | emit (Seq.forall2 (fun elem1 elem2 -> elem1 < 10 && elem2 < 10) seq1to5 seq5to1) 140 | @> 141 | 142 | [] 143 | member this.``Sequence groupBy`` () = 144 | test <@ let sequence = seq { 1 .. 100 } 145 | let sequences3 = Seq.groupBy (fun index -> 146 | if (index % 2 = 0) then 0 else 1) sequence 147 | let result = sequences3 148 | |> Seq.fold (fun acc (key,values) -> 149 | acc + "(" + key.ToString() + ", [" + (values |> Seq.fold(fun acc2 next -> acc2 + next.ToString() + "," ) "") + "])") "" 150 | emit result @> 151 | 152 | [] 153 | member this.``Sequence initInfinite and take`` () = 154 | test <@ let seqInfinite = Seq.initInfinite (fun i -> i + 1) 155 | 156 | let seqTake = seqInfinite |> Seq.take 100 157 | let result = seqTake |> Seq.fold (fun acc next -> acc + next.ToString() + "," ) "" 158 | emit result @> 159 | 160 | [] 161 | member this.``Sequence init`` () = 162 | test <@ let init = Seq.init 10 (fun i -> i + 1) 163 | let result = init |> Seq.fold (fun acc next -> acc + next.ToString() + "," ) "" 164 | emit result 165 | 166 | @> 167 | 168 | [] 169 | member this.``Sequence isEmpty`` () = 170 | test <@ let seq = seq { 1..10 } 171 | emit (seq |> Seq.isEmpty) @> 172 | 173 | [] 174 | member this.``Sequence iter2`` () = 175 | test <@ let seq1 = [1; 2; 3] 176 | let seq2 = [4; 5; 6] 177 | let result = ref "" 178 | Seq.iter2 (fun x y -> result := (!result + x.ToString() + ":" + y.ToString() + ",")) seq1 seq2 179 | 180 | emit (!result) @> 181 | 182 | [] 183 | member this.``Sequence iteri`` () = 184 | test <@ let seq1 = seq { 1..5 } 185 | let result = ref "" 186 | Seq.iteri (fun i x -> result := (!result + i.ToString() + ":" + x.ToString() + ",")) seq1 187 | emit (!result) @> 188 | 189 | [] 190 | member this.``Sequence map2`` () = 191 | test <@ let seq1 = seq { 1..5 } 192 | let seq2 = seq { 5.. -1 .. 1 } 193 | let resultSeq = Seq.map2 (fun x y -> (x + y)) seq1 seq2 194 | let result = resultSeq |> Seq.fold(fun acc next -> acc + next.ToString() + ",") "" 195 | emit result 196 | 197 | @> 198 | 199 | [] 200 | member this.``Sequence mapi`` () = 201 | test <@ let seq1 = seq { 1..5 } 202 | let resultSeq = Seq.mapi (fun i x -> i + x) seq1 203 | let result = resultSeq |> Seq.fold(fun acc next -> acc + next.ToString() + ",") "" 204 | emit result @> 205 | 206 | [] 207 | member this.``Sequence maxBy`` () = 208 | test <@ let seq1 = seq { 1..5 } 209 | let result = Seq.maxBy (fun x -> x + 1) seq1 210 | emit result @> 211 | 212 | [] 213 | member this.``Sequence max`` () = 214 | test <@ let seq1 = seq { 1..5 } 215 | let result = Seq.max seq1 216 | emit result @> 217 | 218 | [] 219 | member this.``Sequence minBy`` () = 220 | test <@ let seq1 = seq { 1..5 } 221 | let result = Seq.minBy (fun x -> x + 1) seq1 222 | emit result @> 223 | 224 | [] 225 | member this.``Sequence min`` () = 226 | test <@ let seq1 = seq { 1..5 } 227 | let result = Seq.min seq1 228 | emit result @> 229 | 230 | [] 231 | member this.``Sequence pairwise`` () = 232 | test <@ let seq1 = Seq.pairwise (seq { for i in 1 .. 10 -> i * i }) 233 | let result = seq1 |> Seq.fold(fun acc (x,y) -> acc + "(" + x.ToString() + ", " + y.ToString() + ") ") "" 234 | emit result @> 235 | 236 | [] 237 | member this.``Sequence pick`` () = 238 | test <@ let seq1 = seq { 1..10 } 239 | let result = seq1 |> Seq.pick (fun x -> if x = 4 then Some x else None) 240 | emit result @> 241 | 242 | [] 243 | member this.``Sequence tryPick`` () = 244 | test <@ let seq1 = seq { 1..10 } 245 | let result = seq1 |> Seq.tryPick (fun x -> if x = 11 then Some x else None) 246 | emit result.IsSome @> 247 | 248 | [] 249 | member this.``Sequence reduce`` () = 250 | test <@ let seq = seq { 1..10 } 251 | let result = seq |> Seq.reduce(fun acc x -> acc + x) 252 | emit result @> 253 | 254 | [] 255 | member this.``Sequence scan`` () = 256 | test <@ let initialBalance = 1122.73 257 | let transactions = [ -100.00; +450.34; -62.34; -127.00; -13.50; -12.92 ] 258 | let balances = Seq.scan (fun balance transactionAmount -> balance + transactionAmount) initialBalance transactions 259 | let result = balances |> Seq.fold (fun acc next -> acc + next.ToString() + ",") "" 260 | emit result @> 261 | 262 | [] 263 | member this.``Sequence skip``() = 264 | test <@ let seq1 = seq { 1..40 } 265 | let seq2 = seq1 |> Seq.skip 10 266 | let result = seq2 |> Seq.fold (fun acc next -> acc + next.ToString() + ",") "" 267 | emit result @> 268 | 269 | [] 270 | member this.``Sequence skipWhile``() = 271 | test <@ let seq1 = seq { 1..40 } 272 | let seq2 = seq1 |> Seq.skipWhile (fun x -> x < 20) 273 | let result = seq2 |> Seq.fold (fun acc next -> acc + next.ToString() + ",") "" 274 | emit result @> 275 | 276 | [] 277 | member this.``Sequence truncate`` () = 278 | test <@ let seq1 = seq { 1..40 } 279 | let seq2 = seq1 |> Seq.truncate 20 280 | let result = seq2 |> Seq.fold (fun acc next -> acc + next.ToString() + ",") "" 281 | emit result @> 282 | 283 | [] 284 | member this.``Sequence tryFindIndex`` () = 285 | test <@ let seq1 = seq { 1..40 } 286 | let result = seq1 |> Seq.tryFindIndex(fun x -> x = 10) 287 | emit result.Value @> 288 | 289 | [] 290 | member this.``Sequence unfold`` () = 291 | test <@ let seq1 = Seq.unfold (fun state -> if (state > 20) then None else Some(state, state + 1)) 0 292 | let result = seq1 |> Seq.fold (fun acc next -> acc + next.ToString() + ",") "" 293 | emit result @> 294 | 295 | [] 296 | member this.``Sequence windowed`` () = 297 | test <@ let seqNumbers = [ 1.0; 1.5; 2.0; 1.5; 1.0; 1.5 ] :> seq 298 | let seqWindows = Seq.windowed 3 seqNumbers 299 | 300 | let result = seqWindows |> Seq.fold(fun acc next -> acc + "[" + (next |> Seq.fold(fun innerAcc n -> innerAcc + n.ToString() + ",") "") + "] ") "" 301 | emit result @> 302 | 303 | [] 304 | member this.``Sequence zip`` () = 305 | test <@ let seq1 = seq { 1..10 } 306 | let seq2 = seq { 10.. -1 .. 1 } 307 | let zip = Seq.zip seq1 seq2 308 | let result = zip |> Seq.fold (fun acc (l,r) -> acc + "(" + l.ToString() + ", " + r.ToString() + ") ") "" 309 | emit result @> 310 | 311 | [] 312 | member this.``Sequence zip3`` () = 313 | test <@ let seq1 = seq { 1..10 } 314 | let seq2 = seq { 10.. -1 .. 1 } 315 | let seq3 = seq { 100 .. -1 .. 1 } 316 | let zip = Seq.zip3 seq1 seq2 seq3 317 | let result = zip |> Seq.fold (fun acc (l,m,r) -> acc + "(" + l.ToString() + ", " + m.ToString() + ", " + r.ToString() + ") ") "" 318 | emit result @> -------------------------------------------------------------------------------- /FSharp.Javascript/ModuleCompiler.fs: -------------------------------------------------------------------------------- 1 | #light 2 | module FSharp.Javascript.ModuleCompiler 3 | 4 | open FSharp.Javascript.Ast 5 | open FSharp.Javascript.QuotationsConverter 6 | 7 | open System 8 | open System.Reflection 9 | open Microsoft.FSharp.Reflection 10 | 11 | 12 | 13 | let getDefaultValue (t:PropertyInfo) = 14 | match t.ReflectedType with 15 | | x when x = typeof -> Number(Some(0), None) 16 | | x when x = typeof -> Number(None, Some(float 0)) 17 | | x when x = typeof -> Ast.String("", '"') 18 | | _ -> Null 19 | 20 | let camelCase (input:string) = 21 | if input.Length = 0 then 22 | input 23 | else 24 | let first = (input.Substring(0, 1)).ToUpper() 25 | first + (input.Substring(1, input.Length - 1)) 26 | 27 | 28 | let getName (m:System.Reflection.MethodInfo) = 29 | let rec loop (typ:System.Type) acc = 30 | if typ.DeclaringType = null then 31 | acc 32 | else 33 | loop typ.DeclaringType (typ.Name.Replace("|", "")::acc) 34 | 35 | (loop m.DeclaringType (m.Name::[])) |> String.concat "." 36 | 37 | let getBaseType (startingType:System.Type) = 38 | let rec innerGet (typ:System.Type) = 39 | if typ.BaseType = null || typ.BaseType.Name = "Object" 40 | then typ 41 | else 42 | innerGet typ.BaseType 43 | 44 | innerGet startingType 45 | 46 | let getEqualityFunction (memberAccess:Ast.node) (parameters:string list) (func:string -> string) = 47 | 48 | let initialStatement = Assign(Identifier("result", true), Ast.Boolean(true)) 49 | let typeStatement = Assign(Identifier("result", false), 50 | BinaryOp(Identifier("result", false), 51 | Ast.InstanceOf(Identifier("compareTo", false), 52 | memberAccess), 53 | 54 | System.Linq.Expressions.ExpressionType.AndAlso)) 55 | 56 | let getBlock (p:string) = Assign(Identifier("result", false), 57 | BinaryOp(Identifier("result", false), 58 | Call(Call(Identifier("Microsoft.FSharp.Core.Operators.op_Equality", false), 59 | [MemberAccess("get_" + func p + "()", Identifier("this", false))]), 60 | [MemberAccess("get_" + func p + "()", Identifier("compareTo", false))]), 61 | System.Linq.Expressions.ExpressionType.AndAlso)) 62 | 63 | 64 | let blockStatements = parameters |> List.map getBlock |> List.rev 65 | 66 | 67 | 68 | (Function(Block(Return(Identifier("result", false))::blockStatements@[typeStatement;initialStatement]), [Identifier("compareTo", false)], None)) 69 | 70 | let createPropertyGet (property:PropertyInfo, t:System.Type) = 71 | let def = (Microsoft.FSharp.Quotations.Expr.TryGetReflectedDefinition(property.GetGetMethod())) 72 | let ast = if def.IsSome then Some((QuotationsConverter.convertToAst def.Value).Head) else None 73 | 74 | Assign(MemberAccess("get_" + property.Name, 75 | MemberAccess("prototype", 76 | getMemberAccess (t.Name, t.DeclaringType, t.Namespace))), 77 | if ast.IsSome then 78 | ast.Value 79 | else 80 | Function(Return(Identifier("this." + property.Name, false)), [], None) 81 | ) 82 | 83 | let createPropertySet (property:PropertyInfo, t:System.Type) = 84 | let setMethod = property.GetSetMethod() 85 | let setMethod = if setMethod = null then None else Some setMethod 86 | let def = if setMethod.IsSome then (Microsoft.FSharp.Quotations.Expr.TryGetReflectedDefinition(setMethod.Value)) else None 87 | let ast = if def.IsSome then Some((QuotationsConverter.convertToAst def.Value).Head) else None 88 | 89 | Assign(MemberAccess("set_" + property.Name, 90 | MemberAccess("prototype", 91 | getMemberAccess (t.Name, t.DeclaringType, t.Namespace))), 92 | if ast.IsSome then 93 | ast.Value 94 | else 95 | Function(Block([Assign(Identifier("this." + property.Name, false), Identifier("x", false))]), [Identifier("x", false)], None) 96 | ) 97 | 98 | let getInheritance (t:Type) = 99 | let baseType = getBaseType t 100 | let inherits = if baseType = t then [] else [Assign(MemberAccess("prototype", getMemberAccess (t.Name, t.DeclaringType, t.Namespace)), MemberAccess("prototype", getMemberAccess (baseType.Name, t.DeclaringType, t.Namespace)))] 101 | inherits 102 | 103 | let getAstFromType (mo:System.Type) = 104 | let rec loop (t:Type) acc = 105 | 106 | let childResults = [for ty in t.GetNestedTypes() do yield! loop ty []] 107 | let quotesAndMethods = [for m in t.GetMethods() -> 108 | (m, Microsoft.FSharp.Quotations.Expr.TryGetReflectedDefinition(m))] 109 | |> List.filter(fun (x,y) -> y.IsSome) |> List.map(fun (x,y) -> (x,y.Value)) 110 | 111 | if FSharpType.IsModule t then 112 | let moduleName = if t.Namespace = "" || t.Namespace = null then t.Name else t.Namespace + "." + t.Name 113 | 114 | let getResult (m:MethodInfo,q:Quotations.Expr) = match QuotationsConverter.convertToAst q |> List.head with 115 | //extension method support 116 | | Function(b,args,name) when m.Name.Contains(".") -> 117 | let split = m.Name.Split('.') 118 | let func = match b with 119 | | Return x -> match x with 120 | | Function(t,y,z) -> Function(t, args, None) 121 | | _ -> x 122 | | _ -> Function(b,args,None) 123 | Some(Block([ 124 | Assign(MemberAccess(split.[1], MemberAccess(split.[0], Identifier(t.Name, false))), func); 125 | Assign(MemberAccess(split.[0], Identifier(moduleName, false)), Function(Block([]), [], None)) 126 | ])) 127 | //active pattern support 128 | | Function(b,args,name) when m.Name.Contains("|") -> 129 | let name = m.Name.Replace("|", "") 130 | let func = Assign(MemberAccess(name, Identifier(moduleName, false)), Function(b,args,None)) 131 | Some(func) 132 | | Function(b,args,name) -> 133 | Some(Assign(MemberAccess(m.Name, Identifier(moduleName, false)), Function(b,args, None))) 134 | | _ -> None 135 | 136 | let result = quotesAndMethods |> List.map getResult |> List.filter(fun x -> x.IsSome) |> List.map(fun x-> x.Value) 137 | 138 | let props = [for p in t.GetProperties() do yield (p, (Microsoft.FSharp.Quotations.Expr.TryGetReflectedDefinition(p.GetGetMethod())))] 139 | |> List.filter(fun (p,x) -> x.IsSome) 140 | |> List.map(fun (p,x) -> (p,(QuotationsConverter.convertToAst x.Value).Head)) 141 | |> List.map(fun (p,x) -> Assign(MemberAccess("get_" + p.Name, Identifier(moduleName, false)), Function(Return(x), [], None))) 142 | 143 | 144 | let d = Call(Identifier("registerNamespace", false), [Ast.String(moduleName, '"')]) 145 | 146 | 147 | let mainCall = Ast.If(Identifier(moduleName + ".main", false), Call(Identifier(moduleName + ".main", false), []), None, false) 148 | 149 | 150 | [d; Block((childResults@Block(result@props)::acc) |> List.rev);mainCall] 151 | 152 | elif FSharpType.IsUnion t then 153 | let cases = FSharpType.GetUnionCases t 154 | let rdr = [for c in cases do yield FSharpValue.PreComputeUnionConstructorInfo c] 155 | let rd = [for r in rdr do yield (r,r.GetParameters())] |> List.rev 156 | 157 | let cleanName (name:string) = 158 | name.Replace("New", "").Replace("get_", "") 159 | 160 | let createPropertyGet (property:ParameterInfo, r:MethodInfo) = 161 | Assign(MemberAccess("get_" + camelCase property.Name, 162 | MemberAccess("prototype", 163 | MemberAccess(cleanName r.Name, 164 | getMemberAccess(t.Name, t.DeclaringType, t.Namespace)))), 165 | Function(Return(Identifier("this." + camelCase property.Name, false)), [], None)) 166 | 167 | 168 | 169 | let func = [for (r,parameters) in rd do yield! 170 | let name = cleanName r.Name in 171 | let values = [for p in parameters do yield (Identifier(p.Name, false), Assign(MemberAccess(camelCase(p.Name), Identifier("this", false)), Identifier(p.Name,false)))] in 172 | let construct = Assign(MemberAccess(name, getMemberAccess(t.Name, t.DeclaringType, t.Namespace)), 173 | Function(Block( [for (par,prop) in values do yield prop]), [for (par,prop) in values do yield par], None)) in 174 | 175 | let inheritance = Assign(MemberAccess("prototype", MemberAccess(name, getMemberAccess(t.Name, t.DeclaringType, t.Namespace))), 176 | New(getMemberAccess(t.Name, t.DeclaringType, t.Namespace), [], None)) in 177 | //MemberAccess("prototype", getMemberAccess(t.Name, t.DeclaringType, t.Namespace))) in 178 | let memberAccess = MemberAccess(cleanName r.Name, getMemberAccess(t.Name, t.DeclaringType, t.Namespace)) in 179 | let equals = Assign(MemberAccess("Equality", MemberAccess("prototype", memberAccess)), 180 | getEqualityFunction memberAccess (parameters |> Array.map (fun p -> p.Name) |> Array.toList) camelCase ) in 181 | 182 | let props = parameters |> Array.map (fun prop -> createPropertyGet (prop,r)) |> Array.toList in 183 | 184 | props@[equals;inheritance;construct] 185 | ] 186 | 187 | 188 | Assign(getMemberAccess (t.Name, t.DeclaringType, t.Namespace), Function(Block([]), [], None))::[Block(func)] 189 | 190 | elif t.BaseType = typeof then 191 | let values = Enum.GetValues(t) :?> int[] 192 | let enums = values |> Array.map (fun v -> (Enum.GetName(t,v), v)) |> Array.toList 193 | 194 | let func = [for (n,i) in enums do yield! 195 | let construct = Assign(MemberAccess(n, getMemberAccess(t.Name, t.DeclaringType, t.Namespace)), 196 | Function(Block([Assign(MemberAccess("Text", Identifier("this", false)), Ast.String(n,'"')); 197 | Assign(MemberAccess("Integer", Identifier("this", false)), Number(Some(i), None))]), [], None)) in 198 | 199 | let inheritance = Assign(MemberAccess("prototype", MemberAccess(n, getMemberAccess(t.Name, t.DeclaringType, t.Namespace))), 200 | MemberAccess("prototype", getMemberAccess(t.Name, t.DeclaringType, t.Namespace))) in 201 | [inheritance;construct]] 202 | 203 | let inherits = Assign(MemberAccess("prototype", getMemberAccess (t.Name, t.DeclaringType, t.Namespace)), MemberAccess("prototype", Identifier("System.Enum", false))) 204 | 205 | Assign(getMemberAccess (t.Name, t.DeclaringType, t.Namespace), Function(Block([]), [], None))::inherits::[Block(func)] 206 | else 207 | let properties = t.GetProperties() |> Array.toList 208 | let constructors = t.GetConstructors() |> Array.toList 209 | let construct = if constructors.Length > 0 then Some(constructors.Head) else None 210 | 211 | let parameters = if construct.IsSome then [for p in construct.Value.GetParameters() do yield Identifier(p.Name, false)] else [] 212 | 213 | let members = [for p in properties do yield 214 | Assign(MemberAccess(p.Name, Identifier("this", false)), 215 | let d = [for r in parameters do yield match r with 216 | | Identifier(n,l) when n.ToLower() = p.Name.ToLower() -> Some(Identifier(n,l)) 217 | | _ -> None] |> List.filter(fun i -> i.IsSome) 218 | match d with 219 | | h::[] when h.IsSome -> h.Value 220 | | _ -> getDefaultValue p 221 | 222 | )] 223 | 224 | 225 | let func = Assign(getMemberAccess(t.Name, t.DeclaringType, t.Namespace), Function(Block(members),parameters, None)) 226 | 227 | let baseType = getBaseType t 228 | let inherits = if baseType = t then [] else [Assign(MemberAccess("prototype", getMemberAccess (t.Name, t.DeclaringType, t.Namespace)), MemberAccess("prototype", getMemberAccess (baseType.Name, t.DeclaringType, baseType.Namespace)))] 229 | 230 | let q = [for (m,q) in quotesAndMethods do yield 231 | Assign(MemberAccess(m.Name, MemberAccess("prototype", getMemberAccess (t.Name, t.DeclaringType, t.Namespace))), 232 | let t = (QuotationsConverter.convertToAst q) |> List.head 233 | match t with 234 | | Function(n,args,props) -> match n with 235 | | Return(x) -> x 236 | | _ -> t 237 | | _ -> t) 238 | ] 239 | 240 | let equality = 241 | if FSharpType.IsRecord t then 242 | let propertyNames = (properties |> List.map (fun x -> x.Name)) 243 | let memberAccess = getMemberAccess(t.Name, t.DeclaringType, t.Namespace) 244 | let equalityFunction = getEqualityFunction memberAccess propertyNames (fun x -> x) 245 | let result = Assign(MemberAccess("Equality", MemberAccess("prototype", memberAccess)), equalityFunction ) 246 | [result] 247 | else 248 | [] 249 | 250 | 251 | 252 | 253 | let getProps = properties |> List.map (fun prop -> createPropertyGet (prop,t)) 254 | let setProps = if FSharpType.IsRecord t then [] else properties |> List.map (fun prop -> createPropertySet (prop,t)) 255 | let props = getProps@setProps 256 | 257 | (func::acc@inherits@equality@q@props)@childResults 258 | 259 | 260 | (loop mo []) |> List.rev 261 | -------------------------------------------------------------------------------- /FSharp.Javascript.Utilities/Parser.fs: -------------------------------------------------------------------------------- 1 | #light 2 | module FSharp.Javascript.Parser 3 | 4 | open JavascriptParser 5 | open Antlr.Runtime; 6 | open Antlr.Runtime.Tree; 7 | open FSharp.Javascript.Ast 8 | open System.Linq.Expressions 9 | 10 | //let getAst input = 11 | // let generator = new IronJS.Compiler.AstGenerator() 12 | // let ast = generator.Build(input) |> ResizeArray.toList |> List.rev 13 | // 14 | // convertFromIronJS ast 15 | 16 | let getChildSafe (node:ITree) index = 17 | let child = node.GetChild(index) 18 | if child = null then failwith "Expected child" 19 | 20 | if child.IsNil = false && child.Type = 0 then failwith ("Unexpected" + child.Text) 21 | 22 | child 23 | 24 | let rewriteIfContainsNew (node:ITree) = 25 | let rec loop (tempNode:ITree) = 26 | if tempNode = null then None else 27 | match tempNode.Type with 28 | | ES3Parser.NEW -> 29 | let child = getChildSafe tempNode 0 30 | let idNode = new CommonTree(new CommonToken(child.Type, child.Text)) 31 | 32 | tempNode.Parent.ReplaceChildren(0,0,idNode) 33 | Some(tempNode) 34 | | ES3Parser.CALL -> None 35 | | ES3Parser.PAREXPR -> None 36 | | _ -> loop (tempNode.GetChild(0)) 37 | 38 | loop node 39 | 40 | 41 | 42 | 43 | let getAst input = 44 | 45 | let lexer = new ES3Lexer(new ANTLRStringStream(input)) 46 | let parser = new ES3Parser(new CommonTokenStream(lexer)) 47 | 48 | let program = parser.program() 49 | let root = program.Tree :?> ITree 50 | 51 | 52 | 53 | let rec traverse (node:ITree) = 54 | if node = null then Ignore else 55 | match node.Type with 56 | | ES3Parser.WITH -> 57 | let left = traverse (getChildSafe node 0) 58 | let right = traverse (getChildSafe node 1) 59 | 60 | With(left,right) 61 | | ES3Parser.BLOCK -> 62 | buildBlock node 63 | | ES3Parser.RegularExpressionLiteral -> 64 | let regex = node.Text 65 | let lastIndex = regex.LastIndexOf('/') 66 | let reg = regex.Substring(1, lastIndex - 1) 67 | let modifiers = regex.Substring(lastIndex + 1) 68 | Regex(reg, modifiers) 69 | | ES3Parser.PAREXPR -> 70 | traverse (getChildSafe node 0) 71 | | ES3Parser.EXPR -> 72 | traverse (getChildSafe node 0) 73 | | ES3Parser.CEXPR -> 74 | let nodes = (if node.ChildCount > 0 then [for i in 0..(node.ChildCount - 1) -> (traverse (node.GetChild(i)))] else []) |> List.rev 75 | AssignmentBlock(nodes, false) 76 | | ES3Parser.OBJECT -> 77 | let namedProps = [for i in 0..(node.ChildCount - 1) -> 78 | let child = getChildSafe node i 79 | AutoProperty((getChildSafe child 0).Text.Trim('\'', '"'), traverse (getChildSafe child 1))] |> List.rev 80 | 81 | New(Identifier("Object", false), [], Some(namedProps)) 82 | | ES3Parser.NEW -> 83 | New(traverse (getChildSafe node 0), [], None) 84 | | ES3Parser.INSTANCEOF -> 85 | InstanceOf(traverse (getChildSafe node 0), traverse (getChildSafe node 1)) 86 | | ES3Parser.ARRAY -> 87 | let arrayElements = [for i in 0..(node.ChildCount - 1) -> 88 | let child = getChildSafe node i 89 | traverse (getChildSafe child 0)] |> List.rev 90 | NewArray(Identifier("Array", false), arrayElements) 91 | | ES3Parser.FUNCTION -> 92 | if node.ChildCount > 2 then 93 | let name = Some((getChildSafe node 0).Text) 94 | buildLambda (getChildSafe node 1) (getChildSafe node 2) name 95 | else 96 | buildLambda (getChildSafe node 0) (getChildSafe node 1) None 97 | | ES3Parser.RETURN -> 98 | if node.ChildCount = 0 then 99 | Return(Null) 100 | else 101 | Return(traverse (getChildSafe node 0)) 102 | | ES3Parser.CALL -> 103 | let newNode = rewriteIfContainsNew (getChildSafe node 0) 104 | if newNode.IsSome then 105 | let childNode = getChildSafe node 1 106 | New(traverse (getChildSafe newNode.Value 0), (if childNode.ChildCount > 0 then [for i in 0..(childNode.ChildCount - 1) -> traverse(childNode.GetChild(i))] else []) |> List.rev, None) 107 | else 108 | let childNode = getChildSafe node 1 109 | Call(traverse (getChildSafe node 0), (if childNode.ChildCount > 0 then [for i in 0..(childNode.ChildCount - 1) -> traverse( childNode.GetChild(i))] else []) |> List.rev) 110 | | ES3Parser.IF | ES3Parser.QUE -> buildIf node 111 | | ES3Parser.SWITCH -> 112 | let def = ref Null 113 | let cases = [for i in 1..(node.ChildCount - 1) -> 114 | let child = getChildSafe node i 115 | if child.Type = ES3Parser.DEFAULT then 116 | def := traverse (getChildSafe child 0) 117 | None 118 | else 119 | 120 | let caseBlock = (if child.ChildCount > 0 then [for j in 1..(child.ChildCount - 1) -> traverse (getChildSafe child j)] else []) |> List.rev 121 | if caseBlock.Length = 1 then 122 | Some(traverse (getChildSafe child 0), caseBlock.[0]) 123 | else 124 | Some(traverse (getChildSafe child 0), Block(caseBlock))] |> List.filter(fun x -> x.IsSome) |> List.map(fun x -> x.Value) |> List.rev 125 | 126 | Switch(traverse (getChildSafe node 0), def.Value, cases, null) 127 | | ES3Parser.THIS | ES3Parser.Identifier -> Identifier(node.Text, false) 128 | | ES3Parser.TRY -> 129 | if node.ChildCount > 2 then 130 | let catch = (getChildSafe node 1) 131 | let finallyNode = (getChildSafe node 2) 132 | Try(traverse (getChildSafe node 0), (if catch = null then None else Some(traverse catch)), (if finallyNode = null then None else Some(traverse finallyNode))) 133 | else 134 | let secondChild = getChildSafe node 1 135 | if secondChild.Type = ES3Parser.FINALLY then 136 | let finallyNode = getChildSafe node 1 137 | Try(traverse (getChildSafe node 0), None, (if finallyNode = null then None else Some(traverse finallyNode))) 138 | else 139 | let catch = (getChildSafe node 1) 140 | Try(traverse (getChildSafe node 0), (if catch = null then None else Some(traverse catch)), None) 141 | | ES3Parser.CATCH -> 142 | Catch(traverse (getChildSafe node 0), traverse (getChildSafe node 1)) 143 | | ES3Parser.FINALLY -> 144 | buildBlock (getChildSafe node 0) 145 | | ES3Parser.THROW -> 146 | Throw(traverse (getChildSafe node 0)) 147 | | ES3Parser.BYFIELD -> 148 | let tempNode = (getChildSafe node 0) 149 | let newNode = rewriteIfContainsNew tempNode 150 | if newNode.IsSome then 151 | New(traverse newNode.Value, [], None) 152 | else 153 | MemberAccess((getChildSafe node 1).Text, traverse (getChildSafe node 0)) 154 | | ES3Parser.BYINDEX -> 155 | let newNode = rewriteIfContainsNew(getChildSafe node 0) 156 | if newNode.IsSome then 157 | New(traverse newNode.Value, [], None) 158 | else 159 | IndexAccess(traverse (getChildSafe node 0), traverse (getChildSafe node 1)) 160 | 161 | | ES3Parser.IN -> 162 | In(traverse (getChildSafe node 1), traverse (getChildSafe node 0)) 163 | | ES3Parser.WHILE -> 164 | While(traverse (getChildSafe node 0), traverse (getChildSafe node 1), true) 165 | | ES3Parser.FOR | ES3Parser.FORSTEP -> 166 | let body = traverse (getChildSafe node 1) 167 | let typ = getChildSafe node 0 168 | 169 | if typ.Type = ES3Parser.FORSTEP then 170 | let init = getChildSafe typ 0 171 | let test = getChildSafe typ 1 172 | let incr = getChildSafe typ 2 173 | 174 | let initNode = if init.ChildCount > 0 then traverse init else Null 175 | let testNode = if test.ChildCount > 0 then traverse test else Boolean(true) 176 | let incrNode = if incr.ChildCount > 0 then traverse incr else Null 177 | 178 | ForStepNode(initNode, testNode, incrNode, body) 179 | else 180 | ForInNode(traverse (getChildSafe typ 0), traverse (getChildSafe typ 1), body) 181 | 182 | | ES3Parser.DO -> 183 | let body = traverse (getChildSafe node 0) 184 | let test = traverse (getChildSafe node 1) 185 | While(test, body, false) 186 | | ES3Parser.BREAK -> 187 | if node.ChildCount = 0 then 188 | BreakNode(null) 189 | else 190 | BreakNode((getChildSafe node 0).Text) 191 | | ES3Parser.CONTINUE -> 192 | if node.ChildCount = 0 then 193 | Continue(null) 194 | else 195 | Continue((getChildSafe node 0).Text) 196 | // | ES3Parser.LABELLED -> 197 | // let label = getChildSafe node 0 198 | // let target = traverse (getChildSafe node 1) 199 | // 200 | // 201 | | ES3Parser.DecimalLiteral -> 202 | if node.Text.Contains(".") || node.Text.Contains("E") then 203 | Number(None, Some(System.Double.Parse(node.Text, System.Globalization.CultureInfo.InvariantCulture))) 204 | else 205 | Number(Some(System.Int32.Parse(node.Text, System.Globalization.CultureInfo.InvariantCulture)), None) 206 | | ES3Parser.StringLiteral -> 207 | String(node.Text.Substring(1, node.Text.Length - 2), node.Text.[0]) 208 | | ES3Parser.NULL -> Null 209 | | ES3Parser.TRUE | ES3Parser.FALSE -> Boolean(node.Type = 5) 210 | | ES3Parser.VAR -> 211 | let nodes = [for i in 0..(node.ChildCount - 1) -> 212 | let assignNode = traverse (getChildSafe node i) 213 | match assignNode with 214 | | Assign(l,r) -> Assign((match l with 215 | | Identifier(x,y) -> Identifier(x, false) 216 | | t -> t), r) 217 | | Identifier(n, isLocal) -> Identifier(n, true) 218 | | _ -> assignNode] |> List.rev 219 | 220 | if nodes.Length = 1 then 221 | nodes.[0] 222 | else 223 | AssignmentBlock(nodes, true) 224 | | ES3Parser.ASSIGN -> 225 | let left = getChildSafe node 0 226 | let right = getChildSafe node 1 227 | Assign(traverse left, traverse right) 228 | | ES3Parser.ADD -> buildBinaryOp node ExpressionType.Add 229 | | ES3Parser.SUB -> buildBinaryOp node ExpressionType.Subtract 230 | | ES3Parser.MUL -> buildBinaryOp node ExpressionType.Multiply 231 | | ES3Parser.DIV -> buildBinaryOp node ExpressionType.Divide 232 | | ES3Parser.MOD -> buildBinaryOp node ExpressionType.Modulo 233 | | ES3Parser.ADDASS -> buildBinaryOpAssign node ExpressionType.Add 234 | | ES3Parser.SUBASS -> buildBinaryOpAssign node ExpressionType.Subtract 235 | | ES3Parser.MULASS -> buildBinaryOpAssign node ExpressionType.Multiply 236 | | ES3Parser.DIVASS -> buildBinaryOpAssign node ExpressionType.Divide 237 | | ES3Parser.MODASS -> buildBinaryOpAssign node ExpressionType.Modulo 238 | | ES3Parser.EQ -> buildBinaryOp node ExpressionType.Equal 239 | | ES3Parser.NEQ -> buildBinaryOp node ExpressionType.NotEqual 240 | | ES3Parser.SAME -> buildStrictCompare node ExpressionType.Equal 241 | | ES3Parser.NSAME -> buildStrictCompare node ExpressionType.NotEqual 242 | | ES3Parser.LT -> buildBinaryOp node ExpressionType.LessThan 243 | | ES3Parser.GT -> buildBinaryOp node ExpressionType.GreaterThan 244 | | ES3Parser.GTE -> buildBinaryOp node ExpressionType.GreaterThanOrEqual 245 | | ES3Parser.LTE -> buildBinaryOp node ExpressionType.LessThanOrEqual 246 | | ES3Parser.SHR -> buildBinaryOp node ExpressionType.RightShift 247 | | ES3Parser.SHL -> buildBinaryOp node ExpressionType.LeftShift 248 | | ES3Parser.SHU -> UnsignedRightShift(traverse (getChildSafe node 0), traverse (getChildSafe node 1)) 249 | | ES3Parser.SHRASS -> buildBinaryOpAssign node ExpressionType.RightShift 250 | | ES3Parser.SHLASS -> buildBinaryOpAssign node ExpressionType.LeftShift 251 | | ES3Parser.SHUASS -> 252 | Assign(traverse (getChildSafe node 0), UnsignedRightShift(traverse (getChildSafe node 0), traverse (getChildSafe node 1))) 253 | | ES3Parser.AND -> buildBinaryOp node ExpressionType.And 254 | | ES3Parser.OR -> buildBinaryOp node ExpressionType.Or 255 | | ES3Parser.XOR -> buildBinaryOp node ExpressionType.ExclusiveOr 256 | | ES3Parser.ANDASS -> buildBinaryOpAssign node ExpressionType.And 257 | | ES3Parser.ORASS -> buildBinaryOpAssign node ExpressionType.Or 258 | | ES3Parser.XORASS -> buildBinaryOpAssign node ExpressionType.ExclusiveOr 259 | | ES3Parser.LAND -> buildLogicalOp node ExpressionType.AndAlso 260 | | ES3Parser.LOR -> buildLogicalOp node ExpressionType.OrElse 261 | | ES3Parser.PINC -> buildIncDecOp node ExpressionType.PostIncrementAssign 262 | | ES3Parser.PDEC -> buildIncDecOp node ExpressionType.PostDecrementAssign 263 | | ES3Parser.INC -> buildIncDecOp node ExpressionType.PreIncrementAssign 264 | | ES3Parser.DEC -> buildIncDecOp node ExpressionType.PreDecrementAssign 265 | | ES3Parser.INV -> buildUnaryOp node ExpressionType.OnesComplement 266 | | ES3Parser.NOT -> buildUnaryOp node ExpressionType.Not 267 | | ES3Parser.NEG -> buildUnaryOp node ExpressionType.Negate 268 | | ES3Parser.POS -> buildUnaryOp node ExpressionType.UnaryPlus 269 | | ES3Parser.TYPEOF -> TypeOf(traverse (getChildSafe node 0)) 270 | | ES3Parser.VOID -> Void(traverse (getChildSafe node 0)) 271 | | ES3Parser.DELETE -> Delete(traverse (getChildSafe node 0)) 272 | | _ -> failwith "javascript parser failed" 273 | and buildUnaryOp node op = 274 | UnaryOp(traverse (getChildSafe node 0), op) 275 | and buildIncDecOp node op = 276 | match op with 277 | | ExpressionType.PreIncrementAssign | ExpressionType.PreDecrementAssign -> 278 | Assign(traverse (getChildSafe node 0), BinaryOp(traverse (getChildSafe node 0), Number(Some(1), None), if op = ExpressionType.PreIncrementAssign then ExpressionType.Add else ExpressionType.Subtract)) 279 | | ExpressionType.PostIncrementAssign -> PostfixOperator(traverse (getChildSafe node 0), ExpressionType.PostIncrementAssign) 280 | | ExpressionType.PostDecrementAssign -> PostfixOperator(traverse (getChildSafe node 0), ExpressionType.PostDecrementAssign) 281 | | _ -> failwith "invalid inc dec op" 282 | and buildLogicalOp node op = 283 | Logical(traverse (getChildSafe node 0), traverse (getChildSafe node 1), op) 284 | and buildBinaryOp node op = 285 | BinaryOp(traverse (getChildSafe node 0), traverse (getChildSafe node 1), op) 286 | and buildBinaryOpAssign node op = 287 | Assign(traverse (getChildSafe node 0), BinaryOp(traverse (getChildSafe node 0), traverse (getChildSafe node 1), op)) 288 | and buildStrictCompare node op = 289 | StrictCompare(traverse (getChildSafe node 0), traverse (getChildSafe node 1), op) 290 | and buildIf ifNode = 291 | let elseNode = ifNode.GetChild(2) 292 | If(traverse (getChildSafe ifNode 0), traverse (getChildSafe ifNode 1), (if elseNode = null then None else Some(traverse elseNode)), ifNode.Type = ES3Parser.QUE) 293 | and buildLambda argsNode blockNode name = 294 | let args = (if argsNode.ChildCount > 0 then [for i in 0..(argsNode.ChildCount - 1) -> Identifier((getChildSafe argsNode i).Text, false)] else []) 295 | let body = buildBlock blockNode 296 | Function(body, args, name) 297 | and buildBlock blockNode = 298 | let nodes = (if blockNode.ChildCount > 0 then [for i in 0..(blockNode.ChildCount - 1) -> (traverse (blockNode.GetChild(i)))] else []) |> List.rev 299 | if nodes.Length = 1 then 300 | nodes.[0] 301 | else 302 | Block(nodes) 303 | 304 | 305 | 306 | if root.IsNil then 307 | [for i in 0..(root.ChildCount - 1) do yield (traverse (root.GetChild(i)))] |> List.rev 308 | else 309 | [traverse root] -------------------------------------------------------------------------------- /FSharp.Javascript/Dom.fs: -------------------------------------------------------------------------------- 1 | module FSharp.Javascript.Dom 2 | 3 | type Window() = 4 | [] 5 | val mutable closed : bool 6 | [] 7 | val mutable defaultStatus : string 8 | [] 9 | val mutable document : Document 10 | [] 11 | val mutable frameElement : HtmlElement 12 | [] 13 | val mutable frames : System.Array 14 | [] 15 | val mutable history : History 16 | [] 17 | val mutable innerHeight : float 18 | [] 19 | val mutable innerWidth : float 20 | [] 21 | val mutable length : float 22 | [] 23 | val mutable location : Location 24 | [] 25 | val mutable name : string 26 | [] 27 | val mutable navigator : Navigator 28 | [] 29 | val mutable opener : Window 30 | [] 31 | val mutable outerHeight : float 32 | [] 33 | val mutable outerWidth : float 34 | [] 35 | val mutable parent : Window 36 | [] 37 | val mutable screen : Screen 38 | [] 39 | val mutable self : Window 40 | [] 41 | val mutable status : string 42 | [] 43 | val mutable top : Window 44 | [] 45 | val mutable window : Window 46 | 47 | member this.alert(x) = () 48 | member this.attachEvent(event:string, notify) = () 49 | member this.blur() = () 50 | member this.captureEvents(x) = () 51 | member this.clearInterval(x:float) = () 52 | member this.clearTimeout(x:float) = () 53 | member this.close() = () 54 | member this.confirm(x) = true 55 | member this.createPopup() = new Window() 56 | member this.detachEvent(event:string, notify) = () 57 | member this.focus() = () 58 | member this.moveBy(x:float, y:float) = () 59 | member this.moveTo(x:float, y:float) = () 60 | member this.navigate(url:string) = () 61 | member this.``open``(url:string, windowName:string, features:string) = new Window() 62 | member this.print() = () 63 | member this.prompt(message:string, defaultReply:string) = "" 64 | member this.resizeBy() = () 65 | member this.resizeTo() = () 66 | member this.ScriptEngineMajorVersion() = "" 67 | member this.ScriptEngineMinorVersion() = "" 68 | member this.scroll() = () 69 | member this.scrollBy() = () 70 | member this.scrollTo() = () 71 | member this.setInterval(func:unit -> unit, timeout:float) = float 0 72 | member this.setTimeout(func:unit -> unit, timeout:float) = float 0 73 | member this.showModalDialog(url:string) = new Window() 74 | member this.showModelessDialog(url:string) = new Window() 75 | 76 | and Document() = 77 | [] 78 | val mutable documentElement : Element 79 | [] 80 | val mutable anchors : HtmlElement array 81 | [] 82 | val mutable applets : Node array 83 | [] 84 | val mutable body : HtmlElement 85 | [] 86 | val mutable cookie : string 87 | [] 88 | val mutable domain : string 89 | [] 90 | val mutable embeds : System.Array 91 | [] 92 | val mutable forms : HtmlElement array 93 | [] 94 | val mutable frames : HtmlElement array 95 | [] 96 | val mutable images : HtmlElement array 97 | [] 98 | val mutable layers : System.Array 99 | [] 100 | val mutable links : HtmlElement array 101 | [] 102 | val mutable location : Location 103 | [] 104 | val mutable parentWindow : Window 105 | [] 106 | val mutable plugins : System.Array 107 | [] 108 | val mutable referrer : string 109 | [] 110 | val mutable scripts : System.Array 111 | [] 112 | val mutable styleSheets : System.Array 113 | [] 114 | val mutable title : string 115 | [] 116 | val mutable uniqueID : string 117 | [] 118 | val mutable url : string 119 | [] 120 | val mutable window : Window 121 | 122 | member this.createElement(tagName:string) = Element() 123 | member this.createTextNode(data:string) = Text() 124 | 125 | member this.write(text:string) = () 126 | member this.getElementById(x:string) = HtmlElement() 127 | member this.getElementsByTagName(tagName:string) = [||] : HtmlElement array 128 | member this.getElementsByName(elementName:string) = [||] : HtmlElement array 129 | 130 | 131 | member this.attachEvent(event:string, x) = true 132 | member this.captureEvents(x) = () 133 | member this.close() = () 134 | member this.createStyleSheet(url:string, index:float) = StyleSheet() 135 | member this.``open``() = () 136 | member this.writeln(text:string) = () 137 | 138 | and StyleSheet() = 139 | [] 140 | val mutable href : string 141 | [] 142 | val mutable rules : System.Array 143 | 144 | member this.addRule(selector:string, style:string, index:float) = float 0 145 | member this.removeRule(index:float) = () 146 | 147 | and Node() = 148 | [] 149 | val mutable attributes : Node array 150 | [] 151 | val mutable childNodes : Node array 152 | [] 153 | val mutable firstChild : Node 154 | [] 155 | val mutable lastChild : Node 156 | [] 157 | val mutable nextSibling : Node 158 | [] 159 | val mutable nodeName : Node 160 | [] 161 | val mutable nodeType : float 162 | [] 163 | val mutable nodeValue : string 164 | [] 165 | val mutable ownderDocument : Document 166 | [] 167 | val mutable parentElement : Node 168 | [] 169 | val mutable parentNode : Node 170 | [] 171 | val mutable previousSibling : Node 172 | 173 | member this.appendChild(newChild:Node) = Node() 174 | member this.cloneNode(b:bool) = Node() 175 | member this.hasChildNodes() = false 176 | member this.insertBefore(newChild:Node, refChild:Node) = Node() 177 | member this.removeChild(oldChild:Node) = Node() 178 | member this.removeNode(removeChildren:bool) = Node() 179 | member this.replaceChild(newChild:Node, refChild:Node) = Node() 180 | 181 | and Element() = 182 | inherit Node() 183 | 184 | [] 185 | val mutable tagName : string 186 | 187 | member this.getAttribute(name:string) = "" 188 | member this.getElementsByTagName(name:string) = [||] : HtmlElement array 189 | member this.normalize() = () 190 | member this.removeAttribute(name:string) = () 191 | member this.setAttribute(name:string, value:string) = () 192 | 193 | and HtmlElement() = 194 | inherit Element() 195 | 196 | [] 197 | val mutable children : HtmlElement array 198 | [] 199 | val mutable className : string 200 | [] 201 | val mutable dir : string 202 | [] 203 | val mutable document : Document 204 | [] 205 | val mutable id : string 206 | [] 207 | val mutable innerHTML : string 208 | [] 209 | val mutable innerText : string 210 | [] 211 | val mutable lang : string 212 | [] 213 | val mutable offsetHeight : float 214 | [] 215 | val mutable offsetLeft : float 216 | [] 217 | val mutable offsetParent : float 218 | [] 219 | val mutable offsetTop : float 220 | [] 221 | val mutable offsetWidth : float 222 | [] 223 | val mutable title : string 224 | [] 225 | val mutable uniqueID : string 226 | 227 | member this.addBehavior(url:string) = float 0 228 | member this.attachEvent(event:string, x) = true 229 | member this.detachEvent(event:string, x) = () 230 | member this.insertAdjavacentHTML(where:string, html:string) = () 231 | member this.removeBehavior(x:float) = true 232 | 233 | 234 | and HtmlImageElement() = 235 | inherit HtmlElement() 236 | 237 | [] 238 | val mutable alt : string 239 | [] 240 | val mutable src : string 241 | [] 242 | val mutable useMap : string 243 | [] 244 | val mutable isMap : bool 245 | [] 246 | val mutable width : float 247 | [] 248 | val mutable height : float 249 | [] 250 | val mutable naturalWidth : float 251 | [] 252 | val mutable naturalHeight : float 253 | [] 254 | val mutable complete : bool 255 | 256 | and MediaError() = 257 | [] 258 | val mutable MEDIA_ERR_ABORTED : float 259 | [] 260 | val mutable MEDIA_ERR_NETWORK : float 261 | [] 262 | val mutable MEDIA_ERR_DECODE : float 263 | [] 264 | val mutable MEDIA_ERR_SRC_NOT_SUPPORTED : float 265 | [] 266 | val mutable code : float 267 | 268 | and TimeRanges() = 269 | [] 270 | val mutable length : float 271 | member this.start(index:float) = float 0 272 | member this.``end``(index:float) = float 0 273 | 274 | and DocumentFragment() = class end 275 | 276 | and TimedTrackCue() = 277 | [] 278 | val mutable track : TimedTrack 279 | [] 280 | val mutable id : string 281 | [] 282 | val mutable startTime : float 283 | [] 284 | val mutable endTime : float 285 | [] 286 | val mutable pauseOnExit : bool 287 | [] 288 | val mutable direction : string 289 | [] 290 | val mutable snapToLines : bool 291 | [] 292 | val mutable linePosition : float 293 | [] 294 | val mutable textPosition : float 295 | [] 296 | val mutable size : float 297 | [] 298 | val mutable alignment : string 299 | [] 300 | val mutable voice : string 301 | 302 | member this.getCuseAsSource() = "" 303 | member this.getCueAsHtml() = DocumentFragment() 304 | 305 | [] 306 | val mutable onenter : unit -> unit 307 | [] 308 | val mutable onexit : unit -> unit 309 | 310 | and TimedTrackCueList() = 311 | [] 312 | val mutable length : float 313 | 314 | member this.getCueById(id:string) = TimedTrackCue() 315 | and TimedTrack() = 316 | 317 | [] 318 | val mutable kind : string 319 | [] 320 | val mutable label : string 321 | [] 322 | val mutable language : string 323 | [] 324 | val mutable NONE : float 325 | [] 326 | val mutable LOADING : float 327 | [] 328 | val mutable LOADED : float 329 | [] 330 | val mutable ERROR : float 331 | [] 332 | val mutable readyState : float 333 | [] 334 | val mutable onload : unit -> unit 335 | [] 336 | val mutable onerror : unit -> unit 337 | [] 338 | val mutable OFF : float 339 | [] 340 | val mutable HIDDEN : float 341 | [] 342 | val mutable SHOWING : float 343 | [] 344 | val mutable mode : float 345 | [] 346 | val mutable cues : TimedTrackCueList 347 | [] 348 | val mutable activeCues : TimedTrackCueList 349 | [] 350 | val mutable oncuechange : unit -> unit 351 | 352 | and MutableTimedTrack() = 353 | inherit TimedTrack() 354 | 355 | member this.addCue(cue:TimedTrackCue) = () 356 | member this.removeCue(cue:TimedTrackCue) = () 357 | 358 | and HtmlMediaElement() = 359 | inherit HtmlElement() 360 | 361 | [] 362 | val mutable error : MediaError 363 | [] 364 | val mutable src : string 365 | [] 366 | val mutable NETWORK_EMPTY : float 367 | [] 368 | val mutable NETWORK_IDLE : float 369 | [] 370 | val mutable NETWORK_LOADING : float 371 | [] 372 | val mutable NETWORK_NO_SOURCE : float 373 | [] 374 | val mutable networkState : float 375 | [] 376 | val mutable preload : string 377 | [] 378 | val mutable buffered : TimeRanges 379 | [] 380 | val mutable HAVE_NOTHING : float 381 | [] 382 | val mutable HAVE_METADATA : float 383 | [] 384 | val mutable HAVE_CURRENT_DATA : float 385 | [] 386 | val mutable HAVE_FUTURE_DATA : float 387 | [] 388 | val mutable HAVE_ENOUGH_DATA : float 389 | [] 390 | val mutable readyState : float 391 | [] 392 | val mutable seeking : bool 393 | [] 394 | val mutable currentTime : float 395 | [] 396 | val mutable initialTime : float 397 | [] 398 | val mutable duration : float 399 | [] 400 | val mutable startOffsetTime : System.DateTime 401 | [] 402 | val mutable paused : bool 403 | [] 404 | val mutable defaultPlaybackRate : float 405 | [] 406 | val mutable playbackRate : float 407 | [] 408 | val mutable played : TimeRanges 409 | [] 410 | val mutable seekable : TimeRanges 411 | [] 412 | val mutable ended : bool 413 | [] 414 | val mutable autoplay : bool 415 | [] 416 | val mutable loop : bool 417 | [] 418 | val mutable controls : bool 419 | [] 420 | val mutable volumne : float 421 | [] 422 | val mutable muted : bool 423 | [] 424 | val mutable tracks : TimedTrack array 425 | 426 | 427 | 428 | member this.load() = () 429 | member this.canPlayType(typ:string) = "" 430 | member this.play() = () 431 | member this.pause() = () 432 | member this.addTrack(kind:string) = MutableTimedTrack() 433 | 434 | and HtmlVideoElement() = 435 | inherit HtmlMediaElement() 436 | 437 | [] 438 | val mutable width : float 439 | [] 440 | val mutable height : float 441 | [] 442 | val mutable videoWidth : float 443 | [] 444 | val mutable videoHeight : float 445 | [] 446 | val mutable poster : string 447 | 448 | and CharacterData() = 449 | inherit Node() 450 | 451 | [] 452 | val mutable data : string 453 | [] 454 | val mutable length : float 455 | 456 | member this.appendData(arg:string) = () 457 | member this.deleteData(offset:float, count:float) = () 458 | member this.insertData(offset:float, arg:string) = () 459 | member this.replaceData(offset:float, count:float, arg:string) = () 460 | member this.substringData(offset:float, count:float) = "" 461 | 462 | and Text() = 463 | inherit CharacterData() 464 | 465 | member this.splitText(offset:float) = Text() 466 | 467 | and History() = 468 | [] 469 | val mutable current : string 470 | [] 471 | val mutable next : string 472 | [] 473 | val mutable previous : string 474 | 475 | member this.back() = () 476 | member this.forward() = () 477 | member this.go(x) = () 478 | 479 | and Location() = 480 | [] 481 | val mutable hash : string 482 | [] 483 | val mutable host : string 484 | [] 485 | val mutable hostname : string 486 | [] 487 | val mutable href : string 488 | [] 489 | val mutable pathname : string 490 | [] 491 | val mutable port : string 492 | [] 493 | val mutable protocol : string 494 | [] 495 | val mutable search : string 496 | 497 | member this.assign(url:string) = () 498 | member this.reload(b:bool) = () 499 | member this.replace(url:string) = () 500 | 501 | and Navigator() = 502 | [] 503 | val mutable appCodeName : string 504 | [] 505 | val mutable appMinorVersion : string 506 | [] 507 | val mutable appName : string 508 | [] 509 | val mutable appVersion : string 510 | [] 511 | val mutable browserLanguage : string 512 | [] 513 | val mutable cookieEnabled : bool 514 | [] 515 | val mutable cpuClass : string 516 | [] 517 | val mutable isWebKing : bool 518 | [] 519 | val mutable mimeTypes : System.Array 520 | [] 521 | val mutable online : bool 522 | [] 523 | val mutable platform : string 524 | [] 525 | val mutable plugins : Plugin 526 | [] 527 | val mutable userAgent : string 528 | 529 | member this.getContext() = new WebKingContext() 530 | member this.javaEnabled() = false 531 | 532 | 533 | and Plugin() = 534 | member this.refresh() = () 535 | and WebKingContext() = 536 | member this.clear() = () 537 | member this.get(key:string) = new obj() 538 | member this.getContext(typ:string) = new WebKingContext() 539 | member this.getContextContaining(name:string) = new WebKingContext() 540 | member this.getContextName() = "" 541 | member this.getContextType() = "" 542 | member this.getKeys() = seq { yield "" } 543 | member this.getNamedContext(name:string) = () 544 | member this.getParentContext() = () 545 | member this.put(key:string, value:obj) = () 546 | 547 | and Screen() = 548 | [] 549 | val mutable availHeight : float 550 | [] 551 | val mutable availLeft : float 552 | [] 553 | val mutable availTop : float 554 | [] 555 | val mutable availWidth : float 556 | [] 557 | val mutable colorDepth : float 558 | [] 559 | val mutable height : float 560 | [] 561 | val mutable pixelDepth : float 562 | [] 563 | val mutable width : float 564 | 565 | and Math() = 566 | [] 567 | val mutable E : float 568 | [] 569 | val mutable LN2 : float 570 | [] 571 | val mutable LN10 : float 572 | [] 573 | val mutable LOG2E : float 574 | [] 575 | val mutable LOG10E : float 576 | [] 577 | val mutable PI : float 578 | [] 579 | val mutable SQRT1_2 : float 580 | [] 581 | val mutable SQRT2 : float 582 | 583 | member this.abs(x:float) = float 0 584 | member this.acos(x:float) = float 0 585 | member this.asin(x:float) = float 0 586 | member this.atan(x:float) = float 0 587 | member this.atan2(x:float) = float 0 588 | member this.ceil(x:float) = float 0 589 | member this.cose(x:float) = float 0 590 | member this.exp(x:float) = float 0 591 | member this.floor(x:float) = float 0 592 | member this.log(x:float) = float 0 593 | member this.pow(x,y) = float 0 594 | member this.random() = float 0 595 | member this.round(x:float) = float 0 596 | member this.sin(x:float) = float 0 597 | member this.sqrt(x:float) = float 0 598 | member this.tan(x:float) = float 0 599 | 600 | let window = new Window() 601 | let document = window.document 602 | 603 | let Math = new Math() 604 | 605 | let alert x = window.alert(x) 606 | 607 | --------------------------------------------------------------------------------