Spin language extensions
ersmith
Posts: 6,053
in Propeller 1
I've been working again on spin2cpp (a compiler for Spin), adding the remaining parts of Spin that hadn't been implemented yet. All that's left now is implementing COGINIT/COGNEW for Spin methods (for PASM those functions have pretty much always worked), and the _FREE and _STACK variables; the latter already can be assigned to but don't do anything (and may never in spin2cpp).
I'm starting to think about going beyond the current Spin language and adding a few (optional) new features that would be controlled by a command line flag or some kind of language extension keywords. Things I'd like to add are:
(1) Optional variable typing; this would allow us to treat floats and strings as first class objects (so x + y where x and y are both floating point could be converted into a call to something like F32.add). I think the type of variables should be deduced from their uses, with optional type annotations at the declaration point. The default would have to be to ignore type mismatches (or issue only warnings) but it should be possible with a switch to make the typing strict to help catch errors.
(2) The ability to pass objects as parameters to methods. This would require that we have some way to specify interfaces that objects can implement, but I can see this as being useful for implementing generic formatting functions that work on TV, VGA, serial, and so on.
This is pretty blue sky right now, but what would you like to see added to a Spin++ language?
Eric
I'm starting to think about going beyond the current Spin language and adding a few (optional) new features that would be controlled by a command line flag or some kind of language extension keywords. Things I'd like to add are:
(1) Optional variable typing; this would allow us to treat floats and strings as first class objects (so x + y where x and y are both floating point could be converted into a call to something like F32.add). I think the type of variables should be deduced from their uses, with optional type annotations at the declaration point. The default would have to be to ignore type mismatches (or issue only warnings) but it should be possible with a switch to make the typing strict to help catch errors.
(2) The ability to pass objects as parameters to methods. This would require that we have some way to specify interfaces that objects can implement, but I can see this as being useful for implementing generic formatting functions that work on TV, VGA, serial, and so on.
This is pretty blue sky right now, but what would you like to see added to a Spin++ language?
Eric
Comments
I think it is quite relavent to link your related post from another thread.
Support for the "infamous" @@@ operator provided to us in BST??
From the BST manual:
There is code around that uses this (in OBEX, I believe) but the reliability of being able to run BST on more recent OS levels is at times a concern. (It is still working for me on latest Win/OSX/Linux but I may just be lucky). Support for @@@ in spin2cpp (and openspin) would remove some future headaches.
It certainly sounds like an interesting project and a nice face lift for Spin.
ZiCog uses it.
If I recall it only exists because @ and or @@ are broken when used in DAT sections.
Can't we just fix @@ to work properly there. Would that even break any existing code?
I'm glad to hear you're still working on spin2cpp. Would there be any advantage to creating a spin2llvm? I've started looking at what is involved in writing an LLVM backend for the Propeller, both P1 and P2.
I certainly expect openspin to stick around -- spin2cpp is an option in addition to openspin, not really in place of it. Besides, other people are developing and constantly improving openspin, and I'm sure that with P2 coming the Spin language will be supported there as well. I guess in this thread I'm just trying to open up ideas of how Spin could be improved. Parallax (and everyone else) is free to take or leave what they want from this!
I'd forgotten about that one. Sounds like a good idea. As Heater said it would be even better to make @ work as expected in PASM, but that would break backwards compatibility so it probably won't fly right now. @@@ is only for PASM right? In Spin code it would do the same thing as @ (I guess there could be a difference in implementation underneath, but for spin2cpp @ is evaluated at compile time anyway so it's not an issue there).
Eric
An LLVM backend would be cool! I hope you can get that working, and if you could use any help on it let me know. It should be possible to retarget spin2cpp to emit LLVM directly (rather than having to go through C/C++).
Eric
I like both of your extension ideas. Have you figured out a way with number 2 to check for parameter-count -- and now, type -- agreement during runtime, since it can no longer be verified at compile time?
-Phil
Might be cool to be able to test and debug your Spin code in a browser. No IDE or compiler to install, no Propeller required.
Kind of leaves all that PASM and hardware emulation to deal with.....
That way, you can choose 'compatible' or 'works properly', depending on the project.
Call the old spin Spin 1.0 and this Spin 2.0 for example.
I'm guessing conditional compile features are already in Spin2cpp ?
wrong.
@@@ gives the actual hub address of something at compile time to use to build tables with pointers or such.
In Spin you can't do that without @@@ because @ is resolved a runtime and @@ just gives you the offset in the module.
If you resolve @ at compile time then @@@ is just an alias for it.
Enjoy!
Mike.
I have to read the Prop manual again. But the last hundred times I did that it implied that @@ "gives the actual hub address of something"
Problem is it does not.
Does not give the actual hub address of something.
Hence the introduction of @@@.
When is @@ ever actually useful? Have people ever used it? Can't we just fix it?
The @@@ operator was introduced in BST to provide the absolute address of a variable within a DAT section.
Why does it work that way? You would have to ask Chip. I would guess it's just a natural outcome of the object structure used in Spin. Object offsets are useful if you want the program to be relocateable.
-Phil
Perhaps I'm remembering this "@" thing incorrectly. Hardly surprising given that it is so confusing. Straight away there we have two different meanings of the same operator. Eeek. Great but we cannot use it in DAT. Can't imagine.
A DAT section is shared across all instances of an object. Unlike VAR. All we want is the actual real address of something in DAT.
Surely one of these uses of @ or @@ is actually useless and never used and can be fixed without breaking anything.
May be?
May be time to start from scratch and not worry so much about backwards compatibility? Perhaps a unique one or two character symbol for each of the current use cases?
How about:
For that "give met the the real actual frikken address of something"
For example.
1. First pass compile the top object, among other things, this produces a list of any other spin files referenced in the OBJ section(s).
2a. If it has referenced objects, then loop over all the referenced objects:
2b. Recurse to step 1 (essentially compile the referenced object as if it is the top object).
2c. Loop back to 2a until all the referenced objects are compiled.
3. Redo the first pass compile of the top object.
4. Second pass compile the top object. At this stage any referenced objects are copied onto the end of this object from the heap (note: those objects can contain other objects that they reference).
5. Copy the object onto the heap.
6. This is where we return from the recursion that happens in step 2b. If we are done recursing and finished the top object compile then we fall through to step 7.
7. We now have a compiled object that has all of it's referenced objects tacked onto the end of itself (and each of those has their referenced objects tack on to them, and so on).
8. Distill all the objects down, eliminating duplicate objects and fixing up tables used for calling into objects.
9. Finalize the binary, sticking on the beginning portion and doing the checksum calc.
So when it's compiling a given object it only has the context of that object and it's directly referenced objects, and for those directly referenced objects it only knows the CON values and the PUB indices of it. This is why the @ operator in DAT sections is an offset from the start of the given object and not absolute. It doesn't know what the absolute address is going to be yet.
So what needs to happen to get @@@ working (or change @@) is to add another pass after the distill step has been done to go over the objects and figure out the actual end result address and fixup that places where @@@ (or @@) where used. However, because they can be used in many different ways and contexts it's difficult to fixup without being able to recompile expressions and do that could change the bytecode which could move the address.
BST likely compiles things in a completely different way, and probably also forces the compiling of expressions with @@@ involved to always go a certain way so as to not change the bytecode when fixing up (just needing changing a value used with the load constant bytecode). This would be pretty difficult to do with the compile method used by Chip (and OpenSpin).
Roy
That is less key presses than "@@@"
At the end of the day readability is preferable to typabily. Code is read more often than it is written.
But hey, it was only a "for instance"
It would be verified at compile time. Variables would now have types (at least in the "extended spin" mode) and so the type of the parameter would have to be compatible with the type of the object being passed in; and that type would determine the method signatures. I guess we'd have several options for specifying how objects are compatible, e.g.:
(1) Object X is compatible with object Y if they provide the exact same methods and variables.
(2) Object X is compatible with object Y if X contains a subobject that matches Y in the sense of (1) above.
(3) Object X is compatible with object Y if Y is an abstract class (interface) and X implements Y
(1) is really simple, but very limiting. I think (2) might work, but is still pretty rigid. (3) is more flexible, and I think is the "right" solution, but finding a simple implementation (in the spirit of Spin) may be tricky.
Any other ideas, thoughts?
Eric
Yup, Which is exactly why hieroglyphs should be avoided like the plague.
Google finds already in use, the clear operators like ADR(), ADDR() and AddressOf()
There is no need to invent new symbols, in what is already a niche language.
Chip's compiler and OpenSpin do not "work" with Unicode. The wrapper code converts the Unicode to PASCII (an 8bit per character remapping where the bottom 127 chars are ASCII, and the upper 128 chars are all the circuit symbol things and what not from the parallax font). The guts of the compiler pretty much just uses ASCII and ignores the extra stuff.
It is fine to clean up errors, and use of Compile mode switches is a common way to deprecate features, but you cannot discard backwards compatibility.
Sorry, yeah, I meant to write "in DAT" rather than "PASM". That is, inside Spin PUB and PRI methods @@@ and @ seem to be equivalent in meaning, although @ may be slower because it requires runtime computation. But inside DAT @ means just the offset from the object base, so it differs from @@@.
I think I've actually got @@@ working in the git version of spin2cpp, but only when the --gas switch is given (in which case DAT sections are output as inline assembly rather than being assembled by spin2cpp into a C array). My test case (exec12.spin) produces the same result as bstc.
Deciphering this also reveals what @@ is: it's an operator that adds the base address of the object to the thing after it. Normally that "thing" will be something fetched from DAT which itself has an @ in front of it. So in a sense @@(@foo) == absolute address of foo, although this is true only when the @foo part comes from DAT (if you write "@foo" in a PUB or PRI you already get the absolute address of foo, and then @@(@foo) will add the base address twice).
spin2cpp converts Spin to C++ (or C) and then compiles it with a C compiler, normally PropGCC. So all of those optimizations are available.
I'm imagining something like: which would be used like: The PUB. notation in the declaration would distinguish the parameter as being a method parameter, and at run time the call to putfloat would actually have to pass the source object (fds or vga in our examples), a method pointer (str or string), and then the other parameters.