Ivy 2005 is the latest version of the scripting language I wrote originally in 1993. This version adds an extensible syntax and is designed to be embedded in my test editor JOE. It is just starting to work, so I've uploaded it to sourceforge.
By "extensible syntax" I mean that you can define new statements in the language just by declaring new functions. The trick then is to make functions powerful enough to do the same things that statements can do: delayed evaluation and messing around with scope.
For example, here is a function for a text editor which allows the body code to move the cursor. When the code is complete, the cursor is automatically restored (akin to unwind-protect in LISP):
fn excursion(&body) var save = cursor var rtn = *body cursor = save (rtn)
The '&' prefixing the formal argument indicates that the code for that argument should not be evaluated immediately (as would normally be done in this pass-by-value language), but to instead delay its evaluation (the argument is packaged up as a function in its closure). The '*' causes the function to be called (evaluated). In LISP, this would all be done with quoting or macros.
Other features
Ivy's interpreter and parser are both event driven. For example, when an Ivy program calls a C-language function, it returns from the interpreter and return a pointer to the C-language function to the caller. When the C-function is done, the interpreter should be called again.
This means Ivy can be used in a co-operative multi-threaded environment: think of a command interpreter for a MUD.
In Ivy everything is a function, but to make statements look "normal" (and to separate statments out from the parser as in LISP), there is a "command" format for function calls. Basically, these are the same:
func(x,y,z) func x y z
Block structuring can be indicated by square brackets or indentation:
# Indented blocks of commands foreach a {1 2 3} if a==2 print "There's a 2" print "Hello"
# square bracket blocks of commands [foreach a {1 2 3} [if a==2 [print "There's a 2"; print "Hello"]]]
# Expressions foreach(a,{1 2 3},if(a==2,print("There's a 2")\print("Hello")))
Indentation is preferred for blocks, but square brackets are convenient for when Ivy is used interactively. A generic method of passing multiple indented blocks to a function is provided. This:
if a==1 print "It's a 1" next a==2 print "It's a 2" last print "It's something else"
Is the same as this:
if(a==1,print("It's a 1"),a==2,print("It's a 2"),print("It's something else"))
And can be used for your own functions:
fred a==1 print "It's a 1" next a==2 print "It's a 2" last print "It's something else"
'fred' gets passed 5 arguments.
Ivy is compiled to byte-code, which is then interpreted. Type checking is done at run time. It is a late binding language, meaning that variable name to value bindings happen late (basically there's a hash table lookup whenever a variable is accessed). To help make this a little faster, all names are converted to "atoms", which are unique strings which exist at only one address. The string's address is all that needs to be compared during the hash table lookup. The address is used as the hash value itself: so most variable lookups reduce to a single array access followed by a single word compare.
Ivy has closures: you can define functions inside others, and then return them. The returned function still have access to the creating function's scope at the time of creation.
Ivy has lambda (nameless) functions.
print fn(x,x*x)(7) # Prints 49
Ivy has named argument passing and default argument values:
{x y z} = {1 2 3} # A tuple: assign three variables at # once
c = {`next=(), `value=0} # A linked list b = {`next=c, `value=1} a = {`next=b, `value=2}
These objects are also used for closures. They are the primary data structure of the language. When objects are used as closured, several special members get defined:
this # The closure itself mom # The next outer lexical scope dynamic # The next outer dynamic scope
Ivy has a few other basic types: "hi" # String 123 # Integer 12.3 # Double precision floating point fn((x),x*x) # Function
Ivy has C-like operators. It also has post-assignment operators, a generalization of C post-increment.
a=b=3 # 3 written to b, result (3) written to a a=b:3 # 3 written to b, previous value of b written to a
a+=3 # pre-add a (returns a+3) a+:3 # post-add a (returns old value of a)
a:b:a # swap a and b
It has an assignment form of the '.' (member selection operator). This is convenient for traversing linked lists:
a="Hello" print a(2,5) # Prints "llo" print a(0) # Prints "H"
Ivy has labeled break and continue:
outer: for a=0, a!=10, ++a for b=0, b!=10, ++b if a+b==15 break outer
Other planned features:
Exceptions.
Continuations or co-routines (haven't decided yet: leaning towards co-routines, but designing for continuations).
First-class regular expressions, as in perl.
All UNIX system calls and library functions, as in perl.
Object oriented Ivy (you can do it now with closures, but there is no inheritance, protection or module system).
Widget library and X interface. I'd like to use Ivy as a replacement for "gnu-plot" (and when built into JOE, as a free version of "mathcad"). -- /* jhal...@world.std.com (192.74.137.5) */ /* Joseph H. Allen */ int a[1817];main(z,p,q,r){for(p=80;q+p-80;p-=2*a[p])for(z=9;z--;)q=3&(r=time(0) +r*57)/7,q=q?q-1?q-2?1-p%79?-1:0:p%79-77?1:0:p<1659?79:0:p>158?-79:0,q?!a[p +q*2 ]?a[p+=a[p+=q]=q]=q:0:0;for(;q++-1817;)printf(q%79?"%c":"%c\n"," #"[!a[q-1]]);}
> Ivy 2005 is the latest version of the scripting language I wrote > originally > in 1993. This version adds an extensible syntax and is designed to be > embedded in my test editor JOE. It is just starting to work, so I've > uploaded it to sourceforge.
<snip rest>
is this the same text editor as 'jmacs' (typically a symlink to 'joe'), which came with many linux distros.
if so, that is cool. I had used that editor a lot until eventually using x11 primarily (then, switching over to gedit).
ok, eventually, I migrated back over to windows, whereby I am using notepad...
ok, vaguely interesting.
likely the usual rules for most scripting languages apply, eg, getting anyone to care being likely a major challenge.
now, I am off in physics-engine land, seeing if anyone will care there. hell, at least I have less competition, but ode is pretty well seated. what of my scripting lang (currently a language somewhere between scheme, javascript, and self)? I don't know, probably I will continue to use that for my stuff whenever I need a scripting language.
unsurprisingly, I doubt anyone will care much about anything I do...
(and I watch as the number of posts to this group gradually diminishes afaict...).
In article <IVY-20051101034...@ram.dialup.fu-berlin.de>,
Stefan Ram <r...@zedat.fu-berlin.de> wrote: > Mathematically, a tuple, say a 2-tuple, is defined by > requiring that: >(a,b)=(c,d) <==> a=c ^ b=d, > where "^" is the logical "and". > So IVY has tuples if after the above assignment, >if {x y z} == {1 2 3} > print "a" > will print "a".
True, two tuples are the same if their components have the same value and are in the same order... but mathematics does not require that the symbol '==' should have this particular meaning of 'the same'. Perhaps the symbol '===' has it (LISP has three eq's).
-- /* jhal...@world.std.com (192.74.137.5) */ /* Joseph H. Allen */ int a[1817];main(z,p,q,r){for(p=80;q+p-80;p-=2*a[p])for(z=9;z--;)q=3&(r=time(0) +r*57)/7,q=q?q-1?q-2?1-p%79?-1:0:p%79-77?1:0:p<1659?79:0:p>158?-79:0,q?!a[p +q*2 ]?a[p+=a[p+=q]=q]=q:0:0;for(;q++-1817;)printf(q%79?"%c":"%c\n"," #"[!a[q-1]]);}
In article <21ec4$4366d8da$ca83a7e9$4...@saipan.com>,
cr88192 <cr88...@NOSPAM.hotmail.com> wrote: >is this the same text editor as 'jmacs' (typically a symlink to 'joe'), >which came with many linux distros.
Yes.
>likely the usual rules for most scripting languages apply, eg, getting >anyone to care being likely a major challenge.
Of course: but people did switch to Python when Perl was perfectly adequate.
>(and I watch as the number of posts to this group gradually diminishes >afaict...).
It's all been done before in LISP, so why bother :-)
Actually, USENET itself seems to be in decline. It's sad.
-- /* jhal...@world.std.com (192.74.137.5) */ /* Joseph H. Allen */ int a[1817];main(z,p,q,r){for(p=80;q+p-80;p-=2*a[p])for(z=9;z--;)q=3&(r=time(0) +r*57)/7,q=q?q-1?q-2?1-p%79?-1:0:p%79-77?1:0:p<1659?79:0:p>158?-79:0,q?!a[p +q*2 ]?a[p+=a[p+=q]=q]=q:0:0;for(;q++-1817;)printf(q%79?"%c":"%c\n"," #"[!a[q-1]]);}
> In article <21ec4$4366d8da$ca83a7e9$4...@saipan.com>, > cr88192 <cr88...@NOSPAM.hotmail.com> wrote:
>>is this the same text editor as 'jmacs' (typically a symlink to 'joe'), >>which came with many linux distros.
> Yes.
cool.
>>likely the usual rules for most scripting languages apply, eg, getting >>anyone to care being likely a major challenge.
> Of course: but people did switch to Python when Perl was perfectly > adequate.
well, this one can be understood (sort of, though I am not so fond of python either...).
>>(and I watch as the number of posts to this group gradually diminishes >>afaict...).
> It's all been done before in LISP, so why bother :-)
yes.
mine have typically been little 'new' per se. my newest one can say primarily "resembles javascript" but it is not javascript (some things are different, and I couldn't make crap for sense out of the spec...). as typically, I wrote a compiler for it as well (spews out c), but I can see how much I use this (with a sucky/incomplete ffi, and still unimpressive generated code, there is not that much reason to use it for much...). I am probably the only one who uses it, but this is no big deal.
then I tried ripping off ideas from java (making a mostly statically typed language, and a vm resembling the jvm). gave up as it was proving tedious (a static typesystem complicates things a whole lot) and I couldn't see 'that' much reason to continue implementing it.
actually, it would have been more of a hybrid, allowing mixing a few different things (static and dynamic types, classes and delegation, ...). it changed a few things vs java: modular, instead of one class per file; limited-scope toplevels, vs no toplevels; plain functions as well, ...
in the simple case, the code would likely look very similar to java. I also considered the possibility of using java itself, but noted that it had little hope of effectively managing dynamic typing, and a few other things I didn't really like (I also wanted operator overloading, for example).
java also didn't have the idea of stack-allocated/in-place arrays or structures, which was a detractor. my design included 'structs', where structs differed primarily from classes in that: they were allocated in place; they were passed by value; (considered) disallowing extending and methods.
if extending were allowed, it would be limited, eg, in that a derived struct couln't generally be passed to something expecting the parent type due to size issues. methods would be limited, if present at all (no non-static methods, unless explicitly part of the struct body).
arrays were similar: int foo[3]; //creates an in-place array; int foo[]=new int[3]; //creates a dynamic array
...
reasons for it: likely more efficient with memory; possibly faster interpreter; less ffi work needed (typesystem would be much closer to c); possibly worthwhile generated c code, and the ability to call directly to/from the language (my other langs have typically required 'stubs' to convert arg/return types back and forth and do the calls); ...
against: I allready have a working interpreter for my other lang; the effort required for implementing it; ...
dunno, I could continue if I saw a reason.
> Actually, USENET itself seems to be in decline. It's sad.
yes, it used to be that I could actually watch stuff being talked about on all the groups. over time, everywhere gets more and more empty...
In article <bad88$4369376a$ca83a7e9$27...@saipan.com>,
cr88192 <cr88...@NOSPAM.hotmail.com> wrote: >...static typing is tedious...
It's so limiting.. but it's fast.
I was looking into macros for Ivy at point and came across in interesting paper. Some scheme programmer came up with the idea of first class macros in a statically typed language (so you can return a macro and call it). What he realized was that this would be possible if macros had types. Think about a macro which declares a variable and you'll see the need for this.
>java also didn't have the idea of stack-allocated/in-place arrays or >structures, which was a detractor.
(as much as it pains me to say this) You should take a look at C#. Like Java, most things are handled by reference. But it distinguishes between stack and heap values, especially for primitive types. When a primitive type needs to on the heap, it gets boxed up in a class, like java. Anyway, I think it might have stack allocated arrays, or at least stack allocated tuples.
The stack allocation is interesting for classes. It would be nice if stack allocated classes had their destructors called when they go out of scope, as in C++. A version with reference counting instead of garbage collection would also be interesting. I've seen Java programmers jump through hoops trying to manage external resources like file-descriptors, with only GC finalizers.
Someone needs to add templates to Java or C#: that you have to use downcasting to make generic containers is dangerous. -- /* jhal...@world.std.com (192.74.137.5) */ /* Joseph H. Allen */ int a[1817];main(z,p,q,r){for(p=80;q+p-80;p-=2*a[p])for(z=9;z--;)q=3&(r=time(0) +r*57)/7,q=q?q-1?q-2?1-p%79?-1:0:p%79-77?1:0:p<1659?79:0:p>158?-79:0,q?!a[p +q*2 ]?a[p+=a[p+=q]=q]=q:0:0;for(;q++-1817;)printf(q%79?"%c":"%c\n"," #"[!a[q-1]]);}
> In article <bad88$4369376a$ca83a7e9$27...@saipan.com>, > cr88192 <cr88...@NOSPAM.hotmail.com> wrote:
>>...static typing is tedious...
> It's so limiting.. but it's fast.
my idea was actually more for a hybrid, eg, statically typed core with dynamic types as well. they would be called 'variant', and would be processed at run-time whenever they pop up.
the compiler logic for static typing is a horrible pita though.
no longer can one, say, reduce the left and right-hand expressions (as a simple process involving eliminating constants), then just spit out an opcode for 'add' and be done with it.
instead, it is necessary to check the types, and generate the correct bytecode for those types. many things can get weird as well, and one has to worry about a lot more possible occurances during compilation.
also, one can't just insert some opcode like 'ok, go fetch this variable', instead, one needs to locate the var exactly, and generate bytecode for fetching it from the object or its respective place on the stack.
...
> I was looking into macros for Ivy at point and came across in interesting > paper. Some scheme programmer came up with the idea of first class macros > in a statically typed language (so you can return a macro and call it). > What he realized was that this would be possible if macros had types. > Think > about a macro which declares a variable and you'll see the need for this.
ok, cool.
hmm, lispy macros in a c-style language would be cool, but I can see some notable implementation issues (needing something like an interpreter at compile time, and running into problems based on the ad-hoc ways I tend to structure the parse trees).
better would be probably trying to pull off magic with templates, and making the compiler smart enough to figure what stuff is going on at compile time and what is going on at run-time (eg: it could expand all the code as if it were to be done at run-time, and the optimizer would eliminate everything that can be done at compile time).
still, this could have limits, eg, recursive templates could be a problem as they would generate a recursive pattern in the parse trees. more hackery could be done, eg, lazily evaluating templates during optimization. the result would be that, during optimization, branches that get eliminated first (eg: if with a constant expression) never get processed, and, thus, the templates are never evaluated.
or something (likely, c++ compilers do something similar allready, but I haven't looked into this).
for now, I probably wont add them (if I get to finishing implementing the language at all...).
>>java also didn't have the idea of stack-allocated/in-place arrays or >>structures, which was a detractor.
> (as much as it pains me to say this) You should take a look at C#. Like > Java, most things are handled by reference. But it distinguishes between > stack and heap values, especially for primitive types. When a primitive > type needs to on the heap, it gets boxed up in a class, like java. > Anyway, > I think it might have stack allocated arrays, or at least stack allocated > tuples.
c# lacks any dynamic types (ok, so did java), which are at least sort-of a requirement for my uses. likewise I am not compelled much to write a c# compiler anyways, nor do I know of any besides ms's, ...
problem is: I like dynamic types, so much so that I did my own dynamic type-system and have been using it with c for quite a while (along with garbage collection, though I keep overly relying on it, and the gc kicking on can be rather annoying sometimes).
though one doesn't always (or even often) need dynamic types, there are cases where they are imo necessary (or at least quite helpful).
but, yeah, any scripting lang I use should support dynamic types, in particular, 'my' dynamic types. this does limit my options a little.
> The stack allocation is interesting for classes. It would be nice if > stack > allocated classes had their destructors called when they go out of scope, > as > in C++. A version with reference counting instead of garbage collection > would also be interesting. I've seen Java programmers jump through hoops > trying to manage external resources like file-descriptors, with only > GC finalizers.
yes.
java's lack of explicit destruction seems like a problem imo (I had considered explicit destruction, but more as a 'use with caution' feature).
stack allocated classes were not included in my idea due to syntactic reasons (lack of explicit pointers). potentially, the language could infer that an object would never go outside the scope of some function, and thus make it stack allocated, but I didn't do this. I opted making it explicit, eg, 'structs'.
alternatively, though, I could make it so that some keyword or something would make classes reside on the stack.
class Foo extends Bar options pass_by_value { ...
}
ok, this looks like crap. if something like this were done, I might need something different ('on_stack' looked worse imo).
> Someone needs to add templates to Java or C#: that you have to use > downcasting to make generic containers is dangerous.
yes, ok. my idea was that generic containers would be handled by use of variant. as for classes, variant would allways know that it is a class, and what class. assignment back to typed variables would incure typechecking though.
templates could be cool, but likely I would change their syntax a little.
template min(x, y) { return (x<y)?x:y;
}
vs: template min<x, y> { return (x<y)?x:y;
}
wtf is with those angle brackets anyways?... who sat around and thought that one was a good idea? given c++'s design, it is unlikely it was needed to avoid confusing the compiler, so, I don't get it...