Skip to content

Commit

Permalink
Support try-catch-finally
Browse files Browse the repository at this point in the history
This more or less rewrites how we do try-catch-finally. From an API point-of-view it looks
the same but behind the scenes we actually create the entire try-catch-finally in one go.
  • Loading branch information
pontusmelke committed May 17, 2016
1 parent 6834986 commit 1aa2a67
Show file tree
Hide file tree
Showing 15 changed files with 759 additions and 90 deletions.
46 changes: 46 additions & 0 deletions community/codegen/src/main/java/org/neo4j/codegen/CatchClause.java
@@ -0,0 +1,46 @@
/*
* Copyright (c) 2002-2016 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.codegen;

import java.util.List;
import java.util.function.Consumer;

public class CatchClause
{
private final Parameter exception;
private final List<Consumer<MethodEmitter>> actions;

public CatchClause( Parameter exception, List<Consumer<MethodEmitter>> actions )
{
this.exception = exception;
this.actions = actions;
}

public Parameter exception()
{
return exception;
}

public List<Consumer<MethodEmitter>> actions()
{
return actions;
}

}
76 changes: 31 additions & 45 deletions community/codegen/src/main/java/org/neo4j/codegen/CodeBlock.java
Expand Up @@ -19,39 +19,41 @@
*/ */
package org.neo4j.codegen; package org.neo4j.codegen;


import java.util.HashMap; import java.util.function.Consumer;
import java.util.Map;


import static org.neo4j.codegen.LocalVariables.copy;
import static org.neo4j.codegen.Resource.withResource; import static org.neo4j.codegen.Resource.withResource;
import static org.neo4j.codegen.TypeReference.typeReference; import static org.neo4j.codegen.TypeReference.typeReference;


public class CodeBlock implements AutoCloseable public class CodeBlock implements AutoCloseable
{ {

final ClassGenerator clazz; final ClassGenerator clazz;
private MethodEmitter emitter; private MethodEmitter emitter;
private final CodeBlock parent; private final CodeBlock parent;
private boolean done; private boolean done;
private Map<String, LocalVariable> localVariables = new HashMap<>( );
private int varCount = 0; protected LocalVariables localVariables = new LocalVariables();


CodeBlock( CodeBlock parent ) CodeBlock( CodeBlock parent )
{ {
this.clazz = parent.clazz; this.clazz = parent.clazz;
this.emitter = parent.emitter; this.emitter = parent.emitter;
parent.emitter = InvalidState.IN_SUB_BLOCK; parent.emitter = InvalidState.IN_SUB_BLOCK;
this.parent = parent; this.parent = parent;
this.localVariables = parent.localVariables; //copy over local variables from parent
this.localVariables = copy(parent.localVariables);
} }


CodeBlock( ClassGenerator clazz, MethodEmitter emitter, Parameter...parameters ) CodeBlock( ClassGenerator clazz, MethodEmitter emitter, Parameter...parameters )
{ {
this.clazz = clazz; this.clazz = clazz;
this.emitter = emitter; this.emitter = emitter;
this.parent = null; this.parent = null;
localVariables.put("this", localVariable( clazz.handle(), "this" ) ); localVariables.createNew( clazz.handle(), "this" );
for ( Parameter parameter : parameters ) for ( Parameter parameter : parameters )
{ {
localVariables.put( parameter.name(), localVariable( parameter.type(), parameter.name() ) ); localVariables.createNew( parameter.type(), parameter.name() );
} }
} }


Expand All @@ -75,7 +77,7 @@ public void close()
this.emitter = InvalidState.BLOCK_CLOSED; this.emitter = InvalidState.BLOCK_CLOSED;
} }


private void endBlock() protected void endBlock()
{ {
if ( !done ) if ( !done )
{ {
Expand All @@ -84,9 +86,14 @@ private void endBlock()
} }
} }


protected void emit( Consumer<MethodEmitter> emitFunction )
{
emitFunction.accept( emitter );
}

public void expression( Expression expression ) public void expression( Expression expression )
{ {
emitter.expression( expression ); emit( ( e ) -> e.expression( expression ) );
} }


LocalVariable local( String name ) LocalVariable local( String name )
Expand All @@ -96,15 +103,14 @@ LocalVariable local( String name )


