Hi Kix users,

For a while now, I've been working on a project that may interest you. I'm a 22 year old student from the Netherlands and I enjoy a bit of programming in my spare time. I'm especially interested in using new technologies related to creating programming languages. The project I'm working on is an implementation of Kix on the new Dynamic Language Runtime built by Microsoft. The DLR runs on top of the CLR and is part of the .net technology.
I was introduced to Kix by my brother. Although Kix is not really impressive (language feature wise), I was pretty fascinated by the number of people that use it and the stuff built around it (like KiXforms). Having built a few useless languages, I decided to build one that may actually be useful to somebody.


The main advantage of SteelKix is the .net framework. SteelKix opens up the entire non generic .net framework, allowing much more functionality in the language.

Here is a list of some of the things that are possible in SteelKix:

• Multithreading
• Using byte arrays
• Sockets
• Using .net events
• Com event sinks
• Using exception handling

A large difference with KiXtart is the way of executing scripts: SteelKix compiles your script before it runs. Your script is effectively translated to machine code at runtime by the .NET JIT compiler. The SteelKix compiler detects syntax errors before your script is executed.

I've designed SteelKix to be backward compatible. All of the kix scripts should also run on SteelKix.

At this point, the project is in an early stage. Most of the standard functions and some of the commands are not yet implemented. My idea is to implement the standard functions in SteelKix itself, since most things that are possible in C# are also possible in SteelKix. Macro's can also be defined within SteelKix.

Enough with the talk, I'll just post some examples where some of the new features are clearly visible. Please tell me what you think!

Solving the producer-consumer problem (multithreading)
 Code:
Imports $t = system.threading ;new imports statement, importing namespaces defined by .net assemblies
imports $s = system

/* steelkix supports declaring with assignments (unlike vanilla kix) */
/* steelkix supports constructing clr objects */

global $fullSem = $t.Semaphore(10, 10),
	$emptySem = $t.Semaphore(0, 10),
	$buffer = $s.collections.Queue(),
	$bufferMutex = $t.Mutex(),
	$continue = 1

/* steelkix supports function to delegate conversion */

dim $producerThread = $t.Thread($t.ThreadStart(AddressOf Producer)),
	$consumerThread = $t.Thread($t.ThreadStart(AddressOf Consumer))

$producerThread.Start
$consumerThread.Start

$producerThread.Join
$consumerThread.Join

"done"

/* produce some crap (fibonacci), simulate hard working thread */
function Producer()
	dim $fibOne = 1, $fibTwo = 2
	dim $rand = $s.random()
	dim $tmp
	dim $proberen
	dim $verhogen

	while $fibTwo < 100000
	
		$proberen = $fullSem.WaitOne
	
		$tmp = $fibTwo
		
		$fibTwo = $fibOne + $fibTwo
	
		$fibOne = $tmp	

		$proberen = $bufferMutex.WaitOne

		$buffer.Enqueue($fibTwo)

		$bufferMutex.ReleaseMutex

		$verhogen = $emptySem.Release

		SLEEP $rand.Next(0, 5)		
	loop	
	
	$continue = 0	
endfunction

/* consume results from producer (print them) */
function Consumer()	
	dim $proberen
	dim $verhogen

	while $continue
		if not $emptySem.WaitOne(5000)
			exit 0
		endif
		
		$proberen = $bufferMutex.WaitOne
	
		? $buffer.Dequeue()		

		$bufferMutex.ReleaseMutex

		$verhogen = $fullSem.Release		
	loop
endfunction


Creating a simple TCP server
 Code:
imports $system = system
imports $net = system.net
imports $sockets = system.net.sockets
imports $threading = system.threading

global $continue = 1

; new addressof operator

dim $listenThread = $threading.Thread($threading.ThreadStart(AddressOf Listen))
global $listenSocket
dim $line = ""

"Starting listen thread"

$listenThread.Start

while $line <> "exit"
	gets $line
loop

$continue = 0

? "Closing.."

$listenSocket.Close

