view manual.txt @ 253:697c2c562af2

Fix infinite loop in hash dict
author Michael Pavone <pavone@retrodev.com>
date Sat, 31 May 2014 21:27:03 -0700
parents 966a09d226e3
children
line wrap: on
line source
Intro
-----

TP is an ahead of time compiled, dynamically typed (though there are plans for an optional type checker) language heavily inspired by Smalltalk. The main goal of the language is to be a suitable target for a structured editor on touch-screen devices and tablets in particular. The prototype of the editor is not really complete enough to be useful at this time.

Assignment
----------

Assignment is done with the <- operator. Inside a lambda, it is used to assign a value to a variable. Inside an object definition it is used to either assign an initial value to a property or a lambda to be used as the definition of the method. Assignments are currently the only construct that are not expressions and as a result they cannot be used in an expression construct. This may change in the future.


Symbols
-------

Symbols in TP must start with a letter, underscore, bang, question mark or at symbol. Numbers and colons can be used in symbol names as long as they are not the first character. Colons allow a function or method name to be split into multiple parts with the arguments interspersed between them. This is covered in more detail in the second on function and method calls.

Lambdas
-------

Lambdas are enclosed in curly braces. If present, the argument list is preceded by a colon. Individual argument names are separated by spaces and may also be preceded by a colon. These internal colons provide a hint to the user (and eventually the structured editor) about how to best intersperse function name parts and arguments. The body of a lambda is made up of zero or more assignments or expressions. The result of evaluating the final expression of a lambda is used as the result.

Examples:
{} //Empty lambda with no arguments
:foo bar {} //Empty lambda with two arguments: foo and bar
:foo :bar {} //Same as before with a placement hint
:foo {
	foo
} //A lambda that simply returns its only argument

Objects
-------

TP has no named object types. All objects are created via object literals. An object literal is started with a hash followed by an open curly bracket character and is terminated with a close curly bracket character. Properties and methods are defined with assignments. A property is really just syntactic sugar for a getter method and a setter method. The getter method has a name that is identical to the name of the property. The setter method has a bang appended to the end of the property name. Setter methods return the object being modified.

A method is created when a lambda is assigned to a name inside of an object definition. This assignment must be done with a literal lambda. Assigning a lambda to a variable and then using that variable inside an object definition will generate a property that is initialized to that value. The first argument to a method is named self and refers to the object the method was called on. If self is not explicitly named as the first argument, it will be added implicitly.

Examples:
#{} //Object with no methods
#{
	foo <- 42
	bar <- baz
} //Object with two properties
#{
	baz <- 42
	foo <- :bar {
		2 * bar + (self baz)
	}
}//object with method with an implicit self parameter
#{
	baz <- 42
	foo <- :self bar {
		2 * bar + (self baz)
	}
}//identical object with an explicit self parameter on the foo method
_foo <- :bar { 2 * bar }
#{
	foo <- _foo
}//object with a property named foo initialized to contain a lambda

Operators
---------

TP has the following binary operators. Operators are listed in order of precedence with operators of the same precedence listed on the same line.
* / %            //multiplication, division, modulus
+ - . xor and or //addition, subtraction, concatenation, bitwise operations
<= >= < > = !=   //comparison
&& ||            //logical

Operators can be the target of an assignment in an object definition. This allows operators to be defined for user types.

Function and method calls
-------------------------

There are three syntaxes for function and method calls. There is the unary method syntax, the regular method syntax and the function call syntax. Despite their names, there is no semantic difference between these three syntaxes and they can be used for both function calls and method calls. The one limitation is that the unary method syntax can only be used with methods/functions that take a single argument, including the self argument.

The unary syntax consists of the first parameter followed by the function or method name. The two are separated by a space. Example:

object methodName

The regular method syntax adds a colon to the method or function name. Additional arguments follow the colon and are separated by spaces. Example:

firstParam methodName: secondParam thirdParam

The function call syntax is similar, but has the first argument following the method or function name. This syntax is generally the only way to call a function with no arguments. Examples:

methodName: firstParam secondParam thirdParam
funcWithNoArgs:

Symbols can contain internal colons and when used as a function or method name, the symbol can be split into several pieces at those colons. Example:

//call foo:withBar:andQux with the arguments: baz, dive and quixotic
foo: baz withBar: dive andQux: quixotic

Flow Control
------------

TP has no explicit flow control structures. Instead, the flow control structures are implemented as methods that take lambdas as arguments. The methods if and if:else are implemented on the boolean objects and provide for conditional execution. while:do is implemented on lambda objects and provides a basic while loop. foreach is implemented on sequence types to provide a mechanism for easily looping over an array. Examples:

if: foo = bar {
	//do something when foo is equal to bar
}

if: foo = bar {
	//do something when foo is equal to bar
} else: {
	//do something else when foo is not equal to bar
}

while: { foo = bar } do: {
	foo bazinate
}

//print each string in the array
foreach: #["foo" "bar" "baz" "qux"] :index value {
	print: (value . "\n")
}

Scope
-----

Variables are lexically scoped. Objects also participate in scoping. This allows access to properties and methods in the current object and objects in parent scopes without an explicit reference to the relevant object. Modules exist at the root of the scope tree. The name true, refers to the module in modules/true.tp unless it has been shadowed with an assignment.

Module
------

A TP source file contains exactly one module. A module is simply an object. The top level of a TP source file should be an object literal or a lambda with no arguments that returns an object literal.

Importing
---------

Methods from one object can be imported into another object. This is essentially just synatctic sugar for delegation. A reference to the imported object is created in the target object and calls to the imported methods are forwarded to that object.

Imports are currently not really implemented in the C backend at this moment, but I may be able to add partial support in time for the contest.