Skip to content

Commit

Permalink
POC for context buffers
Browse files Browse the repository at this point in the history
  • Loading branch information
bdw429s committed Jan 8, 2024
1 parent 772fe5c commit 69fc644
Show file tree
Hide file tree
Showing 8 changed files with 323 additions and 17 deletions.
42 changes: 25 additions & 17 deletions src/main/java/ortus/boxlang/runtime/BoxRuntime.java
Original file line number Diff line number Diff line change
Expand Up @@ -504,15 +504,19 @@ public void executeTemplate( BoxTemplate template, IBoxContext context ) {

IBoxContext scriptingContext = ensureContextWithVariables( context );

// Fire!!!
template.invoke( scriptingContext );

// Debugging Timer
instance.logger.atDebug().log(
"Executed template [{}] in [{}] ms",
template.getRunnablePath(),
timerUtil.stopAndGetMillis( "execute-" + template.hashCode() )
);
try {
// Fire!!!
template.invoke( scriptingContext );
} finally {
scriptingContext.flushBuffer();

// Debugging Timer
instance.logger.atDebug().log(
"Executed template [{}] in [{}] ms",
template.getRunnablePath(),
timerUtil.stopAndGetMillis( "execute-" + template.hashCode() )
);
}
}

/**
Expand Down Expand Up @@ -543,6 +547,7 @@ public Object executeStatement( String source, IBoxContext context ) {
// Fire!!!
return scriptRunnable.invoke( scriptingContext );
} finally {
scriptingContext.flushBuffer();
// Debugging Timer
instance.logger.atDebug().log(
"Executed source [{}] ms",
Expand Down Expand Up @@ -576,15 +581,18 @@ public void executeSource( String source, IBoxContext context ) {
instance.logger.atDebug().log( "Executing source " );

IBoxContext scriptingContext = ensureContextWithVariables( context );
// Fire!!!
scriptRunnable.invoke( scriptingContext );

// Debugging Timer
instance.logger.atDebug().log(
"Executed source [{}] ms",
timerUtil.stopAndGetMillis( "execute-" + source.hashCode() )
);
try {
// Fire!!!
scriptRunnable.invoke( scriptingContext );
} finally {
scriptingContext.flushBuffer();

// Debugging Timer
instance.logger.atDebug().log(
"Executed source [{}] ms",
timerUtil.stopAndGetMillis( "execute-" + source.hashCode() )
);
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/**
* [BoxLang]
*
* Copyright [2023] [Ortus Solutions, Corp]
*
* 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 ortus.boxlang.runtime.bifs.global.system;

import ortus.boxlang.runtime.bifs.BIF;
import ortus.boxlang.runtime.bifs.BoxBIF;
import ortus.boxlang.runtime.context.IBoxContext;
import ortus.boxlang.runtime.scopes.ArgumentsScope;
import ortus.boxlang.runtime.scopes.Key;
import ortus.boxlang.runtime.types.Argument;

@BoxBIF
@BoxBIF( alias = "echo" )
public class WriteOutput extends BIF {

/**
* Constructor
*/
public WriteOutput() {
super();
declaredArguments = new Argument[] {
new Argument( true, "any", Key.message )
};
}

