The Portabl E language & compiler
by Chris Handley, for Portabl E r6b (24.11.2022)
For my email address, please see the "About the author" chapter.
Manual last updated 24.11.2022.

This is the finished r6 release, with the "beta" tag removed, although it hasn't really been beta since the last couple of release.
The changes in the r6b release:
- Amiga: Fixed the installer still failing at "Copying executables..." in some cases. Many thanks to Benedetto Lorello for reporting the bug & assisting with testing (as it didn't happen for me).
- AmigaOS4: Worked-around a bug in the latest OS4 SDK (54.16), which has problems compiling C++ code, unless you use GCC v6.4.0 . Many thanks to Benedetto Lorello for reporting the problem.
The changes in the r6a release:
- AmigaOS4: Fixed the 'std/cGui' module failing to compile (MUIA_Dtpic_Name not declared), due to the SDK not using MUI4+ by default.
- Linux: Fixed 32-bit hex values > $7FFFFFFF not being interpreted as negative by the type checker.
- AROS: Fixed Install_AROS not offering to install the extra C header files (although they're not really needed).
The biggest changes since the last r6 beta release in 2016 include:
- Added basic Linux support (64bit x86 only), to the same level as Windows, i.e. Shell-only, with no graphics or internet access. This was a major effort, partly due to all the differences (64-bit pointers, case-sensitive filing system, mount-points anywhere, etc), and partly due to all the C headers that needed to be converted.
- Linux: PEGCC now supports cross-compilation (for Amiga & Windows) using the TargetOS parameter, as long as an appropriate GCC cross-compiler is installed.
- Windows/Linux: In 'std/cPath', added a per-user Assignments.txt file, but removed the per-program-start-folder Assignments.txt file.
- Programs will now compile using the latest SDK of AmigaOS4, AROS and MorphOS.
- All OS procedures that can support unlimited parameters now do so, including the Amiga's SystemTags().
- AmigaOS3: No-longer needs a modified "intuition/classusr.h" file.
- Added the 'std/pUnsigned' module, to provide basic support for unsigned number types, and the example program "Examples/std/Shell/crc32.e". Useful for porting certain C algorithms.
- Added the procedures InStrNoCase(), BigMax(), BigMin(), BigFastMod(), IsBigEndian() & IsLittleEndian().
- In 'std/pTime', improved CurrentTime() to take a timezone parameter.
- Fixed FastNew() (and so NEW) which would trash memory, instead of raising the "MEM" exception, if it failed to allocate memory. Thanks to Dimitris Panokostas for reporting symptoms of this long-standing bug, especially as I don't see out-of-memory errors on the OSes I normally use.
- Amiga: The installer would fail at "Copying executables..." if the user-specified path for executables did not contain any (sub) folders, such as "C:" (which sadly was the default). Many thanks to "Zendarion" for the bug report.
- Windows: In 'std/pTime', CurrentTime() now returns the correct time when DST is in effect.
- I've renamed the language from "PortablE" to "Portabl E" with a space, in the hope of making it more easily searchable on the internet (as well as clarifying how to pronounce it). But the "PortablE" command name itself is unchanged.
The other biggest changes since the r5 release in 2009 include:
- Added Graphics, Sound, Music & GUI modules (which are pretty powerful,
portable & easy to use) for Amiga OSes (but not yet for Windows or Linux).
- Added lots of documentation & some nice examples for the new modules.
- The documentation is now aimed at new users (as well as old ones!).
- The Amiga installer now uses file & choice requesters, has a Simple
Installation mode, and the PEmodules folder can be moved.
- Added the ADDRESSOF keyword, so some Amiga (and especially MUI) code is much
easier to write/port. Revised the MUI example code.
- Various new standard functions have been added, including PrintException().
- You can now use target-specific #ifdef, to more easily have the same code work
for different targets (OSes).
- CreateNewProc() now automagically adds the OS-specific tagitems.
- Solved the C++ multi-threading problem with the 'CSH/pAmiga_fakeNewProcess'
module.
- Pointer & array global variables are now automatically initialised (to NIL).
- Portabl E now stores it's ".pem" cache files in a special folder, instead of
your source code folder(s).
- Fixed out-of-memory allocation failures trashing memory, and also improved
low-memory behaviour.
- Fixed memory allocation being very slow and/or heavily wasting memory in
certain circumstances, and possibly some other rare bugs.
- StringF() is now much improved, and should no-longer cause memory corruption
in some cases.
- You can now use a % inside a string without a problem.
- Added some library functions which were accidentally missing. And tweaked
many library modules.
- Fixed quite a few bugs.
Please see the 23. History chapter for a full summary of recent changes. For the
details of any particular changes, you can read the relevant sections of this
manual.
Go back to CONTENTS
Portabl E is my recreation of the AmigaE programming language, along with most
of the improvements I have wanted. And while AmigaE only worked on AmigaOS3,
Portabl E also works on AmigaOS4, AROS, MorphOS, as well as even Linux & Windows!
Portabl E works by translating your E code into C++, and then using GCC to
compile it into an executable that you can run. But you don't usually need to
worry about those details, because the PEGCC program will do it for you.
Portabl E does need an installation of GCC, which is free & easily installed.
Previous versions of Portabl E were aimed at existing AmigaE users, but the r6
release of Portabl E aims to be attractive for new users too.
In 1991 Wouter van Oortmerssen started working on the friendly but powerful
AmigaE language, he released the first version in 1993, and continued to improve
it up till 1997, by which time it had become a very popular programming language
for the Amiga. But during 1998 development stalled, and it was finally
officially abandoned in 1999, partly due to the Amiga platform's own lack of
development since Commodore went under.
Jason Hulance's good AmigaE beginners guide: cshandley.co.uk/JasonHulance
(TIP: If you want to use Portabl E rather than AmigaE with this guide, then make
sure to use the OptAmigaE switch described in 5.1. Usage description.)
The original AmigaE manual: cshandley.co.uk/amigae/
The home page of AmigaE: strlen.com/amiga-e/
The Wikipedia entry on AmigaE: en.wikipedia.org/wiki/AmigaE
Aminet AmigaE stuff: aminet.net/dev/e
Amiga E Tutorials and Code Samples: web.archive.org/web/20091026160233/http://www.amigau.com/c-programming/amigae/etut.htm
The original AmigaE shareware package: (Amiga only)
aminet.net/package/dev/e/amigae33a and
wouter.fov120.com/files/lang/e/amigae33a.lha
The full AmigaE compiler released for free: (Amiga only)
wouter.fov120.com/files/lang/e/ec33a.lha and
wouter.fov120.com/files/lang/e/ec33a.readme
New users should only bother reading the first part of the 4. A quick start
chapter in this manual. Then they should look at the "Standard Functionality"
document, and also at the "Examples/std" folder. Eventually they may want to
come back to this manual, and look at the 15. The type system, 5. Usage of the compiler & 7. Modules chapters. They might also consider joining the official
Portabl E forum, or the AmigaE mailing list.
For Linux & Windows users, some familiarity with the Amiga is assumed,
particularly the ReadArgs syntax used to specify command parameters & what
assignments are, as both are 'emulated' by Portabl E on Linux & Windows systems.
Existing AmigaE users should try to read most of this manual, as it
describes the differences between Portabl E & AmigaE. They can look at the
"Examples/Amiga" folder, to see how Portabl E handles classic AmigaE programs.
They are also advised to look at the "Standard Functionality" document, and the
"Examples/std" folder, as these explain & demonstrate the new modules that come
with Portabl E
Portabl E's "Standard Functionality" document can be found here:
cshandley.co.uk/portable/StandardFunctionality.html
Portabl E's official forum for questions & discussions:
ae.amigalife.org/index.php?board=10.0 (this covers all OSes, not just AROS!)
The current forum lost most of it's content after an upgrade, but the old content is archived here:
web.archive.org/web/20181007125741/http://aros-exec.org/modules/newbb/viewforum.php?sortname=p.post_time&sortorder=DESC&since=0&forum=28&type=&refresh=Go
The AmigaE mailing list is still running:
www.freelists.org/list/positron
Annotate is a nice (Amiga only) editor with syntax highlighting:
aminet.net/package/text/edit/Annotate_usr or
os4depot.net/index.php?function=showfile&file=utility/text/edit/annotate.lha
I have written an add-on for Annotate, which allows you to compile & run
Portabl E code from inside Annotate: cshandley.co.uk/portable/AnnPEGCC_r1.lha
The homepage of Portabl E: cshandley.co.uk/portable/
Portabl E is capable of generating code for the C++ language (as well as for
AmigaE itself!), which is then compiled to a proper executable. It supports
Linux, Windows, AmigaOS3, AmigaOS4, AROS & MorphOS. (It can also potentially
support other OSes & generate code for other languages.)
Portabl E has native executables for Linux (64bit x86), Windows, AmigaOS3,
AmigaOS4, AROS (x86) & MorphOS, because Portabl E is written in E itself!
It comes with portable modules to cover stuff like file & directory access,
shell parameter parsing, graphics, sound & GUIs. These portable modules are NOT
always supported by all OSes, especially not by Linux & Windows yet. You can
find a complete list & description of all of them in the "Standard Functionality"
document, but essentially Linux & Windows only supports Shell-like stuff.
Many Amiga modules are also provided for AmigaOS3/OS4/AROS/MorphOS: AmigaGuide,
AmigaLib, Asl, Commodities, Console, DataTypes, Devices (inc. AHI & Timer),
Diskfont, Dos, Exec, Gadgets, Gadtools, Graphics, Icon, Identify, IFF, IFFParse,
Images, Intuition, Layers, Locale, Keymap, MPEGA, MUIMaster, Resources,
ReqTools, RexxSysLib, Utility & Workbench. Plus part of class, mui/*_mcc, Other
& Tools. Also 'libraries/ahi_sub' & 'libraries/cd_play'. (Additional modules
can be added if there is interest, but the original idea for Portabl E was to
provide abstract modules that did not expose the OS.)
Additionally, some modules contributed by others are currently only available
for some targets: 'mui/Lamp_mcc' (OS3/OS4), 'mui/TheBar_mcc' (OS3/OS4).
Modules that are specific to certain OSes: 'Picasso96API' (OS4),
'target/application' (OS4's application.library), 'target/cybergraphics'
(AROS/MOS).
For Amiga-like OSes, 256MB of installed memory is the recommended minimum. A
stack of at least 100KB is also required.
I only became interested in AmigaE in 1996, after becoming dissatisfied with the
other languages available (such as the buggy AMOS Pro). Luckily I was hooked
before AmigaE was abandoned, and due to it's lack of bugs I happily continued to
use it after that. Around 2000 severe problems with my Blizzard PPC forced me
to contemplate ditching the Amiga, for the (sort of Amiga-like) Psion platform,
which meant loosing all my code & switching languages...
First I considered writing a crude translator from AmigaE to Psion's OPL language,
but it became clear something more advanced would be needed. Then in 2001
Amithlon appeared, just as Psion was abandoning my planned replacement platform,
which allowed me to stay with the Amiga. But by this time I was very aware of
how fragile & limiting it was to tie my programs to any single platform or OS,
so my plans crystalised on writing a "universal" E translator that would
future-proof my code & also allow my programs to run on all the other platforms
I used. Anything less would likely be a waste of my time & effort!
I started properly designing Portabl E in about 2001, and gradually resolved to
improve the E language, with each new feature spurring ideas for further
improvements. Due to a lack of time, a desire to get the design "right first
time", a lack of any prior experience writing something like this, and in
general being overly ambitious :-) , it took me until early 2006 before it was
complete enough to start working. And it then took me until January 2008 before
it was able to successfully compile itself - a major milestone. It was finally
officially released in June 2008. Windows support was added in May 2009. Linux
support was finally added in November 2022, as I had recently switched from
Windows to Linux.
AmigaE hadn't been developed by Wouter for about a decade by the time I first
released PortablE, but if it had then it would have likely looked quite
different from the AmigaE v3.3 (and close descendants) that we were stuck with.
Think of Portabl E as what AmigaE v4 or v5 might have looked like - except
without Wouter's penchant for adding features from completely unrelated
languages!
- E is now type checked. This is something which AmigaE sorely lacked,
particularly for big object-orientated programs, as well as for beginners. But
I aim to make the type system work with the programmer - rather than against him
as you might have experienced with C/C++! The type system also allows some neat
features to be implemented.
- Automatic compilation of changed modules, and those that depend on them, so no
more Make files - or crashes due to forgetting to recompile a module.
- Much better support for Object Orientated Programming (OOP), without loosing
E's charming simplicity.
- One of the biggest changes to E has been the decision to make E code truely
portable (hence it's name), so that one program can be compiled for many OSes &
languages. Thus like Java you shouldn't directly access OS functions, but
instead use carefully designed abstractions/wrappers. Direct access to AmigaOS
is still possible, but it won't be supported by all targets (such as Windows!).
- I have taken the opportunity to rationalise the E language, so that some
historical baggage & a few wierd choices have been corrected. Portabl E is not
entirely compatible with AmigaE anyway, so it seems sensible to make a few other
improvements while I am at it. Wouter (the author of AmigaE) did not really
have this luxury!
Go back to CONTENTS
This program is distributed for free, in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
In Plain English (and only as an aid to understanding) the above is intended to
roughly mean: Portabl E cost you nothing, so don't expect me to take
responsibility for any problems that it causes you. If it erases your harddisk,
or directs your car into a ditch, that's your problem. Of course, I try to
ensure that it works well, but I can't guarantee it, so all use is soley at your
risk. Backups are a wonderful invention, make use of them.
Go back to CONTENTS
This chapter is to help get existing AmigaE users quickly writing new programs
in Portabl E. I still strongly suggest that users read the full list of
differences from AmigaE, which are given in later chapters, as well as the
chapters on the type system & possibly on object orientation.
For the Amiga, Portabl E needs a stack of at least 100KB to run, so either have
the STACK=100000 tooltype set in your Shell's icon, or otherwise type the
following each time you start the Shell:
Stack 100000
Linux & Windows user do not need to worry about this of course!
And if you want a list or explanation of all the standard (portable) functions,
then please read the "Standard Functionality" document.
Using a text editor like Notepad or EditPad, type the following program into a
text file called Hello.e :
PROC main()
Print('Hello world!\n')
ENDPROC
If Portabl E and GCC have been correctly installed, and you have saved
Hello.e to your Work: partition, then you can compile it by typing the
following at a Shell or Command prompt:
PEGCC Work:Hello.e
This will produce an executable that you can run straight away. If you are
feeling lazy, then you can have the executable automatically run as soon as it
is compiled:
PEGCC Work:Hello.e RUN
More advanced users may wish to generate C++ code that they can compile
themselves, by typing the following at a Shell or Command prompt:
PortablE Work:Hello.e
This should produce the file Work:Hello.cpp, which you can then compile &
run using a C++ compiler (but for details on the quirks of each compiler please
read the 6. Compiling the code generated by Portabl E chapter).
If you wanted to produce C++ code for AmigaOS4, using say the Windows or AROS
version of Portabl E, then you would type the following at a Shell or Command
prompt:
PortablE Work:Hello.e OS=AmigaOS4
And if you wanted to produce 'old skool' AmigaE code instead, then you would
type the following at a Shell prompt:
PortablE Work:Hello.e LANG=AmigaE
This should produce the file Work:Hello_OUTPUT.e .
With this program, the only difference from AmigaE is that we use the Print()
procedure, rather than PrintF() or WriteF(). If you really prefer the old name,
then you could try 'emulating' it:
PROC main()
writeF('Hello world!\n')
ENDPROC
PROC writeF(string:ARRAY OF CHAR, param1=0, param2=0)
Print(string, param1, param2)
PrintFlush()
ENDPROC
Here we see another difference - strings now have the type ARRAY OF CHAR, rather
than PTR TO CHAR. And dynamically allocated arrays can be passed around (like
pointers), rather than just being fixed-sized arrays preallocated on the stack.
The reason for this is that Portabl E is now type-checked, and for portability
pointers may not be indexed like an array (unless you enable the 'dangerous'
pointer arithmetic option).
Now, you are perhaps thinking that this 'emulation' is a bit inefficient, and
would be better done using a line like:
#define writeF(a,b,c) (Print(a,b,c) BUT PrintFlush())
Well, such macros are not recommended for Portabl E (although they will work),
because it provides an alternative which is generally better:
PROC writeF(string:ARRAY OF CHAR, param1=0, param2=0) IS Print(string, param1, param2) BUT PrintFlush()
This is an "in-line procedure", which means that any calls to writeF() will be
substituted by the given Print() code, when optimisations (or inlining) are
enabled. So this is just as efficient as a macro, but it is more portable,
supports default parameters, you don't need to worry about enclosing parameters
within brackets, and parameters with side-effects can't cause problems.
Still, this is writeF() not WriteF(), because E does not let you declare
procedures that begin with a capital letter, which means that it won't work with
old programs. There is a way around this, but I don't want to introduce bad
habits early on, so just think of this as an incentive to read the rest of this
manual ;-) .
It's worth noting that the backwards compatibility mode does provide
WriteF() and PrintF(), but you should only use that mode as a stepping stone
when porting your programs over to Portabl E.
Also note that while Print() is usually buffered, you can flush the buffer with
PrintFlush(), so you shouldn't miss the unbuffered WriteF().
Portabl E is properly typed, so you no-longer need to use confusing ! symbols
everywhere when dealing with floating point numbers. Here's a simple example:
PROC main()
DEF result:FLOAT, number
number := 5
result := number / 2.5
IF result > 2
Print('Result was > 2\n')
ELSE
Print('Result was <= 2\n')
ENDIF
ENDPROC
You will note that an integer variable was divided by a floating point number,
and then stored in a floating point variable, without any worries. Similarly, a
floating point variable was compared with an integer number.
Like C, you only need worry when dividing one integer by another integer. In
that case Portabl E will give you an integer, unless you cast one of the numbers
as a floating point like so:
result := 12 !!FLOAT / 34
The !! symbol is used for casting any type. It is always wise to cast the
first number of a division, since E's left-to-right order of evaluation means
that trying to cast the second number would end-up casting the result instead
(unless you used brackets around it).
It is also worth mentioning that if you try to store a floating point variable
in an integer variable, then Portabl E will report an error, because precision
will be lost. In that case you must cast it to an integer first:
number := 12.34 !!LONG
Lets get Portabl E to do something a bit more interesting:
PROC main()
DEF newString:ARRAY OF CHAR
newString := combine('one two ', 'three four\n')
Print(newString)
ENDPROC
PROC combine(first:ARRAY OF CHAR, second:ARRAY OF CHAR)
DEF eString:STRING
NEW eString[ StrLen(first) + StrLen(second) ]
StrAdd(eString, first)
StrAdd(eString, second)
Print('Third character=\c\n', eString[2]) ->will show "e"
ENDPROC eString
This example demonstrates quite a few changes. Let's deal with the combine()
procedure first:
The eString variable has the e-string type, but where-as AmigaE only allowed you
to declare fixed-sized STRINGs preallocated on the stack, Portabl E also allows
you to declare dynamically allocated STRINGs, as shown here.
We could have (dynamically) created an e-string using the NewString() procedure,
which is the new name for our old friend String(), but with Portabl E it is
always better to use NEW & END if you can. Where-as AmigaE's NEW could only
allocate an array, Portabl E's NEW can be used to allocate an e-string or an
e-list (amoung other talents!), as shown here.
The use of StrAdd() should be obvious, but it is worth pointing out that if you
accidentally typed StrAdd(first, eString) then rather than crashing at run-time
as AmigaE would, Portabl E will report an error at compile-time, because first
does not have the required type of STRING.
The final ENDPROC eString declares that the combine() procedure returns a
value of type STRING, since eString has that type. All procedures that return
something must declare their return type(s) in this way, even if they always use
RETURN. (Actually, you can declare the return type(s) on the PROC line using
RETURNS instead, but I don't want to over-complicate things yet!)
Everything from main() should be pretty self-explanatory, and in fact look very
similar to something written for AmigaE. But wait a minute, doesn't combine()
return a STRING, so why does Portabl E allow it to be assigned to newString
which has the type ARRAY OF CHAR? Well, while e-strings are a specialised kind
of ARRAY OF CHAR, they can still be treated as ARRAY OF CHAR, so it's all right
- in technical terms STRING is a subtype of ARRAY OF CHAR.
However, you may have spotted that something is wrong... main() fails to
deallocate the e-string, so we have a memory leak, at least until the program
quits & all remaining memory is reclaimed. Not a problem for a silly little
program like this, but in a proper program it could be a serious issue. You
could try adding this line at the bottom of main():
DisposeString(newString)
But Portabl E will complain that newString has the wrong type. So you could try
this instead:
END newString
The compiler won't complain about this, but it is wrong, because END is
treating newString as an ARRAY OF CHAR, rather than a STRING. So the only way
to correctly deallocate something is to have it stored in a variable of the
correct type:
DEF newString:STRING
Both the previous suggestions will now compile & work correctly. And as you may
have noticed, Portabl E does not allow you to specify an array's size when it
is being deallocated using END, although you can end it with an empty [] if you
want.
Before we move on, here's one final trick with NEW:
eString := NEW 'immediate string'
This creates an e-string copy of the immediate string, and is significantly less
tedious than what you'd need to do in AmigaE.
Having looked at e-strings, you should have a good idea what to expect from
e-lists. All lists are some kind of ARRAY OF VALUE, and so can contain any
value you want (except for floating point & 64-bit values). An immediate list
looks the same in Portabl E as it does in AmigaE:
e.g. [1, 2, variable, 4]
This actually has the type ILIST, because unlike a plain ARRAY OF VALUE it knows
it's own length. So just as in AmigaE, you could do this:
length := ListLen( [1,4,9] ) ->stores the value 3
But just as in AmigaE, you should not try to modify the contents of an immediate
list - and in fact no list-modifying procedure will accept an ILIST. If you
want to modify a list, then you must allocate a proper LIST (note it doesn't
start with an "I"):
PROC main()
DEF eList:LIST
NEW eList[ 5 ]
ListAdd(eList, [1,2,3])
ListAdd(eList, [4,5,6])
Print('List length=\d\n', ListLen(eList)) ->will show 5, not 6
Print('Third value=\d\n', eList[2]) ->will show 3
FINALLY
END eList
ENDPROC
As with e-strings, we could have created an e-list using the NewList()
procedure, which is the new name for our old friend List(), but using NEW is
preferred. Similarly, we could have used DisposeList() for deallocation,
instead of END.
We could also have avoided dynamic allocation altogether, and simply said:
DEF eList[5]:LIST
You should note that the procedure ListLen(list:ILIST) accepts both ILIST & LIST
types, because LIST is a specialised kind of ILIST - in technical terms LIST is
a subtype of ILIST.
But what's this FINALLY doing? It's Portabl E's equivalent of EXCEPT DO, which
means that the code after it will always be executed - whether or not an
exception is raised. It is used here to ensure that the memory does not leak,
even if an exception is thrown.
Portabl E has no equivalent of EXCEPT, so things that should only happen during
an exception must be contained within an IF exception ... ENDIF statement.
FINALLY does a couple of things which EXCEPT DO does not. First, it
automatically rethrows any exception at the end, so that exceptions cannot be
accidentally lost. Use exception:=0 if you want to clear an exception. Second,
it is always executed, however you exit the procedure - even if you use
RETURN! This means that your clean-up code really does need to be in only one
place - so no more accidental memory leaks...
Portabl E is heavily focused on improving OOP, which was a bit basic in AmigaE.
But OOP is far too big a subject to tackle in one page, which is why it has it's
own chapter later on. But I can still give you a taste of the differences right
now:
PROC main()
DEF test:PTR TO example
NEW test.new()
test.set('Portal is a great game\n')
Print( test.get() ) ->This prints "Portal is a great game"
FINALLY
END test
ENDPROC
CLASS example
string[20]:STRING
ENDCLASS
PROC new() OF example
StrCopy(self.string, 'default')
ENDPROC
PROC set(string:ARRAY OF CHAR) OF example
StrCopy(self.string, string)
ENDPROC
PROC get() OF example IS self.string
The first difference is that any procedure, such as main(), can refer to the
example object - even if it is declared after that procedure. This means you
can put your code in the order which makes most sense to you, rather than the
order that the compiler wants.
With AmigaE, if a variable like test could be ENDed when an exception was
thrown, then it should be initialised to NIL, so that END could never be passed
a nonsense value. But Portabl E guarantees that all pointers are initialised to
NIL, so we don't need to. In fact, within DEF you cannot initialise any
variables, for a good reason which is explained elsewhere.
The next difference is that objects with methods are known as classes. Such an
object must (eventually) inherit the class object, and we can ensure this if
we declare the object using the CLASS keyword (instead of OBJECT).
Another useful difference is that classes can contain preallocated arrays, such
as the fixed-size e-string in this example. So we don't have to remember to
allocate it in the new() constructor (nor deallocate it later).
Apart from strings being ARRAY OF CHAR, the rest of the code is standard AmigaE,
albiet type-checked! But there is a hidden requirement that you should be aware
of:
Portabl E needs to know which methods are constructors. Either we hint at that
with the method's name, or we must explicitly say so using a keyword. If the
method's name is new(), or it begins with "new" & is then followed by a capital
letter, such as newThing(), then it is assumed to be a constructor. But if your
constructor needs a different name, then you must use the NEW keyword like this:
PROC myConstructor() NEW OF example
Another thing which happens automatically is that the return type of the in-line
method get() is deduced to be STRING, because it returns "self.string". But
what if we don't want the user to get an e-string, because he might try to
modify it? Then we must cast the returned e-string to a plain old string:
PROC get() OF example IS self.string!!ARRAY OF CHAR
As you see here, the !! symbol is used to cast whole types. Note that you can
still use :: to cast something as a pointer to an object. Alternatively, we can
specifically declare the return types:
PROC get() OF example RETURNS value:ARRAY OF CHAR IS self.string
It's worth mentioning that when a child class inherits from a parent class,
Portabl E places restrictions on the procedure parameters & return values of the
child class, to ensure that the child can always be used where the parent is
expected. But it is more flexible than AmigaE, because it allows the child
class to have more procedure parameters than the parent. Please read the
16. Object orientation chapter for a full explanation.
This whirl-wind tour of Portabl E has only covered some of the more obvious
changes - there are many more improvements, as well as a few things which have
been lost from AmigaE. So I strongly recommend that you read some of the later
chapters (particularly from 8. How to compile your old AmigaE programs up to
13. AmigaE features that are missing). But don't let that stop you from
experimenting - Portabl E will warn you of most problems!
The other changes include: RAISE now works with user procedures and methods
too! Modules are more flexible. For procedures & methods that return objects,
you are allowed to do something like procedure().method().member . Constant
names can be most keywords. You can have 5 return values. ELSE IF is normally
used instead of ELSEIF. exceptionInfo replaces exceptioninfo. E-list linking
is not implemented. EXIT is not yet implemented, but ENDWHILE IF & ENDFOR IF
reduces the need for it. JUMP is not supported.
I am willing to try to increase Portabl E's backwards compatibility with AmigaE,
but please be aware that some things are not easy to fix, and a few things are
impossible if Portabl E is to remain truely portable.
Go back to CONTENTS
The main Portabl E command is PortablE without a space.
For the Amiga, PortablE requires a 100KB stack, and will refuse to run with
less. Either have the STACK=100000 tooltype set in your Shell's icon, or
otherwise type this before running PortablE:
Stack 100000
Linux & Windows users do not need to worry about the stack.
PortablE is a Shell program, and it's parameter template is:
Source/A, TargetFile/K, TargetOS=OS, TargetLanguage=Lang,
OptOptimise/S, OptPointer/S, OptAmigaE/S, OptNoPtrToChar/S,
NoOptInline/S, NoListOptim/S, RefreshCache/S, Obfuscate/S, NoOptInlineVarargs/S
- Source is the source file, from which it will generate the target code.
- TargetFile is the optional file, where the target code will be
written. If nothing is specified, then it will be based upon the source file
name.
- TargetOS (or just OS) is the optional OS choice, for which the target code
will be written. The current choices are "Linux", "Windows", "AmigaOS3",
"AmigaOS4", "AROS" & "MorphOS" (excluding quotes), but anyone can add support
for other OSes. It defaults to the OS that the PortablE executable is compiled
for (which is the current OS unless you ran the AmigaOS3 version on AmigaOS4 or
MorphOS).
- TargetLanguage (or just Lang) is the optional programming language choice,
which the target code will be written using. The current choices are "CPP" (for
C++), "AmigaE" & "ECX". It defaults to "CPP".
- The switch OptOptimise enables OPT OPTIMISE for all modules.
- The switch OptPointer enables OPT POINTER for all user modules.
- The switch OptAmigaE enables OPT AMIGAE for all user modules.
- The switch OptNoPtrToChar enables OPT NOPTRTOCHAR for all user modules.
(See 7.2. Module options (OPT) for more info on specific OPTs.)
- The switch NoOptInline DISables OPT INLINE for all modules.
- The switch NoListOptim disables any optimisations for immediate lists that
would initialise static items well before the list is used (unlike dynamic items
which must always be initialised just before the list is used). This is handy
if you want the target code to be more human-readable (and don't mind it being
less optimised).
- The switch RefreshCache prevents the module cache from being read, and so
regenerates all the module cache files for the current target. This is handy if
you run into a bug in the module cache, but please report it!
- The switch Obfuscate causes the chosen module to be obfuscated, and then
written back out under a new file name (ending in _OBFUSCATED.e). See the
following 5.4. Obfuscation mode sub-chapter.
- The switch NoOptInlineVarargs DISables OPT INLINE for NATIVE procedures
with varargs (i.e. procedures with a ... parameter) of all modules, and must be
used with the NoOptInline switch.
WARNING: This causes incorrect to be generated, which must not be executed.
It is only intended to be used for testing that NATIVE modules will generate
compilable code.
For the Amiga, if you haven't already followed the stack warning given at
the beginning of this chapter, then type the following in your Shell first:
Stack 100000
To compile the program Work:Code/PE/example.e, you would enter the following
line:
PortablE Work:Code/PE/example.e
Similarly, for Linux users to compile the program ~/Code/example.e,
they should enter:
PortablE ~/Code/example.e
Similarly, for Windows users to compile the program C:\PortablE\Code\example.e,
they should enter:
PortablE C:\PortablE\Code\example.e
It should not take long to compile, although it has to use some large system
modules - which will slow it down UNTIL their module cache files have been
automatically created (the first time they are used).
The end result should be the file example.cpp in the same folder, which you
can then compile using a C++ compiler. (Note that PortablE can also generate
AmigaE v3 compatible code, even when using new features not supported by
AmigaE.)
To compile the C++ code for all Amiga targets on Linux (and possibly Windows)
please see the 6.2. Cross-compilation of C++ code sub-chapter.
Alternatively, you can use the PEGCC program to combine both of those steps,
so that it automatically compiles the generated C++ code into an executable.
You use it just like PortablE:
PEGCC Work:Code/PE/example.e
or
PEGCC ~/Code/example.e
or
PEGCC C:\PortablE\Code\example.e
The end result should be an example executable file.
In addition to PortablE's shell parameters, PEGCC has these additional
parameters:
TargetDir/K, LeaveTargetFile/S, NoStrip/S, Debug/S, GccOpts/F/K, Run/S, RunUsing=Using/K, RunParams=Params/F/K
- TargetDir is the optional folder, where the target code will be
written. If nothing is specified, then it will be the same folder as the source
file.
- LeaveTargetFile is a switch, which causes the intermediate .cpp file
to be kept.
- NoStrip is a switch, which prevents PEGCC from stripping the executable.
This means larger executables, but they may be easier to debug (at least on
AmigaOS4 & AROS).
- Debug is a switch. It acts as if you supplied NoStrip LeaveTargetFile
GccOpts -g, which is ideal for use with Addr2Line if your OS supports crash
stack traces (as AmigaOS4 & AROS do).
- GccOpts is a keyword, which causes everything after it (such as -O2) to
be passed on to GCC.
- Run is a switch. It causes the executable to be run by the Shell, if it
compiled.
- RunUsing is a keyword, which allows you to say how you want it to be
executed by the Shell (if the Run switch is used). e.g. WbRun, Run, Timer
- RunParams is a keyword, which allows Shell parameters to be passed to the
executable (if the Run switch is used).
Similarly, you can use the PE-EC script to automatically compile the
generated AmigaE code with EC (if it is installed on your Amiga).
The Obfuscate switch causes the chosen module to be obfuscated, and then
written back out under a new file name (ending in _OBFUSCATED.e).
This makes the module almost unreadable by people, but it should behave exactly
the same as the original. Some of the ways it obfuscates a module:
- Comments are removed (except for any /*comments*/ before the first keyword
that is not OPT or MODULE).
- Multiple spaces & tabs (such as indenting) are removed.
- Lines are joined by semi-colons, where possible.
- It changes the names of all PRIVATE elements (and local variables), so you
can't easily tell what they are supposed to do. The names of constants, types,
variables, procedures, methods & objects will overlap, making it difficult to do
a simple search & replace on them. Even names within one type of element (e.g.
variables) will tend to overlap each other! The very similar (and repetitive)
names also makes it hard to tell them apart.
- Values & private constants are replaced by two cryptic numbers XORed together.
This makes it hard to tell what it is supposed to be.
- Procedures will be inlined where possible.
- Immediate strings are moved.
Obfuscation does have some unavoidable limitations:
- If you use OPT PREPROCESS then it is possible (but not certain) that the
obfuscated module will only work for the currently chosen target. This will
happen if you use some target-specific macros, so it is best to put
macro-dependant stuff (like MUI code) in a separate module. A warning will be
given to remind you of this.
- Only PRIVATE elements (and local variables) can have their names obfuscated,
so make sure you mark as many things private as possible.
- The module cache will be read, but not updated.
- Obfuscating a module is a bit slower than just parsing it (perhaps half the
speed).
In case anyone wonders, the reason for obfuscating a module is if you want to
release it publically, but you want to discourage people from modifying it &
releasing their own version. This should be nearly (but not quite) as effective
as releasing a binary blob (e.g. a .o file), like you can do for some other
languages. And it should be at least as effective as compiling Java code, since
Java 'binaries' can be automatically turned back into source code (minus the
comments, names of private elements, etc).
This shell program recursively deletes all .PEM (module cache) files. It's
parameter template is:
Folder, Verbose/S
If no Folder parameter is specified, then it defaults to the whole
PEmodules: folder, which is usually what you want. (In some cases you might
have local (i.e. *) modules, which are stored outside of PEmodules: )
If the Verbose parameter is specified, then it reports the path of every
module cache file that is deleted.
NOTE: Currently this program handles both the old-style module cache files
(which are stored in the same folder as the source module itself), and the
new-style module cache files (which are always stored somewhere inside
PEmodules:PE/cache ). At some point support for the old-style module cache
files will be dropped.
This shell program checks that all module cache files correspond to source code
that still exists, and deletes the cache files if not.
You shouldn't normally need to use this, as PortablE automatically does it
gradually for you anyway (every time it is run). It's only provided for
occasions where you've moved or deleted a large quantity of modules, and can't
bear to think of all that wasted disk space!
NOTE: This program only works with new-style module cache files (which are
always stored somewhere inside PEmodules:PE/cache ).
Go back to CONTENTS
Older C++ compilers (as often used for the Amiga) have their own bugs, and also
have different restrictions on what C++ code is allowed. So it has proven
tricky to get the C++ code generated by PortablE to consistently work, but so
far I have managed it for all the compilers available to me. However, I have
not tested everything, nor have I tested every single version of every C++
compiler. So please email me if you find any problems with the C++ code
generated by PortablE.
Each compiler I've tried has it's own quirks:
- GCC v2.95.3 to v9.4.0 should work, but you MAY need to use the option
-noixemul to get it to compile (particularly for AmigaOS3 & MorphOS).
If you use the PEGCC command, then this automatically calls GCC with any
necessary options.
- AmigaOS4 SDK 54.16 (which uses GCC). Beware that GCC v8 (the default) &
newer versions fail to compile C++ programs, so you must use GCC v6.4.0 .
If you use the PEGCC command, then this automatically uses GCC v6.4.0.
- MinGW v0.6.3 (which uses GCC). Works without any problem on Windows.
- AmiDevCpp v0.9.8 (which uses GCC). Go to the menu Project/Project Options,
choose the Parameters tab, and then add -noixemul to the Linker parameters.
You can have this automatically done for all projects, by going to the menu
Tools/Compiler Options, and choosing the Compiler tab. Add -noixemul to the
linker command line (which is the second box). Note that Windows, Linux & AROS
do not need nor support -noixemul, while MorphOS requires it.
- StormC v3 has not been tested in some time, although it used to work... with
some caveats: It does not handle exceptions (try/catch) properly, unless the
Compiler Settings has it's Optimizer set to level 5 or lower. You should also
check that Exceptions are enabled. It also has lots of other wierd bugs.
- StormC v4 is untested, but it may work fine since I heard it uses GCC.
- Microsoft Visual C++ has not been tested in some time, although it used to
work. Please report if you have any problems, or if it works for you.
Note that OS4's 'libraries/mpega' module was modified to work with the corrected
headers from:
www.os4depot.net/index.php?function=showfile&file=development/example/mpega_demo.lha
PortablE supports generating C++ code for OSes other than the current one, using
to the TargetOS parameter. However, you still need to compile that code - which
won't work without a special version of GCC.
You can get special "cross-compiler" versions of GCC for Linux from here:
cshandley.co.uk/crosscompilers/
Once installed, you should be able to use PEGCC with the TargetOS parameter.
Or if you use Windows, then AmiDevCpp did support compiling for other Amiga
OSes - but it's no-longer available:
web.archive.org/web/20160509140125/http://amidevcpp.amiga-world.de/index.php?HR_LANG=english
I still have copies of the main AmiDevCpp downloads, if there is any interest...
The code generated is AmigaE v3 code, which is compatible with CreativE. It is
not completely compatible with ECX - but you can use TargetLanguage=ECX
(instead of =AmigaE) to make the code completely compatible with ECX.
Warning: The ECX mode is a slight hack, because it uses the same modules as
AmigaE, and it shares the module cache with AmigaE. The upshot of this is that
if you compile something for AmigaE, compiling it again for ECX will not
generate ECX compatible code, unless you use the REFRESHCACHE option. Therefore
I recommend that you either use "AmigaE" or "ECX", but not both. The ECX code
can still be compiled by AmigaE.
Beware that AmigaE has a bug where SUPER methods cannot be called when they have
the same name as a member in any object (even from an OS module). Making
PortablE work-around this bug would make the generated source code look very
messy, and in the case of the end() method it is not really possible to fix. I
have an unreleased version of the CreativE that fixes this problem, and if you
are interest then please ask it's author (Tomasz Wiszkowski) about it. I
suggest using his GMail address, which can be found here:
web.archive.org/web/20130322222429/http://www.tbs-software.com/fp/author.phtml
Go back to CONTENTS
Portabl E expects that the code for any module ends with .e, and can be found
using the PEmodules: assignment.
Portabl E requires several special "system" modules; most of these modules are
stored within the main PE folder, but some of them are stored inside PE
folders that can be found within the target folder. There are also system
modules within the targetShared folder. Please do not try to use these
modules yourself!
The target folder is special, as it allows the same module declaration to
refer to different implementations depending on which target your code is
compiled for, and is described later.
As with AmigaE, module paths starting with * use local paths (i.e. paths which
start in the same directory as the current file).
The automatic module cache provides a big speed boost (up to 3 times faster), by
storing the result of parsing a module for re-use next time, somewhat like
.o files in traditional compilers (and .m files in AmigaE). Each module
cache ends in .pem .
But the cache will not be used for modules that have been modified, nor for
modules that depend on modified modules. So modifying a low-level module
(upon which most modules ultimately depend) will temporarily loose you the
speed benefit of the module cache.
Also, the module cache will (temporarily) not be used when you change one of the
command line OPT switches, such as OptOptimise or OptAmigaE. So I strongly
recommend being consistent in your usage of such switches.
PLEASE DO NOT replace any module cache files (which end in .pem) with
different or backup versions, as this could break the logic used by the
automatic module cache (unless you use the REFRESHCACHE switch). But you can of
course replace the module files themselves (which end in .e) with different
or backup versions.
Like AmigaE you can specify module options using OPT . The current options are:
- OPT OPTIMISE enables optimisations (including OPT INLINE).
- OPT INLINE enables in-lining of procedures declared in this module.
- OPT POINTER enables pointer arithmetic/manipulation support.
- OPT AMIGAE enables the AmigaE backwards compatibility mode, including pointer arithmetic/manipulation.
- OPT NOPTRTOCHAR stops variables defaulting to PTR TO CHAR, when OPT AMIGAE is used.
- OPT NATIVE enables the use of NATIVE target language elements.
- OPT PREPROCESS enables the preprocessor.
- OPT ELSEIF enables the use of ELSEIF but disables ELSE IF support.
- OPT STACK=N requests a minimum stack of N bytes for the program, but it must be supported by the target compiler.
- OPT MULTITHREADED enables multi-threading support in a program.
You can apply certain options to all modules from the command line (see the
earlier 5. Usage of the compiler chapter). The original AmigaE options are also
present, but they do nothing.
This is not (yet) as good as the GCC optimiser, and it will impair the GCC
optimiser, thus resulting in a slower program if you use the GCC optimiser
as well! So it is currently only recommended for target languages that are
badly optimised (such as AmigaE).
But you may wish to use OPT INLINE instead, as this can give a significant
speed-up, without impacting GCC's optimiser.
Portability will be impaired - it will not be possible to generate code for
target languages which do not support real pointers, like Java. Better to use
arrays if you can, but it's your choice :-)
I suggest restricting this to (low-level) modules that absolutely require it,
so that only those modules need rewriting if you want to support more target
languages later.
Portability will be impaired - it will not be possible to generate valid code
for strongly-typed target languages, such as Java.
It also tends to produce messy C++ code, because untyped variables have the type
PTR TO CHAR (rather than VALUE), yet C++ has many restrictions on the use of
pointers that must be avoided using casts. You can avoid messy C++ code by
using OPT NOPTRTOCHAR.
This is only useful for source code that was generated using OPT AMIGAE, as it
stops untyped variables from defaulting to the PTR TO CHAR type. Obviously it
reduces compatibility with AmigaE code, but usually you just have to declare a
few variables as being PTR TO CHAR when Portabl E gives an error that they can't
be indexed as an array.
Apart from preventing messy C++ code being generated, it used to be
necessary to work-around wierd C++ compiler errors like "cast from 'char*' to
'XXX' loses precision" or "cast to pointer from integer of different size". If
this option fails to solve such compiler errors, then please let me know.
Portability could be completely lost - so you are strongly recommended to not
use it, except for low-level abstractions (modules) that will need to be
rewritten for every target language/OS.
For best speed, multi-threading support is normally disabled in programs
compiled by Portabl E. But if you use this option in your main program, then
multi-threading support is enabled for the whole program.
Without it, semaphores (and some internal) functions are 'dummies' that
literally do nothing. But if you use this option then the semaphore/etc
functions are properly implemented. This allows you to write functions that
support multi-threading (using semaphores), but avoid the multi-threading
overhead unless your program is multi-threaded!
And in particular, FastNew()/FastDispose()/NEW/END have multi-threaded support,
but they won't be slowed down by it unless you use OPT MULTITHREADED.
WARNING: Unless you use the 'CSH/pAmiga_fakeNewProcess' module to create a
new process on the Amiga, you will find that certain Portabl E features do not
work (reliably) with multi-threaded programs:
- Multiple return values (except for the first return value) may be incorrect.
- Exceptions & FINALLY will cause strange program behaviour, and even crashes,
if used outside of the main thread. Since FastNew() and NEW can raise a "MEM"
exception when you run out of memory, this means it is not a good idea to use
them in child threads. But FastDispose() and END are perfectly safe.
Note that using the 'CSH/pAmiga_fakeNewProcess' module will mean your new
processes will not share their global variables. So if you want to share
any state, you must pass a pointer to it when the process is created.
Go back to CONTENTS
There are a few restrictions on compiling your old programs using Portabl E:
- You need all of the source code (even for modules), since pre-compiled 68k
modules are not supported (and wouldn't work with most targets anyway).
- A few (usually rarely used) features are not supported - please see the
13. AmigaE features that are missing chapter.
- Many but not all Amiga modules are provided (see the 2.3. Current status
sub-chapter of the "Introduction" chapter).
- You can only compile them for Amiga-like OSes, and thus NOT for Linux or
Windows.
If these restrictions are no problem, then have a go! And please email to let
me know how you get on - good or bad :-)
While you can just try compiling with the OptAmigaE switch, and then fixing
errors as they are reported (see the 8.2. Compatibility hints sub-chapter for
hints), you will likely have less problems if you follow these suggested steps:
1.First skim the 12. Other changes from AmigaE &
13. AmigaE features that are missing chapters, to get a feel for any problems you
may encounter.
2.You should compile your program using both the OptAmigaE and OptPointer
switches (see an earlier chapter), to enable maximum compatibility for all
modules. You will probably still get a few errors, which will need to be fixed,
so read the following 8.2. Compatibility hints sub-chapter for help. If you get
many errors of a particular kind, which you think are silly, then please email
me, and I will see what I can do...
If you run across missing modules, then you might like to consider porting them
too (if their E source code exists). Or if they have C++ counterparts, then I
might be willing to add native support for them - and any help doing that would
be most appreciated (I have a semi-automated tool that greatly reduces the effort
required, please contact me for details).
3.If you got your old program to compile, you can now take the generated target
code (which will be C++ unless you said otherwise), and use it with a 'real'
compiler. Run the program to see if it works. If not, then check your E code
for assumptions which may no-longer be true, and if that fails then try
debugging the generated (C++) code (in case that contains a mistake).
It USED to be the case that some C++ compilers gave errors like "cast from
'char*' to 'XXX' loses precision" or "cast to pointer from integer of different
size" when you used the OptAmigaE switch. This should no-longer happen, but if
it still does then please let me know (although a work-around is to use the
OptNoPtrToChar switch).
4.Assuming that your program actually compiles & runs OK, then you should stop
using the OptAmigaE switch (but keep using the OptPointer switch). You will now
have to modify your program to stick to Portabl E's stricter rules, particularly
it's type-checking rules. So read the 11. Reversible changes from AmigaE &
15. The type system chapters.
If an untyped variable is treated as an array, you will usually need to change
that variable's type to ARRAY OF CHAR.
If a variable is of the wrong type, then you should first try changing it to the
correct type. If there is a conflict in the expected type of a variable, then
you could try using the parent type shared by those different types (see the
type diagram in 15. The type system chapter). Only rarely & as a last resort
should you need to use !! to cast the variable to the required type; read the
15.9. Casting hints sub-chapter of the "The type system" chapter if you get stuck.
5.Finally, you can try to get rid of direct pointer manipulation in some
modules, say by replacing pointers with arrays. For any modules where you can't
do this, you will need to add OPT POINTER to it. You can now stop using the
OptPointer switch!
6.After that you might like to consider how you can use some of Portabl E's funky
new features... So read the 9. New features compared to AmigaE & 10. Current improvements over AmigaE chapters, and maybe the 16. Object orientation chapter
too.
Here are solutions to common problems that you may encounter when trying to
compile your old programs using the compatibility mode:
- ARRAY does not default to ARRAY OF CHAR. It now has a different purpose,
which will likely cause an error in existing AmigaE programs, so you need to
replace "ARRAY" with "ARRAY OF CHAR".
- You are warned that the code "var[]++" behaves differently in Portabl E.
Replace it with "(var++)[]". Similarly, replace "var[]--" with "(--var)[]".
- You got an error with "var[]++ := foo" and tried replacing it with
"(var++)[] := foo", but that doesn't work either. Instead you must replace it
with "var[] := foo", and then follow it by the statement "var++". If you don't
mind changing what value it returns, then you could simply replace it with
"(var[] := foo) BUT var++". For -- it would be "var-- BUT var[] := foo".
- With RETURN you are told "more return values than declared". This is because
you must declare the types of all the returned values, either at ENDPROC or
using the new RETURNS keyword. The proper way to do this is to declare a
variable of the appropriate type, and then place that after ENDPROC. Or
otherwise simply put those variables after RETURNS at the end of the PROC line.
- Labels & JUMPs are not allowed. If you are JUMPing backwards, then you need
to replace it with some kind of loop. If you are JUMPing forwards, then you
need to replace it with an IF statement.
If you are JUMPing out of a loop or other structure, then it gets a little more
complicated - you will usually need to use a variable to remember that the
loop/etc should be left immediately, and then use that variable with the
appropriate replacement loop/IF. See below for an example.
You could easily modify it, like this code:
DEF exit
WHILE test
IF (exit := foo()) = FALSE
test := bar()
ENDIF
ENDWHILE IF exit
Which is not so pretty, but in this case it can be rewritten a bit better as:
IF test
WHILE foo() = FALSE
test := bar()
ENDWHILE IF test = NIL
ENDIF
Minor differences in the original code could allow it to be simplified much
better than this.
- For a method you are told "object is not a CLASS". Objects with methods must
inherit from the "class" object, so just add "OF class" to the object's
definition, for example "OBJECT foo OF class". Or you can replace
OBJECT/ENDOBJECT with CLASS/ENDCLASS.
- If you have ^ptr then simply replace it with GetLong(ptr), or even ptr[] if
ptr is declared a PTR TO LONG or ARRAY OF LONG.
- If you need to pass the the address of a {variable} then use the ADDRESSOF
operator. For example, if you start with this code:
DEF var=123
test({var})
Then you can easily modify it, like this code:
DEF var
var := 123
test(ADDRESSOF var)
- If you need to pass the address of a procedure then simply replace
"{procedureName}" with "CALLBACK procedureName()". This gives you the
required function pointer. However, if the function pointer is never passed to
the OS, then it could be worth considering using FUNC procedures instead, as
these are safer & more portable.
Note that you need to use OPT POINTER for CALLBACK to be supported.
Note that unlike AmigaE, your callback procedure cannot have less parameters
than it will be called with. For example, hook procedures MUST have 3
parameters.
Or if it does not return a value, then use "call2empty" instead of "call2". And
make sure that all parameters (and any return value) of the function have the
default type (i.e. VALUE), or else the compiled code may crash.
Or if it returns multiple values, then use "call2many" instead of "call2".
This last function is not yet available for AmigaE targets.
However, if the function pointer originated from within the E code, then it
could be worth considering using FUNC procedures instead, as these are safer &
more portable.
Q.What is the type given to something like "DEF variable" without a specific
type?
A.The type is VALUE, hence it is equivalent to "DEF variable:VALUE". Well,
unless you use the AmigaE compatibility mode, as that defaults to PTR TO CHAR.
Q.Why can't I pass a string to my PTR TO CHAR parameter?
A.That's because strings are now ARRAY OF CHAR . But you can temporarily allow
it by enabling the POINTER arithmetic or AMIGAE compatibility option.
Q.Which Amiga modules are supported?
A.Please see the 2.3. Current status sub-chapter of the "Introduction" chapter. Or
You can see exactly what is supported, by looking within PEmodules: but
ignoring the PE, target & targetShared folders.
While the original idea for Portabl E was to provide abstract modules that did
not expose the OS, additional OS modules may be added if there is interest - and
any help doing that would be most appreciated (I have a semi-automated tool that
greatly reduces the effort required, please contact me for details).
Q.I want an in-line procedure to call another procedure (which returns a value),
but I don't want my in-line procedure to return that value.
A.Make it return EMPTY:
e.g. PROC meef(x) IS function(x) BUT EMPTY
Q.How do I force floating point maths, such as when dividing one integer by
another? Before I could use ! to do this.
A.What you need to do is cast one of the integers as a float:
answer := firstInt!!FLOAT / secondInt
It is wise to cast the first integer, because otherwise E's left-to-right order
of evaluation will likely mean you end-up casting the RESULT of the division -
not what you intended! (Alternatively you can enclose your cast in brackets.)
Q.Why won't it let me cast one value into a different type?!?
A.Portabl E does not allow a type to be cast to a completely unrelated type (i.e.
a different branch of the type tree), for safety reasons. However, you can
usually get around this by first casting to the VALUE type. For example:
DEF string:STRING, number:INT
number := string !!VALUE!!INT
So Portabl E still allows bad or unsafe casts, but they are not as easy to do,
which I think is good language design, since bad code should be harder to write.
It is also easier to search for unsafe casts.
Q.Why does it tell me the "return type is less restrictive than for the
inherited method"?
A.You must either make the parent method's return type more general (bigger), or
you must make the current method return a less general (smaller) type. Have a
look at Portabl E's type diagram. To help you decide, you will be told the
return type of both the current method & the inherited method.
Or, if you don't need to pass your current object where the parent is expected,
then you can simply declare that your object is an ORPHAN, then declare that
method is an ORPHAN.
Q.Why does it tell me the "return type is different for the inherited method"?
A.Either you must make the parent method's return type be more general
(bigger) than that returned by your current method, or if you don't need to pass
your current object where the parent is expected, then you can simply declare
that your object is an ORPHAN, then declare that method is an ORPHAN.
Go back to CONTENTS
To make the large list of funky new features easier to digest, I have grouped
them into sections.
- The compiler has been carefully designed with the future in mind, it uses a
modern object-orientated design, is entirely written in E, and is able to
compile itself :-) .
- All used modules (and modules used by them, etc) are automatically found,
compiled & cached, so no need to worry about out-of-date modules, manual make
files, or complex IDEs.
- Circular module references are automatically detected & an error is reported,
to prevent ambiguous code. AmigaE allowed them, even though it caused serious
problems.
- Standard modules that work on all supported platforms, including Linux &
Windows.
- Modules now support set-up & tidy-up procedures, called "new()" and "end()"
respectively. This allows automatic initialisation & clean-up of a module's
global state, on entry to & exit from the program's main() procedure. This is
extremely handy for any modules which use global variables (say for holding an
object), or which need to make initialisation calls to the OS (say for loading a
library). Note that neither new() nor end() may be called directly.
- RAISE works with user-defined procedures, so you can let the user of a module
decide when exceptions should be raised, rather than forcing particular
exceptions upon him.
- RAISE works with method calls too! Instead of the procedure name, simply use
the object name followed by a dot and then the method name. Such declarations
also cover child objects, with the "closest" parent object being used in case of
conflicting declarations.
e.g. RAISE "demo" IF objectName.methodName() = NIL
- You can define STATIC globals that contain a static immediate string or list.
So no more need for hacks like VOID or #define! You can think of them as a
cross between globals & constants.
e.g. STATIC foo = 'immediate string'
STATIC bar = [1,2,3]
- MemCopy() is provided, so you no-longer need to rely on Exec's unportable
CopyMem() procedure. The only difference is that the first two parameters must
be swapped. N.B. There are also matching StrCopy(), ListCopy() and ArrayCopy()
procedures.
- New() now has the second parameter "noClear=FALSE:BOOL", which allows you to
request that time isn't wasted clearing the allocated memory, although some
targets may ignore this request.
- The target module folder is special. For example, when generating C++
code for AmigaOS3, the declaration MODULE 'target/Foo' would use the module
file 'PEmodules:target/CPP_AmigaOS3/Foo.e'. When generating AmigaE code, the
same declaration would use the module file 'PEmodules:target/AmigaE_AmigaOS3/Foo.e'.
So the same module declaration can refer to a different module file for each
target - so that different implementations can be used when necessary.
Different implementations can share (some of) the same code (from other modules)
using PUBLIC module declarations (see below).
- Advanced users can 'join' modules together, by declaring certain modules are
visible from inside other modules. Any such module declarations must begin with
PUBLIC MODULE, rather than just MODULE. This is very handy for modules which
expose their reliance on other modules, as previously the user of such a module
would need to remember to add several modules together.
- There are various preprocessor macros that tell you which language & OS your
program was compiled for:
pe_TargetOS_AmigaOS3
pe_TargetOS_AmigaOS4
pe_TargetOS_AROS
pe_TargetOS_MorphOS
pe_TargetOS_Linux
pe_TargetOS_Windows
pe_TargetLanguage_CPP
pe_TargetLanguage_AmigaE
You can use these with #ifdef & #ifndef to enable or disable sections of code
for different targets. They are best used to work-around subtle differences
between different Amiga-like OSes. But you are strongly advised to use the
special target module folder instead, if: (1) You have large sections of
code (especially whole procedures) for different targets, or (2) You have a
different section of code for every target OS.
- The pe_TargetLanguage & pe_TargetOS static strings tell you which language &
OS your program was compiled for. They are the same as the parameter that you
can pass to the compiler, such as 'CPP', 'AmigaE', 'AmigaOS3' and 'AmigaOS4'.
- You usually don't need to fake stuff with the preprocessor anymore, due to
improvements & new features of Portabl E. For example:
Instead of #ifdef/#endif, you can use IF/ENDIF with a real constant, and
replacing "#define MAGIC_SWITCH" with "CONST MAGIC_SWITCH = TRUE". Any such IFs
will be "inlined" or omitted when optimisations are enabled.
Instead of #define stringName 'a string' or #define listName [1 2 3], you can
use STATIC stringName = 'a string' or STATIC listName = [1 2 3].
Instead of #defining a complex constant, you can simply use a real CONST.
Instead of defining a preprocessor procedure like #define fakeProc(foo), you can
replace it with a real in-line procedure. For example, replace
"#define MAX(a,b) (IF (a)>(b) THEN a ELSE b)" with
"PROC max(a,b) IS IF a>b THEN a ELSE b". And unlike macros, procedure calls can
be used with parameters that have side-effects, and you don't have to enclose
variables within brackets.
You can also cast to pointers or arrays, although pointer manipulation must be
enabled if the value is not already a pointer or array.
e.g. string := value!!ARRAY OF CHAR
Arrays can also be dynamically allocated with NewArray(sizeInItems, sizeOfItem),
and deallocated with DisposeArray(array).
e.g. bar := NewArray(5, SIZEOF LONG)
DisposeArray(bar)
But NewArray() can only be used when pointer arithmetic is enabled, since it
may not be implementable in a Java-like language; this is enforced using a
type-checking kludge that may give an odd error message.
Note that ArrayCopy()'s offset parameters are in items not bytes.
- StrCopy() and StrAdd() have a fourth parameter, which allows you to specify at
what position/index the plain string should be read from. This means you
no-longer need to use pointer arithmetic.
- Added StrCmpNoCase() and OstrCmpNoCase(), which are case-insensitive versions
of StrCmp() and OstrCmp().
- Added StrJoin(), which efficiently joins the supplied strings into one
e-string.
- Any character value can be put in a string using the escape code \xHH where HH
is a hexadecimal value.
- Added the NOT, XOR, SHL & SHR operators. Note that these operators have the
same behaviour as the Not(), Xor(), Shl() & Shr() functions. In fact, Not() &
Xor() are now depreciated.
- Added ENDWHILE IF, which acts like UNTIL. This is easier to understand &
translate than EXIT, and will hopefully remove most of the need for EXIT (which
is not supported - see later).
- Also added ENDFOR IF, which has a similar purpose to ENDWHILE IF, and should
hopefully remove most of the need for EXIT.
- Added functions for dealing with endian issues: BigEndianINT(),
BigEndianLONG() & BigEndianBIGVALUE() return a value with swapped endianness,
when used on a Little Endian processor (like x86), while they do nothing to the
value when used on a Big Endian processor (like 68k or PPC). They should be
used when reading or writing a value that is stored in Big Endian format.
Similarly, LittleEndianINT(), LittleEndianLONG() & LittleEndianBIGVALUE() should
be used when reading or writing a value that is stored in Little Endian format.
While SwapEndianINT(), SwapEndianLONG() & SwapEndianBIGVALUE() always return a
value with swapped endianness, whatever processor is used. These functions
should not normally be needed, but are provided for completeness.
The original procedure can be accessed by preceeding it with the SUPER keyword,
but only from within the module declaring the replacement.
e.g. mem := SUPER New(size, noClear)
Beware that only the current module (and modules that use it) will make use of
the replacement. (The exception to this is when a PROTOTYPE procedure is being
replaced - see below.)
Beware that you are not allowed to replace the same procedure twice, from within
different modules, because that would likely result in ambiguity as to which
replacement procedure should be used. So you must be very careful when
using REPLACEMENT, because it can cause two modules to be incompatible with each
other!
However, there is nothing to stop you from replacing the first replacement
procedure. In that case you would get an inheritance-like chain of replacement
procedures, where the most recent one takes precedence over all the others.
- You can declare a PROTOTYPE procedure in a (lower-level) module, which
contains no actual code, and then later declare a REPLACEMENT procedure (in a
higher module), which contains actual code. Then all calls to the prototype
procedure will use the replacement procedure - even for modules that do not use
the module declaring the replacement.
e.g. PROC New(size, noClear=FALSE:BOOL) RETURNS mem:ARRAY PROTOTYPE IS EMPTY
- A procedure's return types are usually deduced from what it returns at
ENDPROC. For example, this procedure has the ARRAY OF CHAR return type:
PROC foo()
DEF text:ARRAY OF CHAR
text := 'bar'
ENDPROC text
However, you can explicitly state the return type using RETURNS instead:
PROC foo() RETURNS text:ARRAY OF CHAR
text := 'bar'
ENDPROC
It can also be used by in-line procedures:
PROC foo() RETURNS text:ARRAY OF CHAR IS 'bar'
Although since the string 'bar' already has the type ARRAY OF CHAR, you could
just type this instead:
PROC foo() IS 'bar'
You can also do member/method access on any expression which evaluates to an
object, such as the (IF x THEN object1 ELSE object2) expression - even when
object1 & object2 are slightly different types! This is real value
polymorphism.
- Support for PROTECTED object members, which act like PRIVATE members unless
they are accessed from a method that inherits the object.
- Run Time Type Information (RTTI) for classes (objects with methods). Please
see the 16. Object orientation chapter for full details.
Go back to CONTENTS
These changes are improvements over existing AmigaE features.
- Fixed AmigaE's faulty global exception model, so that exception really is
zero unless your procedure thows an exception. In particular, this means that
ReThrow() and "exception:=0" don't cause wierd problems in some situations.
- No need to specify EXPORT, as this happens automatically. Parts of a module
can be made private, by putting PRIVATE before them and PUBLIC after them. Both
PRIVATE & PUBLIC must be on their own line. Thus you no-longer need to write
EXPORT before 95% of your PROCs! And unlike EXPORT in AmigaE, the PUBLIC &
PRIVATE keywords are allowed in your main program, even though they technically
do nothing - so you can switch between compiling a module (for testing itself)
and using the module, without needing to (un)comment those keywords.
- Every module is allowed a main() procedure, but it cannot be called, and only
the program's main() procedure will be executed. This means that every module
can contain it's own test code, but that code will only be used if the module
itself is compiled - so no editing of the module is required. And as mentioned
above, the PUBLIC & PRIVATE keywords (which replace EXPORT) do not need to be
commented out when compiling a module as a program - so again no editing of the
module is required! It is small touches like this that should help make
Portabl E much more pleasant than AmigaE for large projects.
- Global variables (DEF) do not need to be placed before the first procedure.
- The preprocessor supports #undefine, #else, #public and #private. While the
#ifdef ... #else ... #endif structure can be all on one line if you want.
- When a macro is declared, the preprocessor will usually detect that it would
recurse infinitely, rather than waiting for the macro to be used. And there is
no arbitrary depth limit for recursion either. Plus macros may end with a
comment.
- Library bases now have the type "lib", so they can be accessed without needing
to be cast first.
- Integer maths is always 32-bit, so no need for messy Mul() or Div() calls.
(Where possible 16-bit maths will be used automatically.)
- Fixed-sized (preallocated) STRINGs & LISTs are allowed within class objects
(i.e. objects with methods).
- All pointers are automatically initialised to NIL, which means that ENDing of
objects within a FINALLY section won't try to end a random memory location.
WARNING: This may partially change in the future, so do not rely on it,
except for deallocation!
- Arrays of pointers are allowed, so you can store/access objects directly
within arrays.
e.g. DEF foo[5]:ARRAY OF PTR TO object
foo[1].method()
- Arrays can be passed around like pointers, so you don't have to use fixed-size
(preallocated) arrays, despite the stricter type system.
e.g. DEF bar:ARRAY OF LONG, foo[5]:ARRAY OF LONG
bar := foo
Unallocated arrays hold the constant NILA.
- Constants may be keyword names like PROC, except for this limited selection of
reserved keywords:
CALLBACK, EMPTY, ENDCLASS, ENDOBJECT, ENDPROC, FINALLY, IF, NATIVE, NEW,
NOT, PASS, SIZEOF, SUPER, TYPEOF.
- Constants may be initialised to other constants on the same line.
- Immediate lists can contain arbitrary expressions (AmigaE does not allow
expressions that start with a constant & are then followed by a variable, such
as [2*var]).
- Immediate lists can be empty!
- The IF statement (with a constant expression) can be used instead of #ifdef,
just like Java does to simplify the language, and also for portability.
Optimisations must be enabled.
- Complex expressions are accepted anywhere that a constant is required, as long
as it statically evaluates to an actual value (and without calling any
procedures or methods).
e.g. You can use 1+(2*3) for the value of a CONST, or in a SELECT OF statement.
- SIZEOF type is a valid constant, when "type" is a primitive like LONG.
- Assignment of multiple values works for members & arrays now.
e.g. object.member, array[index] := procedure()
- Accessing a member after a cast of another member is allowed:
e.g. var := object.member::cast.member
- The :: cast won't crash if the value is NIL.
- The :: cast is allowed after procedure & method calls.
- Method calls are allowed after the :: cast.
- Procedure names do not clash with method names within a module.
- Object members do not clash with method names within a module.
- The simple version of the SELECT statement accepts expressions, not just
variables.
- CleanUp() is no-longer depreciated, because it is implemented using exception
handling.
- Increased the maximum number of return values to 5. This could have been even
higher, but 4 is highest number that is generally useful, so 5 should cover even
unlikely situations (beyond which this way of passing values is overly
cumbersome, so a different method should be used anyway.)
- FINALLY replaces EXCEPT DO, while EXCEPT has been removed (but can be easily
emulated using IF exception ... ENDIF). Although not an obvious improvement
itself, it simplifies what was an unnecessarily complex system, and allows the
next item. (Both EXCEPT & EXCEPT DO are only available when the compatibility
mode is enabled.)
- RETURN causes the FINALLY section to be executed, so that your tidy-up code
only needs to be in one place. This is one reason why EXCEPT was removed.
- Using RETURN with fewer or no values will cause the relevant ENDPROC return
values (or RETURNS variables) to be used instead - somewhat like parameter
defaults. This allows specific variables to be used for returning values, and
then have those variables after ENDPROC, so that you can then just use RETURN on
it's own.
- Exceptions are automatically rethrown at the end of the FINALLY section, so
problems can't be accidentally hidden. [You can prevent automatic rethrowing by
putting exception:=0 before ENDPROC, should that be necessary.]
Note that exceptions are actively prevented from being thrown out of
destructor end() methods.
- Unused global variables & method parameters are never reported, while unused
local variables & procedure parameters are always reported (AmigaE was a bit
unreliable).
- You can use "self" as a local variable of a procedure without confusing the
compiler!
Go back to CONTENTS
These changes are the ones which are hidden by the AmigaE backwards
compatibility mode, or in a few cases by other means. See the 7.2. Module options (OPT)
chapter for more information on these modes.
- Procedure calls from the 'dos', 'exec', 'graphics' & 'intuition' modules are
not loaded, unless the compatibility mode is enabled. Alternatively, you can
of course still access them by declaring MODULE 'dos', etc.
- The "arg" variable is not available, unless the 'dos' module is used, or the
compatibility mode is enabled.
- The "wbmessage" variable is not available, unless the 'wb' module is used, or
the compatibility mode is enabled.
- Global variables with the same name from different modules will not be joined,
and will cause an error, unless the compatibility mode is enabled. And even
then Portabl E is unable to join globals from two or more unrelated modules - you
must use a shared module for the global.
- VOID outside of procedures is unimplemented, but you can use STATIC globals
instead to hold an immediate string or list.
- Preprocessor symbols (declared using #define) are exported from a module by
default, just like other elements in Portabl E. To prevent a symbol being
exported, you can either #undefine it at the end of the module, or you can
declare it as #private. All declarations after #private will be private, until
you use #public.
- Variables default to the VALUE type, instead of PTR TO CHAR, unless the
compatibility mode is enabled.
- The single exclamation (!) used for toggling floating-point maths is not
supported, unless the compatibility mode is enabled. But even when enabled,
note that floating-point values must be stored in a variable of type FLOAT.
- Pointer manipulation (& arithmetic) is disabled by default, as it won't work
for Java-like target languages, and it also makes your programs harder to
understand. BUT you can easily enable pointer manipulation, should it be
necessary or should you not care about portability.
- You can't treat pointers as arrays (or vice versa) any more, but arrays may be
passed around, so this shouldn't be a problem. Thus pointer[index] is illegal.
Unless the pointer arithmetic or compatibility option is enabled.
- Strings are now ARRAY OF CHAR, because you can't treat pointers as arrays any
more. Unless the pointer arithmetic or compatibility option is enabled.
- "NEW array[size]" does not allow "array" to be a pointer type (like PTR TO
object), unless the pointer arithmetic option is enabled. END shares the same
limitation.
- "NEW pointer" does not allow pointers to non-objects (like PTR TO LONG),
unless the pointer arithmetic option is enabled. END shares the same
limitation.
- "END array[size]" does not allow a "size" expression inside the [square
brackets], unless the compatibility mode is enabled. This is because you
no-longer even need the square brackets (so "END array" would be fine), and thus
it could be wrongly interpreted as "END array[index]" when array is an ARRAY OF
ARRAY type.
- Immediate lists (like [1,2,3]) are effectively allocated on the stack, so that
they work with recursive procedures, unless the compatibility mode is enabled.
Of course, lists are still statically allocated if they only contain constants
and other static data.
- Typed lists are fully supported, with minor differences for object lists:
Missing object members are always initialised to zero (not just when using NEW),
while objects that inherit (from other objects) are not yet supported (tell me
if this is a problem!). But NEW can only create copies of object lists when
pointer arithmetic is enabled.
- Local variables do not accept initialisation values, so the variables must be
initialised separately using assignments, unless the compatibility mode is
enabled. The reason for this is that having a few initialisations hidden within
a large mass of declarations is a bad idea, while separate assignments are only
a small effort when few variables are declared.
- ELSE IF replaces ELSEIF, unless the compatibility mode is enabled, as I feel
this fits better with the rest of the language. However, if you really dislike
this change, then you can revert back to ELSEIF without the compatibility mode -
use OPT ELSEIF. That option disables ELSE IF, because it would look very messy
to allow both versions within the same source code...
- EMPTY effectively replaces NOP, unless the compatibility mode is enabled.
- INC & DEC are removed, unless the compatibility mode is enabled.
- Print() replaces PrintF() and WriteF(), unless the compatibility mode is
enabled. Print() is usually buffered, depending on the target language, but
PrintFlush() overcomes the need for unbuffered output. PrintFlush() allows you
to flush the output buffer. This is simpler & much more flexible than the
AmigaE way of having the two semi-incompatible procedures PrintF() & WriteF().
- NewString() replaces String(), unless the compatibility mode is
enabled.
- NewList() replaces List(), unless the compatibility mode is enabled.
- DisposeString() replaces DisposeLink() for e-strings, unless the compatibility
mode is enabled. END can also be used, but the variable must be of type STRING.
- DisposeList() replaces FastDisposeList() for NEW [list], unless the
compatibility mode is enabled. END can also be used, but the variable must be
of type LIST.
- GetChar(), GetInt() and GetLong() replace Char(), Int() and Long(), unless the
compatibility mode is enabled. Not only does this better match PutChar(),
PutInt(), etc, but it will allow Char() etc to be used for casting, if I decide
that's necessary.
- Xor() replaces Eor(), as this really annoyed me given I've never seen
Exclusive-OR referred to as EOR. The compatibility option restores Eor().
- The CtrlC() procedure is not available, unless the 'dos' module is used, or
the compatibility mode is enabled, OR the 'std/pShell' module is used.
- The FreeStack() procedure is not available, unless the 'exec' module is used,
or the compatibility mode is enabled, OR the 'std/pStack' module is used.
- NewM() is not available, unless the 'exec' module is used, or the
compatibility mode is enabled. And even then most of the flags are not
supported, so it is always best to use NewR() instead.
- The built-in Graphics helper functions (like Plot() & TextF()) are not
available, unless the 'graphics' module is used, or the compatibility mode is
enabled.
- The built-in Intuition helper functions (like OpenW() & Gadget()) are not
available, unless the 'intuition' module is used, or the compatibility mode is
enabled.
- exceptionInfo replaces exceptioninfo, unless the compatibility mode is enabled.
[Java-style "camel hump" naming has been adopted, and is the recommended
standard for user programs, if they wish to be consistent with Portabl E. This
may seem a trivial change, but if I can't fix aesthetic issues now, then we will
be stuck with them for a long time...]
- No need for HANDLE anymore. In fact you can't use it unless the compatibility
mode is enabled.
- NEW only accepts methods that have been specified as constructors. The
compatibility mode disables this requirement, however that means fixed-sized
(preallocated) STRINGs & LISTs will not work in objects (which AmigaE did not
support anyway), and perhaps some other new features will not work either.
A method will automatically be assumed a constructor if the method's name is
new(), or if it begins with "new" and is followed by an uppercase letter (thus
newer() would NOT be a constructor). A method may also be explicitly declared
as a constructor by putting NEW before the method's OF keyword.
e.g. PROC myConstructor() NEW OF myClass
- The members of classes (that's objects with methods) default to PROTECTED
instead of PUBLIC, unless the compatibility mode is enabled. (Objects without
methods always have members default to PUBLIC, just as before.)
Go back to CONTENTS
These changes are the ones which cannot be avoided by any special mode.
- CONST & DEF declarations must come after MODULE declarations.
- Global variables must be after an object, if they are a pointer to (or array
of) that object. Possibly fixable, but it's not really a problem.
- ARRAY does not default to ARRAY OF CHAR, but instead is used as the parent of
all other array types, like PTR is for all pointers. See the type diagram.
- Like AmigaE, NEW can be used to create dynamic array copies of typed lists,
but UNlike AmigaE you must use DisposeArray() to destroy the copy, instead of
FastDispose(). END can also be used, but the variable must be of the correct
ARRAY type.
- Fpow(x,y) is incompatible, as it sensibly performs x^y instead of the
back-to-front y^x.
- \a and \' are the only valid apostrophes in a string, hence '' is removed.
- \q and \" are the only valid quotes in a QUAD-character, hence "" is removed.
- FastDispose() cannot deallocate memory from NEW - you must use END instead (or
a matching procedure such as DisposeArray()).
- DisposeList() replaces DisposeLink() for e-lists.
- ++ & -- now behave like they do in C, so that they operate on whole
expressions (not just the first variable), thus object.member++ increments the
member not the object. And using them before/after determines pre/post
increment & decrement. This means that var-- decrements after (rather than
before) evaluation. Thankfully the compatibility mode warns when the behaviour
of ++ & -- differs from AmigaE, so that it can be corrected.
- Commas are the only thing which allows a statement to be split onto another
line. The most obvious use of commas includes CONST, DEF and CASE. [This was
done to simplify the compiler, but it may now be possible to change this if
there is enough interest.]
- The main comparison expression of CASE statements are 'read only', so that
no changes may be made to variables, etc. For technical reasons neither BUT, IF
THEN ELSE nor non-static immediate lists are allowed within those expressions
either.
- Instead of getting the address of a {variable}, you must use ADDRESSOF
followed by the variable name (typically to give to AmigaOS). It evaluates to a
value of type ARRAY OF, so that you can easily dereference it.
Note that you need to use OPT POINTER for CALLBACK to be supported.
Note that { } now has a different purpose, which is disabled by default.
If the function pointer is only used by E code (and not AmigaOS), then you
should consider using FUNC procedures instead (see below).
Note that you need to use OPT POINTER for CALLBACK to be supported.
Note that unlike AmigaE, your callback procedure cannot have less parameters
than it will be called with. For example, hook procedures MUST have 3
parameters.
But if the function pointer originated from E code, then you should consider
using FUNC procedures instead (see below).
- FUNC procedures look like normal PROC procedures, but they have an (emulated)
function pointer that can be passed around in a similar way to what AmigaE
allowed, except that it is type-safe. See the 17. Functional programming chapter
for more details.
- Exceptions are actively prevented from being thrown out of end() methods.
- The end() method cannot take any parameters, nor return any values.
- The main () method cannot take any parameters.
- Unused procedures are not reported.
- OBJECTs with methods must inherit from the 'class' object, or you can
implicitly do this by using the CLASS keyword instead of OBJECT. This allows
classes to report what kind of object they are, as well as other Java-like
features.
Go back to CONTENTS
- E-list linking is unimplemented, mainly because I hope that e-lists can be
directly implemented using arrays (that know their size) in Java-like languages.
- ^ is unsupported, but there have been better ways to do it since at least
AmigaE v3, thus they have been depreciated for over 10 years anyway. ^ can be
replaced by GetLong() or []. See the 8.2. Compatibility hints sub-chapter of the
"How to compile your old AmigaE programs" chapter for help.
- JUMP is unsupported, as are labels. They are simply not supported by most
modern languages, since gotos are usually considered a bad idea. I never found
a need for them anyway, as typically JUMP can be replaced by a loop or an IF
statement. See the 8. How to compile your old AmigaE programs chapter for help.
- EXIT is unimplemented, because it might cause serious portability problems
(and certainly messy code), but ENDWHILE IF & ENDFOR IF should make it less
necessary. Note that the use of EXIT can be avoided in almost all situations
anyway, with a little thought. See the
8. How to compile your old AmigaE programs chapter for help. [If this causes
many people problems, I will look at the issue again.]
- No esoteric stuff like Lisp cells, unification or quoted expressions. If you
use any of these features regularly, you may be able to help me implement them,
by explaining their subtleties!
- 68k assembler isn't supported, for obvious reasons. You must replace any such
code with proper E code, or perhaps NATIVE target code.
- Fsincos(a,b) is unimplemented, because I don't know what it's supposed to do!
Although it always seems to equal Fsin(b).
And there may be other changes I have forgotten, or maybe didn't even realise!
Please report anything that you think I may have missed.
Go back to CONTENTS
Portabl E lacks operator precedence, just like AmigaE, so all expressions are
simply parsed left to right. Parentheses must be used to group (sub)
expressions together.
e.g. w+x*y+z is parsed the same as ((w+x)*y)+z
The NOT operator does not strictly obey the left to right parsing rule, as it
operates on the first expression it can.
e.g. w+NOT x+y is parsed the same as w+(NOT x)+y
w AND NOT x OR y is parsed the same as w AND (NOT x) OR y
This choice was made, so that the presence or absence of a NOT doesn't
completely change the whole meaning of an expression. You can consider NOT to
behave in a similar fashion to the - (negation) operator.
Portabl E does not guarantee the order in which an expression will be evaluated,
but this should not be a problem since AmigaE did not either. (Of course,
anyone relying on AmigaE's current implementation will be in trouble. Slap your
wrist for using undocumented behaviour!)
e.g. x+y could evaluate x or y first, which would be a problem if you wrote
something wierd like w.set(5) + w.get(), or like (x:=5) + x
If this was a wide-spread problem (which I find hard to imagine) then I might be
able to implement a special mode that would guarantee the correct order (or even
implement it as part of the compatibility mode), at the expense of very messy
target code.
Go back to CONTENTS
The basic type relationships are shown in the picture below:

Smaller types point to the larger type that they can fit within. So BYTE fits
within INT, LONG, VALUE, etc. Thus a BYTE value may be assigned to an INT
variable, or passed to an INT parameter. Conversely, a LONG value cannot be
assign to a BYTE variable, at least not without casting it first.
The VALUE type is used for variables that do not have a stated type.
The idea is to allow anything that is physically possible & sensible, with
explicit casts being needed in the cases where it might not be possible or
sensible. This is of course a big change from AmigaE, but so far I have found
the type-checking to be much more of a help than a hinderance, and it has even
revealed some subtle bugs in old AmigaE programs that I tried compiling.
Please read the following sub-chapters for a more detailed description.
The primitive numerical types are FLOAT, VALUE, QUAD, LONG, INT, BYTE & BOOL in
order of decreasing size. Smaller types can fit within larger types, so you can
pass a smaller type where a larger one is expected. e.g. a BYTE may be used
where an INT is expected.
A quick explanation: BOOL is 1-bit and holds the values -1 to 0. BYTE is
8-bits and holds the values -128 to 127. INT is 16-bits and holds the values
-32768 to 32767. LONG is 32-bit and it's value is also signed. QUAD represents
the type needed to hold the value of 4 characters, like "abcd". VALUE is a
special type which can hold all integer types, and is the type which
variables have when no type is specified. FLOAT is a floating point type of
unspecified accuracy (typically it is the most accurate float available in the
target language). All types with X-bit sizes may be implemented with more bits,
for example BOOL may be implemented using 8-bits.
Note that this means FLOAT cannot fit within a VALUE, and so must always be cast
as an integer if it needs to be supplied to something which expects an integer.
The character type CHAR is considered smaller than (or equal in size to) INT,
but you can't pass any other type where a CHAR is expected (so it does not fit
directly between INT & BYTE). On some systems CHAR may be a 16-bit Unicode
value.
Notice that CHAR may be signed or unsigned, so if you want to compare it to a
value it is best to use "\xHH" where HH is your value in hexadecimal. However,
if that is not easy, then you can use CharToUnsigned() & UnsignedToChar().
The special type ANY is an abstract type which represents any possible type,
such as values, pointers, objects or arrays. While it may be considered similar
to the VALUE type, it cannot be used directly (unlike VALUE). Thus you cannot
write foo:ANY, or even bar:PTR TO ANY .
The special type PTR is normally used to point to a particular type, like PTR TO
LONG, but it can also be specified on it's own as PTR (without any TO ...).
PTR (on it's own) is a special type, and while most pointer types have
limitations about which pointers they can be used as, PTR may be used where any
pointer is expected. This is so that NIL can be assigned to any pointer, amoung
other uses.
A pointer to one primitive type may not be passed as a pointer to another type.
For example you cannot give a PTR TO CHAR where a PTR TO INT is expected. One
special case is that PTR TO VALUE will accept all pointers to primitive types
(although I am not sure if this is a good idea!). Pointers to objects follow
the inheritance relationships, therefore if we have declared OBJECT foo OF bar,
then PTR TO bar will accept values from both PTR TO bar & PTR TO foo.
Pointers are considered larger than QUAD (& LONG), but smaller than VALUE. Also
a PTR will not accept a QUAD, but neither will a QUAD accept a PTR.
In case it is not obvious, this means that VALUE can also store pointers, but
LONG cannot.
The special type ARRAY is normally used to hold arrays of a particular type,
like ARRAY OF LONG, but it can also be on it's own as ARRAY (without any
OF ...). Unlike AmigaE, arrays do not need to be of a fixed-sized (i.e.
preallocated using [n] ), thus they may be passed around in a type-safe manner.
No array may be passed as an array of any other type (including pointers),
therefore only arrays of exactly the same type may be passed. Arrays of classes
(i.e. objects with methods) are not allowed - although arrays of pointers to
classes are fine.
ARRAY (on it's own) is a special type, and may be used where any ARRAY (OF ...)
is expected. This is so that NILA can be assigned to any array, amoung other
uses. It also means that memory returned by New() can be used by any array.
But ARRAY may not be of a fixed-size (i.e. preallocated using [n]).
Preallocated arrays cannot be replaced by an assignment. Also, arrays may
contain any type, including pointers or arrays - but arrays of arrays cannot
preallocate the inner arrays. Thus given that strings are ARRAY OF CHAR, you
can have arrays of strings using ARRAY OF ARRAY OF CHAR, but the strings will
not be preallocated themselves. So Portabl E's arrays behave a lot like Java's.
If you use the pointer manipulation mode, then an ARRAY OF x will be accepted as
a PTR TO x, and vice versa.
Tip: While NewArray() & DisposeArray() may be used to dynamically (de)allocate
arrays, it is easier to use NEW & END on an ARRAY variable, with the size
specified in [square brackets] after the variable for NEW. And actually
NewArray() can only be used with OPT POINTER enabled, since it may not be
implementable in a Java-like language; this is enforced using a type-checking
kludge that may result in an odd error message.
Tip: ArrayCopy() may be used to copy arrays. But it can only be used with OPT
POINTER enabled, since it may not be implementable in Java-like languages;
this is enforced using another type-checking kludge.
The type STRING is an "e-string", which is a subtype of ARRAY OF CHAR (i.e. a
normal string). Since it is an array, it may be of a fixed-size (i.e.
preallocated using [n]), but unlike AmigaE it does not need to be. Thus a
procedure that expects an e-string can ensure this is the case, by specifying
the parameter like so:
PROC procedure(parameter:STRING)
Unallocated e-strings hold the value NILS.
Tip: While NewString() & DisposeString() may be used to dynamically
(de)allocate e-strings, it is easier to use NEW & END on a STRING variable, with
the size specified in [square brackets] after the variable for NEW.
Tip: StrCopy() can be used to copy a string into a e-string. Also, NEW can be
used to create a dynamic e-string copy of an immediate string, like so:
eString := NEW 'immediate string'
Similarly, the type LIST is an "e-list", which is a subtype of ARRAY OF VALUE.
So e-lists can contain most expressions, including strings. Unallocated e-lists
hold the value NILL.
Immediate lists (such as [1,2,var]) have the type ILIST, which is also a subtype
of ARRAY OF VALUE. In fact, LIST is really a subtype of ILIST, which means you
can use a LIST were an ILIST is expected (but not vice versa). Note that for
technical reasons, immediate lists cannot be used within the 'read only' main
expression of CASE statements - unless the list only contains constants.
Just as with AmigaE, you should never modify the contents of immediate lists.
None of the List functions will allow you to do so, because they expect a LIST
(which as mentioned above is not an ILIST).
Typed lists (such as [1,2,var]:INT) are plain arrays of the given type, just
like in AmigaE. You should never modify the contents of typed lists. And none
of the List functions will work on typed lists, since they are not a LIST.
Tip: While NewList() & DisposeList() may be used to dynamically (de)allocate
e-lists, it is easier to use NEW & END on a LIST variable, with the size
specified in [square brackets] after the variable for NEW.
Tip: ListCopy() can be used to copy a list (except typed lists) into an e-list.
Also, NEW can be used to create a dynamic e-list copy of an immediate list, but
they must be destroyed using DisposeList(). And in fact NEW can be used to
create a dynamic array copy of a typed list, like so:
array := NEW [1,2,3]:INT
The BIGVALUE type is only guaranteed to hold 32-bit signed values, but it will
handle 64-bit signed values if the target supports it.
The special type EMPTY is used to represent an expression which evaluates to
nothing (such as a procedure which returns nothing). You cannot declare a
variable as being of type EMPTY, and it is considered unrelated to any other
type (so EMPTY cannot be passed where any type is expected). However, EMPTY may
be used as an expression element, so that for example PROC meef() IS foo() BUT
EMPTY is a valid way to indicate that meef() returns nothing.
[It is interesting that the E guide by Wouter hints that he was considering
something like this usage of EMPTY as a future addition to AmigaE. This in turn
implies he was planning some sort of return value/type checking, however basic!]
The RANGE type allows you to specify a type which only accepts a range of
values. For example, the "RANGE -128 TO 127" type is equivalent to the "BYTE"
type. You would not often use the RANGE type on it's own, but it can be very
useful when used as part of a TYPE declaration (see the 15.7. User-defined types
sub-chapter).
You are able to create your own types, using TYPE declarations. For example:
TYPE SMALL IS BYTE
This allows you to have (say) parameters of type SMALL, and if you ever need
something larger than a BYTE, then you only need to change SMALL's declaration
(instead of editing every place that SMALL is used). If you get a type error
involving SMALL, it will be reported as:
SMALL (BYTE)
The RANGE type comes into it's own with TYPE declarations:
TYPE SMALL IS RANGE -128 TO 127
TYPE can also be very handy for verbose NATIVE types, which are described in the
20. Advanced usage - accessing native OS/language elements chapter.
Type declarations (especially for parameters or object members) tend to spread
to many other parts of your program, which can be tedious if they don't provide
any obvious benefit. From experience I can say that LONG is not normally worth
it (unless you need to enforce 32-bits), so simply use the default (VALUE) type
instead. INT & BYTE are likely only needed to save memory in objects. Where-as
CHAR & BOOL are very useful, so use them when you can. PTRs & ARRAYs are of
course often required.
Some variables with legal types:
DEF x, x:QUAD, x:CHAR
DEF x:VALUE, x:PTR, x:ARRAY
DEF x:PTR TO VALUE, x:PTR TO PTR, x:PTR TO ARRAY
DEF x:ARRAY OF VALUE, x:ARRAY OF PTR, x:ARRAY OF ARRAY
DEF x:STRING, x[5]:STRING
DEF x:LIST, x[5]:LIST
DEF x:ARRAY, x[5]:ARRAY OF CHAR, x:ARRAY OF CHAR
DEF x:PTR TO CHAR, x:PTR TO LONG, x:PTR TO class
DEF x:ARRAY OF CHAR, x:ARRAY OF LONG, x:ARRAY OF PTR TO class
DEF x[5]:ARRAY OF PTR, x[5]:ARRAY OF PTR TO CHAR
DEF x[5]:ARRAY OF VALUE,x[5]:ARRAY OF ARRAY OF CHAR
And some variables with ILLEGAL types:
DEF x:ANY, x:PTR TO ANY, x:ARRAY OF ANY
DEF x[5]:ARRAY, x:ARRAY OF class
DEF x:PTR TO PTR TO CHAR
With a bit of experience you should find that on average most programs only need
1 cast every 200 lines of code. Even in the worst case, such as for low-level
coding or heavy OS access, on average you still should not need more than 1 cast
every 20 lines of code.
Declaring your variables with the right type is the most important way to avoid
the need to cast. But since casts are sometimes still necessary, here are some
hints...
If you want to cast an expression from any type x to any other type y, and the
compiler says something like "illegal cast to an unrelated type (not super- or
sub-type)", then you can usually get it to work like this:
expression !!VALUE !!y
For example, to cast from a variable of type CHAR to type BYTE:
character !!VALUE !!BYTE
This (usually) works because VALUE is the parent of (nearly) every type. So the
first cast is to VALUE, which is a direct parent, and this is then followed by
a cast to BYTE, which is a direct child of VALUE.
However, casting everything to VALUE is a bit of an extreme measure, and will
not always work if pointer arithmetic isn't enabled. So it pays to be
conservative, and choose the closest parent type that is shared by both types.
You can find the closest parent by simply looking at the type diagram that
begins this chapter. However, I will give a few examples, to get you going:
The closest parent for CHAR & BYTE is INT, so the previous example could be done
this way:
character !!INT !!BYTE
If you wish to cast from ARRAY OF x to ARRAY OF y, then the shared parent type
is ARRAY. For example:
expression !!ARRAY !!ARRAY OF y
If you wish to cast from PTR TO x to PTR TO y, then the shared parent type is
PTR. For example:
expression !!PTR !!PTR TO y
But due to how the type system works, you can actually get-away with casting to
just PTR. For example:
expression !!PTR
I must emphasis that this sort of casting shouldn't normally be necessary. So
if you do think you need to do it, then I strongly recommend that you first
check what you're doing truely makes sense, or couldn't be done in a safer way.
Portabl E implements a fairly advanced type system, which is able to accurately
deduce & represent the type of a result for operations like +, -, *, /, OR and
AND. But it's one big limitation is that currently this doesn't work for
VALUE types.
While the aim is a type system which always acts sensibly, it may
sometimes still be helpful for you to know how it works:
All primitive types (except QUAD & CHAR) cover a specific range of values. For
example, BYTE covers -128 to 127. For our discussion, imagine that we have
declared the following types:
TYPE UBYTE IS RANGE 0 TO 255
TYPE UINT IS RANGE 0 TO 65535
So if we add 1001 to a variable of type UBYTE, then we'd expect the result to be
somewhere between 1001 & 1256. Portabl E actually uses the range of a result
like this as the type itself, which is far more accurate than simply saying the
result fits within a UINT, or worse that it still fits within a UBYTE!
So if you tried to assign the result of a UBYTE + 1001 to another UBYTE, then
Portabl E would complain that the type "RANGE 1001 TO 1256" does not fit within
the type UBYTE. If you multiplied the result by 100, before trying to assign it
to a UBYTE, then it would complain that the type "RANGE 100100 TO 125600" does
not fit. This result doesn't fit within a UINT either.
So Portabl E is pretty good at estimating whether a maths calculation can be
assigned to a variable, etc. It is even able to correctly deduce that something
like "long AND $FF" will always fit within a UBYTE, even if "long" is a LONG.
But this accuracy leads to a problem: It is often common to write something
like "ubyte := ubyte + 1", even though we know that the type "RANGE 1 TO 256"
will not always fit within "RANGE 0 TO 255"! So strictly following the above
rules would require the programmer to cast "ubyte + 1" as a UBYTE, before
Portabl E would allow it.
I decided to allow that kind of operation, where a small value is used on a
primitive type, by letting the result have that primitive type (instead of an
accurate range of values). For addition & subtraction, "small" is defined as
half the size of the primitive type, e.g. under 128 for a BYTE or UBYTE. For
multiplication, "small" is defined as the square root of the size of the
primitive type, e.g. under 8 for a BYTE or UBYTE.
Go back to CONTENTS
AmigaE's support for Object Orientated Programming (OOP) was rather basic, which
made it easy to learn, but it could also be quite limiting, and crashes from
mistakes were quite likely. Portabl E provides greatly improved support for OOP,
while staying pretty backwards compatible - and I have attempted to avoid many
of the unnecessary complexities seen in C++.
I will assume that you are already familiar with OOP concepts, and in particular
with AmigaE's version of OOP. But since Portabl E does things a little
differently to C++ & many other OOP languages, I will begin with a little OOP
theory...
When a child class inherits from it's parent, not only does it inherit the
parent's implementation (i.e. the code inside each method), but it also
inherit's the parent's interface (i.e. each method's parameters & return
types).
In languages that support overloading (such as C++) it is required that a child
method has exactly the same interface as it's parent, because otherwise it would
be treated as a different method. This guarantees that a child object can be
used where it's parent is expected, because the child always supports exactly
the same methods as it's parent.
But Portabl E, like AmigaE, does not support overloading, and this provides room
for some extra OOP freedom - it is possible for a child method to have a
different interface to it's parent! An interesting idea, but I hope that you
can see the potential problem here:
If a child method cannot be used where it's parent would be, then the child
object itself is no-longer a valid substitute for it's parent, and therefore it
is not a true child. For example, if the parent's first parameter was foo:LONG,
but the child's first parameter was foo:INT, then it wouldn't make much sense
for the child to be passed a LONG value when it was expecting an INT, because a
LONG is larger than an INT!
While this might seem to prove that a child's interface must be exactly the same
as it's parent, you would be wrong: If the parent's first parameter was
foo:INT, but the child's first parameter was foo:LONG, then it would be
perfectly fine for the child to be passed an INT value when it was expecting a
LONG, because an INT is smaller than a LONG.
We can generalise this to a rule which says that a child's parameters can be
more general (i.e. larger) than it's parent's, but not less general. In a
similar fashion, a child can have more default parameters & more return values
than it's parent, but not less. This is more formally known as the Liskov
Substitution Principle (LSP), under which a child must be usable in all
situations that it's parent is.
It is interesting to note that this principle gives a reverse rule for return
types - a child's return types can be less general (i.e. smaller) than it's
parent's, but not more general. This is because if a child tried to return a
larger value than was expected, then that value would simply not fit.
If you find any of this confusing, then you may wish ignore the theory, and just
read the next sub-chapter...
Unlike C++ or AmigaE, Portabl E has a proper type system, where each less general
(i.e. smaller) type inherits from a more general (i.e. larger) type. This
means that it is possible for the previously mentioned LSP to be used to
decide whether a child method is valid in all situations that it's parent is.
For Portabl E, the LSP boils down to these rules for children:
- More values can be returned (but not omitted).
- More parameters can be added (but not removed), and they must have defaults
(so that they are optional).
- Existing parameters can have defaults added (but not removed).
- Parameters can be made more general (but not more restrictive).
- Return types can be more restrictive (but not more general).
Typically a child will have the same types for parameters & return values, but
it can be very useful for a child to have additional parameters & return values.
So even if you find it difficult to remember whether types should be more or
less general, MAKE SURE TO REMEMBER THAT CHILDREN CAN HAVE MORE PARAMETERS &
MORE RETURN VALUES!
The above restrictions apply to all methods, including constructor methods, even
though constructors are not really part of a class's interface. This can be
quite limiting, because often a constructor will need to be quite different in a
child class. The solution is to declare that the class is UNGENERIC:
CLASS child UNGENERIC OF parent
ENDCLASS
As Portabl E currently stands, there is no down side to doing this, but in the
future it will probably prevent the child from being used in a more advanced OOP
system known as "generics". Hence the keyword UNGENERIC.
[Note that I am not entirely happy with the word I chose for this keyword, so I
will change it if I can think of a better word, and of course anyone else may
make a suggestion too.]
While the above restrictions can be limiting for constructors, they can
sometimes be limiting for normal methods too, so Portabl E provides a novel
solution that doesn't break the LSP. If a child is declared an ORPHAN of a
parent object, then it is no-longer restricted by it's parent:
CLASS child ORPHAN OF parent
meef
ENDCLASS
Effectively the child class inherits the implementation of the parent (it's
genes if you like), but it does NOT inherit the interface of the parent (say
the language it's taught). Thus the child can access the parent's methods, but
it is free to completely change the interface when redeclaring those methods.
Unlike C++'s private inheritance, the inherited methods are still publically
visible (unless they have been redefined)!
Because the child class is free to completely change it's interface, it will be
treated as if it doesn't have a parent - and therefore will not be accepted
where it's parent is expected. This ensures that the LSP is not broken.
There is a catch though - when you make a child method's interface incompatible
with it's parent, the parent class will not be able to call your child method,
even though polymorphism (aka virtual methods) normally means that it would.
Instead the parent class will only be able to call it's own method, as it knows
that interface. Since this can be a major problem, you are required to
indicate which methods change their interface, like so:
PROC method() OF child ORPHAN
Note that if you only do this for constructor methods, then it would usually
make more sense to just declare that your class is UNGENERIC instead.
If being free to completely change the class's interface sounds like TOO much
freedom, then you can limit the child to the interface of one of it's
grandparents:
CLASS parent OF grandparent
ENDCLASS
CLASS child ORPHAN OF parent IMPLEMENTS grandparent
ENDCLASS
This means that the child will be accepted as a child of the grandparent, but
not the parent! This is present in Portabl E for completeness, but it will have
far less uses than simply ORPHANing a class, so don't worry about it too much.
RTTI is provided for classes, and is better than that provided by C++. It is
extremely useful for larger OOP programs.
You can get a value which represents the type of a named class using
TYPEOF className . Alternatively, every class has the method InfoClassType(),
which returns the object's actual (dynamic) type. All such values have the type
CLASSTYPE.
You can then see if two types are the same, using the procedure
HaveSameClassTypes(first:CLASSTYPE, second:CLASSTYPE), which returns TRUE if
they are the same. Alternatively, every class has the method
IsSameClassTypeAs(type:CLASSTYPE), which indicates whether the object's actual
(dynamic) type is the same as the one provided. It is effectively implemented
like this:
PROC IsSameClassTypeAs(type:CLASSTYPE) OF class IS HaveSameClassTypes(type, self.InfoClassType())
Finally, every class has the method IsOfClassType(parent:CLASSTYPE), which
indicates whether the class is a sub-type of the provided type. Thus it returns
TRUE if the class has the same type the provided type, or if it is a child of
the provided type. This is very handy, because you can check whether it is
really OK to treat an object as a child class (before casting it to that
sub-type).
Please note that the (CLASSTYPE) value representing a class's type may be
different each time a program is run, so there is no point in writing such
values to a file. Additionally, there may even be multiple values representing
the same class, therefore you can only use the provided procedure & methods to
compare them.
Go back to CONTENTS
The basis of functional programming is that functions (or procedures as they are
called in E) are first class, which basically means that they can be treated
like any other value and stored or passed around.
AmigaE allowed this using function pointers, but it was untyped so that a slight
mistake could cause a crash. Portabl E has a similar-looking capability, but it
is typed checked, so mistakes are caught at compile time.
FUNC procedures look like normal PROC procedures, but they have a (pseudo)
function pointer. For example:
FUNC add(a,b) IS a+b
PROC main()
DEF function:PTR TO add
function := add
add(1,2) ->returns 3
function(1,2) ->returns 3
ENDPROC
The function variable must have the type "PTR TO add" to allow it to be
treated as a function. In particular, the type indicates the parameters &
return values of the function.
Of course, this would not be much use if a variable could only ever call one
function, so you can use inheritance for flexibility:
FUNC funcParam2(x,y) IS x
FUNC add(a,b) OF funcParam2 IS a+b
PROC main()
DEF function:PTR TO funcParam2
function := add
add(1,2) ->returns 3
function(1,2) ->returns 3
ENDPROC
This has the same result as the previous example, but this time we could have
called any function that took two parameters, as long as the function inherited
funcParam2.
Portabl E defines many such "base" functions, to cover various number of
parameters, with the idea that code from different people will still be able to
work together. For example:
->these return nothing
FUNC funcParam0empty() IS EMPTY
FUNC funcParam1empty(p1) IS EMPTY
FUNC funcParam2empty(p1, p2) IS EMPTY
->these return one value
FUNC funcParam0() OF funcParam0empty RETURNS value IS EMPTY
FUNC funcParam1(p1) OF funcParam1empty RETURNS value IS EMPTY
FUNC funcParam2(p1, p2) OF funcParam2empty RETURNS value IS EMPTY
These are currently stored in the 'std-alpha/functions' module, but in practice
I haven't found much use for this module, so you are probably safe to ignore it.
The "std-alpha" folder indicates it is intended to eventually become standard
(by moving to the std/ folder), but that currently they are an "alpha"
version, which means they may change significantly (or may have major bugs).
WARNING: The function pointer provided by FUNC is not implemented using a
real function pointer, so passing it to AmigaOS (say for a hook) will not work.
If you need to provide real function pointers, then use a PROC with CALLBACK
proc(). In the unlikely even that you need to call real function pointers, the
'std/pCallback' module provides a klunky solution. See the
8. How to compile your old AmigaE programs chapter for more information.
The 'std-alpha/functions' module currently also contains these two procedures:
PROC Fmap(function:PTR TO funcParam1, list:LIST)
DEF i
FOR i := 0 TO ListLen(list)-1 DO list[i] := function(list[i])
ENDPROC list
PROC Freduce(function:PTR TO funcParam2, list:ILIST, init)
DEF i, sum
sum := init
FOR i := 0 TO ListLen(list)-1 DO sum := function(sum, list[i])
ENDPROC sum
These are LIST-based implementations of Map & Reduce, which are well known in
functional programming. Fmap takes a list, and replaces each item with the
value returned by the supplied function (which is called using the original item
value). Freduce applies a function across the entire list, and returns the
'running total' at the end.
For example, to multiply every item in a list by two, and then add all the items
together, you could use:
FUNC multiply(value) OF funcParam1 IS 2*value
FUNC add(a,b) OF funcParam2 IS a+b
PROC main()
DEF list:LIST
list := NEW [1,2,3]
Fmap(multiply, list) ->list now contains [2,4,6]
Freduce(add, list, 0) ->returns 12 = 2+4+6
ENDPROC
Fmap() & Freduce() can work on more than just numbers, although numbers are
easier. For example, if you had a list of e-strings, then you could use Fmap()
to preprocess those strings (say removing spaces), and then Freduce() to
concatentate those strings together.
In practice I haven't found much use for this module, so you are probably safe
to ignore it.
If you have a child function that inherits a parent function, then the child can
have more parameters & more return values, just like you can with normal OOP
methods:
->one parameter & one return value
FUNC parent(one) IS one*2
->three parameters & two return values
FUNC child(one, two=2, three=1) OF parent IS one*two, one*three
In this case child(x) does the same as parent(x), i.e. it returns x*2, but it
also returns an extra (optional) value, and it has extra (optional) parameters.
So child() can be used where parent() is expected, but when you know that you
have child(), then you can make use of it's extra (optional) capabilities.
As has been previously mentioned, functions are not implemented using real
function pointers. So you might wonder how it is actually implemented. In
the case of this code:
FUNC add(a,b) IS a+b
PROC main()
DEF function:PTR TO add
function := add
add(1,2) ->returns 3
function(1,2) ->returns 3
ENDPROC
It is converted by Portabl E into something like this:
CLASS add OF function
ENDCLASS
PROC call(a,b) OF add IS a+b
DEF add:PTR TO add ->this gets NEWed automatically
PROC main()
DEF function:PTR TO add
function := add
add.call(1,2) ->returns 3
function.call(1,2) ->returns 3
ENDPROC
First FUNC is converted into a method of a new class, then a global variable is
created which contains that object. Finally any function calls to variables
(of the right type) are converted into method calls. Result: Magic! ;-)
While it isn't necessary to understand the implementation, it may help you
understand clever uses of functions, especially if you understand how Portabl E
does OOP. For example, you can give your function a memory (effectively static
variables), by knowing how functions are implemented:
FUNC parent(one) IS one*2
CLASS child OF parent
lastValue ->this is the function's memory
ENDCLASS
PROC call(one, two=2, three=1) OF child
self.lastValue := one
ENDPROC one*two, one*three
DEF child:PTR TO child
PROC new()
NEW child.new()
ENDPROC
PROC end()
END child
ENDPROC
Such a child can even be inherited by another FUNCtion.
Go back to CONTENTS
- The IsOfClassType() method still treats ORPHANs as children on their parents.
- '\\' has a STRLEN of 2 not 1.
- a FUNC before a new() or end() procedure cause a double-declaration error.
Go back to CONTENTS
Am I right to class Portabl E as a compiler, rather than a translator? Well,
it's debatable, but all traditional compilers do is translate from a high-level
language to a low-level one - which C arguably is anyway! What decided it for
me is the fact that Portabl E implements almost everything you would see in a
"real" compiler, and in principle the "missing" low-level functionality could
be added.
Also, PEGCC *does* produce an executable that isn't interpreted - which is
exactly what a real compiler does. Unlike say Python or Hollywood. So from the
end-users point of view there doesn't seem much difference!
Or an alternative solution is to say that Portabl E is a "meta compiler". But I
find that description to be messy, and it may just lead to the question of what
a "meta compiler" is...
Portabl E has basically no hard-coded limits (really!), so you could make your
programs as large & complex as you want. The only limitations I've noted are:
- Modules must be under 32,768 lines, but no warning is given.
- The module cache limits programs to using 65536 modules.
Of course you will still be limited by any hard-coded limits of the target
language's compiler. However, should any of these limits be very small (such as
OPL's limit of 8 nested IF statements) then I will likely work-around them, if
possible.
Portabl E uses a flexible "refactoring" system to replace features not supported
by the target language. The same system is used to implement optimisations.
The refactoring system is designed to allow maximum code reuse. The target code
is then generated by doing a fairly trivial translation, although the actual
translation system is also very flexible, to support maximum code reuse. The
idea was that as more target languages were supported, the easier it would be to
support further languages - but in practice the biggest difficulty in supporting
a language has turned out to be writing all the necessary target & 'wrapper'
modules, so I have ended-up sticking to just C++ (with the hope of also
supporting plain C eventually).
Go back to CONTENTS
For those who find the supplied OS calls too limiting, they may like to know
that it is possible to access most (if not all) of the underlying OS & language.
Of course, this will tie the code to that OS & language.
You can do this in any module you want, as long as OPT NATIVE is specified, but
it is recommended that you carefully think about it. You have two ways to
support different NATIVE code for multiple OSes:
1. You can enclose the NATIVE code inside preprocessor sections, such as
#ifdef pe_TargetOS_Linux . This works well when you only have small amounts
of NATIVE code.
2. You can put the NATIVE code in separate modules. In this case the modules
should be stored under the appropriate sub-folder within the
PEmodules:target/ folder, so that they are automatically used for the right
OS & language.
Native code is simply plain text that passes through Portabl E without being
modified, and is enclosed within curly braces like so:
{CtrlC()}
But native code is rarely useful on it's own. Usually we want to use it as an
expression, like this:
IF {CtrlC()} !!BOOL THEN doSomething()
The !!BOOL cast is needed, because normally native code has the EMPTY type (i.e.
it is assumed to return nothing). If the target language was AmigaE, then the
generated code would look something like this:
IF CtrlC() THEN doSomething()
If the target language was C++ then the generated code would look something like
this:
if (CtrlC()) {doSomething();}
About now you are probably imagining that you can write something like this:
IF {Not( var )} !!VALUE THEN doSomething()
You would be wrong! When Portabl E generates code, there is no guaratee that a
variable's name will be unchanged, because of possible name space clashes. So
what you must do is avoid enclosing variables within curley braces. Your first
suggestion would probably look like this:
IF {Not(} var {)} !!VALUE THEN doSomething()
Unfortunately, the IF statement expects a single expression - but you have given
it three expressions! Each pair of curley braces is treated as a whole
expression, as are any variables. What we have to do is mark the beginning &
end of the native expression, like so:
IF NATIVE {Not(} var {)} ENDNATIVE !!VALUE THEN doSomething()
This is perfectly legal code, and for AmigaE would result in something like the
following code being generated:
IF Not(var2) THEN doSomething()
I think you will agree that this NATIVE stuff is a bit messy, and not something
you want to litter your main code with. Not a problem! Just put it in a
one-line wrapper procedure:
PROC Not(a) IS NATIVE {Not(} a {)} ENDNATIVE !!VALUE
And in fact, if you look in the 'PE/AmigaE/base' module, you will find exactly
this line of code. But you may be thinking this is a bit inefficient - an
unwanted extra procedure call. Not so! Procedures containing such native code
will be automatically inlined. So I hope you can see that storing all your
native wrappers in a separate module is actually a good idea.
If you wish to quickly test that all your declared 'native' procedures are
totally correct, use the NOOPTINLINE switch, and then try to compile the
generated code.
Rather than simply duplicate every feature & wart of the native functions, the
ideal solution is to actually devise some simple procedures or methods which
abstract what you want to do, so that the same procedures or methods can then be
implemented using the native features of other OSes & languages. In this way
you can ensure that porting your program to another OS/language will ONLY
require the rewriting of a simple module.
Some of the quicker readers may have wondered how we can declare the Not()
procedure, when one already exists in the AmigaE target language? The simple
answer is that AmigaE does not allow the declaration of procedures with an
uppercase first letter, so the generated code would look something like this:
PROC not(a) IS Not(a)
If the target language DID contain a procedure who's name clashed with this,
then Portabl E would simply rename the new procedure to something else & all
generated code would use that new name instead. While this can't happen in
AmigaE, it COULD happen in most other target languages. In those cases we must
tell Portabl E about these pre-existing procedures, like so:
NATIVE {Pre_existing_name} PROC
Similarly, if there exists something which could clash with constants, global
variables, or object/type names, then it should be declared:
NATIVE {PRE_EXISTING_NAME} CONST
NATIVE {pre_existing_name} DEF
NATIVE {pre_existing_name} OBJECT
You can also combine name space reservations using commas:
NATIVE {pre_existing_name} DEF, OBJECT
Typically all such potential clashes will have already been declared by me
within the appropriate target module, so you don't have to worry about this.
But if you decided to add some additional code to your module, for example:
{MODULE 'MyCustomModule'}
or like this in C:
{#include "MyCustomInclude.h"}
Then you WOULD need to worry about declaring potential new name clashes.
Lastly, I should mention that procedures beginning with an uppercase letter may
only be declared in a module that has OPT NATIVE specified. Don't abuse it!
Allowing access to native constants & global variables is very easy, as it works
just like normal declarations, except that they must start with a NATIVE {}
part. For example, to allow access to C++'s NULL constant from Portabl E,
the following declaration is used:
NATIVE {NULL} CONST NIL = 0 !!VALUE!!PTR
This simply declares that the NIL constant has the value 0 with type PTR, and
that when generating target code NIL should appear as NULL.
Similarly, to allow access to C++'s stdout global variable from Portabl E,
the following declarion is used:
NATIVE {stdout} DEF stdout:PTR
This simply declares that the stdout global has the type PTR (which is
equivalent to void* in C++), and when generating target code it must always
appear as stdout (rather than possibly being automatically renamed).
Allowing access to native objects is a bit more tricky than constants or
globals, but it follows a similar pattern. Here is what the datestamp
declaration looks like for C++:
NATIVE {DateStamp} OBJECT datestamp
{ds_Days} days :LONG
{ds_Minute} minute:LONG
{ds_Tick} tick :LONG
ENDOBJECT
What this says is that the datestamp object is actually called DateStamp in
the C++ code, which I hope is fairly obvious. What may be less obvious is that
each member must also have it's C++ equivalent declared; so the days member is
actually called ds_Days in the C++ code, etc.
It is worth mentioning that not all object members need to be declared - if they
are not listed, then they are simply inaccessible to Portabl E code. However,
since Portabl E does not know about undeclared members, it is possible (but
unlikely) that there could be a name-space clash (typically with another member
of the same name). In the future I intend to provide a simply solution to this.
Each member must also have it's correct type declared, which is not always
obvious when we are using Portabl E's type system - because the real C++ object
uses C++ types! For example, we may have an object who's C++ member is:
char *string;
While the obvious equivalent is "string:PTR TO CHAR", Portabl E's strings are
ARRAY OF CHAR, so it's real equivalent is "string:ARRAY OF CHAR". It may help
to know that this still results in the C++ type "char* string".
Another example:
UBYTE *CS_Buffer; /* Optional string parsing space. */
Here UBYTE is actually declared by AmigaOS as "typedef unsigned char UBYTE;".
So we should make CS_Buffer an ARRAY OF UBYTE. Since Portabl E does not have
any unsigned types built-in, the UBYTE type is defined within the 'exec/types'
module.
Another example:
UWORD ed_OwnerUID;
Here UWORD is actually declared by AmigaOS as "typedef unsigned short UWORD;".
Again, this is defined within 'exec/types'. So we can use "ed_OwnerUID:UWORD".
What happens if you declare a member as the wrong type? Maybe it will still
seem to work, but in some cases Portabl E may fail to provide an appropriate
cast. If you are unsure that a type is the correct choice, then simple write a
dummy program that contains that type, and see what it get's translated to by
Portabl E.
In some cases it may be necessary to provide additional hints to tell Portabl E
how it should handle a NATIVE declaration. Options are provided using the
following format:
NATIVE {name option1 option2 etc} ...
Which is equivalent to:
NATIVE {name} ...
But with the additional options "option1" and "option2". Currently NATIVE
options are only supported by OBJECT & CLASS declarations, and the only options
available are "Typedef" and "Union", both of which tell Portabl E to not put the
word "struct" before the objects name when referring to it.
e.g. NATIVE {__sigset_t Typedef} OBJECT __sigset_t
Is used on Linux because the __sigset_t object is declared using a typedef:
typedef struct { ... } __sigset_t;
For those cases where Portabl E has no type that maps exactly onto an underlying
type, you can use so-called native types. For example, as previously mentioned,
Portabl E does not have any unsigned types built-in, so they are defined like
this within the 'exec/types' module:
TYPE UBYTE IS NATIVE {UBYTE} CHAR
TYPE UINT IS NATIVE {UWORD} INT
TYPE ULONG IS NATIVE {ULONG} VALUE
TYPE UBIGVALUE IS NATIVE {unsigned long long} BIGVALUE
What this says is that the UBYTE type behaves like a CHAR type, as far as the
user is concerned, but when generating code the {UBYTE} causes UBYTE to be
written instead of the type CHAR. Instead of CHAR, we could have chosen any
type, such as VALUE, but in this case CHAR minimises the amount of casting that
the user needs to do for old AmigaE programs.
As another example, if an object contained the following C++ function pointer:
VOID (*freefunc)();
You can declare a Portabl E equivalent like this:
freefunc:NATIVE {VOID (*)()} PTR
The "PTR" at the end of this declaration can be any type we like, such as VALUE,
since it will not effect the generated code. But for function pointers you
should use PTR, because that is the type that CALLBACK returns.
For C++ targets, please also note that NATIVE types of function pointers should
only be used (1) for members of NATIVE objects, and (2) for NATIVE global
variables, because Portabl E will not create the correct C++ syntax for other
uses.
Unlike some other languages, Portabl E does not (yet) support procedures with an
unlimited number of parameters - except for NATIVE procedures. It's done using
the special ... symbol, but it's mostly easier to demonstrate it's usage rather
than explain it:
PROC Print(fmtString:ARRAY OF CHAR, arg=0, ...) IS NATIVE {printf(} fmtString {,} arg {,} ... {)} ENDNATIVE
The above is how the Print() procedure is implemented. Beware that all ...
parameters are expected to have the same type as the previous parameter, in
this case the "arg" parameter which has the default type VALUE.
Note that the native expression before the ... (which is {,} in this case) is
used to separate the extra parameters when generating code.
Once you've had a bit of practice, doing the above is quite easy. But it can
still be a chore if there is a large quantity of code to support, such as you
might see in an Amiga C++ header file.
Therefore I have written a dumb tool that will semi-automatically convert a C++
header file for you. You still need to go through the generated code yourself,
filling-in or removing certain things it was not sure about, but it probably
gives a 10 times speed-up to the overall process.
I have NOT yet provided the tool with Portabl E, but if you think that you might
find it useful, then please email me.
Go back to CONTENTS
My name is Christopher S Handley, but you don't really want to hear about me do
you? Suffice to say that I am an AmigaE fanatic, and live in England :-)
You can you can get my current email address from this web page:
cshandley.co.uk/email But please do not post my email address in
public, because I might get spammed!
Go back to CONTENTS
While there are many people I could thank, this isn't the Hollywood Oscars, so
in alphabetical order I will just give my biggest thanks to:
- Chris Young.
- Daniel Westerberg.
- Dwayne Jarvis.
- Hans de Ruiter, for coding help (esp graphics).
- Itix, for coding help (esp graphics) & early testing.
- Konrad "recedent" Czuba, for testing on MorphOS.
- Leif Salomonsson, for much constructive criticism, even if we didn't always
agree.
- Olivier Tigreat, for testing the Windows version of Portabl E.
- Pampers, for testing PictureAlbum on MorphOS.
- Paul Beel, for testing the Windows version of Portabl E.
- Stefan Blixth, for help testing the MorphOS version of Portabl E.
- Tomasz Wiszkowski, without whom I would probably have been unable to compile
Portabl E, because AmigaE was unable to handle the sheer quantity of objects used
to code Portabl E! He was kind enough to modify CreativE for me, so that it
could compile Portabl E. He has also done MorphOS testing for me, suggested how
to implement CtrlC() for POSIX, and helped in other ways (see the 23. History
chapter).
- UtilityBase.com forum members for their help, including ZeroG, joerg,
salass00, itix, Hypex, Thomas,�obarthel & Georg.
- Wouter van Oortmerssen, without his AmigaE language I would likely be hobbling
along with C/C++ today, or even have become disillusioned by programming &
given-up altogether!
Others who have helped me are acknowledged within the 23. History chapter, as are
the details of how the above people have helped me.
Go back to CONTENTS
key:
NEW = new or significantly improved feature
CHG = changed or removed feature
BUG = bug fix.
r6b (24.11.2022)
- CHG: AmigaOS4: Worked-around a bug in the latest OS4 SDK (54.16), which has problems compiling C++ code, unless you use GCC v6.4.0 . Many thanks to Benedetto Lorello for reporting the problem.
- BUG: Amiga: Fixed the installer still failing at "Copying executables..." in some cases. Many thanks to Benedetto Lorello for reporting the bug & assisting with testing (as it didn't happen for me).
r6a (13.11.2022)
- BUG: AmigaOS4: Fixed the 'std/cGui' module failing to compile (MUIA_Dtpic_Name not declared), due to the SDK not using MUI4+ by default.
- BUG: Linux: Fixed 32-bit hex values > $7FFFFFFF not being interpreted as negative by the type checker.
- BUG: AROS: Fixed Install_AROS not offering to install the extra C header files (although they're not really needed).
r6 (07.11.2022)
- NEW: Added basic Linux support (64bit x86 only), to the same level as Windows, i.e. Shell-only, no internet or graphics. Linux required changing VALUE from "int" to "long". Improved POSIX implementation of modules.
This was a major effort, partly due to all the differences (64-bit pointers, case-sensitive filing system, mount-points anywhere, etc), and partly due to all the C headers that needed to be converted.
- NEW: In 'std/cPath_shared', added CP_CASEINSENSITIVE, StrCmpPath() & OstrCmpPath().
- NEW: Linux: PEGCC now supports cross-compilation (for Amiga & Windows) using the TargetOS parameter, as long as an appropriate GCC cross-compiler is installed.
- NEW: All OS procedures that can support unlimited parameters now do so.
- NEW: Added the NoOptInlineVarargs switch, to allow checking that NATIVE procedures with a ... parameter will proceduce compilable code.
- NEW: Added Options for NATIVE {} OBJECT/CLASS declarations, so that the "Typedef" & "Union" options can be used to prevent "struct" being written before the object's name.
- NEW: AmigaOS4: Now compiles using the latest AmigaOS4 SDKs (54.16 & 53.34).
- NEW: AmigaOS3: No-longer needs a modified "intuition/classusr.h" file.
- NEW: AROS: Updated certain OS procedures, so they compile.
- NEW: Windows/Linux: In 'std/cPath', added HOME: assignment for the users home folder.
- CHG: Windows/Linux: In 'std/cPath', added a per-user Assignments.txt file, but removed the per-program-start-folder Assignments.txt file.
- CHG: C++: When generating code, it now uses fewer casts & puts them in more logical places.
- CHG: Amiga: In 'std/cPath', queryExtra("ATTR") now correctly reports flags (like read-protected) that had to be temporarily cleared when open()ing with forceOpen=TRUE.
- BUG: Fixed OptOptimise causing statements similar to WHILE ... DO EMPTY fail to parse.
- BUG: Fixed OptOptimise causing inlinable new/end procedures like PROC new() IS ... to produce uncompilable code.
And from much longer ago:
- NEW: Added the 'std/pUnsigned' module, to provide basic support for unsigned number types, and the example program "Examples/std/Shell/crc32.e". Useful for porting certain C algorithms. It is supported by the C++ target, but NOT the AmigaE target.
- NEW: Added the procedures InStrNoCase(), BigMax(), BigMin(), BigFastMod(), IsBigEndian() & IsLittleEndian().
- NEW: In 'dos', added SystemTags() procedure (which supports unlimited parameters).
- NEW: In 'std/pTime', improved CurrentTime() to take a timezone parameter. "Examples/Shell/Timer.e" & some other example programs have been updated to use the quickest zone.
- NEW: In 'std/cPath', for the cDirEntryList class, added the sort() method, and improved the remove(), add() & addString() methods. (Now easy to process a directory list, selectively modifying some items.)
- NEW: In 'std/cPath', changeExtra("COMM", comment) no-longer fails when comment exceeds OS limits, but instead truncates it.
- NEW: In 'std/cGui', added the cGuiString.initMaxLength() method.
- NEW: In 'std/cGui', added the initUseLeastSpace() & infoUseLeastSpace() methods to the cGuiGroupItem class.
- CHG: In 'std/cGui', cGuiLabel now properly obeys initUseLeastSpace(), and no-longer wastes space when used in a Horizontal Group.
- BUG: C++: When generating code, it now creates fewer unnecessary casts - which used to make / and SHR give the wrong result for 'unsigned' NATIVE types. Specifically, a NATIVE type is no-longer treated as potential pointer unless it contains a * symbol, so (for example) maths & logic operations won't add casts for NATIVE types.
- BUG: Fixed FastNew() (and so NEW) which would trash memory, instead of raising the "MEM" exception, if it failed to allocate memory. Thanks to Dimitris Panokostas for reporting symptoms of this long-standing bug, especially as I don't see out-of-memory errors on the OSes I normally use.
- BUG: Amiga: The installer would fail at "Copying executables..." if the user-specified path for executables did not contain any (sub) folders, such as "C:" (which sadly was the default). Many thanks to "Zendarion" for the bug report.
- BUG: Windows: In 'std/pTime', CurrentTime() now returns the correct time when DST is in effect.
- BUG: In 'std/cGui', fixed cGuiList.addEntryF() so it doesn't crash when no entries would be added.
- BUG: In 'std/cGui', fixed cGuiItem.beginGroupPage() to not internally contain a GroupHorizontal, which could then cause wrong behaviour of contained items, e.g. Labels would be fixed-width.
The above changes are all since the last 23.2. r6 beta in 2016. There are too many changes to list since r5 in 2009, see the 23.2. r6 beta sub-chapter for more details.
key:
+ = something different from the last official release
- = something different from the last beta release
r6 beta (26.04.2016)
- +NEW: Improved PortablE so that built-in procedures CAN support unlimited parameters. e.g. Print(), Intuition's NewObject() & SetAttrs().
- +NEW: Improved MUI (and ReAction) procedures to allow unlimited parameters, and their macros to use them instead of immediate (tag) lists. So the C/C++ code generated for GUIs is now human-readable! (If this works well, then I will extend it to all procedures which should allow unlimited parameters.)
- +NEW: Added the NoListOptim switch, so that the code generated for Immediate Lists can be more human-readable.
- +NEW: AmigaOS4: Added the 'intuition/menuclass' module, aka "AISS menus", and the example program "Examples/Amiga/OS4_ReAction/MenuClass.e".
- +CHG: In 'intuition', for GetAttr() changed it's "storagePtr" parameter to the type ARRAY (was ARRAY OF ULONG).
- -BUG: When a bug exception was thrown during compilation, it could wrongly report 'cNumberSpace.end(); power<MINPOWER' instead of the correct message. Now fixed.
- -BUG: AmigaOS4: In 'std/cGui', worked-around a MUI4 bug, which meant that unghosted buttons (containing an image) would still appear mostly ghosted. A recent update of MUI4 should have also fixed this problem...
- -BUG: AmigaOS4: In 'reaction/reaction_macros', fixed Title(), ItemBar(), SubBar() & EndMenu macros from causing a cryptic type error. Also prevented *Object macros from causing a v.cryptic error if the 'intuition' module wasn't used.
- -BUG: AmigaOS4: In 'dos/dosextens', fixed access to some members failing to compile (typo).
r6 beta (11.12.2015)
- +CHG: AROS: Removed use of boopsistubs from 'AmigaLib/boopsi' & 'intuition', as no-longer seems necessary & has a potential dependancy problem with Icaros v2.0.x .
- -BUG: AROS: In 'std/cGui', fixed a bug in the dynamic list which caused it to crash due to AROS's different NList implementation. This serious bug slipped through testing...
r6 beta (06.12.2015)
- +NEW: PortablE now stores ".pem" cache files in "PEmodules:PE/cache/", so your source folders are no-longer filled with unwanted .pem files. Added the CleanModuleCache utility.
- +NEW: PEGCC now has the parameters Run, RunUsing & RunParam, to allow a compiled programs to be automatically executed after it is compiled.
- +NEW: AmigaOS4: Now compiles with the latest AmigaOS4 SDK (53.30). Thanks to Anthony Iliakis for reporting the problem. As before, this likely means AmiDevCpp can no-longer be used for OS4, until/unless it is updated to match the SDK (it might be possible for users to do this manually).
- +NEW: AmigaOS4: Added ReAction modules & a ClassAct 'emulation' layer. This includes modules for 13 previously-missing Gadgets, 2 Classes (for window & requester), and 5 others (bevel, label, penmap, tools/boopsi, tools/inithook).
- +NEW: AROS: Now compiles on Icaros Desktop Live v2.0.x (tested on v2.0.3), but will probably no-longer work on v1.x . And fixed Workbench executables not opening a Shell window (contrary to the C runtime on all other modern Amiga flavours, including AROS v1.x).
- -NEW: In 'std/cGfx', added support for alpha-channel in loaded pictures, but it must be enabled using the enableAlphaChannel option of CreateGfxWindow() or ChangeGfxWindow().
- +NEW: In 'std/cPath', added the cPath.sleep() method.
- +NEW: In 'std/cPath_File', caching has been heavily rewritten, and should be much faster in many cases, since the cache size now automatically adapts itself to recent file usage.
- +NEW: In 'std/cPath_File', added the STATIC string cFile_NewLine, to simplify the writing of text files across different OSes.
- -NEW: In 'std/pBox', the UnboxVALUE() procedure now has the extra parameter "nilValue".
- -NEW: In 'std/pBox', add BoxBIGVALUE()/etc procedures.
- +NEW: Added the example program "Examples/Amiga/AHI_PlaySinewave.e".
- +NEW: Added the procedures ReopenStdOut() & ReopenStdIn(), as SetStdOut() & SetStdIn() no-longer work on AROS & potentially might not on other C++ targets either. Thanks to "ncafferkey" for pointing out the C problem & solution.
- +NEW: AmigaOS4: Added 4 examples programs in "Examples/Amiga/OS4_ClassAct/".
- -CHG: In 'std/cGfx', changed from "UsageCount" to "VisibleCount" for all method names. This was required to fix a bug revealed by one of mrdarek's games.
- -CHG: In 'std/cGui', replaced "altColour" with "style" (use GUI_STYLE_ALTCOLOUR), which causes a few incompatibilities.
- -CHG: In 'std/cGui', most of cGuiGroupPage's methods can now be called before the GUI is built (as long as the group has been closed with cGuiWindow.endGroup()).
- -CHG: In 'std/cGui', removed default values from fGuiListSort's parameters, as they didn't make sense (and could be misleading).
- -CHG: In 'std/cGui', removed restriction that prevented both data & dataBox being stored for the same item in a cGuiList (previously storing one would would zero the other).
- -CHG: MorphOS: In 'std/cGfx', <=256 colour bitmaps no-longer leak video memory, as I got rid of work-around for a MorphOS 2.x datatype bug. I assume most people have upgraded to MorphOS 3.x by now.
- -CHG: In 'std/cGfx', DestroyBitmap()/etc can now be used on a bitmap used by a sprite, without leaking memory (the bitmap will be destroyed when it is no-longer used, rather than only happening when the program quits). Idea came from code provided by "mrdarek", and then fixed after more of his code revealed a bug!
- +CHG: In 'std/cPath', now prevents a file from being simultaneously opened more than once with write access (multiple readers are still allowed).
- -BUG: AmigaOS4: Updated Application.library module for the new SDK, otherwise they would not work correctly.
- -BUG: In 'std/cGfx', fixed rotate()ing a bitmap randomly crashing the program (when bitmap was <=8-bits or had a mask, and it's width was not a multiple of 16). Many thanks to "mrdarek" for the bug report.
- -BUG: In 'std/cGfx', the special keys for PageUp/PageDown were swapped with Home/End (due to me using a confusing Apple keyboard before).
- -BUG: In 'std/cGfxSprites', the first (default) sprite layer wrongly had autoIsDrawable=FALSE. Many thanks to "mrdarek" for the bug report.
- -BUG: In 'std/cGfxSprites', StoreSprite()/etc did not allow you to re-use a named slot, despite you destroying the old stored sprite. Many thanks to "mrdarek" for both bug reports.
- -BUG: In 'std/cGfx', StoreBitmap()/etc did not allow you to re-use a named slot, despite you destroying the old stored bitmap.
- -BUG: In 'std/cMusic', StoreMusic() did not allow you to re-use a named slot, despite you destroying the old stored music.
- -BUG: In 'std/cSnd', StoreSound() did not allow you to re-use a named slot, despite you destroying the old stored sound.
- -BUG: In 'std/cGui', fixed crash when cGuiText's state incorrectly contained line feeds.
- -BUG: In 'std/cGui', fixed cGuiText causing text to be tiny, and/or the whole window not appearing, when the line was too long. Thanks to Thore B�ckelmann for his help solving this.
- -BUG: In 'std/cGui', fixed cGuiList's text colour being unreadable on custom screens when using GUI_STYLE_ALTCOLOUR. Thanks to Thore B�ckelmann for his help solving this.
- -BUG: In 'std/cGui', fixed fGuiListSort functions not being passed Data nor DataBox parameters.
- -BUG: In 'std/cGui', fixed cGuiList.addEntryF() so that entries now appear in the order they are added (rather than the reverse).
- +BUG: In 'utility', fixed FindTagItem() & NextTagItem() to return PTR TO tagitem (rather than ARRAY OF tagitem).
- +BUG: AmigaOS4: Fixed the use of two members of "newmenu" (from libraries/gadtools.e) not compiling in some cases, due to them becoming CONST (STRPTR) in the latest AmigaOS4 SDK.
- -BUG: MorphOS: In 'std/cGui', fixed it failing to compile, due to missing NList & NListview includes. Thanks to Johannes Genberg for reporting the problem.
- -BUG: MorphOS: In 'std/cSnd', fixed no sound, due to a subtle side-effect obfuscation (SDTA_SAMPLESPERSEC has a different value on MorphOS than other OSes).
- +BUG: MorphOS: In 'std/pShell', ExecuteCommand() did not work (had to work-around a MorphOS SDK bug).
- +BUG: Windows: Fixed the installer to correctly update the Command Path (sadly it was never done it correctly, at least from Vista onwards).
- +BUG: Windows: Fixed PEGCC failing to strip executables when using AmiDevCpp.
- +BUG: Windows: In 'std/cPath', if ImportDirPath(), ImportFilePath() or ExportPath() are supplied a NILA path, they now return NILS instead of throwing an exception.
- +BUG: Windows: In 'std/cPath', ExportPath() now handles an empty path (aka the current directory), rather than failing.
- +BUG: Windows: In 'std/cPath_File', CP_MAXNAMELENGTH & CP_COLONCHAR were missing.
- +BUG: AmigaE: In 'libraries/muip', was probably never able to be compiled, now fixed. Also made it visible from 'muimaster', just like 'libraries/mui'.
- +BUG: AmigaE: Fixed various issues (typically use of ; instead of a new line somewhere) which prevented it from compiling obfuscated modules.
- +BUG: AmigaE: Fixed empty OBJECTs (which AmigaE doesn't like).
- +BUG: AmigaE: Fixed typed arrays that use a PTR or ARRAY type.
- +BUG: AmigaE: Fixed array-item accesses on non-storage expressions, e.g. procedure()[i] .
- +BUG: "END array[0]" was wrongly treated as "END array", and could (if you were *lucky*) generate uncompilable code.
- +BUG: The installer would put PEmodules in the "PortablE/PEmodules/PEmodules/" folder when using Simple Mode for a new install. Now just puts it in "PortablE/PEmodules/".
- +BUG: Val() & RealVal() are now thread-safe (oops). This also fixes inexplicable (single-threaded) buggy behaviour of Val() in possibly-rare circumstances.
- +BUG: In 'std/cPath', stopped DeleteDirPath() from following directory links (oops).
- +BUG: Obfuscation mode failed to put $ or % before hexadecimal or binary numbers, causing incorrect (or possibly uncompilable) code. This may have fixed a graphics problem on MorphOS.
- +BUG: Obfuscation mode could use a non-existant name for a method call in certain obscure circumstances (involving a child method with a different interface in the target language of a cached module).
- +BUG: Removed source<>destination restriction for StrAdd().
- +BUG: In 'AmigaLib/ports', fixed a bug which caused it to fail with the exception 'NewM() emulation was passed an unsupported flag' when used.
r6 beta (20.11.2014)
- +NEW: AmigaOS4: Now compiles with the latest AmigaOS4 SDK (53.24). Thanks to Anthony Iliakis for reporting the problem. However, this will likely break compilation under AmiDevCpp for OS4, until/unless it is updated to match the SDK.
r6 beta (14.07.2013)
- +NEW: Added the parameter "startPos=0" to the procedure Val(). This removes the need for pointer arithmetic.
- +NEW: Added the 'std/pBox' module, to provide a simple but very flexible way of storing various types of data, without needing separate getter/setter methods for all of them.
- +NEW: In 'std/cPath', added the RenamePath() procedure, so you don't need to open a file anymore to just rename it.
- +NEW: In 'std/cPath', added the ReadLink() procedure, so it is now possible to get the target of a soft link when the target doesn't exist.
- -NEW: In 'std/cGui', added support for dynamic lists (see cGuiWindow.beginList(), cGuiList, etc), plus three example programs.
- -NEW: In 'std/cGui', added support for embedding native GUI elements (e.g. MUI objects), so people can work-around any cases where PortablE's GUI system is lacking something they need.
- -NEW: In 'std/cGui', added initAllowDropFiles()/etc & getFileDropped()/etc methods to the cGuiWindow class, so GUIs now allow files to be dropped on them.
- -NEW: In 'std/cGui', added initSaveID()/etc methods to the cGuiWindow class, so GUIs can now automatically save/load their position & size.
- -NEW: In 'std/cGui', cGuiButton now listens to initUseLeastSpace().
- -NEW: In 'std/cGui', now activates the first text input item (e.g. cGuiString), so you can start typing straight away.
- -NEW: In 'std/cGui', now generates an event when you leave a text input item without pressing Enter.
- -NEW: In 'std/cGui', now tells the user that the NList or TextEditor classes are missing.
- -NEW: In 'std/cGui', added the queryExtra() method to the cGuiItem class, and made it do something useful for the cGuiList class.
- -CHG: In 'std/cGui', added the "doNotClear" parameter to the methods getCloseRequest() & getQuitRequest(). And calling those methods will now cause their info to be forgotten unless you supply TRUE for doNotClear.
- -CHG: In 'std/cGui', window close requests are now queued, so there is no-longer any chance of them being lost in a race condition.
- +CHG: In 'std/cPath', renamed Exists() to ExistsPath(), Delete() to DeletePath(), and DeleteDir() to DeleteDirPath(). But the old procedures still work for the moment...
- -CHG: In 'std/cGfxSprites', the setDataBox() & getDataBox() methods of cGfxSprite REPLACE the old set/getDataPtr() methods, and their usage is slightly different. This should be completely future-proof, so no more changes will be needed.
- +BUG: Windows: Fixed installation failing to create the required Assignments.txt file. Thanks to Marcus Fernstrom for reporting this bug.
- -BUG: C++: The 'CSH/pAmiga_fakeNewProcess' module (and thus cGfx/cMusic/cSnd) would not work in some situations. Now properly fixed by adding special support to PortablE.
- +BUG: C++: For FOR & some other statements, got rid of the (possibly harmless) GCC warning 'comparison is always true/false due to limited range of data type'.
- -BUG: Fixed obfuscation of FUNCtions randomly marking it's call() method as being an ORPHAN.
- +BUG: Removed source<>destination restriction for StrCopy(), RightStr() & MidStr(); I think Chris Young once requested this. Fixed the type of RightStr()'s eString2 parameter (should have been STRING but was ARRAY OF CHAR for some reason).
- -BUG: In 'std/cGfx', fixed the timer continuously generating bogus events, if stopTimer() was called without the last timer event being handled. Thanks to "mrdarek" for the bug report.
- -BUG: In 'std/cGfx', AmigaOS4; stopped non-drawable bitmaps being moved to video memory by Picasso96. Many thanks to "mrdarek" for the bug report.
- -BUG: In 'std/cGfx', AmigaOS4; fixed a mistake that would have caused non-bitmap drawing to not work after a planned update to OS4.
- -BUG: In 'std/cGfx', AmigaOS4; worked-around composited scaling not working on 16-bit screens.
- -BUG: In 'std/cGfx', AROS; worked-around a strange 24-bit colour bug when drawing filled circles (and also filled circles not being completely filled). Thanks to Alan Fullarton for the bug report.
- -BUG: In 'std/cGfxSprites', the findSpriteAt() method of cGfxStack could wrongly still return the (undocumented) background sprite. Thanks to "mrdarek" for the bug report.
- -BUG: In 'std/cSnd', fixed stereo sounds being silent for their second half. Thanks to "mrdarek" for the bug report.
- -BUG: In 'std/cGui', fixed string objects (like cGuiString) not generating an event when setState() was used on them.
- -BUG: In 'std/cGui', fixed string & number objects generating events despite their contents not changing (in several different circumstances).
- -BUG: In 'std/cGui', fixed cGuiStringBox.getState() not returning anything after the GUI is built.
- -BUG: In 'std/cGui', fixed getState() returning NILS instead of an empty string for cGuiString/etc, if setState() had never been called.
- -BUG: In 'std/cGui', fixed crash if program exited before App was built.
- -BUG: In 'std/cGui', AROS; fixed string objects (like cGuiString) generating (potentially recursive) events when setState() did not change their contents.
- -BUG: In 'std/cGui', AROS; worked-around Zune wrongly reporting the window's size.
- -BUG: In 'std/pShell', Amiga; fixed ShellArgs() to return the exact supplied program parameters, rather than stripping quotes & extra spaces. (Unfortunately still has the old behaviour on Windows.)
r6 beta (07-10-2012)
- +NEW: Added OptMultiThreaded().
- +NEW: AmigaOS4; Added missing (v50) Commodities functions which have no clib declaration.
- +NEW: AmigaOS4; Added missing (v51) Exec functions which have no clib declaration.
- +NEW: AmigaOS4; E's memory allocation procedures now use MEMF_PRIVATE if OPT MULTITHREADED was not used, and when it is they now use MEMF_SHARED without AVT_LOCKing them. This should allow all PortablE programs (including the compiler itself) to be swapped-out to disk when memory runs out.
- +NEW: In 'std/cPath', finally added 64-bit file support for AmigaOS4, and improved handling of files over 2GB for AROS, MorphOS & AmigaOS3.
- -NEW: In 'std/cGfx', now uses REAL double-buffering for Full Screen (except on AROS). This can make animation smoother, and on AmigaOS3 it looks much much better.
- -NEW: In 'std/cGfx', added getPosition() & setPosition() methods to the cGfxWindow class.
- -NEW: In 'std/cGfx', added hideMousePointer option to CreateGfxWindow().
- -NEW: In 'std/cGfxSimple', added ChangeGfxWindow() procedure.
- -NEW: In 'std/cGfxSprites', added setDataPtr() & getDataPtr() methods to cGfxSprite, which do what the setData() & getData() methods USED to do.
- -NEW: In 'std/cGui', added getQuitRequest() & setQuitRequest() methods to the cGuiWindow class, so Exchange quit requests can now be properly handled.
- -NEW: In 'std/cGui', added addBreak() method to the cGuiWindow class.
- -NEW: In 'std/cGui', added initAltColour() method to the cGuiLabel & cGuiFixedListEntry classes.
- -NEW: In 'std/cGui', added initColumnTitles() & infoColumnTitles() methods to the cGuiFixedList class.
- -NEW: In 'std/cGui', windows are finally vertically resizable, thanks to some MUI tips from Thore Boeckelmann. :-)
- -NEW: In 'std/cGui', heavily worked the GUI layout code to behave sensibly in all situations; allowing resizable stuff to be resizable, without adding blank spacing where it would just waste space that should be used by the rest of the GUI.
- -NEW: In 'std/cGui', when iconified it now uses it's own icon (rather than MUI's default icon).
- -NEW: In 'std/cGui', the size & position of windows can now be read & changed, just like with cGfx.
- -NEW: In 'std/cGui', added the cGuiText class.
- -CHG: In 'std/cGui', changed how cGuiTextBox behaves. (The new cGuiText behaves similar to how cGuiTextBox used to, so switch to that if you only need to display one line of text.)
- -CHG: In 'std/cGui', replaced cGuiWindow's setGhosted() method with the setBusy() & getBusy() methods.
- -CHG: In 'std/cGfxSprites', the setData() & getData() methods of cGfxSprite now expect & return a VALUE rather than a PTR. If you need to store pointers, then use setDataPtr() & getDataPtr().
- -CHG: In 'std/cGfxSprites', the findSpriteAt() method of cGfxStack no-longer returns the (undocumented) background sprite. Should help avoid user confusion, and make it impossible for users to modify the background sprite. Thanks to "mrdarek" for suggesting this.
- +CHG: In 'std/cPath', split this module into 'std/cPath_shared', 'std/cPath_File' & 'std/cPath_Dir', so that you can access needed functionality without having loads of unnecessary code loaded into your program.
- +CHG: In 'std/cPath', replaced the makePath() method with getPath() & setPath() methods. This allowed reducing code duplication for the get/set Name/SubPath() methods.
- +CHG: Amiga; removed *Tags() procedures from the modules 'Picasso96API', 'dos', 'exec', 'graphics', 'icon' & 'identify'; they were never supported by AmigaE, only supported a limited number of paramaters, and have unlimited-size taglist alternatives.
- +CHG: In 'dos/dos', made BPTR a real pointer type (and BSTR a real array type), so that they are now auto-initialised to NIL like you would expect.
- +CHG: In 'devices/ahi', recreated this module for all targets, using the latest header files, which helped clean-up various minor issues with the ones originally supplied by Daniel Westerberg.
- -CHG: AmigaOS4; removed superfluous NATIVE {} PROC declarations from all library modules, since OS4 has a separate namespace for library functions.
- +BUG: AmigaOS4; In 'intuition', NewObject() now returns a PTR TO INTUIOBJECT (instead of incorrectly returning an APTR) to match the SDK, and which I feel makes more sense, although this does mean that OS4 now differs from OS3, AROS, etc.
- +BUG: In 'dos' & 'icon', BOOL return values (0,-1) were actually C boolean values (0,1).
- +BUG: Double-declarations of RAISE would cause a compilation crash instead of error message.
- +BUG: RAISE statements were being inherited between modules, when the module cache was not used. They should have always been private to that particular module.
- -BUG: In 'std/cGfx', fixed problem when bitmaps are (approximately speaking) larger than the screen size, especially for certain sized bitmaps. Thanks to "mrdarek" for reporting the bug.
- -BUG: In 'std/cGfx', fixed potential problem with large bitmaps on very large screen sizes.
- -BUG: In 'std/cGfx', fixed a theoretical bug in timer.device usage (which does not seem to cause a problem on any current Amiga-like system).
- -BUG: In 'std/cGui', fixed crashing when a window was closed before all it's events were handled.
- -BUG: In 'std/cGui', fixed WaitForChangedGuiItem() not returning an already-occured event immediately (and instead waiting for upto 0.1 seconds, i.e. for an IntuiTick). Could become a bottleneck for heavy GUI state updating (e.g. selectable lists).
- +BUG: In 'std/cPath', fixed cFile's setName() method wrongly expecting a dir name (ending in a slash).
- +BUG: In 'intuition', fixed the OpenW() helper procedure ignoring certain parameters when no "gadgets" or "screen" was supplied.
- +BUG: fixed multiple-expression END statements from falling outside of one-line statements; definitely affected AmigaE (since forever), but might have affected C++ too.
- +BUG: AmigaE; fixed a crash when compiling an in-line PROC containing an assignment.
- +BUG: AmigaE; fixed a crash when compiling a multi-variable assignment in certain situations.
- +BUG: AmigaE; fixed "tag" & "data" being the wrong way around in "tagitem". This probably explains a lot of problems...
- +BUG: AmigaE; fixed the assumption that AmigaE library bases are declared as having type PTR TO lib (they aren't), thus potentially generating uncompilable code.
- +BUG: AmigaE; fixed multiple-expression END statements from generating uncompilable code (in at least some cases).
- +BUG: AmigaE; fixed automatic casting of member access from generating uncompilable code.
- +BUG: AmigaE; fixed a member access of a cast of a member access from generating uncompilable code (it appears to be unsupported by the AmigaE compiler).
- +BUG: AmigaE; fixed NEW of an empty immediate/typed list generating uncompilable code (empty immediate/typed lists seem to be unsupported by the AmigaE compiler).
- +BUG: AmigaE; fixed one constant equaling an earlier constant on the same line from generating uncompilable code (it appears to be unsupported by the AmigaE compiler).
- +BUG: AmigaE; fixed ... DO EMPTY generating uncompilable code.
- +BUG: AmigaE; fixed removal of unnecessary casts also removing spacing at the end of the cast, which could potentially lead to uncompilable code.
- +BUG: AmigaE; prevented "self" being used as a local variable in a normal procedure, as this causes AmigaE to get completely confused.
- +BUG: AmigaE; fixed wrong multiple return values when an in-line procedure with a RETURNS declaration directly called a procedure/method for all of it's return values. This should also prevent some unnecessary C++ code being generated.
- +BUG: AmigaE; fixed sometimes generating incorrect or uncompilable floating-point arithmetic, due to brackets being incorrectly removed.
- +BUG: AmigaE; fixed floating-point divisions generating incorrect code when when one values was not a float.
- +BUG: AmigaE; added the missing 'ptplay' module.
- +BUG: AmigaE; In 'intuition', fixed parameter types of some helper procedures not matching those used for other targets.
- +BUG: AmigaE; fixed ADDRESSOF causing spurious compilation warnings.
- +BUG: C++; fixed variables that are pointers with NATIVE types (e.g. BPTR) not casting their default value (e.g. NULL).
- -BUG: AROS; got rid of harmless "superfluous cast" warnings from a few modules.
r6 beta (09-04-2012)
- +NEW: Added the modules 'Picasso96API' (for OS4) & 'target/cybergraphics' (for AROS & MOS).
- +NEW: AmigaOS4; Added missing Graphics functions which have no clib declaration, i.e. CompositeTagList().
- +NEW: AmigaOS4; Added 'graphics/composite' module.
- -NEW: AmigaOS3; In 'std/cGfx', added tentative support for AmigaOS3 (AGA).
- -NEW: In 'std/cGfx', the drawing of masked bitmaps now uses hardware acceleration (when supported by OS4 & MOS), so large masked bitmaps no-longer slow-down drawing.
- -NEW: In 'std/cGfx', scaling of bitmaps is now much faster on AmigaOS4 (probably using AltiVec acceleration).
- -NEW: In 'std/cGfx', automatically handles bitmaps that are larger than the largest size supported by the graphics card, so they won't slow-down drawing.
- -NEW: In 'std/cGfx', added cGfxWindow.readDot(). Requested by several people!
- -NEW: In 'std/cGfx', added cGfxBitmap.rotate().
- -NEW: In 'std/cGfx', masks can now be generated from High/True-colour pictures.
- -NEW: In 'std/cGfx', should now work on <= 256 colour screens.
- -NEW: AROS; In 'std/cGfx', scaling of masked bitmaps is now MUCH faster.
- +NEW: In 'std/cPath', added the cPath.create() method. This is much simpler & less error prone than open() in many cases.
- -NEW: PEGCC's DEBUG switch now uses "GCCOPTS -g" for all OSes (not just AmigaOS4), so debugging is much easier on atleast AROS now.
- -BUG: In 'std/cGfx', the right mouse button should now be detected for (non-Full) windows.
- -BUG: In 'std/cGfx', DestroyBitmap()/etc did nothing (in most cases), due to a mistake in the last release.
- -BUG: In 'std/cGfx', drawn bitmaps could overwrite any other windows above the graphics window, if auto-update was not disabled.
- -BUG: In 'std/cGfx', now unlocks the Public screen (used by non-Full windows) when the program quits.
- -BUG: Fixed the examples StarsXY_ToySpaceshipSprite1.e & StarsZYX_ToySpaceshipSprite1.e to use the now-required addToGfx() method, and corrected the documention about creating a sub-class of cGfxDrawable.
- +BUG: Accessing an object member of a variable/etc with a NATIVE type would generate uncompilable code.
r6 beta (21-03-2012)
- -CHG: In 'std/cGfx', DestroyBitmap()/etc can now be used on a bitmap used by a sprite, without causing a crash (the bitmap will simply not be destroyed). Issue reported by "mrdarek".
- -CHG: For PortablE's AROS installer, worked-around an incorrect settings file that comes with Icaros v1.4.0 .
- -CHG: In 'std/cGfxSpritesSimple', CreateGfxWindow() & DestroyGfxWindow() can now be used (with care!). Thanks to "mrdarek" for reporting the issue.
- -BUG: In 'std/cGfx', fixed bitmaps not being auto-destroyed when the window was destroyed. Thanks to "mrdarek" for the bug report.
- -BUG: For PortablE's AROS installer, fixed a bug which would cause a bogus Icaros error message at start-up if you moved the PEmodules folder.
r6 beta (05-03-2012)
- -NEW: In 'std/cGfx', added a "thickness" option to drawLine(). Requested by "mrdarek".
- -NEW: In 'std/cGfx', added cGfxWindow.extractBitmap(). Requested by "mrdarek".
- -NEW: In 'std/cGfx', added cGfxDrawable.drawTiled(), to ease porting BlitzBasic programs that use TileImage.
- -NEW: In 'std/cGfxSpritesSimple', added FullyRedrawSprites(). Also added the "forceFull" parameter to cGfxStack.redraw().
- -NEW: In 'std/cGui', windows now receive a close request when Exchange tried to remove the app.
- -NEW: In 'std/cSnd', heavily rewrote the overly complex (i.e. potentially buggy) client/server messaging, and moved that into a general-purpose module.
- +NEW: In 'std/cPath', changeExtra() now supports creating & destroying Amiga links (i.e. "SLNK" & "HLNK").
- +NEW: In 'std/cPath', added "LINK" to queryExtra().
- +NEW: In 'std/cPath', added the CreateLink() procedure.
- +NEW: Heavily rewrote the installer; the Amiga version now uses choice requesters, it has a Simple Installation mode, you can change the PEmodules assignment, and more. Thanks to Hypex for suggestions!
- +NEW: AmigaOS4; Added the 'target/application' module for AmigaOS4's application.library .
- +NEW: Improved low-memory handling of FastNew/NEW/etc.
- +NEW: In 'std/pShell', added the constants SHELL_RET_OK, SHELL_RET_WARN, SHELL_RET_ERROR & SHELL_RET_FAIL.
- +NEW: AmigaOS4; Executable sizes have been reduced by up to 60-120KB, thanks to an OS4 SDK discovery made by Kas1e.
- +NEW: AmigaOS4; Added support for libraries with multiple interfaces (like application.library).
- +CHG: AmigaOS4; In 'dos', fixed DevNameFromLock() & DevNameFromFH() to correctly return BOOL.
- +CHG: C++: New()/etc no-longer use malloc()/etc, but directly use Exec's AllocVec()/etc (except for MorphOS & Windows). Automatic deallocation on exit still occurs.
- +CHG: In 'std/cPath', queryExtra() now returns paths for Amiga links (i.e. "SLNK" & "HLNK") using the portable format.
- -CHG: In 'std/cGfxSprites', changed get/setWrapped() to get/setTiled().
- -BUG: In 'std/cGfx', drawCircle() drew the circle at the wrong location (if it didn't need clipping or autoUpdate was enabled).
- -BUG: In 'std/cGfx', drawCircle() might not be fully drawn when autoUpdate is disabled (and could corrupt the window border when it was enabled).
- -BUG: In 'std/cGfxSprites', setRegion() did not affect tiled sprites correctly. Also the old region could be wrongly drawn once.
- -BUG: In 'std/cGfxSprites', if setBackgroundColour() was called very early, then it would not correctly update the window.
- +BUG: In 'std/cPath', cFile.queryExtra("SLNK") did not work for soft links.
- +BUG: In 'std/cPath', cDir.makeEntryList() would throw an exception when there were soft links pointing to non-existant files/dirs.
- +BUG: In 'std/cPath', when Delete()ing a link using force=TRUE, the target of the link no-longer has the protection flags set to RWED.
- +BUG: Fixed FastNew/NEW/etc being very slow and/or using excessive amounts of memory in certain circumstances (on AmigaOS4, AmigaOS3 & AROS).
- +BUG: Fixed New/FastNew/NEW/etc crashing when they failed to allocate any memory. May have been a long-standing bug.
- +BUG: Fixed some small theoretical bugs in memory system used by FastNew/NEW/etc (on AmigaOS4, etc).
- -BUG: Obfuscation did not correctly handle custom TYPEs which were PTRs or ARRAYs.
- -BUG: Fixed custom types often being reported as their underlying type, or reported without their underlying type.
r6 beta (27-10-2011)
- +NEW: AmigaOS4; Added BASIC networking support, which is compatible with AmigaE's AmiTCP modules (but not all modules are provided). Requested by several people!
- +NEW: AROS; Added 'libraries/mpega' module, thus making it available for all targets. AROS needs a modified <libraries/mpega.h> file to work properly with C++.
- +NEW: Added 'layers' module.
- +NEW: AmigaOS4; Added some DOS functions which have no clib declaration, such as GetFilePosition().
- +NEW: AROS; Fixed the widely-used 'devices/timer' module to compiler on Icaros v1.3.0 (and later). Thanks to "mrdarek" for the bug report.
- +NEW: AROS; Fixed certain other modules to fully work on Icaros v1.3.0 (and later).
- +NEW: Improved a few of the error messages.
- +NEW: Added a "Debug" switch to PEGCC. Particularly useful for AmigaOS4.
- +NEW: Added a "TargetDir" parameter to PEGCC.
- +NEW: PEGCC now immediately halts if the executable or target code cannot be replaced, rather than waiting until parsing/compilation has finished.
- +NEW: In 'std/pShellParameters', added the "shellArgs" & "silent" parameters to ParseParams().
- -NEW: Improved PrintL() & StringFL() to handle lists of up to 20 items. Added for "mrdarek".
- -NEW: Wrote the "Creating your own cGfxDrawable sub-class" sub-chapter for the StandardFunctionality document.
- -NEW: In 'std/cApp', added the MinimiseApp() procedure & minimise() method.
- -NEW: In 'std/cGui', added the setData() & getData() methods to the cGuiItem class. Very useful for handling a large list of items.
- -NEW: In 'std/cGui', added the infoCurrentBuildGroup() method to the cGuiWindow class.
- -NEW: In 'std/cGui', added the cGuiFixedList & cGuiFixedListEntry classes. This is a quick work-around the lack of proper list support in cGui.
- -NEW: In 'std/cGui', added the setGhosted() method to the cGuiWindow class.
- -NEW: In 'std/cGui', added the queryExtra() method to the cGuiWindow class.
- -NEW: In 'std/cGui', setPopupHint() now allows you to clear any existing hint by supplying NILA.
- -NEW: In 'std/cGui', addLabel() now allows the text's alignment to be specified.
- -NEW: In 'std/cGui', added the initUnit() & infoUnit() methods to the cGuiNumberItem class.
- -NEW: In 'std/cGui', added the initPic() & infoPic() methods to the cGuiButton class.
- -NEW: In 'std/cGfx', massively speeded it up on AROS (and also made it more compatible with buggy Icaros v1.3.0/1), by changing how friend bitmaps are allocated.
- -NEW: In 'std/cGfx', added support for detecting the F-keys. Requested by "mrdarek".
- -NEW: In 'std/cGfx', windows can now be resized (by both the user & the programmer)... and any cGfxStacks will automatically redraw themselves as required. Requested by "mrdarek".
- -NEW: In 'std/cGfx', added the drawCircle() method, thanks to some portable code from "mrdarek". But uses direct Amiga graphics calls unless clipping is required & autoUpdate=FALSE.
- -NEW: In 'std/cGfx', added an "unfilled" option to drawBox(). Requested by "mrdarek".
- -NEW: In 'std/cGfxSprites', speeded-up scrollAllSprites() & scrollAllLayers() when autoDraw is TRUE.
- -NEW: In 'std/cGfxSprites', added the noScrollX/Y parameters to setBackgroundDrawable().
- -NEW: In 'std/cGfxSpritesSimple', added the noTileX/Y parameters to SetBackgroundDrawable().
- -NEW: In 'std/cGfx', the scroll-wheel now works on AROS & MorphOS, due to NewMouse support.
- -CHG: In 'std/cGui', notification functions are now called by Check/WaitForChangedGuiItem(), rather than happening asynchronously. This is more predictable, and means OPT MULTITHREADED won't ever be needed.
- -CHG: In 'std/cGui', changed how cGuiGroupGrid is laid-out in MUI, for a hopefully better look.
- -CHG: In 'std/cGui', apps now have a MUI base name.
- -CHG: In 'std/cGfx', now only starts a separate process if AutoUpdate is FALSE *and* FrameSkipping is TRUE.
- -CHG: In 'std/cGfx', worked-around a bug in Linux-hosted AROS.
- -CHG: In 'std/cGfx', worked-around a memory corruption crash caused by a MorphOS (v2.7) picture datatype bug (for pictures with <= 256 colours). An unfortunate side-effect will be a small memory leak...
- -CHG: In 'std/cGfxSprites', stopped setRegion() from scrolling the layers (it was trying to keep their origins aligned with the top left corner of the region).
- +CHG: In 'std/cPath', if ImportDirPath(), ImportFilePath() or ExportPath() are supplied a NILA path, they now return NILS instead of throwing an exception.
- +CHG: In 'libraries/mui', MUIA_Group_Forward was missing for AmigaOS4 & AROS.
- +CHG: In 'dos/dos', BADDR()/MKBADDR() now return/take a PTR (instead of an ARRAY).
- +CHG: Sign(), OstrCmp() & OstrCmpNoCase() now have the return type RANGE -1 TO 1 (instead of BYTE).
- +CHG: When a procedure's return type is defined by it's return expression, the type will no-longer be converted to a basic (non-RANGE) type unless the expression has a specific value (such as FALSE).
- +CHG: Changed "depended on an invalid cache" message to "depended on an outdated cache", so hopefully less scary & less prone to being misunderstood.
- +CHG: In 'dos' on AROS, fixed MakeLink() not returning a BOOL, and it's "dest" parameter being an APTR instead of a VALUE.
- -BUG: In 'AmigaLib/lists', newList() was broken for MorphOS/AROS/OS3. The problem was spotted by Piru.
- -BUG: In 'std/cGfx', various fixes & work-arounds to get everything working on MorphOS.
- -BUG: In 'std/cGfx', makeScaledTo() did not work.
- -BUG: In 'std/cGfx', startTimer() did not work on MorphOS.
- -BUG: In 'std/cGfx', SetAutoUpdate(TRUE) could cause MorphOS to crash when the user changed screens.
- -BUG: In 'std/cGfxSprites', setRegion() failed to redraw any newly drawable sprites, and could cause sprites to have the wrong auto-drawability.
- -BUG: In 'std/cGfxSprites', using setRegion() with -1 for width/height left the right/bottom edge unchanged, rather than setting it to the edge of the window.
- -BUG: In 'std/cGui', multiple 'simultaneous' events will no-longer be lost.
- -BUG: In 'std/cGui', setPopupHint(), setState(:ARRAY OF CHAR) & add*(label:ARRAY OF CHAR) now copy the supplied string, instead of simply storing the pointer.
- -BUG: In 'std/cGui', fixed empty Groups (and FixedLists) from causing a broken GUI (seems MUI does not like empty groups!).
- -BUG: In 'std/cGui', fixed CheckForChangedGuiItem(FALSE) not clearing getCloseRequest().
- -BUG: In 'std/cGui', fixed start-up crashes on MorphOS, due to MUI app's Title & Base names sometimes breaking (mostly!) documented restrictions.
- -BUG: In 'std/cGui', fixed setNotifyFunction() not returning the correct object type.
- -BUG: In 'std/cGui', fixed cGuipathString.getState() returning an invalid path when the user supplied a non-existant volume.
- -BUG: In 'std/cMusic' & 'std/cSnd', if there is no AHI device available then the program will no-longer hang on start-up, but instead music/sounds will fail to load.
- -BUG: In 'std/pShell', fixed ProgramName() wrongly returning the whole program path on MorphOS.
- +BUG: In 'std/cPath', RecurseDir() would supply dirPath=NILS to funcDirFailure().
- +BUG: In 'std/cPath', the Windows version could fail to increase the size of a file on an Amiga-hosted Samba share (now it automatically falls-back to a slower but normal method of increasing the file size).
- +BUG: In 'std/pCallback', fixed C++ compilation problem with non-simple function pointers.
- +BUG: In 'std/pShellParameters', user parameters beginning with a number would not be treated as a single whole word, even when quotes were used.
- +BUG: In 'libraries/commodities', the newbroker object was missing pad members, which would cause compatibility problems for typed lists. Thanks to Chris Young for reporting the bug.
- +BUG: An in-line procedure's expression (or a normal procs return expression) which had a RANGE type would appear as a basic (non-RANGE) type.
- +BUG: For in-line procedure or method with a RETURNS declaration, a call would have the type of it's return expression (when it should have had that declared by RETURNS).
- +BUG: A parameterised macro with no body would eat the next line.
- +BUG: C++: OPT AMIGAE could cause a "loses precision" C++ compiler error when a pointer/array was (automatically or otherwise) cast to a BOOL.
- +BUG: C++: STATIC strings & lists now work inside immediate lists, instead of appearing as NIL.
- +BUG: C++: In-lined procedures could cause C++ compiler error with multiple address-of (&) operators in certain cases.
- +BUG: AmigaOS4: Procedures were not defined in the 'other/battclock', 'other/cia', 'other/misc' & 'other/potgo' modules. Thanks to Chris Young for reporting the bug.
- +BUG: Fixed some built-in procedures not being thread-safe, unfortunately including FastNew().
- -BUG: Programs using the cGfx, cSnd & cMusic modules no-longer crash when the program executable is renamed/moved/deleted while it is running, as the 'CSH/pAmiga_fakeNewProcess' module has been fixed.
- -BUG: Using ADDRESSOF without OPT POINTER caused a misleading error message.
- -BUG: Obfuscation mode could not parse code where the name of a FUNC was used as a value.
- -BUG: Obfuscation mode could produce uncompilable code when a constant was used in a BUT or IF THEN ELSE expression.
r6 beta (28-04-2011)
- -BUG: In 'std/cGui', for a Group as the first item of another Group, all of it's own items would not respond to user interaction (nor be part of a MUI cycle chain).
- -BUG: In 'std/cGui', for a Group as the last item of another Group, followed by another item, all of it's own items would not respond to user interaction (nor be part of a MUI cycle chain).
- -BUG: In 'std/cGui', for a Page Group as the first (outer) Group of a window, it would not respond to setState(), and setStateItem() would crash.
r6 beta (23-04-2011)
- -BUG: In 'std/cPath', reading & writing files did not work (due to module obfuscation bugs). Thanks to "mrdarek" for reporting the bug.
- -BUG: Obfuscation mode did not always in-line procedures correctly.
r6 beta (20-03-2011)
- +BUG: PEGCC should no-longer fail with the error message "Failed to strip executable" on AmigaOS4 when you have the source code folder open in Filer, DOpus4, etc. (If a similar problem exists on other OSes, then this will fix it too.)
r6 beta (13-03-2011)
- +NEW: Further improved how the installer offers to install the necessary GCC includes.
- +BUG: Fixed a problem with the installer on MorphOS, which caused it to appear to have got stuck.
r6 beta (09-03-2011)
- +NEW: Updated the installer for AmigaOS3 & MOS, so that it offers to install the necessary GCC includes. Also improved how this is done.
- +CHG: The installer will now create a PEmodules folder, rather than assuming you have created one.
r6 beta (13-02-2011)
- +NEW: Updated the installer for AmigaOS4, so that it offers to install the necessary GCC includes.
- +CHG: Minor improvements to the documentation.
- -BUG: In 'std/cGfx', fixed MakeFractalBitmap() to handle red colours above $7F (such as RGB_RED & RGB_ORANGE).
- -BUG: In 'std/cGfx', fixed the module to not crash on MorphOS when you change screens.
r6 beta (06-02-2011)
- +NEW: Added 'std/cApp', 'std/cGfx', 'std/cGfxSimple', 'std/cGfxStack', 'std/cGfxStackSimple', 'std/cGui', 'std/cMusic', 'std/cSnd' & 'std/pTime' modules.
- +NEW: Added 'keymap' & 'ptplay' modules.
- +NEW: Added a module obfuscation mode to PortablE.
- +NEW: Added ADDRESSOF to obtain the address of a variable. Requires OPT POINTER.
- +NEW: Added OS4 Exec functions which have no clib declaration, such as SetMethod().
- +NEW: The Amiga version of the installer now uses a file requester! (More user-friendly)
- +NEW: CreateNewProc() now automatically adds the tagitems required to work with AmigaOS4 & MorphOS. Suggested by by Daniel Westerberg.
- +NEW: C++: The multithreading problems have been solved by the 'CSH/pAmiga_fakeNewProcess' module. (Not yet documented, so please ask.)
- +NEW: C++: OpenS() now uses BestModeID to pick a more appropriate screen (and required for >8bit depth on OS4).
- +NEW: 'std/cPath': Added "SLNK" & "HLNK" (soft/hard link) specific to queryExtra() for AmigaOS.
- +NEW: Added the PrintL() & StringFL() function.
- +NEW: Added target-specific preprocessor macros, such as #ifdef pe_TargetOS_AmigaOS4. Use with care!
- +NEW: Functions can now be called from members (in addition to variables).
- +NEW: Added the PrintException() & QuadToStr() functions.
- +NEW: Added the BigEndian...(), LittleEndian...() & SwapEndian...() functions.
- +NEW: In 'std/pShell', added the ProgramName() function.
- +NEW: Added OpenInOut() & CloseInOut(), for use with SetStdIn()/SetStdOut()/etc, since the AmigaDos Open() function won't work with them on C/C++.
- +NEW: Added 'devices/ahi' for AROS, thus making it available for all Amiga targets.
- +CHG: Pointer & array global variables are now automatically initialised (to NIL), like local variables already were.
- +CHG: The EndianSwap...() functions are now depreciated, in favour of the new BigEndian...() functions.
- +CHG: CALLBACK is now only supported by the OPT POINTER mode.
- +CHG: For PEGCC, the "LeaveTargetFile" parameter replaces "LeaveCppFile" (which is now depreciated & will be removed at a later date).
- +CHG: No-longer warns about FLOAT equality comparisons with 0.
- +CHG: SetStdIn() & SetStdOut() were missing from the "Standard Functionality" document
- +CHG: Moved 'std-alpha/pSemaphores' to 'std/pSemaphores'.
- +CHG: In 'std/cPath', made ImportDirPath(), ExportPath(), InvalidDirPath(), IsDir() & cDir.makeEntryList() handle empty dir paths.
- +CHG: In 'graphics', BltBitMap() was missing for AmigaOS3 (had to work-around an AmiDevCpp problem).
- +CHG: In 'intuition', LeftMouse() & WaitLeftMouse() no-longer clear existing IDCMP flags.
- +CHG: In 'intuition', some procedures had PTR TO ULONG instead of ARRAY OF ULONG, and some had PTR TO instead of ARRAY OF easystruct.
- +CHG: In 'intuition/classusr', CLASSID is now an ARRAY rather than a PTR.
- +CHG: In 'libraries/mui', get() is now a proper procedure, and it's "store" parameter is an ARRAY instead of PTR TO ULONG to avoid annoying type-checking errors (especially with ADDRESSOF string).
- +CHG: In 'asl', changed filerequester.arglist from PTR TO wbarg to ARRAY OF wbarg.
- +CHG: In 'datatypes', made DoDTMethodA()'s "msg" parameter have the type "ARRAY" (instead of "PTR TO msg"), and the procedure itself had been missing on OS3/MorphOS.
- +CHG: Retranslated the MUI example programs to use ADDRESSOF and no-longer use OPT AMIGAE. Also added the missing 'Subtask' program.
- +CHG: The RealF() parameter decimalPlaces is no-longer a BYTE.
- +CHG: Minor tweaks to various library modules.
- +CHG: No-longer creates superfluous code (proxy methods) for private child methods that have been overridden.
- +CHG: Allowed a ; where a new line was previously required by a few expressions & statements.
- +CHG: StringF() is now much more efficient for small target E-strings (under 1000 characters).
- +BUG: StringF() could corrupt memory in certain situations.
- +BUG: StringF() did not set (nor correctly return) the E-string's length when it's maximum length was over 1000 characters.
- +BUG: Using a % inside a string being Print()ed could cause the program to crash. Fixing this means that users must use a blackslash before it when the string isn't used with Print(), StringF(), etc.
- +BUG: NEW array[size] would not allocate sufficient memory for an array of objects, and thus cause memory corruption & other mis-behaviour.
- +BUG: NEW [...]:object would not allocate (nor copy) most of the array. Related to the previous problem, and hopefully prevented all future problems of this kind!
- +BUG: C++: Division could give a wrong result (due to bad C++ casting), when an expression of type INT or smaller was divided by a constant sufficiently large to give a smaller resulting type.
- +BUG: C++: Maths expressions could theoretically give the wrong result (due to bad C++ casting), but only in very unusual circumstances.
- +BUG: C++: FOR did not terminate correctly (or at all!) if the TO expression ended with certain operators, specifically AND, OR, XOR, IF, BUT, >=, >, <=, <, =, <>, :=, NEW.
- +BUG: C++: DEFAULT of a simple SELECT statement would "break" out of any enclosing loop if any of the CASEs weren't constant.
- +BUG: C++: In-line procedures which returned a different type to that declared by RETURNS could generate uncompilable code.
- +BUG: C++: Val() gave the wrong result for hex & binary values >= $80000000.
- +BUG: C++: A backslash at the end of a -> comment would cause the following line to be ignored by C/C++. (This caused the minute hand of clock.e to disappear.)
- +BUG: C++: GCC would warn about "overflow in implicit constant conversion" when a non-decimal number exceeding 0x7FFFFFFF was assigned to an INT or smaller.
- +BUG: C++: An exception in main()'s FINALLY would not be caught, causing an error message to be displayed.
- +BUG: C++: A main() without any return values would generate an "int main()" procedure that didn't explicitly return a value (now returns 0).
- +BUG: AROS: Stopped PEGCC from stripping the executable, since that produced a non-executable file with the version of AROS I used for testing.
- +BUG: Fixed the OptAmigaE switch sometimes causing an "illegal circular reference between modules" error. Thanks to Damien Stewart for reporting the bug.
- +BUG: Shl() & Shr() gave wrong result for negative shift values.
- +BUG: If a method always returned a constant value (using ENDPROC) then that value was wrongly used during compile-time evaluation of such method calls, even though a sub-class could change it.
- +BUG: Fixed a hash table bug which could be revealed by a very large number of global variables (and possibly other cases).
- +BUG: Using SIZEOF on a RANGE type, or having an ARRAY of a RANGE type, would cause PortablE to crash.
- +BUG: A private child method overridden by a parent method (of the same name) could have been incorrectly called by code from the child's module.
- +BUG: UNGENERIC didn't actually do anything!
- +BUG: In 'graphics', SetStdRast() returned the new rastport rather than the old one, while (RGB) table parameters were PTR TO instead of ARRAY OF.
- +BUG: In 'intuition', some procedures no-longer worked on OS4, due to the latest SDK changing some APTR parameters to PTR TO INTUIOBJECT.
- +BUG: In 'intuition', on AROS some procedures like DoMethodA() did not (always) compile. Now fixed!
- +BUG: In 'std/cPath', the timerequest object is now allocated correctly (although it didn't seem to cause a problem).
r5 (27-11-2009)
- NEW: Added experimental support for generating MorphOS compatible C++ code, using OS=MorphOS. And comes with MorphOS executables. Even MUI custom classes seem to work.
- NEW: MUI programs with custom classes can now be compiled by AmiDevCpp for OS3, thanks to a work-around. (AmiDevCpp does not support registered parameters.)
- NEW: Added emulation of AmigaE's ! (floating point) operator to the compatibility mode, as well as ensuring that floating-point values are stored in FLOAT variables.
- NEW: Added OPT MULTITHREADED, so that FastNew/NEW/etc do not have to suffer the overhead of multi-threaded support, unless your program is multi-threaded!
- NEW: C++: Added support for the missing string formating codes (\l, \r, \z, [w] & (x,y)). Requested by Daniel Westerberg.
- NEW: PortablE was optimised to be up to 1.65 times faster than previously (greatest using cache), mostly thanks to profiling the code (plus disabling of multi-threaded support).
- NEW: FastNew (and so NEW) is now implemented using a TLSF algorithm, with a Slab-like layer to reduce the memory overhead for small blocks. Unlike in AmigaE, FastDispose()ed memory is now really freed!
- NEW: Significantly reduced PortablE's memory usage when parsing code, which combined with the improved FastNew reduces PortablE's memory usage by about 54%!
- NEW: Added FastMod() which is roughly twice as fast as Mod().
- NEW: Shl() & Shr() now accept negative shift values, unlike SHL & SHR. So they are no-longer depreciated.
- NEW: RETURN is now implemented using JUMP instead of Raise(0). Gives a signficant speed-up, and avoids AmigaOS C++ multi-threading problems. Requested by Daniel Westerberg.
- NEW: Immediate or preallocated lists are now really allocated on the stack (rather than dynamically faking it), as long as they meet certain conditions (like not exceeding 64 items). Helps avoid C++ multi-threading problems. Requested by Daniel Westerberg.
- NEW: Modules contributed by Daniel Westerberg: devices/ahi (OS3/OS4), libraries/ahi_sub (all), libraries/cd_play (all), libraries/freedb (all), libraries/mpega (OS3/OS4), mui/Lamp_mcc.e (OS3/OS4), mui/TheBar_mcc.e (OS3/OS4).
- NEW: 'std/cPath': cDir.open() & cDir.makeEntryList() were enhanced to be more robust, for the Windows version. Scan the whole C drive if you wish!
- NEW: 'std/cPath': RecurseDir() was enhanced to (1) allow the user to handle dir scanning failure, and (2) allow the supplied file/dir FUNCtions to be combined.
- NEW: 'std/cPath': Added FastIsFile(), FastIsDir(), DeleteDir() & CreateDirs() procedures.
- NEW: Added the portable examples AmigaAttributes.e, Timer.e & RecursiveDir.e . Improved BinDif.e .
- NEW: Improved detection of when global variables & IF expressions are static, which improves efficiency of generated code.
- NEW: My documentation generator now escapes the special AmigaGuide & HTML characters (so they don't disappear!), and it supports clickable chapter links, plus bold/italics/etc emphasis.
- CHG: Trying to replace a preallocated object now causes an error in the compatibility mode.
- CHG: If a PROTOTYPE procedure isn't replaced within any modules then an error is now reported. Requested by Daniel Westerberg.
- CHG: NewArray() (and so large typed lists) now uses FastNew().
- CHG: Now reports an error if source & destination are the same for e-string functions. Problem reported by Matthias Rustler.
- CHG: C++: '/h' is now converted to '%lx' (instead of '%x'), so that it works with Exec's Printf()/etc functions. Thanks for Daniel Westerberg for reporting this.
- BUG: In 'std/cPath', FindName() would return an empty string if the path was for a file with a single character for a name.
- BUG: In 'std/cPath', cDir.makeEntryList() would always report a soft-link as a file. Fix implemented using an idea from Daniel Westerberg.
- BUG: In 'std/cPath', did not support Window's "working directory" concept, where each drive has a Current Directory. Now fixed.
- BUG: In 'std/pShell', ShellArgs() would loose empty parameters enclosed in quotes like "".
- BUG: In 'std/pShellParameters', GetParam() would not return the first two characters of a \F parameter if it begin with a "quote" character.
- BUG: "CASE x TO y" would not compile (unless using OPT AMIGAE), due to changes in the type system, probably since r1.
- BUG: Fixed a rare hash table bug that could crash PortablE when compiling any program, but which was much more likely with large ones. Thanks to Daniel Westerberg for reporting symptoms of the bug.
- BUG: An IF expression with a non-static conditional expression could wrongly be treated as static in certain situations, potentially causing uncompilable code. Reported by Daniel Westerberg.
- BUG: Attempting to replace a non-existant procedure would cause a (harmless) enforcer hit. Reported by Daniel Westerberg.
- BUG: The type resulting from a / or SHR could cover a random RANGE. Thanks to Daniel Westerberg for reporting symptoms of the bug.
- BUG: Anything declared with a RANGE type would appear as a basic (non-RANGE) type outside of the module.
- BUG: A local DEF statement extended over multiple lines did not allow an empty line.
- BUG: Prevented a case where macros could cause an error report to show a large part of the module containing the error. Reported by Daniel Westerberg.
- BUG: A semi-colon after an ENDPROC would cause PortablE to get stuck in an infinite loop. Reported by Daniel Westerberg.
- BUG: C++: AstrCopy() would write one too many characters, thus corrupting memory. Reported by Daniel Westerberg.
- BUG: C++: Casting a floating-point value to an integer did not do so for the generated code.
- BUG: C++: The $STACK cookie was missing a \000 before it.
- BUG: AmigaE: SELECT statements would not produce compilable code if their (storage) expression did not have the type LONG. Reported by Daniel Westerberg.
- BUG: AmigaE: If RETURNS was used, but ENDPROC had a comment immediately after it, then the generated code would not have a space between ENDPROC & the return variables. Thanks to Daniel Westerberg for reporting symptoms of the bug.
r4 (29-05-2009)
- NEW: PortablE now has basic support for Windows.
- NEW: PortablE now runs up to 2 times faster than previously (greatest using cache), due an O(n) algorithm being used during deallocation.
- NEW: PortablE now comes with a basic installer, for all supported platforms.
- NEW: Replaced PE-GCC script with PEGCC program, which means you can use it with Windows & AROS now.
- NEW: Replaced DeleteModuleCache script with a program, which means you can use it with Windows & AROS now.
- NEW: Added MUI support for AROS. Thanks to Matthias Rustler for some help.
- NEW: Added support for OPT STACK (previously did nothing). Requested by Daniel Westerberg.
- NEW: Error reports involving macros now report the line number, rather than nothing. Requested by Daniel Westerberg.
- NEW: FastNew() & things that use it (e.g. ILISTs) are now thread-safe. Requested by Daniel Westerberg.
- NEW: MemCopy(), ArrayCopy(), StrCmp() & OstrCmp() now support offsets, to reduce the need for pointer arithmetic.
- NEW: Added EndianSwapBIGVALUE().
- NEW: Added 'std/cPath', 'std/pCallback', 'std/pShell', 'std/pShellParameters', 'std/pStack' modules.
- NEW: Added 'std-alpha/functions', 'std-alpha/pSemaphores' modules.
- NEW: Various miscellaneous improvements & fixes to the modules.
- NEW: Added the portable examples BinDif.e, DeleteModuleCache.e, InstallPortablE.e & PEGCC.e .
- NEW: C++: Added additional brackets around an assignment in an if() statement, to prevent a -wall warning from GCC. Requested by Daniel Westerberg.
- NEW: C++: Code generated for NEW class.method() no-longer ends with a variable when it would be used, to prevent a -wall warning from GCC. Requested by Daniel Westerberg.
- CHG: Destructor methods (i.e. end) now PREVENT exceptions being throw outside of them, because C++ cannot handle this. Thanks to Matthias Rustler for reporting a bug, which lead me to discovering C++ cannot handle it.
- CHG: Ensured that 'dos' module procedures returning a BOOL only return TRUE or FALSE, to reduce portability problems between different Amiga OSes.
- CHG: Some AmigaOS procedures take or return APTR, which is treated as an ARRAY by PortablE. This did not always make sense, so I have replaced them with APTR2, which is treated as a PTR by PortablE. Thanks to Daniel Westerberg for reporting the problem.
- CHG: AmigaOS modules had PTR TO tagitem, instead of ARRAY OF tagitem. Thanks to Daniel Westerberg for reporting this.
- CHG: Fixed 'Examples/cosmic/cosmic_deluxe.e' to work on AROS, thanks to Matthias Rustler.
- CHG: Fixed 'Examples/MUI/MUI-Demo' to close it's window, and on AROS to not crash, thanks to help from Matthias Rustler.
- CHG: SIZEOF BIGVALUE is now a constant.
- CHG: Captialised endianSwapLONG() to EndianSwapLONG(), and endianSwapINT() to EndianSwapINT().
- CHG: C++: Const-ness is now removed from strings that are assigned, to prevent many warnings under OS4's new SDK.
- CHG: C++: Fixed module problems with OS4's new SDK.
- CHG: C++: '/d' is now converted to '%ld' (instead of '%d'), so that it works with Exec's Printf()/etc functions. Thanks for Daniel Westerberg for reporting this.
- BUG: NEW and FastNew() provided un-aligned memory allocations, which could cause crashes under certain circumstances.
- BUG: OS4: OpenLibrary() could crash. Reported by Daniel Westerberg.
- BUG: Fixed PortablE r3 not working with filingsystems that do not support file comments, attributes or file dates (like hosted AROS). Thanks to Matthias Rustler for reporting the bug.
- BUG: Partly undid r3 change, which made dos's ReadLink() & AddBuffers() wrongly return BOOL (as OS3 AutoDocs were wrong). Suggested by Daniel Westerberg.
- BUG: Would crash if a procedure declared more return values (using RETURNS) than it returned using an in-line procedure/method call.
- BUG: Memory could be corrupted when PortablE was quitting, due to a long-standing linked-list bug. Thanks to Paul Beel & Olivier Tigreat for reporting symptoms of the bug.
- BUG: Making an array[index] access on a variable of type "PTR TO object", with OPT POINTER enabled, would cause an exception to be raised. Bug reported by Daniel Westerberg.
- BUG: Fixed excessive stack usage when PortablE was quitting, which could cause a crash for very large modules.
- BUG: Error reporting failed when it involved a macro followed by an end-of-line comment. Issue reported by Daniel Westerberg.
- BUG: Parsing failed when it involved a macro after the ELSE IF keyword.
- BUG: Operations which involved a CHAR/UBYTE type would wrongly always result in the type CHAR too. Issue reported by Daniel Westerberg.
- BUG: C++: Negation of boolean expressions was wrongly omitted in some cases. Bug reported by Daniel Westerberg.
- BUG: C++: If a procedure's return type was deduced to be a preallocated object, then the C++ procudure had the wrong return type. Bug reported by Daniel Westerberg.
- BUG: C++: Macros did not correctly handle in-line e-lists as parameters. Bug reported by Daniel Westerberg.
- BUG: AmigaOS & 3rd-party library procedures with a "..." parameter had 7 required (rather than optional) parameters. Issues reported by Daniel Westerberg.
- BUG: It was not fixing the global exception model for methods called "main".
- BUG: SIZEOF a NATIVE type did not generate the correct code.
- BUG: AmigaE: MemCopy() would crash if the source or target overlapped, since r3.
- BUG: AmigaE: Non-statement assignments to a single object-member/array-item were not converted into something supported by AmigaE. Bug reported by Daniel Westerberg.
- BUG: AmigaE: StrJoin() was missing.
- BUG: ECX: The type was not translated for SIZEOF, and so would not always match a real type.
- BUG: EndianSwapLONG() would not work for negative values, which could have caused problems for the AROS version of PortablE.
- BUG: Escape codes made single-character quad-chars have type QUAD instead of CHAR.
- BUG: An empty DEFAULT section caused C++ code uncompilable by GCC. Bug reported by Daniel Westerberg.
- BUG: A value with the "ARRAY" type (such as NILA) could be assigned to preallocated arrays. Bug reported by Daniel Westerberg.
r3 (25-12-2008)
- NEW: Added StrJoin() to the set of standard e-string functions.
- NEW: Added OstrCmpNoCase() & StrCmpNoCase() to the set of standard string functions.
- NEW: Improved OS4 'dos' module compatibility with OS3; 'dos/errors' is automatically added by 'dos/dos', and 'dos/anchorpath' by 'dos/dosasl'.
- CHG: Fixed many 'dos' module procedures to correctly return BOOL, as specified in the AutoDocs, even though the C++ headers do not!
- CHG: PortablE now uses my rewritten portable file/dir classes; this may cause problems on buggy filingsystems...
r3 beta2 (11-12-2008)
- NEW: Added the missing 'AmigaLib' modules, especially 'AmigaLib/boopsi' which is required by many MUI programs.
- NEW: Added 'colorwheel', 'mui/muicustomclass', 'tools/domethod', 'tools/installhook', 'other/split', 'other/sendrexx' & 'other/sendexplorer' modules.
- NEW: MemCopy now supports overlapping source & destination.
- NEW: Added REF_TO & DEREF macros to 'muimaster' module, to simplify replacing {}.
- CHG: For the 'tools/arexx' module, added auto-opening of rexxsyslib library, as Chris Young says it is done by his copy of this AmigaE module.
- CHG: AmigaE: Added missing call0many()/etc for AmigaE targets.
- BUG: PortablE now runs up to 7 times faster than previously (better for big programs), due to fixing a long-standing bug which caused token linked list insertion to be O(n) instead of O(1).
- BUG: C++: Fixed Msg type on OS3 to produce correct & compilable code, but you must edit the <intuition/classusr.h> include to give the anonymous Msg struct the name _Msg . This also fixes C++ being unable to compile Msg parameters & return types.
- BUG: Initialisation values for local variables were effectively ignored by the backwards compatibility mode (unless OPT NOPTRTOCHAR was used).
- BUG: The new RETURNS keyword would crash for in-line procedures (due to a last-minute change in beta1).
- BUG: Would crash when BUT wasn't followed by an expression.
- BUG: Floating-point & 64-bit maths now work properly & generate compilable code when use pointer values.
- BUG: Macro parameters that began with an open bracket did not parse correctly.
- BUG: C++: SELECT didn't generate compilable code when used with pointer variables. Native types could also have caused a problem with it & some other statements that use equality tests.
- BUG: C++: The escape character is now represented by an octal value, since hex could be misinterpreted (as it has undefined length).
- BUG: AmigaE: CALLBACK was missing address-of {braces} for the generated code to compile.
- BUG: AmigaE: Could generate lists items with non-constant expressions that began with a constant (such as [1+a]), which AmigaE does not support.
- BUG: AROS: Error highlighting did not work properly, due to AROS not supporting a terminal escape sequence.
- BUG: The 'mui', 'iff' & 'reqtools' had PTR TO CHAR instead of ARRAY OF CHAR, and so would not work without the compatibility or pointer arithmetic mode.
r3 beta1 (11-11-2008)
- NEW: Added full support for (emulated) function pointers, using special FUNC procedures.
- NEW: Added support for PROTOTYPE procedures. Requested by Daniel Westerberg.
- NEW: Added procedure return-type declarations (RETURNS).
- NEW: Added XOR, SHL & SHR operators.
- NEW: Added the 'identify', 'iff', 'muimaster' (not AROS) & 'reqtools' modules for (3rd-party) libraries.
- NEW: Added the 'mui/betterstring_mcc', 'mui/texteditor_mcc', 'mui/NListview_mcc' & 'mui/NList_mcc' modules.
- NEW: Added the 'amigaguide', 'datatypes', 'gadgets', 'iffparse', 'images', 'locale', 'rexxsyslib' & 'tools/arexx' modules. Chris Young provided the 'datatypes' module for OS4, which I then cleaned-up - thanks!
- NEW: A 'datatypes' module has been added for OS4. Implemented by Chris Young - thanks!
- NEW: Added 'other/bitfield' & 'other/setprogname' modules (after discovering the source code).
- NEW: Updated AROS's modules to match the latest AROS #includes used by AmiDevCpp.
- NEW: Added call0many()/etc for function pointers than return multiple values. Not available with AmigaE targets.
- NEW: Macros can now extend over multiple lines using \ .
- NEW: Provided a PE-GCC script which automatically calls GCC after PortablE. PortablE now provides a return code to make scripting easier.
- NEW: Provided a PE-EC script which automatically calls EC after PortablE.
- CHG: You can no-longer declare a PRIVATE child method when the parent is not, unless the object is also private, as this would break inheritance.
- CHG: #define name (foo) is no-longer interpreted as #define name(foo) .
- CHG: AROS: PortablE will work with the latest AROS DevPak for AmiDevCpp (once some bugs are fixed), which previously stopped programs from compiling.
- CHG: OS4: Centralised library opening, to make automatic handling of Interfaces really easy for new modules.
- CHG: C++: A class's friends are no-longer declared, as they are not currently required & waste many lines of code.
- BUG: C++: Brackets could fail to be added in certain circumstances, causing incorrect expression evaluation. (major bug)
- BUG: C++: RealF() did not always write values after the decimal point correctly (zeros could be missed).
- BUG: C++: ENDing an indexed array item, when the index had a side-effect (like ++), would cause the side-effect to happen twice.
- BUG: AmigaE: In-lined procedures could loose spacing after replaced variables, which could cause problems in AmigaE code.
- BUG: Two AmigaOS objects (newmenu & diskobject) were missing a pad member, which would cause compatibility problems for typed lists.
- BUG: An empty immediate list like [] would cause an assertion error.
- BUG: Would crash when a parent method was PRIVATE but a child was not.
- BUG: Fixed a potential (module cache) refactoring bug for static (or pseudo-static) things.
r2 (04-07-2008)
- NEW: GCC v4 is now supported, as used on OS4 machines. Issue reported by Chris Young.
- NEW: NewLib is now supported, as used on OS4 machines. Work-arounds provided by Chris Young.
- NEW: The AmigaE "wbmessage" variable is now supported, as part of the 'wb' module. Also used by the compatibility mode. Partly added for Chris Young.
- NEW: The main() procedure can now return a value (return code). Partly added for Chris Young.
- NEW: Implemented an RTTI (Run Time Type Information) system for classes. See the TYPEOF keyword, the HaveSameClassTypes() procedure, and the methods InfoClassType(), IsSameClassTypeAs() & IsOfClassType().
- NEW: Now reports which OS & language is being used as the compilation target.
- CHG: UpperStr() & LowerStr() now accept NIL as a parameter, but only when using the compatibility mode. Issue reported by Chris Young.
- CHG: Trying to replace a preallocated array now causes an error in the compatibility mode.
- CHG: Removed a few unnecessary casts generated by pointer arithmetic.
- BUG: RETURNing more values than declared at ENDPROC would cause an enforcer hit or crash during compilation. Present since r1 RC1. Reported by Chris Young.
- BUG: C++: FOR did not work when STEP was a negative value. Reported by Chris Young.
- BUG: OS4: CloseLibrary() would probably crash. Reported by Chris Young.
- BUG: C++: The generated programs crashed if started from Workbench. Reported by Chris Young.
- BUG: AmigaE: Capitalised methods did not loose their capitalisation in the generated code (and so would not compile).
- BUG: UpperStr() & LowerStr() did not return the string. Reported by Chris Young.
- BUG: SetStdIn() & SetStdOut() returned the new value, instead of the old one.
r1 (15-06-2008)
- NEW: First public release, which would be "v1.0" if I used version numbers.
- NEW: PortablE now refuses to run if the stack size is too small.
- NEW: Added StackSize() to the 'exec' module.
- NEW: Improved FreeStack() for OS3 & possibly OS4.
- BUG: FreeStack() did not work on AROS.
These versions were limited to the AmigaE mailing list, and could be considered
as coming before "v1.0".
r1 RC2 (14-06-2008)
- NEW: Added ENDFOR IF. Suggested by Daniel Westerberg.
- NEW: Added the 'asl' module. Requested by Daniel Westerberg.
- NEW: The AmigaE "arg" variable is now supported, as part of the 'dos' module.
- NEW: FreeStack() is now provided, as part of the 'exec' module.
- NEW: Expressions after ENDPROC & IS can now extend over multiple lines (as much as normal expressions can in PortablE).
- NEW: C++: RealF() is no-longer limited to 9 decimal places. Requested by Daniel Westerberg.
- NEW: All library bases now have the type "PTR TO lib" for all OSes, especially for the Utility library, just like OS4.
- NEW: FOR statements no-longer have read-only sections.
- NEW: The compatibility mode now supports the RETURN keyword instead of IS for in-line procedures.
- NEW: SdivMod32(), UdivMod32(), Smult64() & Umult64() are now properly implemented in the 'utility' module, for all OSes.
- CHG: Changed Shl()'s & Shr()'s second parameter from BYTE to VALUE.
- CHG: Changed Val()'s second parameter from PTR TO LONG to ARRAY OF LONG.
- CHG: Replaced PTR TO PTR /*TO x*/ with ARRAY OF PTR TO x in AmigaOS modules.
- CHG: Capitalised in-line procedures which replace #define macros, to avoid any chance of clashing with user procedures.
- CHG: The compatibility mode's additional procedures & modules are no-longer hard-coded, but instead are added using the 'PE/compatibility' module. And WriteF() is now unbuffered.
- CHG: OS4: For generated code removed the need/use of OS4's #define USE_INLINE (OS3 compatibility mode).
- CHG: C++: CharToUnsigned() no-longer causes a (harmless) C++ warning.
- CHG: C++: Removed the superfluous automatic opening of exec.library in the 'exec' module.
- CHG: Now reports the expression's type (rather than the procedure's) for type errors, when assigning a procedure's main return value that has been cast.
- BUG: OS4: Non-automatically opened libraries incorrectly got their Interface. Thanks to Daniel Westerberg for reporting the bug.
- BUG: Comparisons for RAISE had the wrong order, which meant >=,>,<,<= were inverted.
- BUG: Procedure inlining could not always cope with non-variable expressions used as parameters. Thanks to Daniel Westerberg for reporting symptoms of the bug.
- BUG: You could not declare local variables with the same name as global variables. Thanks to Daniel Westerberg for reporting the bug.
- BUG: Certain procedures were not available under the AmigaE compatibility mode, specifically NewM(), 'graphics/gfxmacros', and the built-in Graphics & Intuition helper functions.
- BUG: C++: Pointer arithmetic did not handle NATIVE types correctly.
- BUG: C++: Did not generate compilable code when a STEP value was provided & the iterator variable was a pointer.
- BUG: C++: 'stub' AmigaOS modules could sometimes have their #include placed too early in the source code.
- BUG: Ending a procedure's DEF statement with a ; could cause an assertion error.
- BUG: The BIGVALUE type could cause an assertion error.
- BUG: AROS: Some 'graphics' constant names did not match those in AmigaE (again!).
r1 RC1 (31-05-2008)
- NEW: Wrote the 'std/callback' module, which allows you to call function pointers that are obtained using CALLBACK.
- NEW: Added the 'commodities', 'console', 'gadtools', 'icon' & 'workbench' modules, plus some 'AmigaLib', 'class' & 'Tools' modules.
- NEW: Added these built-in functions, to the 'graphics' module: Plot(), Line(), Box(), Colour(), TextF(), SetStdRast(), SetTopaz(). Many thanks to Tomasz Wiszkowski for his detailed help.
- NEW: Added these built-in functions, to the 'intuition' module: SetColour(), OpenW(), CloseW(), OpenS(), CloseS(), Gadget(), Mouse(), LeftMouse(), WaitLeftMouse(), MouseX(), MouseY(), WaitIMessage(), MsgCode(), MsgQualifier(), MsgIaddr(). Many thanks to Tomasz Wiszkowski for his detailed help.
- NEW: Added these built-in functions: KickVersion(), SetStdIn(), SetStdOut().
- NEW: Added TYPE declarations, which are very useful, especially when used with NATIVE or RANGE types.
- NEW: Used TYPE to implement native AmigaOS types (like APTR), which (1) solves C++ type-casting problems, (2) reduces E code compatibility problems between OSes, and (3) reduces the casting required in E code.
- NEW: Unsigned types (like UBYTE) are now defined in 'exec/types', instead of being built-in, which greatly reduces AmigaOS type-casting issues. The type diagram is also rather simpler now.
- NEW: Added the "RANGE x TO y" type, and explained the type it inherits when reporting a type error.
- NEW: CHAR now inherits RANGE 0 TO 127, which means we can *finally* supply numbers where characters are expected, without fiddly casts!
- CHG: Converted overlooked PTR TO CHAR/BYTE/UBYTE into ARRAYs for AmigaOS object members.
- CHG: STATIC now supports multiple (comma separated) items, like everything else does.
- CHG: Procedures now allow new lines after commas, like everything else does.
- CHG: Lists now allow a new line before the first item and after the last item, like AmigaE.
- CHG: Casting a constant to a type that is too small now causes a warning rather than an error.
- CHG: Removed OPT CHARISUBYTE, since this is now superfluous. :-)
- CHG: Allowed pointers to have non-NIL initial values when using the AmigaE compatibility mode.
- CHG: The :: cast is now allowed to cast non-pointer expressions. (At least until I support member/method access after a !!PTR TO cast.)
- BUG: Preprocessor macros did not handle parameters containing (nested) brackets or function calls.
- BUG: Preprocessor macros wrongly reported infinite recursion if a parameter contained another call to the same macro.
- BUG: Preprocessor macros were not used inside #ifdef ... #endif .
- BUG: Error reporting caused an assertion error if the error originated in macro from another module.
- BUG: RETURN did not type check the supplied expressions.
- BUG: Typed lists could corrupt the module cache.
- BUG: Using NEW or STATIC on a typed list wrongly resulted in the type LIST (instead of ARRAY OF ...), and the generated code was missing an appropriate cast for NEW.
- BUG: C++: Immediate lists did not have code generated to allocate their memory, probably since a 'fix' in beta2.
- BUG: C++: Typed lists did not have code generated to allocate their memory.
- BUG: C++: CALLBACK was missing a cast for the generated code to compile.
- BUG: C++: Casts were not generated for NATIVE types that were a sub-type of PTR or ARRAY.
- BUG: C++: Sometimes casts were not generated for NEW [list]:type, and possibly other cases that need to create procedure calls.
- BUG: C++: Object members separated by commas would not generate compilable code.
- BUG: AROS: Fixed "etask" double-declaration in 'exec/tasks' module.
- BUG: AROS: Fixed CONST object members not having an appropriate cast generated when they are read.
- BUG: AROS: Fixed LONG* not having an appropriate cast generated (replaced LONG with the special SLONG type).
- BUG: AmigaE: A past change for C++ had stopped PortablE from compiling some 'exec' modules, due to double declarations.
- BUG: AmigaE: The type was not translated for SIZEOF & typed lists, and so would not always match a real type.
- BUG: AmigaE: The first automatically added 0 for a missing object member in a typed list did not have a comma before it.
- BUG: ECX: Prevented assignments from appearing in expressions, since this is not supported.
r1 beta5 (02-05-2008)
- NEW: The preprocessor now supports macros. Unlike AmigaE it has no recursion depth limit, thanks to a suggestion by Leif Salomonsson. And also allows an end-of-line comment after #define, thanks to Daniel Westerberg mentioning the issue.
- NEW: Updated the AmigaOS modules to use the preprocessor.
- NEW: Added call-back support (i.e. supplying function pointers to AmigaOS), by adding NATIVE types & the CALLBACK keyword.
- NEW: STRLEN is now supported.
- NEW: Added many 'Tools' modules.
- NEW: Added CharToUnsigned() and UnsignedToChar() for dealing with unknown signedness of CHAR.
- NEW: Added some more error hints.
- CHG: Had forgotten to change LONG to VALUE for the return type of AmigaOS procedure calls, as well as some built-in procedure calls.
- BUG: Typed lists of objects raised an assertion error, after better checking was recently introduced (previously it might have caused crashes).
- BUG: Failure to create a module cache would cause a crash, rather than reporting the problem. Thanks to Matthias Rustler for reporting symptoms of the bug.
- BUG: #undefine would not work properly outside of the module that #defined it.
- BUG: AROS: Did not handle SetFileSize() being unsupported (under AROS's FFS). Thanks to Matthias Rustler for reporting symptoms of the bug.
- BUG: AROS: Stopped PortablE from pausing for a long time on hosted AROS, where SetFileDate() does not work. Thanks to Matthias Rustler for reporting the bug.
- BUG: AROS: Some 'graphics' constant names did not match those in AmigaE.
- BUG: Stopped it expanding the path PEmodules:, which could lead to unusable module caches being created.
- BUG: Type-checking of list items did not always obey OPTions.
- BUG: Passing one PTR TO type, where another was expected, did not obey OPTions.
- BUG: AmigaE: Array sizes could be complex (constant) expressions, which AmigaE does not support.
r1 beta4 (11-04-2008)
- NEW: Can generate AROS (i386) compatible C++ code, using OS=AROS. Now comes with an AROS executable.
- NEW: Can generate ECX compatible AmigaE code, using TargetLanguage=ECX.
- NEW: Added support for solving endian issues. (I have standardised on the Big Endian format.)
- NEW: Added OPT CHARISUBYTE to ease the use of strings with AmigaOS, when not using the compatibility mode.
- NEW: Added the BIGVALUE & UBIGVALUE types, to allow support of 64-bit integers.
- NEW: The module cache can no-longer be invalidated due to the use of a different relative path.
- NEW: C++: Removed some spurious casts, by properly implementing the C++ type model, rather than kludging PE's type model to emulate it. And undiscovered casting problems are very unlikely now.
- CHG: Changed LONG to VALUE for object members in AmigaOS modules, to reduce the need for any type casting.
- CHG: Spurious new lines can no-longer appear in the middle of a statement (typically after END).
- CHG: PTR TO FLOAT is no longer a sub-type of PTR TO VALUE, as this created a hole in the type system.
- CHG: ULONG is no longer a sub-type of VALUE, as this was wrong on 32-bit systems.
- CHG: Removed a wierd type-checking kludge, that effectively made INT a sub-type of PTR when using OPT POINTER.
- CHG: NEW array[index].method() was not accepted during parsing.
- BUG: Refactoring an IF expression into a statement could lead to a crash.
- BUG: Parsing & generating code for ENDing an array item or whole array did not always work, and could crash (but only after I removed the need for the array's size, two releases ago).
- BUG: Local module paths (beginning with '*') could cause an assertion error if the source file was not supplied with a path itself (i.e. when used the current directory).
- BUG: Using FLOAT in certain places could cause an assertion error.
- BUG: The 'missing module' error did not identify which module had the problematic MODULE declaration, due to a last-minute change in the previous release.
- BUG: The diskfontbase global was missing from OS3 & AmigaE.
- BUG: "NEW" was raised instead of "MEM" by the new memory functions added two releases ago. (As the AmigaE manual said "NEW", which is wrong.)
- BUG: C++: Shl(), Shr() & Xor() could be inlined incorrectly.
- BUG: AmigaE: Not all trailing casts were removed.
- BUG: AmigaE: The recent update to AmigaE modules accidentaly left CtrlC() implemented using C++ code.
r1 beta3 (07-03-2008)
- NEW: Multiple errors can now be reported, one per procedure body. Handy when porting E code to PortablE.
- NEW: Casts no-longer hide multiple return values.
- CHG: Errors & warnings no-longer report the module, as we already state which module is being parsed, thus it was just wasting lots of space.
- CHG: Changed LONG to VALUE in AmigaOS modules, to reduce the need for any type casting.
- BUG: Crash when reporting an expression error after a method that was not called using a variable.
- BUG: Casting something with a static value to another primitive type did not change the type!
- BUG: Inheritance problems no-longer claim a type is more/less restrictive, when it is actually the wrong type.
- BUG: Potential bug when refactoring NEW. Caught by PortablE's type system.
- BUG: Potential bug when generating AmigaE code. Caught by PortablE's type system.
- BUG: In PortablE, some variables had the wrong object type, but (usually?) seemed to work. Caught by PortablE's type system.
- BUG: In PortablE, passed the wrong object type, for something which wasn't used yet. Caught by PortablE's type system.
r1 beta2 (15-02-2008)
- NEW: AmigaOS 4 PPC native executable provided, which runs nearly 3 times faster than the 68k version.
- NEW: Now supports all v45/v52 modules for Devices, Diskfont, Dos, Exec, Graphics, Intuition, Resources, Utility, and part of Other.
- NEW: The 'graphics' & 'intuition' modules are now used by the compatibility mode.
- NEW: Object pointer casts can now be used on the left side of an assignment.
- NEW: ELSE IF expressions are no-longer 'read only'.
- NEW: Added an extra parameter to StrCopy() and StrAdd() so pointer arithmetic is never needed.
- NEW: BUT now allows the left expression to not have a value (i.e. to be EMPTY).
- NEW: Fixed AmigaE's faulty global exception model, so it now works as expected. Especially for ReThrow() & exception:=0.
- NEW: Added PrintFlush() which flushes the buffer used by Print(). No need for WriteF() now!
- NEW: The loading of module caches are now reported (and without wasting extra lines), so no more inexplicable pauses.
- NEW: Some warnings & errors now offer hints.
- NEW: Warns about suspicious use of pointers in conditional expressions (for IF, WHILE and UNTIL).
- NEW: Totally disabled type checking for the AmigaE compatibility mode.
- NEW: Removed my potentially confusing usage of the word "static", thanks to Leif Salomonsson for pointing it out.
- NEW: Reduced memory usage thanks to the AmigaE-like FastNew(), and added a user-friendly out-of-memory message.
- NEW: C++: FastNew() & FastDipose() are now very fast, as they are implemented like AmigaE does, thanks to help from Tomasz Wiszkowski. This also makes object & e-string (de)allocations very fast too.
- NEW: C++: Non-ASCII characters in strings are now written using octal escape codes for better compiler compatibility.
- NEW: C++: Now using 4 years newer OS4 headers (from 2005) for better compatibility.
- NEW: AmigaE: Updated modules to better match the C++ OS3 ones, and fixed a few small mistakes in the process.
- CHG: The stack must be set manually (to at least 100KB), since PortablE is now compiled using GCC not CreativE. At least it no-longer corrupts memory due to insufficient stack being allocated by AmigaE/CreativE!
- CHG: Methods must now be marked as ORPHAN so that non-orphan methods can be called by parent implementation.
- CHG: END array[size] no-longer allows a size expression, and does not require the [square brackets] anymore.
- CHG: var-- no-longer behaves like AmigaE in the compatibility mode, and instead gives a warning.
- CHG: Floating-point constants are no-longer supported, but AmigaE never allowed them anyway.
- CHG: You can no-longer cast from non-object pointers using ::, unless the compatibility mode is enabled.
- CHG: You can no-longer cast from non-pointers/arrays to pointers/arrays using !!, unless pointer manipulation is enabled.
- CHG: When statement indenting is copied (say for refactoring), comments & blank lines are no-longer also copied.
- CHG: Quad-characters now handle formatting codes in a consistent fashion (by always ignoring them).
- CHG: C++: Quad-characters no-longer cause GCC to issue endian warnings, using a suggestion from Fabio Alemagna.
- BUG: C++: Pointers weren't cast when assigning/passing them to non-pointers.
- BUG: C++: Returning an immediate string/list in in-line procedure caused the return type to miss the "*".
- BUG: C++: A temporary variable to hold an immediate strings or lists would be statically allocated.
- BUG: C++: InStr() had the needle & haystack parameters reversed.
- BUG: C++: Next() and Forward() would throw an exception if passed NIL.
- BUG: C++: Link() would store a corrupt tail pointer if it was passed NIL for the tail.
- BUG: C++: Inlined procedures could have the boolean result of any comparison negated twice (which would appear as -- due to another bug).
- BUG: C++: Negation (and theoretically constants & numbers) added by refactoring were missing a space after them, which could sometimes cause problems.
- BUG: C++: Comparisons between two pointers did not work as expected for negative numbers, which caused big problems for OPT AMIGAE.
- BUG: C++: Fixed a harmless DSI on the PPC version of PortablE, thanks to Dwayne Jarvis's help in testing it on OS4.
- BUG: AmigaE: A 16-bit division could sometimes be used when the result would exceed 16-bits.
- BUG: AmigaE: Method access on an indexed ARRAY OF PTR produced non-compilable code.
- BUG: AmigaE: Global variable declarations (DEF) would sometimes start without a new line character.
- BUG: AmigaE: Member/method accesses on arrays of objects & arrays of pointers to objects produced incorrect code that happened to compile.
- BUG: AmigaE: An END with multiple items output code with a missing new line when ending arrays/strings/lists.
- BUG: AmigaE: Non-zero CONSTants of type PTR or ARRAY, as well as any VALUE type, would halt PortablE with an exception error.
- BUG: The right side of a BUT expression was not parsed like AmigaE did.
- BUG: Methods returning an immediate or preallocated array would not allow a child method to be declared.
- BUG: The wrong entity names could be output in certain situations when the module cache was used.
- BUG: The wrong REPLACEMENT procedure could be called when the module cache was used.
- BUG: SUPER procedure (for REPLACEMENT) would not often work if there were several parents to choose between.
- BUG: Changed how formatting codes are handled, so that strings can contain non-ASCII characters (value>127) without a problem.
- BUG: The refactoring of BUT did not allow for side-effects, so the things could be done in the wrong order.
- BUG: Refactoring the outer expression of an in-line procedure could cause a crash.
- BUG: The Exec module could have a circular dependency on the Dos module.
- BUG: Using two modules containing things of the same name, but one marked private, could cause the public one to not be found.
- BUG: The wrong module was stated for any errors in the header of a module that depended on an invalid cache.
- BUG: Using a module (cache) that was moved or renamed would crash PortablE, now it invalidates the cache instead.
- BUG: Enforcer hit (i.e. possible crash) when a procedure/method was used as a return value before it had been declared.
- BUG: Values created for constant expressions could sometimes be deallocated before being output, and it was only (usually?) working by luck/coincidence.
- BUG: Noticed a potential crash when parsing incorrectly written storage elements.
- BUG: The default NIL constant for pointer & array variables was deallocated before being written, although I didn't notice any crashes or corruption until a recent change.
- BUG: The combined type of two pointers to primitives is now correctly a PTR TO VALUE rather than a PTR TO ANY.
- BUG: Quad-characters containing the % sign were wrongly written, for both C++ & AmigaE.
- BUG: Minor memory leak when had empty /**/ comments.
- BUG: Passing a non-existant source file to PortablE caused a NIL exception.
r1 beta1 (24-06-2007)
- NEW: Added the module cache, which is a fully automatic pre-compiled module system. This makes PortablE 3-7 times faster!
- NEW: Added a basic preprocessor that supports #define, #undefine, #ifdef, #ifndef, #else, #endif, #public & #private (even on a single line).
- NEW: Added support for the v45 Timer device.
- NEW: Methods are now affected by PRIVATE/PUBLIC, and just like members this affects their visibility outside of a module.
- NEW: Implemented PROTECTED for object members.
- NEW: Implemented UNGENERIC for classes.
- NEW: Implemented ORPHAN for classes, along with support for IMPLEMENTS.
- NEW: Constant IF expressions are now optimised, like constant IF statements were. This optimisation is also used when inlining procedures, which is quite cool.
- NEW: In-line procedures that directly call a procedure/method/SUPER-method now return all the values returned by that procedure/method (rather than just the first).
- NEW: The main return expression of a procedure/method no-longer needs any used procedure/method to have been declared before it.
- NEW: Modules which cannot be found now indicate where the faulty MODULE declaration is located.
- NEW: Added the unsigned types UBYTE, UINT & ULONG, that required pretty big changes to the type system, which probably fixed some bugs along the way (and maybe introduced new ones!).
- NEW: NewM() is now provided, as part of the 'exec' module, but most of the flags are unsupported.
- NEW: Added the NoOptInline switch, to aid debugging of OS modules.
- NEW: Added the OptNoPtrToChar switch, to avoid problems with some C++ compilers when using the OptAmigaE switch.
- NEW: Added the TargetOS=OS & TargetLanguage=Lang switches. Removed the TargetAmigaE switch. And the "target/AmigaE" folder was renamed to "target/AmigaE_AmigaOS3".
- NEW: You can now replace existing procedures (even built-in ones) using the REPLACEMENT keyword, and access the old one using SUPER.
- NEW: STATIC globals containing an immediate string or list can now be declared. This was a major omission by AmigaE, which had to be worked-around using #define.
- NEW: The 'dos' & 'exec' modules are now used by the compatibility mode.
- NEW: C++: Can now generate OS4 compatible code, including automatic getting/dropping of interfaces for the supported libraries & devices.
- CHG: NewNoClear() has been removed, since New() now has the second parameter noClear=FALSE:BOOL.
- CHG: FastNewNoClear() has been removed, since FastNew() now has the second parameter noClear=FALSE:BOOL.
- CHG: Built-in memory functions (like New()) now consistently treat memory blocks as ARRAYs rather than PTRs.
- CHG: ARRAY (OF ANY) is now accepted by any PTR type, when pointer arithmetic is enabled, so that memory can still be allocated for objects.
- CHG: Pointer arithmetic with ARRAYs is now supported, when pointer arithmetic is enabled, although the result is of type PTR rather than ARRAY.
- CHG: Lists (like [1,2,3]) can now be assigned to variables of type PTR TO LONG, when the compatibility mode is enabled.
- CHG: Immediate lists are now statically allocated when the compatibility mode is enabled OR when they only contain static data.
- CHG: Static immediate lists are now allowed within read-only sections.
- CHG: Type checking of method inheritance now ignores OPT POINTER, but allows anything when OPT AMIGAE is used.
- CHG: Internally restructured parameter/local variable naming to be more general & future-proof. You shouldn't notice any difference :)
- CHG: Non-class OBJECTs now default to PUBLIC.
- CHG: Rewrote how the types of the results of operations (such as +, *, or AND) are calculated & represented. Is now far more accurate.
- CHG: Updated the OS modules to use the new unsigned types, so the correct casts should be generated now.
- CHG: Extended the list of reserved constants (keywords).
- CHG: Negative array indices are now allowed when pointer arithmetic is enabled.
- CHG: Comparison of float(s) using = or <> now generate a warning, because they are unreliable.
- CHG: Renamed methods are now less likely to have very long/silly names.
- CHG: Unused procedures are now always written, even when optimisations are enabled, because of the module cache.
- CHG: Global variables of the same name in different modules are no-longer joined, and will cause an error, unless OPT AMIGAE is used.
- CHG: AmigaE: Methods with more parameters than their parents are now renamed, because of the module cache.
- CHG: In-linable procedures from OPT NATIVE modules are now always inlined, even when optimisations & inlining is disabled.
- BUG: Compiling large programs could cause a reported memory leak, due to a wierd AmigaE bug with a FOR loop (which is now replaced by a WHILE loop).
- BUG: Large programs could theoretically reveal a bug in my dynamically-sized hash table class.
- BUG: Solved a theoretical problem where automatically generated names (due to a name space clash) could clash with NATIVE name declarations. This also opens the door for some improvements & C++ fixes to methods.
- BUG: C++: Sometimes method names didn't avoid having the same name as it's object (which would be interpreted as a C++ constructor).
- BUG: C++: Now avoids accidental method overloading, which would cause the wrong method to be called. Also works-around buggy C++ compilers that don't like different return values in child methods.
- BUG: Now member & method names cannot clash with those of their parents.
- BUG: ARRAY OF x can now actually be assigned to a variable of PTR TO x, when pointer arithmetic is enabled.
- BUG: Allocating arrays of non-basic types (like PTR TO x) using NEW crashed the compiler.
- BUG: Assignment of values returned by SUPER method calls now allow access to multiple return values like normal methods.
- BUG: Prevented SUPER from being accepted outside of methods, where it doesn't make sense.
- BUG: NEW [immediate list] resulted in the type ILIST, rather than the correct LIST type.
- BUG: An ILIST can no-longer be mistaken as being the same type as a LIST.
- BUG: PRIVATE object members now behave like they do in AmigaE (i.e. per module, not per object).
- BUG: PRIVATE globals were not accessible from within their own module!
- BUG: Declarations within a module are no-longer allowed to clash with those from a parent module (so it now works like AmigaE).
- BUG: Deep module usage caused exponential slow-down & memory usage, because an O(n^2) algorithm was used to find module order. Fixed, as it now uses an O(n) algorithm.
- BUG: Normal modules with paths beginning with 'PE' or 'target' did not work properly.
- BUG: Local modules did not work when the current path began with a '/'.
- BUG: IF THEN ELSE expressions did not correctly handle refactoring when it's conditional THEN or ELSE expression needed to add statements, or when it evaluated to EMPTY.
- BUG: ELSE IF did not generate valid code, due to a previous fix.
- BUG: The STRING, LIST & ILIST types were missing from the type space, although this is unlikely to have caused any real problems.
- BUG: Added missing utilitybase & timerbase global declarations to their respective modules. Corrected the native C++ names of execbase & dosbase.
- BUG: Corrected some procedure declarations for the Dos module.
- BUG: The static size of an immediate string now includes it's terminating zero.
- BUG: Trying to call a procedure/method outside of a procedure now gives a meaningful error message.
- BUG: Trying to use a global variable outside of a procedure was not handled.
- BUG: Parameters could have the same name as important globals (like "exception").
- BUG: Illegal circular references were not detected with non-PUBLIC MODULE declarations, for loops of three or more modules.
- BUG: EXCEPT (DO) behaved like FINALLY, which although intentional it was probably unexpected.
- BUG: C++: The TRUE constant had the value +1, when the Exec module was used, due to a stupid macro in 'exec/types.h' (this is why macros are bad).
- BUG: C++: [Immediate] lists were generating the wrong code, which may have been broken in the previous release :-(
- BUG: C++: Returning of multiple values (from a procedure call) that used SUPER or had been automatically cast was not generating valid code.
- BUG: C++: Returning of multiple non-FLOAT values to FLOAT variables was using the wrong global.
- BUG: C++: END (& maybe other elements) were not handling -> comments on their line.
- BUG: C++: END was not NILing the variable (as bizarely "delete" does not do this in C++).
- BUG: C++: NEW was not clearing memory or throwing "NEW" exception for objects. Thanks to *Fabio Alemagna* for providing an example of how to make the new operator clear memory.
- BUG: C++: NEW was not generating valid code when used as a parameter or item of an [immediate] list.
- BUG: C++: Throw() was not generating valid code, when used in an expression. Then fixed again, for StormC's broken compiler.
- BUG: C++: Automatic casting to the EMPTY type was not working.
- BUG: C++: Global & procedure names potentially clashed with object names.
- BUG: C++: The :: operator was implemented using the wrong C++ operator. Doh.
- BUG: C++: The inherited end() destructors were being called more than once. Double doh!
- BUG: C++: Method prototypes were still written when OPT OPTIMISE & INLINE caused the actual methods to be removed.
- BUG: C++: Comparison of pointers with different types didn't work for StormC's broken compiler.
- BUG: C++: OPT AMIGAE (or wierd uses of PTRs!) was not producing compilable code with SELECT indexes, as well as some uses of the negate and NOT operators.
- BUG: C++: Pointers to pointers (and arrays of pointers, etc) were not the right type.
- BUG: C++: Immediate strings (i.e. 'const char*') were being passed to non-string parameters without a cast to loose their const-ness (C++ ignores const-ness for 'char*' parameters).
- BUG: C++: Refactoring could fail for member/array access or the (automatically added) address-of operator; now fixed, or at least much better for the address-of operator.
- BUG: C++: InStr() was returning nonsense.
- BUG: C++: Comparisons that were stored or passed as parameters were left in C's boolean format, rather than being converted to E's.
- BUG: AmigaE: Memory leak/corruption occured when a child method had more parameters than it's parent.
- BUG: AmigaE: Could write code containing method calls after a cast, which AmigaE does not support. This was known about for a long time...
- BUG: AmigaE: Trailing casts (not followed by member access) were written, even though these can crash AmigaE when the pointer is NIL, and are never allowed by ECX.
- BUG: AmigaE: Globals could be written before the objects they point to, while constants could be written after the globals & objects that use them for array sizes, doh.
- BUG: AmigaE: Statement separators (semi-colons) were never written.
- BUG: AmigaE: Could generate methods with the same name as members (in any object), which AmigaE does not allow within one module.
- BUG: AmigaE: The written end() method could sometimes have the wrong name.
- BUG: AmigaE: Implemented a kludge to prevent any procedures being called end(), until I can discover why this does not happen automatically :-(
- BUG: AmigaE: Comparisons with floating-point numbers did not work, except accidentally.
r1 alpha5 (03-10-2006)
- NEW: Optimised the compiler, which more than doubled it's speed. Further improvement will come when PortablE can compile itself.
- NEW: Allowed whole OBJECTs to be declared NATIVE, so that OS objects can now be accessed.
- NEW: Full support for the v45 Dos, Exec & Utility modules, including objects. This takes some time to compile...
- NEW: NEW is now an expression.
- NEW: Both NEW & END can now handle multiple comma-separated items.
- NEW: Both NEW & END can now be used to (de)allocate arrays, STRINGs & LISTs. END does not need a size in square brackets.
- NEW: NEW can now be used to create e-string/e-list/array copies of immediate strings/lists/typed-lists.
- NEW: Both NEW & END can now handle pointers to non-objects, when the compatibility mode is enabled.
- NEW: Typed lists are now supported, and NEW works with them.
- NEW: RAISE is supported, works with user procedure calls, and handles method calls too.
- NEW: Any return expression is now allowed after ENDPROC.
- NEW: Added FastDisposeList() to the compatibility mode.
- NEW: Global variables now support static STRINGs & LISTs, and initialisation values.
- NEW: Local variable initialisation is now supported by the compatibility mode.
- NEW: Parts of a module can be declared PRIVATE.
- NEW: Added PUBLIC MODULE declarations.
- NEW: Modules now support setup & tidyup code using new() & end() procedures.
- NEW: All modules allow main() procedures, but they may not be called, and only the program's main() will be executed.
- NEW: Strings may now split over multiple lines.
- NEW: NOP, INC & DEC are now supported by the compatibility mode.
- NEW: Added LOOP statement.
- NEW: Added OPT ELSEIF for those who want to use ELSEIF instead of ELSE IF.
- NEW: Added CleanUp() support.
- CHG: Emodules: replaced by PEmodules:, and it's folder layout has been changed for the last time - it now supports different modules for different targets.
- NEW: Added the ILIST type, for immediate lists. List functions will not allow you to modify ILISTs.
- NEW: C++: Optimised immediate lists, so that only dynamic items are updated each time it is evaluated.
- BUG: C++: Recursive /*comments*/ often didn't compile, so now they are replaced.
- BUG: C++: Prevented method with same name as it's object, as that would be interpreted as a constructor.
- BUG: AmigaE: Fixed objects not statically allocating LISTs. (This was intentional but undocumented.)
- BUG: AmigaE: Global variables are now put where AmigaE allows them! (I can't believe I didn't notice this before.)
- BUG: Fixed commas of call parameters & immediate lists, so that they allow splitting onto multiple lines, like other commas do.
- BUG: Fixed joining of global variables from different modules, which might not have been happening.
- BUG: Fixed local '*module' paths, which were completely broken.
- BUG: Fixed MODULE declarations not always working inside shared modules.
- BUG: Stopped array access on ARRAY OF ANY (and PTR TO ANY) being allowed, as it makes no sense & would cause a crash.
- BUG: Fixed in-lining of procedures, which didn't correctly handle additional statements from other refactoring. (deja-vu?)
- BUG: Fixed in-line procedures not having their temporary variables declared.
- BUG: Fixed rebracketing of post-fix ++ & -- expressions.
- BUG: Fixed objects with no methods causing no more methods to be written for any later objects.
- BUG: Preallocated objects are now treated as pointers (like AmigaE does), so member access is possible, and they can be passed where pointers are expected. Doh.
- BUG: Variables can now be preallocated objects, like AmigaE allows.
- BUG: Major rework of expressions to allow array[] accesses where member accesses are, e.g. proc(param)[i] or var++[i]
- BUG: Minor rework of expressions to allow member & method accesses on bracketed & SUPER expressions, e.g. (IF x THEN obj1 ELSE obj2).member
- BUG: Added missing type-checks to the FOR statement.
- NEW: Compatibility mode now allows REG as part of a variable's type declaration.
- NEW: Compatibility mode now enables pointer arithmetic (OPT POINTER) automatically.
- NEW: Added MemCopy() & ArrayCopy().
- CHG: NewString() & NewList() replace String() & List(). Also had forgotten to mention DisposeList().
- CHG: CtrlC() is now officially part of the 'dos' module (and hence depreciated), for all targets.
- CHG: Added NEW to the list of reserved constants (keywords).
- NEW: Added a Ctrl-C check, during tokenisation, as well as a couple of progress messages.
- NEW: Manual: Added a number of differences with AmigaE to the manual, which I had neglected to mention.
- CHG: Other small fixes & improvements, including compatibility improvements.
r1 alpha4 (05-08-2006)
- NEW: C++: Code is now compatible with GCC & StormC; simpler exception handling, avoided troublesome functions, main() returns int not void, etc.
- NEW: C++: Removed spurious brackets around casts.
- BUG: C++: Fixed memory calls, which weren't clearing memory.
- BUG: C++: Fixed Dos module calls, which did not generate compilable code.
- BUG: AmigaE: Fixed not generating valid code for SIZEOF pointers or arrays.
- BUG: Fixed the OptAmigaE switch, which was broken in the previous release. (Yes, *after* I had just fixed it!)
- BUG: Fixed in-lining of procedures, which didn't properly handle temporary variables from other refactoring. (Now one-step closer to in-lining large procedures)
- BUG: Fixed some potential bugs with rebracketing.
- CHG: Constructor methods (those used with NEW) must now be specified as a constructor.
- NEW: Added STRING & LIST types, including support for preallocation, even in class objects. (But globals do not support preallocation yet.)
- NEW: Added immediate [lists], which should make PortablE feel much more AmigaE-like.
- NEW: ARRAY types now have a size (since they are just pointers), so pointer arithmetic should now work with them.
- NEW: EXCEPT is now supported by the compatibility mode.
- NEW: exceptioninfo is now supported by the compatibility mode.
- CHG: Case-sensitivity of name spaces is now the same as AmigaE (e.g. both london & London are allowed).
- CHG: Removed the need for the 'PE/compatibility' module. It may be safely deleted.
- NEW: Added OPT INLINE. Non-user code now retains it's comments (when it isn't optimised).
r1 alpha3 (23-07-2006)
- NEW: Can now generate C++ code. Rejigged module folders to handle the extra files.
- NEW: AmigaE: Improved writing of constants for default parameters & a few other places.
- BUG: AmigaE: Fixed a few mistakes in the module 'PE/target/AmigaE'.
- BUG: Fixed "integer / float" not resulting in a float. Multiplication tweaked for CHAR & QUAD.
- BUG: Fixed reporting of double declarations. (Hopefully! I've already fixed it twice...)
- BUG: Fixed refactoring of in-line procedures.
- BUG: Fixed in-lining of procedures, which didn't properly handle additional statements from other refactoring.
- BUG: Fixed OptAmigaE switch, which was causing a circular module loop.
- BUG: Fixed {native} code & 'strings' that could be mistaken for E code.
- NEW: String linking is now supported, but is unlikely to ever be compatible with LIST.
- CHG: Fpow() is now incompatible.
- NEW: ARRAY OF ARRAY OF type is now allowed, which is useful for arrays of strings. Improved explanation of the ARRAY type.
- NEW: ENDWHILE IF is now available.
- NEW: The UNTIL expression is no-longer a read-only section.
- CHG: Both BUT & IF THEN ELSE are now disallowed from read-only sections, to ensure portability.
- CHG: Reserved a few constants (keywords), which would prevent valid expressions from being accepted. Still way better than AmigaE though!
- NEW: Semi-colon (;) is now allowed outside of PROCs, although silly uses are still restricted.
- NEW: Expanded NATIVE name space reservation to OBJECTs, and also allowed multiple name space declarations with one NATIVE statement.
- CHG: The main() procedure is now sensibly prevented from having parameters or return values.
- CHG: Other small fixes & changes.
r1 alpha2 (23-06-2006)
- NEW: Manual: Major revamp of manual to make it more readable, plus fixed many mistakes & added more info.
- BUG: Fixed ++/-- to increment by the pointer's size.
- BUG: Fixed a minor memory leak that was revealed by a recent change.
- BUG: AmigaE: Fixed writing of constant values for SELECT OF, CASE & CONST, which do not accept complex expressions.
- BUG: AmigaE: Fixed writing of basic SELECT expressions, which have to be variables.
- BUG: Fixed CASE statement commas, so that they allow splitting onto multiple lines, like other commas do.
- CHG: End() methods now rethrow exceptions just like every other method or procedure.
- CHG: Prevented EMPTY or ARRAY values from being modified or compared, as well as improving detection of pointer manipulation.
- BUG: Corrected how some type checking is affected by the POINTER and AMIGAE options.
- NEW: Pointer dereferencing now allows [].
- CHG: Prevented ARRAY OF ANY being preallocated. i.e. array[size]:ARRAY is prevented.
- CHG: Fixed hole in the type system: The type "ARRAY OF PTR TO object" now ignores inheritance relationships, since it is still a container.
- NEW: Unused procedure parameters are now reported (but method parameters are not).
r1 alpha1 (17-06-2006)
- First semi-public release, limited to the AmigaE mailing list.