/* * $Id$ * * Copyright (C) 2003-2015 JNode.org * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; If not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ package org.jnode.shell.syntax; import java.util.ArrayList; import java.util.List; /** * The SyntaxSpecLoader traverses a syntax specification (e.g. in XML) wrapped * in an adapter, and creates a Syntax tree. * * @author crawley@jnode.org */ public class SyntaxSpecLoader { public SyntaxBundle loadSyntax(SyntaxSpecAdapter element) { final String alias = element.getAttribute("alias"); if (alias == null) { throw new SyntaxFailureException("syntax element has no 'alias' attribute"); } final String description = element.getAttribute("description"); int nos = element.getNosChildren(); List<Syntax> childSyntaxes = new ArrayList<Syntax>(nos); for (int i = 0; i < nos; i++) { childSyntaxes.add(doLoad(element.getChild(i))); } return new SyntaxBundle(alias, description, childSyntaxes.toArray(new Syntax[childSyntaxes.size()])); } private Syntax doLoad(SyntaxSpecAdapter syntaxElement) throws SyntaxFailureException, IllegalArgumentException { String label = syntaxElement.getAttribute("label"); String description = syntaxElement.getAttribute("description"); String kind = syntaxElement.getName(); if (kind.equals("empty")) { return new EmptySyntax(label, description); } else if (kind.equals("alternatives")) { int nos = syntaxElement.getNosChildren(); Syntax[] alts = new Syntax[nos]; for (int i = 0; i < nos; i++) { alts[i] = doLoad(syntaxElement.getChild(i)); } return new AlternativesSyntax(label, description, alts); } else if (kind.equals("optionSet")) { int nos = syntaxElement.getNosChildren(); OptionSyntax[] options = new OptionSyntax[nos]; for (int i = 0; i < nos; i++) { try { options[i] = (OptionSyntax) doLoad(syntaxElement.getChild(i)); } catch (ClassCastException ex) { throw new SyntaxFailureException( "<optionSyntax> element can only contain <option> elements"); } } return new OptionSetSyntax(label, description, options); } else if (kind.equals("option")) { String argLabel = syntaxElement.getAttribute("argLabel"); if (argLabel == null) { throw new SyntaxFailureException("<option> element has no 'argLabel' attribute"); } String shortName = syntaxElement.getAttribute("shortName"); String longName = syntaxElement.getAttribute("longName"); String flags = syntaxElement.getAttribute("flags"); if (shortName == null) { if (longName == null) { throw new SyntaxFailureException( "<option> element has must have a 'shortName' or 'longName' attribute"); } return new OptionSyntax(argLabel, longName, flags, description); } else { if (shortName.length() != 1) { throw new SyntaxFailureException( "<option> elements 'shortName' attribute must be one character long"); } if (longName == null) { return new OptionSyntax(argLabel, shortName.charAt(0), flags, description); } else { return new OptionSyntax(argLabel, longName, shortName.charAt(0), flags, description); } } } else if (kind.equals("powerset")) { int nos = syntaxElement.getNosChildren(); boolean eager = getFlag(syntaxElement, "eager", false); Syntax[] members = new Syntax[nos]; for (int i = 0; i < nos; i++) { members[i] = doLoad(syntaxElement.getChild(i)); } return new PowersetSyntax(label, eager, description, members); } else if (kind.equals("repeat")) { int nos = syntaxElement.getNosChildren(); boolean eager = getFlag(syntaxElement, "eager", false); int minCount = getCount(syntaxElement, "minCount", 0); int maxCount = getCount(syntaxElement, "maxCount", Integer.MAX_VALUE); Syntax[] members = new Syntax[nos]; for (int i = 0; i < nos; i++) { members[i] = doLoad(syntaxElement.getChild(i)); } Syntax childSyntax = (members.length == 1) ? members[0] : new SequenceSyntax(members); return new RepeatSyntax(label, childSyntax, minCount, maxCount, eager, description); } else if (kind.equals("sequence")) { int nos = syntaxElement.getNosChildren(); Syntax[] seq = new Syntax[nos]; for (int i = 0; i < nos; i++) { seq[i] = doLoad(syntaxElement.getChild(i)); } return new SequenceSyntax(label, description, seq); } else if (kind.equals("optional")) { boolean eager = getFlag(syntaxElement, "eager", false); int nos = syntaxElement.getNosChildren(); Syntax[] seq = new Syntax[nos]; for (int i = 0; i < nos; i++) { seq[i] = doLoad(syntaxElement.getChild(i)); } return new OptionalSyntax(label, description, eager, seq); } else if (kind.equals("argument")) { String argLabel = syntaxElement.getAttribute("argLabel"); String flags = syntaxElement.getAttribute("flags"); if (argLabel == null) { System.out.println(syntaxElement); throw new SyntaxFailureException("<argument> element has no 'argLabel' attribute"); } return new ArgumentSyntax(label, argLabel, flags, description); } else if (kind.equals("verb")) { String symbol = syntaxElement.getAttribute("symbol"); if (symbol == null) { throw new SyntaxFailureException("<verb> element has no 'symbol' attribute"); } String argLabel = syntaxElement.getAttribute("argLabel"); if (argLabel == null) { System.out.println(syntaxElement); throw new SyntaxFailureException("<argument> element has no 'argLabel' attribute"); } String flags = syntaxElement.getAttribute("flags"); return new VerbSyntax(label, symbol, argLabel, flags, description); } else if (kind.equals("symbol")) { String symbol = syntaxElement.getAttribute("symbol"); if (symbol == null) { throw new SyntaxFailureException("<symbol> element has no 'symbol' attribute"); } return new SymbolSyntax(label, symbol, description); } else { throw new SyntaxFailureException("<" + kind + "> element does not represent a known syntax"); } } private int getCount(SyntaxSpecAdapter element, String name, int defaultValue) { String tmp = element.getAttribute(name); if (tmp == null) { return defaultValue; } else { try { return Integer.parseInt(tmp); } catch (NumberFormatException ex) { throw new SyntaxFailureException("'" + name + "' attribute is not an integer"); } } } private boolean getFlag(SyntaxSpecAdapter element, String name, boolean defaultValue) { String tmp = element.getAttribute(name); if (tmp == null) { return defaultValue; } else if (tmp.equalsIgnoreCase("true")) { return true; } else if (tmp.equalsIgnoreCase("false")) { return true; } else { throw new SyntaxFailureException("'" + name + "' attribute is not 'true' or 'false'"); } } }