module Graphics.Implicit.ExtOpenScad.Parser.Expr where
import Graphics.Implicit.Definitions
import Text.ParserCombinators.Parsec hiding (State)
import Text.ParserCombinators.Parsec.Expr
import Graphics.Implicit.ExtOpenScad.Definitions
import Graphics.Implicit.ExtOpenScad.Parser.Util
variable :: GenParser Char st Expr
variable = fmap Var variableSymb
literal :: GenParser Char st Expr
literal =
try ( (string "true" >> return (LitE $ OBool True) )
<|> (string "false" >> return (LitE $ OBool False) )
<?> "boolean" )
<|> try ( try (do
a <- many1 digit
char '.'
b <- many digit
return $ LitE $ ONum (read (a ++ "." ++ b) :: ℝ)
) <|> (do
a <- many1 digit
return $ LitE $ ONum (read a :: ℝ)
) <?> "number" )
<|> try ( ( do
string "\""
strlit <- many $ try (string "\\\"" >> return '\"') <|> try (string "\\n" >> return '\n') <|> ( noneOf "\"\n")
string "\""
return $ LitE $ OString strlit
) <?> "string" )
<?> "literal"
expression :: Int -> GenParser Char st Expr
expression n@12 = (try literal) <|> (try variable )
<|> (try (do
string "("
expr <- expression 0
string ")"
return expr
) <?> "bracketed expression" )
<|> ( try ( do
string "["
exprs <- sepBy (expression 0) (char ',' )
string "]"
return $ ListE exprs
)<|> try ( do
string "("
exprs <- sepBy (expression 0) (char ',' )
string ")"
return $ ListE exprs
) <|> ( do
string "["
exprs <- sepBy (expression 0) (char ':' )
string "]"
return $ collector "list_gen" exprs
)<?> "vector/list" )
expression n@11 =
let
posMatch a =
(try $ do
x <- a
return $ Just x
) <|> (return Nothing)
modifier =
(try $ (do
genSpace
string "("
genSpace
args <- sepBy
(expression 0)
(try $ genSpace >> char ',' >> genSpace)
genSpace
string ")"
genSpace
return $ \f -> f :$ args
<?> "function application"
)) <|> (try $ (do
genSpace
string "["
i <- pad $ expression 0
string "]"
genSpace
return $ \l -> Var "index" :$ [l, i]
<?> "list indexing"
)) <|> (try $ ( do
string "["
genSpace
start <- posMatch $ expression 0
genSpace
char ':'
genSpace
end <- posMatch $ expression 0
genSpace
string "]"
return $ case (start, end) of
(Nothing, Nothing) -> id
(Just s, Nothing) -> \l -> Var "splice" :$ [l, s, LitE OUndefined ]
(Nothing, Just e ) -> \l -> Var "splice" :$ [l, LitE $ ONum 0, e]
(Just s, Just e ) -> \l -> Var "splice" :$ [l, s, e]
<?> "list splicing"))
in ( try( do
obj <- expression $ n+1
genSpace
mods <- modifier `sepBy` (genSpace)
genSpace
return $ foldl (\a b -> b a) obj mods
) <?> "list splicing" )
<|> try (expression $ n+1 )
expression n@10 =
let
negate x = Var "negate" :$ [x]
in try (do
char '-'
genSpace
expr <- expression $ n+1
return $ negate expr
) <|> try (do
char '+'
genSpace
expr <- expression $ n+1
return expr
) <|> try (expression $ n+1)
expression n@9 = try (( do
a <- expression (n+1)
genSpace
string "^"
genSpace
b <- expression n;
return $ Var "^" :$ [a,b]
) <?> "exponentiation")
<|> try (expression $ n+1)
expression n@8 =
let
div a b = Var "/" :$ [a, b]
in try (( do
exprs <- sepBy1 (sepBy1 (pad $ expression $ n+1)
(try $ genSpace >> char '/' >> genSpace ))
(try $ genSpace >> char '*' >> genSpace)
return $ collector "*" $ map (foldl1 div) exprs
) <?> "multiplication/division")
<|>try (expression $ n+1)
expression n@7 =
let
mod a b = Var "%" :$ [a, b]
in try (( do
exprs <- sepBy1 (expression $ n+1) (try $ genSpace >> string "%" >> genSpace)
return $ foldl1 mod exprs
) <?> "modulo")
<|>try (expression $ n+1)
expression n@6 =
try (( do
exprs <- sepBy1 (expression $ n+1) (try $ genSpace >> string "++" >> genSpace)
return $ collector "++" exprs
) <?> "append")
<|>try (expression $ n+1)
expression n@5 =
let
sub a b = Var "-" :$ [a, b]
in try (( do
exprs <- sepBy1 (sepBy1 (pad $ expression $ n+1)
(try $ genSpace >> char '-' >> genSpace ))
(try $ genSpace >> char '+' >> genSpace)
return $ collector "+" $ map (foldl1 sub) exprs
) <?> "addition/subtraction")
<|>try (expression $ n+1)
expression n@4 =
try ( do
firstExpr <- expression $ n+1
otherComparisonsExpr <- many $ do
comparison <-
(try $ string "==" >> return (Var "==") )
<|> (try $ string "!=" >> return (Var "!=") )
<|> (try $ string ">=" >> return (Var ">=") )
<|> (try $ string "<=" >> return (Var "<=") )
<|> (try $ string ">" >> return (Var ">") )
<|> (try $ string "<" >> return (Var "<") )
expr <- expression $ n+1
return (comparison, expr)
let
(comparisons, otherExprs) = unzip otherComparisonsExpr
exprs = firstExpr:otherExprs
return $ case comparisons of
[] -> firstExpr
[x] -> x :$ exprs
_ -> collector "all" [(comparisons!!n) :$ [exprs!!n, exprs!!(n+1)] | n <- [0.. length comparisons 1] ]
)<|> try (expression $ n+1)
expression n@3 =
try (( do
string "!"
genSpace
a <- expression $ n+1
return $ Var "!" :$ [a]
)<?> "logical-not")
<|> try (expression $ n+1)
expression n@2 =
try (( do
a <- expression (n+1)
genSpace
string "&&"
genSpace
b <- expression n
return $ Var "&&" :$ [a,b]
)<?> "logical-and")
<|> try (( do
a <- expression $ n+1
genSpace
string "||"
genSpace
b <- expression n
return $ Var "||" :$ [a,b]
)<?> "logical-or")
<|> try (expression $ n+1)
expression n@1 =
try (( do
a <- expression (n+1)
genSpace
string "?"
genSpace
b <- expression n
genSpace
string ":"
genSpace
c <- expression n
return $ Var "?" :$ [a,b,c]
) <?> "ternary")
<|> try (expression $ n+1)
expression n@0 = try (do { genSpace; expr <- expression $ n+1; genSpace; return expr}) <|> try (expression $ n+1)