My favorites | Sign in
Project Home Downloads Wiki Issues Source
READ-ONLY: This project has been archived. For more information see this post.
Search
for
LanguageRules  
A description of the Kitsch programming language
Updated Feb 19, 2009 by apangb...@gmail.com

Introduction

This page introduces Kitsch, and explains how to program in it.

Comments

Kitsch currently only supports a single-line comment. Any text after a '#' symbol on the current line will be ignored

Variables

As an imperative programming language, variables are the heart of Kitsch. This section explains how to use them.

Types

Kitsch has three types of variables

  • int
  • bool
  • string.

Note that strings are treated as a primitive type. Kitsch's ints are arbitrary precision integers, and bools are, as one would expect, either True or False.

Kitsch also has an array type for each of the three primitive types.

  • int
  • string
  • bool

No implicit conversions are performed between types. Casting must be used to change a variables type.

Scope Rules

Variables belong to the scope they are first assigned in. Functions can only access their parameters.

Declaration

Kitsch is a strongly typed language with type inference. Variable types are not explicitly declared - they are inferred by the Compiler.

Assignment

<identifier> = <expression>

identifier is the name of this variable; this name must be unique in the current scope. The type of expression is inferred unless explicitly cast (see the section on Casting for details).

If a variable is assigned a new value, the identifier's type will be changed to the type of the new expression. In other words, the most recent assignment to the identifier will be that identifier's current type.

Example

x = 42
y = 96 / 17
s = "This is a string!"

# Case matters!, must be 'True' or 'False'
b = True

x = "foobar" # x is now a string, not an int

Casting

Since Kitsch does not perform implicit conversions it provides an explicit casting mechanism to change a variable's type.

Available types include int, string, and bool.

Example

i = 42
x = (int) "123"
s = (string) i # s will contain the value "42"
b = (bool) i # Will be True
b = (bool) 0 # Will be False

Value Conversions

  • (int) : Casts to an integer. If the value is already an integer, no effect. If the value is a string of numerical digits, it is cast to the equivalent integer - otherwise it a runtime error occurs.
  • (string) : Casts the value to a string representation. If the value is a string, the value will be unchanged. If the value is an integer, it will be a string of the decimal digits (1234 --> "1234"). If the value is a bool, it will be either "True" or "False".
  • (bool) : The internal representation of a bool is an integer. True = 1, False = 0. Casting from a bool to a bool has no effect. Any non-zero integer will be changed to 1 (True). Any 0 integer will remain 0 (False). If the value is a string, a string of length 1 or more --> True, an empty string --> False

Strings

Concatenation

Kitsch overloads the addition + operator for concatenating two strings

a = "foo"
b = "bar"
c = a + b

# String c will contain "foobar"

Multiplication

Kitsch overloads the multiplication * operator between a string and an integer. It is commutative - string * int is the same as int * string

a = "foo"
i = 5

print a*3 # prints 'foofoofoo'
print a*i # prints 'foofoofoofoofoo'
print 3*a # prints 'foofoofoo'
print i*a # prints 'foofoofoofoofoo'

Substrings / String-slicing

Characters in a kitsch string can be indexed like elements of an array. The index is 0-based (the first character is index 0).

a = "foobar"
print a[3] # prints 'b'

Slicing allows a range to be specified rather than a single digit. The last index is not included in the substring. So the range [0:3] would include characters at indexes 0, 1, and 2. Because of this, if a range is specified with both the starting index and the ending index being the same, the result is an empty string (because it does not include the character at the last index)

a = "foobar"
print a[0:3] # prints 'foo'
print a[3:3] # prints an empty string, ''

Either element in the range can be left blank. If the first element in the range is left blank, it means to start from the beginning of the string and is equivalent to start with a 0.

If the second element of the range is left blank, it means to go until the end of the string is reached

Finally if neither is included, the result is the original string

a = "foobar"
print a[3:] # prints 'foo'
print a[:3] # prints 'bar'
print a[:] # prints 'foobar'

Indexes can also be negative! This means it wraps around the string. So for example, the character at index -1 is the last character in the string, at index -2 is the 2nd to the last character in the string.

a = "foobar"
print a[-1] # prints 'r'
print a[:-1] # also prints 'r'
print a[:-3] # prints 'bar'

Expressions and Operators

Kitsch has a standard C-like operator precedence. Bitwise operators are identical to C. Boolean operators are verbose rather than symbolic, like Python or VB. Substring and range operators are similar to Python, with slicing supported. The following are listed from highest priority to lowest priority.

  • Parenthesis: '(' ')'
  • Unary bitwise operators: '~' (bitwise negation)
  • Exponentiation: '**'
  • Bitwise operators: '&', '|', '^' (and,or,xor respectively)
  • Multiplication/Division/Modulo: '*', '/', '%'
  • Addition/Subtraction: '+','-'
  • Comparison: '<','<=','>','>=','!=','=='
  • Boolean Negation: 'not'
  • Boolean Operators: 'and', 'or'
  • Substring/Indexing/Range: '[', ']', ':'

