Steel Wheels Project: The KiwiScript
The KiwiScript
Language Specification

Introduction

The KiwiScript is declarative programming language for the user interface of the application program. This language has following features:

See KiwiScript Framework and KiwiEngine Framework for the implementation of this language.

Project status

The specification design and the implementation is still under construction.

Copyright

This document is produced by Steel Wheels Project. This document and the other KiwiScript products are distributed under GNU public license or GNU lesser public license Ver2.1

Overview and Topics

Prototype base object oriented

The application has hierarchical tree structure based on Application Object Model. The node of the tree is defined by the frame object. Here is a sample frame object to present the GUI button whose title is "OK".


button: {
	prototype:	 Button ;
	title: "OK" ;
}
				

The "Button" is built in class in the KiwiScript with GUI system.

Event driven expression

The slot of the frame can have event driven expression. For example, the button is enabled when flag1 and flag2 are true. The button state is immediately updated when the value of flag1 or flag2 is changed.

The expression is called path expression.

button: {
 prototype:	 Button ;
 enable:	(bool) application.flag1
   && current_document().flag2 ;
}
				

In usually, the compiler estimate the type of the result of path expression. But, in the above case, the cast expression is used to tell it to the compiler.

Event driven function

You can define event-driven function. It is called when the one of the parameter of the function is changed. At the below example, the title of the button is switched to "close" when some documents are opened and "open" when there are no opened document.


button: {
  title: watch(application.document.count) string {
   uint count = application.document.count ;
   string message ;
   if(count > 0){
    return "close" ;
   } else {
   return "open" ;
   }
  }
}
				

Strongly typed

Almost of the light weight langage are weakly typed. But the KiwiScript is strongly typed.

Data Types

Data types

Table of data types
Type nameSample constantDescription
booltrue, falseBoolean value
char'c', 0xc8bit unsigned integer value
int1234, -123464bit signed integer
uint1234u, 0x1234u64bit unsigned integer
float1.234, -12.34Floating point value
string"Hello, world!!"Unmodifiable array of Char
array[1234, 123], []Array of objects which has same data type
frame{ a:0 ; b:"hello";}Frame object

The data type is attached for each objects. The assignment between different data type objects are not allowed. You have to use cast expression.

Data attributes

Table of data attributes
Attribute nameSample DeclarationDescription
readonlyreadonly int aThe variable can be read access only
fixed { a : (fixed int) 0x1234 }The slot can not be removed from the object

The data attribute is attached for each variables (Some variables points same objects, but they have different type attributes). The assignment between different data attribute variable are restricted. The assignment from readonly variable into non-readonly variable is not allowed.


{
 int a ;
 readonly int b ;
 readonly int c = a ; /* allowed */
 readonly int d = b ; /* allowed */
 int e = b ; /* not allowed */
}
			

The readonly attribute is attached automatically. The function parameter variables will have this attribute. See function.

Number

The bool, char, int, uint, float types are called number type.

String

The context of string object can not be modified. The result of string operation alway generate new object instead of modifying the source.

Enumerated type

Enumerated type can be defined in a frame. Here is a sample code for the enumerated type value definition. The "Week" is a type name and "Sunday", "Monday" are the identifier of the constant integer values.


{
 Week : enum { Sunday : 0 ; Monday : 1, Tuesday : 2 } ;
}
			

Inheritance and Lookup

The rule to inherit and lookup enum type and value is same with frame's rule. See Inheritance and Lookup for the frame.

Array

All objects in an array must have same data types.

Frame & Slot

The frame object contains zero or more slots. The slot has following context:

Slot
MemberDescription
IdentifierIdentifier to distinguish this slot
ObjectSource object to define the value of the slot

Special member

Special member
MemberDescription
classDefine the name of frame to be referred by other frame
prototypeDeclare the class name to inherit it

Inheritance and Lookup

The rule to search, update and add slot is resembled to the rules for NewtonScript.

Rules to Lookup Frame

Following steps are used to search instance in the frame.

  1. Search slot in the current receiver. If there are slot which has target instance, return it.
  2. Search the instance in the prototype chain of current receiver. If there are target instance, return it.
  3. Search the instance in the parent chain of current receiver. The prototypes for each parents also will be the search target. If there are target instance, return it.
  4. Return nil.

Rules to Set Slot Value

