Compare commits

..

No commits in common. "cbfd729795507f7cf0d5f13792ee5b6877bdaed4" and "ac0e697622ccf1699e08433a7c1c1b0f114ada47" have entirely different histories.

19 changed files with 139 additions and 213 deletions

View file

@ -6,7 +6,6 @@ import System.Directory as Directory
import qualified Control.Monad.Trans.Reader as Reader import qualified Control.Monad.Trans.Reader as Reader
import qualified Data.Set as Set import qualified Data.Set as Set
import qualified Data.Text.IO as Text.IO
import qualified Text.Parsec as Parsec import qualified Text.Parsec as Parsec
@ -23,7 +22,7 @@ minimalConfig = do
main :: IO () main :: IO ()
main = do main = do
text <- Text.IO.getContents text <- getContents
-- fixme: handle errors? -- fixme: handle errors?
parseConfig <- minimalConfig parseConfig <- minimalConfig

View file

@ -29,7 +29,6 @@ dependencies:
- os-string - os-string
- path - path
- parsec - parsec
- text
- transformers - transformers
ghc-options: ghc-options:

View file

@ -1,12 +1,7 @@
module Ubc.Parse.Syntax module Ubc.Parse.Syntax
(Transformer, Token) (Transformer)
where where
import Control.Monad.Reader (ReaderT) import Control.Monad.Reader (ReaderT)
import Data.Text ( Text )
import Ubc.Parse.Syntax.Config (Config) import Ubc.Parse.Syntax.Config (Config)
type Transformer = ReaderT Config IO type Transformer = ReaderT Config IO
type Token = Text

View file

