From 2cd9b04b85e64be16b3d2e72dda3cbde9251c3cc Mon Sep 17 00:00:00 2001 From: VegOwOtenks Date: Sat, 25 Jan 2025 21:37:13 +0100 Subject: [PATCH 1/3] Added support for enumerations --- app/Main.hs | 2 +- src/Ubc/Parse/Syntax/Data/Struct.hs | 23 ----------------------- src/Ubc/Parse/Syntax/Enumeration.hs | 23 +++++++++++++++++++++++ src/Ubc/Parse/Syntax/File.hs | 17 ++++++++++++----- src/Ubc/Parse/Syntax/Language.hs | 1 + src/Ubc/Parse/Syntax/Struct.hs | 22 ++++++++++++++++++---- src/Ubc/Parse/Syntax/TypeExpression.hs | 2 +- ubcc.cabal | 2 +- 8 files changed, 57 insertions(+), 35 deletions(-) delete mode 100644 src/Ubc/Parse/Syntax/Data/Struct.hs create mode 100644 src/Ubc/Parse/Syntax/Enumeration.hs diff --git a/app/Main.hs b/app/Main.hs index 0bd8497..cbbd268 100644 --- a/app/Main.hs +++ b/app/Main.hs @@ -6,4 +6,4 @@ main :: IO () main = do text <- getContents - print $ Parsec.parse File.parse "" text + print $ Parsec.parse (File.parse <* Parsec.eof) "" text diff --git a/src/Ubc/Parse/Syntax/Data/Struct.hs b/src/Ubc/Parse/Syntax/Data/Struct.hs deleted file mode 100644 index ece3e8d..0000000 --- a/src/Ubc/Parse/Syntax/Data/Struct.hs +++ /dev/null @@ -1,23 +0,0 @@ -module Ubc.Parse.Syntax.Data.Struct -( Struct(..) -, addVariable -, addFunction) -where - -import Ubc.Parse.Syntax.VariableType (VariableType) -import Ubc.Parse.Syntax.Function (Function) - -type VariableName = String - -data Struct = Struct - { name :: String - , variables :: [(VariableName, VariableType)] - , functions :: [Function] - } - deriving (Show) - -addVariable :: Struct -> VariableName -> VariableType -> Struct -addVariable (Struct sn vs fs) n t = Struct sn ((n, t): vs) fs - -addFunction :: Struct -> Function -> Struct -addFunction (Struct sn vs fs) f = Struct sn vs (f:fs) diff --git a/src/Ubc/Parse/Syntax/Enumeration.hs b/src/Ubc/Parse/Syntax/Enumeration.hs new file mode 100644 index 0000000..1d70d1c --- /dev/null +++ b/src/Ubc/Parse/Syntax/Enumeration.hs @@ -0,0 +1,23 @@ +module Ubc.Parse.Syntax.Enumeration +( Enumeration(..) +, parse +) +where +import qualified Ubc.Parse.Syntax.Language as UbcLanguage +import Text.Parsec (ParsecT, many) + +type EnumerationMember = String +data Enumeration = Enumeration + { name :: String + , members :: [EnumerationMember] + } + deriving (Show) + +parse :: Monad m => ParsecT String u m Enumeration +parse = do + UbcLanguage.reserved "enum" + identifier <- UbcLanguage.identifier + values <- UbcLanguage.braces $ many UbcLanguage.identifier + + return $ Enumeration identifier values + diff --git a/src/Ubc/Parse/Syntax/File.hs b/src/Ubc/Parse/Syntax/File.hs index 1548c52..6bd3d94 100644 --- a/src/Ubc/Parse/Syntax/File.hs +++ b/src/Ubc/Parse/Syntax/File.hs @@ -8,38 +8,45 @@ import Control.Monad ((<$!>)) import Text.Parsec (choice, ParsecT, many) -import Ubc.Parse.Syntax.Data.Struct ( Struct ) +import Ubc.Parse.Syntax.Struct ( Struct ) import Ubc.Parse.Syntax.Function (Function) import Ubc.Parse.Syntax.Statement (Statement) +import Ubc.Parse.Syntax.Enumeration (Enumeration) + import qualified Ubc.Parse.Syntax.Struct as Struct import qualified Ubc.Parse.Syntax.Function as Function import qualified Ubc.Parse.Syntax.Statement as Statement +import qualified Ubc.Parse.Syntax.Enumeration as Enumeration data File = File { name :: String , structs :: [Struct] , functions :: [Function] , statements :: [Statement] + , enumerations :: [Enumeration] } deriving (Show) data FileMember = FileFunction Function | FileStruct Struct + | FileEnumeration Enumeration | FileStatement Statement accumulateFile :: File -> FileMember -> File -accumulateFile (File name_ struct_ functions_ statements_) (FileFunction f) = File name_ struct_ (f:functions_) statements_ -accumulateFile (File name_ struct_ functions_ statements_) (FileStatement s) = File name_ struct_ functions_ (s:statements_) -accumulateFile (File name_ struct_ functions_ statements_) (FileStruct s) = File name_ (s:struct_) functions_ statements_ +accumulateFile (File name_ sss fs sts es) (FileStruct s) = File name_ (s:sss) fs sts es +accumulateFile (File name_ sss fs sts es) (FileFunction f) = File name_ sss (f:fs) sts es +accumulateFile (File name_ sss fs sts es) (FileStatement s) = File name_ sss fs (s:sts) es +accumulateFile (File name_ sss fs sts es) (FileEnumeration e) = File name_ sss fs sts (e:es) parse :: Monad m => ParsecT String u m File -parse = foldl accumulateFile (File "" [] [] []) <$!> many fileMember +parse = foldr (flip accumulateFile) (File "" [] [] [] []) <$!> many fileMember fileMember :: Monad m => ParsecT String u m FileMember fileMember = choice [ FileStruct <$!> Struct.parse , FileFunction <$!> Function.parse , FileStatement <$!> Statement.parse + , FileEnumeration <$!> Enumeration.parse ] diff --git a/src/Ubc/Parse/Syntax/Language.hs b/src/Ubc/Parse/Syntax/Language.hs index fe67728..c18f683 100644 --- a/src/Ubc/Parse/Syntax/Language.hs +++ b/src/Ubc/Parse/Syntax/Language.hs @@ -56,6 +56,7 @@ languageDef = LanguageDef { , opStart = oneOf "+-*/%" , opLetter = oneOf "+-*/%" , reservedNames = [ "struct" + , "enum" , "u32" , "i32" , "f32" diff --git a/src/Ubc/Parse/Syntax/Struct.hs b/src/Ubc/Parse/Syntax/Struct.hs index 77d02df..cc027be 100644 --- a/src/Ubc/Parse/Syntax/Struct.hs +++ b/src/Ubc/Parse/Syntax/Struct.hs @@ -13,18 +13,32 @@ import Text.Parsec ParsecT, ) -import Ubc.Parse.Syntax.Data.Struct (Struct(..)) import Ubc.Parse.Syntax.VariableType (VariableType) +import Ubc.Parse.Syntax.Function (Function) + import qualified Ubc.Parse.Syntax.Language as UbcLanguage import qualified Ubc.Parse.Syntax.VariableType as VariableType -import qualified Ubc.Parse.Syntax.Data.Struct as Struct import qualified Ubc.Parse.Syntax.Function as Function type VariableName = String + data StructStatement = Variable VariableName VariableType | Function Function.Function +data Struct = Struct + { name :: String + , variables :: [(VariableName, VariableType)] + , functions :: [Function] + } + deriving (Show) + +addVariable :: Struct -> VariableName -> VariableType -> Struct +addVariable (Struct sn vs fs) n t = Struct sn ((n, t): vs) fs + +addFunction :: Struct -> Function -> Struct +addFunction (Struct sn vs fs) f = Struct sn vs (f:fs) + parse :: Monad m => ParsecT String u m Struct parse = do _ <- UbcLanguage.reserved "struct" @@ -33,8 +47,8 @@ parse = do foldl accumulateStruct (Struct structIdentifier [] []) <$!> UbcLanguage.braces (many structMember) accumulateStruct :: Struct -> StructStatement -> Struct -accumulateStruct s (Variable n t) = Struct.addVariable s n t -accumulateStruct s (Function f) = Struct.addFunction s f +accumulateStruct s (Variable n t) = addVariable s n t +accumulateStruct s (Function f) = addFunction s f structMember :: Monad m => ParsecT String u m StructStatement structMember = choice [ structVariableOrFunction ] diff --git a/src/Ubc/Parse/Syntax/TypeExpression.hs b/src/Ubc/Parse/Syntax/TypeExpression.hs index 6430128..ad0db90 100644 --- a/src/Ubc/Parse/Syntax/TypeExpression.hs +++ b/src/Ubc/Parse/Syntax/TypeExpression.hs @@ -9,7 +9,7 @@ import Control.Monad ((<$!>)) import Text.Parsec (choice, ParsecT) import Ubc.Parse.Syntax.VariableType (VariableType) -import Ubc.Parse.Syntax.Data.Struct (Struct) +import Ubc.Parse.Syntax.Struct (Struct) import qualified Ubc.Parse.Syntax.Language as UbcLanguage import qualified Ubc.Parse.Syntax.VariableType as VariableType diff --git a/ubcc.cabal b/ubcc.cabal index 5ccb58e..ace0687 100644 --- a/ubcc.cabal +++ b/ubcc.cabal @@ -26,7 +26,7 @@ source-repository head library exposed-modules: Ubc.Parse.Syntax.Config - Ubc.Parse.Syntax.Data.Struct + Ubc.Parse.Syntax.Enumeration Ubc.Parse.Syntax.Expression Ubc.Parse.Syntax.File Ubc.Parse.Syntax.Function From 2b4e5fcdc0c7d7ab681a0d3c58dcdb6ca9a7df8e Mon Sep 17 00:00:00 2001 From: VegOwOtenks Date: Thu, 13 Feb 2025 21:44:40 +0100 Subject: [PATCH 2/3] Improved enum parsing error messages --- src/Ubc/Parse/Syntax/Enumeration.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Ubc/Parse/Syntax/Enumeration.hs b/src/Ubc/Parse/Syntax/Enumeration.hs index 1d70d1c..d891217 100644 --- a/src/Ubc/Parse/Syntax/Enumeration.hs +++ b/src/Ubc/Parse/Syntax/Enumeration.hs @@ -4,7 +4,7 @@ module Ubc.Parse.Syntax.Enumeration ) where import qualified Ubc.Parse.Syntax.Language as UbcLanguage -import Text.Parsec (ParsecT, many) +import Text.Parsec (ParsecT, many, ()) type EnumerationMember = String data Enumeration = Enumeration @@ -16,7 +16,7 @@ data Enumeration = Enumeration parse :: Monad m => ParsecT String u m Enumeration parse = do UbcLanguage.reserved "enum" - identifier <- UbcLanguage.identifier + identifier <- UbcLanguage.identifier "enum identifier" values <- UbcLanguage.braces $ many UbcLanguage.identifier return $ Enumeration identifier values From 4e8e5b9e8432f33dd9dcecba1a9e543ea9cc4173 Mon Sep 17 00:00:00 2001 From: VegOwOtenks Date: Thu, 13 Feb 2025 21:45:02 +0100 Subject: [PATCH 3/3] Collecting the body of structs with monoids --- src/Ubc/Parse/Syntax/Struct.hs | 43 +++++++++++++++++----------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/src/Ubc/Parse/Syntax/Struct.hs b/src/Ubc/Parse/Syntax/Struct.hs index cc027be..03ab5ee 100644 --- a/src/Ubc/Parse/Syntax/Struct.hs +++ b/src/Ubc/Parse/Syntax/Struct.hs @@ -1,9 +1,14 @@ +{-# LANGUAGE DerivingVia #-} +{-# LANGUAGE DeriveGeneric #-} module Ubc.Parse.Syntax.Struct ( Struct(..) , parse ) where +-- yay, explicit dependency on ghc +import GHC.Generics (Generic) + import Control.Monad ((<$!>)) import Text.Parsec @@ -23,37 +28,31 @@ import qualified Ubc.Parse.Syntax.Function as Function type VariableName = String -data StructStatement = Variable VariableName VariableType - | Function Function.Function - -data Struct = Struct +data Struct = Struct { name :: String - , variables :: [(VariableName, VariableType)] - , functions :: [Function] + , body :: StructBody } deriving (Show) -addVariable :: Struct -> VariableName -> VariableType -> Struct -addVariable (Struct sn vs fs) n t = Struct sn ((n, t): vs) fs - -addFunction :: Struct -> Function -> Struct -addFunction (Struct sn vs fs) f = Struct sn vs (f:fs) +data StructBody = StructBody + { variables :: [(VariableName, VariableType)] + , functions :: [Function] + } + deriving stock (Generic, Show) + deriving (Semigroup, Monoid) via StructBody parse :: Monad m => ParsecT String u m Struct parse = do _ <- UbcLanguage.reserved "struct" structIdentifier <- UbcLanguage.identifier + structBody <- mconcat <$!> UbcLanguage.braces (many structMember) - foldl accumulateStruct (Struct structIdentifier [] []) <$!> UbcLanguage.braces (many structMember) + pure $ Struct structIdentifier structBody -accumulateStruct :: Struct -> StructStatement -> Struct -accumulateStruct s (Variable n t) = addVariable s n t -accumulateStruct s (Function f) = addFunction s f - -structMember :: Monad m => ParsecT String u m StructStatement +structMember :: Monad m => ParsecT String u m StructBody structMember = choice [ structVariableOrFunction ] -structVariableOrFunction :: Monad m => ParsecT String u m StructStatement +structVariableOrFunction :: Monad m => ParsecT String u m StructBody structVariableOrFunction = do (typeName, identifier) <- try $ do typeName <- UbcLanguage.typeName @@ -61,10 +60,10 @@ structVariableOrFunction = do return (VariableType.fromString typeName, objectIdentifier) choice [ parseVariable typeName identifier - , Function <$!> Function.parsePrefixed typeName identifier - ] -- TODO: Functions on structs + , (\ f -> mempty { functions = [f] }) <$!> Function.parsePrefixed typeName identifier + ] -parseVariable :: Monad m => VariableType -> String -> ParsecT String u m StructStatement +parseVariable :: Monad m => VariableType -> String -> ParsecT String u m StructBody parseVariable variableType variableName = do _ <- UbcLanguage.semicolon - return $ Variable variableName variableType + return $ mempty { variables = [(variableName, variableType)] }