svnno****@sourc*****
svnno****@sourc*****
2009年 2月 6日 (金) 02:57:30 JST
Revision: 2623 http://svn.sourceforge.jp/view?root=jiemamy&view=rev&rev=2623 Author: ashigeru Date: 2009-02-06 02:57:30 +0900 (Fri, 06 Feb 2009) Log Message: ----------- gtreeのパーサに変数の概念を追加。 Modified Paths: -------------- artemis/trunk/generic-tree/src/main/java/org/jiemamy/utils/gtree/text/Parser.java artemis/trunk/generic-tree/src/main/java/org/jiemamy/utils/gtree/text/package-info.java artemis/trunk/generic-tree/src/main/javacc/GtreeParser.jj artemis/trunk/generic-tree/src/test/java/org/jiemamy/utils/gtree/text/ParserTest.java Added Paths: ----------- artemis/trunk/generic-tree/src/main/java/org/jiemamy/utils/gtree/text/Variables.java -------------- next part -------------- Modified: artemis/trunk/generic-tree/src/main/java/org/jiemamy/utils/gtree/text/Parser.java =================================================================== --- artemis/trunk/generic-tree/src/main/java/org/jiemamy/utils/gtree/text/Parser.java 2009-02-05 17:56:32 UTC (rev 2622) +++ artemis/trunk/generic-tree/src/main/java/org/jiemamy/utils/gtree/text/Parser.java 2009-02-05 17:57:30 UTC (rev 2623) @@ -17,6 +17,8 @@ import java.io.IOException; import java.io.Reader; +import java.util.Collections; +import java.util.Map; import org.jiemamy.utils.gtree.model.Value; @@ -26,28 +28,50 @@ * @author Suguru ARAKAWA */ public class Parser { - - /** - * 指定のソースから{@code Generic Tree Notation}形式のテキストを読み出し、 - * 対応する{@link Value}を構築する。 - * @param source {@code Generic Tree Notation}のテキストを保持するソース - * @return 対応する{@link Value} - * @throws IOException 解析に失敗した場合 - * @throws NullPointerException 引数に{@code null}が指定された場合 - */ - public static Value parse(Reader source) throws IOException { - if (source == null) { - throw new NullPointerException("source"); //$NON-NLS-1$ - } - GtreeParser0 parser = new GtreeParser0(source); - try { - return parser.parse(); - } - catch (ParseException e) { - throw (IOException) new IOException().initCause(e); - } - finally { - source.close(); - } - } + + /** + * 指定のソースから{@code Generic Tree Notation}形式のテキストを読み出し、 + * 対応する{@link Value}を構築する。 + * @param source {@code Generic Tree Notation}のテキストを保持するソース + * @return 対応する{@link Value} + * @throws IOException 解析に失敗した場合 + * @throws NullPointerException 引数に{@code null}が指定された場合 + */ + public static Value parse(Reader source) throws IOException { + if (source == null) { + throw new NullPointerException("source"); //$NON-NLS-1$ + } + return parse(source, Collections.<String, Value> emptyMap()); + } + + /** + * 指定のソースから{@code Generic Tree Notation}形式のテキストを読み出し、 + * 対応する{@link Value}を構築する。 + * <p> + * ソース中に値の代わりに{@code $id}という形式の変数を指定することができ、 + * {@code id}の名前で登録された値を{@code variables}から検出して利用する。 + * そのような名前が{@code variables}に指定されていない場合、解析は失敗する。 + * </p> + * @param source {@code Generic Tree Notation}のテキストを保持するソース + * @param variables 変数名と束縛された値の一覧 + * @return 対応する{@link Value} + * @throws IOException 解析に失敗した場合 + * @throws NullPointerException 引数に{@code null}が指定された場合 + */ + public static Value parse(Reader source, Map<String, ? extends Value> variables) throws IOException { + if (source == null) { + throw new NullPointerException("source"); //$NON-NLS-1$ + } + if (variables == null) { + throw new NullPointerException("variables"); //$NON-NLS-1$ + } + GtreeParser0 parser = new GtreeParser0(source); + try { + return parser.parse(new Variables(variables)); + } catch (ParseException e) { + throw (IOException) new IOException("Parse failure").initCause(e); //$NON-NLS-1$ + } finally { + source.close(); + } + } } Added: artemis/trunk/generic-tree/src/main/java/org/jiemamy/utils/gtree/text/Variables.java =================================================================== --- artemis/trunk/generic-tree/src/main/java/org/jiemamy/utils/gtree/text/Variables.java (rev 0) +++ artemis/trunk/generic-tree/src/main/java/org/jiemamy/utils/gtree/text/Variables.java 2009-02-05 17:57:30 UTC (rev 2623) @@ -0,0 +1,79 @@ +/* + * Copyright 2007-2009 Jiemamy Project and the Others. + * Created on 2009/02/06 + * + * This file is part of Jiemamy. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.jiemamy.utils.gtree.text; + +import java.text.MessageFormat; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.jiemamy.utils.gtree.model.Value; + +/** + * 変数表。 + * @author Suguru ARAKAWA + */ +class Variables { + + /** + * 値がひとつも束縛されてない変数表。 + */ + public static final Variables NULL = new Variables(Collections.<String, Value> emptyMap()); + + /** + * 変数表。 + */ + private final Map<String, Value> entity; + + + /** + * インスタンスを生成する。 + * @param entity 変数名と値の束縛表 + * @throws NullPointerException 引数に{@code null}が指定された場合 + */ + public Variables(Map<String, ? extends Value> entity) { + super(); + if (entity == null) { + throw new NullPointerException("entity"); //$NON-NLS-1$ + } + this.entity = Collections.unmodifiableMap(new HashMap<String, Value>(entity)); + } + + /** + * 指定のトークンを解析して、対応する変数の内容を返す。 + * @param token 変数を表現するトークン + * @return 対象の変数に束縛された値 + * @throws ParseException 指定の変数に値が束縛されていない場合 + */ + public Value resolve(Token token) throws ParseException { + if (token == null) { + throw new NullPointerException("token"); //$NON-NLS-1$ + } + if (token.image.startsWith("$") == false) { + throw new IllegalArgumentException(token.toString()); + } + String name = token.image.substring(1); + Value bound = entity.get(name); + if (bound == null) { + throw new ParseException(MessageFormat.format("Undefined variable \"{0}\" (line {1}, column {2})", //$NON-NLS-1$ + token.image, token.beginLine, token.endColumn)); + } + return bound; + } +} Property changes on: artemis/trunk/generic-tree/src/main/java/org/jiemamy/utils/gtree/text/Variables.java ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:keywords + Date Author Id Revision HeadURL Added: svn:eol-style + native Modified: artemis/trunk/generic-tree/src/main/java/org/jiemamy/utils/gtree/text/package-info.java =================================================================== --- artemis/trunk/generic-tree/src/main/java/org/jiemamy/utils/gtree/text/package-info.java 2009-02-05 17:56:32 UTC (rev 2622) +++ artemis/trunk/generic-tree/src/main/java/org/jiemamy/utils/gtree/text/package-info.java 2009-02-05 17:57:30 UTC (rev 2623) @@ -30,6 +30,7 @@ * OrderedList * UnorderedList * Record + * Variable * * Terminal : * STRING @@ -46,6 +47,9 @@ * < > * < EntryList > * + * Variable : + * $ IDENTIFIER + * * ValueList : * Value * ValueList , Value @@ -59,6 +63,17 @@ * * STRING : * (Javaの文字列リテラル) + * + * IDENTIFIER : + * [A-Za-z0-9]+ + * * </code></pre> + * <p> + * このうち、{@code Variable}は擬似的な構文規則で、あらかじめ登録された値を + * 変数表から探し出し、評価結果を該当の変数に格納された値とする。 + * 変数表には変数の名前を束縛する値の一覧を指定できるが、このとき + * 先頭の{@code $}を除いた識別子で変数の名前を指定する。 + * </p> */ package org.jiemamy.utils.gtree.text; + Modified: artemis/trunk/generic-tree/src/main/javacc/GtreeParser.jj =================================================================== --- artemis/trunk/generic-tree/src/main/javacc/GtreeParser.jj 2009-02-05 17:56:32 UTC (rev 2622) +++ artemis/trunk/generic-tree/src/main/javacc/GtreeParser.jj 2009-02-05 17:57:30 UTC (rev 2623) @@ -45,14 +45,30 @@ class GtreeParser0 { + private ThreadLocal<Variables> variables = new ThreadLocal<Variables>(); + /** * Parse and returns the analyzed Generic Tree Model. * @return the analyzed model * @throws ParseException if parse was failed */ - public Value parse() throws ParseException { - return script(); + public Value parse(Variables vars) throws ParseException { + variables.set(vars); + try { + return script(); + } + finally { + variables.set(null); + } } + + private Value resolve(Token variable) throws ParseException { + Variables vars = variables.get(); + if (vars == null) { + vars = Variables.NULL; + } + return vars.resolve(variable); + } private static <T> List<T> list() { return new ArrayList<T>(); @@ -90,6 +106,10 @@ } TOKEN : +{ <VARIABLE : "$" (["A"-"Z", "a"-"z", "0"-"9", "_"])+ > +} + +TOKEN : { <STRING : "'" (<SCHAR>|<ESCAPE>)* "'" | "\"" (<DCHAR>|<ESCAPE>)* "\"" @@ -130,6 +150,7 @@ * OrderedList * UnorderedList * Record + * Variable * </pre> */ private Value value() : @@ -156,6 +177,11 @@ { return value; } +| + value = variable() + { + return value; + } } /** @@ -255,6 +281,23 @@ /** * <pre> + * Variable : + * "$" (Identifier) + * </pre> + */ +private Value variable() : +{ + Token t; +} +{ + t = <VARIABLE> + { + return resolve(t); + } +} + +/** + * <pre> * ValueList : * Value * ValueList "," Value Modified: artemis/trunk/generic-tree/src/test/java/org/jiemamy/utils/gtree/text/ParserTest.java =================================================================== --- artemis/trunk/generic-tree/src/test/java/org/jiemamy/utils/gtree/text/ParserTest.java 2009-02-05 17:56:32 UTC (rev 2622) +++ artemis/trunk/generic-tree/src/test/java/org/jiemamy/utils/gtree/text/ParserTest.java 2009-02-05 17:57:30 UTC (rev 2623) @@ -21,7 +21,9 @@ import java.io.IOException; import java.io.StringReader; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.jiemamy.utils.gtree.model.Entry; import org.jiemamy.utils.gtree.model.Record; @@ -200,6 +202,45 @@ "ul", ul("D", "E"), "rc", rc("f", "G")))); } + + /** + * Test method for {@link Parser#parse(java.io.Reader, java.util.Map)}. + * @throws Exception if occur + */ + @Test + public void testParse_Variable() throws Exception { + Map<String, Value> vars = new HashMap<String, Value>(); + vars.put("a", value("Hello")); + Value v = parse("$a", vars); + assertThat(v, is(terminal("Hello"))); + } + + /** + * Test method for {@link Parser#parse(java.io.Reader, java.util.Map)}. + * @throws Exception if occur + */ + @Test + public void testParse_Variables() throws Exception { + Map<String, Value> vars = new HashMap<String, Value>(); + vars.put("a", value("A")); + vars.put("b", value("B")); + vars.put("c", value("C")); + Value v = parse("<'a':$a, 'b':$b, 'c':$c>", vars); + assertThat(v, is(rc("a", "A", "b", "B", "c", "C"))); + } + + /** + * Test method for {@link Parser#parse(java.io.Reader, java.util.Map)}. + * @throws Exception if occur + */ + @Test(expected = IOException.class) + public void testParse_Variables_Unbound() throws Exception { + Map<String, Value> vars = new HashMap<String, Value>(); + vars.put("a", value("A")); + vars.put("b", value("B")); + vars.put("c", value("C")); + parse("<'a':$a, 'b':$b, 'c':$c, 'd':$d>", vars); + } private Value terminal(Object content) { return Terminal.of(String.valueOf(content)); @@ -244,4 +285,8 @@ private Value parse(String script) throws IOException { return Parser.parse(new StringReader(script)); } + + private Value parse(String script, Map<String, ? extends Value> vars) throws IOException { + return Parser.parse(new StringReader(script), vars); + } }