When setting a slot, the inheritance search is the same as for slot lookup, except that the slot is not always set where it is found. These are the rules for where a slot is set:

  1. If a slot exists in the currently executing frame, its value is set there.
  2. If the slot exists in the prototype chain of the current frame, a new slot is made in the currently executing frame and its value is set there.
  3. If the slot exists in the parent of the currently executing frame, its value is set in that parent frame.
  4. If the slot exists in the prototype chain of the parent, a new slot is made in the parent frame at the same level at which it was found, and its value is set in that parent frame.

User type definition

Use type to define the new data type. Here is examples fot type definition


{
  days_t : type { user_t : array of int ; }
}
			

Inheritance and Lookup

The rule to inherit and lookup the defined type is same with frame's rule. See Inheritance and Lookup for the frame.

Operators

ANSI-C like operators are supported.

Unary Operator
OperatorTarget typeDescription
+numberGive + sign
-numberNegate the sign. The result value will have signed integer type
!booleanLogical NOT
~booleanBitwise NOT
Binary Operator
OperatorTarget typeDescription
+numberAdd 2 numbers
-numberSub R-val from L-val
/numberDivide L-val by R-val
%numberModulo L-val by R-val
&integer, booleanBitwise AND operation
|integer, booleanBitwise OR operation
^integer, booleanBitwise XOR operation
<<integerBitwise left shift operation
>>integerBitwise right shift operation
&&booleanLogical AND operation
||booleanLogical OR operation

Expression

Path expression

The path expression is used to point the object on hierarchical frame structure. It is described as the sequence of expression separated by the period.


/* system: */ {
  application: {
    func0 : sum(int a, int b){
      return a + b ;
    }
    frame0: {
      var0 : (int) 0 ;
    }
    main: (array of string argv) int {
      int c = system.application.func0(10, 20) ;
      application.frame0.var0 = self.frame0.var0 + 1 ;
    }
  }
}
				

Cast expression

The function which has the same name with the primitive data type is used as case function. The ANSI-C style cast operation (ex. ((int) a)) is not supported.


float a ;
array of int b ;
int(a) ;	 // cast type of 'a' into 'int'
float(b) ; // semantics error 
				

Assignment expression

Deep copy & Shallow copy

The assignment statement copies context of the primitive object. But it copy only reference when the assign data set object. It means the context of assigned object will be modified by the modification of source object. To keep the assigned object unique, you have to use clone method.


/* a and b is different object */
int a = b ;
/* c points the same object with d */
array of int c = d ; 
/* e and f points different objects */
array of int e = f.clone()	 ;
	     	

Statement

Switch statement

The syntax is restricted. The break statement is required for each case and default labels. You can not describe fall through case.


switch(..){
	case A:  case B:
		...
	/* break for case is always required */
	break ;	
}
				

Function

There are 2 ways to define function. First, the function is defined as a slot. Here is a sample code for the "div" function. It has two integer parameters and returns one double value.


{
	div: func(readonly int a, readonly int b) double {
		return double(a) / double(b) ;
	}
}
			

Second, the function is also defined as an expression because the function is first class object.


div = func(readonly int a, readonly int b) double {
	return double(a) / double(b) ;
}
double a = div(b, c) ;
			

Every parameters are called-by-value and they can no be modified in the called function. The readonly data attribute is attached for each parameters. (The attribute is attached by the compiler, So the user does not have to declare it.)

The function can return multiple values by using tuple.


div_and_mod =  func(readonly int a, readonly int b) (int, int) {
	return a / b, a % b ;
}
(int, int) a = div_and_mod(b, c) ;
			

Watch function

Watch function observes the update of source path expressions. When the observer found the some update, the function body is executed. The returned value is treated as the slot value.


{
	// calculate the width of this item by the
	// parent width
	width : watch(parent().width) float {
		float width = parent().width ;
		return width * 0.8 ;
	}
}
		

Built-in Classes

The built-in class has the interface with KiwiScript but the function is implemented by the Objective-C.

Examples

Hello, world


application: {
	main: func (array of string argv)  int {
		system.console.puts("Hello, world !!")  ;
	} 
}
	     

The "hello, world" window

The following example display the window which contains "Hello, world !!" text.


application: {
	window: {
		prototype: Window ;
		title: "Untitled" ;
		text: {
			prototype: TextField ;
			value:  "Hello, world !!" ;
		}
	}
}
	    

References


Produced by Steel Wheels Project.