/******************************************************************************* * Copyright (c) 2012 Bruno Medeiros and other Contributors. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Bruno Medeiros - initial API and implementation *******************************************************************************/ package dtool.ast.expressions; import static melnorme.utilbox.core.Assert.AssertNamespace.assertTrue; import melnorme.lang.tooling.ast.CommonASTNode; import melnorme.lang.tooling.ast.IASTVisitor; import melnorme.lang.tooling.ast.util.ASTCodePrinter; import melnorme.lang.tooling.ast_actual.ASTNodeTypes; import dtool.parser.DeeTokens; /** * An infix binary expression. */ public class ExpInfix extends Expression { /** * Infix operations types (not just binary expressions) * The ordering of these elements is important as it defines precedence (lower to higher) */ public static enum InfixOpType { COMMA(DeeTokens.COMMA), SLICE(DeeTokens.DOUBLE_DOT), ASSIGN(DeeTokens.ASSIGN), MINUS_ASSIGN( ASSIGN, DeeTokens.MINUS_ASSIGN), PLUS_ASSIGN( ASSIGN, DeeTokens.PLUS_ASSIGN), DIV_ASSIGN( ASSIGN, DeeTokens.DIV_ASSIGN), MULT_ASSIGN( ASSIGN, DeeTokens.MULT_ASSIGN), MOD_ASSIGN( ASSIGN, DeeTokens.MOD_ASSIGN), POW_ASSIGN( ASSIGN, DeeTokens.POW_ASSIGN), AND_ASSIGN( ASSIGN, DeeTokens.AND_ASSIGN), OR_ASSIGN( ASSIGN, DeeTokens.OR_ASSIGN), XOR_ASSIGN( ASSIGN, DeeTokens.XOR_ASSIGN), CONCAT_ASSIGN( ASSIGN, DeeTokens.CONCAT_ASSIGN), LEFT_SHIFT_ASSIGN( ASSIGN, DeeTokens.LEFT_SHIFT_ASSIGN), RIGHT_SHIFT_ASSIGN( ASSIGN, DeeTokens.RIGHT_SHIFT_ASSIGN), TRIPLE_RSHIFT_ASSIGN(ASSIGN, DeeTokens.TRIPLE_RSHIFT_ASSIGN), CONDITIONAL(DeeTokens.QUESTION), LOGICAL_OR(DeeTokens.LOGICAL_OR), LOGICAL_AND(DeeTokens.LOGICAL_AND), OR(DeeTokens.OR), XOR(DeeTokens.XOR), AND(DeeTokens.AND), EQUALS(DeeTokens.EQUALS), NOT_EQUAL( EQUALS, DeeTokens.NOT_EQUAL), IS( EQUALS, DeeTokens.KW_IS), NOT_IS( EQUALS, "!is"), IN( EQUALS, DeeTokens.KW_IN), NOT_IN( EQUALS, "!in"), LESS_THAN( EQUALS, DeeTokens.LESS_THAN), LESS_EQUAL( EQUALS, DeeTokens.LESS_EQUAL), GREATER_THAN( EQUALS, DeeTokens.GREATER_THAN), GREATER_EQUAL(EQUALS, DeeTokens.GREATER_EQUAL), LESS_GREATER( EQUALS, DeeTokens.LESS_GREATER), LESS_GREATER_EQUAL(EQUALS, DeeTokens.LESS_GREATER_EQUAL), UNORDERED_E( EQUALS, DeeTokens.UNORDERED_E), UNORDERED( EQUALS, DeeTokens.UNORDERED), UNORDERED_GE( EQUALS, DeeTokens.UNORDERED_GE), UNORDERED_G( EQUALS, DeeTokens.UNORDERED_G), UNORDERED_LE( EQUALS, DeeTokens.UNORDERED_LE), UNORDERED_L( EQUALS, DeeTokens.UNORDERED_L), SHIFT(DeeTokens.LEFT_SHIFT), RIGHT_SHIFT( SHIFT, DeeTokens.RIGHT_SHIFT), UNSIGNED_RSHIFT(SHIFT, DeeTokens.TRIPLE_RSHIFT), ADD(DeeTokens.PLUS), MINUS( ADD, DeeTokens.MINUS), CONCAT(ADD, DeeTokens.CONCAT), MUL(DeeTokens.STAR), DIV(MUL, DeeTokens.DIV), MOD(MUL, DeeTokens.MOD), POW(DeeTokens.POW), NULL(null, (String) null), // Special entry that doesn't represent any infix operator ; public final InfixOpType category; public final String sourceValue; public final int precedence; InfixOpType(InfixOpType category, String sourceValue) { this.category = category == null ? this : category; this.precedence = category == null ? Holder.precedenceCounter++ : category.precedence; this.sourceValue = sourceValue; } InfixOpType(InfixOpType category, DeeTokens tokenType) { this(category, tokenType.getSourceValue()); int ix = tokenType.ordinal(); assertTrue(Holder.mapping[ix] == null); Holder.mapping[ix] = this; } InfixOpType(DeeTokens tokenType) { this(null, tokenType); } protected static class Holder { private static int precedenceCounter = 1; private static final InfixOpType[] mapping = new InfixOpType[DeeTokens.values().length]; } public static InfixOpType tokenToInfixOpType(DeeTokens token) { return Holder.mapping[token.ordinal()]; } } public final Expression leftExp; public final InfixOpType kind; public final Expression rightExp; public ExpInfix(Expression leftExp, InfixOpType kind, Expression rightExp) { this.leftExp = parentize(leftExp); this.kind = kind; assertTrue(this.kind != InfixOpType.NULL); this.rightExp = parentize(rightExp); } @Override public ASTNodeTypes getNodeType() { return ASTNodeTypes.EXP_INFIX; } @Override public void visitChildren(IASTVisitor visitor) { acceptVisitor(visitor, leftExp); acceptVisitor(visitor, rightExp); } @Override protected CommonASTNode doCloneTree() { return new ExpInfix(clone(leftExp), kind, clone(rightExp)); } @Override public void toStringAsCode(ASTCodePrinter cp) { cp.append(leftExp); cp.appendStrings(" ", kind.sourceValue, " "); // Some operators have alpha so we need spaces to sep. cp.append(rightExp); } }