j2s: Add 'extern' type and ignored fields.

Closes #14.
This commit is contained in:
Jordan Bancino 2023-11-06 14:19:49 -05:00
parent d242597e73
commit 618bcbbac3
2 changed files with 65 additions and 16 deletions

View file

@ -5,6 +5,16 @@ Cytoplasm. It is intended to be updated with every commit that makes a user-faci
change worth reporting in the change log. As such, it changes frequently between change worth reporting in the change log. As such, it changes frequently between
releases. Final change log entries are published as [Releases](releases). releases. Final change log entries are published as [Releases](releases).
## v0.4.1
### Tools
#### `j2s`
- Added an option to allow additional fields in structures and ignore them in
encoding and decoding. Note that additional fields are totally untouched—they
are not even initialized to a default value.
## v0.4.0 ## v0.4.0
**Released on November 1, 2023** **Released on November 1, 2023**

View file

@ -309,22 +309,23 @@ Main(Array * args)
ArrayAdd(requiredTypes, StrDuplicate(type)); ArrayAdd(requiredTypes, StrDuplicate(type));
} }
typeFieldsVal = HashMapGet(typeObj, "fields");
if (JsonValueType(typeFieldsVal) != JSON_OBJECT)
{
Log(LOG_ERR, "Validation error: 'types.%s.fields' must be an object.", type);
goto finish;
}
typeFields = JsonValueAsObject(typeFieldsVal);
if (StrEquals(typeType, "struct")) if (StrEquals(typeType, "struct"))
{ {
typeFieldsVal = HashMapGet(typeObj, "fields");
if (JsonValueType(typeFieldsVal) != JSON_OBJECT)
{
Log(LOG_ERR, "Validation error: 'types.%s.fields' must be an object.", type);
goto finish;
}
typeFields = JsonValueAsObject(typeFieldsVal);
while (HashMapIterate(typeFields, &fieldName, (void **) &fieldVal)) while (HashMapIterate(typeFields, &fieldName, (void **) &fieldVal))
{ {
char *fieldType; char *fieldType;
int isArrType = 0; int isArrType = 0;
JsonValue *requiredVal; JsonValue *requiredVal;
JsonValue *ignoreVal;
if (JsonValueType(fieldVal) != JSON_OBJECT) if (JsonValueType(fieldVal) != JSON_OBJECT)
{ {
@ -379,10 +380,26 @@ Main(Array * args)
Log(LOG_ERR, "Validation error: 'types.%s.fields.%s.required' must be a boolean.", type, fieldName); Log(LOG_ERR, "Validation error: 'types.%s.fields.%s.required' must be a boolean.", type, fieldName);
goto finish; goto finish;
} }
ignoreVal = HashMapGet(fieldObj, "ignore");
if (ignoreVal && JsonValueType(ignoreVal) != JSON_BOOLEAN)
{
Log(LOG_ERR, "Validation error: 'types.%s.fields.%s.ignore' must be a boolean.", type, fieldName);
goto finish;
}
} }
} }
else if (StrEquals(typeType, "enum")) else if (StrEquals(typeType, "enum"))
{ {
typeFieldsVal = HashMapGet(typeObj, "fields");
if (JsonValueType(typeFieldsVal) != JSON_OBJECT)
{
Log(LOG_ERR, "Validation error: 'types.%s.fields' must be an object.", type);
goto finish;
}
typeFields = JsonValueAsObject(typeFieldsVal);
while (HashMapIterate(typeFields, &fieldName, (void **) &fieldVal)) while (HashMapIterate(typeFields, &fieldName, (void **) &fieldVal))
{ {
char *name; char *name;
@ -403,16 +420,17 @@ Main(Array * args)
} }
} }
} }
else if (StrEquals(typeType, "extern"))
{
/*
* No code will be generated for this type. We simply assume that it exists.
*/
}
else else
{ {
Log(LOG_ERR, "Validation error: 'types.%s.type' must be 'struct' or 'enum'.", type); Log(LOG_ERR, "Validation error: 'types.%s.type' must be 'struct' or 'enum'.", type);
goto finish; goto finish;
} }
/*
* TODO: Add "extern" type that doesn't actually generate any code,
* but trusts the user that it has been generated somewhere else. This
* is effectively "importing" types.
*/
} }
sortedNodes = GraphTopologicalSort(dependencyGraph, &sortedNodesLen); sortedNodes = GraphTopologicalSort(dependencyGraph, &sortedNodesLen);
@ -471,6 +489,12 @@ Main(Array * args)
} }
typeType = JsonValueAsString(JsonGet(types, 2, type, "type")); typeType = JsonValueAsString(JsonGet(types, 2, type, "type"));
if (StrEquals(typeType, "extern"))
{
continue;
}
fields = JsonValueAsObject(JsonGet(types, 2, type, "fields")); fields = JsonValueAsObject(JsonGet(types, 2, type, "fields"));
StreamPrintf(headerFile, "typedef %s %s\n{\n", typeType, type); StreamPrintf(headerFile, "typedef %s %s\n{\n", typeType, type);
@ -615,11 +639,18 @@ Main(Array * args)
{ {
char *key = ArrayGet(keys, i); char *key = ArrayGet(keys, i);
int required = JsonValueAsBoolean(JsonGet(fields, 2, key, "required")); int required = JsonValueAsBoolean(JsonGet(fields, 2, key, "required"));
int ignore = JsonValueAsBoolean(JsonGet(fields, 2, key, "ignore"));
char *fieldType = JsonValueAsString(JsonGet(fields, 2, key, "type")); char *fieldType = JsonValueAsString(JsonGet(fields, 2, key, "type"));
int isEnum = StrEquals(JsonValueAsString(JsonGet(types, 2, fieldType, "type")), "enum"); int isEnum = StrEquals(JsonValueAsString(JsonGet(types, 2, fieldType, "type")), "enum");
JsonType jsonType = isEnum ? JSON_STRING : TypeToJsonType(fieldType); JsonType jsonType = isEnum ? JSON_STRING : TypeToJsonType(fieldType);
char *jsonTypeStr = JsonTypeToStr(jsonType); char *jsonTypeStr = JsonTypeToStr(jsonType);
if (ignore)
{
StreamPrintf(implFile, " /* Ignored field: %s */\n\n", key);
continue;
}
StreamPrintf(implFile, " val = HashMapGet(json, \"%s\");\n", Trim('_', key)); StreamPrintf(implFile, " val = HashMapGet(json, \"%s\");\n", Trim('_', key));
StreamPrintf(implFile, " if (val)\n {\n"); StreamPrintf(implFile, " if (val)\n {\n");
@ -847,6 +878,13 @@ Main(Array * args)
char *key = ArrayGet(keys, i); char *key = ArrayGet(keys, i);
char *fieldType = JsonValueAsString(JsonGet(fields, 2, key, "type")); char *fieldType = JsonValueAsString(JsonGet(fields, 2, key, "type"));
int isEnum = StrEquals(JsonValueAsString(JsonGet(types, 2, fieldType, "type")), "enum"); int isEnum = StrEquals(JsonValueAsString(JsonGet(types, 2, fieldType, "type")), "enum");
int ignore = JsonValueAsBoolean(JsonGet(fields, 2, key, "ignore"));
if (ignore)
{
StreamPrintf(implFile, " /* Ignored field: %s */\n\n", key);
continue;
}
if (StrEquals(fieldType, "array")) if (StrEquals(fieldType, "array"))
{ {
@ -1022,8 +1060,9 @@ Main(Array * args)
else else
{ {
/* Ignore primitives but call the appropriate free /* Ignore primitives but call the appropriate free
* method on declared types */ * method on declared types that aren't "extern". */
if (!isEnum && HashMapGet(types, fieldType)) char *fieldTypeType = JsonValueAsString(JsonGet(types, 2, fieldType, "type"));
if (!isEnum && HashMapGet(types, fieldType) && !StrEquals(fieldTypeType, "extern"))
{ {
StreamPrintf(implFile, " %sFree(&val->%s);\n", fieldType, key); StreamPrintf(implFile, " %sFree(&val->%s);\n", fieldType, key);
} }