Commit d3e5540c authored by Kenton Varda's avatar Kenton Varda

Fix bugs in annotations, implement ability to set C++ namespace via annotations.

parent 4d121574
...@@ -84,10 +84,13 @@ libcapnproto_a_SOURCES= \ ...@@ -84,10 +84,13 @@ libcapnproto_a_SOURCES= \
# Tests ============================================================== # Tests ==============================================================
capnpc_inputs = \ capnpc_inputs = \
src/capnproto/c++.capnp \
src/capnproto/test.capnp \ src/capnproto/test.capnp \
src/capnproto/test-import.capnp src/capnproto/test-import.capnp
capnpc_outputs = \ capnpc_outputs = \
src/capnproto/c++.capnp.c++ \
src/capnproto/c++.capnp.h \
src/capnproto/test.capnp.c++ \ src/capnproto/test.capnp.c++ \
src/capnproto/test.capnp.h \ src/capnproto/test.capnp.h \
src/capnproto/test-import.capnp.c++ \ src/capnproto/test-import.capnp.c++ \
......
# 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.
$id("v3JF2GP4Supe9JSSJ3pnSdUqhJI");
$namespace("capnproto::annotations");
annotation namespace: Text on(file);
...@@ -48,17 +48,26 @@ inline std::ostream& operator<<(std::ostream& os, Void) { ...@@ -48,17 +48,26 @@ inline std::ostream& operator<<(std::ostream& os, Void) {
namespace internal { namespace internal {
void initTestMessage(TestAllTypes::Builder builder); // Explicitly import each of these to make sure they're really located in capnproto::test and not,
void initTestMessage(TestDefaults::Builder builder); // say, the global namespace.
using ::capnproto::test::TestAllTypes;
using ::capnproto::test::TestDefaults;
using ::capnproto::test::TestEnum;
using ::capnproto::test::TestUnion;
using ::capnproto::test::TestUnionDefaults;
using ::capnproto::test::TestNestedTypes;
void checkTestMessage(TestAllTypes::Builder builder); void initTestMessage(test::TestAllTypes::Builder builder);
void checkTestMessage(TestDefaults::Builder builder); void initTestMessage(test::TestDefaults::Builder builder);
void checkTestMessage(TestAllTypes::Reader reader); void checkTestMessage(test::TestAllTypes::Builder builder);
void checkTestMessage(TestDefaults::Reader reader); void checkTestMessage(test::TestDefaults::Builder builder);
void checkTestMessageAllZero(TestAllTypes::Builder builder); void checkTestMessage(test::TestAllTypes::Reader reader);
void checkTestMessageAllZero(TestAllTypes::Reader reader); void checkTestMessage(test::TestDefaults::Reader reader);
void checkTestMessageAllZero(test::TestAllTypes::Builder builder);
void checkTestMessageAllZero(test::TestAllTypes::Reader reader);
} // namespace internal } // namespace internal
} // namespace capnproto } // namespace capnproto
......
...@@ -21,6 +21,10 @@ ...@@ -21,6 +21,10 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using Cxx = import "c++.capnp";
$Cxx.namespace("capnproto::test");
enum TestEnum { enum TestEnum {
foo @0; foo @0;
bar @1; bar @1;
......
...@@ -25,14 +25,14 @@ module Compiler where ...@@ -25,14 +25,14 @@ module Compiler where
import Grammar import Grammar
import Semantics import Semantics
import Token(Located(Located)) import Token(Located(Located), locatedPos, locatedValue)
import Parser(parseFile) import Parser(parseFile)
import Control.Monad(unless) import Control.Monad(unless)
import qualified Data.Map as Map import qualified Data.Map as Map
import Data.Map((!)) import Data.Map((!))
import qualified Data.Set as Set import qualified Data.Set as Set
import qualified Data.List as List import qualified Data.List as List
import Data.Maybe(mapMaybe, fromMaybe) import Data.Maybe(mapMaybe, fromMaybe, listToMaybe, catMaybes)
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)
...@@ -154,27 +154,7 @@ lookupDesc scope name = lookupDesc (descParent scope) name ...@@ -154,27 +154,7 @@ lookupDesc scope name = lookupDesc (descParent scope) name
builtinTypeMap :: Map.Map String Desc builtinTypeMap :: Map.Map String Desc
builtinTypeMap = Map.fromList builtinTypeMap = Map.fromList
([(builtinTypeName t, DescBuiltinType t) | t <- builtinTypes] ++ ([(builtinTypeName t, DescBuiltinType t) | t <- builtinTypes] ++
[("List", DescBuiltinList), ("id", DescAnnotation builtinId)]) [("List", DescBuiltinList), ("id", DescBuiltinId)])
builtinId = AnnotationDesc
{ annotationName = "id"
, annotationParent = DescFile FileDesc
{ fileName = "capnproto-builtins.capnp"
, fileImports = []
, fileAliases = []
, fileConstants = []
, fileEnums = []
, fileStructs = []
, fileInterfaces = []
, fileAnnotations = Map.empty
, fileMemberMap = Map.fromList [("id", Just $ DescAnnotation builtinId)]
, fileImportMap = Map.empty
, fileStatements = [DescAnnotation builtinId]
}
, annotationType = BuiltinType BuiltinText
, annotationAnnotations = Map.fromList [(idId, (builtinId, TextDesc idId))]
, annotationTargets = Set.fromList [minBound::AnnotationTarget .. maxBound::AnnotationTarget]
}
------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------
...@@ -304,30 +284,57 @@ compileType scope (TypeExpression n (param:moreParams)) = do ...@@ -304,30 +284,57 @@ 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."
compileAnnotation :: Desc -> AnnotationTarget -> Annotation -> Status (AnnotationDesc, ValueDesc) compileAnnotation :: Desc -> AnnotationTarget -> Annotation
-> Status (Maybe AnnotationDesc, ValueDesc)
compileAnnotation scope kind (Annotation name (Located pos value)) = do compileAnnotation scope kind (Annotation name (Located pos value)) = do
nameDesc <- lookupDesc scope name nameDesc <- lookupDesc scope name
annDesc <- case nameDesc of case nameDesc of
DescAnnotation a -> return a DescBuiltinId -> do
_ -> makeError (declNamePos name) compiledValue <- compileValue pos (BuiltinType BuiltinText) value
$ printf "'%s' is not an annotation." (declNameString name) return (Nothing, compiledValue)
DescAnnotation annDesc -> do
unless (Set.member kind (annotationTargets annDesc)) unless (Set.member kind (annotationTargets annDesc))
(makeError (declNamePos name) (makeError (declNamePos name)
$ printf "'%s' cannot be used on %s." (declNameString name) (show kind)) $ printf "'%s' cannot be used on %s." (declNameString name) (show kind))
compiledValue <- compileValue pos (annotationType annDesc) value compiledValue <- compileValue pos (annotationType annDesc) value
return (annDesc, compiledValue) return (Just annDesc, compiledValue)
_ -> makeError (declNamePos name)
$ printf "'%s' is not an annotation." (declNameString name)
compileAnnotationMap :: Desc -> AnnotationTarget -> [Annotation] -> Status AnnotationMap compileAnnotations :: Desc -> AnnotationTarget -> [Annotation]
compileAnnotationMap scope kind annotations = do -> Status (Maybe String, AnnotationMap) -- (id, other annotations)
compiled <- doAll $ map (compileAnnotation scope kind) annotations compileAnnotations scope kind annotations = do
let compileLocated ann@(Annotation name _) =
fmap (Located $ declNamePos name) $ compileAnnotation scope kind ann
-- Makes a map entry for the annotation keyed by ID. Throws out annotations with no ID. compiled <- doAll $ map compileLocated annotations
let makeMapEntry ann@(desc, _) =
case Map.lookup idId $ annotationAnnotations desc of
Just (_, TextDesc globalId) -> Just (globalId, ann)
_ -> Nothing
return $ Map.fromList $ mapMaybe makeMapEntry compiled -- Makes a map entry for the annotation keyed by ID. Throws out annotations with no ID.
let ids = [ Located pos i | Located pos (Nothing, TextDesc i) <- compiled ]
theId = fmap locatedValue $ listToMaybe ids
dupIds = map (flip makeError "Duplicate annotation 'id'." . locatedPos) $ List.drop 1 ids
-- For the annotations other than "id", we want to build a map keyed by annotation ID.
-- We drop any annotation that doesn't have an ID.
locatedEntries = catMaybes
[ annotationById pos (desc, v) | Located pos (Just desc, v) <- compiled ]
annotationById pos ann@(desc, _) =
case descAutoId (DescAnnotation desc) of
Just globalId -> Just (Located pos (globalId, ann))
Nothing -> Nothing
-- TODO(cleanup): Generalize duplicate detection.
sortedLocatedEntries = detectDup $ List.sortBy compareIds locatedEntries
compareIds (Located _ (a, _)) (Located _ (b, _)) = compare a b
detectDup (Located _ x@(id1, _):Located pos (id2, _):rest)
| id1 == id2 = succeed x:makeError pos "Duplicate annotation.":detectDup rest
detectDup (Located _ x:rest) = succeed x:detectDup rest
detectDup [] = []
finalEntries <- doAll sortedLocatedEntries
_ <- doAll dupIds
return (theId, Map.fromList finalEntries)
------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------
...@@ -559,9 +566,10 @@ compileDecl scope (ConstantDecl (Located _ name) t annotations (Located valuePos ...@@ -559,9 +566,10 @@ compileDecl scope (ConstantDecl (Located _ name) t annotations (Located valuePos
CompiledStatementStatus name (do CompiledStatementStatus name (do
typeDesc <- compileType scope t typeDesc <- compileType scope t
valueDesc <- compileValue valuePos typeDesc value valueDesc <- compileValue valuePos typeDesc value
compiledAnnotations <- compileAnnotationMap scope ConstantAnnotation annotations (theId, compiledAnnotations) <- compileAnnotations scope ConstantAnnotation annotations
return (DescConstant ConstantDesc return (DescConstant ConstantDesc
{ constantName = name { constantName = name
, constantId = theId
, constantParent = scope , constantParent = scope
, constantType = typeDesc , constantType = typeDesc
, constantValue = valueDesc , constantValue = valueDesc
...@@ -575,9 +583,10 @@ compileDecl scope (EnumDecl (Located _ name) annotations decls) = ...@@ -575,9 +583,10 @@ compileDecl scope (EnumDecl (Located _ name) annotations decls) =
let numbers = [ num | EnumValueDecl _ num _ <- decls ] let numbers = [ num | EnumValueDecl _ num _ <- decls ]
requireSequentialNumbering "Enum values" numbers requireSequentialNumbering "Enum values" numbers
requireOrdinalsInRange numbers requireOrdinalsInRange numbers
compiledAnnotations <- compileAnnotationMap scope EnumAnnotation annotations (theId, compiledAnnotations) <- compileAnnotations scope EnumAnnotation annotations
return (DescEnum EnumDesc return (DescEnum EnumDesc
{ enumName = name { enumName = name
, enumId = theId
, enumParent = scope , enumParent = scope
, enumValues = [d | DescEnumValue d <- members] , enumValues = [d | DescEnumValue d <- members]
, enumAnnotations = compiledAnnotations , enumAnnotations = compiledAnnotations
...@@ -588,9 +597,10 @@ compileDecl scope (EnumDecl (Located _ name) annotations decls) = ...@@ -588,9 +597,10 @@ compileDecl scope (EnumDecl (Located _ name) annotations decls) =
compileDecl scope@(DescEnum parent) compileDecl scope@(DescEnum parent)
(EnumValueDecl (Located _ name) (Located _ number) annotations) = (EnumValueDecl (Located _ name) (Located _ number) annotations) =
CompiledStatementStatus name (do CompiledStatementStatus name (do
compiledAnnotations <- compileAnnotationMap scope EnumValueAnnotation annotations (theId, compiledAnnotations) <- compileAnnotations scope EnumValueAnnotation annotations
return (DescEnumValue EnumValueDesc return (DescEnumValue EnumValueDesc
{ enumValueName = name { enumValueName = name
, enumValueId = theId
, enumValueParent = parent , enumValueParent = parent
, enumValueNumber = number , enumValueNumber = number
, enumValueAnnotations = compiledAnnotations , enumValueAnnotations = compiledAnnotations
...@@ -605,13 +615,14 @@ compileDecl scope (StructDecl (Located _ name) annotations decls) = ...@@ -605,13 +615,14 @@ compileDecl scope (StructDecl (Located _ name) annotations decls) =
let fieldNums = extractFieldNumbers decls let fieldNums = extractFieldNumbers decls
requireSequentialNumbering "Fields" fieldNums requireSequentialNumbering "Fields" fieldNums
requireOrdinalsInRange fieldNums requireOrdinalsInRange fieldNums
compiledAnnotations <- compileAnnotationMap scope StructAnnotation annotations (theId, compiledAnnotations) <- compileAnnotations scope StructAnnotation annotations
return (let return (let
fields = [d | DescField d <- members] fields = [d | DescField d <- members]
unions = [d | DescUnion d <- members] unions = [d | DescUnion d <- members]
(packing, _, fieldPackingMap) = packFields fields unions (packing, _, fieldPackingMap) = packFields fields unions
in DescStruct StructDesc in DescStruct StructDesc
{ structName = name { structName = name
, structId = theId
, structParent = scope , structParent = scope
, structPacking = packing , structPacking = packing
, structFields = fields , structFields = fields
...@@ -635,11 +646,12 @@ compileDecl scope@(DescStruct parent) ...@@ -635,11 +646,12 @@ compileDecl scope@(DescStruct parent)
orderedFieldNumbers = List.sort $ map fieldNumber fields orderedFieldNumbers = List.sort $ map fieldNumber fields
discriminantMap = Map.fromList $ zip orderedFieldNumbers [0..] discriminantMap = Map.fromList $ zip orderedFieldNumbers [0..]
requireNoMoreThanOneFieldNumberLessThan name numPos number fields requireNoMoreThanOneFieldNumberLessThan name numPos number fields
compiledAnnotations <- compileAnnotationMap scope UnionAnnotation annotations (theId, compiledAnnotations) <- compileAnnotations scope UnionAnnotation annotations
return (let return (let
(tagOffset, tagPacking) = structFieldPackingMap parent ! number (tagOffset, tagPacking) = structFieldPackingMap parent ! number
in DescUnion UnionDesc in DescUnion UnionDesc
{ unionName = name { unionName = name
, unionId = theId
, unionParent = parent , unionParent = parent
, unionNumber = number , unionNumber = number
, unionTagOffset = tagOffset , unionTagOffset = tagOffset
...@@ -667,11 +679,12 @@ compileDecl scope ...@@ -667,11 +679,12 @@ compileDecl scope
defaultDesc <- case defaultValue of defaultDesc <- case defaultValue of
Just (Located defaultPos value) -> fmap Just (compileValue defaultPos typeDesc value) Just (Located defaultPos value) -> fmap Just (compileValue defaultPos typeDesc value)
Nothing -> return Nothing Nothing -> return Nothing
compiledAnnotations <- compileAnnotationMap scope FieldAnnotation annotations (theId, compiledAnnotations) <- compileAnnotations scope FieldAnnotation annotations
return (let return (let
(offset, packing) = structFieldPackingMap parent ! number (offset, packing) = structFieldPackingMap parent ! number
in DescField FieldDesc in DescField FieldDesc
{ fieldName = name { fieldName = name
, fieldId = theId
, fieldParent = parent , fieldParent = parent
, fieldNumber = number , fieldNumber = number
, fieldOffset = offset , fieldOffset = offset
...@@ -689,9 +702,10 @@ compileDecl scope (InterfaceDecl (Located _ name) annotations decls) = ...@@ -689,9 +702,10 @@ compileDecl scope (InterfaceDecl (Located _ name) annotations decls) =
let numbers = [ num | MethodDecl _ num _ _ _ <- decls ] let numbers = [ num | MethodDecl _ num _ _ _ <- decls ]
requireSequentialNumbering "Methods" numbers requireSequentialNumbering "Methods" numbers
requireOrdinalsInRange numbers requireOrdinalsInRange numbers
compiledAnnotations <- compileAnnotationMap scope InterfaceAnnotation annotations (theId, compiledAnnotations) <- compileAnnotations scope InterfaceAnnotation annotations
return (DescInterface InterfaceDesc return (DescInterface InterfaceDesc
{ interfaceName = name { interfaceName = name
, interfaceId = theId
, interfaceParent = scope , interfaceParent = scope
, interfaceMethods = [d | DescMethod d <- members] , interfaceMethods = [d | DescMethod d <- members]
, interfaceNestedAliases = [d | DescAlias d <- members] , interfaceNestedAliases = [d | DescAlias d <- members]
...@@ -709,9 +723,10 @@ compileDecl scope@(DescInterface parent) ...@@ -709,9 +723,10 @@ compileDecl scope@(DescInterface parent)
CompiledStatementStatus name (feedback (\desc -> do CompiledStatementStatus name (feedback (\desc -> do
paramDescs <- doAll (map (compileParam desc) (zip [0..] params)) paramDescs <- doAll (map (compileParam desc) (zip [0..] params))
returnTypeDesc <- compileType scope returnType returnTypeDesc <- compileType scope returnType
compiledAnnotations <- compileAnnotationMap scope MethodAnnotation annotations (theId, compiledAnnotations) <- compileAnnotations scope MethodAnnotation annotations
return (DescMethod MethodDesc return (DescMethod MethodDesc
{ methodName = name { methodName = name
, methodId = theId
, methodParent = parent , methodParent = parent
, methodNumber = number , methodNumber = number
, methodParams = paramDescs , methodParams = paramDescs
...@@ -724,9 +739,10 @@ compileDecl _ (MethodDecl (Located pos name) _ _ _ _) = ...@@ -724,9 +739,10 @@ compileDecl _ (MethodDecl (Located pos name) _ _ _ _) =
compileDecl scope (AnnotationDecl (Located _ name) typeExp annotations targets) = compileDecl scope (AnnotationDecl (Located _ name) typeExp annotations targets) =
CompiledStatementStatus name (do CompiledStatementStatus name (do
typeDesc <- compileType scope typeExp typeDesc <- compileType scope typeExp
compiledAnnotations <- compileAnnotationMap scope AnnotationAnnotation annotations (theId, compiledAnnotations) <- compileAnnotations scope AnnotationAnnotation annotations
return (DescAnnotation AnnotationDesc return (DescAnnotation AnnotationDesc
{ annotationName = name { annotationName = name
, annotationId = theId
, annotationParent = scope , annotationParent = scope
, annotationType = typeDesc , annotationType = typeDesc
, annotationAnnotations = compiledAnnotations , annotationAnnotations = compiledAnnotations
...@@ -739,9 +755,10 @@ compileParam scope@(DescMethod parent) ...@@ -739,9 +755,10 @@ compileParam scope@(DescMethod parent)
defaultDesc <- case defaultValue of defaultDesc <- case defaultValue of
Just (Located pos value) -> fmap Just (compileValue pos typeDesc value) Just (Located pos value) -> fmap Just (compileValue pos typeDesc value)
Nothing -> return Nothing Nothing -> return Nothing
compiledAnnotations <- compileAnnotationMap scope ParamAnnotation annotations (theId, compiledAnnotations) <- compileAnnotations scope ParamAnnotation annotations
return ParamDesc return ParamDesc
{ paramName = name { paramName = name
, paramId = theId
, paramParent = parent , paramParent = parent
, paramNumber = ordinal , paramNumber = ordinal
, paramType = typeDesc , paramType = typeDesc
...@@ -754,9 +771,11 @@ compileFile name decls annotations importMap = ...@@ -754,9 +771,11 @@ compileFile name decls annotations importMap =
feedback (\desc -> do feedback (\desc -> do
(members, memberMap) <- compileChildDecls (DescFile desc) decls (members, memberMap) <- compileChildDecls (DescFile desc) decls
requireNoDuplicateNames decls requireNoDuplicateNames decls
compiledAnnotations <- compileAnnotationMap (DescFile desc) FileAnnotation annotations (theId, compiledAnnotations)
<- compileAnnotations (DescFile desc) FileAnnotation annotations
return FileDesc return FileDesc
{ fileName = name { fileName = name
, fileId = theId
, fileImports = Map.elems importMap , fileImports = Map.elems importMap
, fileAliases = [d | DescAlias d <- members] , fileAliases = [d | DescAlias d <- members]
, fileConstants = [d | DescConstant d <- members] , fileConstants = [d | DescConstant d <- members]
...@@ -774,6 +793,7 @@ dedup = Set.toList . Set.fromList ...@@ -774,6 +793,7 @@ dedup = Set.toList . Set.fromList
emptyFileDesc filename = FileDesc emptyFileDesc filename = FileDesc
{ fileName = filename { fileName = filename
, fileId = Nothing
, fileImports = [] , fileImports = []
, fileAliases = [] , fileAliases = []
, fileConstants = [] , fileConstants = []
......
...@@ -30,7 +30,7 @@ import Data.FileEmbed(embedFile) ...@@ -30,7 +30,7 @@ import Data.FileEmbed(embedFile)
import Data.Word(Word8) import Data.Word(Word8)
import qualified Data.Digest.MD5 as MD5 import qualified Data.Digest.MD5 as MD5
import qualified Data.Map as Map import qualified Data.Map as Map
import Data.Maybe(catMaybes) import Data.Maybe(catMaybes, fromMaybe)
import Data.Binary.IEEE754(floatToWord, doubleToWord) import Data.Binary.IEEE754(floatToWord, doubleToWord)
import Text.Printf(printf) import Text.Printf(printf)
import Text.Hastache import Text.Hastache
...@@ -50,12 +50,20 @@ muNull = MuBool False; ...@@ -50,12 +50,20 @@ muNull = MuBool False;
-- Using a single-element list has the same effect, though. -- Using a single-element list has the same effect, though.
muJust c = MuList [c] muJust c = MuList [c]
namespaceAnnotationId = "v3JF2GP4Supe9JSSJ3pnSdUqhJI.namespace"
fileNamespace desc = fmap testAnnotation $ Map.lookup namespaceAnnotationId $ fileAnnotations desc
testAnnotation (_, TextDesc x) = x
testAnnotation (desc, _) =
error "Annotation was supposed to be text, but wasn't: " ++ annotationName desc
fullName desc = scopePrefix (descParent desc) ++ descName desc fullName desc = scopePrefix (descParent desc) ++ descName desc
scopePrefix (DescFile _) = "" scopePrefix (DescFile _) = ""
scopePrefix desc = fullName desc ++ "::" scopePrefix desc = fullName desc ++ "::"
globalName (DescFile _) = " " -- TODO: namespaces globalName (DescFile desc) = maybe " " (" ::" ++) $ fileNamespace desc
globalName desc = globalName (descParent desc) ++ "::" ++ descName desc globalName desc = globalName (descParent desc) ++ "::" ++ descName desc
-- Flatten the descriptor tree in pre-order, returning struct, union, and interface descriptors -- Flatten the descriptor tree in pre-order, returning struct, union, and interface descriptors
...@@ -303,14 +311,20 @@ importContext parent filename = mkStrContext context where ...@@ -303,14 +311,20 @@ importContext parent filename = mkStrContext context where
context "importIsSystem" = MuBool False context "importIsSystem" = MuBool False
context s = parent s context s = parent s
namespaceContext parent part = mkStrContext context where
context "namespaceName" = MuVariable part
context s = parent s
fileContext desc = mkStrContext context where fileContext desc = mkStrContext context where
flattenedMembers = flattenTypes $ catMaybes $ Map.elems $ fileMemberMap desc flattenedMembers = flattenTypes $ catMaybes $ Map.elems $ fileMemberMap desc
namespace = maybe [] (splitOn "::") $ fileNamespace desc
context "fileName" = MuVariable $ fileName desc context "fileName" = MuVariable $ fileName desc
context "fileBasename" = MuVariable $ takeBaseName $ fileName desc context "fileBasename" = MuVariable $ takeBaseName $ fileName desc
context "fileIncludeGuard" = MuVariable $ context "fileIncludeGuard" = MuVariable $
"CAPNPROTO_INCLUDED_" ++ hashString (fileName desc) "CAPNPROTO_INCLUDED_" ++ hashString (fileName desc ++ ':':fromMaybe "" (fileId desc))
context "fileNamespaces" = MuList [] -- TODO context "fileNamespaces" = MuList $ map (namespaceContext context) namespace
context "fileEnums" = MuList $ map (enumContext context) $ fileEnums desc context "fileEnums" = MuList $ map (enumContext context) $ fileEnums desc
context "fileTypes" = MuList $ map (typeContext context) flattenedMembers context "fileTypes" = MuList $ map (typeContext context) flattenedMembers
context "fileImports" = MuList $ map (importContext context) $ Map.keys $ fileImportMap desc context "fileImports" = MuList $ map (importContext context) $ Map.keys $ fileImportMap desc
......
...@@ -184,9 +184,9 @@ constantDecl = do ...@@ -184,9 +184,9 @@ constantDecl = do
name <- located varIdentifier name <- located varIdentifier
colon colon
typeName <- typeExpression typeName <- typeExpression
annotations <- many annotation
equalsSign equalsSign
value <- located fieldValue value <- located fieldValue
annotations <- many annotation
return (ConstantDecl name typeName annotations value) return (ConstantDecl name typeName annotations value)
typeDecl statements = enumDecl statements typeDecl statements = enumDecl statements
...@@ -235,8 +235,8 @@ fieldDecl = do ...@@ -235,8 +235,8 @@ fieldDecl = do
(name, ordinal) <- nameWithOrdinal (name, ordinal) <- nameWithOrdinal
colon colon
t <- typeExpression t <- typeExpression
annotations <- many annotation
value <- optionMaybe (equalsSign >> located fieldValue) value <- optionMaybe (equalsSign >> located fieldValue)
annotations <- many annotation
return (FieldDecl name ordinal t annotations value) return (FieldDecl name ordinal t annotations value)
negativeFieldValue = liftM (IntegerFieldValue . negate) literalInt negativeFieldValue = liftM (IntegerFieldValue . negate) literalInt
...@@ -288,8 +288,8 @@ paramDecl = do ...@@ -288,8 +288,8 @@ paramDecl = do
name <- varIdentifier name <- varIdentifier
colon colon
t <- typeExpression t <- typeExpression
annotations <- many annotation
value <- optionMaybe (equalsSign >> located fieldValue) value <- optionMaybe (equalsSign >> located fieldValue)
annotations <- many annotation
return (ParamDecl name t annotations value) return (ParamDecl name t annotations value)
annotationDecl = do annotationDecl = do
...@@ -297,10 +297,10 @@ annotationDecl = do ...@@ -297,10 +297,10 @@ annotationDecl = do
name <- located varIdentifier name <- located varIdentifier
colon colon
t <- typeExpression t <- typeExpression
annotations <- many annotation
onKeyword onKeyword
targets <- try (parenthesized asterisk >> return allAnnotationTargets) targets <- try (parenthesized asterisk >> return allAnnotationTargets)
<|> parenthesizedList annotationTarget <|> parenthesizedList annotationTarget
annotations <- many annotation
return (AnnotationDecl name t annotations targets) return (AnnotationDecl name t annotations targets)
allAnnotationTargets = [minBound::AnnotationTarget .. maxBound::AnnotationTarget] allAnnotationTargets = [minBound::AnnotationTarget .. maxBound::AnnotationTarget]
......
...@@ -39,8 +39,6 @@ import Grammar(AnnotationTarget(..)) ...@@ -39,8 +39,6 @@ import Grammar(AnnotationTarget(..))
-- ordinal is 65534. -- ordinal is 65534.
maxOrdinal = 65534 :: Integer maxOrdinal = 65534 :: Integer
idId = "com.capnproto.compiler.builtin.id"
type ByteString = [Word8] type ByteString = [Word8]
data Desc = DescFile FileDesc data Desc = DescFile FileDesc
...@@ -57,6 +55,7 @@ data Desc = DescFile FileDesc ...@@ -57,6 +55,7 @@ data Desc = DescFile FileDesc
| DescAnnotation AnnotationDesc | DescAnnotation AnnotationDesc
| DescBuiltinType BuiltinType | DescBuiltinType BuiltinType
| DescBuiltinList | DescBuiltinList
| DescBuiltinId
descName (DescFile _) = "(top-level)" descName (DescFile _) = "(top-level)"
descName (DescAlias d) = aliasName d descName (DescAlias d) = aliasName d
...@@ -72,6 +71,31 @@ descName (DescParam d) = paramName d ...@@ -72,6 +71,31 @@ descName (DescParam d) = paramName d
descName (DescAnnotation d) = annotationName d descName (DescAnnotation d) = annotationName d
descName (DescBuiltinType d) = builtinTypeName d descName (DescBuiltinType d) = builtinTypeName d
descName DescBuiltinList = "List" descName DescBuiltinList = "List"
descName DescBuiltinId = "id"
descId (DescFile d) = fileId d
descId (DescAlias _) = Nothing
descId (DescConstant d) = constantId d
descId (DescEnum d) = enumId d
descId (DescEnumValue d) = enumValueId d
descId (DescStruct d) = structId d
descId (DescUnion d) = unionId d
descId (DescField d) = fieldId d
descId (DescInterface d) = interfaceId d
descId (DescMethod d) = methodId d
descId (DescParam d) = paramId d
descId (DescAnnotation d) = annotationId d
descId (DescBuiltinType _) = Nothing
descId DescBuiltinList = Nothing
descId DescBuiltinId = Just "0U0T3e_SnatEfk6UcH2tcjTt1E0"
-- Gets the ID if explicitly defined, or generates it by appending ".name" to the parent's ID.
-- If no ancestor has an ID, still returns Nothing.
descAutoId d = case descId d of
Just i -> Just i
Nothing -> case d of
DescFile _ -> Nothing
_ -> fmap (++ '.':descName d) $ descAutoId $ descParent d
descParent (DescFile _) = error "File descriptor has no parent." descParent (DescFile _) = error "File descriptor has no parent."
descParent (DescAlias d) = aliasParent d descParent (DescAlias d) = aliasParent d
...@@ -87,6 +111,23 @@ descParent (DescParam d) = DescMethod (paramParent d) ...@@ -87,6 +111,23 @@ descParent (DescParam d) = DescMethod (paramParent d)
descParent (DescAnnotation d) = annotationParent d descParent (DescAnnotation d) = annotationParent d
descParent (DescBuiltinType _) = error "Builtin type has no parent." descParent (DescBuiltinType _) = error "Builtin type has no parent."
descParent DescBuiltinList = error "Builtin type has no parent." descParent DescBuiltinList = error "Builtin type has no parent."
descParent DescBuiltinId = error "Builtin annotation has no parent."
descAnnotations (DescFile d) = fileAnnotations d
descAnnotations (DescAlias _) = Map.empty
descAnnotations (DescConstant d) = constantAnnotations d
descAnnotations (DescEnum d) = enumAnnotations d
descAnnotations (DescEnumValue d) = enumValueAnnotations d
descAnnotations (DescStruct d) = structAnnotations d
descAnnotations (DescUnion d) = unionAnnotations d
descAnnotations (DescField d) = fieldAnnotations d
descAnnotations (DescInterface d) = interfaceAnnotations d
descAnnotations (DescMethod d) = methodAnnotations d
descAnnotations (DescParam d) = paramAnnotations d
descAnnotations (DescAnnotation d) = annotationAnnotations d
descAnnotations (DescBuiltinType _) = Map.empty
descAnnotations DescBuiltinList = Map.empty
descAnnotations DescBuiltinId = Map.empty
type MemberMap = Map.Map String (Maybe Desc) type MemberMap = Map.Map String (Maybe Desc)
...@@ -264,6 +305,7 @@ descQualifiedName scope desc = descQualifiedName (descParent scope) desc ...@@ -264,6 +305,7 @@ descQualifiedName scope desc = descQualifiedName (descParent scope) desc
data FileDesc = FileDesc data FileDesc = FileDesc
{ fileName :: String { fileName :: String
, fileId :: Maybe String
, fileImports :: [FileDesc] , fileImports :: [FileDesc]
, fileAliases :: [AliasDesc] , fileAliases :: [AliasDesc]
, fileConstants :: [ConstantDesc] , fileConstants :: [ConstantDesc]
...@@ -284,6 +326,7 @@ data AliasDesc = AliasDesc ...@@ -284,6 +326,7 @@ data AliasDesc = AliasDesc
data ConstantDesc = ConstantDesc data ConstantDesc = ConstantDesc
{ constantName :: String { constantName :: String
, constantId :: Maybe String
, constantParent :: Desc , constantParent :: Desc
, constantType :: TypeDesc , constantType :: TypeDesc
, constantAnnotations :: AnnotationMap , constantAnnotations :: AnnotationMap
...@@ -292,6 +335,7 @@ data ConstantDesc = ConstantDesc ...@@ -292,6 +335,7 @@ data ConstantDesc = ConstantDesc
data EnumDesc = EnumDesc data EnumDesc = EnumDesc
{ enumName :: String { enumName :: String
, enumId :: Maybe String
, enumParent :: Desc , enumParent :: Desc
, enumValues :: [EnumValueDesc] , enumValues :: [EnumValueDesc]
, enumAnnotations :: AnnotationMap , enumAnnotations :: AnnotationMap
...@@ -301,6 +345,7 @@ data EnumDesc = EnumDesc ...@@ -301,6 +345,7 @@ data EnumDesc = EnumDesc
data EnumValueDesc = EnumValueDesc data EnumValueDesc = EnumValueDesc
{ enumValueName :: String { enumValueName :: String
, enumValueId :: Maybe String
, enumValueParent :: EnumDesc , enumValueParent :: EnumDesc
, enumValueNumber :: Integer , enumValueNumber :: Integer
, enumValueAnnotations :: AnnotationMap , enumValueAnnotations :: AnnotationMap
...@@ -308,6 +353,7 @@ data EnumValueDesc = EnumValueDesc ...@@ -308,6 +353,7 @@ data EnumValueDesc = EnumValueDesc
data StructDesc = StructDesc data StructDesc = StructDesc
{ structName :: String { structName :: String
, structId :: Maybe String
, structParent :: Desc , structParent :: Desc
, structPacking :: PackingState , structPacking :: PackingState
, structFields :: [FieldDesc] , structFields :: [FieldDesc]
...@@ -329,6 +375,7 @@ data StructDesc = StructDesc ...@@ -329,6 +375,7 @@ data StructDesc = StructDesc
data UnionDesc = UnionDesc data UnionDesc = UnionDesc
{ unionName :: String { unionName :: String
, unionId :: Maybe String
, unionParent :: StructDesc , unionParent :: StructDesc
, unionNumber :: Integer , unionNumber :: Integer
, unionTagOffset :: Integer , unionTagOffset :: Integer
...@@ -344,6 +391,7 @@ data UnionDesc = UnionDesc ...@@ -344,6 +391,7 @@ data UnionDesc = UnionDesc
data FieldDesc = FieldDesc data FieldDesc = FieldDesc
{ fieldName :: String { fieldName :: String
, fieldId :: Maybe String
, fieldParent :: StructDesc , fieldParent :: StructDesc
, fieldNumber :: Integer , fieldNumber :: Integer
, fieldOffset :: Integer , fieldOffset :: Integer
...@@ -356,6 +404,7 @@ data FieldDesc = FieldDesc ...@@ -356,6 +404,7 @@ data FieldDesc = FieldDesc
data InterfaceDesc = InterfaceDesc data InterfaceDesc = InterfaceDesc
{ interfaceName :: String { interfaceName :: String
, interfaceId :: Maybe String
, interfaceParent :: Desc , interfaceParent :: Desc
, interfaceMethods :: [MethodDesc] , interfaceMethods :: [MethodDesc]
, interfaceNestedAliases :: [AliasDesc] , interfaceNestedAliases :: [AliasDesc]
...@@ -370,6 +419,7 @@ data InterfaceDesc = InterfaceDesc ...@@ -370,6 +419,7 @@ data InterfaceDesc = InterfaceDesc
data MethodDesc = MethodDesc data MethodDesc = MethodDesc
{ methodName :: String { methodName :: String
, methodId :: Maybe String
, methodParent :: InterfaceDesc , methodParent :: InterfaceDesc
, methodNumber :: Integer , methodNumber :: Integer
, methodParams :: [ParamDesc] , methodParams :: [ParamDesc]
...@@ -379,6 +429,7 @@ data MethodDesc = MethodDesc ...@@ -379,6 +429,7 @@ data MethodDesc = MethodDesc
data ParamDesc = ParamDesc data ParamDesc = ParamDesc
{ paramName :: String { paramName :: String
, paramId :: Maybe String
, paramParent :: MethodDesc , paramParent :: MethodDesc
, paramNumber :: Integer , paramNumber :: Integer
, paramType :: TypeDesc , paramType :: TypeDesc
...@@ -391,43 +442,47 @@ data AnnotationDesc = AnnotationDesc ...@@ -391,43 +442,47 @@ data AnnotationDesc = AnnotationDesc
, annotationParent :: Desc , annotationParent :: Desc
, annotationType :: TypeDesc , annotationType :: TypeDesc
, annotationAnnotations :: AnnotationMap , annotationAnnotations :: AnnotationMap
, annotationId :: Maybe String
, annotationTargets :: Set.Set AnnotationTarget , annotationTargets :: Set.Set AnnotationTarget
} }
type AnnotationMap = Map.Map String (AnnotationDesc, ValueDesc) type AnnotationMap = Map.Map String (AnnotationDesc, ValueDesc)
descToCode :: String -> Desc -> String descToCode :: String -> Desc -> String
descToCode indent self@(DescFile desc) = printf "# %s\n%s%s" descToCode indent self@(DescFile desc) = printf "# %s\n%s%s%s"
(fileName desc) (fileName desc)
(concatMap ((++ ";\n") . annotationCode (descParent self)) $ Map.toList $ fileAnnotations desc) (case fileId desc of
Just i -> printf "$id(%s);\n" $ show i
Nothing -> "")
(concatMap ((++ ";\n") . annotationCode self) $ Map.toList $ fileAnnotations desc)
(concatMap (descToCode indent) (fileStatements desc)) (concatMap (descToCode indent) (fileStatements desc))
descToCode indent (DescAlias desc) = printf "%susing %s = %s;\n" indent descToCode indent (DescAlias desc) = printf "%susing %s = %s;\n" indent
(aliasName desc) (aliasName desc)
(descQualifiedName (aliasParent desc) (aliasTarget desc)) (descQualifiedName (aliasParent desc) (aliasTarget desc))
descToCode indent self@(DescConstant desc) = printf "%sconst %s: %s%s = %s;\n" indent descToCode indent self@(DescConstant desc) = printf "%sconst %s: %s = %s%s;\n" indent
(constantName desc) (constantName desc)
(typeName (descParent self) (constantType desc)) (typeName (descParent self) (constantType desc))
(annotationsCode (descParent self) $ constantAnnotations desc)
(valueString (constantValue desc)) (valueString (constantValue desc))
(annotationsCode self)
descToCode indent self@(DescEnum desc) = printf "%senum %s%s {\n%s%s}\n" indent descToCode indent self@(DescEnum desc) = printf "%senum %s%s {\n%s%s}\n" indent
(enumName desc) (enumName desc)
(annotationsCode (descParent self) $ enumAnnotations desc) (annotationsCode self)
(blockCode indent (enumStatements desc)) (blockCode indent (enumStatements desc))
indent indent
descToCode indent self@(DescEnumValue desc) = printf "%s%s @%d%s;\n" indent descToCode indent self@(DescEnumValue desc) = printf "%s%s @%d%s;\n" indent
(enumValueName desc) (enumValueNumber desc) (enumValueName desc) (enumValueNumber desc)
(annotationsCode (descParent self) $ enumValueAnnotations desc) (annotationsCode self)
descToCode indent self@(DescStruct desc) = printf "%sstruct %s%s {\n%s%s}\n" indent descToCode indent self@(DescStruct desc) = printf "%sstruct %s%s {\n%s%s}\n" indent
(structName desc) (structName desc)
(annotationsCode (descParent self) $ structAnnotations desc) (annotationsCode self)
(blockCode indent (structStatements desc)) (blockCode indent (structStatements desc))
indent indent
descToCode indent self@(DescField desc) = printf "%s%s@%d%s: %s%s%s; # %s\n" indent descToCode indent self@(DescField desc) = printf "%s%s@%d%s: %s%s%s; # %s\n" indent
(fieldName desc) (fieldNumber desc) (fieldName desc) (fieldNumber desc)
(case fieldUnion desc of { Nothing -> ""; Just (u, _) -> " in " ++ unionName u}) (case fieldUnion desc of { Nothing -> ""; Just (u, _) -> " in " ++ unionName u})
(typeName (descParent self) (fieldType desc)) (typeName (descParent self) (fieldType desc))
(annotationsCode (descParent self) $ fieldAnnotations desc)
(case fieldDefaultValue desc of { Nothing -> ""; Just v -> " = " ++ valueString v; }) (case fieldDefaultValue desc of { Nothing -> ""; Just v -> " = " ++ valueString v; })
(annotationsCode self)
(case fieldSize $ fieldType desc of (case fieldSize $ fieldType desc of
SizeReference -> printf "ref[%d]" $ fieldOffset desc SizeReference -> printf "ref[%d]" $ fieldOffset desc
SizeInlineComposite _ _ -> "??" SizeInlineComposite _ _ -> "??"
...@@ -437,34 +492,35 @@ descToCode indent self@(DescField desc) = printf "%s%s@%d%s: %s%s%s; # %s\n" in ...@@ -437,34 +492,35 @@ descToCode indent self@(DescField desc) = printf "%s%s@%d%s: %s%s%s; # %s\n" in
in printf "bits[%d, %d)" (offset * bits) ((offset + 1) * bits)) in printf "bits[%d, %d)" (offset * bits) ((offset + 1) * bits))
descToCode indent self@(DescUnion desc) = printf "%sunion %s@%d%s { # [%d, %d)\n%s%s}\n" indent descToCode indent self@(DescUnion desc) = printf "%sunion %s@%d%s { # [%d, %d)\n%s%s}\n" indent
(unionName desc) (unionNumber desc) (unionName desc) (unionNumber desc)
(annotationsCode (descParent self) $ unionAnnotations desc) (annotationsCode self)
(unionTagOffset desc * 16) (unionTagOffset desc * 16 + 16) (unionTagOffset desc * 16) (unionTagOffset desc * 16 + 16)
(blockCode indent $ unionStatements desc) (blockCode indent $ unionStatements desc)
indent indent
descToCode indent self@(DescInterface desc) = printf "%sinterface %s%s {\n%s%s}\n" indent descToCode indent self@(DescInterface desc) = printf "%sinterface %s%s {\n%s%s}\n" indent
(interfaceName desc) (interfaceName desc)
(annotationsCode (descParent self) $ interfaceAnnotations desc) (annotationsCode self)
(blockCode indent (interfaceStatements desc)) (blockCode indent (interfaceStatements desc))
indent indent
descToCode indent self@(DescMethod desc) = printf "%s%s@%d(%s): %s%s" indent descToCode indent self@(DescMethod desc) = printf "%s%s@%d(%s): %s%s" indent
(methodName desc) (methodNumber desc) (methodName desc) (methodNumber desc)
(delimit ", " (map (descToCode indent . DescParam) (methodParams desc))) (delimit ", " (map (descToCode indent . DescParam) (methodParams desc)))
(typeName (descParent self) (methodReturnType desc)) (typeName (descParent self) (methodReturnType desc))
(annotationsCode (descParent self) $ methodAnnotations desc) (annotationsCode self)
descToCode _ self@(DescParam desc) = printf "%s: %s%s%s" descToCode _ self@(DescParam desc) = printf "%s: %s%s%s"
(paramName desc) (paramName desc)
(typeName (descParent self) (paramType desc)) (typeName (descParent self) (paramType desc))
(annotationsCode (descParent self) $ paramAnnotations desc)
(case paramDefaultValue desc of (case paramDefaultValue desc of
Just v -> printf " = %s" $ valueString v Just v -> printf " = %s" $ valueString v
Nothing -> "") Nothing -> "")
descToCode indent self@(DescAnnotation desc) = printf "%sannotation %s: %s%s on(%s);\n" indent (annotationsCode self)
descToCode indent self@(DescAnnotation desc) = printf "%sannotation %s: %s on(%s)%s;\n" indent
(annotationName desc) (annotationName desc)
(typeName (descParent self) (annotationType desc)) (typeName (descParent self) (annotationType desc))
(annotationsCode (descParent self) $ annotationAnnotations desc)
(delimit ", " $ map show $ Set.toList $ annotationTargets desc) (delimit ", " $ map show $ Set.toList $ annotationTargets desc)
(annotationsCode self)
descToCode _ (DescBuiltinType _) = error "Can't print code for builtin type." descToCode _ (DescBuiltinType _) = error "Can't print code for builtin type."
descToCode _ DescBuiltinList = error "Can't print code for builtin type." descToCode _ DescBuiltinList = error "Can't print code for builtin type."
descToCode _ DescBuiltinId = error "Can't print code for builtin annotation."
maybeBlockCode :: String -> [Desc] -> String maybeBlockCode :: String -> [Desc] -> String
maybeBlockCode _ [] = ";\n" maybeBlockCode _ [] = ";\n"
...@@ -476,12 +532,15 @@ blockCode indent = concatMap (descToCode (" " ++ indent)) ...@@ -476,12 +532,15 @@ blockCode indent = concatMap (descToCode (" " ++ indent))
annotationCode :: Desc -> (String, (AnnotationDesc, ValueDesc)) -> String annotationCode :: Desc -> (String, (AnnotationDesc, ValueDesc)) -> String
annotationCode scope (_, (desc, VoidDesc)) = annotationCode scope (_, (desc, VoidDesc)) =
printf "$%s" (descQualifiedName scope (DescAnnotation desc)) printf "$%s" (descQualifiedName scope (DescAnnotation desc))
annotationCode _ (annId, (desc, val)) | annId == idId =
printf "$id(%s)" (valueString val)
annotationCode scope (_, (desc, val)) = annotationCode scope (_, (desc, val)) =
printf "$%s(%s)" (descQualifiedName scope (DescAnnotation desc)) (valueString val) printf "$%s(%s)" (descQualifiedName scope (DescAnnotation desc)) (valueString val)
annotationsCode scope = concatMap ((' ':) . annotationCode scope) . Map.toList annotationsCode desc = let
nonIds = concatMap ((' ':) . annotationCode (descParent desc)) $ Map.toList
$ descAnnotations desc
in case descId desc of
Just i -> printf " $id(%s)%s" (show i) nonIds
Nothing -> nonIds
instance Show FileDesc where { show desc = descToCode "" (DescFile desc) } instance Show FileDesc where { show desc = descToCode "" (DescFile desc) }
instance Show AliasDesc where { show desc = descToCode "" (DescAlias desc) } instance Show AliasDesc where { show desc = descToCode "" (DescAlias desc) }
......
...@@ -24,12 +24,19 @@ ...@@ -24,12 +24,19 @@
module Util where module Util where
import Data.Char (isUpper, toUpper) import Data.Char (isUpper, toUpper)
import Data.List (intercalate) import Data.List (intercalate, isPrefixOf)
--delimit _ [] = "" --delimit _ [] = ""
--delimit delimiter (h:t) = h ++ concatMap (delimiter ++) t --delimit delimiter (h:t) = h ++ concatMap (delimiter ++) t
delimit = intercalate delimit = intercalate
splitOn :: String -> String -> [String]
splitOn _ "" = [""]
splitOn delimiter text | delimiter `isPrefixOf` text =
[]:splitOn delimiter (drop (length delimiter) text)
splitOn delimiter (c:rest) = let (first:more) = splitOn delimiter rest in (c:first):more
-- Splits "camelCase" into ["camel", "Case"]
splitName :: String -> [String] splitName :: String -> [String]
splitName (a:rest@(b:_)) | isUpper b = [a]:splitName rest splitName (a:rest@(b:_)) | isUpper b = [a]:splitName rest
splitName (a:rest) = case splitName rest of splitName (a:rest) = case splitName rest of
......
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