Java tutorial
/* * [Apache License 2.0] * Copyright 2014 T.Kando and Inuyama-ya sanpu. * * 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.xgmtk.lore.ast; import static org.xgmtk.lore.ast.ASTNodes.id; import static org.xgmtk.lore.ast.ASTNodes.node; import static org.xgmtk.lore.ast.ASTNodes.lit; import static org.xgmtk.lore.ast.Locator.loc; import static org.xgmtk.lore.utils.EncodeFinder.findEncodeInfo; import static org.xgmtk.lore.utils.StringUtils.trim; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; import java.nio.file.Paths; import java.time.OffsetDateTime; import java.time.format.DateTimeParseException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.Stack; import java.util.logging.Logger; import org.antlr.v4.runtime.ANTLRInputStream; import org.antlr.v4.runtime.BufferedTokenStream; import org.antlr.v4.runtime.ParserRuleContext; import org.antlr.v4.runtime.TokenStream; import org.antlr.v4.runtime.misc.NotNull; import org.antlr.v4.runtime.tree.ParseTree; import org.xgmtk.lore.Lore; import org.xgmtk.lore.builtin.HTML; import org.xgmtk.lore.builtin.JID; import org.xgmtk.lore.builtin.Location; import org.xgmtk.lore.builtin.SimpleString; import org.xgmtk.lore.builtin.XML; import org.xgmtk.lore.parser.LoreBaseListener; import org.xgmtk.lore.parser.LoreLexer; import org.xgmtk.lore.parser.LoreParser; public class ASTBuilder extends LoreBaseListener { public static final String DEFAULT_ENCODING = "UTF-8"; public static final int HEADER_SCAN_LINES_FOR_FIND_ENCODING = 100; public static void main(String[] args) { if (args.length == 0 || Arrays.stream(args).anyMatch(s -> (s.equals("-h") || s.equals("-help")))) { System.err.println("[USAGE]This command takes only 1 argument. It is a file path to parse."); } ASTBuilder builder = null; try { builder = new ASTBuilder(Paths.get(args[0]).toFile().toURI().toURL(), Logger.getGlobal()); } catch (IOException e) { e.printStackTrace(); System.exit(1); } AST ast = builder.getTree(); PrintVisitor.printTree(ast, System.out, false); System.exit(0); } protected static void printContext(ParserRuleContext ctx) { System.err.println("(Context object id: " + ctx + ", line: " + ctx.start.getLine() + ", \"" + ctx.getText() + "\", child count: " + ctx.getChildCount() + "){"); for (int i = 0; i < ctx.getChildCount(); ++i) { ParseTree ptree = ctx.getChild(i); System.err.println("\t\"" + ptree.getText() + "\"(has: " + ptree.getChildCount() + ")"); } System.err.println("}"); } /** * TODO write JavaDoc comment. * * @param ctx * @param string * @return */ protected static int indexOf(ParserRuleContext ctx, String string) { for (int i = 0; i < ctx.getChildCount(); ++i) { if (Objects.equals(ctx.getChild(i).getText(), string)) { return i; } } return -1; } private static LoreParser getParser(URL source, String encoding) throws FileNotFoundException, IOException { InputStream in = source.openStream(); InputStreamReader rd = new InputStreamReader(in, encoding); System.err.println("[" + LoreParser.class.getSimpleName() + "] File: \"" + source + "\", Encoding: \"" + rd.getEncoding() + "\""); ANTLRInputStream ain = new ANTLRInputStream(rd); LoreLexer lexer = new LoreLexer(ain); TokenStream tstream = new BufferedTokenStream(lexer); LoreParser parser = new LoreParser(tstream); return parser; } private URL src; private LoreParser parser; private AST tree; private List<AST> children; private Stack<List<AST>> childrenStack; private Logger logger; public ASTBuilder(URL source, Logger logger) throws IOException { this(source, findEncodeInfo(source, HEADER_SCAN_LINES_FOR_FIND_ENCODING, DEFAULT_ENCODING), logger); } public ASTBuilder(URL source, String encoding, Logger logger) throws IOException { super(); this.logger = logger; src = source; parser = getParser(source, encoding); parser.addParseListener(this); this.tree = null; this.children = null; this.childrenStack = new Stack<>(); parser.lore(); } protected void error(ParserRuleContext ctx, String msg) { logger.severe(Lore.errorMessageFormat(src, ctx.start.getLine(), msg)); } /** * This method should call at the begin of the enter*() method of the listener. * Because the method pushes a children list of the parent node into stack. * * @return */ protected List<AST> newChildrenList() { if (this.children != null) {//This condition is expected to be true at the root node. this.childrenStack.push(this.children); } this.children = new ArrayList<>(); return getChildrenList(); } protected int getChildrenCount() { return this.getChildrenList().size(); } /** * TODO write JavaDoc comment. * * @return */ protected List<AST> getChildrenList() { return this.children; } /** * This method should call at the end of exit*() method of the listener. * Because the method pops a children list of parent node from stack. * * @param node */ protected void result(AST node) { this.children = this.childrenStack.pop(); this.getChildrenList().add(node); } public AST getTree() { return this.tree; } protected void nonterminalNodeAsResult(ParserRuleContext ctx, NonTerminalSymbol type) { AST n = node(type, loc(src, ctx.start.getLine())); n.getMdifiableChildren().addAll(this.getChildrenList()); this.result(n); } protected void idNodeAsResult(ParserRuleContext ctx, String idString) { this.result(id(idString, loc(src, ctx.getStart().getLine()))); } protected NonTerminalSymbol selectNonterminalSymbol(ParserRuleContext ctx, String symbolString, final NonTerminalSymbol[] symbols) { for (NonTerminalSymbol type : symbols) { if (type.getSymbolString().equals(symbolString)) { return type; } } throw new IllegalStateException( "Unexpected internal error: The method could not find a suitable Node Type."); } protected AST buildOperatorTree(ParserRuleContext ctx, final NonTerminalSymbol[] ops) { // printContext(ctx); List<AST> cs = this.getChildrenList(); // System.err.println("ParseTree: \""+ctx.getText()+"\""); // System.err.println("AST Children: "+cs.size()); // System.err.println("ParseTree Children: "+ctx.getChildCount()); AST left = cs.get(0); int ci = 1; for (int i = 1; i < ctx.getChildCount(); i += 2) { AST right = cs.get(ci++); NonTerminalSymbol t = selectNonterminalSymbol(ctx, ctx.getChild(i).getText(), ops); left = node(t, loc(src, ctx.getStart().getLine()), left, right); } return left; } @Override public void enterLore(@NotNull LoreParser.LoreContext ctx) { this.newChildrenList(); this.tree = node(NonTerminalSymbol.ROOT, loc(src, 0)); } @Override public void exitLore(@NotNull LoreParser.LoreContext ctx) { this.tree.getMdifiableChildren().addAll(this.getChildrenList()); } @Override public void enterDocinfo(@NotNull LoreParser.DocinfoContext ctx) { this.newChildrenList(); } @Override public void exitDocinfo(@NotNull LoreParser.DocinfoContext ctx) { this.nonterminalNodeAsResult(ctx, NonTerminalSymbol.DOCINFO); } @Override public void enterEncoding(@NotNull LoreParser.EncodingContext ctx) { this.newChildrenList(); } @Override public void exitEncoding(@NotNull LoreParser.EncodingContext ctx) { // AST n = node(NodeType.ENCODING, loc(src, ctx.start.getLine())); // //printContext(ctx); // ParseTree child2 = ctx.getChild(2); // String encName = trim(child2.getText(), "\"", "\""); // n.getMdifiableChildren().add(lit(encName, loc(src, ctx.start.getLine()))); // this.result(n); this.nonterminalNodeAsResult(ctx, NonTerminalSymbol.ENCODING); } @Override public void enterVersion(@NotNull LoreParser.VersionContext ctx) { this.newChildrenList(); } @Override public void exitVersion(@NotNull LoreParser.VersionContext ctx) { this.nonterminalNodeAsResult(ctx, NonTerminalSymbol.VERSION); } @Override public void enterDescription(@NotNull LoreParser.DescriptionContext ctx) { this.newChildrenList(); } @Override public void exitDescription(@NotNull LoreParser.DescriptionContext ctx) { this.nonterminalNodeAsResult(ctx, NonTerminalSymbol.DESC); } @Override public void enterAuthor(@NotNull LoreParser.AuthorContext ctx) { this.newChildrenList(); } @Override public void exitAuthor(@NotNull LoreParser.AuthorContext ctx) { this.nonterminalNodeAsResult(ctx, NonTerminalSymbol.AUTHOR); } @Override public void enterHistory(@NotNull LoreParser.HistoryContext ctx) { this.newChildrenList(); } @Override public void exitHistory(@NotNull LoreParser.HistoryContext ctx) { this.nonterminalNodeAsResult(ctx, NonTerminalSymbol.HISTORY); } @Override public void enterImport_other(@NotNull LoreParser.Import_otherContext ctx) { this.newChildrenList(); } @Override public void exitImport_other(@NotNull LoreParser.Import_otherContext ctx) { // System.err.println("** Author"); // printContext(ctx); this.nonterminalNodeAsResult(ctx, NonTerminalSymbol.IMPORT); } @Override public void enterSection(@NotNull LoreParser.SectionContext ctx) { this.newChildrenList(); } @Override public void exitSection(@NotNull LoreParser.SectionContext ctx) { this.nonterminalNodeAsResult(ctx, NonTerminalSymbol.SECTION); } @Override public void enterPrivate_section_element(@NotNull LoreParser.Private_section_elementContext ctx) { this.newChildrenList(); } @Override public void exitPrivate_section_element(@NotNull LoreParser.Private_section_elementContext ctx) { this.nonterminalNodeAsResult(ctx, NonTerminalSymbol.PRIVATE); } //ID, QNAME @Override public void enterQName(@NotNull LoreParser.QNameContext ctx) { this.newChildrenList(); } @Override public void exitQName(@NotNull LoreParser.QNameContext ctx) { List<AST> cs = this.getChildrenList(); AST left = cs.get(0); for (int i = 1; i < cs.size(); ++i) { AST right = cs.get(i); left = node(NonTerminalSymbol.QNAME, loc(src, ctx.getStart().getLine()), left, right); } this.result(left); } /* * Type definitions */ @Override public void enterEnum_def(@NotNull LoreParser.Enum_defContext ctx) { this.newChildrenList(); } @Override public void exitEnum_def(@NotNull LoreParser.Enum_defContext ctx) { this.nonterminalNodeAsResult(ctx, NonTerminalSymbol.ENUM_DEF); } @Override public void enterEnum_elem(@NotNull LoreParser.Enum_elemContext ctx) { this.newChildrenList(); } @Override public void exitEnum_elem(@NotNull LoreParser.Enum_elemContext ctx) { this.nonterminalNodeAsResult(ctx, NonTerminalSymbol.ENUM_VAL); } @Override public void enterEnum_field(@NotNull LoreParser.Enum_fieldContext ctx) { this.newChildrenList(); } @Override public void exitEnum_field(@NotNull LoreParser.Enum_fieldContext ctx) { this.nonterminalNodeAsResult(ctx, NonTerminalSymbol.VAR); } @Override public void enterUnit_def(@NotNull LoreParser.Unit_defContext ctx) { this.newChildrenList(); } @Override public void exitUnit_def(@NotNull LoreParser.Unit_defContext ctx) { this.nonterminalNodeAsResult(ctx, NonTerminalSymbol.UNIT_DEF); } @Override public void enterForm_def(@NotNull LoreParser.Form_defContext ctx) { this.newChildrenList(); } @Override public void exitForm_def(@NotNull LoreParser.Form_defContext ctx) { this.nonterminalNodeAsResult(ctx, NonTerminalSymbol.FORM_DEF); } @Override public void enterForm_cont_def(@NotNull LoreParser.Form_cont_defContext ctx) { this.newChildrenList(); } @Override public void exitForm_cont_def(@NotNull LoreParser.Form_cont_defContext ctx) { this.nonterminalNodeAsResult(ctx, NonTerminalSymbol.CONT); } @Override public void enterPrivate_member_def(@NotNull LoreParser.Private_member_defContext ctx) { this.newChildrenList(); } @Override public void exitPrivate_member_def(@NotNull LoreParser.Private_member_defContext ctx) { this.nonterminalNodeAsResult(ctx, NonTerminalSymbol.PRIVATE); } @Override public void enterMember_initializer(@NotNull LoreParser.Member_initializerContext ctx) { this.newChildrenList(); } @Override public void exitMember_initializer(@NotNull LoreParser.Member_initializerContext ctx) { if (ctx.getText().startsWith("override")) { this.nonterminalNodeAsResult(ctx, NonTerminalSymbol.OVERRIDE); } else { this.result(this.getChildrenList().get(0)); } } @Override public void enterType_spec(@NotNull LoreParser.Type_specContext ctx) { this.newChildrenList(); } @Override public void exitType_spec(@NotNull LoreParser.Type_specContext ctx) { this.nonterminalNodeAsResult(ctx, NonTerminalSymbol.TYPE_SPEC); } @Override public void enterLambda_type_full(@NotNull LoreParser.Lambda_type_fullContext ctx) { this.newChildrenList(); } @Override public void exitLambda_type_full(@NotNull LoreParser.Lambda_type_fullContext ctx) { List<AST> cs = this.getChildrenList(); // printContext(ctx); // System.err.println("cs.size(): "+cs.size()); AST type = cs.get(1); AST params = cs.get(0); this.result(node(NonTerminalSymbol.LAMBDA_TYPE, loc(src, ctx.getStart().getLine()), type, params)); } @Override public void enterLambda_type_no_param(@NotNull LoreParser.Lambda_type_no_paramContext ctx) { this.newChildrenList(); } @Override public void exitLambda_type_no_param(@NotNull LoreParser.Lambda_type_no_paramContext ctx) { List<AST> cs = this.getChildrenList(); AST type = cs.get(0); AST params = node(NonTerminalSymbol.PARAMS, loc(src, ctx.getStart().getLine())); this.result(node(NonTerminalSymbol.LAMBDA_TYPE, loc(src, ctx.getStart().getLine()), type, params)); } @Override public void enterLambda_type_no_return(@NotNull LoreParser.Lambda_type_no_returnContext ctx) { this.newChildrenList(); } @Override public void exitLambda_type_no_return(@NotNull LoreParser.Lambda_type_no_returnContext ctx) { this.nonterminalNodeAsResult(ctx, NonTerminalSymbol.LAMBDA_TYPE); } @Override public void enterLambda_type_no_param_no_return(@NotNull LoreParser.Lambda_type_no_param_no_returnContext ctx) { this.newChildrenList(); } @Override public void exitLambda_type_no_param_no_return(@NotNull LoreParser.Lambda_type_no_param_no_returnContext ctx) { AST params = node(NonTerminalSymbol.PARAMS, loc(src, ctx.getStart().getLine())); this.result(node(NonTerminalSymbol.LAMBDA_TYPE, loc(src, ctx.getStart().getLine()), params)); } @Override public void enterLambda_type_parameters(@NotNull LoreParser.Lambda_type_parametersContext ctx) { this.newChildrenList(); } @Override public void exitLambda_type_parameters(@NotNull LoreParser.Lambda_type_parametersContext ctx) { this.nonterminalNodeAsResult(ctx, NonTerminalSymbol.PARAMS); } @Override public void enterList_type(@NotNull LoreParser.List_typeContext ctx) { this.newChildrenList(); } @Override public void exitList_type(@NotNull LoreParser.List_typeContext ctx) { this.nonterminalNodeAsResult(ctx, NonTerminalSymbol.LIST_TYPE); } @Override public void enterUnit_type(@NotNull LoreParser.Unit_typeContext ctx) { this.newChildrenList(); } @Override public void exitUnit_type(@NotNull LoreParser.Unit_typeContext ctx) { this.nonterminalNodeAsResult(ctx, NonTerminalSymbol.UNIT_TYPE); } @Override public void enterRange_type(@NotNull LoreParser.Range_typeContext ctx) { this.newChildrenList(); } @Override public void exitRange_type(@NotNull LoreParser.Range_typeContext ctx) { this.nonterminalNodeAsResult(ctx, NonTerminalSymbol.RANGE_TYPE); } @Override public void enterArithmetic_type(@NotNull LoreParser.Arithmetic_typeContext ctx) { this.newChildrenList(); } @Override public void exitArithmetic_type(@NotNull LoreParser.Arithmetic_typeContext ctx) { idNodeAsResult(ctx, ctx.getChild(0).getText()); } @Override public void enterTextual_type(@NotNull LoreParser.Textual_typeContext ctx) { this.newChildrenList(); } @Override public void exitTextual_type(@NotNull LoreParser.Textual_typeContext ctx) { idNodeAsResult(ctx, ctx.getChild(0).getText()); } @Override public void enterTrpg_type(@NotNull LoreParser.Trpg_typeContext ctx) { this.newChildrenList(); } @Override public void exitTrpg_type(@NotNull LoreParser.Trpg_typeContext ctx) { idNodeAsResult(ctx, ctx.getChild(0).getText()); } /* * function / rule / accessor / alter(? Javadoc) */ @Override public void enterRule_def(@NotNull LoreParser.Rule_defContext ctx) { this.newChildrenList(); } @Override public void exitRule_def(@NotNull LoreParser.Rule_defContext ctx) { List<AST> cs = this.getChildrenList(); AST name = cs.get(0); AST block = cs.get(cs.size() - 1); AST paramsNode = node(NonTerminalSymbol.PARAMS, loc(src, ctx.getStart().getLine())); if (cs.size() > 2) { paramsNode.getMdifiableChildren().addAll(cs.subList(1, cs.size() - 1)); } this.result(node(NonTerminalSymbol.RULE, loc(src, ctx.getStart().getLine()), name, paramsNode, block)); } @Override public void enterFunction_def(@NotNull LoreParser.Function_defContext ctx) { this.newChildrenList(); } @Override public void exitFunction_def(@NotNull LoreParser.Function_defContext ctx) { List<AST> cs = this.getChildrenList(); AST name = cs.get(0); AST type = cs.get(cs.size() - 2); AST block = cs.get(cs.size() - 1); AST returnType = node(NonTerminalSymbol.TYPE_SPEC, loc(src, ctx.getStart().getLine()), name, type); AST paramsNode = node(NonTerminalSymbol.PARAMS, loc(src, ctx.getStart().getLine())); // printContext(ctx); // int ix = 0; // for(AST n :cs){ // System.err.println("*** ["+(ix++)+" / "+cs.size()+"]"); // PrintVisitor.printTree(n, System.err, false); // System.err.println("***"); // } if (cs.size() > 3) {//This function definition has parameters. paramsNode.getMdifiableChildren().addAll(cs.subList(1, cs.size() - 2)); } ; this.result(node(NonTerminalSymbol.FUNCTION, loc(src, ctx.getStart().getLine()), returnType, paramsNode, block)); } @Override public void enterAccessor_def(@NotNull LoreParser.Accessor_defContext ctx) { this.newChildrenList(); } @Override public void exitAccessor_def(@NotNull LoreParser.Accessor_defContext ctx) { List<AST> cs = this.getChildrenList(); AST name = cs.get(0); AST type = cs.get(cs.size() - 2); AST block = cs.get(cs.size() - 1); AST returnType = node(NonTerminalSymbol.TYPE_SPEC, loc(src, ctx.getStart().getLine()), name, type); AST paramsNode = node(NonTerminalSymbol.PARAMS, loc(src, ctx.getStart().getLine())); if (cs.size() > 3) {//This function definition has parameters. paramsNode.getMdifiableChildren().addAll(cs.subList(1, cs.size() - 2)); } this.result(node(NonTerminalSymbol.ACCESSOR, loc(src, ctx.getStart().getLine()), returnType, paramsNode, block)); } @Override public void enterAlter_def(@NotNull LoreParser.Alter_defContext ctx) { this.newChildrenList(); } @Override public void exitAlter_def(@NotNull LoreParser.Alter_defContext ctx) { this.nonterminalNodeAsResult(ctx, NonTerminalSymbol.ALTER); } @Override public void enterBlock(@NotNull LoreParser.BlockContext ctx) { this.newChildrenList(); } @Override public void exitBlock(@NotNull LoreParser.BlockContext ctx) { this.nonterminalNodeAsResult(ctx, NonTerminalSymbol.BODY); } /* * Statements * */ @Override public void enterResult_statement(@NotNull LoreParser.Result_statementContext ctx) { this.newChildrenList(); } @Override public void exitResult_statement(@NotNull LoreParser.Result_statementContext ctx) { this.nonterminalNodeAsResult(ctx, NonTerminalSymbol.RESULT); } @Override public void enterVar_def(@NotNull LoreParser.Var_defContext ctx) { this.newChildrenList(); } @Override public void exitVar_def(@NotNull LoreParser.Var_defContext ctx) { this.nonterminalNodeAsResult(ctx, NonTerminalSymbol.VAR); } @Override public void enterField_modify(@NotNull LoreParser.Field_modifyContext ctx) { this.newChildrenList(); } @Override public void exitField_modify(@NotNull LoreParser.Field_modifyContext ctx) { List<AST> cs = this.getChildrenList(); //AST self = cs.get(0); AST name = cs.get(1); AST exp = cs.get(2); this.result(node(NonTerminalSymbol.MODIFY, loc(src, ctx.getStart().getLine()), name, exp)); } @Override public void enterSelf(@NotNull LoreParser.SelfContext ctx) { this.newChildrenList(); } @Override public void exitSelf(@NotNull LoreParser.SelfContext ctx) { this.nonterminalNodeAsResult(ctx, NonTerminalSymbol.SELF); } /* * Expression */ @Override public void enterSelect_expr(@NotNull LoreParser.Select_exprContext ctx) { this.newChildrenList(); } @Override public void exitSelect_expr(@NotNull LoreParser.Select_exprContext ctx) { this.nonterminalNodeAsResult(ctx, NonTerminalSymbol.SELECT); } @Override public void enterCase_block(@NotNull LoreParser.Case_blockContext ctx) { this.newChildrenList(); } @Override public void exitCase_block(@NotNull LoreParser.Case_blockContext ctx) { this.nonterminalNodeAsResult(ctx, NonTerminalSymbol.CASE); } @Override public void enterAs_block(@NotNull LoreParser.As_blockContext ctx) { this.newChildrenList(); } @Override public void exitAs_block(@NotNull LoreParser.As_blockContext ctx) { this.nonterminalNodeAsResult(ctx, NonTerminalSymbol.AS); } @Override public void enterDefault_block(@NotNull LoreParser.Default_blockContext ctx) { this.newChildrenList(); } @Override public void exitDefault_block(@NotNull LoreParser.Default_blockContext ctx) { this.nonterminalNodeAsResult(ctx, NonTerminalSymbol.DEFAULT); } @Override public void enterRange(@NotNull LoreParser.RangeContext ctx) { this.newChildrenList(); } @Override public void exitRange(@NotNull LoreParser.RangeContext ctx) { String opStr = ctx.getChild(1).getText(); // printContext(ctx); // System.err.println("AST children list size: "+this.getChildrenList().size()); final NonTerminalSymbol[] ops = { NonTerminalSymbol.RANGE_OP_EE, NonTerminalSymbol.RANGE_OP_LE, NonTerminalSymbol.RANGE_OP_EL, NonTerminalSymbol.RANGE_OP_LL }; NonTerminalSymbol op = selectNonterminalSymbol(ctx, opStr, ops); this.nonterminalNodeAsResult(ctx, op); } @Override public void enterCond_term(@NotNull LoreParser.Cond_termContext ctx) { this.newChildrenList(); } @Override public void exitCond_term(@NotNull LoreParser.Cond_termContext ctx) { if (ctx.getChildCount() < 2) { this.result(this.getChildrenList().get(0)); } else { String opStr = ctx.getChild(1).getText(); final NonTerminalSymbol[] ops = { NonTerminalSymbol.AND, NonTerminalSymbol.OR }; this.nonterminalNodeAsResult(ctx, selectNonterminalSymbol(ctx, opStr, ops)); } } @Override public void enterRelation(@NotNull LoreParser.RelationContext ctx) { this.newChildrenList(); } @Override public void exitRelation(@NotNull LoreParser.RelationContext ctx) { String opStr = ctx.getChild(1).getText(); final NonTerminalSymbol[] ops = { NonTerminalSymbol.EQ, NonTerminalSymbol.NEQ, NonTerminalSymbol.GE, NonTerminalSymbol.GT, NonTerminalSymbol.LE, NonTerminalSymbol.LT }; this.nonterminalNodeAsResult(ctx, selectNonterminalSymbol(ctx, opStr, ops)); } @Override public void enterCond_monomial(@NotNull LoreParser.Cond_monomialContext ctx) { this.newChildrenList(); } @Override public void exitCond_monomial(@NotNull LoreParser.Cond_monomialContext ctx) { this.nonterminalNodeAsResult(ctx, NonTerminalSymbol.NOT); } @Override public void enterTerms(@NotNull LoreParser.TermsContext ctx) { this.newChildrenList(); } @Override public void exitTerms(@NotNull LoreParser.TermsContext ctx) { // printContext(ctx); final NonTerminalSymbol[] ops = { NonTerminalSymbol.PLUS, NonTerminalSymbol.MINUS }; this.result(buildOperatorTree(ctx, ops)); } @Override public void enterTerm(@NotNull LoreParser.TermContext ctx) { this.newChildrenList(); } @Override public void exitTerm(@NotNull LoreParser.TermContext ctx) { // printContext(ctx); final NonTerminalSymbol[] ops = { NonTerminalSymbol.MULT, NonTerminalSymbol.DIV, NonTerminalSymbol.MOD }; this.result(buildOperatorTree(ctx, ops)); } @Override public void enterFactor(@NotNull LoreParser.FactorContext ctx) { this.newChildrenList(); } @Override public void exitFactor(@NotNull LoreParser.FactorContext ctx) { if (ctx.getChildCount() < 2) { this.result(this.getChildrenList().get(0)); } else { this.nonterminalNodeAsResult(ctx, NonTerminalSymbol.NEGATE); } } @Override public void enterUnit_monomial(@NotNull LoreParser.Unit_monomialContext ctx) { this.newChildrenList(); } @Override public void exitUnit_monomial(@NotNull LoreParser.Unit_monomialContext ctx) { this.nonterminalNodeAsResult(ctx, NonTerminalSymbol.UNIT_VAL); } @Override public void enterDice_monomial(@NotNull LoreParser.Dice_monomialContext ctx) { this.newChildrenList(); } // This method works in conjunction with exitDiceKind(). @Override public void exitDice_monomial(@NotNull LoreParser.Dice_monomialContext ctx) { if (this.getChildrenCount() < 2) { AST dice = this.getChildrenList().get(0); dice.getMdifiableChildren().add(0, lit(1L, loc(src, ctx.getStart().getLine()))); this.result(dice); } else { AST dice = this.getChildrenList().get(1); AST factor = this.getChildrenList().get(0); dice.getMdifiableChildren().add(0, factor); this.result(dice); } } @Override public void enterMonomial(@NotNull LoreParser.MonomialContext ctx) { this.newChildrenList(); } // This method works in conjunction with exitMember_access(). @Override public void exitMonomial(@NotNull LoreParser.MonomialContext ctx) { List<AST> cs = this.getChildrenList(); // System.err.println("=== AST Children: "+cs.size()); // printContext(ctx); AST left = cs.get(0); for (int i = 1; i < cs.size(); ++i) { AST right = cs.get(i); // System.err.print("i: ["+i+"], "); // System.err.print("left: \""+left.symbol.getSymbolString()+"\", "); // System.err.println("right: \""+right.symbol.getSymbolString()+"\""); if (NonTerminalSymbol.CALL.equals(right.symbol)) { AST mname = right.getChildren().get(0); right.getMdifiableChildren().remove(0); AST qname = node(NonTerminalSymbol.QNAME, mname.locator, left, mname); // System.err.println("**** QNAME"); // PrintVisitor.printTree(qname, System.err, false); // System.err.println("****"); // System.err.println("mname: \""+mname.symbol.getSymbolString()+"\""); right.getMdifiableChildren().add(0, qname); left = right; // System.err.println("**** CALL"); // PrintVisitor.printTree(left, System.err, false); // System.err.println("****"); } else { left = node(NonTerminalSymbol.QNAME, right.locator, left, right); // System.err.println("**** QNAME"); // PrintVisitor.printTree(left, System.err, false); // System.err.println("****"); } } // System.err.print("result: \""+left.symbol.getSymbolString()+"\", "); // System.err.println("==="); // System.err.println(); this.result(left); } @Override public void enterMember_access(@NotNull LoreParser.Member_accessContext ctx) { this.newChildrenList(); } // This method works in conjunction with exitMonomial(). @Override public void exitMember_access(@NotNull LoreParser.Member_accessContext ctx) { if (this.getChildrenCount() > 1) { AST call = node(NonTerminalSymbol.CALL, loc(src, ctx.getStart().getLine())); call.getMdifiableChildren().addAll(this.getChildrenList()); this.result(call); } else { this.result(this.getChildrenList().get(0)); } } @Override public void enterSimpleCall(@NotNull LoreParser.SimpleCallContext ctx) { this.newChildrenList(); } @Override public void exitSimpleCall(@NotNull LoreParser.SimpleCallContext ctx) { this.nonterminalNodeAsResult(ctx, NonTerminalSymbol.CALL); } @Override public void enterList_construct(@NotNull LoreParser.List_constructContext ctx) { this.newChildrenList(); } @Override public void exitList_construct(@NotNull LoreParser.List_constructContext ctx) { this.nonterminalNodeAsResult(ctx, NonTerminalSymbol.LIST_VAL); } @Override public void enterForm_construct(@NotNull LoreParser.Form_constructContext ctx) { this.newChildrenList(); } @Override public void exitForm_construct(@NotNull LoreParser.Form_constructContext ctx) { //printContext(ctx); this.nonterminalNodeAsResult(ctx, NonTerminalSymbol.FORM_VAL); } @Override public void enterForm_contents(@NotNull LoreParser.Form_contentsContext ctx) { this.newChildrenList(); } @Override public void exitForm_contents(@NotNull LoreParser.Form_contentsContext ctx) { this.nonterminalNodeAsResult(ctx, NonTerminalSymbol.CONT); } @Override public void enterLambda_full(@NotNull LoreParser.Lambda_fullContext ctx) { this.newChildrenList(); } @Override public void exitLambda_full(@NotNull LoreParser.Lambda_fullContext ctx) { List<AST> cs = this.getChildrenList(); AST type = cs.get(1); AST params = cs.get(0); AST block = cs.get(2); this.result(node(NonTerminalSymbol.LAMBDA, loc(src, ctx.getStart().getLine()), type, params, block)); } @Override public void enterLambda_no_param(@NotNull LoreParser.Lambda_no_paramContext ctx) { this.newChildrenList(); } @Override public void exitLambda_no_param(@NotNull LoreParser.Lambda_no_paramContext ctx) { List<AST> cs = this.getChildrenList(); AST type = cs.get(0); AST params = node(NonTerminalSymbol.PARAMS, loc(src, ctx.getStart().getLine())); AST block = cs.get(1); this.result(node(NonTerminalSymbol.LAMBDA, loc(src, ctx.getStart().getLine()), type, params, block)); } @Override public void enterLambda_no_return(@NotNull LoreParser.Lambda_no_returnContext ctx) { this.newChildrenList(); } @Override public void exitLambda_no_return(@NotNull LoreParser.Lambda_no_returnContext ctx) { this.nonterminalNodeAsResult(ctx, NonTerminalSymbol.LAMBDA); } @Override public void enterLambda_no_param_no_return(@NotNull LoreParser.Lambda_no_param_no_returnContext ctx) { this.newChildrenList(); } @Override public void exitLambda_no_param_no_return(@NotNull LoreParser.Lambda_no_param_no_returnContext ctx) { List<AST> cs = this.getChildrenList(); AST params = node(NonTerminalSymbol.PARAMS, loc(src, ctx.getStart().getLine())); AST block = cs.get(0); this.result(node(NonTerminalSymbol.LAMBDA, loc(src, ctx.getStart().getLine()), params, block)); } @Override public void enterLambda_parameters(@NotNull LoreParser.Lambda_parametersContext ctx) { this.newChildrenList(); } @Override public void exitLambda_parameters(@NotNull LoreParser.Lambda_parametersContext ctx) { this.nonterminalNodeAsResult(ctx, NonTerminalSymbol.PARAMS); } @Override public void enterLambda_block(@NotNull LoreParser.Lambda_blockContext ctx) { this.newChildrenList(); } @Override public void exitLambda_block(@NotNull LoreParser.Lambda_blockContext ctx) { List<AST> cs = this.getChildrenList(); if (NonTerminalSymbol.BODY.equals(cs.get(0).symbol)) {// child is BODY node. this.result(cs.get(0)); } else {// child is expression node. AST exp = cs.get(0); AST result = node(NonTerminalSymbol.RESULT, loc(src, ctx.getStart().getLine()), exp); AST body = node(NonTerminalSymbol.BODY, loc(src, ctx.getStart().getLine()), result); this.result(body); } } /* * Literals */ @Override public void enterHtml(@NotNull LoreParser.HtmlContext ctx) { this.newChildrenList(); } @Override public void exitHtml(@NotNull LoreParser.HtmlContext ctx) { Object v = ((Literal<?>) this.getChildrenList().get(0)).value; String content = ((SimpleString) v).getContent(); HTML html = HTML.create(content, loc(src, ctx.start.getLine()), logger); Literal<HTML> n = lit(html, loc(src, ctx.start.getLine())); this.result(n); } @Override public void enterXml(@NotNull LoreParser.XmlContext ctx) { this.newChildrenList(); } @Override public void exitXml(@NotNull LoreParser.XmlContext ctx) { Object v = ((Literal<?>) this.getChildrenList().get(0)).value; String content = ((SimpleString) v).getContent(); XML xml = XML.create(content, loc(src, ctx.start.getLine()), logger); AST n = lit(xml, loc(src, ctx.start.getLine())); this.result(n); } @Override public void enterUrl(@NotNull LoreParser.UrlContext ctx) { this.newChildrenList(); } @Override public void exitUrl(@NotNull LoreParser.UrlContext ctx) { Object v = ((Literal<?>) this.getChildrenList().get(0)).value; URL url = null; try { url = Lore.getURL(((SimpleString) v).getContent(), src); } catch (IllegalArgumentException e) { error(ctx, e.getMessage()); url = Locator.NOWHERE.file; } AST n = lit(url, loc(src, ctx.start.getLine())); this.result(n); } @Override public void enterDate(@NotNull LoreParser.DateContext ctx) { this.newChildrenList(); } @Override public void exitDate(@NotNull LoreParser.DateContext ctx) { Object v = ((Literal<?>) this.getChildrenList().get(0)).value; String content = ((SimpleString) v).getContent(); OffsetDateTime date = null; try { date = OffsetDateTime.parse(content); } catch (DateTimeParseException e) { error(ctx, e.getMessage()); date = OffsetDateTime.MAX; } AST n = lit(date, loc(src, ctx.start.getLine())); this.result(n); } @Override public void enterJid(@NotNull LoreParser.JidContext ctx) { this.newChildrenList(); } @Override public void exitJid(@NotNull LoreParser.JidContext ctx) { Object v = ((Literal<?>) this.getChildrenList().get(0)).value; String content = ((SimpleString) v).getContent(); JID jid = JID.NOBODY; try { jid = new JID(content); } catch (JID.SyntaxException e) { this.error(ctx, e.getMessage()); } AST n = lit(jid, loc(src, ctx.start.getLine())); this.result(n); } @Override public void enterLoc(@NotNull LoreParser.LocContext ctx) { this.newChildrenList(); } @Override public void exitLoc(@NotNull LoreParser.LocContext ctx) { Object v = ((Literal<?>) this.getChildrenList().get(0)).value; String content = ((SimpleString) v).getContent(); Location loc = Location.NOWHERE; try { loc = Location.parse(content); } catch (Location.SyntaxException e) { this.error(ctx, e.getMessage()); } AST n = lit(loc, loc(src, ctx.start.getLine())); this.result(n); } @Override public void enterStringLiteral(@NotNull LoreParser.StringLiteralContext ctx) { this.newChildrenList(); } @Override public void exitStringLiteral(@NotNull LoreParser.StringLiteralContext ctx) { // System.err.println("** StringLiteral"); // printContext(ctx); ParseTree child0 = ctx.getChild(0); String text = child0.getText(); String begin = null; String end = null; if (text.startsWith("\"")) { begin = "\""; end = begin; } else if (text.startsWith("'")) { begin = "'"; end = begin; } else { StringBuilder sb = new StringBuilder(); int eqs = text.indexOf("[", 1) - 1; for (int i = 0; i < eqs; ++i) { sb.append("="); } begin = "[" + sb.toString() + "["; end = "]" + sb.toString() + "]"; } String str = trim(text, begin, end); SimpleString simple = new SimpleString(str, loc(src, ctx.start.getLine()), logger); AST n = lit(simple, loc(src, ctx.start.getLine())); this.result(n); } @Override public void enterShortStringLiteral(@NotNull LoreParser.ShortStringLiteralContext ctx) { this.newChildrenList(); } @Override public void exitShortStringLiteral(@NotNull LoreParser.ShortStringLiteralContext ctx) { // System.err.println("** StringLiteral"); // printContext(ctx); ParseTree child0 = ctx.getChild(0); String text = child0.getText(); String begin = null; String end = null; if (text.startsWith("\"")) { begin = "\""; end = begin; } else if (text.startsWith("'")) { begin = "'"; end = begin; } String str = trim(text, begin, end); SimpleString simple = new SimpleString(str, loc(src, ctx.start.getLine()), logger); AST n = lit(simple, loc(src, ctx.start.getLine())); this.result(n); } @Override public void enterIntegral(@NotNull LoreParser.IntegralContext ctx) { this.newChildrenList(); } @Override public void exitIntegral(@NotNull LoreParser.IntegralContext ctx) { // System.err.println("** Integral number"); // printContext(ctx); ParseTree child0 = ctx.getChild(0); String text = child0.getText(); try { long l = parseLongIntegral(text); this.result(lit(l, loc(src, ctx.start.getLine()))); } catch (NumberFormatException e2) { error(ctx, e2.getMessage()); this.result(lit(0L, loc(src, ctx.start.getLine()))); } } // private int parseIntegral(String text) throws NumberFormatException { // int i = 0; // if(text.startsWith("0x") || text.startsWith("0X")){ // i = Integer.parseInt(text.substring(2), 16); // }else{ // i = Integer.parseInt(text, 10); // } // return i; // } private long parseLongIntegral(String text) throws NumberFormatException { long i = 0; if (text.startsWith("0x") || text.startsWith("0X")) { i = Long.parseLong(text.substring(2), 16); } else { i = Long.parseLong(text, 10); } return i; } @Override public void enterReal(@NotNull LoreParser.RealContext ctx) { //System.err.println("entterReal() stack size: "+this.childrenStack.size()); this.newChildrenList(); //System.err.println("newChildrenList() stack size: "+this.childrenStack.size()); } @Override public void exitReal(@NotNull LoreParser.RealContext ctx) { //System.err.println("** Real number"); //printContext(ctx); //System.err.println("exitReal() stack size: "+this.childrenStack.size()); ParseTree child0 = ctx.getChild(0); String text = child0.getText(); double r = Double.NaN; try { r = Double.valueOf(text); this.result(lit(r, loc(src, ctx.start.getLine()))); } catch (NumberFormatException e) { error(ctx, e.getMessage()); this.result(lit(r, loc(src, ctx.start.getLine()))); } } @Override public void enterDiceKind(@NotNull LoreParser.DiceKindContext ctx) { this.newChildrenList(); } // This method works in conjunction with exitDice_monomial(). @Override public void exitDiceKind(@NotNull LoreParser.DiceKindContext ctx) { // System.err.println("** Dice kind"); // printContext(ctx); String text = ctx.getChild(0).getText(); long k = 6; if (text.length() > 1) { k = Long.MAX_VALUE; try { k = Long.parseLong(text.substring(1)); } catch (NumberFormatException e) { this.error(ctx, "Dice kind is invalid.(" + e.getMessage() + ")"); } } Literal<Long> kind = lit(k, loc(src, ctx.start.getLine())); this.result(node(NonTerminalSymbol.DICE, loc(src, ctx.start.getLine()), kind)); } @Override public void enterUnitName(@NotNull LoreParser.UnitNameContext ctx) { this.newChildrenList(); } @Override public void exitUnitName(@NotNull LoreParser.UnitNameContext ctx) { // System.err.println("** Unit name"); // printContext(ctx); String unitName = ctx.getChild(0).getText(); this.result(id(unitName, loc(src, ctx.start.getLine()))); } @Override public void enterSimpleName(@NotNull LoreParser.SimpleNameContext ctx) { this.newChildrenList(); } @Override public void exitSimpleName(@NotNull LoreParser.SimpleNameContext ctx) { // System.err.println("** Unit name"); // printContext(ctx); String name = ctx.getChild(0).getText(); this.result(id(name, loc(src, ctx.start.getLine()))); } }