Skip to content

Commit

Permalink
Merge pull request #37 from EdenComp/pablo/parse-conditions-operators
Browse files Browse the repository at this point in the history
Add parse conditions operators
  • Loading branch information
chuipagro authored Jan 9, 2024
2 parents 75ebc68 + ed1c00b commit 142b275
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 15 deletions.
29 changes: 27 additions & 2 deletions src/Dreamberd/Parsing/Elements/Condition.hs
Original file line number Diff line number Diff line change
@@ -1,10 +1,35 @@
{-# LANGUAGE ViewPatterns #-}

module Dreamberd.Parsing.Elements.Condition (parseConditionParts) where
module Dreamberd.Parsing.Elements.Condition (
parseConditionParts,
parseConditionExpression,
) where

import Dreamberd.Parsing.Utils (parseScope)
import Dreamberd.Parsing.Values (parseAnyValue)
import Dreamberd.Types (AstNode (Operator))

import Data.Char (isSpace)
import Data.List (isPrefixOf)
import Dreamberd.Parsing.Utils (parseScope)

-- | Parses a condition expression, e.g. if (x == 5) { ... } elif (x > 5) { ... } else { ... } etc...
parseConditionExpression :: String -> Either String AstNode
parseConditionExpression input =
let trimmedInput = dropWhile isSpace input
operators = ["<=", ">=", "==", "!=", "<", ">"]
extractComponents [] acc = reverse acc
extractComponents s acc =
let (word, rest) = break isSpace s
newAcc = if null word then acc else word : acc
in extractComponents (dropWhile isSpace rest) newAcc
components = extractComponents trimmedInput []
in case components of
[lhs, op, rhs] | op `elem` operators ->
case (parseAnyValue lhs, parseAnyValue rhs) of
(Right lhsValue, Right rhsValue) -> Right (Operator op lhsValue rhsValue)
_ -> Left "Invalid expression"
[single] -> parseAnyValue single
_ -> Left "Invalid expression"

parseConditionParts :: String -> Either String (String, String, [(String, String)], Maybe String, String)
parseConditionParts str =
Expand Down
26 changes: 26 additions & 0 deletions src/Dreamberd/Parsing/Elements/Operator.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
module Dreamberd.Parsing.Elements.Operator (parseExpression) where

import Dreamberd.Parsing.Values (parseAnyValue)
import Dreamberd.Types (AstNode (Operator))

parseExpression :: String -> Either String AstNode
parseExpression str =
case words str of
[lhs, op, rhs] ->
case parseAnyValue lhs of
Left err -> Left err
Right lhsNode ->
case parseOperator op of
Left err -> Left err
Right opNode ->
case parseAnyValue rhs of
Left err -> Left err
Right rhsNode -> Right (Operator opNode lhsNode rhsNode)
_ -> Left "Invalid expression"

parseOperator :: String -> Either String String
parseOperator str =
let operators = ["=", "+=", "-=", "*=", "/=", "%="]
in if str `elem` operators
then Right str
else Left "Invalid operator"
35 changes: 23 additions & 12 deletions src/Dreamberd/Parsing/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ module Dreamberd.Parsing.Main (parseDreamberd, parseFunction, parseCondition) wh

import Data.Char (isSpace)
import Data.List (stripPrefix)
import Dreamberd.Parsing.Elements.Condition (parseConditionParts)
import Dreamberd.Parsing.Elements.Condition (
parseConditionExpression,
parseConditionParts,
)
import Dreamberd.Parsing.Elements.Function (extractFunctionParts, parseReturn)
import Dreamberd.Parsing.Elements.Loop (extractLoopParts)
import Dreamberd.Parsing.Elements.Variable (parseVar)
Expand Down Expand Up @@ -57,14 +60,22 @@ parseCondition str ast =
buildConditionNodes condition ifBody elifs elsePart >>= \ifNodes -> Right (restOfCode, ast ++ ifNodes)

buildConditionNodes :: String -> String -> [(String, String)] -> Maybe String -> Either String [AstNode]
buildConditionNodes _ ifBody [] Nothing = do
ifBodyAst <- parseDreamberd ifBody []
return [If (Boolean True) ifBodyAst []]
buildConditionNodes _ ifBody ((elifCondition, elifBody) : elifs) elsePart = do
ifBodyAst <- parseDreamberd ifBody []
elifNodes <- buildConditionNodes elifCondition elifBody elifs elsePart
return [If (Boolean True) ifBodyAst elifNodes]
buildConditionNodes _ ifBody [] (Just elseBody) = do
ifBodyAst <- parseDreamberd ifBody []
elseBodyAst <- parseDreamberd elseBody []
return [If (Boolean True) ifBodyAst elseBodyAst]
buildConditionNodes cond ifBody [] Nothing =
parseConditionExpression cond
>>= \ifCondAst ->
parseDreamberd ifBody []
>>= \ifBodyAst -> return [If ifCondAst ifBodyAst []]
buildConditionNodes cond ifBody ((elifCondition, elifBody) : elifs) elsePart =
parseConditionExpression cond
>>= \ifCondAst ->
parseDreamberd ifBody []
>>= \ifBodyAst ->
buildConditionNodes elifCondition elifBody elifs elsePart
>>= \elifNodes -> return [If ifCondAst ifBodyAst elifNodes]
buildConditionNodes cond ifBody [] (Just elseBody) =
parseConditionExpression cond
>>= \ifCondAst ->
parseDreamberd ifBody []
>>= \ifBodyAst ->
parseDreamberd elseBody []
>>= \elseBodyAst -> return [If ifCondAst ifBodyAst elseBodyAst]
1 change: 1 addition & 0 deletions src/Dreamberd/Parsing/Values.hs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ parseFunctionCall code =
else Right (afterParams, Call strippedName (rights paramList))

parseAnyValue :: String -> Either String AstNode
parseAnyValue "" = Left "No value found"
parseAnyValue input = case parseString input of
Right result -> Right result
Left _ -> case parseNumber input of
Expand Down
33 changes: 32 additions & 1 deletion test/Unit/Dreamberd/TestDreamberdParsing.hs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
module Unit.Dreamberd.TestDreamberdParsing (testDreamberdParsing) where

import Dreamberd.Parsing.Elements.Condition (parseConditionExpression)
import Dreamberd.Parsing.Elements.Operator (parseExpression)
import Dreamberd.Parsing.Main (parseCondition, parseDreamberd, parseFunction)
import Dreamberd.Parsing.Values (parseFunctionCall)
import Dreamberd.Types (AstNode (AssignVariable, Boolean, Call, Function, Identifier, If, Loop, Number, Operator, Return, String))
import Test.HUnit (Test (..), assertEqual)

testDreamberdParsing :: Test
testDreamberdParsing = TestList [testParseFunction, testParseFunctionCall, testParseCondition, testParseDreamberd]
testDreamberdParsing = TestList [testParseFunction, testParseFunctionCall, testParseCondition, testparseExpression, testParseConditionExpression, testParseDreamberd]

testParseFunction :: Test
testParseFunction =
Expand All @@ -25,6 +27,35 @@ testParseFunction =
, TestCase (assertEqual "parseFunction wrong - invalid function scope" (Left "Unrecognized element") (parseFunction "foo(){unknown content; }" []))
]

