Changeset 12700
- Timestamp:
- May 2, 2019 1:00:03 PM (7 months ago)
- Location:
- trunk/Compiler/ModelicaFrontEnd
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Compiler/ModelicaFrontEnd/src/java/org/jmodelica/util/QualifiedName.java
r12697 r12700 16 16 package org.jmodelica.util; 17 17 18 import java.io.IOException; 19 import java.io.StringReader; 18 20 import java.util.ArrayList; 19 import java.util.regex.Matcher; 20 import java.util.regex.Pattern; 21 import java.util.Iterator; 21 22 23 import org.jmodelica.modelica.parser.ModelicaParser.Terminals; 24 import org.jmodelica.modelica.parser.ModelicaScanner; 22 25 import org.jmodelica.util.exceptions.NameFormatException; 26 27 import beaver.Scanner.Exception; 28 import beaver.Symbol; 23 29 24 30 /** … … 26 32 */ 27 33 public class QualifiedName { 28 private boolean isGlobal;29 private int i = 0;30 ArrayList<String> names;31 private boolean isUnQualifiedImport;34 private final boolean isGlobal; 35 private final ArrayList<String> names = new ArrayList<>(); 36 private final boolean isUnQualifiedImport; 37 private final Iterator<String> iterator; 32 38 33 39 public QualifiedName(String name) { 34 if (name.length() == 0) {35 throw new NameFormatException("A name must have atleast one caracter");36 }37 40 isUnQualifiedImport = name.endsWith(".*"); 38 41 isGlobal = name.startsWith("."); 39 names = splitQualifiedClassName(name); 42 splitQualifiedClassName(name); 43 iterator = names.iterator(); 40 44 } 41 45 42 // Interpret name as global or not regardless o rdot form or not.46 // Interpret name as global or not regardless of dot form or not. 43 47 public QualifiedName(String name, boolean isGlobal) { 44 if (name.length() == 0) { 45 throw new NameFormatException("A name must have atleast one caracter"); 46 } 47 names = splitQualifiedClassName(name); 48 this.isGlobal = isGlobal; 49 } 50 51 public boolean hasNext() { 52 return i < names.size(); 48 isUnQualifiedImport = name.endsWith(".*"); 49 splitQualifiedClassName(name); 50 this.isGlobal = isGlobal; // Note: must be set after splitting 51 iterator = names.iterator(); 53 52 } 54 53 … … 56 55 return names.size(); 57 56 } 57 58 public boolean hasNext() { 59 return iterator.hasNext(); 60 } 61 62 public String next() { 63 return iterator.next(); 64 } 58 65 59 66 /** 60 * Only parse if the name is not simple, don't store the actual parts. 61 * Skips some work. 62 * @return if the name has only a single part. 67 * Checks if the name is a valid and simple (unqualified) identifier. 68 * @param name The name. 69 * @param allowGlobal If <code>true</code>, then takes 'global' notation with a leading dot into account by 70 * ignoring such a character. 71 * @return Whether or not <code>name</code> is a valid identifier. 63 72 */ 64 public static int numberOfParts(String name) { 65 boolean isGlobal = name.startsWith("."); 66 if (isGlobal) { 73 public static boolean isValidSimpleIdentifier(String name, boolean allowGlobal) { 74 if (allowGlobal && name.startsWith(".")) { 67 75 name = name.substring(1, name.length()); 68 76 } 69 Matcher m = p.matcher(name); 70 ArrayList<Integer> nameSeparations = new ArrayList<Integer>(); 71 findNameSeparations(m, nameSeparations); 72 return nameSeparations.size() + 1; 73 } 74 75 public String next() { 76 return names.get(i++); 77 } 78 79 public ArrayList<String> getNames() { 80 return names; 77 ModelicaScanner ms = new ModelicaScanner(new StringReader(name)); 78 try { 79 if (ms.nextToken().getId() != Terminals.ID) 80 return false; 81 if (ms.nextToken().getId() != Terminals.EOF) 82 return false; 83 return true; 84 } catch (IOException e) { 85 // This shouldn't happen when using a StringReader. 86 throw new RuntimeException("Unhandled internal error", e); 87 } catch (Exception e) { 88 // Scanner cannot handle this, so this is not a valid identifier. 89 return false; 90 } 81 91 } 82 92 83 93 @Override 84 94 public String toString() { 85 return names.toString();95 return (isGlobal ? "(global) " : "") + (isUnQualifiedImport ? ".* " : "") + names.toString(); 86 96 } 87 97 … … 90 100 } 91 101 92 static final Pattern p = Pattern.compile("(?<![\\\\])['.]"); 93 94 private static void checkNameLength(int start,int end) { 95 if (end - start < 2) 96 throw new NameFormatException("Names must have a length greater than zero"); 97 } 98 99 private static void findNameSeparations(Matcher m, ArrayList<Integer> list) { 100 boolean inquoted = false; 101 int prev = -1; 102 while (m.find()) { 103 String token = m.group(); 104 if (token.equals("'")) { 105 if (inquoted) { 106 checkNameLength(prev, m.start()); 107 } else { 108 if (m.start() - prev > 2) { 109 throw new NameFormatException("Quotes not allowed inside unqouted name"); 110 } 111 } 112 prev = inquoted ? prev : m.start(); 113 inquoted = !inquoted; 114 } else if (!inquoted) { 115 checkNameLength(prev, m.start()); 116 prev = m.start(); 117 list.add(m.start() + 1); 118 } 102 /** 103 * Splits a composite class name into all its partial accesses 104 */ 105 private final void splitQualifiedClassName(String name) { 106 if (name.length() == 0) { 107 throw new NameFormatException("A name must have at least one caracter"); 119 108 } 120 if (inquoted) {121 throw new NameFormatException("Qualified Name couldn't be interpreted due to unmatched quotes");122 }123 }124 125 /**126 * Splits a composite class name into all the partial access127 *128 * @param name129 * @return array with the names of all accessed classes.130 */131 private final ArrayList<String> splitQualifiedClassName(String name) {132 109 if (isGlobal || isUnQualifiedImport) { 133 110 int start = isGlobal ? 1 : 0; … … 135 112 name = name.substring(start, end); 136 113 } 137 Matcher m = p.matcher(name); 138 ArrayList<Integer> nameSeparations = new ArrayList<Integer>(); 139 findNameSeparations(m, nameSeparations); 140 nameSeparations.add(name.length() + 1); 141 ArrayList<String> parts = new ArrayList<String>(); 142 int partEnd = 0; 143 for (int namePart = 0; namePart < nameSeparations.size() ; namePart++) { 144 parts.add(name.substring(partEnd, nameSeparations.get(namePart) - 1)); 145 partEnd = nameSeparations.get(namePart); 114 ModelicaScanner ms = new ModelicaScanner(new StringReader(name)); 115 try { 116 Symbol sym; 117 do { 118 sym = ms.nextToken(); 119 if (sym.getId() != Terminals.ID) 120 throw new NameFormatException("The qualified name is not valid"); 121 names.add((String)sym.value); 122 } while ((sym = ms.nextToken()).getId() == Terminals.DOT); 123 if (sym.getId() != Terminals.EOF) 124 throw new NameFormatException("Invalid name: " + name); 125 } catch (IOException e) { 126 // This shouldn't happen when using a StringReader. 127 throw new RuntimeException("Unhandled internal error", e); 128 } catch (Exception e) { 129 // Identifier not valid. 130 throw new NameFormatException("Invalid name: " + name); 146 131 } 147 return parts;148 132 } 149 133 } -
trunk/Compiler/ModelicaFrontEnd/test/junit/org/jmodelica/test/common/QualifiedNameTest.java
r12697 r12700 2 2 3 3 import static org.junit.Assert.assertEquals; 4 import static org.junit.Assert.assertTrue; 5 import static org.junit.Assert.assertFalse; 4 6 5 7 import org.jmodelica.util.QualifiedName; … … 11 13 @Test 12 14 public void globalWithQuotedContainingExcapedDot() { 13 assertEquals(" ['quotedWith.Dot\\'.', secondPart]",15 assertEquals("(global) ['quotedWith.Dot\\'.', secondPart]", 14 16 new QualifiedName(".'quotedWith.Dot\\'.'.secondPart").toString()); 15 17 } … … 17 19 @Test 18 20 public void globalDotted() { 19 assertEquals(" [first, second, third]",21 assertEquals("(global) [first, second, third]", 20 22 new QualifiedName(".first.second.third").toString()); 21 23 } … … 23 25 @Test 24 26 public void global() { 25 assertEquals(" [global]",27 assertEquals("(global) [global]", 26 28 new QualifiedName(".global").toString()); 27 29 } … … 52 54 @Test 53 55 public void countNumberOfParts() { 54 assertEquals(4, new QualifiedName( ("A.'B'.C.D")).numberOfParts());56 assertEquals(4, new QualifiedName("A.'B'.C.D").numberOfParts()); 55 57 } 56 58 57 59 @Test 58 60 public void nonSimpleNameParts() { 59 assertEquals(4, QualifiedName.numberOfParts(".A.'B'.C.D"));61 assertEquals(4, new QualifiedName(".A.'B'.C.D").numberOfParts()); 60 62 } 61 63 62 64 @Test 63 65 public void globalSimpleNameParts() { 64 assert Equals(1, QualifiedName.numberOfParts(".'A'"));66 assertTrue(QualifiedName.isValidSimpleIdentifier(".'A'", true)); 65 67 } 66 68 69 @Test 70 public void globalSimpleNamePartsNegative() { 71 assertFalse(QualifiedName.isValidSimpleIdentifier(".'A'", false)); 72 } 73 67 74 @Test 68 75 public void nameFromUnqualifiedImport() { 69 assertEquals(" [A, B, C]", new QualifiedName("A.B.C.*").toString());76 assertEquals(".* [A, B, C]", new QualifiedName("A.B.C.*").toString()); 70 77 } 71 78
Note: See TracChangeset
for help on using the changeset viewer.