Changeset 12697
- Timestamp:
- May 2, 2019 8:42:46 AM (7 months ago)
- Location:
- trunk/Compiler/ModelicaFrontEnd
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Compiler/ModelicaFrontEnd/src/java/org/jmodelica/util/QualifiedName.java
r12695 r12697 16 16 package org.jmodelica.util; 17 17 18 import java.io.IOException;19 import java.io.StringReader;20 18 import java.util.ArrayList; 21 import java.util.Iterator; 19 import java.util.regex.Matcher; 20 import java.util.regex.Pattern; 22 21 23 import org.jmodelica.modelica.parser.ModelicaParser.Terminals;24 import org.jmodelica.modelica.parser.ModelicaScanner;25 22 import org.jmodelica.util.exceptions.NameFormatException; 26 27 import beaver.Scanner.Exception;28 import beaver.Symbol;29 23 30 24 /** … … 32 26 */ 33 27 public class QualifiedName { 34 private finalboolean isGlobal;35 private final ArrayList<String> names = new ArrayList<>();36 private final boolean isUnQualifiedImport;37 private final Iterator<String> iterator;28 private boolean isGlobal; 29 private int i = 0; 30 ArrayList<String> names; 31 private boolean isUnQualifiedImport; 38 32 39 33 public QualifiedName(String name) { 34 if (name.length() == 0) { 35 throw new NameFormatException("A name must have atleast one caracter"); 36 } 40 37 isUnQualifiedImport = name.endsWith(".*"); 41 38 isGlobal = name.startsWith("."); 42 splitQualifiedClassName(name); 43 iterator = names.iterator(); 39 names = splitQualifiedClassName(name); 44 40 } 45 41 46 // Interpret name as global or not regardless o fdot form or not.42 // Interpret name as global or not regardless or dot form or not. 47 43 public QualifiedName(String name, boolean isGlobal) { 48 isUnQualifiedImport = name.endsWith(".*"); 49 splitQualifiedClassName(name); 50 this.isGlobal = isGlobal; // Note: must be set after splitting 51 iterator = names.iterator(); 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(); 52 53 } 53 54 … … 55 56 return names.size(); 56 57 } 57 58 public boolean hasNext() { 59 return iterator.hasNext(); 60 } 61 62 public String next() { 63 return iterator.next(); 58 59 /** 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. 63 */ 64 public static int numberOfParts(String name) { 65 boolean isGlobal = name.startsWith("."); 66 if (isGlobal) { 67 name = name.substring(1, name.length()); 68 } 69 Matcher m = p.matcher(name); 70 ArrayList<Integer> nameSeparations = new ArrayList<Integer>(); 71 findNameSeparations(m, nameSeparations); 72 return nameSeparations.size() + 1; 64 73 } 65 74 66 /** 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. 72 */ 73 public static boolean isValidSimpleIdentifier(String name, boolean allowGlobal) { 74 if (allowGlobal && name.startsWith(".")) { 75 name = name.substring(1, name.length()); 76 } 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 } 75 public String next() { 76 return names.get(i++); 77 } 78 79 public ArrayList<String> getNames() { 80 return names; 91 81 } 92 82 93 83 @Override 94 84 public String toString() { 95 return (isGlobal ? "(global) " : "") + (isUnQualifiedImport ? ".* " : "") +names.toString();85 return names.toString(); 96 86 } 97 87 … … 100 90 } 101 91 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 } 119 } 120 if (inquoted) { 121 throw new NameFormatException("Qualified Name couldn't be interpreted due to unmatched quotes"); 122 } 123 } 124 102 125 /** 103 * Splits a composite class name into all its partial accesses 126 * Splits a composite class name into all the partial access 127 * 128 * @param name 129 * @return array with the names of all accessed classes. 104 130 */ 105 private final void splitQualifiedClassName(String name) { 106 if (name.length() == 0) { 107 throw new NameFormatException("A name must have at least one caracter"); 108 } 131 private final ArrayList<String> splitQualifiedClassName(String name) { 109 132 if (isGlobal || isUnQualifiedImport) { 110 133 int start = isGlobal ? 1 : 0; … … 112 135 name = name.substring(start, end); 113 136 } 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); 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); 131 146 } 147 return parts; 132 148 } 133 149 } -
trunk/Compiler/ModelicaFrontEnd/test/junit/org/jmodelica/test/common/QualifiedNameTest.java
r12694 r12697 2 2 3 3 import static org.junit.Assert.assertEquals; 4 import static org.junit.Assert.assertTrue;5 import static org.junit.Assert.assertFalse;6 4 7 5 import org.jmodelica.util.QualifiedName; … … 13 11 @Test 14 12 public void globalWithQuotedContainingExcapedDot() { 15 assertEquals(" (global)['quotedWith.Dot\\'.', secondPart]",13 assertEquals("['quotedWith.Dot\\'.', secondPart]", 16 14 new QualifiedName(".'quotedWith.Dot\\'.'.secondPart").toString()); 17 15 } … … 19 17 @Test 20 18 public void globalDotted() { 21 assertEquals(" (global)[first, second, third]",19 assertEquals("[first, second, third]", 22 20 new QualifiedName(".first.second.third").toString()); 23 21 } … … 25 23 @Test 26 24 public void global() { 27 assertEquals(" (global)[global]",25 assertEquals("[global]", 28 26 new QualifiedName(".global").toString()); 29 27 } … … 54 52 @Test 55 53 public void countNumberOfParts() { 56 assertEquals(4, new QualifiedName( "A.'B'.C.D").numberOfParts());54 assertEquals(4, new QualifiedName(("A.'B'.C.D")).numberOfParts()); 57 55 } 58 56 59 57 @Test 60 58 public void nonSimpleNameParts() { 61 assertEquals(4, new QualifiedName(".A.'B'.C.D").numberOfParts());59 assertEquals(4, QualifiedName.numberOfParts(".A.'B'.C.D")); 62 60 } 63 61 64 62 @Test 65 63 public void globalSimpleNameParts() { 66 assert True(QualifiedName.isValidSimpleIdentifier(".'A'", true));64 assertEquals(1, QualifiedName.numberOfParts(".'A'")); 67 65 } 68 69 @Test 70 public void globalSimpleNamePartsNegative() { 71 assertFalse(QualifiedName.isValidSimpleIdentifier(".'A'", false)); 72 } 73 66 74 67 @Test 75 68 public void nameFromUnqualifiedImport() { 76 assertEquals(" .*[A, B, C]", new QualifiedName("A.B.C.*").toString());69 assertEquals("[A, B, C]", new QualifiedName("A.B.C.*").toString()); 77 70 } 78 71
Note: See TracChangeset
for help on using the changeset viewer.