function Listen
	dim $port = 1050
	$listenSocket = $sockets.socket($sockets.addressfamily.internetwork,
						$sockets.sockettype.stream,
						$sockets.protocoltype.tcp)

	;listen on port 1050
	
	$listenSocket.Bind($net.IPEndPoint($net.IPAddress.Any, $port))

	$listenSocket.Listen(10)

	? "Started listening on port $port"

	while $continue
		; new try/catch block
		try
			dim $client = $listenSocket.Accept

			? "Accepted client: " + $client.EndPoint.tostring
 
			dim $thread = $threading.Thread($threading.ParameterizedThreadStart(AddressOf HandleClient))

			$thread.Start($client)
		endtry
		catch
			break
		endcatch				
	loop

	$listenSocket.close
endfunction

function HandleClient($client)

	;build byte array

	dim $buffer = $system.Array.CreateInstance($system.Type.GetType("System.Byte"), 1024)

	while $continue
		dim $bytesRead = $client.Receive($buffer)
		
		? "Received $bytesRead! woot!"

		if $bytesRead > 0
			$client.Send($buffer, $bytesRead, $sockets.SocketFlags.None)
		else
			break
		endif
	loop	

endfunction


Creating a WPF application

 Code:
reference("system.xml")
; reference .net assemblies
referenceExact("PresentationFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35")
referenceExact("PresentationCore, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35")

imports $markup = system.windows.markup
imports $win = system.windows
imports $io = system.io
imports $xml = system.xml

; create a cube that can be rotated

dim $xaml = '<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="SteelKix XAML rotating cube biatch!" Height="300" Width="300"
    >
  <DockPanel>
    <ScrollBar Name="hscroll" 
      DockPanel.Dock="Bottom"
      Orientation="Horizontal" 
      Minimum="-180" Maximum="180" 
      LargeChange="10" SmallChange="1" Value="0" />
    <ScrollBar Name="vscroll" 
      DockPanel.Dock="Right"
      Orientation="Vertical"  
      Minimum="-180" Maximum="180" 
      LargeChange="10" SmallChange="1" Value="0" />

    <Viewport3D Margin="4,4,4,4">
        <ModelVisual3D>
          <ModelVisual3D.Content>
            <Model3DGroup>
              <!-- Lights -->
              <AmbientLight Color="Gray" />
              <DirectionalLight Color="Gray" 
                  Direction="1,-2,-3" />
              <DirectionalLight Color="Gray" 
                  Direction="-1,2,3" />

              <GeometryModel3D>
                <GeometryModel3D.Geometry>
                  <!-- Cube -->
                  <MeshGeometry3D 
                    Positions="
                      -1,-1,-1   1,-1,-1   1,-1, 1  -1,-1, 1
                      -1,-1, 1   1,-1, 1   1, 1, 1  -1, 1, 1
                       1,-1, 1   1,-1,-1   1, 1,-1   1, 1, 1
                       1, 1, 1   1, 1,-1  -1, 1,-1  -1, 1, 1
                      -1,-1, 1  -1, 1, 1  -1, 1,-1  
                           -1,-1,-1
                      -1,-1,-1  -1, 1,-1   1, 1,-1   1,-1,-1
                      "
                    TriangleIndices="
                       0  1  2     2  3  0
                       4  5  6     6  7  4
                       8  9 10    10 11  8
                      12 13 14    14 15 12
                      16 17 18    18 19 16
                      20 21 22    22 23 20
                      " />
                </GeometryModel3D.Geometry>

                <GeometryModel3D.Material>
                  <DiffuseMaterial Brush="Red" />
                </GeometryModel3D.Material>
              </GeometryModel3D>

            </Model3DGroup>
          </ModelVisual3D.Content>
        </ModelVisual3D>

      <Viewport3D.Camera>
        <PerspectiveCamera 
          Position = "2, 4, 6"
          LookDirection = "-1, -2, -3"
          UpDirection = "0, 1, 0"
          FieldOfView = "60">
          <PerspectiveCamera.Transform>
            <Transform3DGroup>
              <RotateTransform3D>
                <RotateTransform3D.Rotation>
                  <AxisAngleRotation3D
                      Axis="0 1 0" 
                      Angle="{Binding ElementName=hscroll, Path=Value}" />
                </RotateTransform3D.Rotation>
              </RotateTransform3D>
              <RotateTransform3D>
                <RotateTransform3D.Rotation>
                  <AxisAngleRotation3D
                      Axis="1 0 0" 
                      Angle="{Binding ElementName=vscroll, Path=Value}" />
                </RotateTransform3D.Rotation>
              </RotateTransform3D>
            </Transform3DGroup>
          </PerspectiveCamera.Transform>
        </PerspectiveCamera>
      </Viewport3D.Camera>
    </Viewport3D>
    </DockPanel>
