Commit 271c4728 authored by Kenton Varda's avatar Kenton Varda

Basic code generation starting to work. My machine just did something weird so…

Basic code generation starting to work.  My machine just did something weird so I'm submitting and pushing in case of imminant hardware failure...
parent a1f2e061
#! /bin/sh
# 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.
set -eu
if test $# = 0; then
echo trigger filetype:.capnp
exit 0
fi
INPUT=$1
echo findProvider special:ekam-interceptor
read INTERCEPTOR
if test "$INTERCEPTOR" = ""; then
echo "error: couldn't find intercept.so." >&2
exit 1
fi
echo findProvider file:capnproto-compiler
read CAPNPC
if test "$CAPNPC" = ""; then
echo "error: couldn't find capnproto-compiler." >&2
exit 1
fi
LD_PRELOAD=$INTERCEPTOR DYLD_FORCE_FLAT_NAMESPACE= DYLD_INSERT_LIBRARIES=$INTERCEPTOR \
$CAPNPC "$INPUT" 3>&1 4<&0 >&2
// 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.
#include "test.capnp.h"
#include "message.h"
#include <gtest/gtest.h>
namespace capnproto {
namespace internal {
namespace {
TEST(Encoding, Simple) {
std::unique_ptr<MessageBuilder> message = newMallocMessage(512 * WORDS);
SegmentBuilder* segment = message->getSegmentWithAvailable(1 * WORDS);
word* rootLocation = segment->allocate(1 * WORDS);
Foo::Builder builder(StructBuilder::initRoot(segment, rootLocation, Foo::DEFAULT.words));
EXPECT_EQ(1234, builder.getA());
EXPECT_EQ(-1, builder.getB());
EXPECT_EQ(200, builder.getC());
ASSERT_EQ(0, builder.getNums().size());
builder.setA(321);
builder.setB(45);
builder.setC(67);
builder.initD().setX(55.25);
List<int32_t>::Builder listBuilder = builder.initNums(5);
ASSERT_EQ(5, listBuilder.size());
listBuilder[0] = 12;
listBuilder[1] = 34;
listBuilder[2] = 56;
listBuilder[3] = 78;
listBuilder[4] = 90;
{
int sum = 0;
for (int32_t i: listBuilder) {
sum += i;
}
EXPECT_EQ(12 + 34 + 56 + 78 + 90, sum);
}
EXPECT_EQ(321, builder.getA());
EXPECT_EQ(45, builder.getB());
EXPECT_EQ(67, builder.getC());
EXPECT_EQ(55.25, builder.getD().getX());
Foo::Reader reader(StructReader::readRoot(
segment->getStartPtr(), Foo::DEFAULT.words, segment, 4));
EXPECT_EQ(321, reader.getA());
EXPECT_EQ(45, reader.getB());
EXPECT_EQ(67, reader.getC());
EXPECT_EQ(55.25, reader.getD().getX());
List<int32_t>::Reader listReader = reader.getNums();
ASSERT_EQ(5, listReader.size());
EXPECT_EQ(12, listReader[0]);
EXPECT_EQ(34, listReader[1]);
EXPECT_EQ(56, listReader[2]);
EXPECT_EQ(78, listReader[3]);
EXPECT_EQ(90, listReader[4]);
{
int sum = 0;
for (int32_t i: listReader) {
sum += i;
}
EXPECT_EQ(12 + 34 + 56 + 78 + 90, sum);
}
}
} // namespace
} // namespace internal
} // namespace capnproto
// 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.
// This file is included form all generated headers.
#ifndef CAPNPROTO_GENERATED_HEADER_SUPPORT_H_
#define CAPNPROTO_GENERATED_HEADER_SUPPORT_H_
#include "wire-format.h"
#include "list.h"
#include "descriptor.h" // TODO: Eliminate this.
#endif // CAPNPROTO_GENERATED_HEADER_SUPPORT_H_
// 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.
#include "list.h"
namespace capnproto {
} // namespace capnproto
// 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.
#ifndef CAPNPROTO_LIST_H_
#define CAPNPROTO_LIST_H_
#include "wire-format.h"
namespace capnproto {
namespace internal {
template <typename T> struct IsPrimitive { static constexpr bool value = false; };
template <> struct IsPrimitive<void> { static constexpr bool value = true; };
template <> struct IsPrimitive<bool> { static constexpr bool value = true; };
template <> struct IsPrimitive<int8_t> { static constexpr bool value = true; };
template <> struct IsPrimitive<int16_t> { static constexpr bool value = true; };
template <> struct IsPrimitive<int32_t> { static constexpr bool value = true; };
template <> struct IsPrimitive<int64_t> { static constexpr bool value = true; };
template <> struct IsPrimitive<uint8_t> { static constexpr bool value = true; };
template <> struct IsPrimitive<uint16_t> { static constexpr bool value = true; };
template <> struct IsPrimitive<uint32_t> { static constexpr bool value = true; };
template <> struct IsPrimitive<uint64_t> { static constexpr bool value = true; };
template <> struct IsPrimitive<float> { static constexpr bool value = true; };
template <> struct IsPrimitive<double> { static constexpr bool value = true; };
template<typename T> constexpr T&& move(T& t) noexcept { return static_cast<T&&>(t); }
// Like std::move. Unfortunately, #including <utility> brings in tons of unnecessary stuff.
template <typename T>
class TemporaryPointer {
// This class is a little hack which lets us define operator->() in cases where it needs to
// return a pointer to a temporary value. We instead construct a TemporaryPointer and return that
// (by value). The compiler then invokes operator->() on the TemporaryPointer, which itself is
// able to return a real pointer to its member.
public:
TemporaryPointer(T&& value): value(move(value)) {}
TemporaryPointer(const T& value): value(value) {}
inline T* operator->() { return &value; }
private:
T value;
};
template <typename Container, typename Element, typename Reference>
class IndexingIterator {
public:
IndexingIterator() = default;
inline Reference operator*() { return (*container)[index]; }
inline Reference operator->() { return TemporaryPointer<Element>((*container)[index]); }
inline Reference operator[]( int off) { return (*container)[index]; }
inline Reference operator[](uint off) { return (*container)[index]; }
inline IndexingIterator& operator++() { ++index; return *this; }
inline IndexingIterator operator++(int) { IndexingIterator other = *this; ++index; return other; }
inline IndexingIterator& operator--() { --index; return *this; }
inline IndexingIterator operator--(int) { IndexingIterator other = *this; --index; return other; }
inline IndexingIterator operator+(uint amount) { return IndexingIterator(container, index + amount); }
inline IndexingIterator operator-(uint amount) { return IndexingIterator(container, index - amount); }
inline IndexingIterator operator+( int amount) { return IndexingIterator(container, index + amount); }
inline IndexingIterator operator-( int amount) { return IndexingIterator(container, index - amount); }
inline int operator-(const IndexingIterator& other) { return index - other.index; }
inline IndexingIterator& operator+=(uint amount) { index += amount; return *this; }
inline IndexingIterator& operator-=(uint amount) { index -= amount; return *this; }
inline IndexingIterator& operator+=( int amount) { index += amount; return *this; }
inline IndexingIterator& operator-=( int amount) { index -= amount; return *this; }
// STL says comparing iterators of different containers is not allowed, so we only compare
// indices here.
inline bool operator==(const IndexingIterator& other) { return index == other.index; }
inline bool operator!=(const IndexingIterator& other) { return index != other.index; }
inline bool operator<=(const IndexingIterator& other) { return index <= other.index; }
inline bool operator>=(const IndexingIterator& other) { return index >= other.index; }
inline bool operator< (const IndexingIterator& other) { return index < other.index; }
inline bool operator> (const IndexingIterator& other) { return index > other.index; }
private:
Container* container;
uint index;
friend Container;
IndexingIterator(Container* builder, uint index): container(container), index(index) {}
};
} // namespace internal
template <typename T, bool isPrimitive = internal::IsPrimitive<T>::value>
struct List;
template <typename T>
struct List<T, true> {
class Reader {
public:
Reader() = default;
inline explicit Reader(internal::ListReader reader): reader(reader) {}
typedef internal::IndexingIterator<Reader, T, T> iterator;
inline T operator[](uint index) { return reader.template getDataElement<T>(index * ELEMENTS); }
inline uint size() { return reader.size() / ELEMENTS; }
inline iterator begin() { return iterator(this, 0); }
inline iterator end() { return iterator(this, size()); }
private:
internal::ListReader reader;
};
class Builder {
public:
Builder() = default;
inline explicit Builder(internal::ListBuilder builder): builder(builder) {}
class reference {
public:
reference() = default;
inline operator T() { return (*builder)[index]; }
inline reference& operator=(T value) {
builder->builder.template setDataElement<T>(index * ELEMENTS, value);
return *this;
}
T* operator&() {
static_assert(sizeof(T) < 0,
"You can't take the address of a list member because they are not stored in memory "
"in a directly-usable format.");
return nullptr;
}
private:
Builder* builder;
uint index;
friend class Builder;
reference(Builder* builder, uint index): builder(builder), index(index) {}
};
typedef internal::IndexingIterator<Builder, T, reference> iterator;
inline reference operator[](uint index) { return reference(this, index); }
inline uint size() { return builder.size() / ELEMENTS; }
inline iterator begin() { return iterator(this, 0); }
inline iterator end() { return iterator(this, size()); }
private:
internal::ListBuilder builder;
};
};
template <typename T>
struct List<T, false> {
class Reader {
public:
Reader() = default;
inline explicit Reader(internal::ListReader reader): reader(reader) {}
typedef internal::IndexingIterator<Reader, typename T::Reader, typename T::Reader> iterator;
inline typename T::Reader operator[](uint index) {
return typename T::Reader(reader.getStructElement(index * ELEMENTS, T::DEFAULT.words));
}
inline uint size() { return reader.size() / ELEMENTS; }
inline iterator begin() { return iterator(this, 0); }
inline iterator end() { return iterator(this, size()); }
private:
internal::ListReader reader;
};
class Builder {
public:
Builder() = default;
inline explicit Builder(internal::ListBuilder builder): builder(builder) {}
class reference {
public:
reference() = default;
inline operator typename T::Builder() { return (*builder)[index]; }
// TODO: operator= to accept ownership transfer.
T* operator&() {
static_assert(sizeof(T) < 0,
"You can't take the address of a list member because they are not stored in memory "
"in a directly-usable format.");
return nullptr;
}
private:
Builder* builder;
uint index;
friend class Builder;
reference(Builder* builder, uint index): builder(builder), index(index) {}
};
typedef internal::IndexingIterator<Builder, typename T::Builder, reference> iterator;
inline typename T::Builder operator[](uint index) {
return typename T::Builder(builder.getStructElement(index * ELEMENTS,
(T::DATA_SIZE + T::REFERENCE_COUNT * WORDS_PER_REFERENCE) / ELEMENTS,
T::DATA_SIZE));
}
inline uint size() { return builder.size() / ELEMENTS; }
inline iterator begin() { return iterator(this, 0); }
inline iterator end() { return iterator(this, size()); }
private:
internal::ListBuilder builder;
};
};
} // namespace capnproto
#endif // CAPNPROTO_LIST_H_
......@@ -16,7 +16,10 @@ executable capnproto-compiler
bytestring,
Crypto,
utf8-string,
hastache
hastache,
array,
data-binary-ieee754,
filepath
ghc-options: -Wall -fno-warn-missing-signatures
other-modules:
Lexer,
......
......@@ -279,7 +279,7 @@ compileType scope (TypeExpression n (param:moreParams)) = do
findDupesBy :: Ord a => (b -> a) -> [b] -> [[b]]
findDupesBy getKey items = let
compareItems a b = compare (getKey a) (getKey b)
eqItems a b = (getKey a) == (getKey b)
eqItems a b = getKey a == getKey b
grouped = List.groupBy eqItems $ List.sortBy compareItems items
in [ item | item@(_:_:_) <- grouped ]
......@@ -524,8 +524,8 @@ compileDecl scope (StructDecl (Located _ name) decls) =
CompiledMemberStatus name (feedback (\desc -> do
(members, memberMap, options, statements) <- compileChildDecls desc decls
requireNoDuplicateNames decls
fieldNums <- return ([ num | FieldDecl _ num _ _ _ _ <- decls ] ++
[ num | UnionDecl _ num _ <- decls ])
let fieldNums = [ num | FieldDecl _ num _ _ _ _ <- decls ] ++
[ num | UnionDecl _ num _ <- decls ]
requireSequentialNumbering "Fields" fieldNums
requireFieldNumbersInRange fieldNums
return (let
......@@ -553,7 +553,7 @@ compileDecl scope (StructDecl (Located _ name) decls) =
compileDecl (DescStruct parent) (UnionDecl (Located _ name) (Located numPos number) decls) =
CompiledMemberStatus name (feedback (\desc -> do
(_, _, options, statements) <- compileChildDecls desc decls
fields <- return [f | f <- structFields parent, fieldInUnion name f]
let fields = [f | f <- structFields parent, fieldInUnion name f]
requireNoMoreThanOneFieldNumberLessThan name numPos number fields
return (let
(tagOffset, tagPacking) = structFieldPackingMap parent ! number
......
......@@ -23,19 +23,21 @@
{-# LANGUAGE TemplateHaskell #-}
module CxxGenerator(generateCxx) where
module CxxGenerator(generateCxxHeader, generateCxxSource) where
import qualified Data.ByteString as ByteString
import qualified Data.ByteString.UTF8 as UTF8
import qualified Data.ByteString.UTF8 as ByteStringUTF8
import Data.FileEmbed(embedFile)
import Data.Char(ord)
import Data.Word(Word8)
import qualified Data.Digest.MD5 as MD5
import Text.Printf(printf)
import Text.Hastache
import Text.Hastache.Context
import qualified Codec.Binary.UTF8.String as UTF8
import System.FilePath(takeBaseName)
import Semantics
import Util
import WireFormat
-- MuNothing isn't considered a false value for the purpose of {{#variable}} expansion. Use this
-- instead.
......@@ -45,8 +47,7 @@ hashString :: String -> String
hashString str =
concatMap (printf "%02x" . fromEnum) $
MD5.hash $
ByteString.unpack $
UTF8.fromString str
UTF8.encode str
isPrimitive (BuiltinType _) = True
isPrimitive (EnumType _) = True
......@@ -94,24 +95,6 @@ cxxFieldSizeString Size64 = "EIGHT_BYTES";
cxxFieldSizeString SizeReference = "REFERENCE";
cxxFieldSizeString (SizeInlineComposite _ _) = "INLINE_COMPOSITE";
cEscape [] = []
cEscape (first:rest) = result where
eRest = cEscape rest
result = case first of
'\a' -> '\\':'a':eRest
'\b' -> '\\':'b':eRest
'\f' -> '\\':'f':eRest
'\n' -> '\\':'n':eRest
'\r' -> '\\':'r':eRest
'\t' -> '\\':'t':eRest
'\v' -> '\\':'v':eRest
'\'' -> '\\':'\'':eRest
'\"' -> '\\':'\"':eRest
'\\' -> '\\':'\\':eRest
'?' -> '\\':'?':eRest
c | c < ' ' || c > '~' -> '\\':(printf "%03o" (ord c) ++ eRest)
c -> c:eRest
cxxValueString VoidDesc = error "Can't stringify void value."
cxxValueString (BoolDesc b) = if b then "true" else "false"
cxxValueString (Int8Desc i) = show i
......@@ -124,13 +107,19 @@ cxxValueString (UInt32Desc i) = show i ++ "u"
cxxValueString (UInt64Desc i) = show i ++ "llu"
cxxValueString (Float32Desc x) = show x ++ "f"
cxxValueString (Float64Desc x) = show x
cxxValueString (TextDesc s) = "\"" ++ cEscape s ++ "\""
cxxValueString (DataDesc _) = error "Data defaults are encoded as bytes."
cxxValueString (EnumValueValueDesc v) =
cxxTypeString (EnumType $ enumValueParent v) ++ "::" ++
toUpperCaseWithUnderscores (enumValueName v)
cxxValueString (StructValueDesc _) = error "Struct defaults are encoded as bytes."
cxxValueString (ListDesc _) = error "List defaults are encoded as bytes."
cxxValueString (TextDesc _) = error "No default value literal for aggregate type."
cxxValueString (DataDesc _) = error "No default value literal for aggregate type."
cxxValueString (StructValueDesc _) = error "No default value literal for aggregate type."
cxxValueString (ListDesc _) = error "No default value literal for aggregate type."
defaultValueBytes _ (TextDesc s) = Just (UTF8.encode s ++ [0])
defaultValueBytes _ (DataDesc d) = Just d
defaultValueBytes t v@(StructValueDesc _) = Just $ encodeMessage t v
defaultValueBytes t v@(ListDesc _) = Just $ encodeMessage t v
defaultValueBytes _ _ = Nothing
cxxDefaultDefault (BuiltinType BuiltinVoid) = error "Can't stringify void value."
cxxDefaultDefault (BuiltinType BuiltinBool) = "false"
......@@ -145,15 +134,25 @@ cxxDefaultDefault (BuiltinType BuiltinUInt64) = "0"
cxxDefaultDefault (BuiltinType BuiltinFloat32) = "0"
cxxDefaultDefault (BuiltinType BuiltinFloat64) = "0"
cxxDefaultDefault (BuiltinType BuiltinText) = "\"\""
cxxDefaultDefault (BuiltinType BuiltinData) = error "Data defaults are encoded as bytes."
cxxDefaultDefault (EnumType desc) = cxxValueString $ EnumValueValueDesc $ head $ enumValues desc
cxxDefaultDefault (StructType _) = error "Struct defaults are encoded as bytes."
cxxDefaultDefault (InterfaceType _) = error "Interfaces have no default value."
cxxDefaultDefault (ListType _) = error "List defaults are encoded as bytes."
cxxDefaultDefault (BuiltinType BuiltinData) = error "No default value literal for aggregate type."
cxxDefaultDefault (StructType _) = error "No default value literal for aggregate type."
cxxDefaultDefault (InterfaceType _) = error "No default value literal for aggregate type."
cxxDefaultDefault (ListType _) = error "No default value literal for aggregate type."
elementType (ListType t) = t
elementType _ = error "Called elementType on non-list."
repeatedlyTake _ [] = []
repeatedlyTake n l = take n l : repeatedlyTake n (drop n l)
defaultBytesContext :: Monad m => (String -> MuType m) -> [Word8] -> MuContext m
defaultBytesContext parent bytes = mkStrContext context where
codeLines = map (delimit ", ") $ repeatedlyTake 8 $ map (printf "%3d") bytes
context "defaultByteList" = MuVariable $ delimit ",\n " codeLines
context "defaultWordCount" = MuVariable $ div (length bytes + 7) 8
context s = parent s
fieldContext parent desc = mkStrContext context where
context "fieldName" = MuVariable $ fieldName desc
context "fieldDecl" = MuVariable $ descToCode "" (DescField desc)
......@@ -164,7 +163,10 @@ fieldContext parent desc = mkStrContext context where
context "fieldIsList" = MuBool $ isList $ fieldType desc
context "fieldIsPrimitiveList" = MuBool $ isPrimitiveList $ fieldType desc
context "fieldIsStructList" = MuBool $ isStructList $ fieldType desc
context "fieldDefaultBytes" = muNull
context "fieldDefaultBytes" =
case fieldDefaultValue desc >>= defaultValueBytes (fieldType desc) of
Just v -> MuList [defaultBytesContext context v]
Nothing -> muNull
context "fieldType" = MuVariable $ cxxTypeString $ fieldType desc
context "fieldOffset" = MuVariable $ fieldOffset desc
context "fieldDefaultValue" = case fieldDefaultValue desc of
......@@ -178,10 +180,13 @@ structContext parent desc = mkStrContext context where
context "structName" = MuVariable $ structName desc
context "structFields" = MuList $ map (fieldContext context) $ structFields desc
context "structChildren" = MuList [] -- TODO
context "structDefault" = MuList [defaultBytesContext context
(encodeMessage (StructType desc) (StructValueDesc []))]
context s = parent s
fileContext desc = mkStrContext context where
context "fileName" = MuVariable $ fileName desc
context "fileBasename" = MuVariable $ takeBaseName $ fileName desc
context "fileIncludeGuard" = MuVariable $
"CAPNPROTO_INCLUDED_" ++ hashString (fileName desc)
context "fileNamespaces" = MuList [] -- TODO
......@@ -189,7 +194,10 @@ fileContext desc = mkStrContext context where
context s = MuVariable $ concat ["@@@", s, "@@@"]
headerTemplate :: String
headerTemplate = UTF8.toString $(embedFile "src/c++-header.mustache")
headerTemplate = ByteStringUTF8.toString $(embedFile "src/c++-header.mustache")
srcTemplate :: String
srcTemplate = ByteStringUTF8.toString $(embedFile "src/c++-source.mustache")
-- Sadly it appears that hashtache requires access to the IO monad, even when template inclusion
-- is disabled.
......@@ -201,5 +209,5 @@ hastacheConfig = MuConfig
, muTemplateRead = \_ -> return Nothing
}
generateCxx file =
hastacheStr hastacheConfig (encodeStr headerTemplate) (fileContext file)
generateCxxHeader file = hastacheStr hastacheConfig (encodeStr headerTemplate) (fileContext file)
generateCxxSource file = hastacheStr hastacheConfig (encodeStr srcTemplate) (fileContext file)
......@@ -30,9 +30,10 @@ import Text.Parsec.Pos
import Text.Parsec.Error
import Text.Printf(printf)
import qualified Data.List as List
import CxxGenerator(generateCxx)
import qualified Data.ByteString.Lazy.Char8 as LZ
import CxxGenerator
main::IO()
main = do
files <- getArgs
......@@ -43,8 +44,10 @@ handleFile filename = do
case parseAndCompileFile filename text of
Active desc [] -> do
print desc
cxx <- generateCxx desc
LZ.putStr cxx
header <- generateCxxHeader desc
LZ.writeFile (filename ++ ".h") header
source <- generateCxxSource desc
LZ.writeFile (filename ++ ".c++") source
Active _ e -> mapM_ printError (List.sortBy compareErrors e)
Failed e -> mapM_ printError (List.sortBy compareErrors e)
......
......@@ -172,6 +172,10 @@ data UnionPackingState = UnionPackingState
data FieldSize = Size0 | Size1 | Size8 | Size16 | Size32 | Size64 | SizeReference
| SizeInlineComposite Integer Integer
isDataFieldSize SizeReference = False
isDataFieldSize (SizeInlineComposite _ _) = False
isDataFieldSize _ = True
fieldSize (BuiltinType BuiltinVoid) = Size0
fieldSize (BuiltinType BuiltinBool) = Size1
fieldSize (BuiltinType BuiltinInt8) = Size8
......
......@@ -24,9 +24,11 @@
module Util where
import Data.Char (isUpper, toUpper)
import Data.List (intercalate)
delimit _ [] = ""
delimit delimiter (h:t) = h ++ concatMap (delimiter ++) t
--delimit _ [] = ""
--delimit delimiter (h:t) = h ++ concatMap (delimiter ++) t
delimit = intercalate
splitName :: String -> [String]
splitName (a:rest@(b:_)) | isUpper b = [a]:splitName rest
......
This diff is collapsed.
This diff is collapsed.
{{!
| 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.
Template for generated C++ source files.
}}// Generated code, DO NOT EDIT
#include "{{fileName}}.h"
{{#fileNamespaces}}
namespace {{namespaceName}} {
{{/fileNamespaces}}
{{#fileStructs}}
{{#structDefault}}
const ::capnproto::internal::AlignedData<{{defaultWordCount}}> {{structName}}::DEFAULT = {
{ {{defaultByteList}} }
};
{{/structDefault}}
{{#structFields}}
{{#fieldDefaultBytes}}
const ::capnproto::internal::AlignedData<{{defaultWordCount}}>
{{structName}}::DEFAULT_{{fieldUpperCase}} = {
{ {{defaultByteList}} }
};
{{/fieldDefaultBytes}}
{{/structFields}}
{{/fileStructs}}
{{#fileNamespaces}}
} // namespace
{{/fileNamespaces}}
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