Revision: 1030
http://svn.sourceforge.net/felix/?rev=1030&view=rev
Author: idadesub
Date: 2006-09-24 03:55:31 -0700 (Sun, 24 Sep 2006)
Log Message:
-----------
abstracted the whole "level_str" concept I used to do automatic
test filenaming into an easy to use module, and ported most of the
test, tutorial, and demo code over to use it
Modified Paths:
--------------
felix/trunk/lpsrc/flx_config.pak
felix/trunk/lpsrc/flx_faio.pak
felix/trunk/lpsrc/flx_gmp.pak
felix/trunk/lpsrc/flx_maker.pak
felix/trunk/lpsrc/flx_mmap.pak
felix/trunk/lpsrc/flx_pthread.pak
felix/trunk/lpsrc/flx_regress.pak
felix/trunk/lpsrc/flx_sdl.pak
felix/trunk/lpsrc/flx_tut_bind.pak
felix/trunk/lpsrc/flx_tut_macro.pak
felix/trunk/lpsrc/flx_tut_migrate.pak
felix/trunk/lpsrc/flx_tutorial.pak
felix/trunk/lpsrc/tre.pak
Property Changed:
----------------
felix/trunk/
Property changes on: felix/trunk
___________________________________________________________________
Name: svk:merge
- 5e33587e-cd95-4f00-a2a2-b2ad63d16bc2:/local/felix/trunk:1111
+ 5e33587e-cd95-4f00-a2a2-b2ad63d16bc2:/local/felix/trunk:1113
Modified: felix/trunk/lpsrc/flx_config.pak
===================================================================
--- felix/trunk/lpsrc/flx_config.pak 2006-09-24 10:53:16 UTC (rev 1029)
+++ felix/trunk/lpsrc/flx_config.pak 2006-09-24 10:55:31 UTC (rev 1030)
@@ -156,10 +156,122 @@
@include_file('flx_config_builders.ipk')
-@...")
-@...)
-#package base
+@select(tangler("flxbuild/__init__.py"))
+@doc()
+@select(tangler('flxbuild/iscrutil.py'))
+import interscript.frames.inputf
+
+class setup_test:
+ def __init__(self, root, zfill_pattern=[1], zfill_default=2):
+ self.root = root
+ self.zfill_pattern = zfill_pattern
+ self.zfill_default = 2
+
+ self.levels = []
+ self.testcount = 0
+ self.argcount = 0
+
+ self.names_written = {}
+
+
+ def head(self, level, title=None):
+ if not self.levels and level > 1:
+ self.levels = [1]
+
+ self.testcount = 0
+ self.argcount = 0
+
+ while len(self.levels) < level:
+ self.levels.append(0)
+
+ self.levels[level - 1] = self.levels[level - 1] + 1
+ self.levels = self.levels[:level]
+
+ if title is None:
+ title = self.root + self.level_str()
+
+ return head(level, title)
+
+
+ def level_str(self):
+ levels = []
+ for i in range(len(self.levels)):
+ try:
+ z = self.zfill_pattern[i]
+ except IndexError:
+ z = self.zfill_default
+
+ levels.append(string.zfill(str(self.levels[i]), z))
+
+ return string.join(levels, '.')
+
+
+ def filename(self):
+ return self.root + self.level_str()
+
+
+ def tangler(self, name,
+ extension='',
+ filetype=interscript.frames.inputf.deduce):
+
+ path = name + extension
+ if path in self.names_written:
+ print 'file:', path, 'already created!'
+
+ # XXX: NEED TO GENERATE A NEW FILE NAME
+ # XXX: what's the proper way to error out an interscript file?
+ sys.exit(1)
+
+ h = tangler(path, filetype)
+ self.names_written[path] = h
+
+ return h
+
+
+ def test(self, *args, **kwds):
+ name = '%s-%s' % (self.filename(), self.testcount)
+ self.testcount = self.testcount + 1
+
+ return apply(self.tangler, (name,) + args, kwds)
+
+
+ def expect(self):
+ name = '%s-%s' % (self.filename(), self.testcount - 1)
+
+ return self.tangler(name, '.expect', 'data')
+
+
+ def args(self, arguments):
+ name = '%s-%s-%s' % (self.filename(), self.testcount - 1, self.argcount)
+ self.argcount = self.argcount + 1
+
+ a = self.tangler(name, '.args', 'data')
+
+ select(a)
+ tangle(arguments)
+ doc()
+
+ return a
+
+
+ def test_args(self, arglist, *args, **kwds):
+ t = apply(self.test, args, kwds)
+
+ for arguments in arglist:
+ self.args(arguments)
+
+ return t
+
+
+ def expect_args(self, arguments):
+ self.args(arguments)
+
+ name = '%s-%s-%s' % (self.filename(), self.testcount - 1, self.argcount - 1)
+
+ return self.tangler(name, '.argexpect', 'data')
+@doc()
+
@h=tangler("flxbuild/flxutil.py")
@select(h)
# build system utility module
Modified: felix/trunk/lpsrc/flx_faio.pak
===================================================================
--- felix/trunk/lpsrc/flx_faio.pak 2006-09-24 10:53:16 UTC (rev 1029)
+++ felix/trunk/lpsrc/flx_faio.pak 2006-09-24 10:55:31 UTC (rev 1030)
@@ -1,9 +1,14 @@
+@execfile('config'+os.sep+'config.py')
+@execfile("flxbuild"+os.sep+"iscrutil.py")
+
+@env_faio = setup_test(os.path.join('test', 'faio', 'faio-'))
+@env_win = setup_test(os.path.join('test', 'faio', 'win-'))
+@env_posix = setup_test(os.path.join('test', 'faio', 'posix-'))
+
@head(1,"Faio")
Asynch I/O interface pack.
-@...')
-
-@... = tangler('config/faio.fpc')
+@h = tangler('config/faio.fpc', 'data')
@select(h)
Name: faio
Description: Asynchronous I/O support
@@ -44,18 +49,16 @@
"faio/faio_winio",
]
-EXTRA_TEST_GLOBS = glob.glob("test" + os.sep + "faio_*.flx")
+@tangle('EXTRA_TEST_GLOBS = glob.glob("'+env_faio.root+'*.flx")')
if WIN32:
FAIO_CPPS = FAIO_CPPS + WINDOWS_FAIO_CPPS
- EXTRA_TEST_GLOBS += glob.glob("test" + os.sep + "win_*.flx")
+@tangle(' EXTRA_TEST_GLOBS = glob.glob("'+env_win.root+'*.flx")')
if POSIX:
FAIO_CPPS = FAIO_CPPS + POSIX_FAIO_CPPS
- EXTRA_TEST_GLOBS += glob.glob("test" + os.sep + "posix_*.flx")
+@tangle(' EXTRA_TEST_GLOBS = glob.glob("'+env_posix.root+'*.flx")')
-EXTRA_TEST_GLOBS.sort()
-
cpp_cpps = FAIO_CPPS
rtl_interfaces = FAIORTL_INTERFACES
pkg_requires = ['demux','flx_pthread', 'flx_rtl'] # flx_rtl for rtl_config.
@@ -2140,8 +2143,9 @@
@head(1,"Felix Async IO tests")
-@... = tangler("test/faio_01.flx")
-@...)
+@env_faio.head(2, 'faio tests')
+@env_faio.head(3)
+@select(env_faio.test('.flx'))
// portable flx sockets test (rt = regression test)
#import <flx.flxh>
@@ -2192,9 +2196,19 @@
print "server got "; print str; endl;
flx_close(s);
+@doc()
-@... = tangler("test/posix_t1.flx")
-@...)
+@select(env_faio.expect())
+flx tcp stream test
+spawning connector
+got connection
+connector got server says hi
+server got thanks
+@doc()
+
+@env_posix.head(2, 'Posix tests')
+@env_posix.head(3)
+@select(env_posix.test('.flx'))
#import <flx.flxh>
include "flx_faio_posix";
open Faio_posix;
@@ -2221,9 +2235,17 @@
print "accepted connection\n";
System::exit 0;
} endif;
+@doc()
-@... = tangler("test/posix_t2.flx")
-@...)
+@select(env_posix.expect())
+felix posix accept/connect test
+creating listener
+spawning connector
+accepted connection
+@doc()
+
+@env_posix.head(3)
+@select(env_posix.test('.flx'))
#import <flx.flxh>
include "flx_faio_posix";
open Faio_posix;
@@ -2265,17 +2287,29 @@
async_read(s, &len, b.data, &eof);
print "acceptor read "; print len; print " bytes: "; dprint b; endl;
async_write(s, &len, get_data((c"thanks!!")), &eof);
+@doc()
-@... = tangler("test/posix_t3.flx")
-@...)
+@select(env_posix.expect())
+acceptor read 8 bytes: faio2you
+connector read thanks!!
+@doc()
+
+@env_posix.head(3)
+@select(env_posix.test('.flx'))
#include <flx.flxh>
// actually portable, but I don't know the scheme for
// adding those tests.
include "flx_stream";
print "more output here\n";
+@doc()
-@... = tangler("test/win_t1.flx")
-@...)
+@select(env_posix.expect())
+more output here
+@doc()
+
+@env_win.head(2, 'Windows tests')
+@env_win.head(3)
+@select(env_win.test('.flx'))
#import <flx.flxh>
include "flx_faio_win32";
open Faio_win32;
@@ -2306,9 +2340,15 @@
print "accept failed!\n";
System::exit 1;
} endif;
+@doc()
+@select(env_win.expect())
+spawning connector
+successful accept!
+@doc()
-@... = tangler("test/win_t2.flx")
+@env_win.head(3)
+@select(env_win.test('.flx'))
@select(h)
#import <flx.flxh>
include "Flx_faio_win32";
@@ -2487,33 +2527,9 @@
getbyte(pipe, &c);
print "server got "; print c; endl;
CloseFile(pipe);
+@doc()
-@... = tangler("test/faio_01.expect","data")
-@...)
-flx tcp stream test
-spawning connector
-got connection
-connector got server says hi
-server got thanks
-@... = tangler("test/posix_t1.expect","data")
-@...)
-felix posix accept/connect test
-creating listener
-spawning connector
-accepted connection
-@... = tangler("test/posix_t2.expect","data")
-@...)
-acceptor read 8 bytes: faio2you
-connector read thanks!!
-@... = tangler("test/posix_t3.expect","data")
-@...)
-more output here
-@... = tangler("test/win_t1.expect","data")
-@...)
-spawning connector
-successful accept!
-@... = tangler("test/win_t2.expect","data")
-@...)
+@select(env_win.expect())
Creating named pipe \\.\pipe\flx_pipe
whoo!
client opened pipe
@@ -2524,7 +2540,8 @@
server got b
@doc()
-@... = tangler("test/demo_webserver.flx")
+@head(1, 'Demos')
+@h = tangler("demos/faio/demo_webserver.flx")
@select(h)
#import <flx.flxh>
#import <flx_platform.flxh>
Modified: felix/trunk/lpsrc/flx_gmp.pak
===================================================================
--- felix/trunk/lpsrc/flx_gmp.pak 2006-09-24 10:53:16 UTC (rev 1029)
+++ felix/trunk/lpsrc/flx_gmp.pak 2006-09-24 10:55:31 UTC (rev 1030)
@@ -1,3 +1,7 @@
+@execfile("flxbuild"+os.sep+"iscrutil.py")
+
+@env = setup_test(os.path.join('test', 'gmp', 'gmp-'))
+
@head(1,'GNU Multiple Precision library')
This module provides a wrapper for the Gnu Multiple
Precision Arithmetic library known as gmp.
@@ -23,7 +27,7 @@
@select(h)
execfile('cpkgs'+os.sep+'target'+os.sep+'gmpxx.py')
if HAVE_GMPXX:
- unit_tests = ['test'+os.sep+'flx_gmp_test.flx']
+@tangle(' unit_tests = glob.glob("'+env.root+'*.flx")')
iscr_source = ['lpsrc/flx_gmp.pak']
weaver_directory = 'doc/gmp/'
@@ -110,9 +114,10 @@
fun mpq_of_int: int -> mpq = "mpq_class($1)";
fun mpf_of_double: double -> mpf = "mpf_class($1)";
}
+@doc()
-@... = tangler('test/flx_gmp_test.flx')
-@...)
+@env.head(1,'gmp tests')
+@select(env.test('.flx'))
#import <flx.flxh>
include "flx_gmp";
open Gmp;
@@ -172,9 +177,9 @@
print$ x > y; endl;
print$ x >= y; endl;
};
+@doc()
-@... = tangler('test/flx_gmp_test.expect')
-@...)
+@select(env.expect())
99
7
106
@@ -216,4 +221,4 @@
false
true
true
-@#
+@doc()
Modified: felix/trunk/lpsrc/flx_maker.pak
===================================================================
--- felix/trunk/lpsrc/flx_maker.pak 2006-09-24 10:53:16 UTC (rev 1029)
+++ felix/trunk/lpsrc/flx_maker.pak 2006-09-24 10:55:31 UTC (rev 1030)
@@ -1537,46 +1537,43 @@
log.write('EXECUTING TEST CODE %s\n' % testscript, quiet)
flush()
- arguments = []
- if os.path.exists(basename + '.arguments'):
- f = open(basename + '.arguments')
+ # FIXME
+ argfiles = glob.glob(basename + '*.args')
+
+ if not argfiles:
+ output = vxqt(ENV + testscript, verbose=1, log=log)
+
+ f = open(basename + '.output', 'w')
try:
- for line in f.readlines():
- arguments.append(string.strip(line))
+ f.write(string.join(output, ""))
finally:
f.close()
- if arguments:
- count = 0
- for args in arguments:
+ if deterministic:
+ output = vxqt('%s %s.expect %s.output' % (DIFF, basename, basename),
+ verbose=1, log=log)
+
+ else:
+ for argcount, argfile in zip(range(len(argfiles)), argfiles):
+ # read the arguments fromm the file
+ f = open(argfile)
+ try:
+ args = string.strip(f.read())
+ finally:
+ f.close()
+
output = vxqt(ENV + testscript + ' ' + args, verbose=1, log=log)
- f = open(basename + '.args' + str(count) + '.output', 'w')
+ f = open('%s-%s.argoutput' % (basename, argcount), 'w')
try:
f.write(string.join(output, ""))
finally:
f.close()
- count = count + 1
- else:
- output = vxqt(ENV + testscript, verbose=1, log=log)
- f = open(basename + '.output', 'w')
- try:
- f.write(string.join(output, ""))
- finally:
- f.close()
-
- if deterministic:
- if not arguments:
- output = vxqt('%s %s.expect %s.output' % (DIFF, basename, basename),
- verbose=1, log=log)
- else:
- count = 0
- for args in arguments:
- output = vxqtq('%s %s.args%s.expect %s.args%s.output' % \
- (DIFF, basename, count, basename, count),
+ if deterministic:
+ output = vxqtq('%s %s-%s.argexpect %s-%s.argoutput' % \
+ (DIFF, basename, argcount, basename, argcount),
verbose=1, log=log)
- count = count + 1
@select(tangler('mkplugins/help.py'))
Modified: felix/trunk/lpsrc/flx_mmap.pak
===================================================================
--- felix/trunk/lpsrc/flx_mmap.pak 2006-09-24 10:53:16 UTC (rev 1029)
+++ felix/trunk/lpsrc/flx_mmap.pak 2006-09-24 10:55:31 UTC (rev 1030)
@@ -1,3 +1,8 @@
+@execfile("config"+os.sep+"target_cxx.py")
+@execfile("flxbuild"+os.sep+"iscrutil.py")
+
+@env = setup_test(os.path.join('test', 'mmap', 'mmap-'))
+
@head(1,"Address space management")
@select(tangler('spkgs/mmap.py'))
@@ -2,3 +7,3 @@
if HAVE_MMAP:
- unit_tests = ['test'+os.sep+'flx_mmap_test.flx']
+@tangle(' unit_tests = glob.glob("'+env.root+'*.flx")')
@@ -64,7 +69,8 @@
fun munmap: address * size -> int;
}
-@..."))
+@env.head(1, 'mmap tests')
+@select(env.test('.flx'))
#import <flx.flxh>
include "mmap";
open Mmap;
@@ -94,7 +100,7 @@
done;
@doc()
-@..."))
+@select(env.expect())
mmap worked!
@doc()
Modified: felix/trunk/lpsrc/flx_pthread.pak
===================================================================
--- felix/trunk/lpsrc/flx_pthread.pak 2006-09-24 10:53:16 UTC (rev 1029)
+++ felix/trunk/lpsrc/flx_pthread.pak 2006-09-24 10:55:31 UTC (rev 1030)
@@ -1,3 +1,7 @@
+@execfile("flxbuild"+os.sep+"iscrutil.py")
+
+@env = setup_test(os.path.join('test', 'pthread', 'pthread-'))
+
@head(1,'pthread')
@execfile('config'+os.sep+'config.py')
@@ -83,6 +87,8 @@
PTHREAD_CPPS = PTHREAD_CPPS + SOLARIS_PTHREAD_CPPS
EXTRA_SYS_LIBS = "-lrt " # man sem_wait
+@tangle('completion_tests = glob.glob("'+env.root+'*.flx")')
+
cpp_cpps = PTHREAD_CPPS
rtl_interfaces = PTHREADRTL_INTERFACES
lib_requires = ['libflx_gc']
@@ -1446,8 +1452,9 @@
}
}
-@...')
-@...)
+@env.head(1,'pthread tests')
+@env.head(2)
+@select(env.test('.flx'))
#import <flx.flxh>
include "flx_faio";
include "pthread";
@@ -1489,9 +1496,10 @@
}
export proc flx_main of (1) as "flx_main";
+@doc()
-@...')
-@...)
+@env.head(2)
+@select(env.test('.flx'))
#import <flx.flxh>
include "pthread";
include "flx_faio";
@@ -1524,3 +1532,4 @@
Pthread::spawn_pthread { randprint(5); };
print "Mainline done!"; endl;
+@doc()
Modified: felix/trunk/lpsrc/flx_regress.pak
===================================================================
--- felix/trunk/lpsrc/flx_regress.pak 2006-09-24 10:53:16 UTC (rev 1029)
+++ felix/trunk/lpsrc/flx_regress.pak 2006-09-24 10:55:31 UTC (rev 1030)
@@ -1,24 +1,19 @@
+@set_title('Regression Tests')
+
@import glob
-@... Tests')
@execfile("config"+os.sep+"config.py")
-@... = 'test'+os.sep+'regress'+os.sep
+@execfile("flxbuild"+os.sep+"iscrutil.py")
-@... = []
-@... = ''
-@... flx_regress_head(level, name):
- global flx_regress_levels,flx_regress_level_str
- while len(flx_regress_levels) < level: flx_regress_levels.append(0)
- flx_regress_levels[level - 1] = int(flx_regress_levels[level - 1]) + 1
- flx_regress_levels = flx_regress_levels[:level]
+@env_rt = setup_test(os.path.join('test', 'regress', 'rt-'))
+@env_srt = setup_test(os.path.join('test', 'regress', 'srt-'))
+@env_drt = setup_test(os.path.join('test', 'regress', 'drt-'))
+@env_pt = setup_test(os.path.join('test', 'regress', 'pt-'))
+@env_nd = setup_test(os.path.join('test', 'regress', 'nd-'))
+@env_bt = setup_test(os.path.join('test', 'regress', 'bt-'))
+@env_kf = setup_test(os.path.join('test', 'regress', 'kf-'))
+@env_wt = setup_test(os.path.join('test', 'regress', 'wt-'))
- for i in range(len(flx_regress_levels)):
- flx_regress_levels[i] = string.zfill(str(flx_regress_levels[i]), 2)
-
- flx_regress_level_str = string.join(flx_regress_levels,'.')
-
- return head(level, name)
-
@def kat(code):
tangle("//Check " + code)
f = get_tangler().sink.filename
@@ -51,7 +46,7 @@
execfile(katfile)
except: pass
-@... tests')
+@head(1,'Regression tests')
There are four kinds of test. The compiler
must be run with standard output redirected
to /dev/null. All these tests use the standard
@@ -75,7 +70,7 @@
Performance tests measure speed. The result
is an overall time in seconds, which should
get smaller with each compiler improvement.
-@...')
+@item('nd')
Tests with non-deterministic results. Output
is printed, not compared with expected output.
@item('kf')
@@ -94,7 +89,7 @@
@emit_katlist()
@select(tangler('spkgs/flx_regression_tests_rt.py'))
-@... = glob.glob('"+tdir+"rt-*.flx')")
+@tangle("unit_tests = glob.glob('"+env_rt.root+"*.flx')")
pkg_requires = ['flx_compiler','flx_drivers']
iscr_source = ['lpsrc/flx_regress.pak']
@@ -103,8 +98,18 @@
@doc()
+@select(tangler('spkgs/flx_regression_tests_srt.py'))
+@tangle("static_unit_tests = glob.glob('"+env_srt.root+"*.flx')")
+
+pkg_requires = ['flx_compiler','flx_drivers','flx_regression_tests_rt']
+iscr_source = ['lpsrc/flx_regress.pak']
+
+weaver_directory = 'doc/test/'
+@doc()
+
+
@select(tangler('spkgs/flx_regression_tests_drt.py'))
-@... = glob.glob('"+tdir+"drt-*.flx')")
+@tangle("dynamic_unit_tests = glob.glob('"+env_drt.root+"*.flx')")
pkg_requires = ['flx_compiler','flx_drivers','flx_regression_tests_rt']
iscr_source = ['lpsrc/flx_regress.pak']
@@ -114,7 +119,7 @@
@select(tangler('spkgs/flx_regression_tests_nd.py'))
-@... = glob.glob('"+tdir+"nd-*.flx')")
+@tangle("completion_tets = glob.glob('"+env_nd.root+"*.flx')")
pkg_requires = ['flx_compiler','flx_drivers']
iscr_source = ['lpsrc/flx_regress.pak']
@@ -123,9 +128,19 @@
@doc()
+@select(tangler('spkgs/flx_regression_tests_pt.py'))
+@tangle("perform_tets = glob.glob('"+env_pt.root+"*.flx')")
+
+pkg_requires = ['flx_compiler','flx_drivers']
+iscr_source = ['lpsrc/flx_regress.pak']
+
+weaver_directory = 'doc/test/'
+@doc()
+
+
@select(tangler('spkgs/flx_regression_tests_bt.py'))
# these are supposed to fail!
-@... = glob.glob('"+tdir+"bt-*.flx')")
+@tangle("failure_tests = glob.glob('"+env_bt.root+"*.flx')")
pkg_requires = ['flx_compiler','flx_drivers']
iscr_source = ['lpsrc/flx_regress.pak']
@@ -135,7 +150,7 @@
@select(tangler('spkgs/flx_regression_tests_kf.py'))
# these are supposed to fail!
-@... = glob.glob('"+tdir+"kf-*.flx')")
+@tangle("known_failed_tests = glob.glob('"+env_kf.root+"*.flx')")
pkg_requires = ['flx_compiler','flx_drivers']
iscr_source = ['lpsrc/flx_regress.pak']
@@ -155,10 +170,11 @@
@doc()
-@... tests')
+@env_rt.head(2,'Good tests')
-@...")
-@...'))
+@env_rt.head(3)
+@rt_test1 = env_rt.test('.flx')
+@select(rt_test1)
@kat("integer math")
#import <flx.flxh>
open Tiny;
@@ -217,12 +233,14 @@
print "test complete"; endl;
@doc()
-@..."))
+@rt_expect1 = env_rt.expect()
+@select(rt_expect1)
test complete
@doc()
-@...")
-@...'))
+@env_rt.head(3)
+@rt_test2 = env_rt.test('.flx')
+@select(rt_test2)
@kat("closures")
@kat("recursion")
header r"""
@@ -299,15 +317,16 @@
}
@doc()
-@..."))
+@rt_expect2 = env_rt.expect()
+@select(rt_expect2)
10
10x=1, y=2
Not hidden: int=1 print:int hides outer
module A print int=1
@doc()
-@...")
-@...'))
+@env_rt.head(3)
+@select(env_rt.test('.flx'))
@kat("laziness")
#import <flx.flxh>
// test lazy functions and procedures
@@ -320,14 +339,14 @@
print (f ()); print "\n";
@doc()
-@..."))
+@select(env_rt.expect())
lazy expr eval test
3
5
@doc()
-@...")
-@...'))
+@env_rt.head(3)
+@select(env_rt.test('.flx'))
@kat("strings")
// test the string library
#import <flx.flxh>
@@ -357,7 +376,7 @@
endl;
@doc()
-@..."))
+@select(env_rt.expect())
Hello+World
ello+
Hello+
@@ -367,18 +386,18 @@
dlroW+olleH
@doc()
-@...")
-@...'))
+@env_rt.head(3)
+@select(env_rt.test('.flx'))
// test the chained comparison
#import <flx.flxh>
assert(1<2&<3&<4);
@doc()
-@..."))
+@select(env_rt.expect())
@doc()
-@...")
-@...'))
+@env_rt.head(3)
+@select(env_rt.test('.flx'))
@kat("recursive types")
fun land: 2 * 2 -> 2 = "$1 && $2";
type int = "int";
@@ -422,7 +441,7 @@
print (if 1==0 then "true" else "false" endif); eol;
@doc()
-@..."))
+@select(env_rt.expect())
1
1
25
@@ -433,8 +452,8 @@
false
@doc()
-@...")
-@...'))
+@env_rt.head(3)
+@select(env_rt.test('.flx'))
@kat("closures")
#import <flx.flxh>
// closure formation test
@@ -487,7 +506,7 @@
xprint (exec3(B of (int), 1)); endl;
@doc()
-@..."))
+@select(env_rt.expect())
closure of add primitive 4
struct X
struct X
@@ -498,8 +517,8 @@
union U
@doc()
-@...")
-@...'))
+@env_rt.head(3)
+@select(env_rt.test('.flx'))
@kat("insertions")
// code insertion
body "#include <iostream>";
@@ -511,14 +530,14 @@
print (two());
@doc()
-@..."))
+@select(env_rt.expect())
2
@doc()
-@...")
+@env_rt.head(3)
multiple assignment
-@...'))
+@select(env_rt.test('.flx'))
@kat("def statement")
#import <flx.flxh>
var a:int;
@@ -544,13 +563,13 @@
endl;
@doc()
-@..."))
+@select(env_rt.expect())
1 2 3
9 8 7
@doc()
-@...")
-@...'))
+@env_rt.head(3)
+@select(env_rt.test('.flx'))
@kat("type operator")
#import <flx.flxh>
open Long;
@@ -582,17 +601,17 @@
print two; endl;
@doc()
-@..."))
+@select(env_rt.expect())
1 2
1 2 3 4
1
1
@doc()
-@...")
+@env_rt.head(3)
generics inlining/call lifting tests
-@...'))
+@select(env_rt.test('.flx'))
@kat("polymorphism")
#import <flx.flxh>
@@ -608,13 +627,13 @@
f[int] (1, the pr);
@doc()
-@..."))
+@select(env_rt.expect())
1
@doc()
-@...")
+@env_rt.head(3)
call inlining
-@...'))
+@select(env_rt.test('.flx'))
@kat("inlining")
#import <flx.flxh>
proc g[t]()
@@ -658,7 +677,7 @@
f[int]();
@doc()
-@..."))
+@select(env_rt.expect())
ONE
TWO
THREE
@@ -679,10 +698,10 @@
EIGHTTEEN
@doc()
-@...")
+@env_rt.head(3)
call inlining
-@...'))
+@select(env_rt.test('.flx'))
@kat("inlining")
#import <flx.flxh>
@@ -703,14 +722,14 @@
;
@doc()
-@..."))
+@select(env_rt.expect())
ONE
@doc()
-@...")
+@env_rt.head(3)
more generic stuff
-@...'))
+@select(env_rt.test('.flx'))
@kat("polymorphism")
#import <flx.flxh>
open List;
@@ -752,7 +771,7 @@
;
@doc()
-@..."))
+@select(env_rt.expect())
0 -> 66
1 -> 55
2 -> 44
@@ -761,8 +780,8 @@
5 -> 11
@doc()
-@...")
-@...'))
+@env_rt.head(3)
+@select(env_rt.test('.flx'))
@kat("recursion")
@kat("tail call optimisation")
#import <flx.flxh>
@@ -780,17 +799,17 @@
recur();
@doc()
-@..."))
+@select(env_rt.expect())
4
3
2
1
@doc()
-@...")
+@env_rt.head(3)
non-self-tail rec test (inspect output) (requires --inline atm)
-@...'))
+@select(env_rt.test('.flx'))
@kat("recursion")
@kat("tail call optimisation")
#import <flx.flxh>
@@ -808,17 +827,17 @@
recur2();
@doc()
-@..."))
+@select(env_rt.expect())
4
3
2
1
@doc()
-@...")
+@env_rt.head(3)
self-tail rec test (inspect output) (requires --inline atm)
-@...'))
+@select(env_rt.test('.flx'))
@kat("recursion")
@kat("tail call optimisation")
#import <flx.flxh>
@@ -832,12 +851,12 @@
print (g 10); endl;
@doc()
-@..."))
+@select(env_rt.expect())
1
@doc()
-@...")
-@...'))
+@env_rt.head(3)
+@select(env_rt.test('.flx'))
@kat("recursion")
@kat("tail call optimisation")
#import <flx.flxh>
@@ -853,12 +872,12 @@
print (f 10); endl;
@doc()
-@..."))
+@select(env_rt.expect())
1
@doc()
-@...")
-@...'))
+@env_rt.head(3)
+@select(env_rt.test('.flx'))
@kat("lvalues")
// lvalue decay if function called thru variable
#import <flx.flxh>
@@ -868,11 +887,11 @@
f g of (int);
@doc()
-@..."))
+@select(env_rt.expect())
@doc()
-@...")
-@...'))
+@env_rt.head(3)
+@select(env_rt.test('.flx'))
@kat("regmatch")
// contrib by Valery, mod by Skaller
#import <flx.flxh>
@@ -898,18 +917,18 @@
done;
@doc()
-@..."))
+@select(env_rt.expect())
checking arg 0=--test
test
checking arg 1=words
terminating
@doc()
-@...")
+@env_rt.head(3)
Warning: result is dependent on implementation
detail (order of execution after read/write matchup)
-@...'))
+@select(env_rt.test('.flx'))
@kat("fibres")
@kat("channels")
#import <flx.flxh>
@@ -938,7 +957,7 @@
print "Done"; endl;
@doc()
-@..."))
+@select(env_rt.expect())
Hello
Done
W1
@@ -947,7 +966,7 @@
W2
@doc()
-@...'))
+@select(env_rt.test('.flx'))
@kat("fibres")
@kat("channels")
#import <flx.flxh>
@@ -971,7 +990,7 @@
};
@doc()
-@...'))
+@select(env_rt.expect())
1
2
3
@@ -984,8 +1003,8 @@
10
@doc()
-@...")
-@...'))
+@env_rt.head(3)
+@select(env_rt.test('.flx'))
@kat("type constraints")
#import <flx.flxh>
open C_hack;
@@ -1005,13 +1024,13 @@
@doc()
-@..."))
+@select(env_rt.expect())
3
999
@doc()
-@...")
-@...'))
+@env_rt.head(3)
+@select(env_rt.test('.flx'))
@kat("type constraints")
#import <flx.flxh>
open C_hack;
@@ -1034,13 +1053,13 @@
k px;
@doc()
-@..."))
+@select(env_rt.expect())
3
1
@doc()
-@...")
-@...'))
+@env_rt.head(3)
+@select(env_rt.test('.flx'))
@kat("type constraints")
#import <flx.flxh>
open C_hack;
@@ -1076,9 +1095,9 @@
pr$ ff$ 1,2;
//pr$ ff$ 1,2.0; // should fail
+@doc()
-@...()
-@..."))
+@select(env_rt.expect())
1,1
1,1
1
@@ -1088,8 +1107,8 @@
3
@doc()
-@...")
-@...'))
+@env_rt.head(3)
+@select(env_rt.test('.flx'))
@kat("reductions")
@kat("axioms")
#import <flx.flxh>
@@ -1127,13 +1146,13 @@
axiom_check (add of (int * int), eq of (int * int), 1,2);
@doc()
-@..."))
+@select(env_rt.expect())
Cheat
1
@doc()
-@...")
-@...'))
+@env_rt.head(3)
+@select(env_rt.test('.flx'))
@kat("member count")
#import <flx.flxh>
// HACK!
@@ -1150,14 +1169,14 @@
f2 x;
@doc()
-@..."))
+@select(env_rt.expect())
22
42
42
@doc()
-@...')
-@...'))
+@env_rt.head(3)
+@select(env_rt.test('.flx'))
@kat("arrays")
@kat("array iterators")
#import <flx.flxh>
@@ -1177,7 +1196,7 @@
iter (the foo) y;
iter (the foo) z;
-@..."))
+@select(env_rt.expect())
1
2
3
@@ -1189,8 +1208,8 @@
6
@doc()
-@...')
-@...'))
+@env_rt.head(3)
+@select(env_rt.test('.flx'))
#import <flx.flxh>
var z = 0;
noinline proc f
@@ -1203,12 +1222,12 @@
print z; endl;
@doc()
-@...'))
+@select(env_rt.expect())
3
@doc()
-@...')
-@...'))
+@env_rt.head(3)
+@select(env_rt.test('.flx'))
#import <flx.flxh>
union U =
@@ -1229,12 +1248,12 @@
p0$ A the p1;
-@...'))
+@select(env_rt.expect())
hello
@doc()
-@...')
-@...'))
+@env_rt.head(3)
+@select(env_rt.test('.flx'))
@kat("laziness")
@kat("lazy variables")
#include <flx.flxh>
@@ -1249,13 +1268,13 @@
print$ x; endl;
@doc()
-@...'))
+@select(env_rt.expect())
1
2
@doc()
-@...')
-@...'))
+@env_rt.head(3)
+@select(env_rt.test('.flx'))
@kat("ref semantics")
#include <flx.flxh>
@@ -1336,7 +1355,7 @@
k { a +1 };
@doc()
-@...'))
+@select(env_rt.expect())
3
4
1
@@ -1365,8 +1384,8 @@
71
@doc()
-@...')
-@...'))
+@env_rt.head(3)
+@select(env_rt.test('.flx'))
@kat("lexing keywords")
#import <flx.flxh>
#
@@ -1379,12 +1398,12 @@
print$ X::f 22; endl;
@doc()
-@...'))
+@select(env_rt.expect())
44
@doc()
-@...')
-@...'))
+@env_rt.head(3)
+@select(env_rt.test('.flx'))
@kat("translation of typedefs to _ctor_name calls")
#import <flx.flxh>
@@ -1403,14 +1422,14 @@
print z; endl;
@doc()
-@...'))
+@select(env_rt.expect())
5
5
5
@doc()
-@...')
-@...'))
+@env_rt.head(3)
+@select(env_rt.test('.flx'))
@kat("generators")
#import <flx.flxh>
@@ -1445,7 +1464,7 @@
print "C 4="; print$ g(); endl; // 4
@doc()
-@...'))
+@select(env_rt.expect())
F 1=1
C 1=1
F Even? 4
@@ -1456,8 +1475,8 @@
C 4=4
@doc()
-@...')
-@...'))
+@env_rt.head(3)
+@select(env_rt.test('.flx'))
@kat("generators")
#import <flx.flxh>
@@ -1480,7 +1499,7 @@
print$ x(10); endl; // 64
@doc()
-@...'))
+@select(env_rt.expect())
42
43
44
@@ -1490,8 +1509,8 @@
64
@doc()
-@...")
-@...'))
+@env_rt.head(3)
+@select(env_rt.test('.flx'))
@kat("generators")
#import <flx.flxh>
@@ -1576,7 +1595,7 @@
print$ res; endl;
@doc()
-@...'))
+@select(env_rt.expect())
15
visiting node: left
visiting node: left
@@ -1594,8 +1613,8 @@
15
@doc()
-@...")
-@...'))
+@env_rt.head(3)
+@select(env_rt.test('.flx'))
#import <flx.flxh>
module Foo
@@ -1614,12 +1633,12 @@
endl;
@doc()
-@...'))
+@select(env_rt.expect())
a
@doc()
-@...")
-@...'))
+@env_rt.head(3)
+@select(env_rt.test('.flx'))
@kat("comments")
#import <flx.flxh>
@@ -1672,7 +1691,7 @@
*/ "12"; endl;
@doc()
-@...'))
+@select(env_rt.expect())
1
2
3
@@ -1687,9 +1706,9 @@
12
@doc()
-@...")
+@env_rt.head(3)
test argument handling
-@...'))
+@select(env_rt.test('.flx'))
#import <flx.flxh>
open List;
@@ -1702,57 +1721,59 @@
;
@doc()
-@...'))
-a b c
-e f g
+@select(env_rt.expect())
@doc()
-@...'))
+@select(env_rt.expect_args('a b c'))
a
b
c
@doc()
-@...'))
+@select(env_rt.expect_args('e f g'))
e
f
g
@doc()
-@... good tests")
-@...")
+@env_srt.head(2,"Static good tests")
+
+@env_drt.head(2,"Dynamic good tests")
+@env_drt.head(3)
// plugin loader test
-@...'))
+
+@select(env_drt.test('.flx'))
#import <flx.flxh>
print "Starting .. "; endl;
-@...+'");')
-@...+'");')
+@tangle('Dynlink::run_lib("./' + \
+ os.path.splitext(rt_test1.sink.name)[0] + \
+ EXT_SHLIB + '");')
+@tangle('Dynlink::run_lib("./' + \
+ os.path.splitext(rt_test2.sink.name)[0] + \
+ EXT_SHLIB + '");')
print "Its run"; endl;
@doc()
-@...', 'data'))
-Starting ..
-test complete
-10
-10x=1, y=2
-Not hidden: int=1 print:int hides outer
-module A print int=1
-Its run
+@select(env_drt.expect())
+Starting ..
+@tangle(open(rt_expect1.sink.name).read()[:-1])
+@tangle(open(rt_expect2.sink.name).read()[:-1])
+Its run
@doc()
-@... tests')
+@env_bt.head(2,'Bad tests')
All these should fail gracefully at (felix) compile time.
Run the compiler with the -e option to invert
the return code parity.
-@...")
-@...'))
+@env_bt.head(3)
+@select(env_bt.test('.flx'))
basic parser error
@doc()
-@...")
-@...'))
+@env_bt.head(3)
+@select(env_bt.test('.flx'))
module X { proc p(){} }
module Y { proc p(){} }
open X;
@@ -1760,8 +1781,8 @@
p; // ambiguous
@doc()
-@...")
-@...'))
+@env_bt.head(3)
+@select(env_bt.test('.flx'))
// open depends on self
#import <flx.flxh>
interface I { proc print_endl:int; }
@@ -1774,23 +1795,23 @@
print_endl 1;
@doc()
-@...")
-@...'))
+@env_bt.head(3)
+@select(env_bt.test('.flx'))
#import <flx.flxh>
// these now fail OK: (should yield 'any' .. then fail overload :-)
val aa = bb + 1;
val bb = aa + 1;
@doc()
-@...")
-@...'))
+@env_bt.head(3)
+@select(env_bt.test('.flx'))
// impossible recursion
type int = "int";
fun neg(a:int) = { return -a; }
@doc()
-@...")
-@...'))
+@env_bt.head(3)
+@select(env_bt.test('.flx'))
// privacy violation
#import <flx.flxh>
@@ -1803,24 +1824,24 @@
val x = f 1;
@doc()
-@...")
-@...'))
+@env_bt.head(3)
+@select(env_bt.test('.flx'))
#define FIRST
#define FIRST
@doc()
-@...")
-@...'))
+@env_bt.head(3)
+@select(tangler(env_bt.filename() + '.imp', 'flx'))
#define FIRST
@doc()
-@...'))
+@select(env_bt.test('.flx'))
#define FIRST
-@... "bt-'+flx_regress_level_str+'.imp"')
+@tangle('#import "'+env_bt.filename() + '.imp"')
@doc()
-@...")
-@...'))
+@env_bt.head(3)
+@select(env_bt.test('.flx'))
// this should give an error at felix time
// but we only get one at C++ compile time
@@ -1841,8 +1862,8 @@
;
@doc()
-@...")
-@...'))
+@env_bt.head(3)
+@select(env_bt.test('.flx'))
// function drops off end
#import <flx.flxh>
fun f(x:int):int =
@@ -1852,12 +1873,12 @@
print (f 1); endl;
@doc()
-@... tests')
+@env_kf.head(2,'Known failure tests')
All these should successfully compile, but currently fail
or enter into an infinite loop.
-@...')
-@...'))
+@env_kf.head(3)
+@select(env_kf.test('.flx'))
#import <flx.flxh>
proc foo(x, y:int)
@@ -1872,15 +1893,15 @@
foo 0;
@doc()
-@... tests')
+@env_wt.head(2,'Wish tests')
Tests that suggest a possible language changes that
are not currently implemented. They may or may not
be added to some future version of the compiler, so
they are not currently checked.
-@...")
-@...'))
+@env_wt.head(3)
+@select(env_wt.test('.flx'))
#import <flx.flxh>
if (len s > 3) do
Modified: felix/trunk/lpsrc/flx_sdl.pak
===================================================================
--- felix/trunk/lpsrc/flx_sdl.pak 2006-09-24 10:53:16 UTC (rev 1029)
+++ felix/trunk/lpsrc/flx_sdl.pak 2006-09-24 10:55:31 UTC (rev 1030)
@@ -1,5 +1,10 @@
@set_title('SDL')
+@execfile('config'+os.sep+'config.py')
+@execfile("flxbuild"+os.sep+"iscrutil.py")
+
+@env = setup_test(os.path.join('demos', 'sdl', 'sdl-'))
+
@head(1,'SDL')
@head(2,'SDL configuration')
@@ -2576,7 +2581,7 @@
}
@doc()
-@..."))
+@h = tangler("rtl/flx_sdl_config.hpp")
#ifndef __FLX_SDL_CONFIG_GUARD__
#define __FLX_SDL_CONFIG_GUARD__
#include "flx_rtl_config.hpp"
@@ -2702,7 +2707,9 @@
}
@doc()
-@..."))
+@env.head(2,'SDL tutorial')
+@env.head(3)
+@select(env.test('.flx'))
#import <flx.flxh>
include "SDL/SDL";
include "SDL/SDL_video";
@@ -3021,7 +3028,8 @@
}
@doc()
-@..."))
+@env.head(3)
+@select(env.test('.flx'))
// REQUIRES OpenGL and GLU
/*
* This code was created by Jeff Molofee '99
@@ -3408,7 +3416,8 @@
}
@doc()
-@..."))
+@env.head(3)
+@select(env.test('.flx'))
// REQUIRES OpenGL and GLU
/*
* This code was created by Jeff Molofee '99
@@ -3871,7 +3880,8 @@
}
@doc()
-@..."))
+@env.head(3)
+@select(env.test('.flx'))
// REQUIRES OpenGL and GLU
/*
* This code was created by Jeff Molofee '99
@@ -4369,7 +4379,8 @@
}
@doc()
-@..."))
+@env.head(3)
+@select(env.test('.flx'))
// REQUIRES OpenGL and GLU
/*
* This code was created by Jeff Molofee '99
@@ -4985,8 +4996,10 @@
SDL_GL_SwapBuffers( );
}
+@doc()
-@..."))
+@env.head(3)
+@select(env.test('.flx'))
// REQUIRES OpenGL and GLU
/*
* This code was created by Jeff Molofee '99
Modified: felix/trunk/lpsrc/flx_tut_bind.pak
===================================================================
--- felix/trunk/lpsrc/flx_tut_bind.pak 2006-09-24 10:53:16 UTC (rev 1029)
+++ felix/trunk/lpsrc/flx_tut_bind.pak 2006-09-24 10:55:31 UTC (rev 1030)
@@ -1,23 +1,11 @@
@set_title('Felix Tutorial: Embedding')
-@... = 'tut'+os.sep+'embedding'+os.sep
-@... = []
-@... = ''
-@... flx_tut_bind_head(level, name):
- global flx_tut_bind_levels,flx_tut_bind_level_str
- while len(flx_tut_bind_levels) < level: flx_tut_bind_levels.append(0)
- flx_tut_bind_levels[level - 1] = int(flx_tut_bind_levels[level - 1]) + 1
- flx_tut_bind_levels = flx_tut_bind_levels[:level]
+@execfile("flxbuild"+os.sep+"iscrutil.py")
- for i in range(len(flx_tut_bind_levels)):
- flx_tut_bind_levels[i] = string.zfill(flx_tut_bind_levels[i], 2)
+@env = setup_test(os.path.join('tut', 'embedding', 'bind-'))
- flx_tut_bind_level_str = string.join(flx_tut_bind_levels,'.')
-
- return head(level, name)
-
@select(tangler('spkgs/flx_tut_bind.py'))
-@... = glob.glob("'+tdir+'*.flx")')
+@tangle('TESTS = glob.glob("'+env.root+'*.flx")')
unit_tests = TESTS
pkg_requires = ['flx_compiler','flx_drivers','flx_rtl','faio']
@@ -25,10 +13,10 @@
weaver_directory = 'doc/tutorial/embedding/'
@doc()
-@...')
+@head(1,'Embedding')
Felix is designed to integrate smoothly with C and C++.
-@... Bindings')
+@env.head(2,'Basic Bindings')
In the previous examples, we've use the Felix standard
library. It's time to look at how it works.
@p()
@@ -40,7 +28,7 @@
@p()
Here is an example of a binding.
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
header """
// This is C++ code!
@@ -104,7 +92,7 @@
print n; endl;
@doc()
-@..."))
+@select(env.expect())
(1, 2)
(2, 4)
(-12, 16)
@@ -176,13 +164,13 @@
a ; inside the string, as well as after it.
You can use a compound statement as well.
-@... Binding')
+@env.head(2,'Seamless Binding')
Felix purports to support a property called seamless binding.
What this means is that the boundary between C++ and Felix
code is fluid. To illustrate this, lets consider
a version of the above code written entirely in Felix.
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
struct gauss = {
x : int;
@@ -235,7 +223,7 @@
print n; endl;
@doc()
-@..."))
+@select(env.expect())
(1, 2)
(2, 4)
(4, 16)
@@ -262,13 +250,13 @@
an existing code base containing useful types
you need to work with.
-@... Shortcuts')
+@env.head(2,'Binding Shortcuts')
For your convenience, the ctypes declaration
allows multiple type bindings to be defined
at once. Each Felix name must also be a c identifier
representing a type in C.
-@...'))
+@select(env.test('.flx'))
header "#include <cstdio>";
ctypes int, long;
proc print:int = 'printf("%d\\n",$1);';
@@ -276,12 +264,12 @@
print 2;
@doc()
-@..."))
+@select(env.expect())
1
2
@doc()
-@... C++')
+@env.head(2,'Embedding C++')
We have seen that we can use binding definitions to
embed C++ constants, expressions, and procedures
into Felix code, and we can use the
@@ -314,7 +302,7 @@
in the place it is written.
For example:
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
header "#include<stdio.h>";
print 1; endl;
@@ -322,13 +310,13 @@
print 3; endl;
@doc()
-@..."))
+@select(env.expect())
1
2
3
@doc()
-@... dot')
+@env.head(2,'Operator dot')
For primitive types, x.name is converted to
@begin_displayed_code()
get_name x
@@ -337,7 +325,7 @@
using the dot notation provided you supply
appropriate projection functions.
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
// part 1
@@ -377,7 +365,7 @@
*/
@doc()
-@..."))
+@select(env.expect())
1, 2
@doc()
@@ -408,7 +396,7 @@
[The C++ name of the struct type is not the same
as the Felix name]
-@... primitive bindings')
+@env.head(2,'Generic primitive bindings')
Felix provides a way of creating generic primitive bindings.
A generic binding is a binding to a family of C++ types,
functions, or procedured, parameterised by one or more
@@ -419,7 +407,7 @@
Here is a simple example illustrating
generic primitive bindings.
-@...'))
+@select(env.test('.flx'))
// include STL vector template
header """
@@ -487,12 +475,12 @@
vprint[int] v; endl();
@doc()
-@..."))
+@select(env.expect())
1
1 2 3
@doc()
-@... and body tags')
+@env.head(2,'Header and body tags')
Header and body statements may include tag names
which can be refered to in requires clauses of
binding definitions.
@@ -520,7 +508,7 @@
The same tag can be used on more than one code insertion
statements: this is typically useful on a header-body pair.
-@...'))
+@select(env.test('.flx'))
body "#include <stdio.h>";
body xprint = "void printx(char *fmt, char *s) { printf(fmt,s);}";
body printu = 'void print(char *s) { printx("%s\\n",s); }';
@@ -529,14 +517,14 @@
hello;
@doc()
-@..."))
+@select(env.expect())
Hello
@doc()
Header and body statements can also have requirements.
We can reorganise the previous example using this fact.
-@...'))
+@select(env.test('.flx'))
body "#include <stdio.h>";
body xprint = "void printx(char *fmt, char *s) { printf(fmt,s);}";
body printu = 'void print(char *s) { printx("%s\\n",s); }'
@@ -546,7 +534,7 @@
hello;
@doc()
-@..."))
+@select(env.expect())
Hello
@doc()
@@ -554,7 +542,7 @@
They can define dependencies, or simply specify
existing tagged requirements are roots.
-@...'))
+@select(env.test('.flx'))
body "#include <stdio.h>";
body xprint = "void printx(char *fmt, char *s) { printf(fmt,s);}";
body printu = 'void print(char *s) { printx("%s\\n",s); }';
@@ -565,14 +553,14 @@
hello;
@doc()
-@..."))
+@select(env.expect())
Hello
@doc()
You can also use qualified names to refer to tags defined
inside modules, unless they're marked private of course.
-@...'))
+@select(env.test('.flx'))
body "#include <stdio.h>";
body xprint = "void printx(char *fmt, char *s) { printf(fmt,s);}";
module fred {
@@ -584,13 +572,13 @@
hello;
@doc()
-@..."))
+@select(env.expect())
Hello
@doc()
The next example demonstrates untagged bodies at work.
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
body top = 'int ptop() { printf("TOP\\n"); return 1; }';
@@ -619,7 +607,7 @@
// B is not used .. (would cause y,p to be defined twice)
@doc()
-@..."))
+@select(env.expect())
TOP
A will be used
A is used
@@ -629,20 +617,20 @@
Here you can see that insertions can be given
literally too:
-@...'))
+@select(env.test('.flx'))
proc f: 1 = 'printf("A is used\\n");'
requires header '#include <stdio.h>';
f();
@doc()
-@..."))
+@select(env.expect())
A is used
@doc()
Here's an example demonstrating polymorphic insertions.
-@...'))
+@select(env.test('.flx'))
pod type int="int";
pod type double="double";
@@ -653,19 +641,19 @@
pr 1; pr 1.1;
@doc()
-@..."))
+@select(env.expect())
1
1.1
@doc()
-@... declaration')
+@env.head(2,'cstruct declaration')
The cstruct keyword can be used like struct,
and has the same effect, except that no struct
is actually generated by Felix, instead, the nominated struct
is assumed to be defined in embedded C/C++ header
code somewhere.
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
header """
@@ -683,12 +671,12 @@
print y.a; print " "; print y.b; endl;
@doc()
-@..."))
+@select(env.expect())
1 2
2 1
@doc()
-@... fun, proc, const declarations')
+@env.head(2,'bodyless fun, proc, const declarations')
It is allowed to omit the C definition of
primitive functions, procedures, and constants.
Felix will generate the body for a function
@@ -697,7 +685,7 @@
and a const will refer to a C entity of the
same name.
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
body """
@@ -719,17 +707,17 @@
@doc()
-@..."))
+@select(env.expect())
3
4
4
16
@doc()
-@... Classes')
+@env.head(2,'Binding Classes')
C++ classes are bound using the cclass construction.
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
open Long;
@@ -839,7 +827,7 @@
print$ z.sum[int] (12,13); endl; // 25
@doc()
-@..."))
+@select(env.expect())
-50
2
3
@@ -859,9 +847,9 @@
25
@doc()
-@...')
+@env.head(2,'Callbacks')
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
callback fun f: int * f -> int;
@@ -891,7 +879,7 @@
h(yyy,2);
@doc()
-@..."))
+@select(env.expect())
5
31
5
Modified: felix/trunk/lpsrc/flx_tut_macro.pak
===================================================================
--- felix/trunk/lpsrc/flx_tut_macro.pak 2006-09-24 10:53:16 UTC (rev 1029)
+++ felix/trunk/lpsrc/flx_tut_macro.pak 2006-09-24 10:55:31 UTC (rev 1030)
@@ -1,30 +1,17 @@
@set_title('Felix Tutorial: Macros')
-@... = 'tut'+os.sep+'macros'+os.sep
-@... = []
-@... = ''
-@... flx_tut_macro_head(level, name):
- global flx_tut_macro_levels,flx_tut_macro_level_str
- while len(flx_tut_macro_levels) < level: flx_tut_macro_levels.append(0)
- flx_tut_macro_levels[level - 1] = int(flx_tut_macro_levels[level - 1]) + 1
- flx_tut_macro_levels = flx_tut_macro_levels[:level]
+@execfile("flxbuild"+os.sep+"iscrutil.py")
+@env = setup_test(os.path.join('tut', 'macros', 'mac-'))
- for i in range(len(flx_tut_macro_levels)):
- flx_tut_macro_levels[i] = string.zfill(flx_tut_macro_levels[i], 2)
-
- flx_tut_macro_level_str = string.join(flx_tut_macro_levels,'.')
-
- return head(level, name)
-
@select(tangler('spkgs/flx_tut_macro.py'))
-@... = glob.glob("'+tdir+'*.flx")')
+@tangle('TESTS = glob.glob("'+env.root+'*.flx")')
unit_tests = TESTS
pkg_requires = ['flx_compiler','flx_drivers','flx_rtl','faio']
iscr_source = [ 'lpsrc/flx_tut_macro.pak' ]
weaver_directory = 'doc/tutorial/macros/'
-@... PreProcessor')
+@env.head(1,'The PreProcessor')
Felix provides a C like pre-processor. Note that
whilst it is C like in appearance, it isn't the same.
Preprocessor directives start with a # in column 1,
@@ -33,7 +20,7 @@
The syntax and semantics of directives are
described below.
-@... directive')
+@env.head(2,'Include directive')
The #include directive takes the same
form as the corresponding C preprocessor
directive.
@@ -69,30 +56,32 @@
includes a file once: note that symbolic links
will defeat the check for a duplication.
-@...'))
+@h1 = env.test('.flx')
+@select(h1)
#import <flx.flxh>
-@... "This is mac-'+flx_tut_macro_level_str+'a"; endl;')
+@tangle('print "This is '+h1.sink.name+'"; endl;')
@doc()
-@..."))
-@... is mac-'+flx_tut_macro_level_str+'a')
+@select(env.expect())
+@tangle('This is '+h1.sink.name)
@doc()
-@...'))
+@h2 = env.test('.flx')
+@select(h2)
#import <flx.flxh>
-@... "mac-'+flx_tut_macro_level_str+'a.flx"')
-@... "This is mac-'+flx_tut_macro_level_str+'b"; endl;')
-@... "it should have printed the mac-'+flx_tut_macro_level_str+'a message too"; endl;')
+@tangle('#include "'+os.path.basename(h1.sink.name)+'"')
+@tangle('print "This is '+h2.sink.name+'"; endl;')
+@tangle('print "it should have printed the '+h1.sink.name+' message too"; endl;')
@doc()
-@..."))
-@... is mac-'+flx_tut_macro_level_str+'a')
-@... is mac-'+flx_tut_macro_level_str+'b')
-@... should have printed the mac-'+flx_tut_macro_level_str+'a message too')
+@select(env.expect())
+@tangle('This is '+h1.sink.name)
+@tangle('This is '+h2.sink.name)
+@tangle('it should have printed the '+h1.sink.name+' message too')
@doc()
-@... compilation")
-@... variables and functions')
+@env.head(2,"Conditional compilation")
+@env.head(3,'Macro variables and functions')
Felix provides the #define directive to
define a macro variable or macro function.
Unlike C macros, Felix macros are strictly scoped.
@@ -113,7 +102,7 @@
after substitution of macro variables and application
of macro functions.
-@...')
+@env.head(3,'Conditionals')
Felix provides the usual conditional directives
#ifdef, #ifndef, #if, #elif, #else, #endif.
[Add #switch/#case/#endswitch]
@@ -130,7 +119,7 @@
Note that every name encountered must name a
preprocessor macro.
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
print "Defining FIRST"; endl;
#define FIRST
@@ -141,12 +130,12 @@
#endif
@doc()
-@..."))
+@select(env.expect())
Defining FIRST
detected FIRST
@doc()
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
#define FIRST 1
#define SECOND 2
@@ -157,11 +146,11 @@
#endif
@doc()
-@..."))
+@select(env.expect())
OK
@doc()
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
#define FIRST 1
#define SECOND 2
@@ -172,20 +161,21 @@
#endif
@doc()
-@..."))
+@select(env.expect())
OK
@doc()
-@...'))
+@h = env.test('.flx')
+@select(h)
#define FIRST 1
@doc()
-@..."))
+@select(env.expect())
@doc()
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
-@... "mac-'+flx_tut_macro_level_str+'a.flx"')
+@tangle('#import "'+os.path.basename(h.sink.name)+'"')
#ifdef FIRST
print "OK";
#else
@@ -194,16 +184,16 @@
endl;
@doc()
-@..."))
+@select(env.expect())
OK
-@... Lines')
+@env.head(2,'Long Lines')
Preprocessor directives support a kind of 'here' doc.
Place a # character after the first part of the command, and
all lines up to a line consisting solely of a #
will be taken as the argument string.
@doc()
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
#define ONE 1
#define TWO 1
@@ -217,12 +207,12 @@
#endif
@doc()
-@..."))
+@select(env.expect())
Yes
@doc()
-@... Syntax Macro Processor')
-@... Macro Facility')
+@env.head(1,'The Syntax Macro Processor')
+@env.head(2,'Expression Macro Facility')
Felix provides an powerful and dangerous
expression macro facility. Felix macros
generally respect scope, so any definitions
@@ -231,14 +221,14 @@
@p()
Expresion symbols only expand inside expressions.
-@... values')
+@env.head(3,'Macro values')
The macro val statement defines a LHS symbol
as the expansion of the RHS. The same
value can be defined any number of times,
a redefinition hides the preceding defintion
until the end of the scope.
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
macro val mx1 = 1+y;
macro val mx2 = 2+y;
@@ -263,7 +253,7 @@
endl;
@doc()
-@..."))
+@select(env.expect())
101
102
103
@@ -272,7 +262,7 @@
1
@doc()
-@... variables')
+@env.head(3,'Macro variables')
The macro var statement defines a LHS symbol
as the expansion of the RHS. The same
value can be defined any number of times,
@@ -281,7 +271,7 @@
@p()
Macro variables can be assigned a new value.
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
macro var mx1 = 1+y;
val y = 100;
@@ -293,18 +283,18 @@
print mx1; endl; // 103 [uses assigned value]
@doc()
-@..."))
+@select(env.expect())
101
103
103
@doc()
-@... variables in requirements')
+@env.head(3,'Macro variables in requirements')
Named requirements in requirements clauses are
macro expanded as expressions: they must be qualified
names though.
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
header fred = "inline int f(int x){return x;}";
macro val joe = fred;
@@ -313,11 +303,11 @@
print$ f 2; endl;
@doc()
-@..."))
+@select(env.expect())
2
@doc()
-@... functions')
+@env.head(3,'Macro functions')
You can also define a macro function.
The expansion rules are: the body
is not expanded during definition.
@@ -329,7 +319,7 @@
at the end. This is because the RHS is universally
treated as an expression.
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
// a basic expression macro without parameters
@@ -366,7 +356,7 @@
print (z q); endl;
@doc()
-@..."))
+@select(env.expect())
1
2
1
@@ -383,7 +373,7 @@
by manipulation of the abstract syntax tree (AST),
not token pasting or string manipulation.
-@... Expression Folding')
+@env.head(2,'Constant Expression Folding')
The Felix macro processor also performs constant folding;
that is, evaluation of certain expressions involving
only literals. The following operations are folded:
@@ -439,7 +429,7 @@
The first operation is the UTF-8 representation
of 999, whilst the second is the UCS-32 value 999.
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
header '''
#define flx_unix 0
@@ -475,11 +465,11 @@
C_hack::ignore(openlib ("MyLibrary" ext));
@doc()
-@..."))
+@select(env.expect())
LoadTheLibrary(MyLibrary.lib_ext)
@doc()
-@... Macros')
+@env.head(2,'Procedure Macros')
A procedure macro represents a list of statements.
Macros defined in macro procedures are exported
to the surrounding scope so that macro procedures
@@ -487,7 +477,7 @@
This represents a special exception to the rule
that macros respect scope.
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
// procedure macro
macro proc k ()
@@ -540,7 +530,7 @@
dump_e (todump_wa 66);
@doc()
-@..."))
+@select(env.expect())
1 -> 1
2 -> 4
30
@@ -576,7 +566,7 @@
is in the handling of any variable declarations:
they'd be exposed in the first case, but not the second.
-@... Procedure Macro Programming')
+@env.head(2,'Advanced Procedure Macro Programming')
Felix procedure macros also contain rudimentary
control structures: you can encode labels, unconditional
jumps, conditional jumps, and returns. Note the conditional
@@ -594,7 +584,7 @@
a macro expansion has as its argument another expansion
of itself.
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
macro proc print_alot ()
{
@@ -630,16 +620,16 @@
};
@doc()
-@..."))
+@select(env.expect())
10 9 8 7 6 5 4 3 2 1
10 9 8 7 6 5 4 3 2 1
10 9 8 7 6 5 4 3 2 1
@doc()
-@... Barrier')
+@env.head(2,'Expansion Barrier')
The symbol 'noexpand' can be used to block expansion.
-@...'))
+@select(env.test('.flx'))
#include <flx.flxh>
// expansion barrier
macro val x = 1;
@@ -655,11 +645,11 @@
};
@doc()
-@..."))
+@select(env.expect())
2+2 -> 4
@doc()
-@... Macros')
+@env.head(2,'Identifier Macros')
A identifier macros represent names. They replace names
in expressions and most declarations, including the
name of a function or variable being defined.
@@ -676,7 +666,7 @@
name in the chain which is not an ident macro,
or which recurs.
-@...'))
+@select(env.test('.flx'))
#include <flx.flxh>
macro oldname is newname;
@@ -699,17 +689,17 @@
print vold; endl;
@doc()
-@..."))
+@select(env.expect())
1
4
@doc()
-@... Macros')
+@env.head(3,'Forgetting Macros')
You can forget macros defined in the current scope with
the forget statement. If no arguments are given,
all macros defined in the current scope are forgotten.
-@...'))
+@select(env.test('.flx'))
#include <flx.flxh>
macro val hello = "Hello";
macro val place = "world";
@@ -727,17 +717,17 @@
print (greet());
@doc()
-@..."))
+@select(env.expect())
Hi there locality!
Hello locality!
Hello world!
Hello world!
@doc()
-@... Loops')
+@env.head(3,'For Loops')
Felix provides two for loops which iterate over tuples.
-@...'))
+@select(env.test('.flx'))
#include <flx.flxh>
macro for val i in ("Hello","World",42) do
print i; print " ";
@@ -750,18 +740,18 @@
done;
@doc()
-@..."))
+@select(env.expect())
Hello World 42
PTF a:int=1
PTF b:int=1
PTF c:int=1
@doc()
-@... Tuples")
+@env.head(3,"Unpacking Tuples")
Tuples can be unpacked by macro assignment,
macro val, macro var, and macro for val statements.
-@...'))
+@select(env.test('.flx'))
#include <flx.flxh>
macro val x,y = 1,2;
macro var a,b = 1,2;
@@ -774,18 +764,18 @@
endl;
@doc()
-@..."))
+@select(env.expect())
1 2 2 3
(1,2) (3,4)
@doc()
-@... representation")
+@env.head(3,"String representation")
The string representation of an expression can be obtained
with the special operator _str. This is most useful for
printing a variable name (but it works for any expression).
Note the expanded value is stringized.
-@...'))
+@select(env.test('.flx'))
#include <flx.flxh>
var x = 1;
var y = 42;
@@ -794,13 +784,13 @@
print (_str$ x+y); print " = "; print$ x+y; endl;
@doc()
-@..."))
+@select(env.expect())
x = 1
y = 42
(add (x, y)) = 43
@doc()
-@... Tuples")
+@env.head(3,"Packing Tuples")
The Felix syntax macro processor treats tuples as lists.
The for val construction can be used to iterate over
list contents. Two primitive macro functions are provided
@@ -821,7 +811,7 @@
expansions, particularly when driven by user defined
nontermial parses (see the next section).
-@...'))
+@select(env.test('.flx'))
#include <flx.flxh>
macro var x = _tuple 1;
macro x = _tuple_cons (2,x);
@@ -829,15 +819,15 @@
macro for val i in x do print i; print " "; done; endl;
@doc()
-@..."))
+@select(env.expect())
3 2 1
@doc()
-@... defined syntax")
+@env.head(1,"User defined syntax")
Felix has a complete, graded system which
allows the programmer to extend its syntax.
-@... defined operators")
+@env.head(2,"User defined operators")
The programmer may add infix operators at a particular
precedence level. Infix operators are any sequence
of the special characters ~!@#$%^&*.?/\=(){}[], or, any identifier.
@@ -856,7 +846,7 @@
be sure to #import the file in every file that it is
needed.
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
#infix 10 "^%" myfun
print "OK"; endl;
@@ -885,7 +875,7 @@
print y; endl;
@doc()
-@..."))
+@select(env.expect())
OK
10
10
@@ -897,7 +887,7 @@
1
@doc()
-@... defined statements")
+@env.head(2,"User defined statements")
Felix allows the programmer to invent new statements.
The statements must start with a user keyword: they
may not start with an existing non-user keyword.
@@ -926,7 +916,7 @@
Therefore, general cases must be given after specialised
ones.
-@...'))
+@select(env.test('.flx'))
#include <flx.flxh>
#statement#
@@ -1001,7 +991,7 @@
};
@doc()
-@..."))
+@select(env.expect())
10 9 8 7 6 5 4 3 2 1
10 9 8 7 6 5 4 3 2 1
1 plus 2 is 3
@@ -1009,7 +999,7 @@
10 9 8 7 6 5 4 3 2 1
@doc()
-@... Non terminals")
+@env.head(2,"User Non terminals")
Felix syntax extensions are not limited to simple
statements. The parser is a general, backtracking
RD parser and can handle any LL grammar. The only
@@ -1032,7 +1022,7 @@
preprocessor #statement statement, including in
the very next #statement definition.
-@...'))
+@select(env.test('.flx'))
#include <flx.flxh>
#keyword DONE
#keyword THEN
@@ -1093,11 +1083,11 @@
ELSE print "None"; endl; DONE;
@doc()
-@..."))
+@select(env.expect())
None
@doc()
-@... Macro Statement")
+@env.head(2,"User Macro Statement")
The syntax extension feature isn't limited to generated
executable statements or definitions: you can actually
generated macro statements, and thus extend the macro
@@ -1105,7 +1095,7 @@
macro conditional that accepts some statements as an
argument instead of using a macro goto.
-@...'))
+@select(env.test('.flx'))
#include <flx.flxh>
#statement#
IF expr do statements done; =>#
@@ -1122,7 +1112,7 @@
done;
@doc()
-@..."))
+@select(env.expect())
Hello
@#
@doc()
Modified: felix/trunk/lpsrc/flx_tut_migrate.pak
===================================================================
--- felix/trunk/lpsrc/flx_tut_migrate.pak 2006-09-24 10:53:16 UTC (rev 1029)
+++ felix/trunk/lpsrc/flx_tut_migrate.pak 2006-09-24 10:55:31 UTC (rev 1030)
@@ -1,23 +1,10 @@
@set_title('Felix For C++ Programmers')
-@... = 'tut'+os.sep+'migration'+os.sep
-@... = []
-@... = ''
-@... flx_tut_migrate_head(level, name):
- global flx_tut_migrate_levels,flx_tut_migrate_level_str
- while len(flx_tut_migrate_levels) < level: flx_tut_migrate_levels.append(0)
- flx_tut_migrate_levels[level - 1] = int(flx_tut_migrate_levels[level - 1]) + 1
- flx_tut_migrate_levels = flx_tut_migrate_levels[:level]
+@execfile("flxbuild"+os.sep+"iscrutil.py")
+@env = setup_test(os.path.join('tut', 'migration', 'mig-'))
- for i in range(len(flx_tut_migrate_levels)):
- flx_tut_migrate_levels[i] = string.zfill(flx_tut_migrate_levels[i], 2)
-
- flx_tut_migrate_level_str = string.join(flx_tut_migrate_levels,'.')
-
- return head(level, name)
-
@select(tangler('spkgs/flx_tut_migrate.py'))
-@... = glob.glob("'+tdir+'*.flx")')
+@tangle('TESTS = glob.glob("'+env.root+'*.flx")')
unit_tests = TESTS
pkg_requires = ['flx_compiler','flx_drivers','flx_rtl','faio']
@@ -25,12 +12,12 @@
weaver_directory = 'doc/tutorial/migration/'
@doc()
-@...")
+@env.head(1,"Introduction")
Felix is a new programming language with special support for
for C/C++ integration. This document highlights some of
the similarities and differences between Felix and C/C++.
-@... Features')
+@env.head(1,'General Features')
A brief comparison of C++ and Felix reveals the
following key similarities and differences:
@@ -102,15 +89,15 @@
@end_list()
-@...')
+@env.head(1,'Overloading')
Both C++ and Felix support overloading, including
overloading of generic functions. The overloading
rules differ in several key aspects.
-@... Conversions')
+@env.head(2,'Automatic Conversions')
Felix does not provide any automatic conversions.
-@... matching rule')
+@env.head(2,'Exact matching rule')
For non-generic functionbs, Felix only supports exact
matches when overloading, whereas C++ rules are more relaxed.
@p()
@@ -123,12 +110,12 @@
in the same scope with the same signature will lead
to an ambiguity.
-@... hiding rule')
+@env.head(2,'Function hiding rule')
For the purpose of overloading, a non-generic
function in Felix only hides another if they have
the same signature. For example:
-@..."))
+@select(env.test('.flx'))
#import <flx.flxh>
proc f(x:int){ print 1; endl; }
module X {
@@ -138,7 +125,7 @@
}
@doc()
-@..."))
+@select(env.expect())
1
2
@doc()
@@ -147,7 +134,7 @@
by the inner one, and f(double) called, with an automatic
conversion from 1 to 1.0.
-@... functions')
+@env.head(2,'Generic functions')
Like C++, Felix supports template style generic functions.
The rule for selection of a function in the presence
of generics is a generalisation of the rules for
@@ -173,7 +160,7 @@
is also accepted by the other, and the other also accepts
at least one additional argument. For example:
-@..."))
+@select(env.test('.flx'))
#import <flx.flxh>
fun f[t,u] (x:t,y:u)=> 1; //1
fun f[v] (x:v,y:v)=>2; //2: specialises 1
@@ -182,7 +169,7 @@
print (f (1,2)); endl; //calls 2
@doc()
-@..."))
+@select(env.expect())
1
2
@doc()
@@ -197,14 +184,14 @@
is known as the unification algorithm, and the process
of matching is known as unification.
-@... of type variables')
+@env.head(2,'Deduction of type variables')
As in C++: when a generic function is called,
it must be possible to determine bindings for
all its type variables. As in C++, leading type
variables may be given explicitly, and the ones
not given deduced from the function argument.
-@...')
+@env.head(1,'Scope')
Unlike C++, the scope of an identifier is the
whole of the construction containing it, just
like labels. In particular, all functions in
@@ -212,21 +199,21 @@
can be called before it is defined without a
forward declaration.
-@..."))
+@select(env.test('.flx'))
#import <flx.flxh>
fun f(x:int) => g(x-1);
fun g(x:int) => if x>0 then f(x-1) else 0 endif;
print (g 10); endl;
@doc()
-@..."))
+@select(env.expect())
0
@doc()
In particular this rule also applies to types,
allowing recursive types to be easily defined:
-@..."))
+@select(env.test('.flx'))
#import <flx.flxh>
union ilist = empty | cons of int * ilist;
var x = empty;
@@ -243,11 +230,11 @@
xprint x; endl;
@doc()
-@..."))
+@select(env.expect())
2 1
@doc()
-@... system')
+@env.head(1,'Type system')
Felix types and their annotations are quite different
to C++. Felix currenty supports tuple types, anonymous
sum types, a struct type like C, and a union type,
Modified: felix/trunk/lpsrc/flx_tutorial.pak
===================================================================
--- felix/trunk/lpsrc/flx_tutorial.pak 2006-09-24 10:53:16 UTC (rev 1029)
+++ felix/trunk/lpsrc/flx_tutorial.pak 2006-09-24 10:55:31 UTC (rev 1030)
@@ -1,44 +1,33 @@
@set_title('Felix Tutorial')
-@... = 'tut'+os.sep+'tutorial'+os.sep
+
@execfile('config/flx_data.py')
+@execfile("flxbuild"+os.sep+"iscrutil.py")
-@... = []
-@... = ''
-@... flx_tutorial_head(level, name):
- global flx_tutorial_levels,flx_tutorial_level_str
- while len(flx_tutorial_levels) < level: flx_tutorial_levels.append(0)
- flx_tutorial_levels[level - 1] = int(flx_tutorial_levels[level - 1]) + 1
- flx_tutorial_levels = flx_tutorial_levels[:level]
+@env = setup_test(os.path.join('tut', 'tutorial', 'tut-'))
- for i in range(len(flx_tutorial_levels)):
- flx_tutorial_levels[i] = string.zfill(flx_tutorial_levels[i], 2)
-
- flx_tutorial_level_str = string.join(flx_tutorial_levels,'.')
-
- return head(level, name)
-
@select(tangler('spkgs/flx_tutorial.py'))
-@... = glob.glob("'+tdir+'*.flx")')
+@tangle('TESTS = glob.glob("'+env.root+'*.flx")')
unit_tests = TESTS
pkg_requires = ['flx_compiler','flx_drivers','flx_rtl','faio']
iscr_source = [ 'lpsrc/flx_tutorial.pak' ]
weaver_directory = 'doc/tutorial/introduction/'
+@doc()
-@... Felix 101')
+@env.head(1,'Basic Felix 101')
This section deals with the basic concepts in Felix.
-@... Felix')
+@env.head(2,'Hello Felix')
There is no better introduction to a programming
language than the infamous hello-world program.
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
print "Hello World\n";
@doc()
-@..."))
+@select(env.expect())
Hello World
@doc()
@@ -54,33 +43,33 @@
then type:
@begin_displayed_code()
-@...(' bin/flx '+tdir+'tut-'+flx_tutorial_level_str)
+@weave(' bin/flx '+env.root+env.level_str())
@end_displayed_code()
This produces three files:
@begin_displayed_code()
-@...(' '+tdir+'tut-'+flx_tutorial_level_str+'.hpp')
-@...(' '+tdir+'tut-'+flx_tutorial_level_str+'.cpp')
-@...(' '+tdir+'tut-'+flx_tutorial_level_str+'.so')
+@weave(' '+env.root+env.level_str()+'.hpp')
+@weave(' '+env.root+env.level_str()+'.cpp')
+@weave(' '+env.root+env.level_str()+'.so')
@end_displayed_code()
We'll learn more about their structure later.
-@...')
+@env.head(2,'Overloading')
Felix supports overloading. To demonstrate this,
we'll make a small modification to the hello
world program. You can compile and run the
program as before, just change the example number.
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
print "Hello World ";
print 42;
print "\n";
@doc()
-@..."))
+@select(env.expect())
Hello World 42
@doc()
@@ -93,7 +82,7 @@
Felix has no automatic conversions, and
overload matching must be exact.
-@...')
+@env.head(2,'Expressions')
Felix provides many of the operators found
in C. Here is are some examples with equivalent
function calls. Note: there are no shift operators,
@@ -102,7 +91,7 @@
used facility]. There are no bitwise operators,
because both & and | have different uses.
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
// arith
print (1 + 1); endl; print (add (1,2)); endl;
@@ -132,7 +121,7 @@
print (1 >= 2); endl; print (ge (1,2)); endl;
@doc()
-@..."))
+@select(env.expect())
2
3
0
@@ -163,11 +152,11 @@
false
@doc()
-@... declaration')
+@env.head(2,'Value declaration')
Felix allows values to be declared using the 'val'
keyword.
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
val i = 40;
val j = 2;
@@ -175,7 +164,7 @@
print k; print "\n";
@doc()
-@..."))
+@select(env.expect())
42
@doc()
@@ -192,7 +181,7 @@
if you want: the following program is equivalent
to the one above:
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
val i : int = 40;
val j : int = 2;
@@ -200,7 +189,7 @@
print k; print "\n";
@doc()
-@..."))
+@select(env.expect())
42
@doc()
@@ -218,7 +207,7 @@
There is a shortcut form for declaring variables
using the := operator:
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
a := 1;
b:int := 2;
@@ -233,15 +222,15 @@
endl;
@doc()
-@..."))
+@select(env.expect())
1 2 3 4 5
@doc()
-@... declaration')
+@env.head(2,'Variable declaration')
Felix also support mutable variables, which are
declared with the 'var' keyword.
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
var i = 1;
var j : int;
@@ -253,7 +242,7 @@
};
@doc()
-@..."))
+@select(env.expect())
2
4
6
@@ -286,9 +275,9 @@
We'll find out exactly why later, but here is a hint:
there is no while statement in Felix!
-@... patterns')
+@env.head(2,'Lvalue patterns')
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
var a:int;
@@ -314,17 +303,17 @@
endl;
@doc()
-@..."))
+@select(env.expect())
1 2 3
9 8 7
@doc()
-@...')
+@env.head(2,'Mutators')
Felix provides a range of mutators,
these being assignment operators and counting operators.
Below is a list of operators and equivalent procedure names.
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
open Uint;
@@ -356,17 +345,17 @@
i--; post_decr (i);
@doc()
-@..."))
+@select(env.expect())
@doc()
-@...')
+@env.head(2,'Functions')
@set_anchor('Functions')
Felix allows you to define functions,
although the syntax is different from C.
Here is an example:
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
fun mid(a:int, b:int):int =
{
@@ -376,7 +365,7 @@
print (mid(2,4)); print "\n";
@doc()
-@..."))
+@select(env.expect())
3
@doc()
@@ -395,7 +384,7 @@
function is clearly given, it is not necessary,
as illustrated by the next example:
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
fun mid(a:int, b:int) =
{
@@ -405,7 +394,7 @@
print (mid(2,4)); print "\n";
@doc()
-@..."))
+@select(env.expect())
3
@doc()
@@ -413,10 +402,10 @@
Note however that the types of the arguments
must be given.
-@... and postconditions')
+@env.head(3,'Preconditions and postconditions')
Functions can be given preconditions:
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
fun guarded_div(a:int, b:int when b!=0) =
{
@@ -425,13 +414,13 @@
print (guarded_div(2,4)); print "\n";
@doc()
-@..."))
+@select(env.expect())
0
@doc()
Functions can also be given postconditions:
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
fun abs_div(a:int, b:int when b!=0) expect result >=0 =
{
@@ -440,7 +429,7 @@
print (abs_div(2,4)); print "\n";
@doc()
-@..."))
+@select(env.expect())
0
@doc()
@@ -455,7 +444,7 @@
At present (Felix 1.1.1) recovery is not possible,
nor is it possible to catch the exception.
-@...')
+@env.head(2,'Procedures')
Felix allows you to define procedures.
They're like functions, but they can't return values.
On the other hand, procedures may have side effects,
@@ -465,7 +454,7 @@
Here is an example of a procedure definition
and use:
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
proc print_newline (a:int)
{
@@ -475,7 +464,7 @@
print_newline 1;
@doc()
-@..."))
+@select(env.expect())
1
@doc()
@@ -483,13 +472,13 @@
with unit argument: if the procedure is called
by its name, the () can be elided:
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
print 1; endl();
print 2; endl;
@doc()
-@..."))
+@select(env.expect())
1
2
@doc()
@@ -502,10 +491,10 @@
that always represents the closure of the procedure
at the point of writing.
-@... and Postconditions')
+@env.head(3,'Preconditions and Postconditions')
Procedures may also have pre and post conditions.
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
var x = 7;
var y = x;
@@ -519,11 +508,11 @@
print x; endl;
@doc()
-@..."))
+@select(env.expect())
5
@doc()
-@...')
+@env.head(2,'Tuples')
As you might guess from the title, Felix has
tuples. A tuple is a value consisting of an ordered sequence of
two or more values, not necessarily of the same type.
@@ -549,7 +538,7 @@
to the Functions example.
@ref_anchor('Functions')
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
fun mid(a:int, b:int):int =
{
@@ -560,7 +549,7 @@
print (mid x); print "\n";
@doc()
-@..."))
+@select(env.expect())
3
@doc()
@@ -601,7 +590,7 @@
You can get at tuple components using a suffixed
dot followed a zero origin integer in brackets:
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
val x = (0,1,(3,4));
print x.(0); print " ";
@@ -610,7 +599,7 @@
print x.(2).(1); print "\n";
@doc()
-@..."))
+@select(env.expect())
0 1 3 4
@doc()
@@ -620,11 +609,11 @@
there is a better way called pattern matching
which you will learn about soon.
-@... Matching Tuples')
+@env.head(2,'Pattern Matching Tuples')
It is also possible to pattern match tuples.
Here is an example:
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
val v = 1,2,(3,4);
match (v) with
@@ -647,7 +636,7 @@
endl;
@doc()
-@..."))
+@select(env.expect())
1, (3, 4)
@doc()
@@ -655,13 +644,13 @@
something without naming it. The ?x designation
in a pattern introduces a variable.
-@... unions')
+@env.head(2,'Numbered unions')
Numbered unions are algebraic types used to
represent alternative cases. The infix
operator + is the type combinator used
to denote them. The number is zero origin.
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
open Long;
@@ -704,7 +693,7 @@
f i3;
@doc()
-@..."))
+@select(env.expect())
Case 0 of three
Case 1 of three
Case 2 of three
@@ -713,7 +702,7 @@
case 2 33
@doc()
-@...')
+@env.head(2,'Structs')
Felix supports C like structs. A struct, like a tuple,
is a categorical product type. Unlike a tuple,
a struct is named, its members are named, and
@@ -722,7 +711,7 @@
Struct members can be used with C style dot notation.
Here is an example:
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
struct XY {
@@ -737,7 +726,7 @@
print xy.y; endl;
@doc()
-@..."))
+@select(env.expect())
1
2
@doc()
@@ -747,7 +736,7 @@
from a tuple consisting of values to initialise
the members in sequence. For example:
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
struct XY = {
@@ -760,12 +749,12 @@
print xy.y; endl;
@doc()
-@..."))
+@select(env.expect())
1
2
@doc()
-@...: anonymous structs')
+@env.head(2,'Records: anonymous structs')
A record is an anonymous struct: its a tuple with
named fields. Two records are the same type if their
field names are the same, and have the same types.
@@ -773,7 +762,7 @@
@p()
A record can be coerced to a record with less fields.
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
open Float;
@@ -790,12 +779,12 @@
f (b:small);
@doc()
-@..."))
+@select(env.expect())
6
3.1
@doc()
-@...')
+@env.head(2,'Arrays')
Felix provides arrays of constant length.
The type notation
@begin_displayed_code()
@@ -812,7 +801,7 @@
An array is just a tuple of m elements of type t.
[More .. ]
-@...')
+@env.head(2,'Unions')
Felix supports unions, but they are a bit
different to C unions. A union is a way
of merging a finite set of types into
@@ -822,7 +811,7 @@
the component has, and the actual component.
Here are some examples of unions.
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
union parity =
@@ -855,7 +844,7 @@
print$ str d + str (caseno d); endl;
@doc()
-@..."))
+@select(env.expect())
a0
b2
c3
@@ -886,11 +875,11 @@
The enum form only permits constant constructors
(ones with no arguments), values are not permitted.
-@... Matching Unions')
+@env.head(2,'Pattern Matching Unions')
The only way to get at the current component
of a union is by pattern matching. Here is an example:
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
union int_option =
| iSome of int
@@ -913,7 +902,7 @@
endl;
@doc()
-@..."))
+@select(env.expect())
Some 1
@doc()
@@ -940,10 +929,10 @@
purely functional! It doesn't print anything, it just
returns a procedure which could print something.
-@... Conditional Expression')
+@env.head(2,'The Conditional Expression')
Felix supports the conditional expression as shown:
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
fun sign1(x:int):int =
@@ -996,7 +985,7 @@
print (sign3 20); endl;
@doc()
-@..."))
+@select(env.expect())
-1
0
1
@@ -1018,7 +1007,7 @@
a shortcut for a match, as shown in the
third sign function.
-@...')
+@env.head(2,'Objects')
Felix provides a way of making objects from functions.
An object is just a struct whose members are functions
nested in the scope of the object constructor function.
@@ -1044,7 +1033,7 @@
are taken as methods. Implicit functions such as blocks
are not taken.
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
obj a(x:int) {
var v = x;
@@ -1058,12 +1047,12 @@
print (z.fetch()); endl;
@doc()
-@..."))
+@select(env.expect())
1
2
@doc()
-@... Matching')
+@env.head(2,'Regular Matching')
Felix provides support for matching strings
against regular expressions.
@p()
@@ -1103,7 +1092,7 @@
@end_table()
Note that a char is represented by a one character string.
-@... = tangler(tdir+'tut-'+flx_tutorial_level_str+'.flx')
+@h = env.test('.flx')
@select(h)
#import <flx.flxh>
regexp lower = ["abcdefghijklmnopqrstuvwxyz"];
@@ -1146,7 +1135,7 @@
endl;
@doc()
-@..."))
+@select(env.expect())
Identifier
Number
Neither
@@ -1166,7 +1155,7 @@
state = matrix[*start++][state];
@end_displayed_code()
-@...')
+@env.head(2,'Lexing')
Felix provides a mechanism for constructing lexers.
The reglex construction matches a prefix of the string.
Of all possible matches, reglex chooses the longest match.
@@ -1177,7 +1166,7 @@
values of type iterator: lexeme_start, lexeme_end and
buffer_end.
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
open Lexer;
@@ -1226,7 +1215,7 @@
print "Done.\n";
@doc()
-@..."))
+@select(env.expect())
Identifier: A
White:
Identifier: string
@@ -1237,10 +1226,9 @@
Done.
@doc()
-@... (much) longer example')
-
-@...'))
-#!/bin/env flx
+@env.head(3,'A (much) longer example')
+@h = env.test('.flx', 'data')
+@select(h)
#import <flx.flxh>
include "flx_lex";
use Lexer::sub;
@@ -1252,7 +1240,7 @@
val xx = 1214;
//val s = "A string is here == != @@ ";
-@... s = Text_file::load("'+tdir+'tut-'+flx_tutorial_level_str+'.flx");')
+@tangle('var s = Text_file::load("'+h.sink.name+'");')
//print s; endl;
@@ -1310,16 +1298,8 @@
while { i1 != i2 } { print_token; };
@doc()
-@..."))
+@select(env.expect())
Lexer here
-#!/: "#!/"
-Id: "bin"
-SLASH: "/"
-Id: "env"
-White: " "
-Id: "flx"
-Eol: "
-"
HASH: "#"
Id: "import"
White: " "
@@ -1387,7 +1367,7 @@
::: "::"
Id: "load"
LPAR: "("
-@...: ""'+tdir+'tut-'+flx_tutorial_level_str+'.flx""')
+@tangle('Other: ""'+h.sink.name+'""')
RPAR: ")"
SEMI: ";"
Eol: "
@@ -2765,11 +2745,11 @@
"
@doc()
-@... expressions')
+@env.head(2,'Lazy expressions')
There is a function which is so useful, there
is a special syntax for it: the lazy expression.
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
var x = 1;
var y = 2;
@@ -2788,7 +2768,7 @@
endl;
@doc()
-@..."))
+@select(env.expect())
3355
@doc()
@@ -2800,7 +2780,7 @@
You can also put statements inside curly brackets
to define a lazy function:
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
val x = 1;
val f = { val y = x + 1; return y; };
@@ -2809,7 +2789,7 @@
print (f ()); eol;
@doc()
-@..."))
+@select(env.expect())
2
@doc()
@@ -2817,12 +2797,12 @@
otherwise the return type is the type of the return
statement arguments, which must all be the same.
-@... block procedure')
+@env.head(2,'The block procedure')
There is a procedure which is so useful, there
is a special syntax for it, as described above in
the section on lazy things: the block.
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
var x = 1;
val p1 = { print x; };
@@ -2838,7 +2818,7 @@
print x; endl;
@doc()
-@..."))
+@select(env.expect())
1111111
@doc()
@@ -2851,11 +2831,11 @@
short cut rule.
-@... Functions')
+@env.head(2,'Generic Functions')
Felix functions and procedures can be generic too.
Here is a simple example.
-@...'))
+@select(env.test('.flx'))
header "#include <iostream>";
type int = "int";
proc print[T]:T="std::cout << $1 << std::endl;";
@@ -2871,7 +2851,7 @@
pp[int] (snd[int,int] x);
@doc()
-@..."))
+@select(env.expect())
1
2
2
@@ -2884,7 +2864,7 @@
Synthesised type variables are added
to the type variable list at the end. For example:
-@...'))
+@select(env.test('.flx'))
header "#include <iostream>";
type int = "int";
proc print[T]:T="std::cout << $1 << std::endl;";
@@ -2900,7 +2880,7 @@
pp[int] (snd[int,int] x);
@doc()
-@..."))
+@select(env.expect())
1
2
2
@@ -2918,7 +2898,7 @@
type subscripts must be given explicity, because they cannot
be deduced from the argument.
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
fun pair1 x y = { return x,y; }
fun pair2[t,u] (x:t) (y:u) = { return x,y; }
@@ -2946,17 +2926,17 @@
print x; print ","; print y; endl;
@doc()
-@..."))
+@select(env.expect())
3,4
3,4
2,2
@doc()
-@... Structs and Unions')
+@env.head(2,'Generic Structs and Unions')
Felix structs and unions can be generic too.
Here is a simple example.
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
union list[T] =
| Cons of T * list[T]
@@ -2977,18 +2957,18 @@
print y.fst; print ","; print y.snd; endl;
@doc()
-@..."))
+@select(env.expect())
1,2
@doc()
-@... Deduction')
+@env.head(2,'Argument Deduction')
It is inconvenient to specify the type
arguments for a function. Generally,
this is not necessary, as illustrated in
the example: Felix deduces the value
of the type variables from function arguments.
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
union list[T] =
| Cons of T * list[T]
@@ -3058,7 +3038,7 @@
pr (x,(printint of (int))); endl;
@doc()
-@..."))
+@select(env.expect())
1,2
1
321
@@ -3067,7 +3047,7 @@
321Empty
@doc()
-@... modules')
+@env.head(2,'Generic modules')
It is also possible specify type arguments for a module.
The effect is simply that all the entities declared in
the module are parameterised by the type parameter.
@@ -3082,7 +3062,7 @@
arguments of the parent of a function are fully
determined by its child.
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
module X[t] {
@@ -3127,15 +3107,15 @@
if cmp(x,y) do print "YES"; endl; else print "NO"; endl; done;
@doc()
-@..."))
+@select(env.expect())
1111111112YES
@doc()
-@... types')
+@env.head(2,'Inductive types')
Felix supports inductive types such as lists.
Here is a list of ints.
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
union float_list =
@@ -3164,7 +3144,7 @@
xprint t2; endl;
@doc()
-@..."))
+@select(env.expect())
200.2 100.1 []
@doc()
@@ -3172,7 +3152,7 @@
Here, we use a recursive routine to build the list,
and an iterative routine to reverse it.
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
union int_list =
@@ -3226,12 +3206,12 @@
print "Reversed= "; xprint (rev a); endl;
@doc()
-@..."))
+@select(env.expect())
List= 1 2 3 4 5 6 7 8 9 10 []
Reversed= 10 9 8 7 6 5 4 3 2 1 []
@doc()
-@... order Functions')
+@env.head(2,'Higher order Functions')
In Felix, functions and procedures are first class:
they may accept functions or procedures as arguments,
functions may return them, and you can have variables
@@ -3250,7 +3230,7 @@
Here is an example, beware this example
contains quite a lot of subtle features!
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
var j = 2;
@@ -3266,7 +3246,7 @@
print_i(); endl;
@doc()
-@..."))
+@select(env.expect())
42
43
@doc()
@@ -3336,7 +3316,7 @@
Even more confusing, it sometimes means procedures
as well (even though they're utterly different beasts).
-@... "the" keyword')
+@env.head(2,'The "the" keyword')
When naming functions, it annoying
to write the signature of the function
when there is clearly only one function
@@ -3344,7 +3324,7 @@
you can use the keyword 'the' to specify
you mean that function.
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
fun f(x:int):int=>x*x;
@@ -3353,14 +3333,14 @@
print (apply (the f) 4); endl;
@doc()
-@..."))
+@select(env.expect())
16
@doc()
-@...')
+@env.head(2,'Currying')
Consider the following example:
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
fun f4(i4:int): int->int->int->int = {
@@ -3387,7 +3367,7 @@
print (curry 3 4); endl;
@doc()
-@..."))
+@select(env.expect())
10
10
10
@@ -3431,7 +3411,7 @@
to declare functions suitable for currying.
Here is the equivalent code, using this sugar:
-@...'))
+@select(env.test('.flx'))
#import <flx.flxh>
fun f4(i4:int) (i3:int) (i2:int) (i1:int): int = {
@@ Diff output truncated at 100000 characters. @@
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|