public LocalVariable declare( TypeReference type, String name ) public LocalVariable declare( TypeReference type, String name )
{ {
LocalVariable local = localVariable( type, name ); LocalVariable local = localVariables.createNew( type, name );
localVariables.put(name, local); emit( e -> e.declare( local ) );
emitter.declare( local );
return local; return local;
} }


public void assign( LocalVariable local, Expression value ) public void assign( LocalVariable local, Expression value )
{ {
emitter.assignVariableInScope( local, value ); emit( e -> e.assignVariableInScope( local, value ) );
} }


public void assign( Class<?> type, String name, Expression value ) public void assign( Class<?> type, String name, Expression value )
Expand All @@ -114,14 +120,13 @@ public void assign( Class<?> type, String name, Expression value )


public void assign( TypeReference type, String name, Expression value ) public void assign( TypeReference type, String name, Expression value )
{ {
LocalVariable variable = localVariable( type, name ); LocalVariable variable = localVariables.createNew( type, name );
localVariables.put(name, variable ); emit( e -> e.assign( variable, value ) );
emitter.assign( variable, value );
} }


public void put( Expression target, FieldReference field, Expression value ) public void put( Expression target, FieldReference field, Expression value )
{ {
emitter.put( target, field, value ); emit( e -> e.put( target, field, value ) );
} }


public Expression self() public Expression self()
Expand All @@ -136,74 +141,55 @@ public Expression load( String name )


public CodeBlock forEach( Parameter local, Expression iterable ) public CodeBlock forEach( Parameter local, Expression iterable )
{ {
emitter.beginForEach( local, iterable ); emit( e -> e.beginForEach( local, iterable ) );
return new CodeBlock( this ); return new CodeBlock( this );
} }


public CodeBlock whileLoop( Expression test ) public CodeBlock whileLoop( Expression test )
{ {
emitter.beginWhile( test ); emit( e -> e.beginWhile( test ) );
return new CodeBlock( this ); return new CodeBlock( this );
} }


public CodeBlock ifStatement( Expression test ) public CodeBlock ifStatement( Expression test )
{ {
emitter.beginIf( test ); emit( e -> e.beginIf( test ) );
return new CodeBlock( this ); return new CodeBlock( this );
} }


CodeBlock emitCatch( Parameter exception ) public TryBlock tryBlock( Class<?> resourceType, String resourceName, Expression resource )
{
endBlock();
emitter.beginCatch( exception );
return new CodeBlock( this );
}

CodeBlock emitFinally()
{
endBlock();
emitter.beginFinally();
return new CodeBlock( this );
}

public CodeBlock tryBlock( Class<?> resourceType, String resourceName, Expression resource )
{ {
return tryBlock( withResource( resourceType, resourceName, resource ) ); return tryBlock( withResource( resourceType, resourceName, resource ) );
} }


public CodeBlock tryBlock( TypeReference resourceType, String resourceName, Expression resource ) public TryBlock tryBlock( TypeReference resourceType, String resourceName, Expression resource )
{ {
return tryBlock( withResource( resourceType, resourceName, resource ) ); return tryBlock( withResource( resourceType, resourceName, resource ) );
} }


public TryBlock tryBlock( Resource... resources ) public TryBlock tryBlock( Resource... resources )
{ {
emitter.beginTry( resources ); return new TryBlock( this, resources );
return new TryBlock( this );
} }


public void returns() public void returns()
{ {
emitter.returns(); emit( MethodEmitter::returns );
} }


public void returns( Expression value ) public void returns( Expression value )
{ {
emitter.returns( value ); emit( e -> e.returns( value ) );
} }


public void throwException( Expression exception ) public void throwException( Expression exception )
{ {
emitter.throwException( exception ); emit( e -> e.throwException( exception ) );
} }


public TypeReference owner() public TypeReference owner()
{ {
return clazz.handle(); return clazz.handle();
} }


private LocalVariable localVariable( TypeReference type, String name )
{
return new LocalVariable( type, name, varCount++ );
}
} }
Expand Up @@ -70,7 +70,7 @@ public void accept( ExpressionVisitor visitor )
}; };
} }


