Background

Embedded scripting engines have applications in several areas, including the ability to extend or modify the core functionality of a software application. In the game development world, scripting provides a means for the game engine developer to hand over control to the designer, allowing him or her to implement the game's plotline events, NPC behaviour, and so on, without the intervention of the game engine developer who may otherwise need to hard-wire game play logic into the game engine.

Introduction

The final article relating to the Conscript embeddable scripting engine for .NET presents an implementation of an IDE for Conscript, with functionality and look-and-feel reminiscent of Microsoft Visual Studio and other similar IDEs.

The IDE Windows application is included with this article in C# source form, and consists of the code for the scripting engine itself, the IDE, and additionally, an illustrative host function module to provide trigonometric functions and the ability to render 2D graphics. By default, the IDE application itself is a host function module that provides a Print function to allow for text output within the IDE's output window. Details for extending the scripting language with host functions is illustrated in the Dungeon of Despair scripted-game article presented as part of the Conscript article series. Techniques applied to integrate the Conscript scripting engine within the IDE application are illustrated in the previous articles, and hence will not be repeated here.

Using the Conscript IDE

The IDE window layout consists of a script source panel on the left-hand side, a virtual machine details panel on the right-hand side, and an output window at the bottom. In addition, a status bar beneath the output window provides compilation status and text cursor coordinates.

The script panel is a tabbed control that allows editing of multiple scripts. The IDE provides a ScriptLoader implementation that overrides the default script loading behaviour by giving priority to scripts loaded in the IDE. This allows one script within the IDE to include another script in the IDE even if it is not committed to disk.

The VM panel is also a tabbed control that provides access to compiled Conscript byte code, global, script, and local scopes, calling and parameter stacks, and thread locking states. The Byte Code tab within the VM panel allows setting of breakpoints, and also highlights the currently executing instruction during debugging.

The Scope tabs allow viewing and editing of variables in the Global, Script, and Local scopes during debugging. The Stack tabs allow viewing of the current call stack and the parameter stack that regulates variable scoping within functions. Finally, the Locks tab displays the state of synchronisation locks used in multi-threaded scripts.

The output panel provides compilation logs, and also acts as an output device for the Print() host function provided by default.

The menu strip of the application is organised in a traditional layout, and consists of the menus File, Edit, Build, Debug, and Help. The File menu provides script source management and termination of the IDE. The Edit menu provides standard Undo/Redo and Cut/Copy/Paste functionality. The Build menu allows incremental or full re-building of scripts. Incremental building essentially only compiles modified scripts, while re-building discards all compiled scripts and recompiles them from scratch. The Build menu also provides access to a Build Settings dialog to control debug code generation and code optmisiation, and to a Host Environment dialog to allow registration of host function module plug-ins. The Debug menu provides standard debugging functionality including single-stepping, monitored execution, the ability to step into, over, and out of functions, and toggling and clearing of breakpoints. Finally, the Help menu provides access to an informative dialog box.

Using the Graphics Host Function Module

The illustrative module plug-in included in the source code implements two host function modules: one for basic trigonometric functions, and the other for simple 2D graphics. The trig functions provided are:

Comments and Discussions

Hello Colin,
After having a look on your source I see a good start for a rich scripting language.

I have lots of ideas for this language and the toolset around this project.

Conscript itself:

It would be nice to extend the TokenTypes and opcodes to make conscript more flexible.

Adding a 'Register' tokentype and let the Script object itself push the registering of HostModules to the ScriptManageris about 10 min work (like the include TokenType).
That would eliminate the dependency to pre-register host modules.

I'm not sure (have to investigate the code more) but I think the 'thread' opcode does not really executes script blocks asynchron. I do not see any internal usage of Threads in your source, so if I'm right, everything happens in the main execution thread (as I mentioned, I'm not sure until now, perhaps I haven't seen it unitil now). So that needs to be implemented.
I also would like to extend the opcodes (ex: a 'Wait' opcode, which works together with WaitHandles..., a Timeout opcode to intiate a javascript like timout...)

In a comment in your 'Conscript' article someone asked for saving and executing the compiled code.
I've seen some unnecsessary references to the 'Script' object.
In the 'ScriptContext' object, there's no need to have a reference to the 'Script' object, because the code is only dealing with the instructions, found in the 'ScriptExecutable' object.
That's also the case in the 'ScriptExecutable' object itself, that also does not need a reference to the Script object.
So with a little redesign it's possible to isolate the 'ScriptExecutable' object and to save and run it within the 'ScriptContext' object without refernce to the source. Thenb it's possible to compile, save the compiled object (ScriptExecutable) and to run it isolated.
(The you need the 'Register' tokentype indeed to recognize the need of loading host functions)

IDE:

The ide is a nice start, but lazy coders as we are, we always want the most luxury expandible ide, we can get.
When running a debug sesseion, I only can see one tab in the right sight (Virtual Machine Panel) at the same time.
It would be nice to give the user the possibility to arrange the ide windows / tabs the way he likes it (Like in VS ide). This can be managed in a relative simple way with the usage of the WeifenLuo Docking solution).

Toolset:

When doing the previous mentioned changes and extensions, it's simple to create various tools around Conscript.
A console scriptrunner which detects the provided argument (path to script or compiled script) and deals with 'ScriptContext/ScriptExecutable' when using compiled scrtipt, or with lexer / parser and 'ScriptContext/ScriptExecutable' when the path to a sourcefile is provided.

A 'Compiler' which can pack the compiled code with some runtime into one executable to create executables form script....
and so on, lots of possibilities.

What do you think about creating a project on CodePlex or SourceForge to make it possible for other people to help you with this project?

(I would like to help and extend the code, but it's a bad idea to do so parrallel to changes, you're doing)

With regards to the register opcode, I think it's a good idea. Perhaps another option for this would be to place a declaration for host functions in the script.. that way, they could be compiled and stored on disk and the host function calls would only need to be resolved at run-time. This means 0that the script engine does not need to have the function registered before the script is compiled.
For example:

As for threading, this is really virtual threading. The scripting engine performs threading in a way similar to how a single CPU manages native threading, that is, by using context switching, running some opcodes on one context and switching to another. If you run a script that creates several threads each with their own output, you can see that their output is interleaved as they contend for the virtual CPU. However, all this runs on the main application's actual thread.

As for the other points, I pretty much agree.. the only problem is time. I'd be quite happy to place Conscript on SourceForge if you feel you can enhance it. I'll give it a try.