/**
* Copyright 2012 Tobias Gierke <tobias.gierke@code-sourcery.de>
*
* 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 de.codesourcery.jasm16.parser;
import java.io.IOException;
import de.codesourcery.jasm16.ast.ASTNode;
import de.codesourcery.jasm16.ast.ASTUtils;
import de.codesourcery.jasm16.ast.ExpressionNode;
import de.codesourcery.jasm16.ast.ISimpleASTNodeVisitor;
import de.codesourcery.jasm16.ast.NumberNode;
import de.codesourcery.jasm16.ast.OperatorNode;
import de.codesourcery.jasm16.ast.TermNode;
import de.codesourcery.jasm16.compiler.CompilationUnit;
import de.codesourcery.jasm16.compiler.ICompilationContext;
import de.codesourcery.jasm16.compiler.ICompilationUnit;
import de.codesourcery.jasm16.exceptions.ParseException;
import de.codesourcery.jasm16.utils.Misc;
public class ExpressionNodeTest extends TestHelper {
public void testParseNegativeNumberOnly() throws IOException {
final String source = "-7";
final IParseContext context = createParseContext( source );
ASTNode result = new ExpressionNode().parse( context );
assertFalse( result.hasErrors() );
assertTrue( result instanceof TermNode );
TermNode expr = (TermNode) result;
ICompilationContext compContext = createCompilationContext( CompilationUnit.createInstance("string",source) );
assertEquals( Long.valueOf( -7 ) , expr.calculate( compContext.getSymbolTable() ) );
}
public void testParseBitwiseAnd() throws IOException {
// 111
final String source = "7 & 4";
final IParseContext context = createParseContext( source );
ASTNode result = new ExpressionNode().parse( context );
assertFalse( result.hasErrors() );
assertTrue( result instanceof TermNode );
TermNode expr = (TermNode) result;
ICompilationContext compContext = createCompilationContext( CompilationUnit.createInstance("string",source) );
Long calculated = expr.calculate( compContext.getSymbolTable() );
System.out.println("Result: "+Misc.toBinaryString( calculated.intValue() , 16 ) );
assertEquals( Long.valueOf( 4 ) , calculated );
}
public void testParseBitwiseOr() throws IOException {
// 111
final String source = "2 | 5";
final IParseContext context = createParseContext( source );
ASTNode result = new ExpressionNode().parse( context );
assertFalse( result.hasErrors() );
assertTrue( result instanceof TermNode );
TermNode expr = (TermNode) result;
ICompilationContext compContext = createCompilationContext( CompilationUnit.createInstance("string",source) );
Long calculated = expr.calculate( compContext.getSymbolTable() );
System.out.println("Result: "+Misc.toBinaryString( calculated.intValue() , 16 ) );
assertEquals( Long.valueOf( 7 ) , calculated );
}
public void testParseBitwiseXOR() throws IOException {
// 111
final String source = "5 ^ 11";
final IParseContext context = createParseContext( source );
ASTNode result = new ExpressionNode().parse( context );
assertFalse( result.hasErrors() );
assertTrue( result instanceof TermNode );
TermNode expr = (TermNode) result;
ICompilationContext compContext = createCompilationContext( CompilationUnit.createInstance("string",source) );
Long calculated = expr.calculate( compContext.getSymbolTable() );
System.out.println("Result: "+Misc.toBinaryString( calculated.intValue() , 16 ) );
assertEquals( Long.valueOf( 14 ) , calculated );
}
public void testParseExpressionWithDifferentNumberLiteralNotations() throws Exception
{
final String source = "2 + 5 - 10 * 0x100 + b10101";
final IParseContext context = createParseContext( source );
ASTNode result = new ExpressionNode().parse( context );
ASTUtils.printAST(result );
assertFalse( result.hasErrors() );
assertTrue( result instanceof TermNode );
TermNode expr = (TermNode) result;
ICompilationContext compContext = createCompilationContext( CompilationUnit.createInstance("string",source) );
Long calculated = expr.calculate( compContext.getSymbolTable() );
assertEquals( Long.valueOf( -2532 ) , calculated );
}
public void testParseNegation() throws IOException {
// 111
final String source = "2+~5";
final IParseContext context = createParseContext( source );
ASTNode result = new ExpressionNode().parse( context );
assertFalse( result.hasErrors() );
assertTrue( result instanceof TermNode );
TermNode expr = (TermNode) result;
ICompilationContext compContext = createCompilationContext( CompilationUnit.createInstance("string",source) );
Long calculated = expr.calculate( compContext.getSymbolTable() );
System.out.println("Result: "+Misc.toBinaryString( calculated.intValue() , 16 ) );
assertEquals( Long.valueOf( -4 ) , calculated );
}
public void testCalculateValueWithNegativeNumber() throws IOException {
final String source = " (1 + 3)*5 - - 7 ";
final IParseContext context = createParseContext( source );
ASTNode result = new ExpressionNode().parse( context );
assertFalse( result.hasErrors() );
assertTrue( result instanceof TermNode );
TermNode expr = (TermNode) result;
ICompilationContext compContext = createCompilationContext( CompilationUnit.createInstance("string",source) );
assertEquals( Long.valueOf( 27 ) , expr.calculate( compContext.getSymbolTable() ) );
}
public void testCalculateValueWithNegativeNumber2() throws IOException {
final String source = " (1 + 3)*5 + - 7 ";
final IParseContext context = createParseContext( source );
ASTNode result = new ExpressionNode().parse( context );
assertFalse( result.hasErrors() );
assertTrue( result instanceof TermNode );
TermNode expr = (TermNode) result;
ICompilationContext compContext = createCompilationContext( CompilationUnit.createInstance("string",source) );
assertEquals( Long.valueOf( 13 ) , expr.calculate( compContext.getSymbolTable() ) );
}
public void testCalculateValueWithNegativeNumber3() throws IOException {
final String source = " (1 + -3)*5 + - 7 ";
final IParseContext context = createParseContext( source );
ASTNode result = new ExpressionNode().parse( context );
assertFalse( result.hasErrors() );
assertTrue( result instanceof TermNode );
TermNode expr = (TermNode) result;
ICompilationContext compContext = createCompilationContext( CompilationUnit.createInstance("string",source) );
assertEquals( Long.valueOf( -17 ) , expr.calculate( compContext.getSymbolTable() ) );
}
public void testTooManyMinusOperators() throws IOException {
final String source = " (1 + 3)*5 - - - 7 ";
final IParseContext context = createParseContext( source );
ASTNode result = new ExpressionNode().parse( context );
assertTrue( result.hasErrors() );
}
public void testCalculateValue() throws IOException {
final String source = " (1 + 3)*5 -7 ";
final IParseContext context = createParseContext( source );
ASTNode result = new ExpressionNode().parse( context );
assertFalse( result.hasErrors() );
assertTrue( result instanceof TermNode );
TermNode expr = (TermNode) result;
ICompilationContext compContext = createCompilationContext( CompilationUnit.createInstance("string",source) );
assertEquals( Long.valueOf( 13 ) , expr.calculate( compContext.getSymbolTable() ) );
}
public void testParseNumberLiteral() {
final String expression = "0x1234";
final IParseContext parseContext = createParseContext( expression );
final ASTNode result = new ExpressionNode().parse( parseContext );
assertNotNull( result );
assertFalse( result.hasErrors() );
assertEquals( expression , toSourceCode( result , expression ) );
}
public void testParseRegisterReference() {
final String expression = " SP ";
final IParseContext parseContext = createParseContext( expression );
final ASTNode result = new ExpressionNode().parse( parseContext );
assertNotNull( result );
assertFalse( result.hasErrors() );
assertEquals( expression , toSourceCode( result , expression ) );
}
public void testParseAddition() {
final String expression = "1 + 2";
final IParseContext parseContext = createParseContext( expression );
final ASTNode result = new ExpressionNode().parse( parseContext );
assertNotNull( result );
assertFalse( result.hasErrors() );
assertEquals( expression , toSourceCode( result , expression ) );
}
public void testParseExpressionWithParens() {
final String expression = "(1 + 2)";
final IParseContext parseContext = createParseContext( expression );
final ASTNode result = new ExpressionNode().parse( parseContext );
ASTUtils.printAST( result );
assertNotNull( result );
assertFalse( result.hasErrors() );
assertEquals( OperatorNode.class , result.getClass() );
OperatorNode op = (OperatorNode) result;
assertEquals( 2 , op.getChildCount() );
assertEquals( NumberNode.class ,op.child(0).getClass() );
assertEquals( NumberNode.class , op.child(1).getClass() );
assertEquals( expression , toSourceCode( result , expression ) );
}
public void testParseIncompleteExpression() {
final String expression = "1+2*";
final IParseContext parseContext = createParseContext( expression );
final ASTNode result = new ExpressionNode().parse( parseContext );
assertNotNull( result );
assertTrue( result.hasErrors() );
}
public void testOperatorPrecedence() {
final String expression = " (4+5*(3+2))";
final IParseContext parseContext = createParseContext( expression );
final ASTNode result = new ExpressionNode().parse( parseContext );
assertNotNull( result );
assertFalse( result.hasErrors() );
assertEquals( expression , toSourceCode( result , expression ) );
}
public void testParseExpressionWithNestedParens() {
final String expression = "(((1 + 2)))";
final IParseContext parseContext = createParseContext( expression );
final ASTNode result = new ExpressionNode().parse( parseContext );
assertNotNull( result );
assertFalse( result.hasErrors() );
final ISimpleASTNodeVisitor<ASTNode> visitor = new ISimpleASTNodeVisitor<ASTNode>() {
@Override
public boolean visit(ASTNode node)
{
System.out.println( node.getClass().getName() +" '"+node.toString()+"'" );
return true;
}
};
ASTUtils.visitInOrder( result , visitor );
assertEquals( expression , toSourceCode( result , expression ) );
}
public void testParseExpressionWithNestedParens2() {
final String expression = "((( 1+2 )))";
final IParseContext parseContext = createParseContext( expression );
final ASTNode result = new ExpressionNode().parse( parseContext );
assertNotNull( result );
assertFalse( result.hasErrors() );
final ISimpleASTNodeVisitor<ASTNode> visitor = new ISimpleASTNodeVisitor<ASTNode>() {
@Override
public boolean visit(ASTNode node)
{
System.out.println( node.getClass().getName() +" '"+node.toString()+"'" );
return true;
}
};
ASTUtils.visitInOrder( result , visitor );
assertEquals( expression , toSourceCode( result , expression ) );
}
public void testParseSubtraction() {
final String expression = "1 - 2";
final IParseContext parseContext = createParseContext( expression );
final ASTNode result = new ExpressionNode().parse( parseContext );
assertNotNull( result );
assertFalse( result.hasErrors() );
assertEquals( expression , toSourceCode( result , expression ) );
}
public void testParseMultiplication() {
final String expression = "1 * 2";
final IParseContext parseContext = createParseContext( expression );
final ASTNode result = new ExpressionNode().parse( parseContext );
assertNotNull( result );
assertEquals( expression , toSourceCode( result , expression ) );
}
public void testParseDivision() {
final String expression = "1 / 2";
final IParseContext parseContext = createParseContext( expression );
final ASTNode result = new ExpressionNode().parse( parseContext );
assertNotNull( result );
assertFalse( result.hasErrors() );
assertEquals( expression , toSourceCode( result , expression ) );
}
public void testParseMismatchedClosingParensFails() {
final String expression = "((1+2)";
final IParseContext parseContext = createParseContext( expression );
final ASTNode result = new ExpressionNode().parse( parseContext );
assertNotNull( result );
assertTrue( result.hasErrors() );
assertEquals( expression , toSourceCode( result , expression ) );
}
public void testParseMismatchedOpeningParensFails() {
assertDoesNotCompile( "SET A ,1+2)" );
}
public void testFoldSimpleConstantExpression() throws ParseException, IOException {
final String source = " 1 + 1 ";
final ICompilationUnit unit = CompilationUnit.createInstance("string input" , source );
final ICompilationContext compilationContext = createCompilationContext( unit );
final IParseContext context = createParseContext( source );
final ASTNode result = new ExpressionNode().parse( context );
assertFalse( result.hasErrors() );
final TermNode foldingResult = ((TermNode) result).reduce( compilationContext );
assertEquals( NumberNode.class , foldingResult.getClass() );
assertEquals( 2L , ((NumberNode) foldingResult).getValue() );
}
public void testFoldConstantExpression1j() throws ParseException, IOException {
final String source = " 1 + 4 + 5 * 3 ";
final ICompilationUnit unit = CompilationUnit.createInstance("string input" , source );
final ICompilationContext compilationContext = createCompilationContext( unit );
final IParseContext context = createParseContext( source );
final ASTNode result = new ExpressionNode().parse( context );
ASTUtils.printAST( result );
assertFalse( result.hasErrors() );
final TermNode foldingResult = ((TermNode) result).reduce( compilationContext );
assertEquals( NumberNode.class , foldingResult.getClass() );
assertEquals( 20L , ((NumberNode) foldingResult).getValue() );
}
public void testFoldConstantExpression1a() throws ParseException, IOException {
final String source = " ( 3+3 ) *2 ";
final ICompilationUnit unit = CompilationUnit.createInstance("string input" , source );
final ICompilationContext compilationContext = createCompilationContext(unit);
final IParseContext context = createParseContext( source );
final ASTNode result = new ExpressionNode().parse( context );
assertFalse( result.hasErrors() );
final TermNode foldingResult = ((TermNode) result).reduce( compilationContext );
assertEquals( NumberNode.class , foldingResult.getClass() );
assertEquals( 12L , ((NumberNode) foldingResult).getValue() );
}
public void testFoldConstantExpression1c() throws ParseException, IOException {
final String source = " ( 3+(3*2)) ";
final ICompilationUnit unit = CompilationUnit.createInstance("string input" , source );
final ICompilationContext compilationContext = createCompilationContext(unit);
final IParseContext context = createParseContext( source );
final ASTNode result = new ExpressionNode().parse( context );
assertFalse( result.hasErrors() );
final TermNode foldingResult = ((TermNode) result).reduce( compilationContext );
assertEquals( NumberNode.class , foldingResult.getClass() );
assertEquals( 9L , ((NumberNode) foldingResult).getValue() );
}
public void testFoldConstantExpression1d() throws ParseException, IOException {
final String source = " ( (3+3)*2) ";
final ICompilationUnit unit = CompilationUnit.createInstance("string input" , source );
final ICompilationContext compilationContext = createCompilationContext(unit);
final IParseContext context = createParseContext( source );
final ASTNode result = new ExpressionNode().parse( context );
assertFalse( result.hasErrors() );
final TermNode foldingResult = ((TermNode) result).reduce( compilationContext );
assertEquals( NumberNode.class , foldingResult.getClass() );
assertEquals( 12L , ((NumberNode) foldingResult).getValue() );
}
public void testFoldConstantExpression1e() throws ParseException, IOException {
final String source = " 4-3 ";
final ICompilationUnit unit = CompilationUnit.createInstance("string input" , source );
final ICompilationContext compilationContext = createCompilationContext(unit);
final IParseContext context = createParseContext( source );
final ASTNode result = new ExpressionNode().parse( context );
assertFalse( result.hasErrors() );
final TermNode foldingResult = ((TermNode) result).reduce( compilationContext );
assertEquals( NumberNode.class , foldingResult.getClass() );
assertEquals( 1L , ((NumberNode) foldingResult).getValue() );
}
public void testFoldConstantExpression1f() throws ParseException, IOException {
final String source = " 13-(3*3) ";
final ICompilationUnit unit = CompilationUnit.createInstance("string input" , source );
final ICompilationContext compilationContext = createCompilationContext(unit);
final IParseContext context = createParseContext( source );
final ASTNode result = new ExpressionNode().parse( context );
assertFalse( result.hasErrors() );
final TermNode foldingResult = ((TermNode) result).reduce( compilationContext );
assertEquals( NumberNode.class , foldingResult.getClass() );
assertEquals( 4L , ((NumberNode) foldingResult).getValue() );
}
public void testFoldConstantExpression1g() throws ParseException, IOException {
final String source = " (13-3)*3 ";
final ICompilationUnit unit = CompilationUnit.createInstance("string input" , source );
final ICompilationContext compilationContext = createCompilationContext(unit);
final IParseContext context = createParseContext( source );
final ASTNode result = new ExpressionNode().parse( context );
assertFalse( result.hasErrors() );
final TermNode foldingResult = ((TermNode) result).reduce( compilationContext );
assertEquals( NumberNode.class , foldingResult.getClass() );
assertEquals( 30L , ((NumberNode) foldingResult).getValue() );
}
public void testFoldConstantExpression1h() throws ParseException, IOException {
final String source = " (3 + ((4 * 2) / ( 1 - 5 ) )) "; // 3 + ( 8 / -4 ) = 3 + -2 = 1
final ICompilationUnit unit = CompilationUnit.createInstance("string input" , source );
final ICompilationContext compilationContext = createCompilationContext(unit);
final IParseContext context = createParseContext( source );
final ASTNode result = new ExpressionNode().parse( context );
ASTUtils.printAST( result );
assertFalse( result.hasErrors() );
final TermNode foldingResult = ((TermNode) result).reduce( compilationContext );
assertEquals( NumberNode.class , foldingResult.getClass() );
assertEquals( 1L , ((NumberNode) foldingResult).getValue() );
}
public void testFoldConstantExpression() throws ParseException, IOException {
final String source = " ( ( ( 3+3 ) *2 ) - 4 ) / ( 1 + 1)";
final ICompilationUnit unit = CompilationUnit.createInstance("string input" , source );
final ICompilationContext compilationContext = createCompilationContext(unit);
final IParseContext context = createParseContext( source );
final ASTNode result = new ExpressionNode().parse( context );
assertFalse( result.hasErrors() );
final TermNode foldingResult = ((TermNode) result).reduce( compilationContext );
assertEquals( NumberNode.class , foldingResult.getClass() );
assertEquals( 4L , ((NumberNode) foldingResult).getValue() );
}
public void testFoldConstantExpression1b() throws ParseException, IOException {
final String source = "( ( 3+3 ) *2 ) - 4"; //
final ICompilationUnit unit = CompilationUnit.createInstance("string input" , source );
final ICompilationContext compilationContext = createCompilationContext(unit);
final IParseContext context = createParseContext( source );
final ASTNode result = new ExpressionNode().parse( context );
ASTUtils.printAST( result );
assertFalse( result.hasErrors() );
final TermNode foldingResult = ((TermNode) result).reduce( compilationContext );
assertEquals( NumberNode.class , foldingResult.getClass() );
assertEquals( 8L , ((NumberNode) foldingResult).getValue() );
}
public void testFoldRegisterExpression1() throws ParseException, IOException {
final String source = " 3 + a ";
final ICompilationUnit unit = CompilationUnit.createInstance("string input" , source );
final ICompilationContext compilationContext = createCompilationContext(unit);
final IParseContext context = createParseContext( source );
final ASTNode result = new ExpressionNode().parse( context );
assertFalse( result.hasErrors() );
assertEquals( source , toSourceCode( result , source ) );
final TermNode foldingResult = ((TermNode) result).reduce( compilationContext );
assertEquals( source , toSourceCode( foldingResult , source ) );
}
public void testFoldRegisterExpression2() throws ParseException, IOException {
final String source = " a + 3 ";
final ICompilationUnit unit = CompilationUnit.createInstance("string input" , source );
final ICompilationContext compilationContext = createCompilationContext(unit);
final IParseContext context = createParseContext( source );
final ASTNode result = new ExpressionNode().parse( context );
assertFalse( result.hasErrors() );
final TermNode foldingResult = ((TermNode) result).reduce( compilationContext );
assertEquals( source , toSourceCode( foldingResult , source ) );
}
public void testFoldRegisterExpression3a() throws ParseException, IOException {
final String source = " 3+3 ";
final ICompilationUnit unit = CompilationUnit.createInstance("string input" , source );
final ICompilationContext compilationContext = createCompilationContext(unit);
final IParseContext context = createParseContext( source );
final ASTNode result = new ExpressionNode().parse( context );
assertFalse( result.hasErrors() );
assertEquals( source , toSourceCode( result , source ) );
final TermNode foldingResult = ((TermNode) result).reduce( compilationContext );
assertEquals( NumberNode.class , foldingResult.getClass() );
assertEquals( 6L , ((NumberNode) foldingResult).getValue() );
assertEquals( source , toSourceCode( foldingResult , source ) );
}
public void testFoldRegisterExpression3() throws ParseException, IOException {
final String source = " a+3+3 ";
final ICompilationUnit unit = CompilationUnit.createInstance("string input" , source );
final ICompilationContext compilationContext = createCompilationContext(unit);
final IParseContext context = createParseContext( source );
final ASTNode result = new ExpressionNode().parse( context );
assertFalse( result.hasErrors() );
assertEquals( source , toSourceCode( result , source ) );
final ASTNode foldingResult = ((TermNode) result).reduce( compilationContext );
assertEquals( source , toSourceCode( foldingResult , source ) );
}
public void testFoldRegisterExpression4() throws ParseException, IOException {
final String source = " 2*3 + a ";
final ICompilationUnit unit = CompilationUnit.createInstance("string input" , source );
final ICompilationContext compilationContext = createCompilationContext(unit);
final IParseContext context = createParseContext( source );
final ASTNode result = new ExpressionNode().parse( context );
assertFalse( result.hasErrors() );
final TermNode foldingResult = ((TermNode) result).reduce( compilationContext );
assertEquals( source , toSourceCode( foldingResult , source ) );
}
public void testExpressionWithCharacterLiteral1() throws ParseException, IOException {
final String source = " 3 + \"a\" ";
final IParseContext context = createParseContext( source );
final ASTNode result = new ExpressionNode().parse( context );
ASTUtils.printAST( result );
assertFalse( result.hasErrors() );
final Long value = ((TermNode) result).calculate( symbolTable );
assertEquals( source , toSourceCode( result , source ) );
final int expected = 'a'+3;
assertEquals( expected , value.intValue() );
}
public void testExpressionWithCharacterLiteral2() throws ParseException, IOException {
final String source = " \"a\" + 3 ";
final IParseContext context = createParseContext( source );
final ASTNode result = new ExpressionNode().parse( context );
ASTUtils.printAST( result );
assertFalse( result.hasErrors() );
final Long value = ((TermNode) result).calculate( symbolTable );
assertEquals( source , toSourceCode( result , source ) );
final int expected = 'a'+3;
assertEquals( expected , value.intValue() );
}
public void testFoldRegisterExpression5() throws ParseException, IOException {
final String source = " 3 + a + 3 ";
final ICompilationUnit unit = CompilationUnit.createInstance("string input" , source );
final ICompilationContext compilationContext = createCompilationContext(unit);
final IParseContext context = createParseContext( source );
final ASTNode result = new ExpressionNode().parse( context );
assertFalse( result.hasErrors() );
final TermNode foldingResult = ((TermNode) result).reduce( compilationContext );
assertEquals( source , toSourceCode( foldingResult , source ) );
}
public void testFoldRegisterExpression6() throws ParseException, IOException {
final String source = " 1 + 2 + 3 + a + 4 + 5 + 6 ";
final ICompilationUnit unit = CompilationUnit.createInstance("string input" , source );
final ICompilationContext compilationContext = createCompilationContext( unit );
final IParseContext context = createParseContext( source );
final ASTNode result = new ExpressionNode().parse( context );
assertFalse( result.hasErrors() );
final TermNode foldingResult = ((TermNode) result).reduce( compilationContext );
assertEquals( source , toSourceCode( foldingResult , source ) );
}
}