@ -1,4 +1,3 @@
{-# LANGUAGE OverloadedStrings #-}
module Ubc.Parse.Syntax.Enumeration module Ubc.Parse.Syntax.Enumeration
( Enumeration(..) ( Enumeration(..)
, parse , parse
@ -8,17 +7,15 @@ where
import Text.Parsec (ParsecT, many, (<?>)) import Text.Parsec (ParsecT, many, (<?>))
import qualified Ubc.Parse.Syntax.Language as UbcLanguage import qualified Ubc.Parse.Syntax.Language as UbcLanguage
import Ubc.Parse.Syntax (Token)
import Data.Text (Text)
type EnumerationMember = Token type EnumerationMember = String
data Enumeration = Enumeration data Enumeration = Enumeration
{ name :: Text { name :: String
, members :: [EnumerationMember] , members :: [EnumerationMember]
} }
deriving (Show) deriving (Show)
parse :: Monad m => ParsecT Token u m Enumeration parse :: Monad m => ParsecT String u m Enumeration
parse = do parse = do
UbcLanguage.reserved "enum" UbcLanguage.reserved "enum"
identifier <- UbcLanguage.identifier <?> "enum identifier" identifier <- UbcLanguage.identifier <?> "enum identifier"

View file

@ -1,8 +1,6 @@
{-# LANGUAGE OverloadedStrings #-}
module Ubc.Parse.Syntax.Expression module Ubc.Parse.Syntax.Expression
( Expression(..) ( Expression(..)
, expressionParser , expressionParser
, blockExpression
) )
where where
@ -11,32 +9,27 @@ import Data.Functor ( (<&>), ($>) )
import Data.Ratio ((%)) import Data.Ratio ((%))
import Text.Parsec.Expr (Operator(Infix, Prefix), Assoc (AssocLeft, AssocRight), buildExpressionParser) import Text.Parsec.Expr (Operator(Infix, Prefix), Assoc (AssocLeft, AssocRight), buildExpressionParser)
import Text.Parsec (ParsecT, (<|>), (<?>), choice, option, many1, digit, lookAhead, oneOf, char, notFollowedBy, many) import Text.Parsec (ParsecT, (<|>), (<?>), choice, option, many1, digit, lookAhead, oneOf, char, notFollowedBy)
import Ubc.Parse.Syntax.Statement (Statement) import Ubc.Parse.Syntax.Statement (blockExpression, Statement)
import Ubc.Parse.Syntax.Operators (BinaryOperator(..), UnaryOperator (..)) import Ubc.Parse.Syntax.Operators (BinaryOperator(..), UnaryOperator (..))
import qualified Ubc.Parse.Syntax.Language as UbcLanguage import qualified Ubc.Parse.Syntax.Language as UbcLanguage
import Ubc.Parse.Syntax (Token)
import qualified Ubc.Parse.Syntax.Statement as Statement
data Expression = Binary BinaryOperator Expression Expression data Expression = Binary BinaryOperator Expression Expression
| Unary UnaryOperator Expression | Unary UnaryOperator Expression
| ConstantInteger Integer | ConstantInteger Integer
| ConstantFraction Rational | ConstantFraction Rational
| FunctionCall Token [Expression] | FunctionCall String [Expression]
| Variable Token | Variable String
| If Expression Expression (Maybe Expression) -- if then else | If Expression Expression (Maybe Expression) -- if then else
| Loop Expression Expression -- condition body | Loop Expression Expression -- condition body
| Block [Statement] | Block [Statement]
deriving (Show) deriving (Show)
operatorTable :: Monad m => [[Operator Token u m Expression]] operatorTable :: Monad m => [[Operator String u m Expression]]
operatorTable = operatorTable =
[ [
[ Infix (UbcLanguage.reservedOperator "." $> Binary StructureAccess) AssocLeft
]
,
[ Infix (UbcLanguage.reservedOperator "*" $> Binary Multiply) AssocLeft [ Infix (UbcLanguage.reservedOperator "*" $> Binary Multiply) AssocLeft
, Infix (UbcLanguage.reservedOperator "/" $> Binary Divide) AssocLeft , Infix (UbcLanguage.reservedOperator "/" $> Binary Divide) AssocLeft
, Infix (UbcLanguage.reservedOperator "%" $> Binary Modulo) AssocLeft , Infix (UbcLanguage.reservedOperator "%" $> Binary Modulo) AssocLeft
@ -70,10 +63,10 @@ operatorTable =
, [ Infix (UbcLanguage.reservedOperator "=" $> Binary Assign) AssocRight ] , [ Infix (UbcLanguage.reservedOperator "=" $> Binary Assign) AssocRight ]
] ]
expressionParser :: (Monad m) => ParsecT Token u m Expression expressionParser :: (Monad m) => ParsecT String u m Expression
expressionParser = buildExpressionParser operatorTable termParser <?> "expression" expressionParser = buildExpressionParser operatorTable termParser <?> "expression"
numberTerm :: Monad m => ParsecT Token u m Expression numberTerm :: Monad m => ParsecT String u m Expression
numberTerm = do numberTerm = do
notFollowedBy $ char '0' notFollowedBy $ char '0'
integerDigits <- many1 digit integerDigits <- many1 digit
@ -83,7 +76,7 @@ numberTerm = do
] ]
<* UbcLanguage.whiteSpace <* UbcLanguage.whiteSpace
decimalTerm :: Monad m => [Char] -> ParsecT Token u m Expression decimalTerm :: Monad m => [Char] -> ParsecT String u m Expression
decimalTerm integerDigits = do decimalTerm integerDigits = do
_ <- lookAhead $ oneOf "e." _ <- lookAhead $ oneOf "e."
fractionalDigits <- option "" $ char '.' *> many1 digit fractionalDigits <- option "" $ char '.' *> many1 digit
@ -96,7 +89,7 @@ decimalTerm integerDigits = do
return $ ConstantFraction $ numeratorInteger ^ numeratorPower % denominatorInteger ^ denominatorPower return $ ConstantFraction $ numeratorInteger ^ numeratorPower % denominatorInteger ^ denominatorPower
termParser :: Monad m => ParsecT Token u m Expression termParser :: Monad m => ParsecT String u m Expression
termParser = UbcLanguage.parens expressionParser termParser = UbcLanguage.parens expressionParser
<|> numberTerm <|> numberTerm
<|> fmap ConstantInteger UbcLanguage.integer <|> fmap ConstantInteger UbcLanguage.integer
@ -108,13 +101,13 @@ termParser = UbcLanguage.parens expressionParser
<|> functionCallOrVariable <|> functionCallOrVariable
<?> "term" <?> "term"
loopExpression :: Monad m => String -> (Expression -> Expression) -> ParsecT Token u m Expression loopExpression :: Monad m => String -> (Expression -> Expression) -> ParsecT String u m Expression
loopExpression startKeyword conditionWrapper = do loopExpression startKeyword conditionWrapper = do
_ <- UbcLanguage.reserved startKeyword _ <- UbcLanguage.reserved startKeyword
condition <- conditionWrapper <$!> expressionParser condition <- conditionWrapper <$!> expressionParser
Loop condition <$> expressionParser Loop condition <$> expressionParser
conditionalExpression :: Monad m => String -> (Expression -> Expression) -> ParsecT Token u m Expression conditionalExpression :: Monad m => String -> (Expression -> Expression) -> ParsecT String u m Expression
conditionalExpression startKeyword conditionWrapper = do conditionalExpression startKeyword conditionWrapper = do
_ <- UbcLanguage.reserved startKeyword _ <- UbcLanguage.reserved startKeyword
condition <- conditionWrapper <$!> expressionParser condition <- conditionWrapper <$!> expressionParser
@ -124,7 +117,7 @@ conditionalExpression startKeyword conditionWrapper = do
return $ If condition then_ else_ return $ If condition then_ else_
functionCallOrVariable :: Monad m => ParsecT Token u m Expression functionCallOrVariable :: Monad m => ParsecT String u m Expression
functionCallOrVariable = do functionCallOrVariable = do
name <- UbcLanguage.identifier name <- UbcLanguage.identifier
choice choice
@ -132,5 +125,3 @@ functionCallOrVariable = do
, return $ Variable name , return $ Variable name
] ]
blockExpression :: Monad m => ParsecT Token u m Expression
blockExpression = UbcLanguage.braces (many Statement.parse) <&> Block

View file

@ -1,14 +1,21 @@
module Ubc.Parse.Syntax.Expression module Ubc.Parse.Syntax.Expression
( Expression ( Expression(..)
, expressionParser , expressionParser
, blockExpression
) )
where where
import Text.Parsec (ParsecT) import Text.Parsec (ParsecT)
import Ubc.Parse.Syntax (Token) import Ubc.Parse.Syntax.Operators (BinaryOperator, UnaryOperator)
import {-# SOURCE #-} Ubc.Parse.Syntax.Statement (Statement)
data Expression data Expression = Binary BinaryOperator Expression Expression
| Unary UnaryOperator Expression
| ConstantInteger Integer
| ConstantFraction Rational
| FunctionCall String [Expression]
| Variable String
| If Expression Expression (Maybe Expression) -- if then else
| Loop Expression Expression -- condition body
| Block [Statement]
instance Show Expression instance Show Expression
expressionParser :: Monad m => ParsecT Token u m Expression expressionParser :: Monad m => ParsecT String u m Expression
blockExpression :: Monad m => ParsecT Token u m Expression

View file

@ -11,13 +11,9 @@ import GHC.Generics (Generic, Generically(..))
import Control.Monad ((<$!>)) import Control.Monad ((<$!>))
import Data.Functor ((<&>)) import Data.Functor ((<&>))
import qualified Data.Text as Text
import Text.Parsec (choice, ParsecT, many) import Text.Parsec (choice, ParsecT, many)
import qualified Text.Parsec as Parsec import Ubc.Parse.Syntax (Transformer)
import Ubc.Parse.Syntax (Transformer, Token)
import {-# SOURCE #-} Ubc.Parse.Syntax.Import (Import) import {-# SOURCE #-} Ubc.Parse.Syntax.Import (Import)
import Ubc.Parse.Syntax.Struct (Struct) import Ubc.Parse.Syntax.Struct (Struct)
@ -30,9 +26,10 @@ import qualified Ubc.Parse.Syntax.Struct as Struct
import qualified Ubc.Parse.Syntax.Function as Function import qualified Ubc.Parse.Syntax.Function as Function
import qualified Ubc.Parse.Syntax.Statement as Statement import qualified Ubc.Parse.Syntax.Statement as Statement
import qualified Ubc.Parse.Syntax.Enumeration as Enumeration import qualified Ubc.Parse.Syntax.Enumeration as Enumeration
import qualified Text.Parsec as Parsec
data File = File data File = File
{ name :: Token { name :: String
, body :: FileBody , body :: FileBody
} }
deriving (Show) deriving (Show)
@ -48,13 +45,13 @@ data FileBody = FileBody
deriving (Semigroup, Monoid) via Generically FileBody deriving (Semigroup, Monoid) via Generically FileBody
-- dont use `deriving ... via FileBody` because that leads to a loop, somehow -- dont use `deriving ... via FileBody` because that leads to a loop, somehow
parse :: ParsecT Token u Transformer File parse :: ParsecT String u Transformer File
parse = do parse = do
fileName <- Text.pack . Parsec.sourceName <$!> Parsec.getPosition fileName <- Parsec.sourceName <$!> Parsec.getPosition
fileBody <- mconcat <$!> many fileMember fileBody <- mconcat <$!> many fileMember
pure $ File fileName fileBody pure $ File fileName fileBody
fileMember :: ParsecT Token u Transformer FileBody fileMember :: ParsecT String u Transformer FileBody
fileMember = choice fileMember = choice
[ Struct.parse <&> \s -> mempty { structs = [s] } [ Struct.parse <&> \s -> mempty { structs = [s] }
, Import.parse <&> \i -> mempty { imports = [i] } , Import.parse <&> \i -> mempty { imports = [i] }

View file

@ -6,10 +6,10 @@ where
import Text.Parsec (ParsecT) import Text.Parsec (ParsecT)
import Ubc.Parse.Syntax (Transformer, Token) import Ubc.Parse.Syntax (Transformer)
data File data File
instance Show File instance Show File
parse :: ParsecT Token u Transformer File parse :: ParsecT String u Transformer File

View file

@ -1,4 +1,3 @@
{-# LANGUAGE OverloadedStrings #-}
module Ubc.Parse.Syntax.Function module Ubc.Parse.Syntax.Function
( Function(..) ( Function(..)
, parse , parse
@ -13,32 +12,26 @@ import Text.Parsec (lookAhead, try, ParsecT)
import Ubc.Parse.Syntax.VariableType (VariableType) import Ubc.Parse.Syntax.VariableType (VariableType)
import {-# SOURCE #-} Ubc.Parse.Syntax.Expression (Expression, expressionParser) import {-# SOURCE #-} Ubc.Parse.Syntax.Expression (Expression, expressionParser)
import Ubc.Parse.Syntax.Generic (Generic)
import qualified Ubc.Parse.Syntax.Language as UbcLanguage import qualified Ubc.Parse.Syntax.Language as UbcLanguage
import qualified Ubc.Parse.Syntax.VariableType as VariableType import qualified Ubc.Parse.Syntax.VariableType as VariableType
import qualified Ubc.Parse.Syntax.Generic as Generic
import Ubc.Parse.Syntax (Token)
data Function = Function data Function = Function
{ returnType :: VariableType { identifier :: String
, identifier :: Token , returnType :: VariableType
, generics :: [Generic]
, body :: Expression , body :: Expression
, arguments :: [(VariableType, Token)] , arguments :: [(VariableType, String)]
} }
deriving (Show) deriving (Show)
parsePrefixed :: Monad m => VariableType -> Token -> ParsecT Token u m Function parsePrefixed :: Monad m => VariableType -> String -> ParsecT String u m Function
parsePrefixed ftype fname = do parsePrefixed ftype fname = do
genericList <- UbcLanguage.angles $ UbcLanguage.commaSeparated1 Generic.parse
argumentList <- UbcLanguage.parens (UbcLanguage.commaSeparated argumentDefinition) argumentList <- UbcLanguage.parens (UbcLanguage.commaSeparated argumentDefinition)
expressionBody <- expressionParser expressionBody <- expressionParser
return $ Function ftype fname genericList expressionBody argumentList return $ Function fname ftype expressionBody argumentList
parse :: Monad m => ParsecT Token u m Function parse :: Monad m => ParsecT String u m Function
parse = do parse = do
(resultType, name) <- try $ do (resultType, name) <- try $ do
resultType <- UbcLanguage.typeName resultType <- UbcLanguage.typeName
@ -48,7 +41,7 @@ parse = do
parsePrefixed resultType name parsePrefixed resultType name
argumentDefinition :: Monad m => ParsecT Token u m (VariableType, Token) argumentDefinition :: Monad m => ParsecT String u m (VariableType, String)
argumentDefinition = do argumentDefinition = do
argumentType <- VariableType.fromString <$!> UbcLanguage.typeName argumentType <- VariableType.fromString <$!> UbcLanguage.typeName
argumentName <- UbcLanguage.identifier argumentName <- UbcLanguage.identifier

View file

@ -1,19 +0,0 @@
{-# LANGUAGE DerivingStrategies #-}
module Ubc.Parse.Syntax.Generic
( Generic(..)
, parse
)
where
import qualified Ubc.Parse.Syntax.Language as Language
import Control.Monad ((<$!>))
import Text.Parsec (ParsecT)
import Ubc.Parse.Syntax (Token)
data Generic = Generic
{ name :: Token
}
deriving stock (Show)
parse :: Monad m => ParsecT Token u m Generic
parse = Generic <$!> Language.identifier

View file

@ -1,6 +1,5 @@
{-# LANGUAGE LambdaCase #-} {-# LANGUAGE LambdaCase #-}
{-# LANGUAGE DerivingStrategies #-} {-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE OverloadedStrings #-}
module Ubc.Parse.Syntax.Import module Ubc.Parse.Syntax.Import
( parse ( parse
, Import(..) , Import(..)
@ -19,19 +18,17 @@ import Data.Functor ((<&>))
import Data.List.NonEmpty (NonEmpty) import Data.List.NonEmpty (NonEmpty)
import qualified Data.List as List import qualified Data.List as List
import qualified Data.List.NonEmpty as NonEmpty
import qualified Data.Set as Set import qualified Data.Set as Set
import qualified Data.Text as Text import qualified Data.List.NonEmpty as NonEmpty
import qualified Data.Text.IO as Text.IO
import qualified System.Directory as IO import qualified System.Directory as IO
import Text.Parsec (sepBy1, ParsecT, anyChar, many, char, choice, notFollowedBy, oneOf) import Text.Parsec (sepBy1, ParsecT, anyChar, many, char, choice, notFollowedBy, oneOf, option)
import qualified Text.Parsec as Parsec import qualified Text.Parsec as Parsec
import Path as Path ( Path, File, parseRelFile, Rel, parseRelDir, Dir, Abs, (</>), fromAbsFile, fromRelFile ) import Path as Path ( Path, File, parseRelFile, Rel, parseRelDir, Dir, Abs, (</>), fromAbsFile, fromRelFile )
import Ubc.Parse.Syntax (Transformer, Token) import Ubc.Parse.Syntax (Transformer)
import Ubc.Parse.Syntax.Config (Config) import Ubc.Parse.Syntax.Config (Config)
import qualified Ubc.Parse.Syntax.Config as Config import qualified Ubc.Parse.Syntax.Config as Config
import qualified Ubc.Parse.Syntax.File as File import qualified Ubc.Parse.Syntax.File as File
@ -39,22 +36,21 @@ import qualified Ubc.Parse.Syntax.Language as UbcLanguage
data Import = Import data Import = Import
{ file :: File.File { file :: File.File
, alias :: Maybe Token , alias :: String
, list :: [Token]
} }
deriving stock (Show) deriving stock (Show)
importPath :: Monad m => ParsecT Token u m (NonEmpty Token) importPath :: Monad m => ParsecT String u m (NonEmpty String)
importPath = UbcLanguage.angles (many importChar `sepBy1` char '/') importPath = UbcLanguage.angles (many importChar `sepBy1` char '/')
<&> NonEmpty.fromList . List.map Text.pack <&> NonEmpty.fromList
importChar :: (Monad m) => ParsecT Token u m Char importChar :: (Monad m) => ParsecT String u m Char
importChar = choice importChar = choice
[ char '\\' >> oneOf ">/\\" [ char '\\' >> oneOf ">/\\"
, notFollowedBy (oneOf ">/") >> anyChar , notFollowedBy (oneOf ">/") >> anyChar
] ]
parse :: ParsecT Token u Transformer Import parse :: ParsecT String u Transformer Import
parse = do parse = do
UbcLanguage.reserved "import" UbcLanguage.reserved "import"
fragments <- importPath fragments <- importPath
@ -71,34 +67,32 @@ parse = do
-- fail or parse -- fail or parse
importedFile <- case existingFiles of importedFile <- case existingFiles of
[] -> fail . Text.unpack $ notFoundMessage relFile possiblePaths [] -> fail $ notFoundMessage relFile possiblePaths
[path] -> parseFile path [path] -> parseFile path
fs@_ -> fail . Text.unpack $ multipleFoundMessage relFile fs fs@_ -> fail $ multipleFoundMessage relFile fs
importAs <- Parsec.optionMaybe importAlias importAs <- Parsec.parserTraced "alias" $ option (NonEmpty.last fragments) importAlias
importList <- UbcLanguage.parens $ UbcLanguage.commaSeparated UbcLanguage.identifier return $ Import importedFile importAs
return $ Import importedFile importAs importList importAlias :: Monad m => ParsecT String u m String
importAlias :: Monad m => ParsecT Token u m Token
importAlias = UbcLanguage.reserved "as" importAlias = UbcLanguage.reserved "as"
*> UbcLanguage.identifier *> UbcLanguage.identifier
multipleFoundMessage :: Path Rel File -> [Path Abs File] -> Token multipleFoundMessage :: Path Rel File -> [Path Abs File] -> String
multipleFoundMessage relFile foundFiles = "Could not identify imported file " <> Text.pack (Path.fromRelFile relFile) <> "\n" multipleFoundMessage relFile foundFiles = "Could not identify imported file " <> Path.fromRelFile relFile <> "\n"
<> "Found multiple files in the search path:" <> "Found multiple files in the search path:"
<> (Text.unlines . List.map (Path.fromAbsFile >>> ('\t':) >>> Text.pack) $ foundFiles) <> (unlines . List.map (Path.fromAbsFile >>> ('\t':)) $ foundFiles)
notFoundMessage :: Path Rel File -> [Path Abs File] -> Token notFoundMessage :: Path Rel File -> [Path Abs File] -> String
notFoundMessage relFile searchedLocations = "Could not locate import file <" <> Text.pack (Path.fromRelFile relFile) <> ">\n" notFoundMessage relFile searchedLocations = "Could not locate import file <" <> Path.fromRelFile relFile <> ">\n"
<> "Searched locations were:\n" <> "Searched locations were:\n"
<> (Text.unlines . List.map (Path.fromAbsFile >>> ('\t':) >>> Text.pack) $ searchedLocations) <> (unlines . List.map (('\t':) . Path.fromAbsFile) $ searchedLocations)
parseFile :: Path Abs File -> ParsecT Token u Transformer File.File parseFile :: Path Abs File -> ParsecT String u Transformer File.File
parseFile path = do parseFile path = do
let stringPath = Path.fromAbsFile path let stringPath = Path.fromAbsFile path
contents <- liftIO . Text.IO.readFile $ stringPath contents <- liftIO . readFile $ stringPath
-- save old state -- save old state
oldInput <- Parsec.getInput oldInput <- Parsec.getInput
@ -126,10 +120,10 @@ parseFile path = do
pure importedFile pure importedFile
parseRelPath :: MonadThrow m => NonEmpty Token -> m (Path Rel File) parseRelPath :: MonadThrow m => NonEmpty FilePath -> m (Path Rel File)
parseRelPath fragments = do parseRelPath fragments = do
name <- Path.parseRelFile . Text.unpack $ NonEmpty.last fragments name <- Path.parseRelFile $ NonEmpty.last fragments
dirPath <- mapM (Path.parseRelDir . Text.unpack) . NonEmpty.init $ fragments dirPath <- mapM Path.parseRelDir . NonEmpty.init $ fragments
pure $ constructRelative name dirPath pure $ constructRelative name dirPath
constructRelative :: Path Rel t -> [Path Rel Dir] -> Path Rel t constructRelative :: Path Rel t -> [Path Rel Dir] -> Path Rel t

View file

@ -6,10 +6,10 @@ where
import Text.Parsec (ParsecT) import Text.Parsec (ParsecT)
import Ubc.Parse.Syntax (Transformer, Token) import Ubc.Parse.Syntax (Transformer)
data Import data Import
instance Show Import instance Show Import
parse :: ParsecT Token u Transformer Import parse :: ParsecT String u Transformer Import

View file

@ -1,4 +1,3 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE NoMonomorphismRestriction #-} {-# LANGUAGE NoMonomorphismRestriction #-}
module Ubc.Parse.Syntax.Language module Ubc.Parse.Syntax.Language
( languageDef ( languageDef
@ -34,24 +33,19 @@ module Ubc.Parse.Syntax.Language
) )
where where
import Data.Functor ( ($>), (<&>) ) import Data.Functor ( ($>) )
import qualified Data.Text as Text
import Text.Parsec import Text.Parsec
( alphaNum, char, letter, oneOf, choice, (<|>), ParsecT ) ( alphaNum, char, letter, oneOf, choice, (<|>), ParsecT )
import Text.Parsec.Token import Text.Parsec.Token
( makeTokenParser, ( makeTokenParser,
GenLanguageDef(..), GenLanguageDef(..),
GenTokenParser(TokenParser, GenTokenParser(TokenParser, identifier, reserved, operator,
charLiteral, natural, integer, float, reservedOp, charLiteral, stringLiteral, natural, integer, float,
naturalOrFloat, decimal, hexadecimal, octal, lexeme, naturalOrFloat, decimal, hexadecimal, octal, symbol, lexeme,
whiteSpace, parens, braces, angles, brackets, whiteSpace, parens, braces, angles, brackets, semi, comma, colon,
semiSep, semiSep1, commaSep, commaSep1) ) dot, semiSep, semiSep1, commaSep, commaSep1) )
import qualified Text.Parsec.Token as Token
import Ubc.Parse.Syntax (Token) languageDef :: Monad m => GenLanguageDef String u m
languageDef :: Monad m => GenLanguageDef Token u m
languageDef = LanguageDef { languageDef = LanguageDef {
commentStart = "/*" commentStart = "/*"
, commentEnd = "*/" , commentEnd = "*/"
@ -98,29 +92,44 @@ languageDef = LanguageDef {
, caseSensitive = True , caseSensitive = True
} }
tokenParser :: Monad m => GenTokenParser Token u m tokenParser :: Monad m => GenTokenParser String u m
tokenParser = makeTokenParser languageDef tokenParser = makeTokenParser languageDef
characterLiteral :: Monad m => ParsecT Token u m Char identifier :: Monad m => ParsecT String u m String
natural :: Monad m => ParsecT Token u m Integer reserved :: Monad m => String -> ParsecT String u m ()
integer :: Monad m => ParsecT Token u m Integer operator :: Monad m => ParsecT String u m String
float :: Monad m => ParsecT Token u m Double reservedOperator :: Monad m => String -> ParsecT String u m ()
naturalOrFloat :: Monad m => ParsecT Token u m (Either Integer Double) characterLiteral :: Monad m => ParsecT String u m Char
decimal :: Monad m => ParsecT Token u m Integer stringLiteral :: Monad m => ParsecT String u m String
hexadecimal :: Monad m => ParsecT Token u m Integer natural :: Monad m => ParsecT String u m Integer
octal :: Monad m => ParsecT Token u m Integer integer :: Monad m => ParsecT String u m Integer
lexeme :: Monad m => ParsecT Token u m a -> ParsecT Token u m a float :: Monad m => ParsecT String u m Double
whiteSpace :: Monad m => ParsecT Token u m () naturalOrFloat :: Monad m => ParsecT String u m (Either Integer Double)
parens :: Monad m => ParsecT Token u m a -> ParsecT Token u m a decimal :: Monad m => ParsecT String u m Integer
braces :: Monad m => ParsecT Token u m a -> ParsecT Token u m a hexadecimal :: Monad m => ParsecT String u m Integer
angles :: Monad m => ParsecT Token u m a -> ParsecT Token u m a octal :: Monad m => ParsecT String u m Integer
brackets :: Monad m => ParsecT Token u m a -> ParsecT Token u m a symbol :: Monad m => String -> ParsecT String u m String
semicolonSeparated :: Monad m => ParsecT Token u m a -> ParsecT Token u m [a] lexeme :: Monad m => ParsecT String u m a -> ParsecT String u m a
semicolonSeparated1 :: Monad m => ParsecT Token u m a -> ParsecT Token u m [a] whiteSpace :: Monad m => ParsecT String u m ()
commaSeparated :: Monad m => ParsecT Token u m a -> ParsecT Token u m [a] parens :: Monad m => ParsecT String u m a -> ParsecT String u m a
commaSeparated1 :: Monad m => ParsecT Token u m a -> ParsecT Token u m [a] braces :: Monad m => ParsecT String u m a -> ParsecT String u m a
angles :: Monad m => ParsecT String u m a -> ParsecT String u m a
brackets :: Monad m => ParsecT String u m a -> ParsecT String u m a
semicolon :: Monad m => ParsecT String u m String
comma :: Monad m => ParsecT String u m String
colon :: Monad m => ParsecT String u m String
dot :: Monad m => ParsecT String u m String
semicolonSeparated :: Monad m => ParsecT String u m a -> ParsecT String u m [a]
semicolonSeparated1 :: Monad m => ParsecT String u m a -> ParsecT String u m [a]
commaSeparated :: Monad m => ParsecT String u m a -> ParsecT String u m [a]
commaSeparated1 :: Monad m => ParsecT String u m a -> ParsecT String u m [a]
TokenParser{ TokenParser{
charLiteral = characterLiteral identifier = identifier
, reserved = reserved
, operator = operator
, reservedOp = reservedOperator
, charLiteral = characterLiteral
, stringLiteral = stringLiteral
, natural = natural -- decimal, hexadecimal or octal , natural = natural -- decimal, hexadecimal or octal
, integer = integer -- decimal, hexadecimal or octal , integer = integer -- decimal, hexadecimal or octal
, float = float , float = float
@ -128,49 +137,24 @@ TokenParser{
, decimal = decimal , decimal = decimal
, hexadecimal = hexadecimal , hexadecimal = hexadecimal
, octal = octal , octal = octal
, symbol = symbol
, lexeme = lexeme , lexeme = lexeme
, whiteSpace = whiteSpace , whiteSpace = whiteSpace
, parens = parens , parens = parens
, braces = braces , braces = braces
, angles = angles , angles = angles
, brackets = brackets , brackets = brackets
, semi = semicolon
, comma = comma
, colon = colon
, dot = dot
, semiSep = semicolonSeparated , semiSep = semicolonSeparated
, semiSep1 = semicolonSeparated1 , semiSep1 = semicolonSeparated1
, commaSep = commaSeparated , commaSep = commaSeparated
, commaSep1 = commaSeparated1 , commaSep1 = commaSeparated1
} = tokenParser } = tokenParser
semicolon :: Monad m => ParsecT Token u m Token typeName :: Monad m => ParsecT String u m String
semicolon = Token.semi tokenParser <&> Text.pack
comma :: Monad m => ParsecT Token u m Token
comma = Token.comma tokenParser <&> Text.pack
colon :: Monad m => ParsecT Token u m Token
colon = Token.colon tokenParser <&> Text.pack
dot :: Monad m => ParsecT Token u m Token
dot = Token.dot tokenParser <&> Text.pack
symbol :: Monad m => String -> ParsecT Token u m Token
symbol = (<&> Text.pack) . Token.symbol tokenParser
stringLiteral :: Monad m => ParsecT Token u m Token
stringLiteral = Token.stringLiteral tokenParser <&> Text.pack
identifier :: Monad m => ParsecT Token u m Token
identifier = Token.identifier tokenParser <&> Text.pack
reserved :: Monad m => String -> ParsecT Token u m ()
reserved = Token.reserved tokenParser
operator :: Monad m => ParsecT Token u m Token
operator = Token.operator tokenParser <&> Text.pack
reservedOperator :: Monad m => String -> ParsecT Token u m ()
reservedOperator = Token.reservedOp tokenParser
typeName :: Monad m => ParsecT Token u m Token
typeName = choice typeName = choice
[ Ubc.Parse.Syntax.Language.reserved "i32" $> "i32" [ Ubc.Parse.Syntax.Language.reserved "i32" $> "i32"
, Ubc.Parse.Syntax.Language.reserved "u32" $> "u32" , Ubc.Parse.Syntax.Language.reserved "u32" $> "u32"

View file

@ -26,5 +26,4 @@ data BinaryOperator = Plus
| LogicAnd | LogicAnd
| LogicOr | LogicOr
| Assign | Assign
| StructureAccess
deriving (Show) deriving (Show)

View file

@ -1,12 +1,12 @@
{-# LANGUAGE OverloadedStrings #-}
module Ubc.Parse.Syntax.Statement module Ubc.Parse.Syntax.Statement
( Statement(..) ( Statement(..)
, parse , parse
, blockExpression
) )
where where
import Ubc.Parse.Syntax.VariableType (VariableType) import Ubc.Parse.Syntax.VariableType (VariableType)
import {-# SOURCE #-} Ubc.Parse.Syntax.Expression (expressionParser, Expression,) import {-# SOURCE #-} Ubc.Parse.Syntax.Expression (expressionParser, Expression (Block))
import Ubc.Parse.Syntax.TypeExpression (TypeExpression) import Ubc.Parse.Syntax.TypeExpression (TypeExpression)
import Text.Parsec (choice, ParsecT, try, many) import Text.Parsec (choice, ParsecT, try, many)
import qualified Ubc.Parse.Syntax.Language as UbcLanguage import qualified Ubc.Parse.Syntax.Language as UbcLanguage
@ -14,23 +14,22 @@ import qualified Ubc.Parse.Syntax.VariableType as VariableType
import qualified Ubc.Parse.Syntax.TypeExpression as TypeExpression import qualified Ubc.Parse.Syntax.TypeExpression as TypeExpression
import Control.Monad ((<$!>)) import Control.Monad ((<$!>))
import Data.Functor ((<&>)) import Data.Functor ((<&>))
import Ubc.Parse.Syntax (Token)
type VariableName = Token type VariableName = String
type TypeName = Token type TypeName = String
data Statement = VariableDefinition VariableType VariableName Expression data Statement = VariableDefinition VariableType VariableName Expression
| TypeDefinition TypeName TypeExpression | TypeDefinition TypeName TypeExpression
| ExpressionStatement Expression | ExpressionStatement Expression
deriving (Show) deriving (Show)
parse :: Monad m => ParsecT Token u m Statement parse :: Monad m => ParsecT String u m Statement
parse = choice [ variableDefinition parse = choice [ variableDefinition
, typeDefinition , typeDefinition
, ExpressionStatement <$!> expressionParser , ExpressionStatement <$!> expressionParser
] ]
typeDefinition :: Monad m => ParsecT Token u m Statement typeDefinition :: Monad m => ParsecT String u m Statement
typeDefinition = do typeDefinition = do
UbcLanguage.reserved "type" UbcLanguage.reserved "type"
@ -41,7 +40,7 @@ typeDefinition = do
TypeDefinition name <$> TypeExpression.parseTypeExpression TypeDefinition name <$> TypeExpression.parseTypeExpression
variableDefinition :: Monad m => ParsecT Token u m Statement variableDefinition :: Monad m => ParsecT String u m Statement
variableDefinition = do variableDefinition = do
(variableType, variableName) <- try $ do (variableType, variableName) <- try $ do
variableType <- UbcLanguage.typeName variableType <- UbcLanguage.typeName
@ -50,3 +49,6 @@ variableDefinition = do
return (VariableType.fromString variableType, variableName) return (VariableType.fromString variableType, variableName)
VariableDefinition variableType variableName <$> expressionParser VariableDefinition variableType variableName <$> expressionParser
blockExpression :: Monad m => ParsecT String u m Expression
blockExpression = UbcLanguage.braces (many parse) <&> Block

View file

@ -1,6 +1,5 @@
{-# LANGUAGE DerivingVia #-} {-# LANGUAGE DerivingVia #-}
{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
module Ubc.Parse.Syntax.Struct module Ubc.Parse.Syntax.Struct
( Struct(..) ( Struct(..)
, parse , parse
@ -26,14 +25,11 @@ import Ubc.Parse.Syntax.Function (Function)
import qualified Ubc.Parse.Syntax.Language as UbcLanguage import qualified Ubc.Parse.Syntax.Language as UbcLanguage
import qualified Ubc.Parse.Syntax.VariableType as VariableType import qualified Ubc.Parse.Syntax.VariableType as VariableType
import qualified Ubc.Parse.Syntax.Function as Function import qualified Ubc.Parse.Syntax.Function as Function
import qualified Ubc.Parse.Syntax.Generic as Syntax.Generic
import Ubc.Parse.Syntax (Token)
type VariableName = Token type VariableName = String
data Struct = Struct data Struct = Struct
{ name :: Token { name :: String
, generics :: [Syntax.Generic.Generic]
, body :: StructBody , body :: StructBody
} }
deriving (Show) deriving (Show)
@ -45,19 +41,18 @@ data StructBody = StructBody
deriving stock (Generic, Show) deriving stock (Generic, Show)
deriving (Semigroup, Monoid) via Generically StructBody deriving (Semigroup, Monoid) via Generically StructBody
parse :: Monad m => ParsecT Token u m Struct parse :: Monad m => ParsecT String u m Struct
parse = do parse = do
_ <- UbcLanguage.reserved "struct" _ <- UbcLanguage.reserved "struct"
structIdentifier <- UbcLanguage.identifier structIdentifier <- UbcLanguage.identifier
structGenerics <- UbcLanguage.angles $ UbcLanguage.commaSeparated1 Syntax.Generic.parse
structBody <- mconcat <$!> UbcLanguage.braces (many structMember) structBody <- mconcat <$!> UbcLanguage.braces (many structMember)
pure $ Struct structIdentifier structGenerics structBody pure $ Struct structIdentifier structBody
structMember :: Monad m => ParsecT Token u m StructBody structMember :: Monad m => ParsecT String u m StructBody
structMember = choice [ structVariableOrFunction ] structMember = choice [ structVariableOrFunction ]
structVariableOrFunction :: Monad m => ParsecT Token u m StructBody structVariableOrFunction :: Monad m => ParsecT String u m StructBody
structVariableOrFunction = do structVariableOrFunction = do
(typeName, identifier) <- try $ do (typeName, identifier) <- try $ do
typeName <- UbcLanguage.typeName typeName <- UbcLanguage.typeName
@ -68,7 +63,7 @@ structVariableOrFunction = do
, (\ f -> mempty { functions = [f] }) <$!> Function.parsePrefixed typeName identifier , (\ f -> mempty { functions = [f] }) <$!> Function.parsePrefixed typeName identifier
] ]
parseVariable :: Monad m => VariableType -> Token -> ParsecT Token u m StructBody parseVariable :: Monad m => VariableType -> String -> ParsecT String u m StructBody
parseVariable variableType variableName = do parseVariable variableType variableName = do
_ <- UbcLanguage.semicolon _ <- UbcLanguage.semicolon
return $ mempty { variables = [(variableName, variableType)] } return $ mempty { variables = [(variableName, variableType)] }

View file

@ -14,14 +14,13 @@ import Ubc.Parse.Syntax.Struct (Struct)
import qualified Ubc.Parse.Syntax.Language as UbcLanguage import qualified Ubc.Parse.Syntax.Language as UbcLanguage
import qualified Ubc.Parse.Syntax.VariableType as VariableType import qualified Ubc.Parse.Syntax.VariableType as VariableType
import qualified Ubc.Parse.Syntax.Struct as Struct import qualified Ubc.Parse.Syntax.Struct as Struct
import Ubc.Parse.Syntax (Token)
data TypeExpression = TypeAlias VariableType data TypeExpression = TypeAlias VariableType
| StructExpression Struct | StructExpression Struct
deriving (Show) deriving (Show)
parseTypeExpression :: Monad m => ParsecT Token u m TypeExpression parseTypeExpression :: Monad m => ParsecT String u m TypeExpression
parseTypeExpression = choice parseTypeExpression = choice
[ TypeAlias . VariableType.fromString <$!> UbcLanguage.typeName [ TypeAlias . VariableType.fromString <$!> UbcLanguage.typeName
, StructExpression <$!> Struct.parse , StructExpression <$!> Struct.parse

View file

@ -1,18 +1,16 @@
{-# LANGUAGE OverloadedStrings #-}
module Ubc.Parse.Syntax.VariableType module Ubc.Parse.Syntax.VariableType
(VariableType(..) (VariableType(..)
, fromString , fromString
) )
where where
import Ubc.Parse.Syntax (Token)
data VariableType = BuiltInI32 data VariableType = BuiltInI32
| BuiltInU32 | BuiltInU32
| BuiltInF32 | BuiltInF32
| UserStruct Token | UserStruct String
deriving (Show, Eq) deriving (Show, Eq)
fromString :: Token -> VariableType fromString :: String -> VariableType
fromString "i32" = BuiltInI32 fromString "i32" = BuiltInI32
fromString "u32" = BuiltInU32 fromString "u32" = BuiltInU32
fromString "f32" = BuiltInF32 fromString "f32" = BuiltInF32

View file

@ -31,7 +31,6 @@ library
Ubc.Parse.Syntax.Expression Ubc.Parse.Syntax.Expression
Ubc.Parse.Syntax.File Ubc.Parse.Syntax.File
Ubc.Parse.Syntax.Function Ubc.Parse.Syntax.Function
Ubc.Parse.Syntax.Generic
Ubc.Parse.Syntax.Import Ubc.Parse.Syntax.Import
Ubc.Parse.Syntax.Language Ubc.Parse.Syntax.Language
Ubc.Parse.Syntax.Operators Ubc.Parse.Syntax.Operators
@ -56,7 +55,6 @@ library
, os-string , os-string
, parsec , parsec
, path , path
, text
, transformers , transformers
default-language: Haskell2010 default-language: Haskell2010
@ -79,7 +77,6 @@ executable ubcc-exe
, os-string , os-string
, parsec , parsec
, path , path
, text
, transformers , transformers
, ubcc , ubcc
default-language: Haskell2010 default-language: Haskell2010
@ -104,7 +101,6 @@ test-suite ubcc-test
, os-string , os-string
, parsec , parsec
, path , path
, text
, transformers , transformers
, ubcc , ubcc
default-language: Haskell2010 default-language: Haskell2010