testparseExpression :: Test
testparseExpression =
TestList
[ TestCase (assertEqual "parseExpression =" (Right (Operator "=" (Number 1) (Number 1))) (parseExpression " 1 = 1"))
, TestCase (assertEqual "parseExpression wrong" (Left "Invalid expression") (parseExpression "1 1"))
, TestCase (assertEqual "parseExpression +=" (Right (Operator "+=" (Identifier "i") (Number 1))) (parseExpression "i += 1"))
, TestCase (assertEqual "parseExpression -= without spaces" (Right (Operator "-=" (Identifier "i") (Number 1))) (parseExpression "i -= 1"))
, TestCase (assertEqual "parseExpression *=" (Right (Operator "*=" (Identifier "i") (Number 1))) (parseExpression "i *= 1"))
, TestCase (assertEqual "parseExpression /=" (Right (Operator "/=" (Identifier "i") (Number 1))) (parseExpression "i /= 1"))
, TestCase (assertEqual "parseExpression %=" (Right (Operator "%=" (Identifier "i") (Number 1))) (parseExpression "i %= 1"))
, TestCase (assertEqual "parseExpression +=" (Right (Operator "+=" (Identifier "i") (Number 1))) (parseExpression "i += 1"))
, TestCase (assertEqual "parseExpression =+" (Left "Invalid operator") (parseExpression "i =+ 1"))
]

testParseConditionExpression :: Test
testParseConditionExpression =
TestList
[ TestCase (assertEqual "parseConditionExpression basic" (Right (Operator "<" (Number 1) (Number 2))) (parseConditionExpression "1 < 2"))
, TestCase (assertEqual "parseConditionExpression with spaces" (Right (Operator ">" (Number 1) (Number 2))) (parseConditionExpression "1 > 2"))
, TestCase (assertEqual "parseConditionExpression with spaces" (Right (Operator ">=" (Number 1) (Number 2))) (parseConditionExpression "1 >= 2"))
, TestCase (assertEqual "parseConditionExpression with spaces" (Right (Operator "<=" (Number 1) (Number 2))) (parseConditionExpression "1 <= 2"))
, TestCase (assertEqual "parseConditionExpression with spaces" (Right (Operator "==" (Number 1) (Number 2))) (parseConditionExpression "1 == 2"))
, TestCase (assertEqual "parseConditionExpression with spaces" (Right (Operator "!=" (Number 1) (Number 2))) (parseConditionExpression "1 != 2"))
, TestCase (assertEqual "parseConditionExpression with spaces" (Left "Invalid expression") (parseConditionExpression " 1 2 "))
, TestCase (assertEqual "parseConditionExpression with spaces" (Right (Number 1)) (parseConditionExpression "1 "))
, TestCase (assertEqual "parseConditionExpression with spaces" (Left "Invalid expression") (parseConditionExpression " "))
, TestCase (assertEqual "parseConditionExpression with spaces" (Left "Invalid expression") (parseConditionExpression "1 a 1"))
]

testParseFunctionCall :: Test
testParseFunctionCall =
TestList
Expand Down

0 comments on commit 142b275

Please sign in to comment.