( see Downloads at bottom of page )
ParentheTcl (pronounced "parenTHETical," abbreviated "p7tcl" or "P7")
is a safe language for writing fast, compiled extensions
for Tcl.
Purpose
ParentheTcl is designed primarily for doing
things that either are
Really Slow
or that you
Just Can't
do in Tcl:
- Efficient Character and Byte Operations
(like HTML or MIME encodings, or cryptography)
- Objects allocated from the Heap
(like objects in Java;
automatically deleted when unreferenced)
- [Not Yet Implemented] Functional programming with
lambda expresssion with lexical scoping
Compatability with Tcl
Functions written in ParentheTcl show up as commands in Tcl
when the compiled module is loaded.
ParentheTcl remains Tcl-ish in style and syntax,
as well as in compatability of its
data types and exception handling.
Safety
Like Tcl, ParentheTcl is automatically memory-managed,
so exploits due to memory errors should not occur (once the
compiler and runtime are debugged!).
Array bounds are checked, pointers are checked for null,
and reference counting is used to free memory objects.
Parenthesized Extensions
ParentheTcl extends the syntax and semantics of Tcl
in three fundamental ways, all marked by
the use of parentheses:
- Parenthesized types:
All functions, parameters, and variables
are strongly typed, with type declarations
preceeding the first occurrance of the
name, in parentheses.
- Parenthesized expressions:
Arithmetic expressions are simply in parentheses,
rather than as an argument to an expr command.
- Parenthesized subscripts:
ParentheTcl has two kinds of composite data types that
use parentheses to subscript their elements:
Vectors
(which are like Java arrays) and
Classes
(which are like Java classes with only nonstatic
public fields). Vectors are indexed by
a parenthesized integer expression; members of tuples are
named using a parenthesized identifier.
A Few Small P7 Examples
Define the triangle of n to be 1+2+3+...+n.
Triangle is like factorial,
but uses addition instead of multiplication
so the numbers
don't overflow so fast. Here's a straightforward
recursive definition of triangle:
p7proc (int)triangle_recursive { (int)x } {
if ( $x < 1 ) { return 0 }
return ( $x + [triangle_recursive ($x-1)] )
}
|
- p7proc
defines a ParentheTcl function, which will be compiled
and made available as a command in Tcl as well as
to other ParentheTcl functions.
- (int)
marks the return type of the function and the
type of the parameter. All functions and variables must
be typed at their first mention.
- The last return statement has a parenthesized expression,
which is replaced with its result,
as an argument to the return command.
Here's an iterative definition of triangle:
p7proc (int)triangle_iterative { (int)x } {
set (int)sum 0
for {set (int)i 0} ($i <= $x) {incr i} {
incr sum $i
}
return $sum
}
|
- Two local variables
sum & i
have their type
(int)
declared with
set
statements.
There cannot be white space in the parentheses, nor before the
variable or procedure name being typed.
Think of it forming one word, by Tcl's syntax.
- The boolean condition expressions required by control
statements
if, for, & while
are specified with parenthesized expressions. You cannot
use curly braces or anything else.
- The termination condition expressions for the looping statements
for & while
are re-evaluated each time (they're special that way.)
- Curly braces are required for the blocks of code
in the control statements
if, for, & while.
- Parenthesized expressions may have white space within them.
Now here's an example with a vector of unicode characters.
In P7 this type is named
(uni*)
. It's like the type
char[]
in Java.
pproc (uni*)to_lower { (uni*)x } {
for {set (int)i 0} ($i < [len $x]) {incr i} {
if ( 'A' <= $x($i) && $x($i) <= 'Z' ) {
set x($i) ($x($i) - 'A' + 'a')
}
}
return $x
}
|
- In a P7 type name, a trailing * means "vector of",
like a trailing [] means "array of" in Java.
- The builtin command
len
tells the size of a vector.
- Subscripting looks a lot like Tcl's array subscripting --
but it has nothing to do with Tcl's array variables, which are
hashes indexxed by strings. P7 vectors are indexxed by integers,
starting with index 0. It doesn't show up in this example,
but arbitrarty arithmetic expressions (with embedded
white space allowed) can be inside those parenthesized
subscripts -- both as the first argument to
set
and inside other parenthesized expressions.
- The type
(uni*)
relates to normal Tcl strings in a special way:
when Tcl calls P7 or vice versa, any strings in Tcl
get copied to
(uni*)
vectors, or back, with each character in Tcl matching one character
slot in the vector.
- The elements in the
(uni*)
vector are of type
(uni),
which is a 16-bit unsigned short (as in Java), compatible with
(int),
very much like strings in C are made of little C ints.
- The single-quoted characters
'A' & 'Z'
are also of type
(int),
like in C.
- When called from Tcl,
the (uni*) parameters are in parameters. The Tcl string
is copied to produce the (uni*). Changing the elements
of the (uni*) will not alter the original string in Tcl.
When p7proc returns the (uni*) variable x
as its result, the contents of its vector are copied
back to Tcl.
- This is very tricky: When called from P7,
the vector is passed by reference. This pproc
modifies its caller's vector,
when called from another ParentheTcl pproc.
- If you want to pass a vector to & from Tcl by reference,
you can put it in a member of a
class instance (see next section)
and pass the class instance instead.
Class instances are always passed by reference,
whether the p7proc is called from P7 or Tcl.
The next example defines a p7class named Node,
which has two fields, left and right.
Then ParentheTcl functions
cons, car, & cdr
simulate Lisp operations with the Node class
to construct a new Node get the left part, or
get the right part.
p7class Node { (tcl)left (Node)right }
p7proc (Node)cons { (tcl)a (Node)b } {
set (Node)z [new Node]
set z(left) $a
set z(right) $b
return $z
}
p7proc (tcl)car { (Node)x } { return $x(left) }
p7proc (Node)cdr { (Node)x } { return $x(right) }
p7proc (Node)append_item { (Node)list (tcl)item } {
if ($list==null) { return [cons $item null] }
cons [car $list] [append_item [cdr $list] $item]
}
p7proc (Node)reverse { (Node)x } {
if ($x==null) {return $x}
append_item [reverse [cdr $x]] [car $x]
}
|
- The builtin type (tcl) is Tcl's string
type (internally, it is a Tcl_Obj).
It can hold Tcl strings, Tcl lists, and other things Tcl
does with strings.
- Double-quoted literal strings in P7 are of type (tcl),
as are "barewords" and anything else that is not
specifically typed as something else.
- Type (tcl) can also hold a reference to a P7
class instance.
(Internally, a new Tcl_Obj type holds the reference.)
- The function cons returns a new instance of Node.
When cons is called from Tcl, the new Node is returned to Tcl
in a special string value.
- Then that Tcl value can be passed to car or cdr or any
other ParentheTcl function that takes a Node.
- The special value null represents the NULL reference,
like null in Java.
If passed to Tcl, the null reference becomes the empty string.
- Tcl array subscript syntax is used to access the fields
of the tuple. Bare words must be used inside the parentheses.
- Exercizes for the reader:
What does append_item do? Why is it needed in reverse?
See more sample programs
here.
Reference Manual
Work In Progress: see
http://yak.net/repos/parenthetcl/_darcs/current/doc/
for a snapshot.
Philosophy
ParentheTcl is a 90/10 Language.
it only needs to have the 10% of language features
that cover 90% of the problems in
our target applications.
It does not need all the features
of a complete modern language;
all of Tcl is still there for the rest.
Other Completed Features
- Global variables (with p7global)
- Overloading function names on number of arguments
- Overloading function names on type of first argument
- Runtime selection of function based on actual class
of a (tcl) value as the first argument to the function.
That is, ParentheTcl has object-oriented dispatch
based on a distinguished receiver, as in Java
(but without class inheritance).
- Generics: templated Class and Function types
(but you must explicitly choose them;
there is no pattern-matching in the compiler.)
- Metaprogramming: A P7 program is just a Tcl script,
evaluated in a "safe interpreter" with just four
extra commands added to generate P7 functions,
classes, and global variables.
Future Directions
Not in any particular order of priority, just some ideas...
- Wide & double types
- Builtin dict type
- Vectors of vectors & vectors of classes
- namespaces
- Modular compilation & linking
- Functional programming: lambda expressions with
lexical scoping
- Extend Parenthesized Expression syntax to accept more
Java & C syntax (to ease translating code to p7) (it seems
this will actually work quite well!)
- Reference Count optimizations
Download
Beta quality. All "make test" tests should work.
Tested only on Fedora Core with i386.
Get tarballs from
http://yak.net/repos/
or use "darcs get" from http://yak.net/repos/parenthetcl/
Instructions:
Run "sh configure --help", then configure and make.
Use tcl8.4.4 or later.
Reports:
Works with Ubuntu 64-bit LiveCD:
- Add to your environment:
P7EXTRACFLAGS='-I /usr/include/tcl8.4/ -fPIC'
- Add to your make command:
INCLUDES='-I /usr/include/tcl8.4 -fPIC'
- All tests work except 'encode', which needs /etc/termcap
as sample data.
UPDATES
New: type (dict), for (tcl)-to-(tcl) hashtables
New: lambda expressions
New: oo7, an object-oriented class system for Tcl, written in ParentheTcl
http://yak.net/repos/parenthetcl-0.6.2.tar.gz
[ Sorry, all guestbooks disabled temporarily due to rampant spam :( ]
parenthetcl-0.6.4.tar.gz