Expressions using ints give int results, and can contain identifiers and numeric constants and can be assigned to integers. Expressions using comparison operators and logical operators (and, or, not) are only valid within an if or while test, or as part of a boolean expression (ie, assignment to a bool variable).

Overloaded Operators

+ is supported between int types for addition

+ is supported between string types for string concatenation

+ is supported between array types for concatenation. The array types must be the same. For example, int[] and int[] can be added together, but string[] and int[] cannot.

* is supported between int types for integer multiplication

* is supported between int and string for duplication of strings.

All other arithmetic and bit-wise operators are only supported by int variables.

Conditional Control Structure

So far the language only supports an "if/elif/else" form of conditional control. Rather than using curly {} braces for blocks, the if statement has a matching fi statement to close the block.

A colon is used to separate the expressions in the condition from the statements in the block.

Multiple tests can be created by using the elif keyword and a condition, and a final default block with the else keyword.

NOTE: Conditionals must be either boolean variables, comparisons (like <, ==, etc), or logical combinations thereof (using not, and, and or).

Form

	if <some comparison> :
		<some statements>
	elif <another condition> :
		<more statements>
	else :
		<more statements>
	fi

Valid Examples

	if x < y :
		x = y
	elif x > y :
		y = x
	else :
		x = z
		y = z
	fi 
        if True:
               <statements>
        fi
        if boolvar1 and boolvar2 :
               <statements>
        fi

Invalid Examples

Conditionals may not have just strings or integers

       if "foobar":
               <statements>
       fi
       if 42:
               <statements>
       fi

Iteration

At the moment the language only supports a while loop for iteration. An iterator based 'for' loop is planned for the future.

Form

while <some condition> :
<statements>
elihw

Example

while x < 100:
    sum = sum + x
    x = x +1
elihw

Input/Output

I/O is accomplished through the use of print and read statements. print _expr_ prints the result of the expression followed by a newline to standard out. read <ident> reads the next line from standard in. The endline is not included in the string. All values read in become strings. An explicit cast must be made to make it into another type.

Reading blocks indefinitely until a newline is received(\n). The text can be empty, but must still be followed by a newline.

Example

read x # this will set "x" equal to the next line of text entered via stdin 
print x # Print out the string + \n to stdout

Functions

Function Declaration

Functions are declared with the following syntax.

def functionName(<required_parameters>*,<optional_parameters>*):
    <function statements>
    <return type> return <expression>
fed

Function Calling

Functions are called/invoked with the following syntax. Arguments are positional, the first argument passed into the function will be the first parameter to the function. All function arguments are passed by value.

functionName(<argument1>,<argument2>,...,<argument n>)

Function Rules

  • Function parameters do not require types
    • However a function only works with one set of types. (examples follow for clarity)
    • Kitsch performs type-inference of the function parameters based upon the calls made to that function.
    • The first call in the program (first in terms of program flow - not necessarily the first time it appears in the source file) determines the types of the parameters. Multiple versions of the same function would have to be generated to support calls to the same function with different types - this is not implemented (yet?).
    • A type error will occur at compile-time if the function is called again with arguments of different types.

  • The return statement must be prefaced by the return type (this simplifies type inference - this may go away in the future)
    • The return statement is optional, if a return is not specified then null (0) is returned automatically.
  • All required parameters (those without a default value) must come before optional/default parameters
  • Optional parameters must be assigned to constants.
  • If an optional argument is provided by the caller, the argument type must match the type of the default value.

Examples

# A simple function with no arguments and no return statement, this will return 0
def simple():
    print "Hello World!"
fed

# Call the simple function
simple()

# Adds two numbers, x and y, and returns the result
def add(x,y):
    int return x+y
fed

# Call the function with arguments
add(10,20)
# Or assign its result to a variable
sum = add(10,20)
# Or use it an expression
sum = add(10,20)+30

print "Sum is: " + (string) sum

# Adds two numbers, x and y, and returns the result. 
# y is optional and defaults to a value of 42 if not specified by the caller
def addDefault(x,y=42):
    int return x+y
fed

# Call it with both parameters specified
addDefault(10,20)
# Call it with just the required parameter, y will be 42 inside the function
addDefault(10)

Invalid Examples

# A simple function meant to concatenate 2 strings
def concat(s1,s2="bar"):
    string return s1+s2
fed

