Skip to content

Commit

Permalink
abstract support
Browse files Browse the repository at this point in the history
  • Loading branch information
bdw429s committed Jun 10, 2024
1 parent dd1c48e commit 469f958
Show file tree
Hide file tree
Showing 18 changed files with 304 additions and 127 deletions.
16 changes: 8 additions & 8 deletions src/main/antlr/BoxScriptGrammar.g4
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,8 @@ include: INCLUDE expression;

// class {}
boxClass:
importStatement* (preannotation)* boxClassName postannotation* LBRACE property* classBody RBRACE
;
importStatement* (preannotation)* ABSTRACT? boxClassName postannotation* LBRACE property*
classBody RBRACE;

// The actual word "class"
boxClassName: CLASS_NAME;
Expand All @@ -139,18 +139,18 @@ staticInitializer: STATIC statementBlock;
// interface {}
interface:
importStatement* (preannotation)* boxInterfaceName postannotation* LBRACE (
interfaceFunction
| function
function
| abstractFunction
| staticInitializer
)* RBRACE;

// the actual word "interface"
boxInterfaceName: INTERFACE;

// TODO: default method implementations
interfaceFunction: (preannotation)* functionSignature (
// Default method implementations
abstractFunction: (preannotation)* functionSignature (
postannotation
)* eos;
)* eos?;

// public String myFunction( String foo, String bar )
functionSignature:
Expand Down Expand Up @@ -208,7 +208,7 @@ type:
) (LBRACKET RBRACKET)?;

// Allow any statement or a function. TODO: This may need to be changed if functions are allowed inside of functions
functionOrStatement: function | statement;
functionOrStatement: function | abstractFunction | statement;

// property name="foo" type="string" default="bar" inject="something";
property: (preannotation)* PROPERTY postannotation* eos;
Expand Down
8 changes: 4 additions & 4 deletions src/main/antlr/CFScriptGrammar.g4
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ include: INCLUDE expression;

// component {}
boxClass:
importStatement* boxClassName postannotation* LBRACE property* classBody RBRACE;
importStatement* ABSTRACT? boxClassName postannotation* LBRACE property* classBody RBRACE;

// the actual word "component"
boxClassName: CLASS_NAME;
Expand All @@ -138,15 +138,15 @@ classBody: ( staticInitializer | functionOrStatement)*;
// interface {}
interface:
importStatement* boxInterfaceName postannotation* LBRACE (
interfaceFunction
abstractFunction
| function
)* RBRACE;

// the actual word "interface"
boxInterfaceName: INTERFACE;

// function String foo( required integer param1=42 );
interfaceFunction: functionSignature ( postannotation)* eos;
abstractFunction: functionSignature ( postannotation)* eos?;

// public String myFunction( String foo, String bar )
functionSignature:
Expand Down Expand Up @@ -200,7 +200,7 @@ type:
) (LBRACKET RBRACKET)?;

// Allow any statement or a function. TODO: This may need to be changed if functions are allowed inside of functions
functionOrStatement: function | statement;
functionOrStatement: function | abstractFunction | statement;

