├── samples ├── test.hxml ├── snippets │ ├── double.as │ ├── new.as │ └── expr.as ├── ForTest.as ├── Test.hx ├── Test.as ├── AsWingApplication.as └── GridLayout.as ├── as3tohaxe-mac.zip ├── definitions └── AS3_definitions.rar ├── .gitignore ├── Parseit.hs ├── README ├── Tokenize.hs ├── ActionhaXe ├── CLArgs.hs ├── Prim.hs ├── Lexer.hs ├── Data.hs ├── Parser.hs └── Translator.hs ├── Lexitall.hs ├── as3tohaxe.hs ├── System └── Console │ └── ParseArgs.hs └── LICENSE /samples/test.hxml: -------------------------------------------------------------------------------- 1 | -swf-version 10 2 | -swf test.swf 3 | -main Test 4 | -------------------------------------------------------------------------------- /as3tohaxe-mac.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekrelief/as3tohaxe/HEAD/as3tohaxe-mac.zip -------------------------------------------------------------------------------- /definitions/AS3_definitions.rar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekrelief/as3tohaxe/HEAD/definitions/AS3_definitions.rar -------------------------------------------------------------------------------- /samples/snippets/double.as: -------------------------------------------------------------------------------- 1 | 2e+5 2 | 3.e-2 3 | 1 4 | .1 5 | .1e-2 6 | .1e+2 7 | .1e2 8 | 3.14 9 | 10.12e+10 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Translate 2 | Tokenize 3 | Lexitall 4 | Parseit 5 | template 6 | *.swf 7 | *.hi 8 | *.o 9 | *.swp 10 | *.hx 11 | as3tohaxe 12 | header 13 | prepend 14 | -------------------------------------------------------------------------------- /samples/snippets/new.as: -------------------------------------------------------------------------------- 1 | package { 2 | 3 | public class Test { 4 | public function Test(){ 5 | var a:Object = new Object.prop(); 6 | var b:Sprite = a.b[(1)].t; 7 | var director:XML = loan.(DIRECTOR); 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /samples/snippets/expr.as: -------------------------------------------------------------------------------- 1 | package test { 2 | public class Test { 3 | static public var _a:int = 0; 4 | public var d:int = 0, b:String = "hi", c:Object = {a:0, b:"hi"}; 5 | public var e:int = 1; 6 | 7 | public function Test(){ 8 | 9 | var c1:int = ++a.b[(1)].t; 10 | //var c2:int = 1 + 3 * 2 + 1 >> 2; 11 | //var c3:Sprite = container.getChild(1) as Sprite; 12 | //var c4:Boolean = this instanceof Sprite; 13 | //var a:int = 1 ? 2 ? 4 : 5 : 3; 14 | //a = b = 1; 15 | //doSomething(1+a); 16 | //this.addChild(textField); 17 | //function() { "test"} 18 | //var a:int = 0, b:String = "hi", c:Object = {a:0, b:"hi"}; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /samples/ForTest.as: -------------------------------------------------------------------------------- 1 | package 2 | { 3 | import flash.display.Sprite; 4 | import flash.text.TextField; 5 | 6 | public class ForTest extends Sprite 7 | { 8 | public function ForTest(){ 9 | var txt:TextField = new TextField(); 10 | 11 | for(var i:uint = 0; i < 10; i++) 12 | { 13 | txt.appendText(i+" "); 14 | } 15 | 16 | for(var j = 5; j < 10; j++){ 17 | txt.appendText(j+" "); 18 | } 19 | 20 | addChild(txt); 21 | 22 | var arr:Array = [1,2,3] 23 | for each( k in arr) { 24 | trace(k); 25 | } 26 | 27 | for(var l:int = 0; l < 32; l+=8) { 28 | trace(l); 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /samples/Test.hx: -------------------------------------------------------------------------------- 1 | 2 | 3 | import flash.display.Sprite; 4 | import flash.text.TextField; 5 | 6 | class Test extends Sprite 7 | { 8 | static function main() { 9 | var txt:TextField = new TextField(); 10 | 11 | var o:Dynamic = {red:0xFF0000, green:0x00FF00, blue:0x0000FF, msg:"hello"}; 12 | 13 | var r:EReg = ~/hello/gi; 14 | 15 | var x:Xml = Xml.parse(" 16 | 17 | "); 18 | 19 | //txt.text = o.red; 20 | var ar:Array = [1,2,3,4]; 21 | 22 | var a:Int = 0; 23 | var i:Int = (a); 24 | 25 | var f:Dynamic = function ():String { return "f";}; 26 | 27 | txt.appendText(a+" "+i+" "+ f()); 28 | 29 | addChild(txt); 30 | 31 | if (o.msg == "hello") { 32 | trace("in if block"); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /samples/Test.as: -------------------------------------------------------------------------------- 1 | package 2 | { 3 | import flash.display.Sprite; 4 | import flash.text.TextField; 5 | 6 | public class Test extends Sprite 7 | { 8 | public function Test(){ 9 | var txt:TextField = new TextField(); 10 | 11 | var o:Object = {red:0xFF0000, green:0x00FF00, blue:0x0000FF, msg:"hello"}; 12 | 13 | var r:RegExp = /hello/gi; 14 | 15 | var x:XML = 16 | 17 | ; 18 | 19 | //txt.text = o.red; 20 | var ar:Array = [1,2,3,4]; 21 | 22 | var a:int = 0; 23 | var i:int = (a); 24 | 25 | var f:Function = function lambda():String { return "f";}; 26 | 27 | txt.appendText(a+" "+i+" "+ f()); 28 | 29 | addChild(txt); 30 | 31 | if (o.msg == "hello") { 32 | trace("in if block"); 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Parseit.hs: -------------------------------------------------------------------------------- 1 | {- 2 | as3tohaxe - An Actionscript 3 to haXe source file translator 3 | Copyright (C) 2008 Don-Duong Quach 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | -} 18 | -- Parse a file 19 | 20 | import ActionhaXe.Lexer 21 | import ActionhaXe.Prim 22 | import ActionhaXe.Parser 23 | import System.Environment (getArgs) 24 | 25 | 26 | 27 | main = do args <- getArgs 28 | let filename = args!!0 29 | contents <- readFile filename 30 | let tokens = runLexer "" contents 31 | case parseTokens filename tokens of 32 | Right ast -> print ast 33 | Left err -> print err 34 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | as3tohaxe - An Actionscript 3 to haXe source file converter written in Haskell 2 | Copyright (C) 2008-2009 Don-Duong Quach 3 | 4 | This is NOT a complete converter. It is not possible for haXe to override the 5 | getters and setters of native Flash classes (e.g. Sprite), so converting your 6 | as3 code to haxe completely is not possible as far as I know. 7 | 8 | So I stopped working on the project, but the code and executable may still be 9 | useful to someone. 10 | 11 | For more info check visit: 12 | http://www.github.com/geekrelief/as3tohaxe 13 | http://geekrelief.wordpress.com 14 | 15 | -- Running -- 16 | Type 'as3tohaxe' and a directory or file to convert. 17 | A directory named "hx_output" will be created in the current 18 | directory if necessary. The supplied ".as" files will be 19 | translated into haxe files and stored there. If the command 20 | is run more than once, and pre-existing files will be overwritten. 21 | 22 | -- Binary -- 23 | Binaries for Mac OSX Leopard and Windows are available under 24 | the Files section of the as3tohaxe google group. 25 | 26 | -- Compiling -- 27 | Requirements 28 | - The source http://www.github.com/geekrelief/as3tohaxe 29 | - GHC (6.10.1, 6.8.3) http://www.haskell.org/ghc/ 30 | - Cabal (1.6.0.1) for parsec http://www.haskell.org/cabal/ 31 | - parsec 3 http://hackage.haskell.org/cgi-bin/hackage-scripts/package/parsec 32 | 33 | Compile with: ghc --make -XDeriveDataTypeable as3tohaxe.hs 34 | or the './build' script 35 | 36 | -- License -- 37 | This program and its source is GPL licensed. Please read the LICENSE 38 | for more details. 39 | -------------------------------------------------------------------------------- /Tokenize.hs: -------------------------------------------------------------------------------- 1 | {- 2 | as3tohaxe - An Actionscript 3 to haXe source file translator 3 | Copyright (C) 2008 Don-Duong Quach 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | -} 18 | module Main where 19 | 20 | import ActionhaXe.Lexer 21 | 22 | import System.Environment (getArgs) 23 | import Text.PrettyPrint 24 | 25 | format:: Token -> Doc 26 | format t = parens (hcat [text (tokenSource t), space, int (tokenLine t), colon, int (tokenCol t) ]) <+> text (tokenItemS t) 27 | 28 | unknowns ts = [ format t | t@(s, TokenUnknown a) <- ts] 29 | comments ts = [ format t | t@(s, TokenComment a) <- ts] 30 | strings ts = [ format t | t@(s, TokenString a) <- ts] 31 | xmls ts = [ format t | t@(s, TokenXml a) <- ts] 32 | 33 | main = do args <- getArgs 34 | let filename = args!!0 35 | contents <- readFile filename 36 | let tokens = runLexer "" contents 37 | putStrLn $ render $ hcat $ punctuate (text "\n") $ unknowns tokens 38 | putStrLn "\n\nTokenized--" 39 | print tokens 40 | 41 | -------------------------------------------------------------------------------- /ActionhaXe/CLArgs.hs: -------------------------------------------------------------------------------- 1 | {- 2 | as3tohaxe - An Actionscript 3 to haXe source file translator 3 | Copyright (C) 2008 Don-Duong Quach 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | -} 18 | module ActionhaXe.CLArgs (CLArg(..), Conf(..), clargs) where 19 | 20 | import System.Console.ParseArgs 21 | import Data.Generics 22 | import Data.Map 23 | 24 | data CLArg = NumberToInt 25 | | NoCarriage 26 | | CreateImports 27 | | Input 28 | | OutputDir 29 | deriving (Eq, Ord, Show, Data, Typeable) 30 | 31 | data Conf = Conf{ confArgs::Args CLArg, confInput::String, confOutput::String, imports::Map String [String] } 32 | | ConfNone 33 | deriving (Show, Data, Typeable) 34 | 35 | initArg f desc = Arg{ argIndex = f, argAbbr = Nothing, argName = Nothing, argData = Nothing, argDesc = desc } 36 | 37 | clargs = 38 | [ 39 | (initArg NumberToInt "translate :Number to :Int (default :Float)"){ argAbbr = Just 'i', argName = Just "intnum" } 40 | , (initArg NoCarriage "remove carriage returns '\\r' in output"){ argAbbr = Just 'r', argName = Just "nocarriage" } 41 | , (initArg CreateImports "creates \"Import\" files in place of * imports (e.g. import a.*;)"){ argAbbr= Just 'c', argName = Just "imports" } 42 | , (initArg Input "input to convert") { argData = argDataRequired "directory | file" ArgtypeString } 43 | ] 44 | -------------------------------------------------------------------------------- /samples/AsWingApplication.as: -------------------------------------------------------------------------------- 1 | /** 2 | * author: Alva sun 3 | * site : www.alvas.cn 4 | * 5 | * need AsWingA3 6 | * 2007-05-07 7 | */ 8 | package example 9 | { 10 | import flash.display.Sprite; 11 | import flash.events.Event; 12 | import flash.events.MouseEvent; 13 | 14 | import org.aswing.BorderLayout; 15 | import org.aswing.FlowLayout; 16 | import org.aswing.GridLayout; 17 | import org.aswing.Insets; 18 | import org.aswing.JButton; 19 | import org.aswing.JFrame; 20 | import org.aswing.JLabel; 21 | import org.aswing.JPanel; 22 | import org.aswing.border.EmptyBorder; 23 | import org.aswing.geom.IntDimension; 24 | 25 | public class AsWingApplication extends Sprite 26 | { 27 | private static var labelPrefix : String = "Number of button clicks: "; 28 | private var numClicks : int = 0; 29 | private var label : JLabel; 30 | private var button : JButton; 31 | 32 | public function AsWingApplication(){ 33 | super(); 34 | createUI(); 35 | } 36 | 37 | private function createUI() : void{ 38 | var frame : JFrame = new JFrame( this, "AsWingApplication" ); 39 | frame.getContentPane().append( createCenterPane() ); 40 | frame.setSize(new IntDimension( 200, 120 ) ); 41 | frame.show(); 42 | } 43 | 44 | private function createCenterPane() : JPanel{ 45 | var pane : JPanel = new JPanel(new FlowLayout(FlowLayout.CENTER)); 46 | label = new JLabel(labelPrefix+"0"); 47 | button = new JButton("I'm a AsWing button!"); 48 | pane.append(button); 49 | pane.append(label); 50 | pane.setBorder(new EmptyBorder(null, new Insets(10,5,10,5))); 51 | initHandlers(); 52 | return pane; 53 | } 54 | 55 | private function initHandlers() : void{ 56 | //button.addActionListener( __pressButton ); 57 | button.addEventListener(MouseEvent.MOUSE_UP, __pressButton); 58 | } 59 | 60 | private function __pressButton( e : Event ) : void{ 61 | numClicks++; 62 | label.setText(labelPrefix+numClicks); 63 | label.revalidate(); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Lexitall.hs: -------------------------------------------------------------------------------- 1 | {- 2 | as3tohaxe - An Actionscript 3 to haXe source file translator 3 | Copyright (C) 2008 Don-Duong Quach 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | -} 18 | module Main where 19 | 20 | import ActionhaXe.Lexer 21 | import Text.Parsec.Pos 22 | import System.Environment (getArgs) 23 | import Text.PrettyPrint 24 | import System.Directory 25 | import Data.Char 26 | import Data.List 27 | import Control.Monad 28 | 29 | format s a = parens (hcat [text (sourceName s), space, int (sourceLine s), colon, int (sourceColumn s) ]) <+> text a 30 | 31 | {- 32 | unknowns ts = [ format s a | t@(s, TokenUnknown a) <- ts] 33 | comments ts = [ format s a | t@(s, TokenComment a) <- ts] 34 | strings ts = [ format s a | t@(s, TokenString a) <- ts] 35 | xmls ts = [ format s a | t@(s, TokenXml a) <- ts] 36 | regexs ts = [ format s (r1++"/"++r2) | t@(s, TokenRegex (r1,r2)) <- ts] 37 | -} 38 | 39 | unknowns ts = [ t | t@(s, TokenUnknown a) <- ts] 40 | comments ts = [ t | t@(s, TokenComment a) <- ts] 41 | strings ts = [ t | t@(s, TokenString a) <- ts] 42 | xmls ts = [ t | t@(s, TokenXml a) <- ts] 43 | regexs ts = [ t | t@(s, TokenRegex (r1,r2)) <- ts] 44 | 45 | inRange (s, _) (t, _) = linet > lines - 3 && linet < lines + 3 46 | where 47 | linet = sourceLine t 48 | lines = sourceLine s 49 | 50 | getContext ftoken tokens = filter (\t -> inRange ftoken t) tokens 51 | 52 | displayToken tokens t = do putStrLn "Detected Unknown: " 53 | print t 54 | putStrLn "Context --" 55 | mapM_ print $ getContext t tokens 56 | 57 | renderTokens lfilter filename = 58 | do contents <- readFile filename 59 | putStrLn $ "Checking: "++filename 60 | let tokens = runLexer filename contents 61 | let ftokens = lfilter tokens 62 | if null ftokens == False 63 | then do putStrLn $ "Detected: "++filename 64 | -- putStrLn $ render $ hcat $ punctuate (text "\n") $ ftokens 65 | mapM_ (displayToken tokens) ftokens 66 | else return () 67 | 68 | isFile f = do t <- doesFileExist f 69 | return $ t && ("as" == (map toLower $ reverse $ take 2 $ reverse f)) 70 | 71 | isDir d = do t <- doesDirectoryExist d 72 | return $ t && d /= "." && d /= ".." && d /= ".svn" 73 | 74 | getASFiles dir = do contents <- getDirectoryContents dir 75 | let c = map (\e -> dir++"/"++e) (filter (\d-> d /= "." && d /="..") contents) 76 | asfiles <- filterM isFile c 77 | asdirs <- filterM isDir c 78 | childAsFiles <- mapM getASFiles asdirs 79 | if null asfiles 80 | then return $ concat childAsFiles 81 | else return $ concat (asfiles: childAsFiles) 82 | 83 | 84 | main = do args <- getArgs 85 | if isSuffixOf ".as" (args!!0) 86 | then renderTokens unknowns $ args!!0 87 | else do asFiles <- getASFiles (args!!0) 88 | mapM_ (renderTokens unknowns) asFiles 89 | 90 | {- 91 | main = do args <- getArgs 92 | renderTokens unknowns $ args!!0 93 | -} 94 | -------------------------------------------------------------------------------- /ActionhaXe/Prim.hs: -------------------------------------------------------------------------------- 1 | {- 2 | as3tohaxe - An Actionscript 3 to haXe source file translator 3 | Copyright (C) 2008 Don-Duong Quach 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | -} 18 | module ActionhaXe.Prim where 19 | 20 | import ActionhaXe.Lexer 21 | import ActionhaXe.Data 22 | import Text.Parsec 23 | import Text.Parsec.Prim 24 | import Text.Parsec.Pos 25 | 26 | mytoken :: (Token -> Maybe a) -> AsParser a 27 | mytoken test = token showTok posFromTok testTok 28 | where showTok (pos, t) = show t 29 | posFromTok a@(pos, t) = newPos (tokenSource a) (tokenLine a) (tokenCol a) 30 | testTok t = test t 31 | 32 | anytok' = mytoken $ \t -> Just [t] 33 | 34 | white = mytoken $ \t -> case tokenItem t of 35 | TokenWhite x -> Just t 36 | _ -> Nothing 37 | 38 | nl = mytoken $ \t -> case tokenItem t of 39 | TokenNl x -> Just t 40 | _ -> Nothing 41 | 42 | com = mytoken $ \t -> case tokenItem t of 43 | TokenComment x -> Just t 44 | _ -> Nothing 45 | 46 | whiteSpace = many (white <|> nl <|> com) 47 | 48 | startWs = do{ w <- whiteSpace; return ([], w)} 49 | 50 | mylexeme p = do{ x <- p; w <- whiteSpace; return (x, w)} 51 | 52 | num' = mytoken $ \t -> case tokenItem t of 53 | TokenNum x -> Just [t] 54 | _ -> Nothing 55 | 56 | id' = mytoken $ \t -> case tokenItem t of 57 | TokenIdent x -> Just [t] 58 | _ -> Nothing 59 | 60 | mid' i = mytoken $ \t -> case tokenItem t of 61 | TokenIdent i' | i == i' -> Just [t] 62 | _ -> Nothing 63 | 64 | str' = mytoken $ \t -> case tokenItem t of 65 | TokenString x -> Just [t] 66 | _ -> Nothing 67 | 68 | kw' k = mytoken $ \t -> case tokenItem t of 69 | TokenKw k'| k == k' -> Just [t] 70 | _ -> Nothing 71 | 72 | op' o = mytoken $ \t -> case tokenItem t of 73 | TokenOp o' | o == o' -> Just [t] 74 | _ -> Nothing 75 | 76 | xml' = mytoken $ \t -> case tokenItem t of 77 | TokenXml x -> Just [t] 78 | _ -> Nothing 79 | 80 | idn = mylexeme $ id' 81 | num = mylexeme $ num' 82 | str = mylexeme $ str' 83 | xml = mylexeme $ xml' 84 | 85 | mid i = mylexeme $ mid' i 86 | kw k = mylexeme $ kw' k 87 | op o = mylexeme $ op' o 88 | 89 | -- sepByI includes the separators in the list 90 | sepByI1 :: AsParser [a] -> AsParser [a] -> AsParser [[a]] 91 | sepByI1 p sep = do{ x <- p 92 | ; xs <- many (do{ s <- sep; i<- p; return (s++i)}) 93 | ; return (x:xs) 94 | } 95 | 96 | sepByCI1 :: AsParser CToken -> AsParser CToken -> AsParser [CToken] 97 | sepByCI1 p sep = do{ x <- p 98 | ; xs <- many (do{ s <- sep; i<- p; return [s,i]}) 99 | ; return (x:(concat xs)) 100 | } 101 | 102 | sepEndByI1 :: AsParser [a] -> AsParser [a] -> AsParser [[a]] 103 | sepEndByI1 p sep = do{ x <- sepByI1 p sep 104 | ; s <- sep 105 | ; return $ x++[s] 106 | } 107 | 108 | ident' = do{ n <- sepByI1 id' (op' "."); return (concat n)} 109 | -- ident : qualified identifier 110 | ident = mylexeme $ ident' 111 | -- sident : qualified identifier with possible * at end 112 | sident = mylexeme $ try( do{ n <- id'; ns <- many(do{ d <- op' "."; n <- (id' <|> op' "*"); return $ d++n}); return $ n ++ concat ns}) <|> ident' 113 | --sident = mylexeme $ try( do{ n <- mid' "event"; p <- op' "."; o <- op' "*"; return $ n ++ p ++ o}) <|> ident' 114 | -- nident : identifier qualified with namespace 115 | nident = mylexeme $ do{ q<- try(do{ n'<- ident'; c <- op' "::"; return $ n'++c }) <|> return []; n <- ident'; return $ q++n } 116 | 117 | anytok = mylexeme $ anytok' 118 | 119 | maybeSemi = optionMaybe $ op ";" 120 | -------------------------------------------------------------------------------- /as3tohaxe.hs: -------------------------------------------------------------------------------- 1 | {- 2 | as3tohaxe - An Actionscript 3 to haXe source file translator 3 | Copyright (C) 2008 Don-Duong Quach 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | -} 18 | -- Translate a file 19 | 20 | import ActionhaXe.Lexer 21 | import ActionhaXe.Data 22 | import ActionhaXe.Prim 23 | import ActionhaXe.Parser 24 | import ActionhaXe.Translator 25 | import ActionhaXe.CLArgs 26 | 27 | import System.Directory 28 | import System.Environment (getArgs) 29 | import Control.Monad.State 30 | import System.Exit 31 | import Data.Char (toUpper, toLower) 32 | import Data.List (isSuffixOf, intercalate) 33 | import System.Console.ParseArgs 34 | import Data.Maybe (fromJust, fromMaybe) 35 | import System.FilePath.Posix (takeDirectory, takeBaseName, splitDirectories) 36 | import qualified Data.Map as Map 37 | 38 | translateFile :: String -> StateT Conf IO () 39 | translateFile filename = do 40 | conf <- get 41 | let outdir = confOutput conf 42 | let dir = takeDirectory filename 43 | dirExists <- liftIO $ doesDirectoryExist (outdir ++ dir) -- check if dir exists 44 | -- create dir 45 | liftIO $ unless dirExists (createDirectoryIfMissing True (outdir++dir) >> putStrLn ("Created " ++ outdir++dir)) 46 | -- add path to imports 47 | unless dirExists (put conf{ imports = (Map.insert dir [] $ imports conf) }) 48 | -- add class to imports 49 | put conf{imports = (Map.insertWith (\x y -> x ++ y) dir [takeBaseName $ (toUpper $ head filename):(tail filename)] $ imports conf) } 50 | liftIO $ putStrLn $ "Translating " ++ filename 51 | contents <- liftIO $ readFile filename 52 | let updated_contents = if gotArg (confArgs conf) NoCarriage 53 | then filter ( /= '\r' ) contents -- remove carriage 54 | else contents 55 | let tokens = runLexer "" updated_contents 56 | let outfilename = outdir ++ (reverse $ "xh" ++ ( drop 2 $ reverse filename)) 57 | program <- case parseTokens filename tokens of 58 | Right p@(AS3Program x st) -> return (p, st{outfile = outfilename, conf=conf }) 59 | Right p@(AS3Directives x st) -> return (p, st{outfile = outfilename, conf=conf }) 60 | Left err -> fail $ show err 61 | trans <- liftIO $ runStateT (translateAs3Ast (fst program)) (snd program) 62 | liftIO $ writeFile outfilename $ fst trans 63 | 64 | isFile :: String -> StateT Conf IO Bool 65 | isFile f = do conf <- get 66 | let outdir = confOutput conf 67 | t <- liftIO $ doesFileExist f 68 | let outfilename = outdir ++ (reverse $ "xh" ++ ( drop 2 $ reverse f)) 69 | o <- liftIO $ doesFileExist (outfilename) 70 | when o $ liftIO $ putStrLn $ "Skipping " ++ f 71 | return $ not o && t && ("as" == (map toLower $ reverse $ take 2 $ reverse f)) 72 | 73 | isDir :: String -> StateT Conf IO Bool 74 | isDir d = do t <- liftIO $ doesDirectoryExist d 75 | return $ t 76 | 77 | translateDir :: String -> StateT Conf IO () 78 | translateDir dir = do 79 | conf <- get 80 | let outdir = confOutput conf 81 | contents <- liftIO $ getDirectoryContents dir 82 | let c = map (\e -> dir++"/"++e) (filter (\d-> d /= "." && d /=".." && d /= ".svn") contents) 83 | asfiles <- filterM isFile c 84 | asdirs <- filterM isDir c 85 | mapM_ translateFile asfiles 86 | mapM_ translateDir asdirs 87 | 88 | main = do args <- parseArgsIO ArgsTrailing clargs 89 | let input = fromJust $ getArgString args Input 90 | let outdir = fromMaybe "hx_output/" $ getArgString args OutputDir 91 | let conf = Conf{ confArgs = args , confInput = input, confOutput = outdir, imports = Map.empty} 92 | (_, updated_conf) <- if isSuffixOf ".as" input 93 | then do dirExists <- doesDirectoryExist outdir 94 | unless dirExists ((createDirectoryIfMissing True outdir) >> putStrLn ("Created " ++ outdir)) 95 | runStateT (translateFile input) conf 96 | else runStateT (translateDir input) conf 97 | if gotArg (confArgs updated_conf) CreateImports 98 | then do putStrLn $ "Creating import files in "++outdir 99 | mapM_ (\(k, v)-> createImport outdir k $ reverse v) $ Map.toList $ imports updated_conf 100 | else return () 101 | 102 | createImport outdir packagePath packageList = do let importFileName = intercalate "_" ("Import":(splitDirectories packagePath)) 103 | writeFile (outdir ++ importFileName++".hx") $ packageContent packagePath packageList 104 | where packageContent path list = foldl (\content klass -> content++ "typedef "++klass++" = "++ppath++klass++"\n") "" list 105 | where ppath = (intercalate "." $ splitDirectories path)++"." 106 | 107 | -------------------------------------------------------------------------------- /ActionhaXe/Lexer.hs: -------------------------------------------------------------------------------- 1 | {- 2 | as3tohaxe - An Actionscript 3 to haXe source file translator 3 | Copyright (C) 2008 Don-Duong Quach 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | -} 18 | -- Turn the as3 source into Tokens for parsing 19 | 20 | module ActionhaXe.Lexer (runLexer, Token, tokenSource, tokenLine, tokenCol, tokenItem, tokenItemS, TPos(..), TokenType(..), TokenNum(..), keywords, operators) where 21 | 22 | import Text.Parsec 23 | import Text.Parsec.String (Parser) 24 | import Text.Parsec.Char 25 | import Text.Parsec.Perm 26 | import Data.Char 27 | import Data.List 28 | import Data.Generics -- not Haskell '98 29 | 30 | type Token = (TPos, TokenType) 31 | 32 | data TPos = TPos SourceName Line Column 33 | deriving (Show, Eq, Ord, Data, Typeable) 34 | 35 | tokenSource ((TPos s l c), i) = s 36 | tokenLine ((TPos s l c), i) = l 37 | tokenCol ((TPos s l c), i) = c 38 | tokenItem (s, i) = i 39 | 40 | tokenItemS (p, i) = case i of 41 | TokenWhite s -> s 42 | TokenComment s -> s 43 | TokenNum s -> case s of 44 | TokenInteger n -> n 45 | TokenDouble n -> n 46 | TokenOctal n -> n 47 | TokenHex n -> n 48 | TokenIdent s -> s 49 | TokenString s -> s 50 | TokenNl s -> s 51 | TokenEscaped s -> s 52 | TokenXml s -> s 53 | TokenKw s -> s 54 | TokenOp s -> s 55 | TokenUnknown s -> s 56 | 57 | data TokenNum = TokenInteger String 58 | | TokenDouble String 59 | | TokenOctal String 60 | | TokenHex String 61 | deriving (Show, Eq, Ord, Data, Typeable) 62 | 63 | data TokenType = 64 | TokenWhite String 65 | | TokenComment String 66 | | TokenNum TokenNum 67 | | TokenIdent String 68 | | TokenString String 69 | | TokenNl String 70 | | TokenEscaped String 71 | | TokenKw String 72 | | TokenOp String 73 | | TokenXml String 74 | | TokenUnknown String 75 | deriving (Show, Eq, Ord, Data, Typeable) 76 | 77 | keywords = [ "...", "as", "break", "case", "catch", "class", "const", "continue", "default", 78 | "delete", "do", "else", "extends", "false", "finally", "for", "function", "if", 79 | "implements", "import", "in", "instanceof", "interface", "internal", "is", 80 | "native", "new", "null", "package", 81 | "private", "protected", "public", "return", "super", "switch", "this", "throw", 82 | "true", "try", "typeof", "use", "undefined", "var", "void", "while", "with", 83 | -- syntactic keywords 84 | "each", "get", "set", "namespace", "include", "dynamic", "final", "native", 85 | "override", "static" 86 | ] 87 | 88 | operators = [ "...", ".", "[", "]", "(", ")", "@", "::", "..", "{", "}", 89 | "++", "--", "-", "~", "!", "*", "/", "%", 90 | "+", "-", "<<", ">>", ">>>", "<", "<=", ">", ">=", 91 | "==", "!=", "===", "!==", "&", "^", "|", "&&", "||", 92 | "?", "=", "+=", "-=", "*=", "/=", "%=", "<<=", ">>=", 93 | ">>>=", "&=", "^=", "|=", ",", ":", ";" 94 | ] 95 | 96 | keyword = do { x <- many1 identChar; if (elem x $ keywords) then return (TokenKw x) else unexpected "keyword" } 97 | 98 | identifier = do{ x<- (satisfy (\c -> isAlpha c || c == '_' || c == '$')); x' <- many identChar; return $ TokenIdent $ [x]++x' } 99 | 100 | identChar = satisfy (\c -> isAlphaNum c || c == '_' || c == '$') 101 | 102 | sortByLength = sortBy (\x y -> compare (length y) (length x)) 103 | 104 | operator' (o:os) = try (do{ s <- string o; return $ TokenOp s }) 105 | <|> operator' os 106 | operator' [] = fail " failed " 107 | 108 | operator = operator' $ sortByLength operators 109 | 110 | utf8 = do { c <- string "\239\187\191"; return $ TokenWhite c } 111 | 112 | simpleSpace = many1 (satisfy (\c -> c == ' ' || c == '\t')) 113 | whiteSpace = do{ x <- many1 ( try( simpleSpace ) <|> nl' ); return $ TokenWhite $ concat x} 114 | 115 | anyCharButNl = do{ c <- (satisfy(\c-> isPrint c && c /= '\r' && c /= '\n')); return c } 116 | 117 | escapedAnyChar = try(do{ char '\\'; c <- anyCharButNl; return $ "\\"++[c]}) 118 | <|> do{ c <- anyCharButNl; return [c]} 119 | 120 | escapedCharToken = do{ char '\\'; c <- anyCharButNl; return $ TokenEscaped $ "\\"++[c]} 121 | 122 | nl' = do{ try (string "\r\n"); return "\r\n" } 123 | <|> do{ try (char '\n'); return "\n" } 124 | <|> do{ try (char '\r'); return "\r" } 125 | 126 | nl = do{ x <- nl'; return $ TokenNl x} 127 | 128 | quotedDString = do{ char '"'; s <- manyTill escapedAnyChar (char '"'); return $ TokenString $ "\"" ++ (concat s) ++ "\""} 129 | quotedSString = do{ char '\''; s <- manyTill escapedAnyChar (char '\''); return $ TokenString $ "'" ++ (concat s) ++ "'"} 130 | 131 | commentSLine = do{ string "//"; s <- manyTill anyChar (lookAhead nl); return $ TokenComment $ "//"++s} 132 | commentMLine = do{ string "/*"; s <- manyTill anyChar (try(string "*/")); return $ TokenComment $ "/*"++s++"*/" } 133 | 134 | xml = do{ char '<'; t <- many1 (satisfy (\c -> isPrint c && c /= '>')); char '>'; x <- manyTill anyChar (try (string $ "")); return $ TokenXml $ "<"++t++">"++x++""} 135 | 136 | xmlSTag = do{ char '<'; t <- manyTill (satisfy (\c -> isPrint c && c /= '/' && c /= '>')) (string "/>"); return $ TokenXml $ "<"++t++"/>"} 137 | 138 | number = try (do{ char '0'; char 'x'; x <- many1 hexDigit; return $ TokenNum $ TokenHex $ "0x"++x}) 139 | <|> try (do{ char '0'; x <- many1 octDigit; return $ TokenNum $ TokenOctal $ "0"++x}) 140 | <|> try (do{ x <- double; return $ TokenNum $ TokenDouble $ x }) 141 | <|> do{ x <- many1 digit; return $ TokenNum $ TokenInteger $ x } 142 | 143 | double = try ( do{ h <- decimalInt; char '.'; t <- optionMaybe decimalInt; e <- optionMaybe expPart; return $ h++"."++(maybe "" id t)++(maybe "" id e) }) 144 | <|> try ( do{ char '.'; t <- decimalInt; e <- optionMaybe expPart; return $ "."++t++(maybe "" id e)}) 145 | <|> do{ h <- decimalInt; e <- expPart; return $ h++e} 146 | 147 | decimalInt = do{ char '0'; return "0"} 148 | <|> do{ h <- nonZeroDigit; t <- many digit; return $ h++t} 149 | 150 | nonZeroDigit = do{ x<- oneOf "123456789"; return [x]} 151 | 152 | expPart = do{ e <- oneOf "eE"; i <- signedInt; return $ [e]++i} 153 | 154 | signedInt = do{ s <- optionMaybe (oneOf "+-"); i <- many1 digit; return $ (maybe "" (\x -> [x]) s) ++ i} 155 | 156 | atoken = 157 | try (do{ x <- utf8; return x}) 158 | <|> try (do{ x <- keyword; return x}) 159 | <|> try (do{ x <- commentSLine; return x}) 160 | <|> try (do{ x <- commentMLine; return x}) 161 | <|> try (do{ x <- xmlSTag; return x}) 162 | <|> try (do{ x <- xml; return x}) 163 | <|> try (do{ x <- escapedCharToken; return x}) 164 | <|> try (do{ x <- number; return x}) 165 | <|> try (do{ x <- operator; return x}) 166 | <|> try (do{ x <- identifier; return x}) 167 | <|> try (do{ x <- quotedDString; return x}) 168 | <|> try (do{ x <- quotedSString; return x}) 169 | <|> try (do{ x <- whiteSpace; return x}) 170 | <|> do{ x <- anyToken; return $ TokenUnknown $ x:[]} 171 | 172 | 173 | lexer = many1 (do { p <- getPosition; t <- atoken; return (TPos (sourceName p) (sourceLine p) (sourceColumn p), t) }) 174 | 175 | runLexer :: String -> String -> [Token] 176 | runLexer filename s = case parse lexer filename s of 177 | Right l -> l 178 | Left _ -> [] 179 | -------------------------------------------------------------------------------- /samples/GridLayout.as: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright aswing.org, see the LICENCE.txt. 3 | */ 4 | package org.aswing{ 5 | 6 | import org.aswing.Component; 7 | import org.aswing.Container; 8 | import org.aswing.EmptyLayout; 9 | import org.aswing.geom.IntDimension; 10 | import org.aswing.Insets; 11 | import org.aswing.geom.IntRectangle; 12 | 13 | /** 14 | * @author feynixs(Cai Rong) 15 | * @author iiley 16 | */ 17 | public class GridLayout extends EmptyLayout{ 18 | /** 19 | * This is the horizontal gap (in pixels) which specifies the space 20 | * between columns. They can be changed at any time. 21 | * This should be a non-negative integer. 22 | * 23 | * @see #getHgap() 24 | * @see #setHgap(hgap:int) 25 | */ 26 | private var hgap:int; 27 | /** 28 | * This is the vertical gap (in pixels) which specifies the space 29 | * between rows. They can be changed at any time. 30 | * This should be a non negative integer. 31 | * 32 | * @see #getVgap() 33 | * @see #setVgap(vgap:int) 34 | */ 35 | private var vgap:int; 36 | /** 37 | * This is the number of rows specified for the grid. The number 38 | * of rows can be changed at any time. 39 | * This should be a non negative integer, where '0' means 40 | * 'any number' meaning that the number of Rows in that 41 | * dimension depends on the other dimension. 42 | * 43 | * @see #getRows() 44 | * @see #setRows(rows:int) 45 | */ 46 | private var rows:int; 47 | /** 48 | * This is the number of columns specified for the grid. The number 49 | * of columns can be changed at any time. 50 | * This should be a non negative integer, where '0' means 51 | * 'any number' meaning that the number of Columns in that 52 | * dimension depends on the other dimension. 53 | * 54 | * @see #getColumns() 55 | * @see #setColumns(cols:int) 56 | */ 57 | private var cols:int; 58 | 59 | 60 | 61 | /** 62 | *

63 | * Creates a grid layout with the specified number of rows and 64 | * columns. All components in the layout are given equal size. 65 | *

66 | *

67 | * In addition, the horizontal and vertical gaps are set to the 68 | * specified values. Horizontal gaps are placed between each 69 | * of the columns. Vertical gaps are placed between each of 70 | * the rows. 71 | *

72 | *

73 | * One, but not both, of rows and cols can 74 | * be zero, which means that any number of objects can be placed in a 75 | * row or in a column. 76 | *

77 | *

78 | * All GridLayout constructors defer to this one. 79 | *

80 | * @param rows the rows, with the value zero meaning 81 | * any number of rows 82 | * @param cols the columns, with the value zero meaning 83 | * any number of columns 84 | * @param hgap (optional)the horizontal gap, default 0 85 | * @param vgap (optional)the vertical gap, default 0 86 | * @throws ArgumentError if the value of both 87 | * rows and cols is 88 | * set to zero 89 | */ 90 | public function GridLayout(rows:int=1, cols:int=0, hgap:int=0, vgap:int=0) { 91 | if ((rows == 0) && (cols == 0)) { 92 | throw new ArgumentError("rows and cols cannot both be zero"); 93 | } 94 | 95 | this.rows = rows; 96 | this.cols = cols; 97 | this.hgap = hgap; 98 | this.vgap = vgap; 99 | } 100 | 101 | /** 102 | * Gets the number of rows in this layout. 103 | * @return the number of rows in this layout 104 | * 105 | */ 106 | public function getRows():int { 107 | return rows; 108 | } 109 | 110 | /** 111 | * Sets the number of rows in this layout to the specified value. 112 | * @param rows the number of rows in this layout 113 | */ 114 | public function setRows(rows:int):void { 115 | this.rows = rows; 116 | } 117 | 118 | /** 119 | * Gets the number of columns in this layout. 120 | * @return the number of columns in this layout 121 | * 122 | */ 123 | public function getColumns():int { 124 | return cols; 125 | } 126 | 127 | /** 128 | * Sets the number of columns in this layout. 129 | * Setting the number of columns has no effect on the layout 130 | * if the number of rows specified by a constructor or by 131 | * the setRows method is non-zero. In that case, the number 132 | * of columns displayed in the layout is determined by the total 133 | * number of components and the number of rows specified. 134 | * @param cols the number of columns in this layout 135 | * 136 | */ 137 | public function setColumns(cols:int):void { 138 | this.cols = cols; 139 | } 140 | 141 | /** 142 | * Gets the horizontal gap between components. 143 | * @return the horizontal gap between components 144 | * 145 | */ 146 | public function getHgap():int { 147 | return hgap; 148 | } 149 | 150 | /** 151 | * Sets the horizontal gap between components to the specified value. 152 | * @param hgap the horizontal gap between components 153 | * 154 | */ 155 | public function setHgap(hgap:int):void { 156 | this.hgap = hgap; 157 | } 158 | 159 | /** 160 | * Gets the vertical gap between components. 161 | * @return the vertical gap between components 162 | * 163 | */ 164 | public function getVgap():int { 165 | return vgap; 166 | } 167 | 168 | /** 169 | * Sets the vertical gap between components to the specified value. 170 | * @param vgap the vertical gap between components 171 | * 172 | */ 173 | public function setVgap(vgap:int):void { 174 | this.vgap = vgap; 175 | } 176 | 177 | override public function preferredLayoutSize(target:Container):IntDimension{ 178 | var insets:Insets = target.getInsets(); 179 | var ncomponents:int = target.getComponentCount(); 180 | var nrows:int = rows; 181 | var ncols:int = cols; 182 | if (nrows > 0){ 183 | ncols = Math.floor(((ncomponents + nrows) - 1) / nrows); 184 | }else{ 185 | nrows = Math.floor(((ncomponents + ncols) - 1) / ncols); 186 | } 187 | var w:int = 0; 188 | var h:int = 0; 189 | for (var i:int = 0; i < ncomponents; i++){ 190 | var comp:Component = target.getComponent(i); 191 | var d:IntDimension = comp.getPreferredSize(); 192 | if (w < d.width){ 193 | w = d.width; 194 | } 195 | if (h < d.height){ 196 | h = d.height; 197 | } 198 | } 199 | return new IntDimension((((insets.left + insets.right) + (ncols * w)) + ((ncols - 1) * hgap)), (((insets.top + insets.bottom) + (nrows * h)) + ((nrows - 1) * vgap))); 200 | } 201 | 202 | override public function minimumLayoutSize(target:Container):IntDimension{ 203 | return target.getInsets().getOutsideSize(); 204 | } 205 | 206 | /** 207 | * return new IntDimension(1000000, 1000000); 208 | */ 209 | override public function maximumLayoutSize(target:Container):IntDimension{ 210 | return new IntDimension(1000000, 1000000); 211 | } 212 | 213 | override public function layoutContainer(target:Container):void{ 214 | var insets:Insets = target.getInsets(); 215 | var ncomponents:int = target.getComponentCount(); 216 | var nrows:int = rows; 217 | var ncols:int = cols; 218 | if (ncomponents == 0){ 219 | return ; 220 | } 221 | if (nrows > 0){ 222 | ncols = Math.floor(((ncomponents + nrows) - 1) / nrows); 223 | }else{ 224 | nrows = Math.floor(((ncomponents + ncols) - 1) / ncols); 225 | } 226 | var w:int = (target.getWidth() - (insets.left + insets.right)); 227 | var h:int = (target.getHeight() - (insets.top + insets.bottom)); 228 | w = Math.floor((w - ((ncols - 1) * hgap)) / ncols); 229 | h = Math.floor((h - ((nrows - 1) * vgap)) / nrows); 230 | var x:int = insets.left; 231 | var y:int = insets.top; 232 | for (var c:int = 0; c < ncols; c++){ 233 | y = insets.top; 234 | for (var r:int = 0; r < nrows; r++){ 235 | var i:int = ((r * ncols) + c); 236 | if (i < ncomponents){ 237 | target.getComponent(i).setBounds(new IntRectangle(x, y, w, h)); 238 | } 239 | y += (h + vgap); 240 | } 241 | x += (w + hgap); 242 | } 243 | } 244 | public function toString():String{ 245 | return ((((((((("GridLayout[hgap=") + hgap) + ",vgap=") + vgap) + ",rows=") + rows) + ",cols=") + cols) + "]"); 246 | } 247 | 248 | /** 249 | * return 0.5 250 | */ 251 | override public function getLayoutAlignmentX(target:Container):Number{ 252 | return 0.5; 253 | } 254 | 255 | /** 256 | * return 0.5 257 | */ 258 | override public function getLayoutAlignmentY(target:Container):Number{ 259 | return 0.5; 260 | } 261 | } 262 | } -------------------------------------------------------------------------------- /ActionhaXe/Data.hs: -------------------------------------------------------------------------------- 1 | {- 2 | as3tohaxe - An Actionscript 3 to haXe source file translator 3 | Copyright (C) 2008 Don-Duong Quach 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | -} 18 | module ActionhaXe.Data where 19 | 20 | import ActionhaXe.Lexer 21 | import ActionhaXe.CLArgs 22 | 23 | import Text.Parsec 24 | import Text.Parsec.Prim 25 | 26 | import Data.Char 27 | import Data.Map (Map) 28 | import qualified Data.Map as Map 29 | import Data.Tree 30 | import Data.Generics -- not Haskel 98 31 | 32 | -- data 33 | showd :: CToken -> String 34 | showd x = foldr (\t s -> (tokenItemS t) ++ s) "" (fst x) 35 | 36 | -- whitespace includes comments 37 | showw :: CToken -> String 38 | showw x = foldr (\t s -> (tokenItemS t) ++ s) "" (snd x) 39 | 40 | -- whitespace filters comments 41 | showws :: CToken -> String 42 | showws x = foldr (\t s -> (tokenItemS t) ++ s) "" (fst (span (\(s, tok) -> case tok of { TokenWhite _ -> True; TokenNl _ -> True; otherwise -> False;}) (snd x))) 43 | 44 | -- both data and whitespace 45 | showb :: CToken -> String 46 | showb x = foldr (\t s -> (tokenItemS t) ++ s) "" ((fst x)++(snd x)) 47 | 48 | -- the whitespace after the first newline 49 | shown :: CToken -> String 50 | shown x = tailAtN $ snd $ break (== '\n') $ foldr (\t s -> (tokenItemS t) ++ s) "" (snd x) 51 | where tailAtN [] = "" 52 | tailAtN t = tail t 53 | 54 | showl :: [CToken] -> String 55 | showl xs = foldr (\t s -> showb t ++ s) "" xs 56 | 57 | -- splits the space from the left and right 58 | splitLR :: String -> [String] 59 | splitLR x = [l, m, r] 60 | where (l, nl) = span (\c -> isSpace c || c == '\n') x 61 | (r') = span (\c -> isSpace c || c == '\n') $ reverse nl 62 | (m, r) = (reverse $ snd r', reverse $ fst r') 63 | 64 | type Name = String 65 | type TList = [Token] 66 | type CToken = (TList, TList) -- compound token with a list for an entity, whitespace 67 | 68 | type Semi = Maybe CToken 69 | 70 | data PrimaryE = PEThis CToken -- this 71 | | PEIdent CToken -- identifier 72 | | PELit CToken -- literal: null, boolean, numeric, string, not regular expression or xml since those don't have operations on them outside of class methods 73 | | PEArray ArrayLit -- array literal 74 | | PEObject ObjectLit -- {, maybe [[property : assignE],[,]] , } 75 | | PEXml CToken 76 | | PEFunc FuncE 77 | | PEParens CToken ListE CToken -- (, List of expressions , ) 78 | deriving (Show, Data, Typeable) 79 | 80 | data ListE = ListE [(AssignE, (Maybe CToken))] 81 | deriving (Show, Data, Typeable) 82 | 83 | data ArrayLit = ArrayLitC CToken (Maybe Elision) CToken -- [, maybe commas, ] 84 | | ArrayLit CToken ElementList CToken -- [, element list, ] 85 | deriving (Show, Data, Typeable) 86 | 87 | data ElementList = El (Maybe Elision) AssignE [EAE] (Maybe Elision) 88 | deriving (Show, Data, Typeable) 89 | 90 | data EAE = EAE Elision AssignE 91 | deriving (Show, Data, Typeable) 92 | 93 | data Elision = Elision [CToken] -- commas possible separated by space in a list 94 | deriving (Show, Data, Typeable) 95 | 96 | data ObjectLit = ObjectLit CToken (Maybe PropertyList) CToken deriving (Show, Data, Typeable) 97 | 98 | data PropertyList = PropertyList [(CToken, CToken, AssignE, (Maybe CToken))] deriving (Show, Data, Typeable) -- [propertyName, :, assignE, maybe ','] 99 | 100 | data FuncE = FuncE CToken (Maybe CToken) Signature BlockItem deriving (Show, Data, Typeable) -- function, maybe ident, signature, block 101 | 102 | data Arguments = Arguments CToken (Maybe ListE) CToken 103 | deriving (Show, Data, Typeable) 104 | 105 | data SuperE = SuperE CToken (Maybe Arguments) 106 | deriving (Show, Data, Typeable) 107 | 108 | data PostFixE = PFFull FullPostFixE (Maybe CToken) 109 | | PFShortNew ShortNewE (Maybe CToken) 110 | deriving (Show, Data, Typeable) 111 | 112 | data FullPostFixE = FPFPrimary PrimaryE [FullPostFixSubE] 113 | | FPFFullNew FullNewE [FullPostFixSubE] 114 | | FPFSuper SuperE PropertyOp [FullPostFixSubE] 115 | | FPFInc PostFixE CToken 116 | | FPFDec PostFixE CToken 117 | deriving (Show, Data, Typeable) 118 | 119 | data FullPostFixSubE = FPSProperty PropertyOp 120 | | FPSArgs Arguments 121 | | FPSQuery QueryOp 122 | deriving (Show, Data, Typeable) 123 | 124 | data FullNewE = FN CToken FullNewE Arguments 125 | | FNPrimary PrimaryE [PropertyOp] 126 | | FNSuper SuperE [PropertyOp] 127 | deriving (Show, Data, Typeable) 128 | 129 | data ShortNewE = SN CToken ShortNewSubE 130 | deriving (Show, Data, Typeable) 131 | 132 | data ShortNewSubE = SNSFull FullNewE 133 | | SNSShort ShortNewE 134 | deriving (Show, Data, Typeable) 135 | 136 | data PropertyOp = PropertyOp CToken CToken -- . , identifier 137 | | PropertyB CToken ListE CToken -- [ list expression ] 138 | deriving (Show, Data, Typeable) 139 | 140 | data QueryOp = QueryOpDD CToken CToken 141 | | QueryOpD CToken CToken ListE CToken 142 | deriving (Show, Data, Typeable) 143 | 144 | data UnaryE = UEPrimary PostFixE 145 | | UEDelete CToken PostFixE 146 | | UEVoid CToken PostFixE 147 | | UETypeof CToken PostFixE 148 | | UEInc CToken PostFixE 149 | | UEDec CToken PostFixE 150 | | UEPlus CToken UnaryE 151 | | UEMinus CToken UnaryE 152 | | UEBitNot CToken UnaryE 153 | | UENot CToken UnaryE 154 | deriving (Show, Data, Typeable) 155 | 156 | data AritE = AEUnary UnaryE 157 | | AEBinary CToken AritE AritE 158 | deriving (Show, Data, Typeable) 159 | 160 | data RegE = RegE CToken [CToken] CToken (Maybe CToken) 161 | deriving (Show, Data, Typeable) 162 | 163 | data CondE = CondE AritE (Maybe (CToken, AssignE, CToken, AssignE)) 164 | | CondRE RegE 165 | deriving (Show, Data, Typeable) 166 | 167 | data NAssignE = NAssignE AritE (Maybe (CToken, NAssignE, CToken, NAssignE)) 168 | deriving (Show, Data, Typeable) 169 | 170 | data AssignE = ACond CondE 171 | | AAssign PostFixE CToken AssignE 172 | | ACompound PostFixE CToken AssignE 173 | | ALogical PostFixE CToken AssignE 174 | deriving (Show, Data, Typeable) 175 | 176 | data BlockItem = Tok CToken 177 | | Expr AssignE 178 | | Block CToken [BlockItem] CToken 179 | | ImportDecl CToken CToken Semi -- import identifier ; 180 | | ClassDecl [CToken] CToken CToken (Maybe (CToken, CToken)) (Maybe (CToken, [(CToken, Maybe CToken)])) BlockItem -- attributes, class, identifier, maybe (extends, idn), maybe (implements [(idn, maybe',')]), body 181 | | Interface [CToken] CToken CToken (Maybe (CToken, [(CToken, Maybe CToken)])) BlockItem -- public | internal, interface, identifier, maybe (extends [(idn, maybe ',')], body 182 | | MethodDecl [CToken] CToken (Maybe CToken) CToken Signature (Maybe BlockItem) -- attributes, function, maybe get/set, identifier, Signature, body 183 | | VarS [CToken] CToken VarBinding [(CToken, VarBinding)] -- maybe attributes, var, varbinding, [(',', varbinding)] 184 | | ForS CToken CToken (Maybe ForInit) CToken (Maybe ListE) CToken (Maybe ListE) CToken BlockItem -- for( ? ; ? ; ?) {} 185 | | ForInS CToken (Maybe CToken) CToken ForInBinding CToken ListE CToken BlockItem -- for, maybe each, ( forinbinding in listE ) {} 186 | | Metadata Metadata 187 | deriving (Show, Data, Typeable) 188 | 189 | data Metadata = MDSwf [(CToken, CToken)] 190 | | MD CToken CToken [CToken] CToken 191 | deriving (Show, Data, Typeable) 192 | 193 | data ForInit = FIListE ListE 194 | | FIVarS BlockItem 195 | deriving (Show, Data, Typeable) 196 | 197 | data ForInBinding = FIBPostE PostFixE 198 | | FIBVar CToken VarBinding -- var | const , varbinding 199 | deriving (Show, Data, Typeable) 200 | 201 | data VarBinding = VarBinding CToken (Maybe (CToken, AsType)) (Maybe (CToken, AssignE)) --varbinding with Type-- identifier, (maybe (:, datatype)), (maybe (=, assignE)) 202 | deriving (Show, Data, Typeable) 203 | 204 | data Signature = Signature CToken [Arg] CToken (Maybe (CToken, AsType)) -- left paren, arguments, right paren, :, return type 205 | deriving (Show, Data, Typeable) 206 | 207 | data Arg = Arg CToken CToken AsType (Maybe (CToken, AssignE)) (Maybe CToken) -- arg name, :, type, maybe default value, maybe comma 208 | | RestArg CToken CToken (Maybe (CToken, AsType)) -- ..., name 209 | deriving (Show, Data, Typeable) 210 | 211 | data Package = Package CToken CToken (Maybe CToken) BlockItem -- whitespace, package, maybe name, block 212 | deriving (Show, Data, Typeable) 213 | 214 | data Ast = AS3Program Package AsState 215 | | AS3Directives [BlockItem] AsState 216 | deriving (Show, Data, Typeable) 217 | 218 | type AsParser = Parsec TList AsState 219 | 220 | --- type and state structures 221 | 222 | data AsType = AsType CToken 223 | | AsTypeRest 224 | | AsTypeUser CToken 225 | | AsTypeUnknown 226 | deriving (Show, Eq, Ord, Data, Typeable) 227 | 228 | -- Symbol Lookup key 229 | data AsDef = DefPackage Name 230 | | DefClass Name 231 | | DefInterface Name 232 | | DefFunction Name -- anonymous functions are not referenced 233 | | DefVar Name -- can be for constants too 234 | | DefNamespace Name 235 | | DefNone 236 | deriving (Show, Eq, Ord, Data, Typeable) 237 | 238 | type Attribute = String 239 | -- Symbol Lookup value 240 | data AsDefInfo = DiNone -- 241 | | DiClass [Attribute] (Maybe AsDef) (Maybe [AsDef]) -- attributes, extends, implements 242 | | DiFunction [Attribute] 243 | | DiVar AsType 244 | deriving (Show, Eq, Ord, Data, Typeable) 245 | 246 | type AsDefTuple = (AsDef, AsDefInfo) 247 | 248 | data AsStateEl = AsStateEl { sid::Int, scope::Map AsDef AsDefInfo } 249 | deriving (Show, Data, Typeable) 250 | 251 | data AsState = AsState{ conf::Conf, filename::String, outfile::String, curId::Int, flags::Map String String, accessors::Map String (AsType, Bool, Bool), initMembers::[String], path::[Int], scopes::Tree AsStateEl } 252 | deriving (Show, Data, Typeable) 253 | 254 | initState :: AsState 255 | initState = AsState{ conf = ConfNone, filename = "", outfile = "", curId = 0, path = [0], flags = Map.empty, accessors = Map.empty, initMembers = [], scopes = newScope 0} 256 | 257 | getProperty name = 258 | do x <- getState 259 | let a = accessors x 260 | let def = (AsTypeUnknown, False, False) 261 | case Map.lookup name a of 262 | Nothing -> do let a' = Map.insert name def a 263 | let x' = x{ accessors = a' } 264 | setState x' 265 | return def 266 | Just prop -> return prop 267 | 268 | setProperty name prop = 269 | do x <- getState 270 | let a = accessors x 271 | let a' = Map.insert name prop a 272 | let x' = x{accessors = a'} 273 | setState x' 274 | 275 | addGetter name astype = 276 | do prop@(t, g, s) <- getProperty name 277 | setProperty name (astype, True, s) 278 | 279 | addSetter name astype = 280 | do prop@(t, g, s) <- getProperty name 281 | setProperty name (astype, g, True) 282 | 283 | enterScope :: AsParser () 284 | enterScope = do x <- getState 285 | let c = (1 +) $ curId x 286 | let p = (c:) $ path x 287 | let s = scopes x 288 | let s' = addScope (reverse p) s 289 | let x' = x{ curId = c, path = p, scopes = s'} 290 | setState x' 291 | return () 292 | 293 | newScope :: Int -> Tree AsStateEl 294 | newScope i = Node{ rootLabel = AsStateEl{ sid = i, scope = Map.empty}, subForest = []} 295 | 296 | addScope :: [Int] -> Tree AsStateEl -> Tree AsStateEl 297 | addScope (p:ps) t = t{ subForest = addScope' ps (subForest t)} 298 | 299 | addScope' :: [Int] -> Forest AsStateEl -> Forest AsStateEl 300 | addScope' (p:[]) [] = [newScope p] 301 | addScope' path@(p:ps) (t:ts) = if p == (sid $ rootLabel t) then ((addScope path t):ts) else (t:(addScope' path ts)) 302 | 303 | exitScope :: AsParser () 304 | exitScope = do x <- getState 305 | let p = tail $ path x 306 | let x' = x{path = p} 307 | setState x' 308 | return () 309 | 310 | lookupSymbol :: AsParser AsDef 311 | lookupSymbol = return DefNone 312 | 313 | updateSymbol :: AsDefTuple -> AsParser () 314 | updateSymbol d = do x <- getState 315 | x' <- updateS d x 316 | setState x' 317 | 318 | updateS :: AsDefTuple -> AsState -> AsParser AsState 319 | updateS d x = do let p = path x 320 | let s = scopes x 321 | let s' = traverseS (reverse p) s d 322 | return x{scopes = s'} 323 | 324 | traverseS :: [Int] -> Tree AsStateEl -> AsDefTuple -> Tree AsStateEl 325 | traverseS (p:[]) t (d, di) = if p == (sid $ rootLabel t) then t{ rootLabel = AsStateEl { sid = (sid $ rootLabel t), scope = (Map.insert d di (scope $ rootLabel t))}} else fail $ "\n\n--Error: in updating state "++(show p)++" "++(show t) 326 | traverseS (p:ps) t dt = if p == (sid $ rootLabel t) then t{ subForest = traverseS' ps (subForest t) dt } else t 327 | 328 | -- check the subtrees 329 | traverseS' :: [Int] -> Forest AsStateEl -> AsDefTuple -> Forest AsStateEl 330 | traverseS' path@(p:[]) [t] dt = [traverseS path t dt] 331 | traverseS' path@(p:ps) (t:ts) dt = if p == (sid $ rootLabel t) then ((traverseS path t dt):ts) else (t:(traverseS' path ts dt)) 332 | 333 | storePackage :: Maybe CToken -> AsParser () 334 | storePackage p = case p of 335 | Just x -> updateSymbol (DefPackage (showd x), DiNone) 336 | Nothing -> updateSymbol (DefPackage "//noname", DiNone) 337 | 338 | storeClass :: CToken -> AsParser () 339 | storeClass c = updateSymbol (DefClass (showd c), DiNone) 340 | 341 | storeProperty name (Just acc) s@(Signature l a r o) = 342 | do{ case showd acc of 343 | "get" -> addGetter (showd name) $ ret o 344 | "set" -> addSetter (showd name) $ arg $ head a 345 | } 346 | where ret (Just (_, t)) = t 347 | arg (Arg _ _ t _ _) = t 348 | 349 | storeProperty name Nothing s = return () 350 | 351 | storeVar :: CToken -> AsType -> AsParser () 352 | storeVar v t = updateSymbol (DefVar (showd v), DiVar t) 353 | -------------------------------------------------------------------------------- /ActionhaXe/Parser.hs: -------------------------------------------------------------------------------- 1 | {- 2 | as3tohaxe - An Actionscript 3 to haXe source file translator 3 | Copyright (C) 2008 Don-Duong Quach 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | -} 18 | -- Parse the tokens generated by Lexer 19 | -- TODO: 20 | -- updating Array parameter type, 21 | -- for 22 | -- while/do 23 | -- if 24 | -- case 25 | 26 | module ActionhaXe.Parser(parseTokens) where 27 | 28 | import ActionhaXe.Lexer 29 | import ActionhaXe.Prim 30 | import ActionhaXe.Data 31 | import Text.Parsec 32 | import Text.Parsec.Combinator 33 | import Text.Parsec.Perm 34 | import Text.Parsec.Expr 35 | 36 | emptyctok = ([],[]) 37 | 38 | parseTokens :: String -> [Token] -> Either ParseError Ast 39 | parseTokens fname ts = do let st = initState 40 | let st' = st{filename = fname} 41 | runParser program st' fname ts 42 | 43 | program :: AsParser Ast 44 | program = try(do{ x <- package; a <-getState; return $ AS3Program x a}) 45 | <|> do{ x <- directives; a <- getState; return $ AS3Directives x a } 46 | 47 | 48 | package = do{ ws <- startWs; p <- kw "package"; i <- optionMaybe(ident); storePackage i; b <- packageBlock; return $ Package ws p i b } 49 | 50 | packageBlock = do{ l <- op "{"; enterScope; x <- inPackageBlock; r <- op "}"; exitScope; return $ Block l x r } 51 | 52 | inPackageBlock = try(do{ lookAhead( op "}"); return [] }) 53 | <|> try(do{ x <- metadata; i <- inPackageBlock; return $ [x] ++ i}) 54 | <|> try(do{ x <- importDecl; i <- inPackageBlock; return $ [x] ++ i}) 55 | <|> try(do{ x <- classDecl; i <- inPackageBlock; return $ [x] ++ i}) 56 | <|> try(do{ x <- interface; i <- inPackageBlock; return $ [x] ++ i}) 57 | <|> (do{ x <- anytok; i <- inPackageBlock; return $ [(Tok x)] ++ i}) 58 | 59 | directives = do{ ws <- startWs; x <- many1 (choice[metadata, importDecl, methodDecl, varS, do{ x <- anytok; return $ Tok x}]); return $ (Tok ws):x} 60 | 61 | classBlock = do{ l <- op "{"; enterScope; x <- inClassBlock; r <- op "}"; exitScope; return $ Block l x r } 62 | 63 | inClassBlock = try(do{ lookAhead( op "}"); return [] }) 64 | <|> try(do{ x <- metadata; i <- inClassBlock; return $ [x] ++ i}) 65 | <|> try(do{ x <- methodDecl; i <- inClassBlock; return $ [x] ++ i}) 66 | <|> try(do{ x <- varS; i <- inClassBlock; return $ [x] ++ i}) 67 | <|> try(do{ x <- block; i <- inClassBlock; return $ [x] ++ i }) -- there can be blocks in classes for static initializations 68 | <|> (do{ x <- anytok; i <- inClassBlock; return $ [(Tok x)] ++ i}) 69 | 70 | interfaceBlock = do{ l <- op "{"; enterScope; x <- inInterfaceBlock; r <- op "}"; exitScope; return $ Block l x r } 71 | 72 | inInterfaceBlock = try(do{ lookAhead( op "}"); return [] }) 73 | <|> try(do{ x <- metadata; i <- inInterfaceBlock; return $ [x] ++ i}) 74 | <|> try(do{ x <- methodDecl; i <- inInterfaceBlock; return $ [x] ++ i}) 75 | <|> (do{ x <- anytok; i <- inInterfaceBlock; return $ [(Tok x)] ++ i}) 76 | 77 | funcBlock = do{ l <- op "{"; enterScope; x <- inMethodBlock; r <- op "}"; exitScope; return $ Block l x r } 78 | 79 | inMethodBlock = try(do{ lookAhead( op "}"); return [] }) 80 | <|> try(do{ x <- metadata; i <- inMethodBlock; return $ [x] ++ i}) 81 | <|> try(do{ x <- expr; i <- inMethodBlock; return $ [x] ++ i}) 82 | <|> try(do{ b <- block; i <- inMethodBlock; return $ [b] ++ i }) 83 | <|> try(do{ x <- statement; i <- inMethodBlock; return $ [x]++i}) 84 | <|> (do{ x <- anytok; i <- inMethodBlock; return $ [(Tok x)] ++ i}) 85 | 86 | block = do{ l <- op "{"; enterScope; x <- inBlock; r <- op "}"; exitScope; return $ Block l x r } 87 | 88 | inBlock = try(do{ lookAhead( op "}"); return [] }) 89 | <|> try(do{ x <- metadata; i <- inBlock; return $ [x] ++ i}) 90 | <|> try(do{ x <- expr; i <- inBlock; return $ [x] ++ i}) 91 | <|> try(do{ b <- block; i <- inBlock; return $ [b] ++ i }) 92 | <|> try(do{ x <- statement; i <- inBlock; return $ [x]++i}) 93 | <|> (do{ x <- anytok; i <- inBlock; return $ [(Tok x)] ++ i}) 94 | 95 | metadata = do{ l <- op "[" 96 | ; try(do{ t <- mid "SWF"; 97 | ; lp <- op "(" 98 | ; m <- metadataSwf 99 | ; rp <- op ")" 100 | ; r <- op "]" 101 | ; return $ Metadata $ MDSwf m 102 | } 103 | ) 104 | <|> try(do{ t <- choice[mid "ArrayElementType" 105 | , mid "Bindable" 106 | , mid "DefaultProperty" , mid "Deprecated" 107 | , mid "Effect" , mid "Embed" , mid "Event" , mid "Exclude" , mid "ExcludeClass" 108 | , mid "IconFile" , mid "Inspectable" , mid "InstanceType" 109 | , mid "NonCommittingChangeEvent" 110 | , mid "RemoteClass" 111 | , mid "Style" 112 | , mid "Transient" 113 | ] 114 | ; x <- manyTill anytok (lookAhead(op "]")) 115 | ; r <- op "]" 116 | ; return $ Metadata $ MD l t x r 117 | } 118 | ) 119 | } 120 | 121 | metadataSwf = 122 | permute $ mlist <$?> (missing, item "width") <|?> (missing, item "height") <|?> (missing, item "backgroundColor") <|?> (missing, item "frameRate") 123 | where mlist w h b f = filter (\a -> (fst a) /= emptyctok) [w, h, b, f] 124 | item i = do{ x <- mid i; op "="; s <- str; optionMaybe (op ","); return (x, s)} 125 | missing = (emptyctok, emptyctok) 126 | 127 | importDecl = do{ k <- kw "import"; s <- sident; o <- maybeSemi; return $ ImportDecl k s o} 128 | 129 | interface = do{ a <- classAttributes; k <- kw "interface"; i <- ident; e <- optionMaybe(interfaceExtends); b <- classBlock; return $ Interface a k i e b} 130 | 131 | interfaceExtends = do{ k <- kw "extends"; s <- many1 (do{n <- nident; c <- optionMaybe (op ","); return (n,c)}); return $ (k,s) } 132 | 133 | classDecl = do{ a <- classAttributes; k <- kw "class"; i <- ident; e <- optionMaybe(classExtends); im <- optionMaybe(classImplements); storeClass i; b <- classBlock; return $ ClassDecl a k i e im b} 134 | 135 | classAttributes = permute $ list <$?> (emptyctok, (choice[kw "public", kw "internal"])) <|?> (emptyctok, kw "static") <|?> (emptyctok, kw "dynamic") 136 | where list v s d = filter (\a -> fst a /= []) [v,s,d] 137 | 138 | classExtends = do{ k <- kw "extends"; s <- nident; return $ (k, s)} 139 | 140 | classImplements = do{ k <- kw "implements"; s <- many1 (do{n <- nident; c <- optionMaybe (op ","); return (n,c)}); return $ (k,s) } 141 | 142 | methodDecl = try(do{ attr <- methodAttributes 143 | ; k <- kw "function" 144 | ; acc <- optionMaybe(try(do{ k <- (kw "get" <|> kw "set"); try(do{ o <- op "("; unexpected (showb o)} <|> return ()); return k})) 145 | ; n <- choice[ nident, kw "each", kw "get", kw "set", kw "include", kw "override"] 146 | ; enterScope 147 | ; sig <- signature 148 | ; b <- optionMaybe funcBlock 149 | ; exitScope 150 | ; storeProperty n acc sig 151 | ; return $ MethodDecl attr k acc n sig b}) 152 | 153 | methodAttributes = permute $ list <$?> (emptyctok, (choice[kw "public", kw "private", kw "protected", kw "internal"])) <|?> (emptyctok, ident) <|?> (emptyctok, kw "internal") <|?> (emptyctok, kw "override") <|?> (emptyctok, kw "static") <|?> (emptyctok, kw "final") <|?> (emptyctok, kw "native") 154 | where list v ns i o s f n = filter (\a -> fst a /= []) [v,ns,i,o,s,f,n] 155 | 156 | signature = do{ lp <- op "("; a <- sigargs; rp <- op ")"; ret <- optionMaybe ( do{ o <- op ":"; r <- datatype; return (o, r)}); return $ Signature lp a rp ret} -- missing return type means constructor 157 | 158 | sigargs = do{ s <- many sigarg; return s} 159 | sigarg = try(do{ a <- idn; o <- op ":"; 160 | try(do{ t <- datatype; d <- optionMaybe( do{ o <- op "="; a <- assignE; return $ (o, a)}); c <- optionMaybe(op ","); storeVar a t; return $ Arg a o t d c}) 161 | <|> try(do{ d <- op "*=" -- special case where no space between *= is parsed as an operator 162 | ; let (d', eq) = extractDynamicType d 163 | ; e <- assignE; 164 | ; c <- optionMaybe(op ",") 165 | ; let t = AsType d' 166 | ; storeVar a t; 167 | ; return $ Arg a o t (Just (eq, e)) c 168 | }) 169 | }) 170 | <|> do{ d <- op "..."; i <- idn; t <- optionMaybe (do{ o <- op ":"; t <- datatype; return (o, t)}); storeVar i AsTypeRest; return $ RestArg d i t } 171 | 172 | -- extractDynamicType used by sigarg to split TokenOp *= into the * datatype and = for assignment 173 | extractDynamicType ([t], s) = (([dt], []), ([eq], s)) 174 | where sourceName = tokenSource t 175 | sourceLine = tokenLine t 176 | sourceCol = tokenCol t 177 | dt = (TPos sourceName sourceLine sourceCol, TokenOp "*") 178 | eq = (TPos sourceName sourceLine (sourceCol+1), TokenOp "=") 179 | 180 | varS = try(do{ ns <- varAttributes 181 | ; k <- choice[kw "var", kw "const"] 182 | ; v <- varBinding 183 | ; vs <- many (do{ s <- op ","; v <- varBinding; return (s, v)}) 184 | ; return $ VarS ns k v vs 185 | } 186 | ) 187 | 188 | varAttributes = permute $ list <$?> (emptyctok, (choice[kw "public", kw "private", kw "protected", kw "internal"])) <|?> (emptyctok, ident) <|?> (emptyctok, kw "static") <|?> (emptyctok, kw "native") 189 | where list v ns s n = filter (\a -> fst a /= []) [v,ns,s,n] 190 | 191 | varBinding = try(do{ n <- idn 192 | ; t <- optionMaybe(do{c <- op ":"; dt <- datatype; return (c, dt)}) 193 | ; i <- optionMaybe (do{ o <- op "="; e <- assignE; return $ (o, e)}) 194 | ; return $ VarBinding n t i 195 | } 196 | ) 197 | 198 | 199 | datatype = try(do{ t <- kw "void"; return $ AsType t}) 200 | <|> try(do{ t <- mid "int"; return $ AsType t}) 201 | <|> try(do{ t <- mid "uint"; return $ AsType t}) 202 | <|> try(do{ t <- mid "Number"; return $ AsType t}) 203 | <|> try(do{ t <- mid "Boolean"; return $ AsType t}) 204 | <|> try(do{ t <- mid "String"; return $ AsType t}) 205 | <|> try(do{ t <- mid "Object"; return $ AsType t}) 206 | <|> try(do{ t <- op "*"; return $ AsType t}) 207 | <|> try(do{ t <- mid "Array"; return $ AsType t}) 208 | <|> try(do{ t <- mid "Function"; return $ AsType t}) 209 | <|> try(do{ t <- mid "RegExp"; return $ AsType t}) 210 | <|> try(do{ t <- mid "XML"; return $ AsType t}) 211 | <|> try(do{ t <- mid "Class"; return $ AsType t}) 212 | -- Vector.<*> new in flash 10 213 | <|> do{ i <- ident; return $ AsTypeUser i} 214 | 215 | primaryE = try(do{ x <- kw "this"; return $ PEThis x}) 216 | <|> try(do{ x <- idn; return $ PEIdent x}) 217 | <|> try(do{ x <- choice[kw "null", kw "true", kw "false", kw "public", kw "private", kw "protected", kw "internal"]; return $ PELit x}) 218 | <|> try(do{ x <- str; return $ PELit x}) 219 | <|> try(do{ x <- num; return $ PELit x}) 220 | <|> try(do{ x <- arrayLit; return $ PEArray x}) 221 | <|> try(do{ x <- objectLit; return $ PEObject x}) 222 | -- <|> try(do{ x <- reg; return $ PERegex x}) 223 | <|> try(do{ x <- xml; return $ PEXml x}) 224 | <|> try(do{ x <- funcE; return $ PEFunc x}) 225 | <|> try(do{ x <- kw "get"; return $ PEIdent x}) 226 | <|> try(do{ x <- kw "set"; return $ PEIdent x}) 227 | <|> do{ x <- parenE; return $ x} 228 | 229 | arrayLit = try(do{ l <- op "["; e <- elementList; r <- op "]"; return $ ArrayLit l e r}) 230 | <|> do{ l <- op "["; e <- optionMaybe elision; r <- op "]"; return $ ArrayLitC l e r} 231 | 232 | elementList = do 233 | l <- optionMaybe elision 234 | e <- assignE 235 | el <- many (try(do{ c <- elision; p <- assignE; return $ EAE c p})) 236 | r <- optionMaybe elision 237 | return $ El l e el r 238 | 239 | elision = do{ x <- many1 (op ","); return $ Elision x} 240 | 241 | objectLit = do{ l <- op "{"; x <- optionMaybe propertyNameAndValueList; r <- op "}"; return $ ObjectLit l x r} 242 | 243 | propertyNameAndValueList = do{ x <- many1 (do{ p <- propertyName; c <- op ":"; e <- assignE; s <- optionMaybe (op ","); return (p, c, e, s)}); return $ PropertyList x} 244 | 245 | propertyName = do{ x <- choice [ident, str, num]; return x} 246 | 247 | funcE = do{ f <- kw "function"; i <- optionMaybe ident; enterScope; s <- signature; b <- funcBlock; exitScope; return $ FuncE f i s b} 248 | 249 | parenE = do{ l <- op "("; e <- listE; r <- op ")"; return $ PEParens l e r} 250 | 251 | listE = do{ e <- many1 (do{x <- assignE; c <- optionMaybe (op ","); return (x, c)}); return $ ListE e} 252 | 253 | listENoIn = do{ e <- many1 (do{x <- assignENoIn; c <- optionMaybe (op ","); return (x, c)}); return $ ListE e} 254 | 255 | postFixE = try(do{ x <- fullPostFixE; o <- postFixUp; return $ PFFull x o}) 256 | <|> do{ x <- shortNewE; o <- postFixUp; return $ PFShortNew x o} 257 | where postFixUp = optionMaybe (do{ o <- choice [op "++", op "--"]; return o}) 258 | 259 | fullPostFixE = try(do{ x <- primaryE; s <- many fullPostFixSubE; return $ FPFPrimary x s}) 260 | <|> try(do{ x <- fullNewE; s <- many fullPostFixSubE; return $ FPFFullNew x s}) 261 | <|> (do{ x <- superE; p <- propertyOp; s <- many fullPostFixSubE; return $ FPFSuper x p s}) 262 | 263 | fullPostFixSubE = try(do{ p <- propertyOp; return $ FPSProperty p}) 264 | <|> try(do{ a <- args; return $ FPSArgs a}) -- call expression 265 | <|> do{ q <- queryOp; return $ FPSQuery q} 266 | 267 | fullNewE = do{ k <- kw "new"; e <- fullNewSubE; a <- args; return $ FN k e a} 268 | 269 | fullNewSubE = try(do{ e <- fullNewE; return e}) 270 | <|> try(do{ e <- primaryE; p <- many propertyOp; return $ FNPrimary e p}) 271 | <|> do{ e <- superE; p <- many1 propertyOp; return $ FNSuper e p} 272 | 273 | shortNewE = do{ k <- kw "new"; s <- shortNewSubE; return $ SN k s} 274 | 275 | shortNewSubE = try(do{ e <- fullNewSubE; return $ SNSFull e}) 276 | <|> do{ e <- shortNewE; return $ SNSShort e} 277 | 278 | superE = do{ k <- kw "super"; p <- optionMaybe args; return $ SuperE k p} 279 | 280 | args = do{ l <- op "("; e <- optionMaybe listE; r <- op ")"; return $ Arguments l e r} 281 | 282 | propertyOp = try(do{ o <- op "."; n <- choice[idn, kw "get", kw "set"]; return $ PropertyOp o n}) 283 | <|> do{ l <- op "["; e <- listE; r <- op "]"; return $ PropertyB l e r} 284 | 285 | queryOp = try(do{ o <- op ".."; n <- nident; return $ QueryOpDD o n}) 286 | <|> do{ o <- op "."; l <- op "("; e <- listE; r <- op ")"; return $ QueryOpD o l e r} 287 | 288 | unaryE = try(do{ k <- kw "delete"; p <- postFixE; return $ UEDelete k p}) 289 | <|> try(do{ k <- kw "void"; p <- postFixE; return $ UEVoid k p}) 290 | <|> try(do{ k <- kw "typeof"; p <- postFixE; return $ UETypeof k p}) 291 | <|> try(do{ o <- op "++"; p <- postFixE; return $ UEInc o p}) 292 | <|> try(do{ o <- op "--"; p <- postFixE; return $ UEDec o p}) 293 | <|> try(do{ o <- op "+"; p <- unaryE; return $ UEPlus o p}) 294 | <|> try(do{ o <- op "-"; p <- unaryE; return $ UEMinus o p}) 295 | <|> try(do{ o <- op "~"; p <- unaryE; return $ UEBitNot o p}) 296 | <|> try(do{ o <- op "!"; p <- unaryE; return $ UENot o p}) 297 | <|> do{ p <- postFixE; return $ UEPrimary p } 298 | 299 | aeUnary = do{ x <- unaryE; return $ AEUnary x} 300 | 301 | aritE = buildExpressionParser (aritOpTable True) aeUnary 302 | 303 | aritENoIn = buildExpressionParser (aritOpTable False) aeUnary 304 | 305 | aritOpTable allowIn = 306 | [ 307 | [o "*", o "/", o "%"], -- multiplicative 308 | [o "+", o "-"], -- additive 309 | [o "<<", o ">>", o ">>>"], -- shift 310 | [o "<", o ">", o "<=", o ">="] 311 | ++ (if allowIn == True then [ok "in"] else []) 312 | ++ [ ok "instanceof", ok "is", ok "as"], -- relational 313 | [o "==", o "!=", o "===", o "!=="], -- equality 314 | [o "&"], [o "^"], [o "|"], -- bitwise 315 | [o "&&"], [o "||"] -- logical 316 | ] 317 | where o opr = Infix (do{ o' <- op opr; return (\x y -> AEBinary o' x y)}) AssocLeft 318 | ok kop = Infix (do{ k <- kw kop; return (\x y -> AEBinary k x y)}) AssocLeft 319 | 320 | regE = do{ l <- op "/"; x <- manyTill anytok (try(lookAhead(op "/"))); r <- op "/"; o <- optionMaybe idn; return $ RegE l x r o} 321 | 322 | condE = try(do{ r <- regE; return $ CondRE r}) 323 | <|> do{ e <- aritE; o <- optionMaybe (do{ q <- op "?"; e1 <- assignE; c <- op ":"; e2 <- assignE; return $ (q, e1, c, e2)}); return $ CondE e o} 324 | 325 | condENoIn = try(do{ r <- regE; return $ CondRE r}) 326 | <|> do{ e <- aritENoIn; o <- optionMaybe (do{ q <- op "?"; e1 <- assignENoIn; c <- op ":"; e2 <- assignENoIn; return $ (q, e1, c, e2)}); return $ CondE e o} 327 | 328 | nonAssignE = do{ e <- aritE; o <- optionMaybe (do{ q <- op "?"; e1 <- nonAssignE; c <- op ":"; e2 <- nonAssignE; return $ (q, e1, c, e2)}); return $ NAssignE e o} 329 | 330 | nonAssignENoIn = do{ e <- aritENoIn; o <- optionMaybe (do{ q <- op "?"; e1 <- nonAssignENoIn; c <- op ":"; e2 <- nonAssignENoIn; return $ (q, e1, c, e2)}); return $ NAssignE e o} 331 | 332 | typeE = nonAssignE 333 | 334 | typeENoIn = nonAssignENoIn 335 | 336 | assignE = try(do{ p <- postFixE; 337 | try(do{o <- choice [op "&&=", op "^^=", op "||="]; a <- assignE; return $ ALogical p o a}) 338 | <|> try(do{o <- choice [op "*=", op "/=", op "%=", op "+=", op "-=", op "<<=", op ">>=", op ">>>=", op "&=", op "^=", op "|="]; a <- assignE; return $ ACompound p o a}) 339 | <|> do{o <- op "="; a <- assignE; return $ AAssign p o a} 340 | } 341 | ) 342 | <|> do{ e <- condE; return $ ACond e} 343 | 344 | assignENoIn = try(do{ p <- postFixE; 345 | try(do{o <- choice [op "&&=", op "^^=", op "||="]; a <- assignENoIn; return $ ALogical p o a}) 346 | <|> try(do{o <- choice [op "*=", op "/=", op "%=", op "+=", op "-=", op "<<=", op ">>=", op ">>>=", op "&=", op "^=", op "|="]; a <- assignENoIn; return $ ACompound p o a}) 347 | <|> do{o <- op "="; a <- assignENoIn; return $ AAssign p o a} 348 | } 349 | ) 350 | <|> do{ e <- condE; return $ ACond e} 351 | 352 | expr = do{ x <- assignE; return $ Expr x} 353 | 354 | exprNoIn = do{ x <- assignENoIn; return $ Expr x} 355 | 356 | statement = try(do{ x <- varS; return x}) 357 | <|> try(do{ x <- forS; return x}) 358 | <|> do{ x <- forInS; return x} 359 | 360 | forS = do k <- kw "for" 361 | l <- op "(" 362 | init <- optionMaybe forInit 363 | s <- op ";" 364 | e <- optionMaybe listE 365 | s1 <- op ";" 366 | e1 <- optionMaybe listE 367 | r <- op ")" 368 | b <- block 369 | return $ ForS k l init s e s1 e1 r b 370 | where forInit = try(do{ l <- listENoIn; return $ FIListE l}) 371 | <|> do{ x <- varS; return $ FIVarS x} 372 | 373 | forInS = do k <- kw "for" 374 | me <- optionMaybe (kw "each") 375 | l <- op "(" 376 | fb <- fbind 377 | i <- kw "in" 378 | e <- listE 379 | r <- op ")" 380 | b <- block 381 | return $ ForInS k me l fb i e r b 382 | where fbind = try(do{ p <- postFixE; return $ FIBPostE p}) 383 | <|> do{ v <- choice [kw "var", kw "const"]; b <- varBinding; return $ FIBVar v b} 384 | -------------------------------------------------------------------------------- /System/Console/ParseArgs.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE FlexibleInstances #-} 2 | -- Full-featured argument parsing library for Haskell programs 3 | -- Bart Massey 4 | 5 | -- Copyright (C) 2007 Bart Massey 6 | -- ALL RIGHTS RESERVED 7 | 8 | -- You can redistribute and/or modify this library under the 9 | -- terms of the "3-clause BSD LICENSE", as stated in the file 10 | -- COPYING in the top-level directory of this distribution. 11 | -- 12 | -- This library is distributed in the hope that it will be 13 | -- useful, but WITHOUT ANY WARRANTY; without even the 14 | -- implied warranty of MERCHANTABILITY or FITNESS FOR A 15 | -- PARTICULAR PURPOSE. 16 | 17 | -- |This module supplies an argument parser. 18 | -- Given a description of type [`Arg`] of the legal 19 | -- arguments to the program, a list of argument strings, 20 | -- and a bit of extra information, the `parseArgs` function 21 | -- in this module returns an 22 | -- `Args` data structure suitable for querying using the 23 | -- provided functions `gotArg`, `getArg`, etc. 24 | module System.Console.ParseArgs ( 25 | -- * Describing allowed arguments 26 | -- |The argument parser requires a description of 27 | -- the arguments that will be parsed. This is 28 | -- supplied as a list of `Arg` records, built up 29 | -- using the functions described here. 30 | Arg(..), 31 | Argtype(..), 32 | ArgsComplete(..), 33 | -- ** DataArg and its pseudo-constructors 34 | DataArg, 35 | argDataRequired, argDataOptional, argDataDefaulted, 36 | -- * Argument processing 37 | -- |The argument descriptions are used to parse 38 | -- the command line arguments, and the results 39 | -- of the parse can later be (efficiently) queried 40 | -- to determine program behavior. 41 | 42 | -- ** Getting parse results 43 | -- |The argument parser returns an opaque map 44 | -- from argument index to parsed argument data 45 | -- (plus some convenience information). 46 | ArgRecord, Args(..), 47 | parseArgs, parseArgsIO, 48 | -- ** Using parse results 49 | -- |Query functions permit checking for the existence 50 | -- and values of command-line arguments. 51 | gotArg, ArgType(..), 52 | getArgString, getArgFile, getArgStdio, 53 | getArgInteger, getArgInt, 54 | getArgDouble, getArgFloat, 55 | ArgFileOpener(..), 56 | -- * Misc 57 | baseName, usageError, 58 | System.IO.IOMode(ReadMode, WriteMode, AppendMode)) 59 | where 60 | 61 | import Data.List 62 | import qualified Data.Map as Map 63 | import Control.Monad 64 | import Data.Maybe 65 | import System.Environment 66 | import Control.Monad.ST 67 | import System.IO 68 | import Control.Exception 69 | import Data.Generics 70 | 71 | -- The main job of this module is to provide parseArgs. 72 | -- See below for its contract. 73 | 74 | -- 75 | -- Provided datatypes. 76 | -- 77 | 78 | -- |The description of an argument, suitable for 79 | -- messages and for parsing. The `argData` field 80 | -- is used both for flags with a data argument, and 81 | -- for positional data arguments. 82 | -- 83 | -- There are two cases: 84 | -- 85 | -- (1) The argument is a flag, in which case at least 86 | -- one of `argAbbr` and `argName` is provided; 87 | -- 88 | -- (2) The argument is positional, in which case neither 89 | -- `argAbbr` nor `argName` are provided, but `argData` is. 90 | -- 91 | -- If none of `argAbbr`, `argName`, or `argData` are 92 | -- provided, this is an error. See also the 93 | -- `argDataRequired`, `argDataOptional`, and 94 | -- `argDataDefaulted` functions below, which are used to 95 | -- generate `argData`. 96 | data (Ord a) => Arg a = 97 | Arg { argIndex :: a -- ^Connects the input description 98 | -- to the output argument. 99 | , argAbbr :: Maybe Char -- ^One-character flag name. 100 | , argName :: Maybe String -- ^\"Long name\" of flag. 101 | , argData :: Maybe DataArg -- ^Datum description. 102 | , argDesc :: String -- ^Documentation for the argument. 103 | } 104 | deriving (Show, Data, Typeable) 105 | 106 | -- |The types of an argument carrying data. The constructor 107 | -- argument is used to carry a default value. 108 | -- 109 | -- The constructor argument should really be hidden. 110 | -- Values of this type are normally constructed within 111 | -- the pseudo-constructors pseudo-constructors 112 | -- `argDataRequired`, `argDataOptional`, and 113 | -- `argDataDefaulted`, to which only the constructor 114 | -- function itself is passed. 115 | data Argtype = ArgtypeString (Maybe String) 116 | | ArgtypeInteger (Maybe Integer) 117 | | ArgtypeInt (Maybe Int) 118 | | ArgtypeDouble (Maybe Double) 119 | | ArgtypeFloat (Maybe Float) 120 | deriving (Show, Data, Typeable) 121 | 122 | -- |Information specific to an argument carrying a datum. This 123 | -- is an opaque type, whose instances are constructed using the 124 | -- pseudo-constructors `argDataRequired`, `argDataOptional`, 125 | -- and `argDataDefaulted`. 126 | data DataArg = DataArg { dataArgName :: String -- ^Print name of datum. 127 | , dataArgArgtype :: Argtype -- ^Type of datum. 128 | , dataArgOptional :: Bool -- ^Datum is not required. 129 | } 130 | deriving (Show, Data, Typeable) 131 | 132 | -- |Generate the `argData` for the given non-optional argument. 133 | argDataRequired :: String -- ^Datum print name. 134 | -> (Maybe a -> Argtype) -- ^Type constructor for datum. 135 | -> Maybe DataArg -- ^Result is `argData`-ready. 136 | argDataRequired s c = Just (DataArg { dataArgName = s, 137 | dataArgArgtype = c Nothing, 138 | dataArgOptional = False }) 139 | 140 | -- |Generate the `argData` for the given optional argument with no default. 141 | argDataOptional :: String -- ^Datum print name. 142 | -> (Maybe a -> Argtype) -- ^Type constructor for datum. 143 | -> Maybe DataArg -- ^Result is `argData`-ready. 144 | argDataOptional s c = Just (DataArg { dataArgName = s, 145 | dataArgArgtype = c Nothing, 146 | dataArgOptional = True }) 147 | 148 | -- |Generate the `argData` for the given optional argument with the 149 | -- given default. 150 | argDataDefaulted :: String -- ^Datum print name. 151 | -> (Maybe a -> Argtype) -- ^Type constructor for datum. 152 | -> a -- ^Datum default value. 153 | -> Maybe DataArg -- ^Result is `argData`-ready. 154 | argDataDefaulted s c d = Just (DataArg { dataArgName = s, 155 | dataArgArgtype = c (Just d), 156 | dataArgOptional = True }) 157 | -- 158 | -- Returned datatypes. 159 | -- 160 | 161 | -- |The \"kinds of values\" an argument can have. 162 | data Argval = ArgvalFlag -- ^For simple present vs not-present flags. 163 | | ArgvalString String 164 | | ArgvalInteger Integer 165 | | ArgvalInt Int 166 | | ArgvalDouble Double 167 | | ArgvalFloat Float 168 | deriving (Show, Data, Typeable) 169 | 170 | -- |The type of the mapping from argument index to value. 171 | newtype ArgRecord a = ArgRecord (Map.Map a Argval) 172 | deriving (Show, Data, Typeable) 173 | 174 | -- |The data structure `parseArgs` produces. The key 175 | -- element is the `ArgRecord` `args`. 176 | data (Ord a) => Args a = 177 | Args { args :: ArgRecord a -- ^The argument map. 178 | , argsProgName :: String -- ^Basename of 0th argument. 179 | , argsUsage :: String -- ^Full usage string. 180 | , argsRest :: [ String ] -- ^Remaining unprocessed arguments. 181 | } 182 | deriving (Show, Data, Typeable) 183 | -- 184 | -- Implementation. 185 | -- 186 | 187 | -- |True if the described argument is positional. 188 | arg_posn :: (Ord a) => 189 | Arg a -- ^Argument. 190 | -> Bool -- ^True if argument is positional. 191 | arg_posn (Arg { argAbbr = Nothing, 192 | argName = Nothing }) = True 193 | arg_posn _ = False 194 | 195 | -- |True if the described argument is a flag. 196 | arg_flag :: (Ord a) => 197 | Arg a -- ^Argument. 198 | -> Bool -- ^True if argument is a flag. 199 | arg_flag a = not (arg_posn a) 200 | 201 | -- |True if the described argument is optional. 202 | arg_optional :: (Ord a) => 203 | Arg a -- ^Argument. 204 | -> Bool -- ^False if argument is required to be present. 205 | arg_optional (Arg { argData = Just (DataArg { dataArgOptional = b }) }) = b 206 | arg_optional _ = True 207 | 208 | -- |Return the value of a defaulted argument. 209 | arg_default_value :: (Ord a) 210 | => Arg a -- ^Argument. 211 | -> Maybe Argval -- ^Optional default value. 212 | arg_default_value arg@(Arg { argData = Just 213 | (DataArg { dataArgArgtype = da }) }) | 214 | arg_optional arg = 215 | defval da 216 | where 217 | defval (ArgtypeString (Just v)) = Just (ArgvalString v) 218 | defval (ArgtypeInteger (Just v)) = Just (ArgvalInteger v) 219 | defval (ArgtypeInt (Just v)) = Just (ArgvalInt v) 220 | defval (ArgtypeDouble (Just v)) = Just (ArgvalDouble v) 221 | defval (ArgtypeFloat (Just v)) = Just (ArgvalFloat v) 222 | defval _ = Nothing 223 | arg_default_value _ = Nothing 224 | 225 | -- |There's probably a better way to do this. 226 | perhaps b s = if b then s else "" 227 | 228 | -- |Format the described argument as a string. 229 | arg_string :: (Ord a) => 230 | Arg a -- ^Argument to be described. 231 | -> String -- ^String describing argument. 232 | arg_string a@(Arg { argAbbr = abbr, 233 | argName = name, 234 | argData = arg }) = 235 | (optionally "[") ++ 236 | (sometimes flag_abbr abbr) ++ 237 | (perhaps ((isJust abbr) && (isJust name)) ",") ++ 238 | (sometimes flag_name name) ++ 239 | (perhaps ((arg_flag a) && (isJust arg)) " ") ++ 240 | (sometimes data_arg arg) ++ 241 | (optionally "]") 242 | where 243 | sometimes = maybe "" 244 | optionally s = perhaps (arg_optional a) s 245 | flag_name s = "--" ++ s 246 | flag_abbr c = [ '-', c ] 247 | data_arg (DataArg {dataArgName = s}) = "<" ++ s ++ ">" 248 | 249 | -- |Filter out the empty keys for a hash. 250 | filter_keys :: [ (Maybe a, b) ] -- ^List of (optional key, value) pairs. 251 | -> [ (a, b) ] -- ^Pairs with actual keys. 252 | filter_keys l = 253 | foldr check_key [] l 254 | where 255 | check_key (Nothing, _) rest = rest 256 | check_key (Just k, v) rest = (k, v) : rest 257 | 258 | -- |Fail with an error if the argument description is bad 259 | -- for some reason. 260 | argdesc_error :: String -- ^Error message. 261 | -> a -- ^Bogus polymorphic result. 262 | argdesc_error msg = 263 | error ("internal error: argument description: " ++ msg) 264 | 265 | -- |Make a keymap. 266 | keymap_from_list :: (Ord k, Show k) => 267 | [ (k, a) ] -- ^List of key-value pairs. 268 | -- Will be checked for duplicate keys. 269 | -> Map.Map k a -- ^Key-value map. 270 | keymap_from_list l = 271 | foldl add_entry Map.empty l 272 | where 273 | add_entry m (k, a) = 274 | case Map.member k m of 275 | False -> Map.insert k a m 276 | True -> argdesc_error ("duplicate argument description name " ++ 277 | (show k)) 278 | 279 | -- |Make a keymap for looking up a flag argument. 280 | make_keymap :: (Ord a, Ord k, Show k) => 281 | ((Arg a) -> Maybe k) -- ^Mapping from argdesc to flag key. 282 | -> [ Arg a ] -- ^List of argdesc. 283 | -> (Map.Map k (Arg a)) -- ^Map from key to argdesc. 284 | make_keymap f_field args = 285 | (keymap_from_list . 286 | filter_keys . 287 | map (\arg -> (f_field arg, arg))) args 288 | 289 | -- |How \"sloppy\" the parse is. 290 | data ArgsComplete = ArgsComplete -- ^Any extraneous arguments 291 | -- (unparseable from description) 292 | -- will cause the parser to fail. 293 | | ArgsTrailing -- ^Trailing extraneous arguments are 294 | -- permitted, and will be skipped, 295 | -- saved, and returned. 296 | | ArgsInterspersed -- ^All extraneous arguments are 297 | -- permitted, and will be skipped, 298 | -- saved, and returned. 299 | deriving (Show, Data, Typeable) 300 | 301 | -- |The iteration function is given a state and a list, and 302 | -- expected to produce a new state and list. The function 303 | -- is again invoked with the resulting state and list. 304 | -- When the function returns the empty list, `exhaust` returns 305 | -- the final state produced. 306 | exhaust :: (s -> [e] -> ([e], s)) -- ^Function to iterate. 307 | -> s -- ^Initial state. 308 | -> [e] -- ^Initial list. 309 | -> s -- ^Final state. 310 | exhaust f s [] = s 311 | exhaust f s l = 312 | let (l', s') = f s l 313 | in exhaust f s' l' 314 | 315 | -- |Print an error message during parsing. 316 | parse_error :: String -- ^Usage message. 317 | -> String -- ^Specific error message. 318 | -> a -- ^Bogus polymorphic result. 319 | parse_error usage msg = error $ usage ++ "\n" ++ msg 320 | 321 | -- |Given a description of the arguments, `parseArgs` produces 322 | -- a map from the arguments to their \"values\" and some other 323 | -- useful byproducts. `parseArgs` requires that the argument 324 | -- descriptions occur in the order 1) flag arguments, 2) required 325 | -- positional arguments, 3) optional positional arguments; otherwise 326 | -- a runtime error will be thrown. 327 | parseArgs :: (Show a, Ord a) => 328 | ArgsComplete -- ^Degree of completeness of parse. 329 | -> [ Arg a ] -- ^Argument descriptions. 330 | -> String -- ^Full program pathname. 331 | -> [ String ] -- ^Incoming program argument list. 332 | -> Args a -- ^Outgoing argument parse results. 333 | parseArgs acomplete argd pathname argv = 334 | runST (do 335 | check_argd 336 | let flag_args = takeWhile arg_flag argd 337 | let posn_args = dropWhile arg_flag argd 338 | let name_hash = make_keymap argName flag_args 339 | let abbr_hash = make_keymap argAbbr flag_args 340 | let prog_name = baseName pathname 341 | let usage = make_usage_string prog_name 342 | let (am, posn, rest) = exhaust (parse usage name_hash abbr_hash) 343 | (Map.empty, posn_args, []) 344 | argv 345 | let required_args = filter (not . arg_optional) argd 346 | unless (and (map (check_present usage am) required_args)) 347 | (error "internal error") 348 | let am' = foldl supply_defaults am argd 349 | return (Args { args = ArgRecord am', 350 | argsProgName = prog_name, 351 | argsUsage = usage, 352 | argsRest = rest })) 353 | where 354 | supply_defaults am ad@(Arg { argIndex = k }) = 355 | case Map.lookup k am of 356 | Just _ -> am 357 | Nothing -> case arg_default_value ad of 358 | Just v -> Map.insert k v am 359 | Nothing -> am 360 | check_present usage am ad@(Arg { argIndex = k }) = 361 | case Map.lookup k am of 362 | Just _ -> True 363 | Nothing -> parse_error usage ("missing required argument " ++ (arg_string ad)) 364 | --- Check for various possible misuses. 365 | check_argd :: ST s () 366 | check_argd = do 367 | --- Order must be flags, posn args, optional posn args 368 | let residue = dropWhile arg_flag argd 369 | let residue' = dropWhile arg_fixed_posn residue 370 | let residue'' = dropWhile arg_opt_posn residue' 371 | unless (null residue'') 372 | (argdesc_error "argument description in wrong order") 373 | --- No argument may be "nullary". 374 | when (or (map arg_nullary argd)) 375 | (argdesc_error "bogus 'nothing' argument") 376 | return () 377 | where 378 | arg_fixed_posn a = (arg_posn a) && (not (arg_optional a)) 379 | arg_opt_posn a = (arg_posn a) && (arg_optional a) 380 | arg_nullary (Arg { argName = Nothing, 381 | argAbbr = Nothing, 382 | argData = Nothing }) = True 383 | arg_nullary _ = False 384 | --- Generate a usage message string 385 | make_usage_string prog_name = 386 | --- top (summary) line 387 | ("usage: " ++ prog_name) ++ 388 | (perhaps (not (null flag_args)) 389 | " [options]") ++ 390 | (perhaps (not (null posn_args)) 391 | (" " ++ (unwords (map arg_string posn_args)))) ++ 392 | (case acomplete of 393 | ArgsComplete -> "" 394 | _ -> " [--] ...") ++ 395 | "\n" ++ 396 | --- argument lines 397 | (concatMap (arg_line n) argd) 398 | where 399 | flag_args = filter arg_flag argd 400 | posn_args = filter arg_posn argd 401 | n = maximum (map (length . arg_string) argd) 402 | arg_line n a = 403 | let s = arg_string a in 404 | " " ++ s ++ 405 | (replicate (n - (length s)) ' ') ++ 406 | " " ++ (argDesc a) ++ "\n" 407 | --- simple recursive-descent parser 408 | parse _ _ _ av@(_, _, []) [] = ([], av) 409 | parse usage _ _ av [] = 410 | case acomplete of 411 | ArgsComplete -> parse_error usage "unexpected extra arguments" 412 | _ -> ([], av) 413 | parse usage name_hash abbr_hash (am, posn, rest) av@(aa : aas) = 414 | case aa of 415 | "--" -> case acomplete of 416 | ArgsComplete -> parse_error usage ("unexpected -- " ++ "(extra arguments not allowed)") 417 | _ -> ([], (am, posn, (rest ++ aas))) 418 | s@('-' : '-' : name) -> 419 | case Map.lookup name name_hash of 420 | Just ad -> peel s ad aas 421 | Nothing -> 422 | case acomplete of 423 | ArgsInterspersed -> 424 | (aas, (am, posn, rest ++ ["--" ++ name])) 425 | _ -> parse_error usage ("unknown argument --" ++ name) 426 | ('-' : abbr : abbrs) -> 427 | case Map.lookup abbr abbr_hash of 428 | Just ad -> 429 | let p@(args', state') = peel ['-', abbr] ad aas 430 | in case abbrs of 431 | [] -> p 432 | ('-' : _) -> parse_error usage ("bad internal '-' in argument " ++ aa) 433 | _ -> (['-' : abbrs] ++ args', state') 434 | Nothing -> 435 | case acomplete of 436 | ArgsInterspersed -> 437 | (['-' : abbrs] ++ aas, 438 | (am, posn, rest ++ [['-', abbr]])) 439 | _ -> parse_error usage ("unknown argument -" ++ [abbr]) 440 | aa -> case posn of 441 | (ad@(Arg { argData = Just adata }) : ps) -> 442 | let (argl', (am', _, rest')) = 443 | peel_process (dataArgName adata) ad av 444 | in (argl', (am', ps, rest')) 445 | [] -> case acomplete of 446 | ArgsComplete -> parse_error usage ("unexpected argument " ++ aa) 447 | _ -> (aas, (am, [], rest ++ [aa])) 448 | where 449 | add_entry s m (k, a) = 450 | case Map.member k m of 451 | False -> Map.insert k a m 452 | True -> parse_error usage ("duplicate argument " ++ s) 453 | peel name ad@(Arg { argData = Nothing, argIndex = index }) argl = 454 | let am' = add_entry name am (index, ArgvalFlag) 455 | in (argl, (am', posn, rest)) 456 | peel name (Arg { argData = Just (DataArg {}) }) [] = 457 | parse_error usage (name ++ " is missing its argument") 458 | peel name ad argl = peel_process name ad argl 459 | peel_process name 460 | ad@(Arg { argData = Just (DataArg { 461 | dataArgArgtype = atype }), 462 | argIndex = index }) 463 | (a : argl) = 464 | let v = case atype of 465 | ArgtypeString _ -> ArgvalString a 466 | ArgtypeInteger _ -> ArgvalInteger (read a) 467 | ArgtypeInt _ -> ArgvalInt (read a) 468 | ArgtypeDouble _ -> ArgvalDouble (read a) 469 | ArgtypeFloat _ -> ArgvalFloat (read a) 470 | am' = add_entry name am (index, v) 471 | in (argl, (am', posn, rest)) 472 | 473 | 474 | -- |Most of the time, you just want the environment's 475 | -- arguments and are willing to live in the IO monad. 476 | -- This version of `parseArgs` digs the pathname and arguments 477 | -- out of the system directly. 478 | parseArgsIO :: (Show a, Ord a) => 479 | ArgsComplete -- ^Degree of completeness of parse. 480 | -> [ Arg a ] -- ^Argument descriptions. 481 | -> IO (Args a) -- ^Argument parse results. 482 | parseArgsIO acomplete argd = do 483 | argv <- getArgs 484 | pathname <- getProgName 485 | return (parseArgs acomplete argd pathname argv) 486 | 487 | 488 | -- |Check whether a given optional argument was supplied. Works on all types. 489 | gotArg :: (Ord a) => 490 | Args a -- ^Parsed arguments. 491 | -> a -- ^Index of argument to be checked for. 492 | -> Bool -- ^True if the arg was present. 493 | gotArg (Args { args = ArgRecord am }) k = 494 | case Map.lookup k am of 495 | Just _ -> True 496 | Nothing -> False 497 | 498 | -- |Type of values that can be parsed by the argument parser. 499 | class ArgType b where 500 | -- |Fetch an argument's value if it is present. 501 | getArg :: (Show a, Ord a) 502 | => Args a -- ^Parsed arguments. 503 | -> a -- ^Index of argument to be retrieved. 504 | -> Maybe b -- ^Argument value if present. 505 | -- |Fetch the value of a required argument. 506 | getRequiredArg :: (Show a, Ord a) 507 | => Args a -- ^Parsed arguments. 508 | -> a -- ^Index of argument to be retrieved. 509 | -> b -- ^Argument value. 510 | getRequiredArg args index = 511 | case getArg args index of 512 | Just v -> v 513 | Nothing -> error ("internal error: required argument " 514 | ++ show index ++ "not supplied") 515 | 516 | getArgPrimitive decons (Args { args = ArgRecord am }) k = 517 | case Map.lookup k am of 518 | Just v -> Just (decons v) 519 | Nothing -> Nothing 520 | 521 | instance ArgType ([] Char) where 522 | getArg = getArgPrimitive (\(ArgvalString s) -> s) 523 | 524 | -- |[Deprecated] Return the `String` value, if any, of the given argument. 525 | getArgString :: (Show a, Ord a) => 526 | Args a -- ^Parsed arguments. 527 | -> a -- ^Index of argument to be retrieved. 528 | -> Maybe String -- ^Argument value if present. 529 | getArgString = getArg 530 | 531 | instance ArgType Integer where 532 | getArg = getArgPrimitive (\(ArgvalInteger i) -> i) 533 | 534 | -- |[Deprecated] Return the `Integer` value, if any, of the given argument. 535 | getArgInteger :: (Show a, Ord a) => 536 | Args a -- ^Parsed arguments. 537 | -> a -- ^Index of argument to be retrieved. 538 | -> Maybe Integer -- ^Argument value if present. 539 | getArgInteger = getArg 540 | 541 | instance ArgType Int where 542 | getArg = getArgPrimitive (\(ArgvalInt i) -> i) 543 | 544 | -- |[Deprecated] Return the `Int` value, if any, of the given argument. 545 | getArgInt :: (Show a, Ord a) => 546 | Args a -- ^Parsed arguments. 547 | -> a -- ^Index of argument to be retrieved. 548 | -> Maybe Int -- ^Argument value if present. 549 | getArgInt = getArg 550 | 551 | instance ArgType Double where 552 | getArg = getArgPrimitive (\(ArgvalDouble i) -> i) 553 | 554 | -- |[Deprecated] Return the `Double` value, if any, of the given argument. 555 | getArgDouble :: (Show a, Ord a) => 556 | Args a -- ^Parsed arguments. 557 | -> a -- ^Index of argument to be retrieved. 558 | -> Maybe Double -- ^Argument value if present. 559 | getArgDouble = getArg 560 | 561 | instance ArgType Float where 562 | getArg = getArgPrimitive (\(ArgvalFloat i) -> i) 563 | 564 | -- |[Deprecated] Return the `Float` value, if any, of the given argument. 565 | getArgFloat :: (Show a, Ord a) => 566 | Args a -- ^Parsed arguments. 567 | -> a -- ^Index of argument to be retrieved. 568 | -> Maybe Float -- ^Argument value if present. 569 | getArgFloat = getArg 570 | 571 | -- |`ArgType` instance for opening a file from its string name. 572 | newtype ArgFileOpener = ArgFileOpener { 573 | argFileOpener :: IOMode -> IO Handle -- ^Function to open the file 574 | } 575 | 576 | instance ArgType ArgFileOpener where 577 | getArg args index = 578 | case getArg args index of 579 | Nothing -> Nothing 580 | Just s -> Just (ArgFileOpener { argFileOpener = openFile s }) 581 | 582 | -- |[Deprecated] Treat the `String` value, if any, of the given argument as 583 | -- a file handle and try to open it as requested. 584 | getArgFile :: (Show a, Ord a) => 585 | Args a -- ^Parsed arguments. 586 | -> a -- ^Index of argument to be retrieved. 587 | -> IOMode -- ^IO mode the file should be opened in. 588 | -> IO (Maybe Handle) -- ^Handle of opened file, if the argument 589 | -- was present. 590 | getArgFile args k m = 591 | case getArg args k of 592 | Just fo -> (do h <- argFileOpener fo m; return (Just h)) 593 | Nothing -> return Nothing 594 | 595 | 596 | -- |Treat the `String` value, if any, of the given argument as a 597 | -- file handle and try to open it as requested. If not 598 | -- present, substitute the appropriate one of stdin or 599 | -- stdout as indicated by `IOMode`. 600 | getArgStdio :: (Show a, Ord a) => 601 | Args a -- ^Parsed arguments. 602 | -> a -- ^Index of argument to be retrieved. 603 | -> IOMode -- ^IO mode the file should be opened in. 604 | -- Must not be `ReadWriteMode`. 605 | -> IO Handle -- ^Appropriate file handle. 606 | getArgStdio args k m = 607 | case getArg args k of 608 | Just s -> openFile s m 609 | Nothing -> 610 | case m of 611 | ReadMode -> return stdin 612 | WriteMode -> return stdout 613 | AppendMode -> return stdout 614 | ReadWriteMode -> 615 | error ("internal error: tried to open stdio " 616 | ++ "in ReadWriteMode") 617 | 618 | --- 619 | --- Misc 620 | --- 621 | 622 | -- |Return the filename part of a pathname. 623 | -- Unnecessarily efficient implementation does a single 624 | -- tail-call traversal with no construction. 625 | baseName :: String -- ^Pathname. 626 | -> String -- ^Rightmost component of pathname. 627 | baseName s = 628 | let s' = dropWhile (/= '/') s in 629 | if null s' then s else baseName (tail s') 630 | 631 | 632 | -- |Generate a usage error with the given supplementary message string. 633 | usageError :: (Ord a) => Args a -> String -> b 634 | usageError args msg = error (argsUsage args ++ "\n" ++ msg) 635 | -------------------------------------------------------------------------------- /ActionhaXe/Translator.hs: -------------------------------------------------------------------------------- 1 | {- 2 | as3tohaxe - An Actionscript 3 to haXe source file translator 3 | Copyright (C) 2008 Don-Duong Quach 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | -} 18 | -- Translate an Actionscript 3 AST to haXe and hxml for Flash 10 19 | 20 | module ActionhaXe.Translator where 21 | 22 | import ActionhaXe.Lexer 23 | import ActionhaXe.Data 24 | import ActionhaXe.Prim 25 | import ActionhaXe.Parser 26 | import ActionhaXe.CLArgs 27 | import qualified System.Console.ParseArgs as PA 28 | 29 | import Data.Map (Map) 30 | import qualified Data.Map as Map 31 | import Control.Monad.State 32 | import Data.Foldable (foldlM, foldrM) 33 | import Data.List (intercalate) 34 | import Data.Char (toUpper, isUpper, isAlphaNum) 35 | import Data.Generics -- not Haskell 98 36 | import Data.Maybe (isJust) 37 | 38 | -- subRegex, mkRegex used for text replacement 39 | import Text.Regex 40 | 41 | -- flags 42 | mainPackage = "mainPackage" 43 | fpackage = "packageName" 44 | fclass = "className" 45 | fclassAttr = "classAttr" 46 | hasConstructor = "hasConstructor" 47 | 48 | updateFlag flag val = do st <- get 49 | put st{flags = Map.insert flag val (flags st)} 50 | 51 | deleteFlag flag = do st <- get 52 | put st{flags = Map.delete flag (flags st)} 53 | 54 | getFlag :: String -> StateT AsState IO String 55 | getFlag flag = do st <- get 56 | case Map.lookup flag $ flags st of 57 | Just mval -> return mval 58 | Nothing -> return "" 59 | {- if Map.member flag $ flags st 60 | then do mval <- Map.lookup flag $ flags st 61 | return mval 62 | else return "" 63 | -} 64 | 65 | insertInitMember output = do st <- get 66 | put st{initMembers = (output:(initMembers st))} 67 | st' <- get 68 | return () 69 | 70 | getMembers = do st <- get 71 | let ret = reverse $ initMembers st 72 | return ret 73 | 74 | getCLArg f = do st <- get 75 | return $ PA.gotArg (confArgs (conf st)) f 76 | 77 | maybeEl f i = maybe "" (\m -> f m) i 78 | 79 | cleanup s = subRegex (mkRegex "\\$") s "_S_" 80 | 81 | --translateAs3Ast :: Ast -> StateT AsState IO String 82 | translateAs3Ast p = 83 | case p of 84 | AS3Program x st -> program x >>= return 85 | AS3Directives x st -> directives x >>= return 86 | 87 | directives ds = foldlM (\str i -> do{s <- directive i; return $ str++s}) "" ds 88 | where directive d = case d of 89 | Tok t -> do{ t' <- tok t; return $ cleanup t'} 90 | ImportDecl _ _ _ -> do{ d' <- importDecl d; return $ cleanup $ d'} 91 | Metadata m -> do{ m' <- metadata m; return $ cleanup m'} 92 | MethodDecl _ _ _ _ _ _ -> do{ d' <- methodDecl d; return $ cleanup d'} 93 | VarS _ _ _ _ -> do{ d' <- memberVarS d; return $ cleanup d'} 94 | _ -> return "--unexpected directive--" 95 | 96 | --program :: Package -> StateT AsState IO String 97 | program (Package w p n b) = do case n of 98 | Just ntok -> do{ updateFlag fpackage $ showd ntok ; x <- packageBlock b; return $ cleanup $ showb w ++ showd p ++" "++ showd ntok ++ ";" ++ showw ntok ++ x} 99 | Nothing -> do{ updateFlag fpackage mainPackage; x <-packageBlock b; return $ cleanup $ showb w ++ showw p ++ x} 100 | 101 | packageBlock (Block l bs r) = do 102 | bi <- foldlM (\s b -> do{ x <- packageBlockItem b; return $ s ++ x} ) "" bs 103 | return $ showw l ++ bi 104 | 105 | classBlock (Block l bs r) = do 106 | x <- get 107 | let a = accessors x 108 | let al = Map.toList a 109 | props <- foldlM (\str (k, (t, g, s)) -> do{ t' <- datatype t 110 | ; return $ str ++ showws l ++ "public var " ++ k ++ "(" 111 | ++ (if g then "get"++ [toUpper $ head k] ++ tail k else "null") ++ ", " 112 | ++ (if s then "set"++ [toUpper $ head k] ++ tail k else "null") 113 | ++ ") : " ++ t' ++ ";" 114 | } 115 | ) "" al 116 | bi <- foldlM (\s b -> do{ x <- classBlockItem b; return $ s ++ x} ) "" bs 117 | nc <- checkConstructor l 118 | return $ showd l ++ showw l ++ nc ++ props ++ showw l ++ bi ++ showb r 119 | 120 | checkConstructor l = do 121 | con <- getFlag hasConstructor 122 | x <- getMembers 123 | if con == "" 124 | then do let (nl, i) = getNlIndent l 125 | initM <- getInitMembers l 126 | return $ "public function new() { " ++ initM ++ "}"++ nl ++ i 127 | else return "" 128 | 129 | interfaceBlock (Block l bs r) = do 130 | bi <- foldlM (\s b -> do{ x <- interfaceBlockItem b; return $ s ++ x} ) "" bs 131 | return $ showb l ++ bi ++ showb r 132 | 133 | blockItemFold bs = foldlM (\s b -> do{ x <- blockItem b; return $ s ++ x} ) "" bs 134 | 135 | block (Block l bs r) = do 136 | bi <- blockItemFold bs 137 | return $ showb l ++ bi ++ showb r 138 | 139 | constructorBlock (Block l bs r) = do 140 | bi <- blockItemFold bs 141 | initM <- getInitMembers l 142 | return $ showb l ++ initM ++ bi ++ showb r 143 | 144 | getNlIndent l = 145 | let spacebreak = break (\c -> c == '\n') ( reverse $ showw l) 146 | i = reverse $ fst spacebreak 147 | nl = if length (snd spacebreak) > 1 && (snd spacebreak)!!1 == '\r' then "\r\n" else "\n" 148 | in (nl, i) 149 | 150 | getInitMembers l = 151 | do let (nl, i) = getNlIndent l 152 | x <- getMembers 153 | if length x > 0 154 | then return $ nl++i++ intercalate (nl++i) x ++ nl ++ i 155 | else return $ "" 156 | 157 | 158 | packageBlockItem b = 159 | do x <- case b of 160 | Tok t -> tok t >>= return 161 | ImportDecl _ _ _ -> importDecl b >>= return 162 | ClassDecl _ _ _ _ _ _ -> classDecl b >>= return 163 | Interface _ _ _ _ _ -> interface b >>= return 164 | Metadata m -> metadata m >>= return 165 | _ -> return "" 166 | return x 167 | 168 | classBlockItem b = 169 | do x <- case b of 170 | Tok t -> tok t >>= return 171 | MethodDecl _ _ _ _ _ _ -> methodDecl b >>= return 172 | VarS _ _ _ _ -> memberVarS b >>= return 173 | Metadata m -> metadata m >>= return 174 | Block _ _ _ -> block b >>= return 175 | _ -> return $ show b 176 | return x 177 | 178 | interfaceBlockItem b = 179 | do x <- case b of 180 | Tok t -> tok t >>= return 181 | MethodDecl _ _ _ _ _ _ -> imethodDecl b >>= return 182 | Metadata m -> metadata m >>= return 183 | _ -> return $ show b 184 | return x 185 | 186 | blockItem b = 187 | do x <- case b of 188 | Tok t -> tok t >>= return 189 | Block _ _ _ -> block b >>= return 190 | VarS _ _ _ _ -> varS b >>= return 191 | ForS _ _ _ _ _ _ _ _ _ -> forS b >>= return 192 | ForInS _ _ _ _ _ _ _ _ -> forInS b >>= return 193 | Expr _ -> expr b >>= return 194 | Metadata m -> metadata m >>= return 195 | _ -> return "" 196 | return x 197 | 198 | tok t = do let x = showb t 199 | f <- getFlag fpackage 200 | return x 201 | 202 | metadata m = case m of 203 | MD l t x r -> do{ return $ "/*" ++ showb l ++ showb t ++ showl x++ showd r ++ "*/" ++ showw r} 204 | MDSwf attr -> do{ o <- swfheader attr ["400", "300", "30", "FFFFFF"] 205 | ; st <- get 206 | ; let outclass = reverse $ drop 3 $ reverse $ filename st 207 | ; liftIO $ writeFile ((outfile st) ++ "ml") ("-swf "++outclass++".swf\n-main "++outclass++"\n-swf-version 10\n-swf-header " ++ o) 208 | ; return "" 209 | } 210 | where swfheader ((k, v):as) [w, h, f, b] = 211 | case showd k of 212 | "width" -> swfheader as [init.tail $ showd v, h, f, b] 213 | "height" -> swfheader as [w, init.tail $ showd v, f, b] 214 | "frameRate" -> swfheader as [w, h, init.tail $ showd v, b] 215 | "backgroundColor" -> swfheader as [w, h, f, tail.init.tail $ showd v] 216 | swfheader [] header = return $ intercalate ":" header 217 | 218 | importDecl (ImportDecl i n s) = do 219 | ci <- getCLArg CreateImports 220 | let show_n = showd n 221 | let n' = if ci && elem '*' show_n 222 | then (\(h, t) -> init h ++ tail t) $ break (== '*') $ subRegex (mkRegex "\\.") ("Import_" ++ show_n) "_" 223 | else show_n 224 | return $ showb i ++ n' ++ maybeEl showb s 225 | 226 | 227 | classDecl (ClassDecl a c n e i b) = do 228 | updateFlag fclass $ showd n 229 | updateFlag fclassAttr $ publicAttr a 230 | x <- classBlock b 231 | let e' = maybe [] (\(k, c) -> if showd c == "Object" then [] else [showb k ++ showd c] ) e 232 | let i' = maybe [] (\(ic, cs) -> map (\(x, co) -> showb ic ++ showd x) cs ) i 233 | let i'' = i' ++ if "dynamic" `elem` map (\a' -> showd a') a then ["implements Dynamic"] else [""] 234 | let ei = intercalate ", " $ filter (\x -> length x > 0) $ e'++i'' 235 | return $ showb c ++ showb n ++ ei ++ " " ++ x 236 | where publicAttr as = if "public" `elem` map (\a -> showd a) as then "public" else "private" 237 | 238 | interface (Interface a i n e b) = do 239 | x <- interfaceBlock b 240 | let e' = maybe [] (\(ic, cs) -> map (\(x, co) -> "implements " ++ showd x) cs ) e 241 | let i' = intercalate ", " e' 242 | return $ showb i ++ showb n ++ i' ++ x 243 | 244 | methodDecl (MethodDecl a f ac n s b) = do 245 | packageName <- getFlag fpackage 246 | className <- getFlag fclass 247 | classAttr <- getFlag fclassAttr 248 | if packageName == mainPackage && className == (showd n) && classAttr == "public" 249 | then do{ x <- maybe (return "") block b; return $ "static " ++ showb f ++ "main() "++ x } 250 | else if className == (showd n) 251 | then do{ updateFlag hasConstructor "true"; x <- maybe (return "") constructorBlock b; s' <- signatureArgs s; return $ namespace a ++ showb f ++ "new"++showw n ++ s' ++ x } 252 | else do st <- get 253 | let accMap = accessors st 254 | case Map.lookup (showd n) accMap of 255 | Just (t, _, _) -> do let arg = getArg s 256 | x <- maybe (return "" ) (accblock arg ac) b 257 | acc' <- accessor ac n s t 258 | return $ namespace a ++ showb f ++ acc' ++ x 259 | Nothing -> do x <- maybe (return "") block b 260 | s' <- signature s 261 | return $ namespace a ++ showb f ++ showb n ++ s' ++ x 262 | where accessor ac name s@(Signature l args r ret) t = 263 | case ac of 264 | Just x -> do{ a <- showArgs args 265 | ; t' <- datatypet t 266 | ; return $ showd x ++ [toUpper $ head $ showd name] ++ tail (showb name) ++ showb l ++ a ++ showd r ++ ":" 267 | ++ fst t' ++ (case ret of { Just (c, t) -> snd t'; Nothing -> showw r}) 268 | } 269 | Nothing -> do{ s' <- signature s; return $ showb name ++ s'} 270 | accblock arg ac (Block l bs r) = 271 | do let ts = case ac of { Just x -> if showd x == "set" then "\treturn "++arg++";"++ initl l else ""; Nothing -> ""} 272 | bi <- blockItemFold bs 273 | return $ showb l ++ bi ++ ts ++ showb r 274 | initl l = if length (showw l) > 0 275 | then init $ showw l 276 | else "" 277 | getArg (Signature l (a@(Arg n c t md mc):as) r ret) = showd n 278 | getArg (Signature l [] r ret) = "" 279 | 280 | 281 | imethodDecl (MethodDecl a f ac n s b) = do 282 | s' <- signature s 283 | return $ attr a ++ showb f ++ showb n ++ s' 284 | where attr as = concat $ map (\attr -> case (showd attr) of { "internal" -> "public" ++ showw attr; x -> showb attr }) as 285 | 286 | 287 | signatureArgs (Signature l args r ret) = do{ a <- showArgs args 288 | ; return $ showb l ++ a ++ showb r 289 | } 290 | 291 | rettype ret = case ret of 292 | Just (c, t) -> do{ t' <- datatype t; return $ showb c ++ t'} 293 | Nothing -> return "" 294 | 295 | signature (Signature l args r ret) = do{ a <- showArgs args 296 | ; ret' <- rettype ret 297 | ; return $ showb l ++ a ++ showb r ++ ret' 298 | } 299 | 300 | showArgs as = do{ as' <- mapM showArg as; return $ concat as'} 301 | where showArg (Arg n c t i mc) = do{ i' <- maybe (return "") (\(o, e) -> do{ e' <- assignE e; return $ showb o ++ e'}) i 302 | ; t' <- datatypeiM t i 303 | ; return $ (case i of{ Just d -> "?"; Nothing -> ""}) ++ showb n ++ showb c ++ t' ++ i' ++ maybeEl showb mc 304 | } 305 | showArg (RestArg o n t) = do{ return $ showd n ++ ":Array"} 306 | 307 | memberVarS (VarS ns k v@(VarBinding n d _) vs) = do 308 | if elem "static" (map (\n -> showd n) ns) 309 | then do v' <- varBinding v 310 | vs' <- foldlM (\s (c, x) -> do{ x' <- varBinding x; return $ s ++ showb c ++ x'}) "" vs 311 | -- let inl = if hasPrimitive v && length vs == length (filter (\(c, v) -> hasPrimitive v) vs) && foldr (\x s -> isUpper x && s ) True (showd n) then "inline " else "" 312 | -- return $ inl ++ namespace ns ++ "var" ++ showw k ++ v' ++ vs' 313 | return $ namespace ns ++ "var" ++ showw k ++ v' ++ vs' 314 | else do{ v' <- varBindingInitMember v; vs' <- foldlM (\s (c, x) -> do{ x' <- varBindingInitMember x; return $ s ++ showb c ++ x'}) "" vs; return $ namespace ns ++ "var" ++ showw k ++ v' ++ vs'} 315 | 316 | {- 317 | hasPrimitive = everything (||) (False `mkQ` hasPrimitive') 318 | 319 | hasPrimitive' (TokenNum _) = True 320 | hasPrimitive' (TokenString _) = True 321 | hasPrimitive' (TokenKw "true") = True 322 | hasPrimitive' (TokenKw "false") = True 323 | hasPrimitive' _ = False 324 | -} 325 | 326 | varS (VarS ns k v vs) = do{ v' <- varBinding v; vs' <- foldlM (\s (c, x) -> do{ x' <- varBinding x; return $ s++ showb c ++x' }) "" vs; return $ namespace ns ++ "var" ++ showw k ++ v' ++ vs'} 327 | 328 | 329 | varBinding' (VarBinding n dt i) = 330 | do{ d' <- case dt of 331 | Just (c, t) -> do{ d <- datatypeiM t i; return $ showb c ++ d} 332 | Nothing -> case i of -- try to determine type from initializer 333 | Just (o, e) -> do let e' = getType e 334 | case e' of 335 | Just t -> return $ ":" ++ t ++ showw n -- set type to initializer's type 336 | Nothing -> return $ ":Dynamic" ++ showw n -- can't determine type 337 | Nothing -> return $ ":Dynamic" ++ showw n -- no datatype, no initializer 338 | ; i' <- maybe (return "") (\(o, e) -> do{ e' <- assignE e; return $ showb o ++ e'}) i; 339 | ; return (d', i') 340 | } 341 | 342 | --varBinding :: VarBinding -> StateT AsState IO String 343 | varBinding (VarBinding n dt i) = 344 | do (d', i') <- varBinding' (VarBinding n dt i) 345 | return $ showd n ++ d' ++ i' 346 | 347 | varBindingInitMember (VarBinding n dt i) = 348 | do (d', i') <- varBinding' (VarBinding n dt i) 349 | if i' /= "" 350 | then do insertInitMember $ showb n ++ (if last(showb n) == ' ' then "" else " ") ++ i' ++ ";" 351 | return $ showd n ++ d' 352 | else return $ showd n ++ d' ++ i' 353 | 354 | 355 | 356 | 357 | getType = everything orElse ((Nothing `mkQ` getTypeTokenNum) `extQ` getTypeTokenType) 358 | 359 | getTypeTokenNum (TokenDouble x) = Just "Float" 360 | getTypeTokenNum (TokenInteger x) = Just "Int" 361 | getTypeTokenNum (TokenHex x) = Just "Int" 362 | getTypeTokenNum (TokenOctal x) = Just "Int" 363 | getTypeTokenType (TokenString x) = Just "String" 364 | getTypeTokenType (TokenKw "true") = Just "Bool" 365 | getTypeTokenType (TokenKw "false") = Just "Bool" 366 | getTypeTokenType _ = Nothing 367 | 368 | namespace ns = concat $ map (\attr -> (case showd attr of { "private" -> "" -- all fields by default are private 369 | ; "protected" -> "" -- in haXe private fields are accessible by subclasses 370 | ; "internal" -> "public" ++ showw attr -- internal fields are used by different packages in as3 371 | ; "dynamic" -> "dynamic /*class must implement Dynamic*/" ++ showw attr 372 | ; "final" -> "" 373 | ; _ -> showb attr 374 | } 375 | ) ) ns 376 | 377 | datatypet d = do{ d' <- datatype d; return $ span (\c -> isAlphaNum c || c =='>' || c == '<') d'} 378 | 379 | datatype :: AsType -> StateT AsState IO String 380 | datatype d = 381 | case d of 382 | AsType n -> do d' <- (case (showd n) of 383 | "void" -> return "Void" 384 | "Boolean" -> return "Bool" 385 | "uint" -> return "UInt" 386 | "int" -> return "Int" 387 | "Number" -> do ni <- getCLArg NumberToInt 388 | if ni 389 | then return "Int" 390 | else return "Float" 391 | "String" -> return "String" 392 | "*" -> return "Dynamic" 393 | "Object" -> return "Dynamic" 394 | "Function"-> return "Dynamic" 395 | "Array" -> return "Array" 396 | "XML" -> return "XML" 397 | "RegExp" -> return "EReg" 398 | "Class" -> return "Class" 399 | ) 400 | return $ d' ++ showw n 401 | AsTypeRest -> return "Array" 402 | AsTypeUser n -> return $ showb n 403 | 404 | -- Changes type based on initializer value 405 | datatypeiM d Nothing = datatype d 406 | datatypeiM d i = 407 | case d of 408 | AsType n -> do{ r <- case (showd n) of 409 | "void" -> return "Void" 410 | "Boolean" -> return "Bool" 411 | "uint" -> return "UInt" 412 | "int" -> return "Int" 413 | "Number" -> do case i of 414 | Just (o, e) -> do{ if hasIntegerInit e 415 | then return "Int" 416 | else return "Float" 417 | } 418 | Nothing -> do ni <- getCLArg NumberToInt 419 | if ni 420 | then return "Int" 421 | else return "Float" 422 | 423 | "String" -> return "String" 424 | "*" -> return "Dynamic" 425 | "Object" -> return "Dynamic" 426 | "Function"-> return "Dynamic" 427 | "Array" -> return "Array" 428 | "XML" -> return "XML" 429 | "RegExp" -> return "EReg" 430 | "Class" -> return "Class" 431 | ; return $ r ++ showw n 432 | } 433 | AsTypeRest -> return $ "Array" 434 | AsTypeUser n -> return $ showb n 435 | 436 | hasIntegerInit = everything (||) (False `mkQ` isIntegerInit) 437 | 438 | isIntegerInit (TokenInteger x) = True 439 | isIntegerInit _ = False 440 | 441 | {- 442 | hasFloat = everything (||) (False `mkQ` isFloat) 443 | 444 | isFloat (TokenDouble x) = True 445 | isFloat _ = False 446 | -} 447 | 448 | primaryE x = case x of 449 | PEThis x -> do{ return $ showb x} 450 | PEIdent x -> do{ return $ showb x} 451 | PELit x -> do{ return $ showb x} 452 | PEArray x -> do{ r <- arrayLit x; return r} 453 | PEObject x -> do{ r <- objectLit x; return r} 454 | PEXml x -> do{ return $ "Xml.parse(\""++ showd x ++ "\")" ++ showw x} 455 | PEFunc x -> do{ r <- funcE x; return r} 456 | PEParens l x r -> do{ v <- listE x; return $ showb l ++ v ++ showd r ++ showw r} 457 | 458 | arrayLit (ArrayLitC l x r) = do{ return $ showb l ++ maybe "" elision x ++ showb r } 459 | 460 | arrayLit (ArrayLit l x r) = do{ e <- elementList x; return $ showb l ++ e ++ showb r} 461 | 462 | elementList (El l e el r) = do{ es <- assignE e; els <- foldrM (\(EAE c p) s -> do{ ps <- assignE p; return $ elision c ++ ps ++ s}) "" el; return $ maybeEl elision l ++ es ++ els ++ maybeEl elision r } 463 | 464 | elision (Elision x) = showl x 465 | 466 | objectLit (ObjectLit l x r) = do{ p <- maybe (return "") propertyNameAndValueList x; return $ showb l ++ p ++ showb r} 467 | 468 | propertyNameAndValueList (PropertyList x) = do 469 | p <- foldrM (\(p, c, e, s) str -> do{ ex <- assignE e; return $ showb p ++ showb c ++ ex ++ maybe "" showb s ++ str}) "" x 470 | return p 471 | 472 | funcE (FuncE f i s b) = do{ x <- block b; s' <- signature s; return $ showb f ++ s' ++ x} 473 | 474 | listE (ListE l) = do{ x <- foldrM (\(e, c) s -> do{es <- assignE e; return $ es ++ maybe "" showb c ++ s} ) "" l; return x} 475 | 476 | listENoIn = listE 477 | 478 | postFixE x = case x of 479 | PFFull p o -> do{ p' <- fullPostFixE p; o' <- postFixUp o; return $ p' ++ o'} 480 | PFShortNew p o -> do{ p' <- shortNewE p; o' <- postFixUp o; return $ p' ++ o'} 481 | where postFixUp o = return $ maybe "" showb o 482 | 483 | fullPostFixE x = case x of 484 | FPFPrimary p sb -> do{ e <- primaryE p; sub <- foldsub sb; return $ e ++ sub} 485 | FPFFullNew f sb -> do{ e <- fullNewE f; sub <- foldsub sb; return $ e ++ sub} 486 | FPFSuper s p sb -> do{ e <- superE s; p' <- propertyOp p; sub <- foldsub sb; return $ e ++ p' ++ sub} 487 | where foldsub sb = foldrM (\a b -> do{c <- fullPostFixSubE a; return $ c ++ b}) "" sb 488 | 489 | fullPostFixSubE x = case x of 490 | FPSProperty p -> propertyOp p >>= return 491 | FPSArgs a -> args a >>= return 492 | FPSQuery q -> queryOp q >>= return 493 | 494 | fullNewE (FN k e a) = do{ e' <- fullNewSubE e; a' <- args a; return $ showb k ++ e' ++ a'} 495 | 496 | fullNewSubE x = case x of 497 | FN _ _ _ -> do{ e <- fullNewE x; return e} 498 | FNPrimary e p -> do{ e' <- primaryE e; p' <- foldprop p; return $ e' ++ p'} 499 | FNSuper e p -> do{ e' <- superE e; p' <- foldprop p; return $ e' ++ p'} 500 | where foldprop p = foldrM (\a b -> do{ a' <- propertyOp a; return $ a' ++ b}) "" p 501 | 502 | shortNewE (SN k s) = do{ s' <- shortNewSubE s; return $ showb k ++ s'} 503 | 504 | shortNewSubE x = case x of 505 | SNSFull e -> fullNewSubE e >>= return 506 | SNSShort e -> shortNewE e >>= return 507 | 508 | superE (SuperE k p) = do{ p' <- maybe (return "") args p; return $ showb k ++ p'} 509 | 510 | propertyOp x = case x of 511 | PropertyOp o n -> return $ showb o ++ showb n 512 | PropertyB l e r -> do{ e' <- listE e; return $ showb l ++ e' ++ showb r } 513 | 514 | args (Arguments l e r) = do{ e' <- maybe (return "") listE e; return $ showb l ++ e' ++ showb r} 515 | 516 | queryOp x = case x of 517 | QueryOpDD o n -> return $ showb o ++ showb n 518 | QueryOpD o l e r -> do{ e' <- listE e; return $ showb o ++ showb l ++ e' ++ showb r} 519 | 520 | unaryE x = case x of 521 | UEDelete k p -> do if checkDelete p 522 | then deleteField p >>= return 523 | else do{ p' <- postFixE p ; return $ showb k ++ p'} 524 | UEVoid k p -> do{ p' <- postFixE p; return $ showb k ++ p'} 525 | UETypeof k p -> do{ p' <- postFixE p; return $ showb k ++ p'} 526 | UEInc o p -> do{ p' <- postFixE p; return $ showb o ++ p'} 527 | UEDec o p -> do{ p' <- postFixE p; return $ showb o ++ p'} 528 | UEPlus o p -> do{ p' <- unaryE p; return $ showb o ++ p'} 529 | UEMinus o p -> do{ p' <- unaryE p; return $ showb o ++ p'} 530 | UEBitNot o p -> do{ p' <- unaryE p; return $ showb o ++ p'} 531 | UENot o p -> do{ p' <- unaryE p; return $ showb o ++ p'} 532 | UEPrimary p -> postFixE p >>= return 533 | where checkDelete (PFFull (FPFPrimary (PEIdent i) [(FPSProperty (PropertyB _ _ _ ))]) _) = True 534 | checkDelete _ = False 535 | deleteField (PFFull (FPFPrimary (PEIdent i) [(FPSProperty (PropertyB l e r ))]) _) = 536 | do e' <- listE e 537 | return $ "Reflect.deleteField("++showd i++", "++e'++")" 538 | 539 | aritE x = case x of 540 | AEUnary u -> unaryE u >>= return 541 | AEBinary _ _ _ -> binaryE x >>= return 542 | 543 | aritENoIn = aritE 544 | 545 | binaryE (AEBinary o x y) 546 | | showd o == "as" = do{ x' <- aritE x >>= (\c -> return $ splitLR c); y' <- aritE y >>= (\c -> return $ splitLR c); return $ "cast( "++ (x'!!1) ++", "++ (y'!!1) ++")" ++ (y'!!2) } 547 | | showd o == "is" = do{ x' <- aritE x >>= (\c -> return $ splitLR c); y' <- aritE y >>= (\c -> return $ splitLR c); return $ "Std.is( "++ (x'!!1) ++", "++ (y'!!1) ++")" ++ (y'!!2) } 548 | | showd o == "===" = do{ x' <- aritE x; y' <- aritE y; return $ x' ++"=="++showw o ++ y' } 549 | | showd o == "!==" = do{ x' <- aritE x; y' <- aritE y; return $ x' ++"!="++showw o ++ y' } 550 | | otherwise = do{ x' <- aritE x; y' <- aritE y; return $ x' ++ showb o ++ y'} 551 | 552 | 553 | regE (RegE l x r o) = do{ return $ "~"++ showb l ++ showl x ++ showb r ++ maybeEl showb o} 554 | 555 | condE (CondRE r) = do{ e <- regE r; return $ e} 556 | condE (CondE e o) = do{ e' <- aritE e; o' <- maybe (return "") (\(q, e1, c, e2) -> do{ e1' <- assignE e1; e2' <- assignE e2; return $ showb q ++ e1' ++ showb c ++ e2'}) o; return $ e' ++ o'} 557 | 558 | condENoIn = condE 559 | 560 | nonAssignE (NAssignE e o) = do{ e' <- aritE e; o' <- maybe (return "") (\(q, e1, c, e2) -> do{ e1' <- nonAssignE e1; e2' <- nonAssignE e2; return $ showb q ++ e1' ++ showb c ++ e2'}) o; return $ e' ++ o'} 561 | 562 | nonAssignENoIn = nonAssignE 563 | 564 | assignE x = case x of 565 | ALogical p o a -> do{ p' <- postFixE p; a' <- assignE a; return $ p' ++ showb o ++ a' } 566 | ACompound p o a -> do{ p' <- postFixE p; a' <- assignE a; return $ p' ++ showb o ++ a' } 567 | AAssign p o a -> do{ p' <- postFixE p; a' <- assignE a; return $ p' ++ showb o ++ a' } 568 | ACond e -> condE e >>= return 569 | 570 | assignENoIn = assignE 571 | 572 | typeE = nonAssignE 573 | typeENoIn = nonAssignENoIn 574 | 575 | expr (Expr x) = assignE x 576 | 577 | forS (ForS k l finit s e s1 e1 r b) = 578 | do if isIterator finit e e1 579 | then do let var = findVar finit 580 | start = findInt finit 581 | rop = findROperand e 582 | bound <- maybe (return "") (\r -> do{ r' <- aritE r; return r' }) rop 583 | fblock <- block b 584 | -- convert to iterator 585 | return $ showb k ++ showb l ++ maybeEl showd var ++ " in " ++ maybeEl id start ++ "..." ++ bound ++ showb r ++ fblock 586 | else do fheader <- maybe (return "") cforInit finit 587 | ftest <- maybe (return "") listE e 588 | ftail <- maybe (return "") listE e1 589 | fblock <- cforBlock b ftail 590 | ws <- wsBlock b 591 | -- convert to while 592 | return $ fheader ++ ";" ++ init ws ++ "while " ++ showb l ++ ftest ++ showb r ++ fblock 593 | where cforInit i = do case i of 594 | FIListE l -> listE l >>= return 595 | FIVarS v -> varS v >>= return 596 | cforBlock (Block l bs r) tail = do bi <- blockItemFold bs 597 | return $ showb l ++ bi ++ "\t" ++ tail ++ ";" ++ init (showw l) ++ showb r 598 | wsBlock (Block l bs r) = return $ showw l 599 | 600 | isIterator fi e e1 = hasInteger fi && hasLessThan e && hasPlusPlus e1 601 | 602 | hasInteger = everything (||) (False `mkQ` isInteger) 603 | 604 | isInteger (TokenInteger x) = True 605 | isInteger _ = False 606 | 607 | hasLessThan = everything (||) (False `mkQ` isLessThan) 608 | 609 | isLessThan (TokenOp x) = x == "<" 610 | isLessThan _ = False 611 | 612 | hasPlusPlus = everything (||) (False `mkQ` isPlusPlus) 613 | 614 | isPlusPlus (TokenOp x) = x == "++" 615 | isPlusPlus _ = False 616 | 617 | findVar = everything orElse ((Nothing `mkQ` findVB) `extQ` findVA) 618 | findVB (VarBinding n _ _) = Just n 619 | findVA (PEIdent n) = Just n 620 | findVA _ = Nothing 621 | 622 | findInt = everything orElse (Nothing `mkQ` findI) 623 | findI (TokenInteger x) = Just x 624 | findI _ = Nothing 625 | 626 | findROperand = everything orElse (Nothing `mkQ` findROp) 627 | findROp (AEBinary op l r) = Just r 628 | findROp _ = Nothing 629 | 630 | forInS (ForInS k me l fb i e r b) = 631 | do if isJust me -- for each in? 632 | then do fb' <- eachBinding fb 633 | e' <- listE e 634 | b' <- block b 635 | return $ showb k ++ showb l ++ fb' ++ showb i ++ e' ++ showb r ++ b' 636 | else do fb' <- elseBinding fb 637 | e' <- listE e 638 | b' <- block b 639 | return $ showb k ++ showb l ++ fb' ++ showb i ++ e' ++ showb r ++ b' 640 | where eachBinding (FIBVar _ (VarBinding i _ _)) = return $ showd i ++ " " 641 | eachBinding (FIBPostE p) = do{ p' <- postFixE p; return $ p'} 642 | elseBinding (FIBVar v b) = do{ b' <- varBinding b; return $ showb v ++ b'} 643 | elseBinding (FIBPostE p) = do{ p' <- postFixE p; return $ p'} 644 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | --------------------------------------------------------------------------------