/** * Expand all configured keywords * * @param drl * @return */ private String expandKeywords(String drl) { // apply all keywords templates for (final DSLMappingEntry entry : this.keywords) { drl = entry.getKeyPattern().matcher(drl).replaceAll(entry.getValuePattern()); } return drl; }
/** * Clean up constructions that exists only in the unexpanded code * * @param drl * @return */ private String cleanupExpressions(String drl) { // execute cleanup for (final DSLMappingEntry entry : this.cleanup) { drl = entry.getKeyPattern().matcher(drl).replaceAll(entry.getValuePattern()); } return drl; }
@Test public void testParseFileWithEscaptedBrackets() { String file = "[when]ATTRIBUTE \"{attr}\" IS IN \\[{list}\\]=Attribute( {attr} in ({list}) )"; try { final Reader reader = new StringReader(file); this.file = new DSLTokenizedMappingFile(); final boolean parsingResult = this.file.parseAndLoad(reader); reader.close(); assertTrue(this.file.getErrors().toString(), parsingResult); assertTrue(this.file.getErrors().isEmpty()); assertEquals(1, this.file.getMapping().getEntries().size()); DSLMappingEntry entry = (DSLMappingEntry) this.file.getMapping().getEntries().get(0); assertEquals(DSLMappingEntry.CONDITION, entry.getSection()); assertEquals(DSLMappingEntry.EMPTY_METADATA, entry.getMetaData()); assertEquals( lookbehind + "ATTRIBUTE\\s+\"(.*?)\"\\s+IS\\s+IN\\s+\\[(.*?)\\](?=\\W|$)", entry.getKeyPattern().toString()); // Attribute( {attr} in ({list}) ) assertEquals("Attribute( {attr} in ({list}) )", entry.getValuePattern()); } catch (final IOException e) { e.printStackTrace(); fail("Should not raise exception "); } }
@Test public void testParseFileWithEscaptedEquals() { String file = "[when]something:\\={value}=Attribute( something == \"{value}\" )"; try { final Reader reader = new StringReader(file); this.file = new DSLTokenizedMappingFile(); final boolean parsingResult = this.file.parseAndLoad(reader); reader.close(); assertTrue(this.file.getErrors().toString(), parsingResult); assertTrue(this.file.getErrors().isEmpty()); assertEquals(1, this.file.getMapping().getEntries().size()); DSLMappingEntry entry = (DSLMappingEntry) this.file.getMapping().getEntries().get(0); assertEquals(DSLMappingEntry.CONDITION, entry.getSection()); assertEquals(DSLMappingEntry.EMPTY_METADATA, entry.getMetaData()); assertEquals(lookbehind + "something:\\=(.*?)$", entry.getKeyPattern().toString()); assertEquals("Attribute( something == \"{value}\" )", entry.getValuePattern()); } catch (final IOException e) { e.printStackTrace(); fail("Should not raise exception "); } }
/** * Add the new mapping to this expander. * * @param mapping */ public void addDSLMapping(final DSLMapping mapping) { for (DSLMappingEntry entry : mapping.getEntries()) { if (DSLMappingEntry.KEYWORD.equals(entry.getSection())) { this.keywords.add(entry); } else if (DSLMappingEntry.CONDITION.equals(entry.getSection())) { this.condition.add(entry); } else if (DSLMappingEntry.CONSEQUENCE.equals(entry.getSection())) { this.consequence.add(entry); } else { // if any, then add to them both condition and consequence this.condition.add(entry); this.consequence.add(entry); } } if (mapping.getOption("result")) showResult = true; if (mapping.getOption("steps")) showSteps = true; if (mapping.getOption("keyword")) showThen = true; if (mapping.getOption("when")) showWhen = true; if (mapping.getOption("then")) showThen = true; }
/** * Perform the substitutions. * * @param exp a DSLR source line to be expanded * @param entries the appropriate DSL keys and values * @param line line number * @return the expanden line */ private String substitute(String exp, List<DSLMappingEntry> entries, int line) { if (entries.size() == 0) { this.addError(new ExpanderException("No mapping entries for expanding: " + exp, line)); return exp; } if (showSteps) { System.out.println("to expand: |" + exp + "|"); } Map<String, String> key2value = new HashMap<String, String>(); for (final DSLMappingEntry entry : entries) { Map<String, Integer> vars = entry.getVariables(); String vp = entry.getValuePattern(); Pattern kp = entry.getKeyPattern(); Matcher m = kp.matcher(exp); int startPos = 0; boolean match = false; while (startPos < exp.length() && m.find(startPos)) { match = true; if (showSteps) { System.out.println(" matches: " + kp.toString()); } // Replace the range of group 0. String target = m.group(0); if (!vars.keySet().isEmpty()) { // Build a pattern matching any variable enclosed in braces. StringBuilder sb = new StringBuilder(); String del = "\\{("; for (String key : vars.keySet()) { sb.append(del).append(Pattern.quote(key)); del = "|"; } sb.append(")(?:!(uc|lc|ucfirst|num|.*))?\\}"); Pattern allkeyPat = Pattern.compile(sb.toString()); Matcher allkeyMat = allkeyPat.matcher(vp); // While the pattern matches, get the actual key and replace by '$' + index while (allkeyMat.find()) { String theKey = allkeyMat.group(1); String theFunc = allkeyMat.group(2); String theValue = m.group(vars.get(theKey)); if (theFunc != null) { if ("uc".equals(theFunc)) { theValue = theValue.toUpperCase(); } else if ("lc".equals(theFunc)) { theValue = theValue.toLowerCase(); } else if ("ucfirst".equals(theFunc) && theValue.length() > 0) { theValue = theValue.substring(0, 1).toUpperCase() + theValue.substring(1).toLowerCase(); } else if (theFunc.startsWith("num")) { // kill all non-digits, but keep '-' String numStr = theValue.replaceAll("[^-\\d]+", ""); try { long numLong = Long.parseLong(numStr); if (theValue.matches("^.*[.,]\\d\\d(?:\\D.*|$)")) { numStr = Long.toString(numLong); theValue = numStr.substring(0, numStr.length() - 2) + '.' + numStr.substring(numStr.length() - 2); } else { theValue = Long.toString(numLong); } } catch (NumberFormatException nfe) { // silently ignore - keep the value as it is } } else { StringTokenizer strTok = new StringTokenizer(theFunc, "?/", true); boolean compare = true; int toks = strTok.countTokens(); while (toks >= 4) { String key = strTok.nextToken(); String qmk = strTok.nextToken(); // '?' String val = strTok.nextToken(); // to use String sep = strTok.nextToken(); // '/' if (key.equals(theValue)) { theValue = val; break; } toks -= 4; if (toks < 4) { theValue = strTok.nextToken(); break; } } } } vp = vp.substring(0, allkeyMat.start()) + theValue + vp.substring(allkeyMat.end()); allkeyMat.reset(vp); key2value.put(theKey, theValue); } } // Try to find any matches from previous lines. Matcher varRefMat = varRefPat.matcher(vp); while (varRefMat.find()) { String theKey = varRefMat.group(1); for (int ientry = substitutions.size() - 1; ientry >= 0; ientry--) { String theValue = substitutions.get(ientry).get(theKey); if (theValue != null) { // replace it vp = vp.substring(0, varRefMat.start()) + theValue + vp.substring(varRefMat.end()); varRefMat.reset(vp); break; } } } // add the new set of substitutions if (key2value.size() > 0) { substitutions.add(key2value); } // now replace the target exp = exp.substring(0, m.start()) + vp + exp.substring(m.end()); if (match && showSteps) { System.out.println(" result: |" + exp + "|"); } startPos = m.start() + vp.length(); m.reset(exp); } } return exp; }
/** * Expand constructions like rules and queries * * @param drl * @return */ private StringBuffer expandConstructions(final String drl) { // display keys if requested if (showKeyword) { for (DSLMappingEntry entry : this.keywords) { System.out.println("keyword: " + entry.getMappingKey()); System.out.println(" " + entry.getKeyPattern()); } } if (showWhen) { for (DSLMappingEntry entry : this.condition) { System.out.println("when: " + entry.getMappingKey()); System.out.println(" " + entry.getKeyPattern()); // System.out.println( " " + entry.getValuePattern() ); } } if (showThen) { for (DSLMappingEntry entry : this.consequence) { System.out.println("then: " + entry.getMappingKey()); System.out.println(" " + entry.getKeyPattern()); } } // parse and expand specific areas final Matcher m = finder.matcher(drl); final StringBuffer buf = new StringBuffer(); int drlPos = 0; int linecount = 0; while (m.find()) { final StringBuilder expanded = new StringBuilder(); int newPos = m.start(); linecount += countNewlines(drl, drlPos, newPos); drlPos = newPos; String constr = m.group().trim(); if (constr.startsWith("rule")) { String headerFragment = m.group(1); expanded.append(headerFragment); // adding rule header and attributes String lhsFragment = m.group(2); expanded.append( this.expandLHS(lhsFragment, linecount + countNewlines(drl, drlPos, m.start(2)) + 1)); String thenFragment = m.group(3); expanded.append(thenFragment); // adding "then" header String rhsFragment = this.expandRHS(m.group(4), linecount + countNewlines(drl, drlPos, m.start(4)) + 1); expanded.append(rhsFragment); expanded.append(m.group(5)); // adding rule trailer } else if (constr.startsWith("query")) { String fragment = m.group(6); expanded.append(fragment); // adding query header and attributes String lhsFragment = this.expandLHS(m.group(7), linecount + countNewlines(drl, drlPos, m.start(7)) + 1); expanded.append(lhsFragment); expanded.append(m.group(8)); // adding query trailer } else { // strange behavior this.addError(new ExpanderException("Unable to expand statement: " + constr, 0)); } m.appendReplacement(buf, Matcher.quoteReplacement(expanded.toString())); } m.appendTail(buf); return buf; }