Commit f0877237 authored by Kenton Varda's avatar Kenton Varda

Bunch of little things.

parent 2e3f671c
...@@ -19,5 +19,6 @@ executable capnproto-compiler ...@@ -19,5 +19,6 @@ executable capnproto-compiler
Grammar, Grammar,
Parser, Parser,
Compiler, Compiler,
Semantics Semantics,
Util
...@@ -28,6 +28,8 @@ import Semantics ...@@ -28,6 +28,8 @@ import Semantics
import Token(Located(Located)) import Token(Located(Located))
import Parser(parseFile) import Parser(parseFile)
import qualified Data.Map as Map import qualified Data.Map as Map
import qualified Data.List as List
import Data.Maybe(mapMaybe)
import Text.Parsec.Pos(SourcePos, newPos) import Text.Parsec.Pos(SourcePos, newPos)
import Text.Parsec.Error(ParseError, newErrorMessage, Message(Message, Expect)) import Text.Parsec.Error(ParseError, newErrorMessage, Message(Message, Expect))
import Text.Printf(printf) import Text.Printf(printf)
...@@ -98,6 +100,8 @@ feedback f = status where ...@@ -98,6 +100,8 @@ feedback f = status where
statusToMaybe (Active x _) = Just x statusToMaybe (Active x _) = Just x
statusToMaybe (Failed _) = Nothing statusToMaybe (Failed _) = Nothing
doAll statuses = Active [x | (Active x _) <- statuses] (concatMap statusErrors statuses)
------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------
-- Symbol lookup -- Symbol lookup
------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------
...@@ -150,30 +154,48 @@ builtinTypeMap = Map.fromList ...@@ -150,30 +154,48 @@ builtinTypeMap = Map.fromList
------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------
fromIntegerChecked :: Integral a => SourcePos -> Integer -> Status a fromIntegerChecked :: Integral a => String -> SourcePos -> Integer -> Status a
fromIntegerChecked pos x = result where fromIntegerChecked name pos x = result where
unchecked = fromInteger x unchecked = fromInteger x
result = if toInteger unchecked == x result = if toInteger unchecked == x
then succeed unchecked then succeed unchecked
else makeError pos "Integer out of range for type." else makeError pos (printf "Integer %d out of range for type %s." x name)
compileValue :: SourcePos -> TypeDesc -> FieldValue -> Status ValueDesc
compileValue _ (BuiltinType BuiltinVoid) VoidFieldValue = succeed VoidDesc compileValue _ (BuiltinType BuiltinVoid) VoidFieldValue = succeed VoidDesc
compileValue _ (BuiltinType BuiltinBool) (BoolFieldValue x) = succeed (BoolDesc x) compileValue _ (BuiltinType BuiltinBool) (BoolFieldValue x) = succeed (BoolDesc x)
compileValue pos (BuiltinType BuiltinInt8) (IntegerFieldValue x) = fmap Int8Desc (fromIntegerChecked pos x) compileValue pos (BuiltinType BuiltinInt8 ) (IntegerFieldValue x) = fmap Int8Desc (fromIntegerChecked "Int8" pos x)
compileValue pos (BuiltinType BuiltinInt16) (IntegerFieldValue x) = fmap Int16Desc (fromIntegerChecked pos x) compileValue pos (BuiltinType BuiltinInt16 ) (IntegerFieldValue x) = fmap Int16Desc (fromIntegerChecked "Int16" pos x)
compileValue pos (BuiltinType BuiltinInt32) (IntegerFieldValue x) = fmap Int32Desc (fromIntegerChecked pos x) compileValue pos (BuiltinType BuiltinInt32 ) (IntegerFieldValue x) = fmap Int32Desc (fromIntegerChecked "Int32" pos x)
compileValue pos (BuiltinType BuiltinInt64) (IntegerFieldValue x) = fmap Int64Desc (fromIntegerChecked pos x) compileValue pos (BuiltinType BuiltinInt64 ) (IntegerFieldValue x) = fmap Int64Desc (fromIntegerChecked "Int64" pos x)
compileValue pos (BuiltinType BuiltinUInt8) (IntegerFieldValue x) = fmap UInt8Desc (fromIntegerChecked pos x) compileValue pos (BuiltinType BuiltinUInt8 ) (IntegerFieldValue x) = fmap UInt8Desc (fromIntegerChecked "UInt8" pos x)
compileValue pos (BuiltinType BuiltinUInt16) (IntegerFieldValue x) = fmap UInt16Desc (fromIntegerChecked pos x) compileValue pos (BuiltinType BuiltinUInt16) (IntegerFieldValue x) = fmap UInt16Desc (fromIntegerChecked "UInt16" pos x)
compileValue pos (BuiltinType BuiltinUInt32) (IntegerFieldValue x) = fmap UInt32Desc (fromIntegerChecked pos x) compileValue pos (BuiltinType BuiltinUInt32) (IntegerFieldValue x) = fmap UInt32Desc (fromIntegerChecked "UInt32" pos x)
compileValue pos (BuiltinType BuiltinUInt64) (IntegerFieldValue x) = fmap UInt64Desc (fromIntegerChecked pos x) compileValue pos (BuiltinType BuiltinUInt64) (IntegerFieldValue x) = fmap UInt64Desc (fromIntegerChecked "UInt64" pos x)
compileValue _ (BuiltinType BuiltinFloat32) (FloatFieldValue x) = succeed (Float32Desc (realToFrac x)) compileValue _ (BuiltinType BuiltinFloat32) (FloatFieldValue x) = succeed (Float32Desc (realToFrac x))
compileValue _ (BuiltinType BuiltinFloat64) (FloatFieldValue x) = succeed (Float64Desc x) compileValue _ (BuiltinType BuiltinFloat64) (FloatFieldValue x) = succeed (Float64Desc x)
compileValue _ (BuiltinType BuiltinFloat32) (IntegerFieldValue x) = succeed (Float32Desc (realToFrac x)) compileValue _ (BuiltinType BuiltinFloat32) (IntegerFieldValue x) = succeed (Float32Desc (realToFrac x))
compileValue _ (BuiltinType BuiltinFloat64) (IntegerFieldValue x) = succeed (Float64Desc (realToFrac x)) compileValue _ (BuiltinType BuiltinFloat64) (IntegerFieldValue x) = succeed (Float64Desc (realToFrac x))
compileValue _ (BuiltinType BuiltinText) (StringFieldValue x) = succeed (TextDesc x) compileValue _ (BuiltinType BuiltinText) (StringFieldValue x) = succeed (TextDesc x)
compileValue _ (BuiltinType BuiltinBytes) (StringFieldValue x) = compileValue _ (BuiltinType BuiltinData) (StringFieldValue x) =
succeed (BytesDesc (map (fromIntegral . fromEnum) x)) succeed (DataDesc (map (fromIntegral . fromEnum) x))
compileValue pos (EnumType desc) (IdentifierFieldValue name) =
case lookupMember name (enumMemberMap desc) of
Just (DescEnumValue value) -> succeed (EnumValueValueDesc value)
_ -> makeError pos (printf "Enum type %s has no value %s." (enumName desc) name)
compileValue _ (StructType desc) (RecordFieldValue fields) = result where
result = fmap StructValueDesc (doAll (map compileFieldAssignment fields))
compileFieldAssignment :: (Located String, Located FieldValue) -> Status (FieldDesc, ValueDesc)
compileFieldAssignment (Located namePos name, Located valPos val) =
case lookupMember name (structMemberMap desc) of
Just (DescField field) ->
fmap (\x -> (field, x)) (compileValue valPos (fieldType field) val)
_ -> makeError namePos (printf "Struct %s has no field %s." (structName desc) name)
compileValue _ (ListType t) (ListFieldValue l) =
fmap ListDesc (doAll [ compileValue vpos t v | Located vpos v <- l ])
compileValue pos (BuiltinType BuiltinVoid) _ = makeError pos "Void fields cannot have values." compileValue pos (BuiltinType BuiltinVoid) _ = makeError pos "Void fields cannot have values."
compileValue pos (BuiltinType BuiltinBool) _ = makeExpectError pos "boolean" compileValue pos (BuiltinType BuiltinBool) _ = makeExpectError pos "boolean"
...@@ -188,12 +210,12 @@ compileValue pos (BuiltinType BuiltinUInt64) _ = makeExpectError pos "integer" ...@@ -188,12 +210,12 @@ compileValue pos (BuiltinType BuiltinUInt64) _ = makeExpectError pos "integer"
compileValue pos (BuiltinType BuiltinFloat32) _ = makeExpectError pos "number" compileValue pos (BuiltinType BuiltinFloat32) _ = makeExpectError pos "number"
compileValue pos (BuiltinType BuiltinFloat64) _ = makeExpectError pos "number" compileValue pos (BuiltinType BuiltinFloat64) _ = makeExpectError pos "number"
compileValue pos (BuiltinType BuiltinText) _ = makeExpectError pos "string" compileValue pos (BuiltinType BuiltinText) _ = makeExpectError pos "string"
compileValue pos (BuiltinType BuiltinBytes) _ = makeExpectError pos "string" compileValue pos (BuiltinType BuiltinData) _ = makeExpectError pos "string"
compileValue pos (EnumType _) _ = makeError pos "Unimplemented: enum default values" compileValue pos (EnumType _) _ = makeExpectError pos "enum value name"
compileValue pos (StructType _) _ = makeError pos "Unimplemented: struct default values" compileValue pos (StructType _) _ = makeExpectError pos "parenthesized list of field assignments"
compileValue pos (InterfaceType _) _ = makeError pos "Interfaces can't have default values." compileValue pos (InterfaceType _) _ = makeError pos "Interfaces can't have default values."
compileValue pos (ListType _) _ = makeError pos "Unimplemented: array default values" compileValue pos (ListType _) _ = makeExpectError pos "list"
makeFileMemberMap :: FileDesc -> Map.Map String Desc makeFileMemberMap :: FileDesc -> Map.Map String Desc
makeFileMemberMap desc = Map.fromList allMembers where makeFileMemberMap desc = Map.fromList allMembers where
...@@ -226,6 +248,47 @@ compileType scope (TypeExpression n (param:moreParams)) = do ...@@ -226,6 +248,47 @@ compileType scope (TypeExpression n (param:moreParams)) = do
else makeError (declNamePos n) "'List' requires exactly one type parameter." else makeError (declNamePos n) "'List' requires exactly one type parameter."
_ -> makeError (declNamePos n) "Only the type 'List' can have type parameters." _ -> makeError (declNamePos n) "Only the type 'List' can have type parameters."
------------------------------------------------------------------------------------------
requireSequentialNumbering :: String -> [Located Integer] -> Status ()
requireSequentialNumbering kind items = Active () (loop 0 sortedItems) where
sortedItems = List.sort items
loop _ [] = []
loop expected (Located pos num:rest) = result where
rest' = loop (num + 1) rest
result = if num == expected
then rest'
else err:rest' where
err = newErrorMessage (Message message) pos
message = printf "Skipped number %d. %s must be numbered sequentially starting \
\from zero." expected kind
maxFieldNumber = 1023
requireFieldNumbersInRange fieldNums =
Active () [ fieldNumError num pos | Located pos num <- fieldNums, num > maxFieldNumber ] where
fieldNumError num = newErrorMessage (Message
(printf "Field number %d too large; maximum is %d." num maxFieldNumber))
requireNoDuplicateNames :: [Declaration] -> Status()
requireNoDuplicateNames decls = Active () (loop (List.sort locatedNames)) where
locatedNames = mapMaybe declarationName decls
loop (Located pos1 val1:Located pos2 val2:t) =
if val1 == val2
then dupError val1 pos1:dupError val2 pos2:loop2 val1 t
else loop t
loop _ = []
loop2 val1 l@(Located pos2 val2:t) =
if val1 == val2
then dupError val2 pos2:loop2 val1 t
else loop l
loop2 _ _ = []
dupError val = newErrorMessage (Message message) where
message = printf "Duplicate declaration \"%s\"." val
------------------------------------------------------------------------------------------
data CompiledDecl = CompiledMember String (Status Desc) data CompiledDecl = CompiledMember String (Status Desc)
| CompiledOption (Status OptionAssignmentDesc) | CompiledOption (Status OptionAssignmentDesc)
...@@ -242,8 +305,6 @@ compileChildDecls desc decls = Active (members, memberMap, options) errors where ...@@ -242,8 +305,6 @@ compileChildDecls desc decls = Active (members, memberMap, options) errors where
| CompiledOption (Active o _) <- compiledDecls] | CompiledOption (Active o _) <- compiledDecls]
errors = concatMap compiledErrors compiledDecls errors = concatMap compiledErrors compiledDecls
doAll statuses = Active [x | (Active x _) <- statuses] (concatMap statusErrors statuses)
compileDecl scope (AliasDecl (Located _ name) target) = compileDecl scope (AliasDecl (Located _ name) target) =
CompiledMember name (do CompiledMember name (do
targetDesc <- lookupDesc scope target targetDesc <- lookupDesc scope target
...@@ -267,6 +328,8 @@ compileDecl scope (ConstantDecl (Located _ name) t (Located valuePos value)) = ...@@ -267,6 +328,8 @@ compileDecl scope (ConstantDecl (Located _ name) t (Located valuePos value)) =
compileDecl scope (EnumDecl (Located _ name) decls) = compileDecl scope (EnumDecl (Located _ name) decls) =
CompiledMember name (feedback (\desc -> do CompiledMember name (feedback (\desc -> do
(members, memberMap, options) <- compileChildDecls desc decls (members, memberMap, options) <- compileChildDecls desc decls
requireNoDuplicateNames decls
requireSequentialNumbering "Enum values" [ num | EnumValueDecl _ num _ <- decls ]
return (DescEnum EnumDesc return (DescEnum EnumDesc
{ enumName = name { enumName = name
, enumParent = scope , enumParent = scope
...@@ -289,6 +352,10 @@ compileDecl scope (EnumValueDecl (Located _ name) (Located _ number) decls) = ...@@ -289,6 +352,10 @@ compileDecl scope (EnumValueDecl (Located _ name) (Located _ number) decls) =
compileDecl scope (StructDecl (Located _ name) decls) = compileDecl scope (StructDecl (Located _ name) decls) =
CompiledMember name (feedback (\desc -> do CompiledMember name (feedback (\desc -> do
(members, memberMap, options) <- compileChildDecls desc decls (members, memberMap, options) <- compileChildDecls desc decls
requireNoDuplicateNames decls
fieldNums <- return [ num | FieldDecl _ num _ _ _ <- decls ]
requireSequentialNumbering "Fields" fieldNums
requireFieldNumbersInRange fieldNums
return (DescStruct StructDesc return (DescStruct StructDesc
{ structName = name { structName = name
, structParent = scope , structParent = scope
...@@ -322,6 +389,8 @@ compileDecl scope (FieldDecl (Located _ name) (Located _ number) typeExp default ...@@ -322,6 +389,8 @@ compileDecl scope (FieldDecl (Located _ name) (Located _ number) typeExp default
compileDecl scope (InterfaceDecl (Located _ name) decls) = compileDecl scope (InterfaceDecl (Located _ name) decls) =
CompiledMember name (feedback (\desc -> do CompiledMember name (feedback (\desc -> do
(members, memberMap, options) <- compileChildDecls desc decls (members, memberMap, options) <- compileChildDecls desc decls
requireNoDuplicateNames decls
requireSequentialNumbering "Methods" [ num | MethodDecl _ num _ _ _ <- decls ]
return (DescInterface InterfaceDesc return (DescInterface InterfaceDesc
{ interfaceName = name { interfaceName = name
, interfaceParent = scope , interfaceParent = scope
...@@ -372,6 +441,7 @@ compileParam scope (name, typeExp, defaultValue) = do ...@@ -372,6 +441,7 @@ compileParam scope (name, typeExp, defaultValue) = do
compileFile name decls = compileFile name decls =
feedback (\desc -> do feedback (\desc -> do
(members, memberMap, options) <- compileChildDecls (DescFile desc) decls (members, memberMap, options) <- compileChildDecls (DescFile desc) decls
requireNoDuplicateNames decls
return FileDesc return FileDesc
{ fileName = name { fileName = name
, fileImports = [] , fileImports = []
......
...@@ -39,8 +39,9 @@ data FieldValue = VoidFieldValue ...@@ -39,8 +39,9 @@ data FieldValue = VoidFieldValue
| IntegerFieldValue Integer | IntegerFieldValue Integer
| FloatFieldValue Double | FloatFieldValue Double
| StringFieldValue String | StringFieldValue String
| ArrayFieldValue [FieldValue] | IdentifierFieldValue String
| RecordFieldValue [(String, FieldValue)] | ListFieldValue [Located FieldValue]
| RecordFieldValue [(Located String, Located FieldValue)]
deriving (Show) deriving (Show)
data Declaration = AliasDecl (Located String) DeclName data Declaration = AliasDecl (Located String) DeclName
...@@ -56,3 +57,14 @@ data Declaration = AliasDecl (Located String) DeclName ...@@ -56,3 +57,14 @@ data Declaration = AliasDecl (Located String) DeclName
TypeExpression [Declaration] TypeExpression [Declaration]
| OptionDecl DeclName (Located FieldValue) | OptionDecl DeclName (Located FieldValue)
deriving (Show) deriving (Show)
declarationName :: Declaration -> Maybe (Located String)
declarationName (AliasDecl n _) = Just n
declarationName (ConstantDecl n _ _) = Just n
declarationName (EnumDecl n _) = Just n
declarationName (EnumValueDecl n _ _) = Just n
declarationName (StructDecl n _) = Just n
declarationName (FieldDecl n _ _ _ _) = Just n
declarationName (InterfaceDecl n _) = Just n
declarationName (MethodDecl n _ _ _ _) = Just n
declarationName (OptionDecl _ _) = Nothing
...@@ -86,6 +86,7 @@ token = keyword ...@@ -86,6 +86,7 @@ token = keyword
<|> liftM (const Colon) (symbol ":") <|> liftM (const Colon) (symbol ":")
<|> liftM (const Period) (symbol ".") <|> liftM (const Period) (symbol ".")
<|> liftM (const EqualsSign) (symbol "=") <|> liftM (const EqualsSign) (symbol "=")
<|> liftM (const MinusSign) (symbol "-")
<?> "token" <?> "token"
locatedToken = located token locatedToken = located token
......
...@@ -25,6 +25,10 @@ module Main ( main ) where ...@@ -25,6 +25,10 @@ module Main ( main ) where
import System.Environment import System.Environment
import Compiler import Compiler
import Util(delimit)
import Text.Parsec.Pos
import Text.Parsec.Error
import Text.Printf(printf)
main::IO() main::IO()
main = do main = do
...@@ -35,5 +39,22 @@ handleFile filename = do ...@@ -35,5 +39,22 @@ handleFile filename = do
text <- readFile filename text <- readFile filename
case parseAndCompileFile filename text of case parseAndCompileFile filename text of
Active desc [] -> print desc Active desc [] -> print desc
Active _ e -> mapM_ print e Active _ e -> mapM_ printError e
Failed e -> mapM_ print e Failed e -> mapM_ printError e
--printError e = mapM_ printMessage (errorMessages e) where
-- pos = errorPos e
-- f = sourceName pos
-- l = sourceLine pos
-- c = sourceColumn pos
-- printMessage :: Message -> IO ()
-- printMessage m = printf "%s:%d:%d: %s\n" f l c (messageString m)
printError e = printf "%s:%d:%d: %s\n" f l c m' where
pos = errorPos e
f = sourceName pos
l = sourceLine pos
c = sourceColumn pos
m = showErrorMessages "or" "Unknown parse error" "Expected" "Unexpected" "end of expression"
(errorMessages e)
m' = delimit "; " (lines m)
...@@ -25,12 +25,31 @@ module Parser (parseFile) where ...@@ -25,12 +25,31 @@ module Parser (parseFile) where
import Text.Parsec hiding (tokens) import Text.Parsec hiding (tokens)
import Token import Token
import Control.Monad (liftM)
import Grammar import Grammar
import Lexer (lexer) import Lexer (lexer)
import Control.Monad.Identity
tokenParser :: (Located Token -> Maybe a) -> Parsec [Located Token] u a tokenParser :: (Located Token -> Maybe a) -> Parsec [Located Token] u a
tokenParser = token (show . locatedValue) locatedPos tokenParser = token (tokenErrorString . locatedValue) locatedPos
tokenErrorString (Identifier s) = "identifier \"" ++ s ++ "\""
tokenErrorString (ParenthesizedList _) = "parenthesized list"
tokenErrorString (BracketedList _) = "bracketed list"
tokenErrorString (LiteralInt i) = "integer literal " ++ show i
tokenErrorString (LiteralFloat f) = "float literal " ++ show f
tokenErrorString (LiteralString s) = "string literal " ++ show s
tokenErrorString AtSign = "\"@\""
tokenErrorString Colon = "\":\""
tokenErrorString Period = "\".\""
tokenErrorString EqualsSign = "\"=\""
tokenErrorString MinusSign = "\"-\""
tokenErrorString ImportKeyword = "\"import\""
tokenErrorString UsingKeyword = "\"using\""
tokenErrorString ConstKeyword = "\"const\""
tokenErrorString EnumKeyword = "\"enum\""
tokenErrorString StructKeyword = "\"struct\""
tokenErrorString InterfaceKeyword = "\"interface\""
tokenErrorString OptionKeyword = "\"option\""
type TokenParser = Parsec [Located Token] [ParseError] type TokenParser = Parsec [Located Token] [ParseError]
...@@ -49,22 +68,23 @@ matchLiteralFloat t = case locatedValue t of { (LiteralFloat v) -> Jus ...@@ -49,22 +68,23 @@ matchLiteralFloat t = case locatedValue t of { (LiteralFloat v) -> Jus
matchLiteralString t = case locatedValue t of { (LiteralString v) -> Just v; _ -> Nothing } matchLiteralString t = case locatedValue t of { (LiteralString v) -> Just v; _ -> Nothing }
matchSimpleToken expected t = if locatedValue t == expected then Just () else Nothing matchSimpleToken expected t = if locatedValue t == expected then Just () else Nothing
identifier = tokenParser matchIdentifier identifier = tokenParser matchIdentifier <?> "identifier"
literalInt = tokenParser matchLiteralInt literalInt = tokenParser matchLiteralInt <?> "integer"
literalFloat = tokenParser matchLiteralFloat literalFloat = tokenParser matchLiteralFloat <?> "floating-point number"
literalString = tokenParser matchLiteralString literalString = tokenParser matchLiteralString <?> "string"
atSign = tokenParser (matchSimpleToken AtSign) atSign = tokenParser (matchSimpleToken AtSign) <?> "\"@\""
colon = tokenParser (matchSimpleToken Colon) colon = tokenParser (matchSimpleToken Colon) <?> "\":\""
period = tokenParser (matchSimpleToken Period) period = tokenParser (matchSimpleToken Period) <?> "\".\""
equalsSign = tokenParser (matchSimpleToken EqualsSign) equalsSign = tokenParser (matchSimpleToken EqualsSign) <?> "\"=\""
importKeyword = tokenParser (matchSimpleToken ImportKeyword) minusSign = tokenParser (matchSimpleToken MinusSign) <?> "\"=\""
usingKeyword = tokenParser (matchSimpleToken UsingKeyword) importKeyword = tokenParser (matchSimpleToken ImportKeyword) <?> "\"import\""
constKeyword = tokenParser (matchSimpleToken ConstKeyword) usingKeyword = tokenParser (matchSimpleToken UsingKeyword) <?> "\"using\""
enumKeyword = tokenParser (matchSimpleToken EnumKeyword) constKeyword = tokenParser (matchSimpleToken ConstKeyword) <?> "\"const\""
structKeyword = tokenParser (matchSimpleToken StructKeyword) enumKeyword = tokenParser (matchSimpleToken EnumKeyword) <?> "\"enum\""
interfaceKeyword = tokenParser (matchSimpleToken InterfaceKeyword) structKeyword = tokenParser (matchSimpleToken StructKeyword) <?> "\"struct\""
optionKeyword = tokenParser (matchSimpleToken OptionKeyword) interfaceKeyword = tokenParser (matchSimpleToken InterfaceKeyword) <?> "\"interface\""
optionKeyword = tokenParser (matchSimpleToken OptionKeyword) <?> "\"option\""
parenthesizedList parser = do parenthesizedList parser = do
items <- tokenParser matchParenthesizedList items <- tokenParser matchParenthesizedList
...@@ -155,16 +175,22 @@ fieldDecl statements = do ...@@ -155,16 +175,22 @@ fieldDecl statements = do
children <- parseBlock fieldLine statements children <- parseBlock fieldLine statements
return (FieldDecl name ordinal t value children) return (FieldDecl name ordinal t value children)
negativeFieldValue = liftM (IntegerFieldValue . negate) literalInt
<|> liftM (FloatFieldValue . negate) literalFloat
fieldValue = liftM IntegerFieldValue literalInt fieldValue = liftM IntegerFieldValue literalInt
<|> liftM FloatFieldValue literalFloat <|> liftM FloatFieldValue literalFloat
<|> liftM StringFieldValue literalString <|> liftM StringFieldValue literalString
<|> liftM ArrayFieldValue (bracketedList fieldValue) <|> liftM IdentifierFieldValue identifier
<|> liftM ListFieldValue (bracketedList (located fieldValue))
<|> liftM RecordFieldValue (parenthesizedList fieldAssignment) <|> liftM RecordFieldValue (parenthesizedList fieldAssignment)
<|> (minusSign >> negativeFieldValue)
<?> "default value"
fieldAssignment = do fieldAssignment = do
name <- identifier name <- located identifier
equalsSign equalsSign
value <- fieldValue value <- located fieldValue
return (name, value) return (name, value)
fieldLine :: Maybe [Located Statement] -> TokenParser Declaration fieldLine :: Maybe [Located Statement] -> TokenParser Declaration
...@@ -186,6 +212,7 @@ methodDecl statements = do ...@@ -186,6 +212,7 @@ methodDecl statements = do
atSign atSign
ordinal <- located literalInt ordinal <- located literalInt
params <- parenthesizedList paramDecl params <- parenthesizedList paramDecl
colon
t <- typeExpression t <- typeExpression
children <- parseBlock methodLine statements children <- parseBlock methodLine statements
return (MethodDecl name ordinal params t children) return (MethodDecl name ordinal params t children)
...@@ -227,8 +254,16 @@ parseBlock parser statements = finish where ...@@ -227,8 +254,16 @@ parseBlock parser statements = finish where
return [ result | Right (result, _) <- results ] return [ result | Right (result, _) <- results ]
parseCollectingErrors :: TokenParser a -> [Located Token] -> Either ParseError (a, [ParseError]) parseCollectingErrors :: TokenParser a -> [Located Token] -> Either ParseError (a, [ParseError])
parseCollectingErrors parser = runParser parser' [] "" where parseCollectingErrors parser tokens = runParser parser' [] "" tokens where
parser' = do parser' = do
-- Work around Parsec bug: Text.Parsec.Print.token is supposed to produce a parser that
-- sets the position by using the provided function to extract it from each token. However,
-- it doesn't bother to call this function for the *first* token, only subsequent tokens.
-- The first token is always assumed to be at 1:1. To fix this, set it manually.
case tokens of
Located pos _:_ -> setPosition pos
[] -> return ()
result <- parser result <- parser
eof eof
errors <- getState errors <- getState
......
...@@ -30,6 +30,7 @@ import Data.Word (Word8, Word16, Word32, Word64) ...@@ -30,6 +30,7 @@ import Data.Word (Word8, Word16, Word32, Word64)
import Data.Char (chr) import Data.Char (chr)
import Text.Printf(printf) import Text.Printf(printf)
import Control.Monad(join) import Control.Monad(join)
import Util(delimit)
type ByteString = [Word8] type ByteString = [Word8]
...@@ -81,7 +82,7 @@ data BuiltinType = BuiltinVoid | BuiltinBool ...@@ -81,7 +82,7 @@ data BuiltinType = BuiltinVoid | BuiltinBool
| BuiltinInt8 | BuiltinInt16 | BuiltinInt32 | BuiltinInt64 | BuiltinInt8 | BuiltinInt16 | BuiltinInt32 | BuiltinInt64
| BuiltinUInt8 | BuiltinUInt16 | BuiltinUInt32 | BuiltinUInt64 | BuiltinUInt8 | BuiltinUInt16 | BuiltinUInt32 | BuiltinUInt64
| BuiltinFloat32 | BuiltinFloat64 | BuiltinFloat32 | BuiltinFloat64
| BuiltinText | BuiltinBytes | BuiltinText | BuiltinData
deriving (Show, Enum, Bounded, Eq) deriving (Show, Enum, Bounded, Eq)
builtinTypes = [minBound::BuiltinType .. maxBound::BuiltinType] builtinTypes = [minBound::BuiltinType .. maxBound::BuiltinType]
...@@ -103,7 +104,10 @@ data ValueDesc = VoidDesc ...@@ -103,7 +104,10 @@ data ValueDesc = VoidDesc
| Float32Desc Float | Float32Desc Float
| Float64Desc Double | Float64Desc Double
| TextDesc String | TextDesc String
| BytesDesc ByteString | DataDesc ByteString
| EnumValueValueDesc EnumValueDesc
| StructValueDesc [(FieldDesc, ValueDesc)]
| ListDesc [ValueDesc]
deriving (Show) deriving (Show)
valueString VoidDesc = error "Can't stringify void value." valueString VoidDesc = error "Can't stringify void value."
...@@ -119,7 +123,11 @@ valueString (UInt64Desc i) = show i ...@@ -119,7 +123,11 @@ valueString (UInt64Desc i) = show i
valueString (Float32Desc x) = show x valueString (Float32Desc x) = show x
valueString (Float64Desc x) = show x valueString (Float64Desc x) = show x
valueString (TextDesc s) = show s valueString (TextDesc s) = show s
valueString (BytesDesc s) = show (map (chr . fromIntegral) s) valueString (DataDesc s) = show (map (chr . fromIntegral) s)
valueString (EnumValueValueDesc v) = enumValueName v
valueString (StructValueDesc l) = "(" ++ delimit ", " (map assignmentString l) ++ ")" where
assignmentString (field, value) = fieldName field ++ " = " ++ valueString value
valueString (ListDesc l) = "[" ++ delimit ", " (map valueString l) ++ "]" where
data TypeDesc = BuiltinType BuiltinType data TypeDesc = BuiltinType BuiltinType
| EnumType EnumDesc | EnumType EnumDesc
......
...@@ -26,11 +26,17 @@ module Token where ...@@ -26,11 +26,17 @@ module Token where
import Text.Parsec.Pos (SourcePos, sourceLine, sourceColumn) import Text.Parsec.Pos (SourcePos, sourceLine, sourceColumn)
import Text.Printf (printf) import Text.Printf (printf)
data Located t = Located { locatedPos :: SourcePos, locatedValue :: t } deriving (Eq) data Located t = Located { locatedPos :: SourcePos, locatedValue :: t }
instance Show t => Show (Located t) where instance Show t => Show (Located t) where
show (Located pos x) = printf "%d:%d:%s" (sourceLine pos) (sourceColumn pos) (show x) show (Located pos x) = printf "%d:%d:%s" (sourceLine pos) (sourceColumn pos) (show x)
instance Eq a => Eq (Located a) where
Located _ a == Located _ b = a == b
instance Ord a => Ord (Located a) where
compare (Located _ a) (Located _ b) = compare a b
data Token = Identifier String data Token = Identifier String
| ParenthesizedList [[Located Token]] | ParenthesizedList [[Located Token]]
| BracketedList [[Located Token]] | BracketedList [[Located Token]]
...@@ -41,6 +47,7 @@ data Token = Identifier String ...@@ -41,6 +47,7 @@ data Token = Identifier String
| Colon | Colon
| Period | Period
| EqualsSign | EqualsSign
| MinusSign
| ImportKeyword | ImportKeyword
| UsingKeyword | UsingKeyword
| ConstKeyword | ConstKeyword
......
-- Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
-- All rights reserved.
--
-- Redistribution and use in source and binary forms, with or without
-- modification, are permitted provided that the following conditions are met:
--
-- 1. Redistributions of source code must retain the above copyright notice, this
-- list of conditions and the following disclaimer.
-- 2. Redistributions in binary form must reproduce the above copyright notice,
-- this list of conditions and the following disclaimer in the documentation
-- and/or other materials provided with the distribution.
--
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
-- ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
module Util where
delimit delimiter list = concat $ loop list where
loop ("":t) = loop t
loop (a:"":t) = loop (a:t)
loop (a:b:t) = a:delimiter:loop (b:t)
loop a = a
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment