/* * * Copyright (C) 1997, 1998 Yuuji ICHISUGI * * Permission to use, copy, modify and redistribution this software in * whole and in part, for evaluation or research purposes and without fee * is hereby granted provided this copyright notice. * See CopyrightAndLicensing.txt for licensing condition. */ #epp "Symbol" #epp "SystemMixin" #epp "AutoSplitFiles" #epp "BackQuote" package PComp; import epp.*; import java.util.Vector; public class PlugIn extends SystemMixinLoader { // NOTE: This method will be invoked when #epp "PComp" is specified. public void load(){ // Remove system mixins which define original comparison grammars. SystemMixin[] oldSetupList = new SystemMixin[SystemMixin.setupList.size()]; SystemMixin.setupList.copyInto(oldSetupList); Vector newSetupList = new Vector(); for (int i = 0; i < oldSetupList.length; i++){ Symbol name = (Symbol)oldSetupList[i].name; if (name != :LT && name != :GT && name != :LE && name != :GE && name != :EQ && name != :NE){ newSetupList.addElement(oldSetupList[i]); } } SystemMixin.setupList = newSetupList; // NOTE: The class PComp will be automatically // generated by SystemMixin plug-in. new PComp().load(); } } SystemMixin PComp { class Epp { extend Tree equalityExpressionLeft(Tree tree) { Token token = lookahead(); if (token == :"<" || token == :">" || token == :"<=" || token == :">=" || token == :"==" || token == :"!=") { return `(PComp ,(new Identifier((Symbol)matchAny())) ,tree ,(equalityExpression1())); } else { return original(tree); } } extend void initMacroTable() { original(); defineMacro(:PComp, new PCompMacro()); } extend void initEmitterTable() { original(); defineEmitter(:"<", new SimpleEmitter("(%) < (%)")); defineEmitter(:">", new SimpleEmitter("(%) > (%)")); defineEmitter(:"<=", new SimpleEmitter("(%) <= (%)")); defineEmitter(:">=", new SimpleEmitter("(%) >= (%)")); defineEmitter(:"==", new SimpleEmitter("(%) == (%)")); defineEmitter(:"!=", new SimpleEmitter("(%) != (%)")); } } } class PCompMacro extends Macro { public Tree call(Tree tree){ checkArgsLength(tree, 3); Tree[] args = tree.args(); Tree comp = args[0]; Tree exp1 = args[1]; Tree exp2 = args[2]; if (exp1.tag() == :PComp){ // ((a < b) < c) should be expanded into ((a < (tmp = b)) && tmp < c) // The method invocation expandNestedPythonStyleComparison("a < b") will // return two trees, "a < (tmp = b)" and "tmp" . Tree[] trees = expandNestedPythonStyleComparison(exp1); Tree newExp1 = trees[0]; Tree tmp = trees[1]; return `(&& ,newExp1 ,(new Tree(comp.idName(), tmp, macroExpandTree(exp2)))); } else { // (a < b) is simply translated to (a < b) return new Tree(comp.idName(), macroExpandTree(exp1), macroExpandTree(exp2)); } } Tree[] expandNestedPythonStyleComparison(Tree tree){ Tree[] args = tree.args(); Tree comp = args[0]; Tree exp1 = args[1]; Tree exp2 = args[2]; Tree tmp = new Identifier(genTemp("_T")); // Add a temporary variable declaration. ((TreeVec)Dynamic.get(:beforeCurrentBlockStatement)) .add(`(decl (modifiers) (id int) // Auguments are assumed to be int !! (vardecls ,tmp))); if (exp1.tag() == :PComp){ // "(a < b) < c" // -> "(a < (tmp0 = b)) && (tmp0 < (tmp = c))" and "tmp" Tree[] trees = expandNestedPythonStyleComparison(exp1); Tree newExp1 = trees[0]; Tree tmp0 = trees[1]; Tree[] ret = { `(&& ,newExp1 ,(new Tree(comp.idName(), tmp0, `(= ,tmp ,(macroExpandTree(exp2)))))), tmp}; return ret; } else { // "a < b" -> "a < (tmp = b)" and "tmp" Tree[] ret = { new Tree(comp.idName(), macroExpandTree(exp1), `(= ,tmp ,(macroExpandTree(exp2)))), tmp}; return ret; } } }