Weeks ago, I was working on my open source project AjTalk, an Smalltalk-like interpreter, written in .NET (using C#), and now, I want to present the status of that work. For years, I was interested in Smalltalk development, altought only in my free time, never as a professional developer. It’s not the first time I wrote such kind of interpreter (my first one was written in the eighties, and it was very simple: no garbage collector, only text commands), but this time I feel it could become a very complete implementation.

Current version is minimal, but it is taken form. The idea is to have dynamic objects, like in Smalltalk, and, at some point, add prototypes a la Self. The objects and the interpreter would access full .NET framework and other libraries, as I did in my AjBasic interpreter (included as part of AjGenesis code generation project).

The very initial version is now published at Google Code:

http://code.google.com/p/ajtalk/

The solution

I’m using Professional VS 2005. There are four projects in the solution.

AjTalk is the main project, a class library containing the core of the system.

AjTalk.Test01 and AjTalk.Test02 are console applications, only for manual tests.

AjTalk.Tests contains the unit tests, written using NUnit framework 2.2.8.

Most of the core system consists of interfaces, defining the base behaviors, and classes, implementing such interfaces.

The object

The base is to have an interface to represent any object:

using System; namespace AjTalk { public interface IObject { IClass Class { get ; } object this [ int n] { get ; set ;} object SendMessage( string msgname, object [] args); } }

I could make a message an object (of type Message), but for now, the message is only a name, and an array of arguments.

The index this[int n] access the intance variables. Each value in AjTalk can point to any .NET object, not only the ones that implements IObject. In this way, I can manage int, long, String, DataSet, from other IObject objects.

The class

I’m implementing a simple IClass interface, without distinguing between class, behaviours, and other classes, as in the classic Smalltalk. I’ll separate these classes in a future version. For now, I’m managing only a interface:

using System; using System.Collections; using System.Collections.Generic; namespace AjTalk { public interface IClass : IObject { IClass SuperClass { get ; } string Name { get ; } void DefineClassMethod(IMethod method); void DefineInstanceMethod(IMethod method); void DefineClassVariable( string varname); void DefineInstanceVariable( string varname); IObject NewObject(); IMethod GetClassMethod( string mthname); IMethod GetInstanceMethod( string mthname); int GetClassVariableOffset( string varname); int GetInstanceVariableOffset( string varname); } }

There is a dictionary of class and instance methods, and lists of class and instance variable names. It doesn’t have support for indexed variables, yet. IClass interface is now implemented in a BaseClass class.

The method

There is an interface implemented in Method class:

using System; namespace AjTalk { public interface IMethod { string Name { get ; } IClass Class { get ; } object Execute(IObject receiver, object [] args); } }

The concrete Method class, has an Execute method:

public object Execute(IObject receiver, object [] args) { return ( new ExecutionBlock(receiver,receiver, this ,args)).Execute(); }

Execution blocks have local variables and arguments. The Execute of an execution block takes the instructions (bytecodes) from “compiled” methods, and then it executes them. Here, I took a departure from Smalltalk ideas: the execution block is not an AjTalk object. In this way, I could run this interpreter without implementing a lot of base classes. I have to research the advantages and problems that this decision could have in the overall design and implementation.

The bytecodes

I must think about using a tree of objects (as in Interpreter pattern) instead of bytecodes. But in this version, bytecodes are used. These are the basic instruction that my “virtual machine” understands and executes step by step.

There is a bytecode list (an enumeration)

namespace AjTalk { public enum ByteCode : byte { Nop = 0 , GetVariable = 1 , SetVariable = 2 , GetArgument = 3 , SetArgument = 4 , GetConstant = 5 , GetLocal = 6 , SetLocal = 7 , GetClassVariable = 8 , SetClassVariable = 9 , GetSelf = 20 , GetClass = 21 , GetSuperClass = 22 , NewObject = 23 , Pop = 24 , ReturnSub = 25 , ReturnPop = 26 , Add = 40 , Substract = 41 , Multiply = 42 , Divide = 43 , Send = 50 } }

The bytecodes contained in a method, are interpreted and executed by the execution block. An excerpt of that code:

while (ip < method.ByteCodes.Length) { ByteCode bc = (ByteCode) method.ByteCodes[ip]; Byte arg; switch (bc) { case ByteCode.ReturnSub: return null ; case ByteCode.ReturnPop: return Top; case ByteCode.GetConstant: ip ++ ; arg = method.ByteCodes[ip]; Push(method.GetConstant(arg)); break ; case ByteCode.GetArgument: ip ++ ; arg = method.ByteCodes[ip]; Push(arguments[arg]); break ; ….

Test everywhere

The initial code was written in VB.NET. Last year I began to rewrote the original source code to C#. Then, this year I switched to “TDD mind”, so, late but sure, I added NUnit tests:

Bootstraping

I plan to use a text file, with an ad-hoc format, to inject the definitions of the initial classes and objects. Now, in the AjTest.Test02, there is an example of such format in Definitions.txt file:

class Point

variables x y method

x ^x. method

y ^y. class Rectangle

variables point1 point2

class Square Rectangle

Next steps

There is a lot of work to do:

– Complete the hierarchy of base classes (Behaviour, Class, ….)

– More byte codes

– Support of local variables in methods

– Standard file text format

– Access to native .NET objects

– Use from .NET applications

– Define the classes and methods for a minimal implementation

– Serialization/deserialization of memory image

– Support for adding variables to a class with created instances (this is a tough problem)

– Support for become:

– And much more….

But I’m confident on the shape the project is taken. I’m applying “baby steps”, to improve the base code and functionality.

Angel “Java” Lopez

http://www.ajlopez.com/en