# We can call it first with 2 string arguments - this is valid
s = concat("foo","bar")

# Now try to call it again with different arguments - this is INVALID
# 'concat' has already had the 's1' argument inferred as a string, an integer is a type error
s = concat(42,"bar")

# Now try to call it with a default value whose value is of a different type - INVALID
s = concat("foo",42)

# This function is invalid because it has a required argument after a default parameter
def invalidDefault(y=42,z):
    int return x+y+z
fed

Arrays

Arrays are dynamically allocated on the heap at run time. They do not need to be explicitly declared.

An arrays must contain homogeneous primitive elements. Every element in the array must be of the same type. Arrays of arrays are not supported yet.

Creating Arrays

An array is created by either being explicitly initialized, or via an index assignment.

Arrays can be initialized with the following syntax:

<identifier> = [expression1, expression2, ..., expressionN]

Example:

    a = [100,200,300,400,500] 

Arrays can also be created simply by assigning to an index of the identifier. If the identifier does not already exist, an array is created. All of the other values are initialized to either 0, an empty string, or False, for int, str, bool, types respectively.

    # This creates an array of 6 elements, the other elements are initialized to 0
    b[5] = 42 

If the array already exists, but an index is used that exceeds the currently allocated space for the array, then Kitsch automatically reallocates a new array and updates the pointer value. There is no such thing as an index out of bounds error for a positive integer.

Array Assignment

Array elements are assigned using the following syntax

<identifier>[expression] = <expression>

The index can be any integer expression. A negative index results in a run-time error. 0 is the index of the first element in the array.

Example:

    a[0] = 0
    a[1] = 42
    a[2*4] = 100
    a[a[1]] = 200
    x = 0
    while x < 5:
        a[x] = x**2
        x = x + 1
    elihw

Arrays in memory

The identifier associated with an array is a pointer to the beginning of the array structure on the heap. The array structure contains the actual length of the array, the amount of memory allocated for the array, and all of the elements of the array (starting with the value at index 0).

Arrays as parameters

The identifier is a pointer (reference) to the array. Therefore a function that modifies the elements of the array will modify the original array in the caller's scope. Arrays are not copied on the stack when passed into functions.

The pointer itself is copied by value, so if a new array is created (by assigning to an element larger than the current length, or adding two arrays) then the identifier in the caller will not point to the new array.

Example of modifying elements:

a [1,2,3]
print a
def f(array):
    i = 0
    while i < len(array):
        array[i] = array[i] + 1
        i = i + 1
    elihw
fed
f(a)
print a

The pointer to the array 'a' is passed by value, however simply modifying the individual elements of the array does not cause a relocation of the array, so the reference to 'a' after the function call points to the modified array

Output:

[1, 2, 3]
[2, 3, 4]

Now consider an example where a new list is created

a = [1,2,3]
def f(array):
     array = array + array + array
fed

print a
f(a)
print a

Output:

[1, 2, 3]
[1, 2, 3]

A new array was created because array+array+array could not fit in the original array's allocated memory. Therefore 'a' contains a reference to the original [1, 2, 3], not [1, 2, 3, 1, 2, 3, 1, 2, 3].

Note that the internal allocation of arrays reserves more space than is required anytime an array is realloced, so the array pointer may not always be moved if elements are assigned to the array larger than its original len(), but this behavior should not be relied upon.

An array pointer should be returned if you want to expand an array inside a function.

Example:

a = [1,2,3]
def f(array):
     int[] return array + array + array
fed

print a
a = f(a)
print a

Output:

[1, 2, 3]
[1, 2, 3, 1, 2, 3, 1, 2, 3]

If you need to return both an updated pointer reference and another value, then you must create an array containing a reference to the modified array and your desired return value(s)

Array Operations

The only operator supported between arrays is addition. It concatenates the elements of the arrays

Example:

    a = [1,2]
    b = [10,11,12]
    c = a + b

    # c = [1,2,10,11,12]

Built-in Functions

Kitsch contains a library of functions that get compiled into all programs (currently the Compiler does not intelligently link functions into the target-code based on whether or not the are used).

These functions are used for things like allocating memory on the heap, copying arrays, initializing arrays, and printing arrays. Most of these built-ins are called directly by the compiler and are not meant to be used by user-code (but they could if they wanted to).

len()

The len() function is a global built-in function that returns the length of an array. The length of the array is determined by the largest index that has been assigned to in the array. If an array is created, or resized, by assigning to an index, then the length will be 1 greater than that index - not the number of elements that have been explicitly assigned.

len() only works on arrays, it will not work for a string.

a = [2,4,6]
size = len(a)
# size will be an integer, 3

b[5] = 0
size = len(b)
# size will be 6, not 1
Powered by Google Project Hosting