splendini
=========
splendini is a programing language. Here is a sample session; building instructions are further down:
1 : 1
1=> 1
2 : Type(1)
2=> MInt
3 : a
3=> a
4 : Type(a)
4=> Symbol
5 : "hello world"
5=> "hello world"
6 : Type("hello world")
6=> String
7 : Type(Type(1))
7=> Symbol
8 : Type(Type(a))
8=> Symbol
9 : Type(Type("hello world"))
9=> Symbol
10 : f(a,1)
10=> f(a, 1)
11 : Type(f(a,1))
11=> f
12 : 1.1
12=> 1.100000000000000
13 : Type(1.1)
13=> MReal
14 : Type(a)
14=> Symbol
15 : Set(a, 1.1)
15=> 1.100000000000000
16 : a
16=> 1.100000000000000
17 : Type(a)
17=> MReal
18 : Type(Quote(a))
18=> Symbol
19 : Add(1,1)
19=> 2
20 : Type(Add(1,1))
20=> MInt
21 : Add(1,1.)
21=> 2.000000000000000
22 : Type(Add(1,1.))
22=> MReal
23 : Function(x, Add(x,1))
23=> Function(List(x), Add(x, 1))
24 : Type(Function(x, Add(x,1)))
24=> Function
25 : Set(f, Function(x, Add(x,1)))
25=> Function(List(x), Add(x, 1))
26 : f(1)
26=> 2
27 : Function(x, Add(x,1))(1)
27=> 2
28 : IsSame(1,1)
28=> True
29 : IsSame(a,a)
29=> True
30 : IsSame(a,b)
30=> False
31 : IsSame(Type(a),Type(b))
31=> False
32 : a
32=> 1.100000000000000
33 : b
33=> b
34 : Quote(a)
34=> a
35 : IsSame(Type(Quote(a)),Type(b))
35=> True
36 : If(True, "yes", "no")
36=> "yes"
37 : If(False, "yes", "no")
37=> "no"
38 : If(True, 1)
38=> 1
39 : If(False, 1)
39=> Null
40 : test
40=> test
41 : Type(test)
41=> Symbol
42 : If(test, 1)
42=> If(test, 1)
43 : If(test, 1, 2)
43=> If(test, 1, 2)
44 : If(test, 1, 2, 3)
44=> 3
45 : And(True, False)
45=> False
46 : Or(True, False)
46=> True
47 : Not(True)
47=> False
48 : Sequence(Set(a,0), Set(a, Add(a, 2)), a)
48=> 2
49 : Length(g(1,2,3))
49=> 3
50 : Length("Hello")
50=> 5
51 : Part(g(1,2,3), 1)
51=> 1
52 : Part(g(1,2,3), -1)
52=> 3
53 : Part(g(1,2,3), 0)
53=> g
54 : Set(a,0)
54=> 0
55 : Clear(a)
55=> 0
56 : a
56=> a
57 : Type(a)
57=> Symbol
58 : Set(a,0)
58=> 0
59 : Loop(Set(a, Add(a, 2)), List(10))
59=> Null
60 : a
60=> 20
61 : Timing(Loop(Set(a, Add(a, 2)), List(1000000)))
61=> List(0.805185079574585, Null)
62 : a
62=> 2000020
63 : Done
Some nice stuff:
================
1 : Set(f, Function(a, If(Not(IsSymbol(a)), Quote(f)(a), Print("Hi");a)))
1=> InterpretedFunction(List(a), If(Not(IsSymbol(a)), Quote(f)(a), Sequence(Print("Hi"), a)), StaticScope)
2 : f(sym)
Hi
2=> sym
3 : f(a)
Hi
3=> a
Closuers (Let):
=================
1 : {inc, dec} = Let({{b, 10}}, {Function({}, SetGlobal(b, b + 1)), Function({}, SetGlobal(b, b + -1))})
1=> List(Function(List(), SetGlobal(b, Add(b, 1)), StaticScope), Function(List(), SetGlobal(b, Add(b, -1)), StaticScope))
2 : inc()
2=> 11
3 : inc()
3=> 12
4 : dec()
4=> 11
5 : dec()
5=> 10
6 : dec()
6=> 9
------------
1 : i=0;j=0; Block({{i,1}}, Print(i); Print(j); i = 2; j = 2; Print(i); Print(j)); {i,j}
1
0
2
2
1=> List(0, 2)
% Block[{{var1, val1},..}, body]
% Block works by temprarily blocking all variables var1.. given and uses the value val1 in place. Also Block does not scope any variables in it's body (as does Let) except those given in var1...
------------
24 : i=0;{Table(i, {i, 1, 2}),i}
24=> List(List(1, 2), 0)
25 : j=0;{Table(j=i, {i, 1, 2}),i}
25=> List(List(1, 2), 0)
26 : j
26=> 2
% Table/Loop use Block for scoping the itator variable.
----------------
1 : i = 0; Let({},i=1)
1=> 1
2 : i
2=> 0
3 : i = 0; Let({},Set(i,1,GlobalFrame))
3=> 1
4 : i
4=> 1
5 : i = 0; Let({}, Let({{frame, Context()}}, Set(i,1, frame)); i)
5=> 1
6 : i
6=> 0
7 : i = 0; Let({}, Let({},SetGlobal(i,1)) )
7=> 1
8 : i
8=> 1
% the difference between SetGlobal and Set with a context is that SetGlobal walks
% up the frames, looks for the variable name and sets it's value (scheme set!).
% Set sets the value of the variable in a context specified.
% SetGlobal and Set with a context are also useful within a Function.
Let over Lambda over Let over Lambda:
======================================
(http://www.letoverlambda.com/textmode.cl/guest/chap2.html#sec_4, Doug Hoyte)
1 : {togle, counterClass} = Let(
{{direction, "up"}},
toggleCounter = Function({},
SetGlobal(direction, If(direction === "up", "down", "up"))
);
counterClass = Let(
{{counter, 0}},
Function({},
SetGlobal(counter, If(direction === "up",
counter + 1,
counter + -1
))
)
);
{toggleCounter, counterClass}
)
1=> List(Function(List(), Set(direction, If(IsSame(direction, "up"), "down", "up")), StaticScope), Function(List(), If(IsSame(direction, "up"), Set(counter, Add(counter, 1)), Set(counter, Add(counter, -1))), StaticScope))
2 : counterClass()
2=> 1
3 : counterClass()
3=> 2
4 : counterClass()
4=> 3
5 : togle()
5=> "down"
6 : counterClass()
6=> 2
7 : counterClass()
7=> 1
8 : counterClass()
8=> 0
9 : counterClass()
9=> -1
10 : togle()
10=> "up"
11 : counterClass()
11=> 0
12 : counterClass()
12=> 1
Tailrecursive :
===============
1 : Import(Load(ToFileName({"Scripts", "NumberTheory.spl"})))
1=> List(GoldenRatio, Fibonacci)
2 : Timing(Fibonacci(100000);)
2=> List(1.107151985168457, Null)
Set(fib,
Function(
List(n, i, f0, f1),
If( Equal(i, n),
f0,
fib(n, Add(i, 1), f1, Add(f0, f1))
)
)
)
Set(Fibonacci,
Function(
n,
%If( And( IsInteger(n), IsPositive(n)),
If( And( IsNumberExact(n), GreaterEqual(n, 0)),
fib(n, 0, 0, 1)
,
Quote(Fibonacci)(n)
)
)
)
Load Library Functions:
=======================
/* example_dll.h
#include "uex.h"
extern ue_p pfTest(ue_p state);
*/
/* example_dll.c
#include "example_dll.h"
ue_p pfTest(const ue_p state) {
ue_p u = ue_mk_String("Hello World!");
return u;
}
*/
//gcc -c -I/home/sigint/git/splendini/uexLib -Wall -Werror -fpic example_dll.c
//gcc -shared -o libexample_dll.so example_dll.o
1 : Test = LoadLibraryFunction("pfTest", "/home/sigint/git/buildSpl/libexample_dll.so")
1=> LibraryFunction("pfTest", "/home/sigint/git/buildSpl/libexample_dll.so")
2 : Test()
2=> "Hello World!"
OptimizeExpressions:
====================
1 : Timing(Table(Add(i,1),{i,1,100000});)
1=> List(0.191010951995850, Null)
2 : oe = OptimizeExpression(Table(Add(i,1),{i,1,100000}))
2=> Table(Add(i, 1), List(i, 1, 100000))
3 : Timing(Evaluate(oe);)
3=> List(0.120177984237671, Null)
OptimizeExpression works by replacing the symbol Add with the actual
system function Add and thus save the lookup of the code in every iteration.
Memorization:
=============
1 : fib = Function(n, If(n <= 2, 1, fib(n + -1) + fib(n + -2)))
1=> InterpretedFunction(List(n), If(LessEqual(n, 2), 1, Add(fib(Add(n, -1)), fib(Add(n, -2)))), StaticScope, Frame$313)
2 : Timing(fib(24))
2=> List(0.708318948745728, 46368)
3 : Timing(fib(23))
3=> List(0.445200204849243, 28657)
4 : memo = Function(fn, Let({ht = LookupData({{},{}}, False)}, Function(key, val = LookupDataFind(ht, key); If(val=!=False, val, LookupDataAdd(ht, {key, fn(key)})))));
5 : fib = memo(fib)
5=> InterpretedFunction(List(key), Sequence(Set(val, LookupDataFind(ht, key)), If(IsNotSame(val, False), val, LookupDataAdd(ht, List(key, fn(key))))), StaticScope, Frame$316)
6 : Timing(fib(24))
6=> List(0.004889965057373, 46368)
7 : Timing(fib(23))
7=> List(0.000065088272095, 28657)
8 : memoInspect = Function(fn, Let({ht = LookupData({{},{}}, False)}, Function(key, val = LookupDataFind(ht, key); If(val=!=False, val, r = LookupDataAdd(ht, {key, fn(key)}); Print(ht);r))));
9 : fib = Function(n, If(n <= 2, 1, fib(n + -1) + fib(n + -2)))
9=> InterpretedFunction(List(n), If(LessEqual(n, 2), 1, Add(fib(Add(n, -1)), fib(Add(n, -2)))), StaticScope, Frame$318)
10 : fib = memoInspect(fib)
10=> InterpretedFunction(List(key), Sequence(Set(val, LookupDataFind(ht, key)), If(IsNotSame(val, False), val, Sequence(Sequence(Set(r, LookupDataAdd(ht, List(key, fn(key)))), Print(ht)), r))), StaticScope, Frame$320)
11 : fib(10)
LookupData(List(List(2), List(1)), False)
LookupData(List(List(2, 1), List(1, 1)), False)
LookupData(List(List(2, 1, 3), List(1, 1, 2)), False)
LookupData(List(List(2, 1, 3, 4), List(1, 1, 2, 3)), False)
LookupData(List(List(2, 1, 3, 4, 5), List(1, 1, 2, 3, 5)), False)
LookupData(List(List(2, 1, 3, 4, 5, 6), List(1, 1, 2, 3, 5, 8)), False)
LookupData(List(List(2, 1, 3, 4, 5, 6, 7), List(1, 1, 2, 3, 5, 8, 13)), False)
LookupData(List(List(2, 1, 3, 4, 5, 6, 7, 8), List(1, 1, 2, 3, 5, 8, 13, 21)), False)
LookupData(List(List(2, 1, 3, 4, 5, 6, 7, 8, 9), List(1, 1, 2, 3, 5, 8, 13, 21, 34)), False)
LookupData(List(List(2, 1, 3, 4, 5, 6, 7, 8, 9, 10), List(1, 1, 2, 3, 5, 8, 13, 21, 34, 55)), False)
11=> 55
12 : fib(9)
12=> 34
% A function that is implemented with sub functions (e.g. system Fibonacci) can only cache function calls but not self calls of internal functions.
13 : Fibonacci = memoInspect( Fibonacci)
13=> InterpretedFunction(List(key), Sequence(Set(val, LookupDataFind(ht, key)), If(IsNotSame(val, False), val, Sequence(Sequence(Set(r, LookupDataAdd(ht, List(key, fn(key)))), Print(ht)), r))), StaticScope, Frame$322)
14 : Fibonacci(10)
LookupData(List(List(10), List(55)), False)
14=> 55
15 : Fibonacci(10)
15=> 55
16 : Fibonacci(9)
LookupData(List(List(10, 9), List(55, 34)), False)
16=> 34
Macros:
========
$ Maxros do two things: 1) they transform code 2) the transformed code is evaluated.
$ Since this functionality is available already there is no special Macro command.
$ The transformation function (i.e. the macro) should have a Quote attribute.
$ When you call the tranformation function on arguments the transformed code is
$ emitted. The code then is evaluated.
1 : when = Function({test, body}, Quote(If)(test, body));
2 : AttributesAdd(when, QuoteAll);
3 : when(False, Print("Should not print"); 1)
3=> If(False, Sequence(Print("Should not print"), 1))
4 : Evaluate(when(False, Print("Should not print"); 1) )
5 : when(True, Print("Should print"); 1)
5=> If(True, Sequence(Print("Should print"), 1))
6 : Evaluate( when(True, Print("Should print"); 1) )
Should print
6=> 1
$ Second example:
1 : let = Function({bindings, body},
Quote(Apply)(
Quote(Function)(Map(Function(x, Part(x,1)), bindings), body),
Map(Function(x, Part(x,2)), bindings)
)
);
AttributesAdd(let, QuoteAll);
2 : let({{x,1},{y,1}},x+y)
2=> Apply(Function(List(x, y), Add(x, y)), List(1, 1))
3 : Evaluate(let({{x,1},{y,1}},x+y))
3=> 2
4 : {x,y}
4=> List(x, y)
5 : w = let({{b,100}}, Function(a, SetGlobal(b, a+b)))
5=> Apply(Function(List(b), Function(a, SetGlobal(b, Add(a, b)))), List(100))
6 : w = Evaluate(let({{b,100}}, Function(a, SetGlobal(b, a+b))))
6=> InterpretedFunction(List(a), SetGlobal(b, Add(a, b)), StaticScope, Frame$154)
7 : w(1)
7=> 101
8 : w(10)
8=> 111
9 : w(-100)
9=> 11
% writinng this in a set of functions:
1 : Macro = Function({macrofun}, MacroData(AttributesAdd(macrofun, QuoteAll)));
2 : MacroExpand = Function(md, Apply(md[0][1], md));
3 : MacroEvaluate = Function(md, Evaluate(MacroExpand(md)));
4 : let = Macro(
Function({bindings, body},
Quote(Apply)(
Quote(Function)(Map(Function(x, Part(x,1)), bindings), body),
Map(Function(x, Part(x,2)), bindings)
)
)
);
5 : MacroExpand(let({{x,1},{y,1}}, x+y))
5=> Apply(Function(List(x, y), Add(x, y)), List(1, 1))
6 : MacroEvaluate(let({{x,1},{y,1}}, x+y))
6=> 2
Building splendini:
--------------------
This is documented in the build.OSNAME files
Run test suite:
---------------
cmake -DCMAKE_BUILD_TYPE=Debug ../splendini/
make
make test
Code coverage (after 'make test'):
----------------------------------
ctest -D ExperimentalCoverage
for a single file (e.g.):
gcov uexLib/CMakeFiles/uexLib.dir/uex.c.o
Splint:
-------
splint -memchecks -I/usr/local/include -I./uexLib/ -I./uexLanguage/ uexLib/*.c uexLanguage/*.c main.c
valgrind:
---------
valgrind --track-origins=yes --leak-check=full --show-reachable=yes --suppressions=../splendini/boehm-gc.suppressions ./splendiniCore test.spl >& vlgTest
cat test.spl
done