Bug 2366 - new parser API - implementation of declared statements
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / rfc6020 / Utils.java
index 101038d94fcb377ae3cb1ebc4bbc136f2e57a0e2..aa9899850b4569c68892eb0ef08dcc2303775f7f 100644 (file)
  */
 package org.opendaylight.yangtools.yang.parser.stmt.rfc6020;
 
+import static org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils.firstAttributeOf;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+import org.antlr.v4.runtime.tree.TerminalNode;
+import org.opendaylight.yangtools.antlrv4.code.gen.YangStatementParser;
 import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier;
+import org.opendaylight.yangtools.yang.model.api.meta.StatementSource;
+import org.opendaylight.yangtools.yang.model.api.stmt.BelongsToStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ModuleStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.PrefixStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.SubmoduleStatement;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
+import org.opendaylight.yangtools.yang.parser.spi.source.BelongsToPrefixToModuleName;
+import org.opendaylight.yangtools.yang.parser.spi.source.ImpPrefixToModuleIdentifier;
+import org.opendaylight.yangtools.yang.parser.spi.source.ModuleIdentifierToModuleQName;
+import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNameToModuleQName;
 import org.opendaylight.yangtools.yang.parser.spi.source.PrefixToModule;
+import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
+import com.google.common.base.CharMatcher;
+import com.google.common.base.Splitter;
 
 public class Utils {
 
+    private static final CharMatcher DOUBLE_QUOTE_MATCHER = CharMatcher.is('"');
+    private static final CharMatcher SINGLE_QUOTE_MATCHER = CharMatcher.is('\'');
+
+    private static final char SEPARATOR_QNAME = '/';
+
+    private static final String REGEX_PATH_ABS = "/[^/].+";
+    private static final String REGEX_PATH_REL1 = "\\.\\.?\\s*/(.+)";
+    private static final String REGEX_PATH_REL2 = "//.*";
+
+    public static final StatementSourceReference CONTEXT_REF = new StatementSourceReference() {
+
+        @Override
+        public StatementSource getStatementSource() {
+            return StatementSource.CONTEXT;
+        }
+    };
+
+    public static void validateXPath(String path) {
+
+        final XPath xPath = XPathFactory.newInstance().newXPath();
+
+        try {
+            xPath.compile(path);
+        } catch (XPathExpressionException e) {
+            throw new IllegalArgumentException("An argument is not valid XPath string");
+        }
+    }
+
+    public static boolean isXPathAbsolute(String path) {
+
+        validateXPath(path);
+
+        return path.matches(REGEX_PATH_ABS);
+    }
+
+    public static Iterable<QName> parseXPath(StmtContext<?, ?, ?> ctx, String path) {
+
+        validateXPath(path);
 
-    public static QName qNameFromArgument(StmtContext<?,?,?> ctx, String value) {
-        // TODO: Implement real parsing
-        String prefix = "";
-        ctx.getFromNamespace(PrefixToModule.class, prefix);
+        Splitter keySplitter = Splitter.on(SEPARATOR_QNAME).omitEmptyStrings().trimResults();
+        List<String> nodeNames = keySplitter.splitToList(path);
+        List<QName> qNames = new ArrayList<>();
 
-        return QName.create(value);
+        for (String nodeName : nodeNames) {
+            try {
+                final QName qName = Utils.qNameFromArgument(ctx, nodeName);
+                qNames.add(qName);
+            } catch (Exception e) {
+                throw new IllegalArgumentException(e);
+            }
+        }
+
+        return qNames;
+    }
+
+    public static Iterable<QName> parseAugmentPath(StmtContext<?, ?, ?> ctx, String path) {
+
+        if (path.matches(REGEX_PATH_REL1) || path.matches(REGEX_PATH_REL2)) {
+            throw new IllegalArgumentException(
+                    "An argument for augment can be only absolute path; or descendant if used in uses");
+        }
+
+        return parseXPath(ctx, path);
+    }
+
+    public static String stringFromStringContext(final YangStatementParser.ArgumentContext context) {
+        StringBuilder sb = new StringBuilder();
+        List<TerminalNode> strings = context.STRING();
+        if (strings.size() == 0) {
+            strings = Arrays.asList(context.IDENTIFIER());
+        }
+        for (TerminalNode stringNode : strings) {
+            final String str = stringNode.getText();
+            char firstChar = str.charAt(0);
+            final CharMatcher quoteMatcher;
+            if (SINGLE_QUOTE_MATCHER.matches(firstChar)) {
+                quoteMatcher = SINGLE_QUOTE_MATCHER;
+            } else if (DOUBLE_QUOTE_MATCHER.matches(firstChar)) {
+                quoteMatcher = DOUBLE_QUOTE_MATCHER;
+            } else {
+                sb.append(str);
+                continue;
+            }
+            sb.append(quoteMatcher.removeFrom(str.substring(1, str.length() - 1)));
+        }
+        return sb.toString();
     }
 
+    public static QName qNameFromArgument(StmtContext<?, ?, ?> ctx, String value) {
+
+        String prefix = null;
+        QNameModule qNameModule = null;
+        try {
+            qNameModule = QNameModule.create(new URI(""), new Date(0));
+        } catch (URISyntaxException e) {
+            e.printStackTrace();
+        }
+        String localName = null;
 
+        String[] namesParts = value.split(":");
+        switch (namesParts.length) {
+        case 1:
+            localName = namesParts[0];
+
+            if (StmtContextUtils.producesDeclared(ctx.getRoot(), ModuleStatement.class)) {
+                prefix = firstAttributeOf(ctx.getRoot().declaredSubstatements(), PrefixStatement.class);
+                qNameModule = ctx.getFromNamespace(PrefixToModule.class, prefix);
+
+            } else if (StmtContextUtils.producesDeclared(ctx.getRoot(), SubmoduleStatement.class)) {
+                String belongsToModuleName = firstAttributeOf(ctx.getRoot().declaredSubstatements(),
+                        BelongsToStatement.class);
+                qNameModule = ctx.getFromNamespace(ModuleNameToModuleQName.class, belongsToModuleName);
+            }
+            break;
+        case 2:
+            prefix = namesParts[0];
+            localName = namesParts[1];
+
+            ModuleIdentifier impModIdentifier = ctx.getRoot().getFromNamespace(ImpPrefixToModuleIdentifier.class,
+                    prefix);
+            qNameModule = ctx.getFromNamespace(ModuleIdentifierToModuleQName.class, impModIdentifier);
+
+            if (qNameModule == null && StmtContextUtils.producesDeclared(ctx.getRoot(), SubmoduleStatement.class)) {
+                String moduleName = ctx.getRoot().getFromNamespace(BelongsToPrefixToModuleName.class, prefix);
+                qNameModule = ctx.getFromNamespace(ModuleNameToModuleQName.class, moduleName);
+            }
+
+            break;
+        default:
+            break;
+        }
+
+        return QName.create(qNameModule, localName);
+    }
 }