|
| 1 | +----------------------------------------------------------------------------- |
| 2 | +-- |
| 3 | +-- Module : PureScript.CodeGen |
| 4 | +-- Copyright : (c) Phil Freeman 2013 |
| 5 | +-- License : MIT |
| 6 | +-- |
| 7 | +-- Maintainer : Phil Freeman <paf31@cantab.net> |
| 8 | +-- Stability : experimental |
| 9 | +-- Portability : |
| 10 | +-- |
| 11 | +-- | |
| 12 | +-- |
| 13 | +----------------------------------------------------------------------------- |
| 14 | + |
| 15 | +module PureScript.CodeGen ( |
| 16 | + declToJs |
| 17 | +) where |
| 18 | + |
| 19 | +import Data.List (nub, intersperse, intercalate) |
| 20 | +import PureScript.Values |
| 21 | +import PureScript.Declarations |
| 22 | + |
| 23 | +declToJs :: Declaration -> Maybe String |
| 24 | +declToJs (ValueDeclaration name val) = Just $ "var " ++ name ++ " = " ++ valueToJs val ++ ";" |
| 25 | +declToJs (DataDeclaration dcs@(DataConstructors { dataConstructors = ctors })) = |
| 26 | + Just $ concatMap (\(ctor, _) -> "var " ++ ctor ++ " = function (value) { return { ctor: '" ++ ctor ++ "', value: value }; };") ctors |
| 27 | +declToJs _ = Nothing |
| 28 | + |
| 29 | +valueToJs :: Value -> String |
| 30 | +valueToJs (NumericLiteral n) = show n |
| 31 | +valueToJs (StringLiteral s) = show s |
| 32 | +valueToJs (BooleanLiteral True) = "true" |
| 33 | +valueToJs (BooleanLiteral False) = "false" |
| 34 | +valueToJs (Unary op value) = unaryOperatorString op ++ "(" ++ valueToJs value ++ ")" |
| 35 | +valueToJs (Binary op left right) = "(" ++ valueToJs left ++ ") " ++ binaryOperatorString op ++ " (" ++ valueToJs right ++ ")" |
| 36 | +valueToJs (ArrayLiteral xs) = "[" ++ intercalate "," (map valueToJs xs) ++ "]" |
| 37 | +valueToJs (ObjectLiteral ps) = "{" ++ intercalate "," (map objectPropertyToJs ps) ++ "}" |
| 38 | +valueToJs (Accessor prop val) = "(" ++ valueToJs val ++ ")." ++ prop |
| 39 | +valueToJs (Abs args value) = "function (" ++ intercalate "," args ++ ") { return " ++ valueToJs value ++ "; }" |
| 40 | +valueToJs (Var ident) = ident |
| 41 | +valueToJs (App f xs) = "(" ++ valueToJs f ++ ") (" ++ intercalate "," (map valueToJs xs) ++ ")" |
| 42 | +valueToJs (Block sts) = "(function () {" ++ intercalate ";" (map statementToJs sts) ++ "})()" |
| 43 | +valueToJs (Constructor name) = name |
| 44 | +valueToJs (Case value binders) = |
| 45 | + "(function (_0) {" |
| 46 | + ++ concatMap (\(b, val) -> fst $ binderToJs 0 0 b $ "return " ++ valueToJs val ++ ";") binders |
| 47 | + ++ "throw \"Failed pattern match\";" |
| 48 | + ++ "})(" ++ valueToJs value ++ ")" |
| 49 | +valueToJs (TypedValue value _) = valueToJs value |
| 50 | + |
| 51 | +unaryOperatorString :: UnaryOperator -> String |
| 52 | +unaryOperatorString Negate = "-" |
| 53 | +unaryOperatorString Not = "!" |
| 54 | +unaryOperatorString BitwiseNot = "~" |
| 55 | + |
| 56 | +binaryOperatorString :: BinaryOperator -> String |
| 57 | +binaryOperatorString Add = "+" |
| 58 | +binaryOperatorString Subtract = "-" |
| 59 | +binaryOperatorString Multiply = "*" |
| 60 | +binaryOperatorString Divide = "/" |
| 61 | +binaryOperatorString Modulus = "%" |
| 62 | +binaryOperatorString LessThan = "<" |
| 63 | +binaryOperatorString LessThanOrEqualTo = "<=" |
| 64 | +binaryOperatorString GreaterThan = ">" |
| 65 | +binaryOperatorString GreaterThanOrEqualTo = ">=" |
| 66 | +binaryOperatorString BitwiseAnd = "&" |
| 67 | +binaryOperatorString BitwiseOr = "|" |
| 68 | +binaryOperatorString BitwiseXor = "^" |
| 69 | +binaryOperatorString ShiftLeft = "<<" |
| 70 | +binaryOperatorString ShiftRight = ">>" |
| 71 | +binaryOperatorString ZeroFillShiftRight = ">>>" |
| 72 | +binaryOperatorString EqualTo = "===" |
| 73 | +binaryOperatorString NotEqualTo = "!==" |
| 74 | +binaryOperatorString And = "&&" |
| 75 | +binaryOperatorString Or = "||" |
| 76 | +binaryOperatorString Concat = "+" |
| 77 | + |
| 78 | +binderToJs :: Int -> Int -> Binder -> String -> (String, Int) |
| 79 | +binderToJs varName fresh (VarBinder s) done = ("var " ++ s ++ " = _" ++ show varName ++ "; " ++ done, fresh) |
| 80 | +binderToJs varName fresh (ConstructorBinder ctor b) done = |
| 81 | + ("if (_" ++ show varName ++ ".ctor === \"" ++ ctor ++ "\") {" |
| 82 | + ++ "var _" ++ show fresh' ++ " = _" ++ show varName ++ ".value;" |
| 83 | + ++ js |
| 84 | + ++ "}", fresh'') |
| 85 | + where |
| 86 | + fresh' = succ fresh |
| 87 | + (js, fresh'') = binderToJs fresh' fresh' b done |
| 88 | +binderToJs varName fresh (ObjectBinder bs) done = go fresh bs done |
| 89 | + where |
| 90 | + go fresh [] done = (done, fresh) |
| 91 | + go fresh ((prop, binder):bs') done = |
| 92 | + ( "var _" ++ show fresh' ++ " = _" ++ show varName ++ "." ++ prop ++ ";" |
| 93 | + ++ js |
| 94 | + , fresh''') |
| 95 | + where |
| 96 | + fresh' = succ fresh |
| 97 | + (done', fresh'') = go fresh' bs' done |
| 98 | + (js, fresh''') = binderToJs fresh' fresh'' binder done' |
| 99 | + |
| 100 | +objectPropertyToJs :: (String, Value) -> String |
| 101 | +objectPropertyToJs (key, value) = key ++ ":" ++ valueToJs value |
| 102 | + |
| 103 | +statementToJs :: Statement -> String |
| 104 | +statementToJs (VariableIntroduction name value) = "var " ++ name ++ " = " ++ valueToJs value |
| 105 | +statementToJs (Assignment target value) = target ++ " = " ++ valueToJs value |
| 106 | +statementToJs (While cond sts) = "while (" |
| 107 | + ++ valueToJs cond ++ ") {" |
| 108 | + ++ intercalate ";" (map statementToJs sts) ++ "}" |
| 109 | +statementToJs (For (init, cond, done) sts) = "for (" ++ |
| 110 | + statementToJs init |
| 111 | + ++ "; " ++ valueToJs cond |
| 112 | + ++ "; " ++ statementToJs done |
| 113 | + ++ ") {" ++ intercalate ";" (map statementToJs sts) ++ "}" |
| 114 | +statementToJs (IfThenElse cond thens elses) = "if (" |
| 115 | + ++ valueToJs cond ++ ") {" |
| 116 | + ++ intercalate ";" (map statementToJs thens) ++ "}" |
| 117 | + ++ flip (maybe "") elses (\sts -> |
| 118 | + " else {" ++ intercalate ";" (map statementToJs sts) ++ "}") |
| 119 | +statementToJs (Return value) = "return " ++ valueToJs value |
0 commit comments