/**
* Print a message with line break to the buffer
*
* @param context The context in which the BIF is being invoked.
* @param arguments Argument scope for the BIF.
*
* @argument.message The message to print
*/
public Object invoke( IBoxContext context, ArgumentsScope arguments ) {
context.writeToBuffer( arguments.get( Key.message ) );
return null;
}
}
49 changes: 49 additions & 0 deletions src/main/java/ortus/boxlang/runtime/context/BaseBoxContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import ortus.boxlang.runtime.BoxRuntime;
import ortus.boxlang.runtime.bifs.BIFDescriptor;
import ortus.boxlang.runtime.dynamic.casters.FunctionCaster;
import ortus.boxlang.runtime.dynamic.casters.StringCaster;
import ortus.boxlang.runtime.loader.ImportDefinition;
import ortus.boxlang.runtime.runnables.BoxTemplate;
import ortus.boxlang.runtime.runnables.ITemplateRunnable;
Expand Down Expand Up @@ -64,6 +65,8 @@ public class BaseBoxContext implements IBoxContext {

protected LinkedHashMap<Query, Integer> queryLoops = new LinkedHashMap<Query, Integer>();

protected StringBuffer buffer = new StringBuffer();

/**
* Creates a new execution context with a bounded execution template and parent context
*
Expand Down Expand Up @@ -525,4 +528,50 @@ public void incrementQueryLoop( Query query ) {
queryLoops.put( query, queryLoops.get( query ) + 1 );
}

/**
* Write output to this buffer. Any input object will be converted to a string
*
* @param o The object to write
*
* @return This context
*/
public IBoxContext writeToBuffer( Object o ) {
buffer.append( StringCaster.cast( o ) );
return this;
}

/**
* Flush the buffer to the output stream and then clears the local buffers
*
* @return This context
*/
public IBoxContext flushBuffer() {
if ( hasParent() ) {
synchronized ( buffer ) {
getParent().writeToBuffer( buffer.toString() );
clearBuffer();
}
}
return this;
}

/**
* Clear the buffer
*
* @return This context
*/
public IBoxContext clearBuffer() {
buffer.setLength( 0 );
return this;
}

/**
* Get the buffer
*
* @return
*/
public StringBuffer getBuffer() {
return buffer;
}

}
33 changes: 33 additions & 0 deletions src/main/java/ortus/boxlang/runtime/context/IBoxContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -305,4 +305,37 @@ public record ScopeSearchResult( IScope scope, Object value ) {
* @param query The query to increment
*/
public void incrementQueryLoop( Query query );

/**
* Write output to this buffer. Any input object will be converted to a string
*
* @param o The object to write
*
* @return This context
*/
public IBoxContext writeToBuffer( Object o );

/**
* Flush the buffer to the output stream. The default implementation simply flushes the buffer in this context
* to its parent context. Different "top level" buffers can decide what they want to do with the buffer.
* i.e. Scripting sends to the console, Web sends to HTTP response stream, etc.
*
* @return This context
*/
public IBoxContext flushBuffer();

/**
* Clear the buffer
*
* @return This context
*/
public IBoxContext clearBuffer();

/**
* Get the buffer
*
* @return
*/
public StringBuffer getBuffer();

}
Original file line number Diff line number Diff line change
Expand Up @@ -207,4 +207,24 @@ public IScope getDefaultAssignmentScope() {
return variablesScope;
}

/**
* Flush the buffer to the output stream
*
* @return This context
*/
public IBoxContext flushBuffer() {
if ( hasParent() ) {
getParent().writeToBuffer( buffer.toString() );
}
String output;
synchronized ( buffer ) {
output = buffer.toString();
clearBuffer();
}
// If a scripting context is our top-level context, we flush to the console.
System.out.print( output );

return this;
}

}
1 change: 1 addition & 0 deletions src/main/java/ortus/boxlang/runtime/scopes/Key.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ public class Key {
public static final Key missingMethodName = Key.of( "missingMethodName" );
public static final Key missingMethodArguments = Key.of( "missingMethodArguments" );
public static final Key accessors = Key.of( "accessors" );
public static final Key output = Key.of( "output" );

public static final Key contains = Key.of( "contains" );
public static final Key find = Key.of( "find" );
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/ortus/boxlang/runtime/types/Function.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import ortus.boxlang.runtime.context.FunctionBoxContext;
import ortus.boxlang.runtime.context.IBoxContext;
import ortus.boxlang.runtime.context.LambdaBoxContext;
import ortus.boxlang.runtime.dynamic.casters.BooleanCaster;
import ortus.boxlang.runtime.dynamic.casters.CastAttempt;
import ortus.boxlang.runtime.dynamic.casters.GenericCaster;
import ortus.boxlang.runtime.runnables.IFunctionRunnable;
Expand Down Expand Up @@ -149,6 +150,11 @@ public Object invoke( FunctionBoxContext context ) {
data.put( "result", result );
runtime.announce( "postFunctionInvoke", data );

// If output=true, then flush any content in buffer
if ( BooleanCaster.cast( getAnnotations().getOrDefault( Key.output, false ) ) ) {
context.flushBuffer();
}

return data.get( "result" );
}

Expand Down
Loading

0 comments on commit 69fc644

Please sign in to comment.