7e114afad563fa58a8d3de5b1774c1596ac457cb
[smo/teiv.git] /
1 /*
2  *  ============LICENSE_START=======================================================
3  *  Copyright (C) 2024 Ericsson
4  *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
5  *  ================================================================================
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *        http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License.
17  *
18  *  SPDX-License-Identifier: Apache-2.0
19  *  ============LICENSE_END=========================================================
20  */
21 package org.oran.smo.yangtools.parser.model.yangdom;
22
23 import org.oran.smo.yangtools.parser.ParserExecutionContext;
24 import org.oran.smo.yangtools.parser.findings.Finding;
25 import org.oran.smo.yangtools.parser.findings.ParserFindingType;
26 import org.oran.smo.yangtools.parser.model.YangModel;
27 import org.oran.smo.yangtools.parser.model.parser.Token;
28 import org.oran.smo.yangtools.parser.model.parser.TokenIterator;
29 import org.oran.smo.yangtools.parser.model.parser.Token.TokenType;
30 import org.oran.smo.yangtools.parser.model.schema.Schema;
31
32 /**
33  * Root element for a YANG DOM. Serves as entry point into the DOM and has no
34  * representation in the YAM.
35  * <p/>
36  * For compliant YAMs, will only ever have a single child DOM element (with a name
37  * of 'module' or 'submodule').
38  *
39  * @author Mark Hollmann
40  */
41 public class YangDomDocumentRoot extends YangDomElement {
42
43     private final YangModel yangModel;
44
45     /**
46      * The schema that owns this YANG DOM.
47      */
48     private final Schema owningSchema;
49
50     /**
51      * Indicates that a change has been made to the DOM (perhaps due to modifications being made).
52      */
53     private boolean domModified;
54
55     public YangDomDocumentRoot(final YangModel yangModel, final Schema owningSchema) {
56         super("/", "/", null, 0);
57         this.yangModel = yangModel;
58         this.owningSchema = owningSchema;
59     }
60
61     @Override
62     public YangModel getYangModel() {
63         return yangModel;
64     }
65
66     public Schema getOwningSchema() {
67         return owningSchema;
68     }
69
70     public void setDomHasBeenModified() {
71         domModified = true;
72     }
73
74     public boolean domHasBeenModified() {
75         return domModified;
76     }
77
78     /**
79      * Processes the token stream and recursively builds the DOM tree.
80      */
81     @Override
82     public void processTokens(final ParserExecutionContext context, final TokenIterator iter) {
83         /*
84          * Document root is a special case. It does not start or end with a brace. The expected format is:
85          *
86          * <statement> <argument> { ... stuff ... }
87          *
88          * And the only statement there should ever be is a "module" or "sub-module" statement.
89          */
90
91         if (iter.done()) {
92             context.addFinding(new Finding(yangModel, ParserFindingType.P013_INVALID_SYNTAX_AT_DOCUMENT_ROOT,
93                     "Document seems empty."));
94             return;
95         }
96
97         final Token token1 = iter.getToken(0);
98         final Token token2 = iter.getToken(1);
99         final Token token3 = iter.getToken(2);
100
101         if (token2 == null || token3 == null) {
102             context.addFinding(new Finding(yangModel, ParserFindingType.P013_INVALID_SYNTAX_AT_DOCUMENT_ROOT,
103                     "Missing content at the beginning of the document."));
104             return;
105         }
106
107         if (!token1.value.equals("module") && !token1.value.equals("submodule")) {
108             context.addFinding(new Finding(yangModel, ParserFindingType.P013_INVALID_SYNTAX_AT_DOCUMENT_ROOT,
109                     "Expected 'module' or 'submodule' at the beginning of the document."));
110             return;
111         }
112
113         if (token3.type == TokenType.LEFT_BRACE) {
114             final YangDomElement newYangDomNode = new YangDomElement(token1.value, token2.value, this, token1.lineNumber);
115             iter.advance(2);
116             newYangDomNode.processTokens(context, iter);
117         } else {
118             context.addFinding(new Finding(yangModel, token3.lineNumber,
119                     ParserFindingType.P013_INVALID_SYNTAX_AT_DOCUMENT_ROOT.toString(),
120                     "Expected opening brace '{' after (sub)module name."));
121             return;
122         }
123
124         if (!iter.done()) {
125             final Token leftoverToken = iter.getToken(0);
126             context.addFinding(new Finding(yangModel, leftoverToken.lineNumber,
127                     ParserFindingType.P014_INVALID_SYNTAX_AT_DOCUMENT_END.toString(),
128                     "Unexpected content at end of document. Check curly braces balance throughout document."));
129         }
130     }
131 }