</Window>'

dim $app = $win.application()

dim $xmlReader = $xml.XmlReader.Create($io.StringReader($xaml)),
		$window = $markup.XamlReader.Load($xmlReader)

$app.Run($window) 


Creating a winforms application

 Code:
reference("system.windows.forms") ;referenceExact is better (prevent dll hell). I'm being lazy here.
reference("system.drawing")
reference("system.data")

dim $explicit = setoption("explicit", "on")

imports $system = system
imports $forms = system.windows.forms
imports $drawing = system.drawing
imports $data = system.data

global $form = $forms.form()
global $grid = $forms.dataGridView()
global $btnClose = $forms.button()

$form.Size = $drawing.size(800, 600)
$form.Load += $system.eventhandler(addressOf Form_load)

$grid.location = $drawing.point(12, 21)
$grid.size = $drawing.size(758, 451)
$grid.anchor = $forms.anchorStyles.Top | $forms.anchorStyles.Left | $forms.anchorStyles.Bottom | $forms.anchorStyles.Right

$btnClose.location = $drawing.point(678, 500)
$btnClose.size = $drawing.size(92, 23)
$btnClose.Text = "Close"
$btnClose.Click += $system.eventhandler(AddressOf btnClose_Click)

$form.Text = "SteelKix WF example"

$form.Controls.add($grid)
$form.controls.add($btnClose)

$forms.Application.enableVisualStyles
$forms.Application.Run($form);

function Form_Load($sender, $e)
;fill the grid up with some xml

	dim $dataSet = $data.dataset()
	dim $reader = $system.io.stringreader("<?xml version='1.0' standalone='yes'?>
                                            <NewDataSet>
                                           	<Product>
                                                	<Name>Bread</Name>
							<Price>$$4</Price>
							<Stock>20</Stock>
                                                </Product>
						<Product>
                                                	<Name>Milk</Name>
							<Price>$$2</Price>
							<Stock>54</Stock>
                                                </Product>
						<Product>
                                                	<Name>Butter</Name>
							<Price>$$1</Price>
							<Stock>13</Stock>
                                                </Product>
                                            </NewDataSet>")

	$dataset.ReadXml($reader)

	$grid.datasource = $dataset.tables[0].defaultview
	
endfunction

function btnClose_Click($sender, $e)
	$form.close
endfunction


Using COM event sinks

 Code:
imports $system = system
dim $xmlHttp = CreateObject("Msxml2.DOMDocument.3.0")

$xmlHttp.onreadystatechange += addressOf XmlHttp_readyStateChange
$xmlHttp.Load("http://posc.org/ebiz/blmSamples/blm3160-3.xml") 

function XmlHttp_readyStateChange
"test"
endfunction


Using LINQ libraries

 Code:
reference("System.Core") ;load up linq libraries

imports $linq = system.linq.expressions.expression
imports $s = system

/* build the parameters used for the lambda */

dim $x = $linq.parameter($s.Type.GetType("System.Int32"), "x"),
	$y = $linq.parameter($s.Type.GetType("System.Int32"), "y")

/* build the lambda (x+y equivalent) */
dim $expr = $linq.Lambda(
			$linq.Add(
					$x,
					$y
				),
			$x, $y
                        )

/* compile into .net delegate */

dim $delegate = $expr.Compile

/* invoke the delegate */

$delegate(1, 2)


Default parameter values

 Code:
imports $debug = System.Diagnostics.Debug

$debug.Assert(assert(foo(1), 1, 5, 6))

$debug.Assert(assert(foo(1, 2), 1, 2, 6)) ; 1 2 6


$debug.Assert(assert(foo(1, , 3), 1, 5, 3)) ; 1 5 3

$debug.Assert(assert(foo(1, ,), 1, 5, 6)) ; 1 5 6

$debug.Assert(assert(foo(1,2,), 1, 2, 6)) ; 1 2 6

"All success"

;optional parameters with default values

function foo($array, optional $b = 5, optional $c = 6)
$foo = [$array, $b, $c]
endfunction

function assert($ret, $v1, $v2, $v3)
$assert = ($ret[0] = $v1 and $ret[1] = $v2 and $ret[2] = $v3)
endfunction





Edited by WvS (2009-05-30 05:10 PM)