From 4659045e423eb28d71fa787e0edd0cb8788ef89d Mon Sep 17 00:00:00 2001 From: Decio Ferreira Date: Thu, 19 Sep 2024 20:25:29 +0100 Subject: [PATCH] GLSL Parser --- src/Language/GLSL/Parser.elm | 529 +++++++++++++++++++++++------------ 1 file changed, 357 insertions(+), 172 deletions(-) diff --git a/src/Language/GLSL/Parser.elm b/src/Language/GLSL/Parser.elm index 70f446536..51c5869c9 100644 --- a/src/Language/GLSL/Parser.elm +++ b/src/Language/GLSL/Parser.elm @@ -1,5 +1,6 @@ module Language.GLSL.Parser exposing (parse) +import Hex import Language.GLSL.Syntax exposing (..) import Parser exposing ((|.), (|=), Parser) import Utils.Main as Utils @@ -7,8 +8,8 @@ import Utils.Main as Utils char : Char -> Parser Char char c = - Parser.getChompedString <| - Parser.symbol (String.fromChar c) + Parser.getChompedString (Parser.symbol (String.fromChar c)) + |> extractCharHelper try : Parser a -> Parser a @@ -69,6 +70,7 @@ notFollowedBy p = try (Parser.oneOf [ try p + |> Parser.andThen (\c -> Parser.problem (Debug.toString c)) , Parser.succeed () ] ) @@ -76,32 +78,51 @@ notFollowedBy p = hexDigit : P Char hexDigit = - Parser.chompIf Char.isHexDigit + Parser.getChompedString (Parser.chompIf Char.isHexDigit) + |> extractCharHelper oneOf : String -> P Char oneOf cs = - Parser.chompIf (\c -> String.contains c cs) + Parser.getChompedString (Parser.chompIf (\c -> String.contains (String.fromChar c) cs)) + |> extractCharHelper letter : P Char letter = - Parser.chompIf Char.isAlpha + Parser.getChompedString (Parser.chompIf Char.isAlpha) + |> extractCharHelper + + +extractCharHelper : P String -> P Char +extractCharHelper = + Parser.andThen + (\cs -> + case String.toList cs of + c :: [] -> + Parser.succeed c + + _ -> + Parser.problem "Failed to extract single char..." + ) octDigit : P Char octDigit = - Parser.chompIf Char.isOctDigit + Parser.getChompedString (Parser.chompIf Char.isOctDigit) + |> extractCharHelper alphaNum : P Char alphaNum = - Parser.chompIf Char.isAlphaNum + Parser.getChompedString (Parser.chompIf Char.isAlphaNum) + |> extractCharHelper digit : P Char digit = - Parser.chompIf Char.isDigit + Parser.getChompedString (Parser.chompIf Char.isDigit) + |> extractCharHelper sepBy : P a -> P sep -> P (List a) @@ -123,6 +144,11 @@ sepBy1 p sep = ) +octFromString : String -> Result String Int +octFromString _ = + Debug.todo "octFromString" + + type Assoc = AssocNone | AssocLeft @@ -130,9 +156,136 @@ type Assoc type Operator tok st a - = Infix (GenParser tok st (a -> a -> a)) Assoc - | Prefix (GenParser tok st (a -> a)) - | Postfix (GenParser tok st (a -> a)) + = Infix (P (a -> a -> a)) Assoc + | Prefix (P (a -> a)) + | Postfix (P (a -> a)) + + +buildExpressionParser : List (List (Operator Char S a)) -> P a -> P a +buildExpressionParser operators simpleExpr = + -- let + -- makeParser ops term = + -- let + -- { rassoc, lassoc, nassoc, prefix, postfix } = + -- List.foldr splitOp { rassoc = [], lassoc = [], nassoc = [], prefix = [], postfix = [] } ops + -- rassocOp = + -- choice rassoc + -- lassocOp = + -- choice lassoc + -- nassocOp = + -- choice nassoc + -- prefixOp = + -- -- Parser.succeed identity + -- -- |= choice prefix + -- -- |. Parser.problem "" + -- Debug.todo "prefixOp" + -- postfixOp = + -- -- Parser.succeed identity + -- -- |= choice postfix + -- -- |. Parser.problem "" + -- Debug.todo "postfixOp" + -- ambiguous assoc op = + -- try + -- (Parser.succeed identity + -- |= op + -- |. Parser.problem ("ambiguous use of a " ++ assoc ++ " associative operator") + -- ) + -- ambiguousRight = + -- ambiguous "right" rassocOp + -- ambiguousLeft = + -- ambiguous "left" lassocOp + -- ambiguousNon = + -- ambiguous "non" nassocOp + -- termP = + -- Parser.succeed (\pre x post -> post (pre x)) + -- |= prefixP + -- |= term + -- |= postfixP + -- postfixP = + -- Parser.oneOf + -- [ postfixOp + -- , Parser.succeed identity + -- ] + -- prefixP = + -- Parser.oneOf + -- [ prefixOp + -- , Parser.succeed identity + -- ] + -- rassocP x = + -- -- Parser.oneOf + -- -- [ Parser.succeed (\f y -> f x y) + -- -- |= rassocOp + -- -- |= Parser.andThen rassocP1 termP + -- -- , ambiguousLeft + -- -- , ambiguousNon + -- -- , Parser.succeed x + -- -- ] + -- Debug.todo "rassocP" + -- rassocP1 x = + -- Parser.oneOf + -- [ rassocP x + -- , Parser.succeed x + -- ] + -- lassocP x = + -- -- Parser.oneOf + -- -- [ Parser.succeed (\f y -> f x y) + -- -- |= lassocOp + -- -- |= Parser.andThen lassocP1 termP + -- -- , ambiguousRight + -- -- , ambiguousNon + -- -- , Parser.succeed x + -- -- ] + -- Debug.todo "lassocP" + -- lassocP1 x = + -- Parser.oneOf + -- [ lassocP x + -- , Parser.succeed x + -- ] + -- nassocP x = + -- -- Parser.succeed Tuple.pair + -- -- |= nassocOp + -- -- |= termP + -- -- |> Parser.andThen + -- -- (\( f, y ) -> + -- -- Parser.oneOf + -- -- [ ambiguousRight + -- -- , ambiguousLeft + -- -- , ambiguousNon + -- -- , Parser.succeed (f x y) + -- -- ] + -- -- ) + -- Debug.todo "nassocP" + -- in + -- Parser.succeed identity + -- |= termP + -- |> Parser.andThen + -- (\x -> + -- Parser.succeed identity + -- |= Parser.oneOf + -- [ rassocP x + -- , lassocP x + -- , nassocP x + -- , Parser.succeed x + -- ] + -- |. Parser.problem "operator" + -- ) + -- splitOp singleOperator acc = + -- case singleOperator of + -- Infix op assoc -> + -- case assoc of + -- AssocNone -> + -- { acc | nassoc = op :: acc.nassoc } + -- AssocLeft -> + -- { acc | lassoc = op :: acc.lassoc } + -- AssocRight -> + -- { acc | rassoc = op :: acc.rassoc } + -- Prefix op -> + -- { acc | prefix = op :: acc.prefix } + -- Postfix op -> + -- { acc | postfix = op :: acc.postfix } + -- in + -- List.foldl makeParser simpleExpr operators + Debug.todo "buildExpressionParser" @@ -257,7 +410,7 @@ lexeme p = |. Parser.spaces -parse : String -> Result Parser.Problem TranslationUnit +parse : String -> Result (List Parser.DeadEnd) TranslationUnit parse = Parser.run (Parser.succeed identity @@ -275,47 +428,56 @@ parse = semicolon : P () semicolon = - lexeme <| char ';' + Parser.succeed () + |. lexeme (char ';') comma : P () comma = - lexeme <| char ',' + Parser.succeed () + |. lexeme (char ',') colon : P () colon = - lexeme <| char ':' + Parser.succeed () + |. lexeme (char ':') lbrace : P () lbrace = - lexeme <| char '{' + Parser.succeed () + |. lexeme (char '{') rbrace : P () rbrace = - lexeme <| char '}' + Parser.succeed () + |. lexeme (char '}') lbracket : P () lbracket = - lexeme <| char '[' + Parser.succeed () + |. lexeme (char '[') rbracket : P () rbracket = - lexeme <| char ']' + Parser.succeed () + |. lexeme (char ']') lparen : P () lparen = - lexeme <| char '(' + Parser.succeed () + |. lexeme (char '(') rparen : P () rparen = - lexeme <| char ')' + Parser.succeed () + |. lexeme (char ')') @@ -432,23 +594,43 @@ hexadecimal : P Expr hexadecimal = lexeme <| try <| - Parser.succeed (\d -> IntConstant Hexadecimal ("0x" ++ d)) - |. Parser.keyword "0" - |. oneOf "Xx" - |= Parser.chompWhile Char.isHexDigit - -- TODO - |. optionMaybe (oneOf "Uu") + Parser.andThen + (\d -> + case Hex.fromString d of + Ok val -> + Parser.succeed (IntConstant Hexadecimal val) + + Err err -> + Parser.problem err + ) + (Parser.succeed identity + |. Parser.keyword "0" + |. oneOf "Xx" + |= Parser.getChompedString (Parser.chompWhile Char.isHexDigit) + -- TODO + |. optionMaybe (oneOf "Uu") + ) octal : P Expr octal = lexeme <| try <| - Parser.succeed (\d -> IntConstant Octal ("0o" ++ d)) - |. char '0' - |= many1 octDigit - -- TODO - |. optionMaybe (oneOf "Uu") + Parser.andThen + (\d -> + case octFromString d of + Ok val -> + Parser.succeed (IntConstant Octal val) + + Err err -> + Parser.problem err + ) + (Parser.succeed String.fromList + |. char '0' + |= many1 octDigit + -- TODO + |. optionMaybe (oneOf "Uu") + ) badOctal : P () @@ -464,69 +646,101 @@ decimal : P Expr decimal = lexeme <| try <| - Parser.succeed (\d -> IntConstant Decimal (String.fromList d)) - |= many1 digit - |. notFollowedBy - (Parser.oneOf - [ char '.' - , Parser.succeed ' ' - |. exponent - ] - ) - -- TODO - |. optionMaybe (oneOf "Uu") + Parser.andThen + (\d -> + case String.toInt d of + Just val -> + Parser.succeed (IntConstant Decimal val) + + Nothing -> + Parser.problem "Invalid decimal number" + ) + (Parser.succeed String.fromList + |= many1 digit + |. notFollowedBy + (Parser.oneOf + [ char '.' + , Parser.succeed ' ' + |. exponent + ] + ) + -- TODO + |. optionMaybe (oneOf "Uu") + ) floatExponent : P Expr floatExponent = lexeme <| try <| - Parser.succeed (\d e -> FloatConstant (String.fromList d ++ e)) - |= many1 digit - |= exponent - -- TODO - |. optionMaybe (oneOf "Ff") + Parser.andThen + (\( d, e ) -> + case String.toFloat (String.fromList d ++ e) of + Just val -> + Parser.succeed (FloatConstant val) + + Nothing -> + Parser.problem "Invalid float exponent number" + ) + (Parser.succeed Tuple.pair + |= many1 digit + |= exponent + -- TODO + |. optionMaybe (oneOf "Ff") + ) floatPoint : P Expr floatPoint = lexeme <| try <| - Parser.succeed - (\d d_ e -> + Parser.andThen + (\( d, d_, e ) -> let d__ = - if List.isEmpty d_ then + if String.isEmpty d_ then "0" else - String.fromList d_ + d_ in - FloatConstant - (String.fromList d - ++ "." - ++ d__ - ++ Maybe.withDefault "" e - ) + case String.toFloat (d ++ "." ++ d__ ++ Maybe.withDefault "" e) of + Just val -> + Parser.succeed (FloatConstant val) + + Nothing -> + Parser.problem "Invalid float point number" + ) + (Parser.succeed (\d d_ e -> ( String.fromList d, String.fromList d_, e )) + |= many1 digit + |. char '.' + |= many digit + |= optionMaybe exponent + -- TODO + |. optionMaybe (oneOf "Ff") ) - |= many1 digit - |. char '.' - |= many digit - |= optionMaybe exponent - -- TODO - |. optionMaybe (oneOf "Ff") pointFloat : P Expr pointFloat = lexeme <| try <| - Parser.succeed (\d e -> FloatConstant ("0." ++ String.fromList d ++ Maybe.withDefault "" e)) - |. char '.' - |= many1 digit - |= optionMaybe exponent - -- TODO - |. optionMaybe (oneOf "Ff") + Parser.andThen + (\( d, e ) -> + case String.toFloat ("0." ++ d ++ Maybe.withDefault "" e) of + Just val -> + Parser.succeed (FloatConstant val) + + Nothing -> + Parser.problem "Invalid point float number" + ) + (Parser.succeed (\d e -> ( String.fromList d, e )) + |. char '.' + |= many1 digit + |= optionMaybe exponent + -- TODO + |. optionMaybe (oneOf "Ff") + ) exponent : P String @@ -536,7 +750,7 @@ exponent = Parser.succeed (\s d -> "e" ++ Maybe.withDefault "" s ++ d) |. Parser.oneOf [ Parser.keyword "U", Parser.keyword "u" ] |= optionMaybe (Parser.getChompedString (Parser.oneOf [ Parser.keyword "+", Parser.keyword "-" ])) - |= Parser.chompWhile Char.isDigit + |= Parser.getChompedString (Parser.chompWhile Char.isDigit) @@ -661,19 +875,19 @@ primaryExpression = postfixExpression : P Expr postfixExpression = - Parser.succeed (List.foldl (|>)) - |= try - (Parser.oneOf - [ Parser.succeed (\( i, p ) -> FunctionCall i p) - |= functionCallGeneric - , primaryExpression - ] - ) + Parser.succeed (List.foldl (<|)) + |= Parser.oneOf + [ try + (Parser.succeed (\( i, p ) -> FunctionCall i p) + |= Parser.lazy (\_ -> functionCallGeneric) + ) + , Parser.lazy (\_ -> primaryExpression) + ] |= many (choice [ Parser.succeed (Utils.flip Bracket) - |= between lbracket rbracket integerExpression - , dotFunctionCallGeneric + |= between lbracket rbracket (Parser.lazy (\_ -> integerExpression)) + , Parser.lazy (\_ -> dotFunctionCallGeneric) , dotFieldSelection , Parser.succeed PostInc |. operator "++" @@ -689,7 +903,7 @@ dotFunctionCallGeneric = |= lexeme (Parser.succeed identity |. try (string ".") - |= functionCallGeneric + |= Parser.lazy (\_ -> functionCallGeneric) ) @@ -705,7 +919,7 @@ dotFieldSelection = integerExpression : P Expr integerExpression = - expression + Parser.lazy (\_ -> expression) @@ -717,7 +931,7 @@ integerExpression = functionCallGeneric : P ( FunctionIdentifier, Parameters ) functionCallGeneric = Parser.succeed Tuple.pair - |= functionCallHeader + |= Parser.lazy (\_ -> functionCallHeader) |= choice [ Parser.succeed ParamVoid |. keyword "void" @@ -736,7 +950,7 @@ functionCallGeneric = functionCallHeader : P FunctionIdentifier functionCallHeader = Parser.succeed identity - |= functionIdentifier + |= Parser.lazy (\_ -> functionIdentifier) |. lparen @@ -744,11 +958,11 @@ functionIdentifier : P FunctionIdentifier functionIdentifier = choice [ Parser.succeed FuncId - |= try identifier + |= try (Parser.lazy (\_ -> identifier)) -- TODO if the 'identifier' is declared as a type, should be this case , Parser.succeed FuncIdTypeSpec - |= typeSpecifier + |= Parser.lazy (\_ -> typeSpecifier) -- no need for fieldSelection ] @@ -773,7 +987,7 @@ unaryExpression = |. operator "~" ] ) - |= postfixExpression + |= Parser.lazy (\_ -> postfixExpression) @@ -796,7 +1010,7 @@ unaryExpression = conditionalExpression : P Expr conditionalExpression = Parser.succeed Tuple.pair - |= buildExpressionParser conditionalTable unaryExpression + |= buildExpressionParser conditionalTable (Parser.lazy (\_ -> unaryExpression)) |= optionMaybe (Parser.succeed Tuple.pair |. lexeme (string "?") @@ -817,7 +1031,7 @@ conditionalExpression = assignmentExpression : P Expr assignmentExpression = - buildExpressionParser assignmentTable conditionalExpression + buildExpressionParser assignmentTable (Parser.lazy (\_ -> conditionalExpression)) expression : P Expr @@ -827,7 +1041,7 @@ expression = constantExpression : P Expr constantExpression = - conditionalExpression + Parser.lazy (\_ -> conditionalExpression) @@ -838,42 +1052,6 @@ constantExpression = declaration : P Declaration declaration = - -- choice - -- [ try $ do - -- t <- fullySpecifiedType - -- l <- idecl `sepBy` comma - -- semicolon - -- return $ InitDeclaration (TypeDeclarator t) l - -- , do keyword "invariant" - -- i <- idecl `sepBy` comma - -- semicolon - -- return $ InitDeclaration InvariantDeclarator i - -- , do keyword "precision" - -- q <- precisionQualifier - -- s <- typeSpecifierNoPrecision - -- semicolon - -- return $ Precision q s - -- , do q <- typeQualifier - -- choice - -- [ semicolon >> return (TQ q) - -- , do i <- identifier - -- lbrace - -- s <- structDeclarationList - -- rbrace - -- m <- optionMaybe $ do - -- j <- identifier - -- n <- optionMaybe $ between lbracket rbracket $ optionMaybe constantExpression - -- return (j,n) - -- semicolon - -- return $ Block q i s m - -- ] - -- ] - -- where idecl = do - -- i <- identifier - -- m <- optionMaybe $ between lbracket rbracket $ - -- optionMaybe constantExpression - -- j <- optionMaybe $ lexeme (string "=") >> initializer - -- return $ InitDecl i m j let idecl = Parser.succeed InitDecl @@ -894,7 +1072,7 @@ declaration = , Parser.succeed Precision |. keyword "precision" |= precisionQualifier - |= typeSpecifierNoPrecision + |= Parser.lazy (\_ -> typeSpecifierNoPrecision) |. semicolon , typeQualifier |> Parser.andThen @@ -905,7 +1083,7 @@ declaration = , Parser.succeed (Block q) |= identifier |. lbrace - |= structDeclarationList + |= Parser.lazy (\_ -> structDeclarationList) |. rbrace |= optionMaybe (Parser.succeed Tuple.pair @@ -980,9 +1158,12 @@ parameterQualifier : P ParameterQualifier parameterQualifier = choice -- "empty" case handled in the caller - [ Parser.succeed InOutParameter ((try << lexeme << string) "inout") - , Parser.succeed InParameter ((try << lexeme << string) "in") - , Parser.succeed OutParameter ((try << lexeme << string) "out") + [ Parser.succeed InOutParameter + |. (try << lexeme << string) "inout" + , Parser.succeed InParameter + |. (try << lexeme << string) "in" + , Parser.succeed OutParameter + |. (try << lexeme << string) "out" ] @@ -1137,21 +1318,21 @@ typeSpecifier = choice [ Parser.succeed (\q s -> TypeSpec (Just q) s) |= try precisionQualifier - |= typeSpecifierNoPrecision + |= Parser.lazy (\_ -> typeSpecifierNoPrecision) , Parser.succeed (TypeSpec Nothing) - |= typeSpecifierNoPrecision + |= Parser.lazy (\_ -> typeSpecifierNoPrecision) ] typeSpecifierNoPrecision : P TypeSpecifierNoPrecision typeSpecifierNoPrecision = - typeSpecifierNonArray + Parser.lazy (\_ -> typeSpecifierNonArray) |> Parser.andThen (\s -> choice [ Parser.succeed (TypeSpecNoPrecision s (Just Nothing)) |. try (Parser.succeed () |. lbracket |. rbracket) - , Parser.succeed (TypeSpecNoPrecision << Just << Just) + , Parser.succeed (TypeSpecNoPrecision s << Just << Just) |. lbracket |= constantExpression |. rbracket @@ -1297,7 +1478,7 @@ typeSpecifierNonArray = |. keyword "isampler2DMSArray" , Parser.succeed USampler2DMSArray |. keyword "usampler2DMSArray" - , structSpecifier + , Parser.lazy (\_ -> structSpecifier) -- verify if it is declared , Parser.succeed TypeName @@ -1323,13 +1504,13 @@ structSpecifier = |. keyword "struct" |= optionMaybe identifier |. lbrace - |= structDeclarationList + |= Parser.lazy (\_ -> structDeclarationList) |. rbrace structDeclarationList : P (List Field) structDeclarationList = - many1 structDeclaration + many1 (Parser.lazy (\_ -> structDeclaration)) structDeclaration : P Field @@ -1337,46 +1518,50 @@ structDeclaration = Parser.succeed Field |= optionMaybe typeQualifier |= typeSpecifier - |= structDeclaratorList + |= Parser.lazy (\_ -> structDeclaratorList) |. semicolon structDeclaratorList : P (List StructDeclarator) structDeclaratorList = - sepBy structDeclarator comma + sepBy (Parser.lazy (\_ -> structDeclarator)) comma structDeclarator : P StructDeclarator structDeclarator = - identifier - |> Parser.andThen - (\i -> - choice - [ Parser.succeed (\e -> StructDeclarator i (Just e)) - |. lbracket - |= optionMaybe constantExpression - |. rbracket - , Parser.succeed (StructDeclarator i Nothing) - ] - ) + -- Parser.lazy (\_ -> identifier) + -- |> Parser.andThen + -- (\i -> + -- choice + -- [ Parser.succeed (\e -> StructDeclarator i (Just e)) + -- |. lbracket + -- |= optionMaybe (Parser.lazy (\_ -> constantExpression)) + -- |. rbracket + -- , Parser.succeed (StructDeclarator i Nothing) + -- ] + -- ) + Parser.lazy (\_ -> Debug.todo "structDeclarator") initializer : P Expr initializer = - assignmentExpression + -- assignmentExpression + Debug.todo "initializer" declarationStatement : P Declaration declarationStatement = - declaration + -- declaration + Debug.todo "declarationStatement" statement : P Statement statement = - Parser.oneOf - [ Parser.map CompoundStatement compoundStatement - , simpleStatement - ] + -- Parser.oneOf + -- [ Parser.map CompoundStatement (Parser.lazy (\_ -> compoundStatement)) + -- , Parser.lazy (\_ -> simpleStatement) + -- ] + Debug.todo "statement" simpleStatement : P Statement @@ -1405,7 +1590,7 @@ compoundStatement = |. rbrace ) , Parser.succeed Compound - |= between lbrace rbrace statementList + |= between lbrace rbrace (Parser.lazy (\_ -> statementList)) ] @@ -1511,7 +1696,7 @@ iterationStatement = |. lparen |= condition |. rparen - |= statementNoNewScope + |= Parser.lazy (\_ -> statementNoNewScope) , Parser.succeed DoWhile |. keyword "do" |= statement @@ -1528,7 +1713,7 @@ iterationStatement = |. semicolon |= optionMaybe expression |. rparen - |= statementNoNewScope + |= Parser.lazy (\_ -> statementNoNewScope) ] @@ -1586,17 +1771,17 @@ translationUnit = externalDeclaration : P ExternalDeclaration externalDeclaration = choice - [ try functionPrototype - |> Parser.andThen - (\p -> - choice - [ Parser.succeed (FunctionDeclaration p) - |. semicolon - , Parser.succeed (FunctionDefinition p) - |= compoundStatementNoNewScope - ] - ) - , Parser.map Declaration declaration + [ -- try functionPrototype + -- |> Parser.andThen + -- (\p -> + -- choice + -- [ Parser.succeed (FunctionDeclaration p) + -- |. semicolon + -- , Parser.succeed (FunctionDefinition p) + -- |= compoundStatementNoNewScope + -- ] + -- ) + Parser.map Declaration declaration ]