1 /*
  2  * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 #include "schema.h"
 26 
 27 void Schema::show(std::ostream &out, char *argArray) {
 28 }
 29 
 30 void indent(std::ostream &out, int depth, char ch) {
 31     while (depth-- > 0) {
 32         out << ch;
 33     }
 34 }
 35 
 36 void Schema::show(std::ostream &out, int depth, Node *node) {
 37     indent(out, depth, ' ');
 38     if (const auto *schemaNode = dynamic_cast<SchemaNode *>(node)) {
 39         std::cout << schemaNode->type;
 40     } else if (const auto *arg = dynamic_cast<ArgNode *>(node)) {
 41         std::cout << arg->idx;
 42     } else if (const auto *structNode = dynamic_cast<StructNode *>(node)) {
 43         std::cout << ((structNode->name == nullptr) ? "?" : structNode->name);
 44     } else if (const auto *unionNode = dynamic_cast<UnionNode *>(node)) {
 45         std::cout << ((unionNode->name == nullptr) ? "?" : unionNode->name);
 46     } else if (auto *array = dynamic_cast<Array *>(node)) {
 47         if (array->flexible) {
 48             std::cout << "[*]";
 49         } else {
 50             std::cout << "[" << array->elementCount << "]";
 51         }
 52     } else if (auto *fieldNode = dynamic_cast<FieldNode *>(node)) {
 53         std::cout << ((fieldNode->name == nullptr) ? "?" : fieldNode->name) << ":" << fieldNode->typeName;
 54     } else {
 55         std::cout << "<node?>";
 56     }
 57     if (node->children.empty()) {
 58         std::cout << std::endl;
 59     } else {
 60         std::cout << "{" << std::endl;
 61         for (Node *n: node->children) {
 62             show(out, depth + 1, n);
 63         }
 64         indent(out, depth, ' ');
 65         std::cout << "}" << std::endl;
 66     }
 67 }
 68 
 69 void Schema::show(std::ostream &out, SchemaNode *schemaNode) {
 70     show(out, 0, schemaNode);
 71 }
 72 
 73 Schema::FieldNode *Schema::FieldNode::parse(SchemaCursor *cursor) {
 74     typeName = cursor->getIdentifier();
 75     return this;
 76 }
 77 
 78 Schema::Array *Schema::Array::parse(SchemaCursor *cursor) {
 79     cursor->in("Array::Parse");
 80     if (cursor->is('*')) {
 81         flexible = true;
 82     } else if (cursor->peekDigit()) {
 83         elementCount = cursor->getLong();
 84     }
 85     cursor->expect(':', "after element count in array", __LINE__);
 86     char *identifier = nullptr;
 87     if (cursor->is('?')) {
 88     } else if (cursor->peekAlpha()) {
 89         identifier = cursor->getIdentifier();
 90     } else {
 91         cursor->error(std::cerr, __FILE__, __LINE__, "expecting '?' or identifier for element");
 92     }
 93     cursor->expect(':', "after name in array", __LINE__);
 94     if (cursor->peekAlpha()) {
 95         elementType = addChild(cursor, new FieldNode(this, identifier));
 96     } else if (cursor->is('{')) {
 97         elementType = addChild(cursor, new StructNode(this, identifier));
 98     } else if (cursor->is('<')) {
 99         elementType = addChild(cursor, new UnionNode(this, identifier));
100     } else {
101         cursor->error(std::cerr, __FILE__, __LINE__, "expecting type  for element");
102     }
103     cursor->expect(']', "after array type", __LINE__);
104     cursor->out();
105     return this;
106 }
107 
108 Schema::AbstractStructOrUnionNode *Schema::AbstractStructOrUnionNode::parse(SchemaCursor *cursor) {
109     cursor->in("StructUnion::parse");
110     do {
111         char *identifier = nullptr;
112         if (cursor->is('?')) {
113             // no name name = null!
114         } else if (cursor->peekAlpha()) {
115             identifier = cursor->getIdentifier();
116         }
117         cursor->expect(':', "after StrutOrUnion name", __LINE__);
118         if (cursor->peekAlpha()) {
119             typeNode = addChild(cursor, new FieldNode(this, identifier));
120         } else if (cursor->is('[')) {
121             typeNode = addChild(cursor, new Array(this));
122         } else if (cursor->is('{')) {
123             typeNode = addChild(cursor, new StructNode(this, identifier));
124         } else if (cursor->is('<')) {
125             typeNode = addChild(cursor, new UnionNode(this, identifier));
126         } else {
127             cursor->error(std::cerr, __FILE__, __LINE__, "expecting type");
128         }
129     } while (cursor->is(separator));
130     cursor->expect(terminator, "at end of struct or union ", __LINE__);
131     cursor->out();
132     return this;
133 }
134 
135 Schema::StructNode *Schema::StructNode::parse(SchemaCursor *cursor) {
136     return dynamic_cast<StructNode *>(AbstractStructOrUnionNode::parse(cursor));
137 }
138 
139 Schema::UnionNode *Schema::UnionNode::parse(SchemaCursor *cursor) {
140     return dynamic_cast<UnionNode *>(AbstractStructOrUnionNode::parse(cursor));
141 }
142 
143 Schema::ArgNode *Schema::ArgNode::parse(SchemaCursor *cursor) {
144     cursor->in("ArgNode::parse");
145     char actual;
146     cursor->expectEither('!', '?', &actual, __LINE__);
147 
148     cursor->expect(':', __LINE__);
149     if (cursor->peekAlpha()) {
150         addChild(cursor, new FieldNode(this, nullptr));
151     } else {
152         cursor->expectDigit("long byteCount of buffer", __LINE__);
153         long bytes = cursor->getLong();
154         if (cursor->isEither('#', '+', &actual)) {
155             bool complete = (actual == '#');
156             cursor->expectAlpha("identifier", __LINE__);
157             char *identifier = cursor->getIdentifier();
158             cursor->expect(':', "after identifier ", __LINE__);
159             cursor->expect('{', "top level arg struct", __LINE__);
160             addChild(cursor, new ArgStructNode(this, complete, identifier));
161         } else if (cursor->peekAlpha()) {
162             addChild(cursor, new FieldNode(this, cursor->getIdentifier()));
163         } else {
164             cursor->error(std::cerr, __FILE__, __LINE__, "expecting '#' ");
165         }
166     }
167     cursor->expect(')', "at end of NamedStructOrUnion", __LINE__);
168     cursor->out();
169 
170     return this;
171 }
172 
173 Schema::SchemaNode *Schema::SchemaNode::parse(SchemaCursor *cursor) {
174     cursor->in("SchemaNode::parse");
175     cursor->expectDigit("arg count", __LINE__);
176     int argc = cursor->getInt();
177     for (int i = 0; i < argc; i++) {
178         cursor->expect('(', __LINE__);
179         addChild(cursor, new ArgNode(this, i));
180         if (i < (argc - 1)) {
181             cursor->expect(',', __LINE__);
182         }
183     }
184     cursor->out();
185     return this;
186 }