module SwfCompiler where -- arch-tag: Scheme to Swf Compiler -- (add-hook 'haskell-mode-hook 'turn-on-haskell-ghci) import SchemeAS import SwfAssembly import SchemeParser import PPrint import List (find) import Text.ParserCombinators.Parsec primOps = [ ("+", 2, ActionAdd) , ("-", 2, ActionSubtract) , ("/", 2, ActionDivide) , ("*", 2, ActionMultiply) , ("eq", 2, ActionEquals) , ("<", 2, ActionLess) ] prim op = find (\(op2,_,_) -> (op == op2)) primOps eta_expand primop nargs = [ActionDefineFunction var_names (load_vars ++ [primop, ActionReturn])] where var_names = [ x | x <- (map ((++) "a" . show) [0..(nargs - 1)])] load_vars = concatMap (\name -> [ActionPushString name, ActionGetVariable]) (reverse var_names) compile_expr label_prefix expr = case expr of Const (StringLit s) -> [ActionPushString s] Const (IntLit i) -> [ActionPushFloat (fromInteger i)] Identifier i -> {- if the identifier is a primative assembly operator, then do eta expansion on it, otherwise just load the value from the location bound to the identifier -} case prim i of Just (_,2,op) -> eta_expand op 2 Nothing -> [ActionPushString i , ActionGetVariable] Lambda (FixedFormals f) body -> [ActionDefineFunction f ((compile_expr label_prefix body) ++ [ActionReturn])] Lambda (VarFormals v) body -> [ActionDefineFunction [v] ((compile_expr label_prefix body) ++ [ActionReturn])] Lambda (FixedVarFormals f v) body -> [ActionDefineFunction (f ++ [v]) ((compile_expr label_prefix body) ++ [ActionReturn])] Apply e0 el -> (concatMap (uncurry compile_expr) $ zip [label_prefix ++ "." ++ show i | i <- [2..]] el) ++ {- test if we are applying a primative assembly operation, eg (+ 2 3), or calling a function, eg (myfun 2 3) -} case primE e0 of Just (_,_,op) -> [op] Nothing -> [ActionPushFloat (fromIntegral (length el))] ++ (compile_expr (label_prefix ++ ".1") e0) ++ [ActionPushString "", ActionCallMethod] If e0 e1 e2 -> compile_expr (label_prefix ++ ".1") e0 ++ [ActionIf (label_prefix ++ ".iftrue")] ++ compile_expr (label_prefix ++ ".2") e2 ++ [ActionJump (label_prefix ++ ".ifdone"), Label (label_prefix ++ ".iftrue")] ++ compile_expr (label_prefix ++ ".3") e1 ++ [Label (label_prefix ++ ".ifdone")] Set i e -> [ActionPushString i] ++ compile_expr label_prefix e ++ [ActionSetVariable] where primE (Identifier i) = prim i primE _ = Nothing -- main predefined = [ ActionDefineFunction ["str"] [ ActionPushString "str" , ActionGetVariable , ActionTrace ] , ActionPushString "display" , ActionSetVariable ] compile :: [Expr] -> [SwfAssembly] compile exprs = concatMap (uncurry compile_expr) $ zip [show i | i <- [1..]] exprs doCompile :: [Char] -> [SwfAssembly] doCompile s = case parse exprs "testAsmSwf" s of Left err -> error ("Failed to compile: " ++ s) Right exprs -> compile exprs testCompiler s = case parse exprs "testAsm" s of Left err -> print err Right x -> print (Movie "display.swf" [(Frame 0 (compile x))])