// property name="foo" type="string" default="bar" inject="something";
property: PROPERTY postannotation* eos;
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/ortus/boxlang/compiler/Boxpiler.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ public Boxpiler() {
if ( BoxRuntime.getInstance().inDebugMode() && Files.exists( this.classGenerationDirectory ) ) {
try {
logger.debug( "Running in debugmode, first startup cleaning out class generation directory: " + classGenerationDirectory );
if ( false )
FileUtils.cleanDirectory( classGenerationDirectory.toFile() );
// if ( false )
FileUtils.cleanDirectory( classGenerationDirectory.toFile() );
} catch ( IOException e ) {
throw new BoxRuntimeException( "Error cleaning out class generation directory on first run", e );
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@

import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.expr.ArrayCreationExpr;
import com.github.javaparser.ast.expr.ArrayInitializerExpr;
import com.github.javaparser.ast.expr.Expression;
import com.github.javaparser.ast.expr.FieldAccessExpr;
import com.github.javaparser.ast.expr.MethodCallExpr;
import com.github.javaparser.ast.expr.NameExpr;
import com.github.javaparser.ast.expr.ObjectCreationExpr;
import com.github.javaparser.ast.expr.StringLiteralExpr;
import com.github.javaparser.ast.stmt.Statement;

import ortus.boxlang.compiler.JavaSourceString;
Expand Down Expand Up @@ -73,6 +81,7 @@
import ortus.boxlang.compiler.ast.expression.BoxStructLiteral;
import ortus.boxlang.compiler.ast.expression.BoxTernaryOperation;
import ortus.boxlang.compiler.ast.expression.BoxUnaryOperation;
import ortus.boxlang.compiler.ast.statement.BoxAccessModifier;
import ortus.boxlang.compiler.ast.statement.BoxArgumentDeclaration;
import ortus.boxlang.compiler.ast.statement.BoxAssert;
import ortus.boxlang.compiler.ast.statement.BoxBreak;
Expand All @@ -88,14 +97,17 @@
import ortus.boxlang.compiler.ast.statement.BoxParam;
import ortus.boxlang.compiler.ast.statement.BoxRethrow;
import ortus.boxlang.compiler.ast.statement.BoxReturn;
import ortus.boxlang.compiler.ast.statement.BoxReturnType;
import ortus.boxlang.compiler.ast.statement.BoxScriptIsland;
import ortus.boxlang.compiler.ast.statement.BoxStatementBlock;
import ortus.boxlang.compiler.ast.statement.BoxSwitch;
import ortus.boxlang.compiler.ast.statement.BoxThrow;
import ortus.boxlang.compiler.ast.statement.BoxTry;
import ortus.boxlang.compiler.ast.statement.BoxType;
import ortus.boxlang.compiler.ast.statement.BoxWhile;
import ortus.boxlang.compiler.ast.statement.component.BoxComponent;
import ortus.boxlang.compiler.ast.statement.component.BoxTemplateIsland;
import ortus.boxlang.compiler.javaboxpiler.transformer.AbstractTransformer;
import ortus.boxlang.compiler.javaboxpiler.transformer.BoxClassTransformer;
import ortus.boxlang.compiler.javaboxpiler.transformer.BoxInterfaceTransformer;
import ortus.boxlang.compiler.javaboxpiler.transformer.BoxStaticInitializerTransformer;
Expand Down Expand Up @@ -386,4 +398,46 @@ public List<Statement> getStaticUDFDeclarations() {
return staticUDFDeclarations;
}

public Expression createAbstractMethod( BoxFunctionDeclaration bfd, AbstractTransformer transformer, String sourceObjectName, String sourceObjectType ) {
BoxAccessModifier access = bfd.getAccessModifier();
BoxReturnType boxReturnType = bfd.getType();
BoxType returnType = BoxType.Any;
String fqn = null;
if ( boxReturnType != null ) {
returnType = boxReturnType.getType();
if ( returnType.equals( BoxType.Fqn ) ) {
fqn = boxReturnType.getFqn();
}
}
String returnTypeString = returnType.equals( BoxType.Fqn ) ? fqn : returnType.name();
if ( access == null ) {
access = BoxAccessModifier.Public;
}
ArrayInitializerExpr argInitializer = new ArrayInitializerExpr();
bfd.getArgs().forEach( arg -> {
Expression argument = ( Expression ) transform( arg );
argInitializer.getValues().add( argument );
} );
ArrayCreationExpr argumentsArray = new ArrayCreationExpr()
.setElementType( "Argument" )
.setInitializer( argInitializer );

// process abstract function (no body)
return new MethodCallExpr( new NameExpr( "abstractMethods" ), "put" )
.addArgument( transformer.createKey( bfd.getName() ) )
.addArgument(
new ObjectCreationExpr()
.setType( "AbstractFunction" )
.addArgument( transformer.createKey( bfd.getName() ) )
.addArgument( argumentsArray )
.addArgument( new StringLiteralExpr( returnTypeString ) )
.addArgument(
new FieldAccessExpr( new FieldAccessExpr( new NameExpr( "Function" ), "Access" ), access.toString().toUpperCase() ) )
.addArgument( transformer.transformAnnotations( bfd.getAnnotations() ) )
.addArgument( transformer.transformDocumentation( bfd.getDocumentation() ) )
.addArgument( new StringLiteralExpr( sourceObjectName ) )
.addArgument( new StringLiteralExpr( sourceObjectType ) )
);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ public class ${className} ${extendsTemplate} implements ${interfaceList} {
private static final Map<Key,Property> properties;
private static final Map<Key,Property> getterLookup=null;
private static final Map<Key,Property> setterLookup=null;
private static Map<Key, AbstractFunction> abstractMethods = new LinkedHashMap<>();
private static final boolean isJavaExtends=${isJavaExtends};
private static StaticScope staticScope = new StaticScope();
// This is public so the ClassLocator can check it easily
Expand Down Expand Up @@ -175,6 +176,20 @@ public Map<Key,Property> getSetterLookup() {
return setterLookup;
}
public Map<Key, AbstractFunction> getAbstractMethods() {
return this.abstractMethods;
}
public Map<Key, AbstractFunction> getAllAbstractMethods() {
// get from parent and override
Map<Key, AbstractFunction> allAbstractMethods = new LinkedHashMap<>();
if ( this._super != null ) {
allAbstractMethods.putAll( this._super.getAllAbstractMethods() );
}
allAbstractMethods.putAll( this.abstractMethods );
return allAbstractMethods;
}
public BoxMeta _getbx() {
return this.$bx;
}
Expand Down Expand Up @@ -564,6 +579,15 @@ public Node transform( BoxNode node, TransformerContext context ) throws Illegal
// Add body
for ( BoxStatement statement : boxClass.getBody() ) {

// TODO: build this check into the BFD transformer and track abstract method in the transpiler
// Same change applies to interfaces
if ( statement instanceof BoxFunctionDeclaration bfd && bfd.getBody() == null ) {
// process abstract function (no body)
pseudoConstructorBody.addStatement( 0,
( ( JavaTranspiler ) transpiler ).createAbstractMethod( bfd, this, className, "class" )
);
continue;
}
Node javaASTNode = transpiler.transform( statement );

// These get left behind from UDF declarations
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,10 @@
import com.github.javaparser.ast.body.FieldDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.expr.ArrayCreationExpr;
import com.github.javaparser.ast.expr.ArrayInitializerExpr;
import com.github.javaparser.ast.expr.Expression;
import com.github.javaparser.ast.expr.FieldAccessExpr;
import com.github.javaparser.ast.expr.IntegerLiteralExpr;
import com.github.javaparser.ast.expr.MethodCallExpr;
import com.github.javaparser.ast.expr.NameExpr;
import com.github.javaparser.ast.expr.ObjectCreationExpr;
import com.github.javaparser.ast.expr.StringLiteralExpr;

import ortus.boxlang.compiler.ast.BoxExpression;
Expand All @@ -41,11 +38,8 @@
import ortus.boxlang.compiler.ast.SourceFile;
import ortus.boxlang.compiler.ast.expression.BoxIntegerLiteral;
import ortus.boxlang.compiler.ast.expression.BoxStringLiteral;
import ortus.boxlang.compiler.ast.statement.BoxAccessModifier;
import ortus.boxlang.compiler.ast.statement.BoxFunctionDeclaration;
import ortus.boxlang.compiler.ast.statement.BoxImport;
import ortus.boxlang.compiler.ast.statement.BoxReturnType;
import ortus.boxlang.compiler.ast.statement.BoxType;
import ortus.boxlang.compiler.javaboxpiler.JavaTranspiler;
import ortus.boxlang.runtime.config.util.PlaceholderHelper;
import ortus.boxlang.runtime.types.exceptions.BoxRuntimeException;
Expand Down Expand Up @@ -117,7 +111,7 @@ public class ${classname} extends BoxInterface {
private final static IStruct annotations;
private final static IStruct documentation;
private static Map<Key, Function> abstractMethods = new LinkedHashMap<>();
private static Map<Key, AbstractFunction> abstractMethods = new LinkedHashMap<>();
private static Map<Key, Function> defaultMethods = new LinkedHashMap<>();
private static ${classname} instance;
private static Key name = ${boxInterfacename};
Expand Down Expand Up @@ -163,7 +157,7 @@ public void _pseudoConstructor( IBoxContext context ) {
return instance;
}
public Map<Key, Function> getAbstractMethods() {
public Map<Key, AbstractFunction> getAbstractMethods() {
return this.abstractMethods;
}
Expand Down Expand Up @@ -355,44 +349,9 @@ public Node transform( BoxNode node, TransformerContext context ) throws Illegal
if ( bfd.getBody() != null ) {
transpiler.transform( statement );
} else {
BoxAccessModifier access = bfd.getAccessModifier();
BoxReturnType boxReturnType = bfd.getType();
BoxType returnType = BoxType.Any;
String fqn = null;
if ( boxReturnType != null ) {
returnType = boxReturnType.getType();
if ( returnType.equals( BoxType.Fqn ) ) {
fqn = boxReturnType.getFqn();
}
}
String returnTypeString = returnType.equals( BoxType.Fqn ) ? fqn : returnType.name();
if ( access == null ) {
access = BoxAccessModifier.Public;
}
ArrayInitializerExpr argInitializer = new ArrayInitializerExpr();
bfd.getArgs().forEach( arg -> {
Expression argument = ( Expression ) transpiler.transform( arg );
argInitializer.getValues().add( argument );
} );
ArrayCreationExpr argumentsArray = new ArrayCreationExpr()
.setElementType( "Argument" )
.setInitializer( argInitializer );

// process interface function (no body)
// process abstract function (no body)
pseudoConstructorBody.addStatement( 0,
new MethodCallExpr( new NameExpr( "abstractMethods" ), "put" )
.addArgument( createKey( bfd.getName() ) )
.addArgument(
new ObjectCreationExpr()
.setType( "AbstractFunction" )
.addArgument( createKey( bfd.getName() ) )
.addArgument( argumentsArray )
.addArgument( new StringLiteralExpr( returnTypeString ) )
.addArgument(
new FieldAccessExpr( new FieldAccessExpr( new NameExpr( "Function" ), "Access" ), access.toString().toUpperCase() ) )
.addArgument( transformAnnotations( bfd.getAnnotations() ) )
.addArgument( transformDocumentation( bfd.getDocumentation() ) )
)
( ( JavaTranspiler ) transpiler ).createAbstractMethod( bfd, this, classname, "interface" )
);
}
} else if ( statement instanceof BoxImport ) {
Expand Down
Loading

0 comments on commit 469f958

Please sign in to comment.