Files
ldc/dmd2/json.c
2013-03-06 18:18:56 +01:00

1092 lines
23 KiB
C

// Compiler implementation of the D programming language
// Copyright (c) 1999-2013 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
// License for redistribution is by either the Artistic License
// in artistic.txt, or the GNU General Public License in gnu.txt.
// See the included readme.txt for details.
// This implements the JSON capability.
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "rmem.h"
#include "dsymbol.h"
#include "template.h"
#include "aggregate.h"
#include "declaration.h"
#include "enum.h"
#include "module.h"
#include "json.h"
#include "mtype.h"
#include "attrib.h"
#include "cond.h"
#include "init.h"
#include "import.h"
#include "id.h"
struct JsonOut
{
OutBuffer *buf;
int indentLevel;
const char *filename;
JsonOut(OutBuffer *buf) {this->buf = buf; indentLevel = 0; filename = NULL;}
void indent();
void removeComma();
void comma();
void stringStart();
void stringEnd();
void stringPart(const char* part);
void value(const char* s);
void value(int value);
void valueBool(bool value);
void item(const char*);
void item(int);
void itemBool(bool);
void arrayStart();
void arrayEnd();
void objectStart();
void objectEnd();
void propertyStart(const char* name);
void property(const char *name, const char* s);
void property(const char *name, int value);
void propertyBool(const char *name, bool value);
void propertyStorageClass(const char *name, StorageClass stc);
void property(const char *name, Loc* loc);
void property(const char *name, Type* type);
void property(const char *name, const char *deconame, Type* type);
void property(const char *name, Parameters* parameters);
void property(const char *name, Expressions* expressions);
void property(const char *name, enum TRUST trust);
void property(const char *name, enum PURE purity);
void property(const char *name, enum LINK linkage);
};
void json_generate(OutBuffer *buf, Modules *modules)
{
JsonOut json(buf);
json.arrayStart();
for (size_t i = 0; i < modules->dim; i++)
{ Module *m = (*modules)[i];
if (global.params.verbose)
printf("json gen %s\n", m->toChars());
m->toJson(&json);
}
json.arrayEnd();
json.removeComma();
}
void JsonOut::indent()
{
if (buf->offset >= 1 &&
buf->data[buf->offset - 1] == '\n')
for (int i = 0; i < indentLevel; i++)
buf->writeByte(' ');
}
void JsonOut::removeComma()
{
if (buf->offset >= 2 &&
buf->data[buf->offset - 2] == ',' &&
(buf->data[buf->offset - 1] == '\n' || buf->data[buf->offset - 1] == ' '))
buf->offset -= 2;
}
void JsonOut::comma()
{
if (indentLevel > 0)
buf->writestring(",\n");
}
void JsonOut::stringStart()
{
buf->writeByte('\"');
}
void JsonOut::stringEnd()
{
buf->writeByte('\"');
}
void JsonOut::stringPart(const char *s)
{
for (; *s; s++)
{
unsigned char c = (unsigned char) *s;
switch (c)
{
case '\n':
buf->writestring("\\n");
break;
case '\r':
buf->writestring("\\r");
break;
case '\t':
buf->writestring("\\t");
break;
case '\"':
buf->writestring("\\\"");
break;
case '\\':
buf->writestring("\\\\");
break;
case '\b':
buf->writestring("\\b");
break;
case '\f':
buf->writestring("\\f");
break;
default:
if (c < 0x20)
buf->printf("\\u%04x", c);
else
// Note that UTF-8 chars pass through here just fine
buf->writeByte(c);
break;
}
}
}
// Json value functions
/*********************************
* Encode string into buf, and wrap it in double quotes.
*/
void JsonOut::value(const char *s)
{
stringStart();
stringPart(s);
stringEnd();
}
void JsonOut::value(int value)
{
buf->printf("%d", value);
}
void JsonOut::valueBool(bool value)
{
buf->writestring(value? "true" : "false");
}
/*********************************
* Item is an intented value and a comma, for use in arrays
*/
void JsonOut::item(const char *s)
{
indent();
value(s);
comma();
}
void JsonOut::item(int i)
{
indent();
value(i);
comma();
}
void JsonOut::itemBool(bool b)
{
indent();
valueBool(b);
comma();
}
// Json array functions
void JsonOut::arrayStart()
{
indent();
buf->writestring("[\n");
indentLevel++;
}
void JsonOut::arrayEnd()
{
indentLevel--;
removeComma();
if (buf->offset >= 2 &&
buf->data[buf->offset - 2] == '[' &&
buf->data[buf->offset - 1] == '\n')
buf->offset -= 1;
else if (!(buf->offset >= 1 &&
buf->data[buf->offset - 1] == '['))
{
buf->writestring("\n");
indent();
}
buf->writestring("]");
comma();
}
// Json object functions
void JsonOut::objectStart()
{
indent();
buf->writestring("{\n");
indentLevel++;
}
void JsonOut::objectEnd()
{
indentLevel--;
removeComma();
if (buf->offset >= 2 &&
buf->data[buf->offset - 2] == '{' &&
buf->data[buf->offset - 1] == '\n')
buf->offset -= 1;
else
{
buf->writestring("\n");
indent();
}
buf->writestring("}");
comma();
}
// Json object property functions
void JsonOut::propertyStart(const char *name)
{
indent();
value(name);
buf->writestring(" : ");
}
void JsonOut::property(const char *name, const char *s)
{
if (s == NULL) return;
propertyStart(name);
value(s);
comma();
}
void JsonOut::property(const char *name, int i)
{
propertyStart(name);
value(i);
comma();
}
void JsonOut::propertyBool(const char *name, bool b)
{
propertyStart(name);
valueBool(b);
comma();
}
void JsonOut::property(const char *name, enum TRUST trust)
{
switch (trust)
{
case TRUSTdefault:
// Should not be printed
//property(name, "default");
break;
case TRUSTsystem:
property(name, "system");
break;
case TRUSTtrusted:
property(name, "trusted");
break;
case TRUSTsafe:
property(name, "safe");
break;
default:
assert(false);
}
}
void JsonOut::property(const char *name, enum PURE purity)
{
switch (purity)
{
case PUREimpure:
// Should not be printed
//property(name, "impure");
break;
case PUREweak:
property(name, "weak");
break;
case PUREconst:
property(name, "const");
break;
case PUREstrong:
property(name, "strong");
break;
case PUREfwdref:
property(name, "fwdref");
break;
default:
assert(false);
}
}
void JsonOut::property(const char *name, enum LINK linkage)
{
switch (linkage)
{
case LINKdefault:
// Should not be printed
//property(name, "default");
break;
case LINKd:
// Should not be printed
//property(name, "d");
break;
case LINKc:
property(name, "c");
break;
case LINKcpp:
property(name, "cpp");
break;
case LINKwindows:
property(name, "windows");
break;
case LINKpascal:
property(name, "pascal");
break;
default:
assert(false);
}
}
void JsonOut::propertyStorageClass(const char *name, StorageClass stc)
{
stc &= STCStorageClass;
if (stc)
{
propertyStart(name);
arrayStart();
while (stc)
{ char tmp[20];
const char *p = StorageClassDeclaration::stcToChars(tmp, stc);
assert(p);
assert(strlen(p) < sizeof(tmp));
if (p[0] == '@')
{
indent();
stringStart();
buf->writestring(p);
stringEnd();
comma();
}
else
item(p);
}
arrayEnd();
}
}
void JsonOut::property(const char *name, Loc *loc)
{
if (loc)
{
const char *filename = loc->filename;
if (filename)
{
if (!this->filename || strcmp(filename, this->filename))
{ this->filename = filename;
property("file", filename);
}
}
if (loc->linnum)
property(name, loc->linnum);
}
}
void JsonOut::property(const char *name, Type *type)
{
if (type)
{
property(name, type->toChars());
}
}
void JsonOut::property(const char *name, const char *deconame, Type *type)
{
if (type)
{
if (type->deco)
property(deconame, type->deco);
else
property(name, type->toChars());
}
}
void JsonOut::property(const char *name, Parameters *parameters)
{
if (parameters == NULL || parameters->dim == 0)
return;
propertyStart(name);
arrayStart();
if (parameters)
for (size_t i = 0; i < parameters->dim; i++)
{ Parameter *p = (*parameters)[i];
objectStart();
if (p->ident)
property("name", p->ident->toChars());
property("type", "deco", p->type);
propertyStorageClass("storageClass", p->storageClass);
if (p->defaultArg)
property("default", p->defaultArg->toChars());
objectEnd();
}
arrayEnd();
}
/* ========================================================================== */
void Type::toJson(JsonOut *json)
{
}
void TypeSArray::toJson(JsonOut *json)
{
json->property("elementType", next);
json->property("dim", dim->toChars());
}
void TypeDArray::toJson(JsonOut *json)
{
json->property("elementType", next);
}
void TypeAArray::toJson(JsonOut *json)
{
json->property("elementType", next);
json->property("index", index);
}
void TypePointer::toJson(JsonOut *json)
{
json->property("targetType", next);
}
void TypeReference::toJson(JsonOut *json)
{
json->property("targetType", next);
}
void TypeFunction::toJson(JsonOut *json)
{
if (purity || isnothrow || isproperty || isref)
{
json->propertyStart("attributes");
json->arrayStart();
if (purity) json->item("pure");
if (isnothrow) json->item("nothrow");
if (isproperty) json->item("@property");
if (isref) json->item("ref");
json->arrayEnd();
}
json->property("trust", trust);
json->property("purity", purity);
json->property("linkage", linkage);
json->property("returnType", next);
json->property("parameters", parameters);
}
void TypeDelegate::toJson(JsonOut *json)
{
next->toJson(json); // next is TypeFunction
}
void TypeQualified::toJson(JsonOut *json) // ident.ident.ident.etc
{
json->propertyStart("idents");
json->arrayStart();
for (size_t i = 0; i < idents.dim; i++)
{ Identifier *ident = idents[i];
json->item(ident->toChars());
}
json->arrayEnd();
}
void TypeIdentifier::toJson(JsonOut *json)
{
TypeQualified::toJson(json);
json->property("rawIdentifier", ident->toChars());
json->property("identifier", ident->toHChars2());
}
void TypeInstance::toJson(JsonOut *json)
{
TypeQualified::toJson(json);
json->property("tempinst", tempinst->toChars());
}
void TypeTypeof::toJson(JsonOut *json)
{
TypeQualified::toJson(json);
json->property("exp", exp->toChars());
json->property("type", exp->type);
}
void TypeReturn::toJson(JsonOut *json)
{
TypeQualified::toJson(json);
}
void TypeStruct::toJson(JsonOut *json)
{
json->propertyStorageClass("storageClass", sym->storage_class);
}
void TypeEnum::toJson(JsonOut *json)
{
sym->jsonProperties(json);
}
void TypeTypedef::toJson(JsonOut *json)
{
sym->jsonProperties(json);
}
void TypeClass::toJson(JsonOut *json)
{
json->propertyStorageClass("storageClass", sym->storage_class);
}
void TypeTuple::toJson(JsonOut *json)
{
json->property("arguments", arguments);
}
void TypeSlice::toJson(JsonOut *json)
{
json->property("lower", lwr->toChars());
json->property("upper", upr->toChars());
}
void TypeNull::toJson(JsonOut *json) { }
void TypeVector::toJson(JsonOut *json)
{
json->property("basetype", basetype);
}
/* ========================================================================== */
void Dsymbol::toJson(JsonOut *json)
{
#if 0
json->objectStart();
jsonProperties(json);
json->objectEnd();
#endif
}
void Dsymbol::jsonProperties(JsonOut *json)
{
json->property("name", toChars());
if (!isTemplateDeclaration()) // TemplateDeclaration::kind() acts weird sometimes
json->property("kind", kind());
if (prot() != PROTpublic)
json->property("protection", Pprotectionnames[prot()]);
json->property("comment", (const char *)comment);
json->property("line", &loc);
#if 0
if (!isModule())
{
Module *module = getModule();
if (module)
{
json->propertyStart("module");
json->objectStart();
module->jsonProperties(json);
json->objectEnd();
}
Module *accessModule = getAccessModule();
if (accessModule && accessModule != module)
{
json->propertyStart("accessModule");
json->objectStart();
accessModule->jsonProperties(json);
json->objectEnd();
}
}
#endif
}
void Module::toJson(JsonOut *json)
{
json->objectStart();
if (md)
json->property("name", md->toChars());
json->property("kind", kind());
json->filename = srcfile->toChars();
json->property("file", json->filename);
json->property("comment", (const char *)comment);
json->propertyStart("members");
json->arrayStart();
for (size_t i = 0; i < members->dim; i++)
{ Dsymbol *s = (*members)[i];
s->toJson(json);
}
json->arrayEnd();
json->objectEnd();
}
void Module::jsonProperties(JsonOut *json)
{
#if 0
Dsymbol::jsonProperties(json);
if (md && md->packages)
{
json->propertyStart("package");
json->arrayStart();
for (size_t i = 0; i < md->packages->dim; i++)
{ Identifier *pid = (*md->packages)[i];
json->item(pid->toChars());
}
json->arrayEnd();
}
json->property("prettyName", toPrettyChars());
#endif
}
void Import::toJson(JsonOut *json)
{
if (id == Id::object)
return;
json->objectStart();
json->propertyStart("name");
json->stringStart();
if (packages && packages->dim)
{
for (size_t i = 0; i < packages->dim; i++)
{ Identifier *pid = (*packages)[i];
json->stringPart(pid->toChars());
json->buf->writeByte('.');
}
}
json->stringPart(id->toChars());
json->stringEnd();
json->comma();
json->property("kind", kind());
json->property("comment", (const char *)comment);
json->property("line", &loc);
if (prot() != PROTpublic)
json->property("protection", Pprotectionnames[prot()]);
if (aliasId)
json->property("alias", aliasId->toChars());
bool hasRenamed = false;
bool hasSelective = false;
for (size_t i = 0; i < aliases.dim; i++)
{ // avoid empty "renamed" and "selective" sections
if (hasRenamed && hasSelective)
break;
else if (aliases[i])
hasRenamed = true;
else
hasSelective = true;
}
if (hasRenamed)
{
// import foo : alias1 = target1;
json->propertyStart("renamed");
json->objectStart();
for (size_t i = 0; i < aliases.dim; i++)
{
Identifier *name = names[i];
Identifier *alias = aliases[i];
if (alias) json->property(alias->toChars(), name->toChars());
}
json->objectEnd();
}
if (hasSelective)
{
// import foo : target1;
json->propertyStart("selective");
json->arrayStart();
for (size_t i = 0; i < names.dim; i++)
{
Identifier *name = names[i];
if (!aliases[i]) json->item(name->toChars());
}
json->arrayEnd();
}
json->objectEnd();
}
void AttribDeclaration::toJson(JsonOut *json)
{
Dsymbols *d = include(NULL, NULL);
if (d)
{
for (size_t i = 0; i < d->dim; i++)
{ Dsymbol *s = (*d)[i];
s->toJson(json);
}
}
}
void ConditionalDeclaration::toJson(JsonOut *json)
{
if (condition->inc)
{
AttribDeclaration::toJson(json);
}
}
void ClassInfoDeclaration::toJson(JsonOut *json) { }
void ModuleInfoDeclaration::toJson(JsonOut *json) { }
void TypeInfoDeclaration::toJson(JsonOut *json) { }
#if DMDV2
void PostBlitDeclaration::toJson(JsonOut *json) { }
#endif
void Declaration::toJson(JsonOut *json)
{
json->objectStart();
//json->property("unknown", "declaration");
jsonProperties(json);
json->objectEnd();
}
void Declaration::jsonProperties(JsonOut *json)
{
Dsymbol::jsonProperties(json);
json->propertyStorageClass("storageClass", storage_class);
json->property("type", "deco", type);
// Emit originalType if it differs from type
if (type != originalType && originalType)
{
const char *ostr = originalType->toChars();
if (type)
{ const char *tstr = type->toChars();
if (strcmp(tstr, ostr))
{
//printf("tstr = %s, ostr = %s\n", tstr, ostr);
json->property("originalType", ostr);
}
}
else
json->property("originalType", ostr);
}
}
void TypedefDeclaration::toJson(JsonOut *json)
{
json->objectStart();
jsonProperties(json);
json->property("base", "baseDeco", basetype);
json->objectEnd();
}
void AggregateDeclaration::toJson(JsonOut *json)
{
json->objectStart();
jsonProperties(json);
ClassDeclaration *cd = isClassDeclaration();
if (cd)
{
if (cd->baseClass && cd->baseClass->ident != Id::Object)
{
json->property("base", cd->baseClass->toChars());
}
if (cd->interfaces_dim)
{
json->propertyStart("interfaces");
json->arrayStart();
for (size_t i = 0; i < cd->interfaces_dim; i++)
{ BaseClass *b = cd->interfaces[i];
json->item(b->base->toChars());
}
json->arrayEnd();
}
}
if (members)
{
json->propertyStart("members");
json->arrayStart();
for (size_t i = 0; i < members->dim; i++)
{ Dsymbol *s = (*members)[i];
s->toJson(json);
}
json->arrayEnd();
}
json->objectEnd();
}
void FuncDeclaration::toJson(JsonOut *json)
{
json->objectStart();
jsonProperties(json);
TypeFunction *tf = (TypeFunction *)type;
if (tf && tf->ty == Tfunction)
json->property("parameters", tf->parameters);
json->property("endline", &endloc);
if (foverrides.dim)
{
json->propertyStart("overrides");
json->arrayStart();
for (size_t i = 0; i < foverrides.dim; i++)
{ FuncDeclaration *fd = foverrides[i];
json->item(fd->toPrettyChars());
}
json->arrayEnd();
}
if (fdrequire)
{
json->propertyStart("in");
fdrequire->toJson(json);
}
if (fdensure)
{
json->propertyStart("out");
fdensure->toJson(json);
}
json->objectEnd();
}
void TemplateDeclaration::toJson(JsonOut *json)
{
json->objectStart();
// TemplateDeclaration::kind returns the kind of its Aggregate onemember, if it is one
json->property("kind", "template");
jsonProperties(json);
json->propertyStart("parameters");
json->arrayStart();
for (size_t i = 0; i < parameters->dim; i++)
{ TemplateParameter *s = (*parameters)[i];
json->objectStart();
json->property("name", s->ident->toChars());
TemplateTypeParameter *type = s->isTemplateTypeParameter();
if (type)
{
#if DMDV2
if (s->isTemplateThisParameter())
json->property("kind", "this");
else
#endif
json->property("kind", "type");
json->property("type", "deco", type->specType);
json->property("default", "defaultDeco", type->defaultType);
}
TemplateValueParameter *value = s->isTemplateValueParameter();
if (value)
{
json->property("kind", "value");
json->property("type", "deco", value->valType);
if (value->specValue)
json->property("specValue", value->specValue->toChars());
if (value->defaultValue)
json->property("defaultValue", value->defaultValue->toChars());
}
TemplateAliasParameter *alias = s->isTemplateAliasParameter();
if (alias)
{
json->property("kind", "alias");
json->property("type", "deco", alias->specType);
if (alias->specAlias)
json->property("specAlias", alias->specAlias->toChars());
if (alias->defaultAlias)
json->property("defaultAlias", alias->defaultAlias->toChars());
}
TemplateTupleParameter *tuple = s->isTemplateTupleParameter();
if (tuple)
{
json->property("kind", "tuple");
}
json->objectEnd();
}
json->arrayEnd();
json->propertyStart("members");
json->arrayStart();
for (size_t i = 0; i < members->dim; i++)
{ Dsymbol *s = (*members)[i];
s->toJson(json);
}
json->arrayEnd();
json->objectEnd();
}
void EnumDeclaration::toJson(JsonOut *json)
{
if (isAnonymous())
{
if (members)
{
for (size_t i = 0; i < members->dim; i++)
{ Dsymbol *s = (*members)[i];
s->toJson(json);
}
}
return;
}
json->objectStart();
jsonProperties(json);
json->property("base", "baseDeco", memtype);
if (members)
{
json->propertyStart("members");
json->arrayStart();
for (size_t i = 0; i < members->dim; i++)
{ Dsymbol *s = (*members)[i];
s->toJson(json);
}
json->arrayEnd();
}
json->objectEnd();
}
void EnumMember::toJson(JsonOut *json)
{
json->objectStart();
jsonProperties(json);
json->property("type", "deco", type);
json->objectEnd();
}
void VarDeclaration::toJson(JsonOut *json)
{
json->objectStart();
jsonProperties(json);
if (init)
json->property("init", init->toChars());
if (storage_class & STCfield)
json->property("offset", offset);
if (alignment && alignment != STRUCTALIGN_DEFAULT)
json->property("align", alignment);
json->objectEnd();
}
void TemplateMixin::toJson(JsonOut *json)
{
json->objectStart();
jsonProperties(json);
json->objectEnd();
}