static Expression load( final LocalVariable variable) public static Expression load( final LocalVariable variable)
{ {
return new Expression() return new Expression()
{ {
Expand Down
Expand Up @@ -19,6 +19,9 @@
*/ */
package org.neo4j.codegen; package org.neo4j.codegen;


import java.util.List;
import java.util.function.Consumer;

class InvalidState implements MethodEmitter class InvalidState implements MethodEmitter
{ {
public static final ClassEmitter CLASS_DONE = new ClassEmitter() public static final ClassEmitter CLASS_DONE = new ClassEmitter()
Expand Down Expand Up @@ -98,20 +101,15 @@ public void beginIf( Expression test )
throw new IllegalStateException( reason ); throw new IllegalStateException( reason );
} }


@Override
public void beginFinally()
{
throw new IllegalStateException( reason );
}

@Override @Override
public void endBlock() public void endBlock()
{ {
throw new IllegalStateException( reason ); throw new IllegalStateException( reason );
} }


@Override @Override
public void beginTry( Resource... resources ) public void tryCatchBlock( List<Consumer<MethodEmitter>> body, List<CatchClause> catchClauses,
List<Consumer<MethodEmitter>> finalClauses, LocalVariables localVariables, Resource... resources )
{ {
throw new IllegalStateException( reason ); throw new IllegalStateException( reason );
} }
Expand All @@ -122,12 +120,6 @@ public void throwException( Expression exception )
throw new IllegalStateException( reason ); throw new IllegalStateException( reason );
} }


@Override
public void beginCatch( Parameter exception )
{
throw new IllegalStateException( reason );
}

@Override @Override
public void declare( LocalVariable local ) public void declare( LocalVariable local )
{ {
Expand Down
@@ -0,0 +1,58 @@
/*
* Copyright (c) 2002-2016 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.codegen;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

/**
* Repository of local variables.
*/
public class LocalVariables
{
private final AtomicInteger counter = new AtomicInteger( 0 );
private final Map<String,LocalVariable> localVariables = new HashMap<>();

public LocalVariable createNew( TypeReference type, String name )
{
LocalVariable localVariable = new LocalVariable( type, name, counter.getAndIncrement() );
localVariables.put( name, localVariable );
return localVariable;
}

public LocalVariable get( String name )
{
return localVariables.get( name );
}

public static LocalVariables copy( LocalVariables original )
{
LocalVariables variables = new LocalVariables();
variables.counter.set( original.counter.get() );
original.localVariables.forEach( variables.localVariables::put );
return variables;
}

public int nextIndex()
{
return counter.getAndIncrement();
}
}
Expand Up @@ -19,6 +19,9 @@
*/ */
package org.neo4j.codegen; package org.neo4j.codegen;


import java.util.List;
import java.util.function.Consumer;

public interface MethodEmitter public interface MethodEmitter
{ {
void done(); void done();
Expand All @@ -37,16 +40,15 @@ public interface MethodEmitter


void beginIf( Expression test ); void beginIf( Expression test );


void beginFinally();

void endBlock(); void endBlock();


void beginTry( Resource... resources ); void tryCatchBlock( List<Consumer<MethodEmitter>> body,
List<CatchClause> catchClauses,
List<Consumer<MethodEmitter>> finalClauses,
LocalVariables localVariables, Resource... resources );


void throwException( Expression exception ); void throwException( Expression exception );


void beginCatch( Parameter exception );

void declare( LocalVariable local ); void declare( LocalVariable local );


void assignVariableInScope( LocalVariable local, Expression value ); void assignVariableInScope( LocalVariable local, Expression value );
Expand Down
Expand Up @@ -46,6 +46,12 @@ private static MethodReference methodReference( Class<?> owner, TypeReference re
return methodReference( typeReference( owner ), returns, name, modifiers, parameters ); return methodReference( typeReference( owner ), returns, name, modifiers, parameters );
} }


public static MethodReference methodReference( TypeReference owner, TypeReference returns, String name,
TypeReference... parameters )
{
return new MethodReference( owner, name, returns, Modifier.PUBLIC, parameters );
}

public static MethodReference methodReference( TypeReference owner, TypeReference returns, String name, public static MethodReference methodReference( TypeReference owner, TypeReference returns, String name,
int modifiers, TypeReference... parameters ) int modifiers, TypeReference... parameters )
{ {
Expand Down

0 comments on commit 1aa2a67

Please sign in to comment.