Omnimaga

Calculator Community => Other Calc-Related Projects and Ideas => TI Z80 => Topic started by: shkaboinka on July 15, 2011, 09:23:16 am

Title: Antelope (formerly "OPIA") - A Polymorphic z80 language
Post by: shkaboinka on July 15, 2011, 09:23:16 am
Sorry to link it like this rather than posting all the details, but I already have it nicely formatted:

[EDIT: here is the current link): http://tinyurl.com/z80antelope

This language has gone through MUCH theorizing and many changes, and now it is about ready to code. Before I do so, I'd like some feedback. I have many of the same goals as were with the AXE Parser; but the differences are large enough that the two language will not be in direct competition with each other. For example, OPIA must be compiled on a computer; but it has the same feel and features as C#/Java/C++, and rather than having "everything you need" built in, it can be used or developed in all different kinds of ways.
Title: Re: OPIA - A full OOP language for z80
Post by: ruler501 on July 15, 2011, 09:25:43 am
This looks good. I'll be interested to see what comes of it.

What is the speed of this?
Title: Re: OPIA - A full OOP language for z80
Post by: Ashbad on July 15, 2011, 10:00:20 am
Shouldn't this go in "Other calc related ideas and projects"?

Also, sounds like a cool idea :). I've been secretly working on something similar for a while so, so feel free to ping me if you want to discuss some aspects of the language and some down-and-dirty specs of the 84+ :)
Title: Re: OPIA - A full OOP language for z80
Post by: Scipi on July 15, 2011, 10:21:08 am
So, in a sense it's a C# or C++-like language that compiles into Z80? (If so, then you are a god!) :P
Title: Re: OPIA - A full OOP language for z80
Post by: ruler501 on July 15, 2011, 10:28:01 am
So, in a sense it's a C# or C++-like language that compiles into Z80? (If so, then you are a god!) :P
It seems that it is a very C++ like language(I read through part of the readme)
You are an epic god shkaboinka
Title: Re: OPIA - A full OOP language for z80
Post by: Munchor on July 15, 2011, 10:31:03 am
Shouldn't this go in "Other calc related ideas and projects"?

Of course, not everybody gets a Major Community Project XD
Title: Re: OPIA - A full OOP language for z80
Post by: Binder News on July 15, 2011, 10:32:42 am
This reminds me of something Ashbad and I tried to do a while ago. But it never really got started. I think I still have the basic compiler source that I started on (C++). Want it?
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on July 15, 2011, 10:54:33 am
OPIA itself is a do-over of a previous project ... I made the mistake of releasing it with all kinds of bugs and lack of [sufficient] testing; but I learned a lot from it. Yeah, I'd love to talk about other related projects/ideas, and perhaps we can refine this a bit? ... I'm happy that there are other people out there doing this kind of thing though; until AXE came out of nowhere (and BBC Basic), I thought I was the only one.

Any emails I get ([email protected]) with "OPIA" on it will get filtered, and I can talk more specifics
Title: Re: OPIA - A full OOP language for z80
Post by: Binder News on July 15, 2011, 10:55:43 am
perfect.
What language were you going to do the compiler in? C++?
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on July 15, 2011, 11:18:21 am
I am going to do it in Java (packaged into an executable Jar) for 2 reasons:
 - It can be run on any machine.
 - It will code it as an API that can be exploited to construct a program in an OOP way rather than by typing it out ... if, hypothetically, someone makes such a thing; but it will be possible (like Bluej) ... basically, if another java-based tool wants to analyze OPIA code before compiling it, instead it can just have the compiler do it anyway, tinker with it, and then hand it back to the compiler.

I am going to make it command-line based, like the Java compiler is, so you just go "OPIA myprogram" or something; but you can pass in other things about where to look for files, and what environment to use (otherwise having to be specified in the code), etc. That will ALSO allow it to be interfaced with a nice GUI editor, which perhaps has it's own ideas about "projects" and managing files, and associating an environment in some other way than as part of the code ... I wanted it to be flexible. I can see this hooking right up to Notepad++, for example.

One other point: If there is a nice Java-based assembly compiler out there, that would be nice. Otherwise, I wouldn't mind undertaking to make one, JUST so that I can have one tool (or a couple of them) to spit out a ready program :)
Title: Re: OPIA - A full OOP language for z80
Post by: Binder News on July 15, 2011, 11:39:09 am
Humm. Java-based assembler. I don't happen to have one on hand, but I would love to work on one. I would also love to work on this compiler thing.
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on July 15, 2011, 11:49:31 am
Language aside, I can talk compiler-theory all day :) ... I have my own technique for Tokenization (inspired by Java's approach to enums) that I think is the stuff :P ... it seems like a small part of the process, but using final class instances for tokens gives you some solid tools that can make a compiler amazingly fast (and cleaner)! :D
Title: Re: OPIA - A full OOP language for z80
Post by: Binder News on July 15, 2011, 12:15:20 pm
I love compiler-theory. It's so interesting. I prefer making class instances for each statement, but I think your way might be better, I'm just a little worried that it wouldn't have support for class names and such (you really need instances for that). But I think a middle-ground could be achieved.

EDIT: Btw, what IDE do you use?
Title: Re: OPIA - A full OOP language for z80
Post by: JustCause on July 15, 2011, 12:30:26 pm
OOP? For z80?/me dies of wanting this

Good luck!
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on July 15, 2011, 01:19:19 pm
Oh yeah JC, this is it.  Since 2004, my mind has been on this topic, and I've read 1 tutorial, 1 amazing book, skimmed a bunch of others, but mostly spent countless hours/days/months at a time pouring over various aspects of an OOP language for z80, and compiler techniques ... this is happening ... maybe not tomorrow, but it will happen :)

...instances and tokens... Yes. This is why I did not actually use the Java ENUM; but my Token class contained a whole list of static final instances for all the keywords and operators, and some "signals" used by the compiler; For identifiers ("names"), it would store an internal tree of Token objects for each identifier it found. When it encountered one, a method would feed it into the tree, and if it existed already, it would return THAT instance; otherwise it would make a new instance and put it in the tree, and return that. That way, comparing names, keywords, operators ... anything... was a matter of straight-up reference comparison ( == rather than .equals). For numbers and strings (and other literals) though, I just let it make new ones. Anyway, each token object contained a final int value that flagged what "kind" of token it was, another final int that stored bit-flags (or for number tokens, stored the numeric value), and a string value that contained the actual string-value of the token. That might sound like a lot of work, but each final instance is declared with the right values in the first place, and identifiers get certain values set ... and then there were methods that looked at that kind of information, so you could just get a token and ask "is it an operator? is it an overloadable operator ... with 1 or 2 arguments (or both)? is it a keyword? is it a control-flow construct? is it numeric?" ... etc, and those checks would not have to check if it was one of some 50 tokens, but just a simple value or a bit or something.

As for OOP on everything else, I had OOP constructs to represent classes, functions, variables, blocks of code, statements, expressions, etc., so pretty quick I could get a whole structure of a program into a very easy to manage tree-like structure, and easily go "Ok, let's look at all the classes and make sure they don't have any circular inheritance, and that they behave together". I had constructs for DataTypes too, which were flexible (polymorphic; some were just primitive Tokens; others were classes; others were complexities of arrays of things). One thing I may do differently this time though ... I went back and made everything that could be the "entity" referred to by an identifier to inherit from "Entity", so that expressions and variables and so on had direct references to "entities". Then I could go back through and replace all the references to Identifier tokens with the actual things they were referencing, without damaging the structure of the parse-tree ... that was actually a bit of a nightmare, because it had to be in a very careful order so that one could identify inner/inherited namespaces properly ("a.b.c"); and the way it handled "private" and "protected" stuff was a bit interesting (it used the "invisible" technique, so things were suddenly "undefined" rather than just restricted). ... But I've done more study about ways to use a symbol table, and I think it would be fine to just stick with that :)
Title: Re: OPIA - A full OOP language for z80
Post by: Binder News on July 15, 2011, 01:32:46 pm
Okay. Umm. Do you have example source code for that? I think I get what you are saying, but I'm not entirely sure. Also, will this be  GNU, GPL, or something else?
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on July 15, 2011, 01:55:07 pm
I did GPL with Antidisassemblage before (which was basically "paste this into your stuff"); but I'm not sure what my options are for that, or what's necessarily better.

Perhaps I can get a sample of it; I will let you see what I have for the Token class :) ... email me at [email protected] and I will reply
Title: Re: OPIA - A full OOP language for z80
Post by: AngelFish on July 15, 2011, 01:56:50 pm
If you're going to write a serious compiler, it's pretty much a prerequisite to read the Dragon book. I've found it to be really good at explaining a lot of the techniques and difficulties in building a compiler.
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on July 15, 2011, 02:15:59 pm
Yes, thank you.  I've found many compiler books, and most of them were way outdated and all about the importance of using tools like "Lex" etc. ... Anyway, I've only ever really found 2 books very useful for me, and that was one of them. I at least glanced at every page, skimming over the stuff that was repetitive, ignoring what I wasn't into (i.e. JIT and Parallel stuff ... that's not happening on z80); but I totally soaked up some good stuff from it that I wasn't finding elsewhere!

The other book, which I think is the best book in the world for what it's about, is "Modern Compiler Implementation In Java" by Appel. That book showed all the good stuff about polymorphic language design, data-flow analysis, register-coloring, etc. Honestly, I don't quite remember what came out of the Dragon Book for me, just that it was helpful and I wouldn't have found it elsewhere.

There have been ideas I've come across on my own as well though, only to discover that it's been talked about in not a few places (Code mutation to store variables; using jump tables; and symbol tables ... I never understood them the way the books tended to explain them, but I came up with a "great idea" about how to track that kind of stuff, and realized that it was the same thing; only I'd do it in a more OOP manner).

...But yes, references are VERY important. When I first started on compiler design, I thought I could just "figure it out"; but I was referred to the "Lets make a compiler" tutorials by Jack Crenshaw, from which I mastered the idea of a recursive decent pattern and recursive expression parsing and tokenizing (which actually are quite fundamental if you want to make a compiler, period). ...anyway, from there is was my own tinkering and thinking, and then the Dragon Book, and then the Java book, and then a bunch of outdated books that I didn't get squat from :P ... But those 2 books (and Jack Crenshaw, which I think is an excellent place to start) helped more than anything else could have.

 ---> If anyone wants to be involved more directly, I just made a FaceBook group. Just search "OPIA" <---
Title: Re: OPIA - A full OOP language for z80
Post by: Binder News on July 15, 2011, 03:03:07 pm
Two things, I would like to be involved more directly, however, I do not have a Facebook account and will not be getting one any time soon (of my own vocation I might add). But I check my email almost daily. Send anything to there.
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on July 22, 2011, 01:48:53 am
FYI, this discussion has moved almost entirely to Cemetech.net , So if anyone wants to participate further, I recommend either going there or emailing me at [email protected]
Title: Re: OPIA - A full OOP language for z80
Post by: Munchor on July 24, 2011, 09:50:18 am
FYI, this discussion has moved almost entirely to Cemetech.net , So if anyone wants to participate further, I recommend either going there or emailing me at [email protected]

I think crossposting stuff is better to make the project more popular, why the full move to Cemetech?
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on September 20, 2011, 10:16:54 am
ATTENTION ALL!

If you want to be involved directly and/or see what's what at this point, take a look: http://tinyurl.com/z80opia
I am hosting the project at Google Code, since it comes with a Wiki and repository!!!

... I imagine I've made many-ish changes since I've sneezed a word about it in here; but it is ready to start becoming code if there are no further points in the way (and if there are points, I have thought pretty hard about all the reasons for things, and its all very solid now). :)
Title: Re: OPIA - A full OOP language for z80
Post by: NanoWar on September 21, 2011, 09:15:46 am
You should involve the community for testing later. Also example programs would help :) .
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on September 22, 2011, 09:42:52 am
Oh, I'll do the coding; but I just wanted to make a point about where/how in case anyone wants to follow the progress and observe the making of a compiler/language. Otherwise, I will indeed make a noise when it is ready to test and make libraries/utils; and there will be examples I am sure.
Title: Re: OPIA - A full OOP language for z80
Post by: DJ Omnimaga on December 31, 2011, 02:13:41 pm
I'm a bit late but I think Nanowar and Ephan points are that it's generally considered a bad practice for a forum member to constantly advertise his own site (or another) on someone else's instead of directly posting updates or copying them there, especially when you only have 10 posts. From a bunch of older member's perspective, this might look like the posts author is trying to use Omnimaga and Cemetech primarily to lure members for his site rather than getting project feedback and this might tarnish his reputation. This isn't to mention that some people are under parental control and may not be able to visit other specific sites.

On the old Omnimaga board, there was a rule disallowing forum members to advertise their own calculator site (except if they got permission) unless they had at least 2000 posts.
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on January 01, 2012, 09:50:48 pm
Sorry DJ ... I began posting about it in both places, and got a decent initial response in both. However, it only REALLY took off at Cemetech, and thus decided to keep most of the posts there (they are time consuming, because they are thought out). Rather than just abandon [these people] altogether, I left notifications ... but I see how that could be a problem. I don't want to "steal" followers from one site to another, and I suppose I could have just copied posts and reposted them here. So much information was interchanged at Cemetech that I found it would be an overwhelming task to keep it all in both places; however, to give SOMETHING of substance, perhaps I will go back and take the key points and put them in a post here. That way there is a glimpse of what's going on, and some of the key discussion.

However, my project is hosted at google code ( http://code.google.com/p/opia/ ), and even when I discuss it anywhere, I leave links there regularly, because that is where one must go to see the language documentation and source etc. (I am not going to host it in multiple places). I will, however, go back and put a lot of the key discussion here as well.

Sorry for the misunderstanding! ... I promise a lot of information HERE soon.
Title: Re: OPIA - A full OOP language for z80
Post by: BlakPilar on January 01, 2012, 10:19:28 pm
Hi shkaboinka. I was talking to Homer-16 on XBox one day and he told me about OPIA. I decided to look it up and I must say: it looks very promising. I admire the syntax you've come up with as it is not overly complex, and elegant. I especially like your implementation of anonymous functions. All in all, though, nice work. :)

I haven't read all of the Cemetech conversation, but do you happen to have an ETA for some kind of an alpha or beta release?
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on January 02, 2012, 01:37:20 am
It's hard to say. The vast majority of the time spent on it (more than 95%) has been conversational and hammering out all the theory. Look up "Antidisassemblage" (but make sure you find version 1.6 alpha), which is a precursor. I spent 2ish years on it, and roughly 6 months of that involved coding what it is; and not more than 20% of that time was actual coding. OPIA is me deciding to scrap that altogether and start all over again, but with much of the same ideas ... so you could say I've been at it for 6 years (not counting a 2 year leave). OPIA was GOING to be very Java/C#-ish, and was VERY nearly all figured out; but then I came across the design of Google's "Go" language, which offers the same polymorphism in a more flexible and simplified form. Thus, just over a month ago, I redesigned the language (again (again (...))); but I have some code in place now, and I spent perhaps a month on the Tokenizer (between school etc.), and basically the last week writing the Preprocessor (finished), and I have yet to write the syntax-tree stuff (at least 2 weeks), the code analysis stuff (at least a month), the assembly conversion (at least a month), other aspects between those (a week), and other touch ups etc. (another week) ...

... So my guess is at LEAST 3 months from now; and that is assuming that school and moving etc. do not push it way to the back (which is likely) and that I do not run into other major changes I want to make (I can scarcely think of any way to improve it more) ... but supposing there are delays, probably 6 months ... I want to have it pretty well set within this year though.

However, even now, there are working & testable aspects of the compiler, and I'd like people to try things out and give me feedback if they want to assist. ... Random thought: if I finish this up, and there is a demand for it, perhaps I can make another version that uses the Java/C#-ish form instead (it would be very similar though and use a lot of the same compiler parts) ... but I don't know if that is likely. I chose the new design because it was simpler and more powerful and lighter weight, which I felt was appropriate for a z80/embedded-ish language.
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on January 02, 2012, 04:40:54 pm
A random list of points discussed previously on other forums (modified):

BOOLEANS - Booleans are a whole byte because it takes extra instructions to extract/insert just one bit, which adds more than just another byte to the program just for using it; so it actually saves space that way.

MEMORY MANAGEMENT - No Garbage collector will be built-in. However, functions can be written which will enable the "new" (and "delete") operators for the language. The idea is that any kind of memory management can be plugged in (whether coded manually, or already part of the platform/OS). As for static allocations, there are preprocessor directives whuch can be used to signify sections of "same RAM" which the compiler will use for larger things that lack initialization values.

VIRTUAL FUNCTIONS - I was originally going to have the compiler just KNOW when functions should be virtual/late-bound because of the overridden definitions (like Java). However, requiring one to explicitly say which functions are virtual (like C#/C++) means that a the internal representation of a class can be determined without having to look at other code. This is important because OPIA allows you to specify an address where something is already stored (e.g. precompiled or otherwise already existing) rather than allocating space for it otherwise.

ENVIRONMENT DEPENDENCIES - If a program is completely generic (i.e. nothing platform-specific), then it will run anywhere (directly on the bare hardware). Standard representations of functions, arrays, etc. also allow things to be picked out explicitly and used with new code. The whole compilation process is going to be very modularized, such that it can be used an API by other tools (e.g. an IDE which uses the compiler itself to highlight syntax and find errors, but without doing a full compile).

FEATURES - OPIA will ONLY include features which would be difficult to do with the language otherwise, which can be implemented using close to the same overhead NECESSARY as if done manually, and which do not add unnecessary complexity to the language. For example, I was going to have classes & interfaces (I will post more about that later) because one would HAVE to use late-bound functions and virtual tables to simulate that anyway; but I have even replaced classes & inheritance with structs and simpler interfaces because it makes the language simpler, adds more power/flexibility, and provides a much closer representation of the underlying mechanisms used. OPIA will NOT include operator overloading, bounds-checks (or any built-in error handling), excpetions, or assertions (though interpreted aspects can be used to compile code dynamically). I was going to provide parametric types (using type-erasure, since that provides a single representation for each thing); but with the new Go-style interfaces, OPIA might be fine without them ... maybe in the future, but I'm not promising it.

VALUE PASSING - Always pass-by-value. I was going to provide reference-types, which use pointers internally, but now that I've switched to a simpler Go-like setup, one can just use pointers directly as needed.

NAMING - I really do not see what it wrong with the name "OPIA" (except for the similar spelling to "opium"); but the only other name suggested so far that I even like at all was "Candu" (Malay for "opium"). No Z++, because there are too many letters and pluses and sharps etc. already. No "TI" anything, because it will run on ANY z80 machine (though heck yes, TI's are the focus) ... but seriously, is "OPIA" such a bad name? (Object-oriented Pre-Interpreted Antidisassemblage ... though admittedly, the Go-style is polymorphic and object-based without being truely object-oriented in the traditional sense).
Title: Re: OPIA - A full OOP language for z80
Post by: BlakPilar on January 02, 2012, 04:52:08 pm
Quote
BOOLEANS - Booleans are a whole byte because it takes extra instructions to extract/insert just one bit, which adds more than just another byte to the program just for using it; so it actually saves space that way.
Hmm... So, for Boolean values, would it be faster on-calc if we just used single bytes and checked if they were (non-)zero ourselves?

As for the name, I like OPIA. I see nothing wrong with it. Everything else sounds good :D
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on January 02, 2012, 05:03:46 pm
REGARDING OBJECT-CONSTRUCTION, INTERPRETED ASPECTS, TYPE-CASTING:

At one point, I provided 3 mechanisms for object (class instance) construction. Given some class called Foo:

Foo f; // No construction used (can be assigned later)
f = Foo(...); // Constructed into a static (anonymous) allocation and then assigned to f
f = new Foo(...); // Constructed into a dynamically allocated location and then assigned to f
f = static Foo(...); // A Pre-constructed (embedded directly into the program) instance is assigned to f
static Foo f = ... // NOT the same as previous statement (static var vs. static instance assigned to var)

This is long gone, because I decided that the compiler can determine when to embed and when/how to allocate as needed. I had also had a $ and a $$ operator, which both told the compiler to interpret certain things, and how strictly. For example, a construct (e.g. a while-loop) marked with $ would be interpreted, but a $$ would mean to also interpret everything (e.g. inner loops) inside of it. A $ function would be inlined, and a $$ function would be inlined AND completely interpreted ($$ was a "deep"/recursive command) ... However, that is a mess! ... Most of the code is pre-interpreted and optimized automatically by tracing values through the code, skipping variables when the same value is known to reside elsewhere, etc. One can still use $ to state that something MUST be interpreted (and with a higher priority), or else an error is given if it is not possible (e.g. values cannot be predicted as needed).

For Type-Casting, I restorted to (expression -> type) syntax. Eventually I replaced all uses of the -> operator ("returns" or "cast") with a colon. Type-casting is not an operation in itself, but more of a guideline to the compiler such that the expression or value is to be TREATED as the specified type. The cast applies to all code previous to the colon. For example, (a+b:byte) performs the addition in such a way that it results in a byte value (i.e. rather than performing it however, and then converting the result to a byte); and (a+(b:byte)) performs the addition is such a way that b is REGARDED as a byte (i.e. only the lower-byte of b is used).
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on January 02, 2012, 05:07:50 pm
REGARDING STRINGS (and a good sample of code prior to the Go-style reformation of the language):

There is no "string" type, but a character array (char[]) is used instead. String literals automatically convert to character arrays followed by a null value (zero). I wanted to have the + operator concatenate strings cleanly, and cleanly means not allocating a whole new array for EVERY concatenation. Java solves this using a "StringBuilder", which I could code (using OPIA code) as follows:

class StringBuilder {
    private class Node {
        public char[] string;
        public Node next;
        public Node(char[] s) { string = s; next = null; }
    }
     
    private Node head, tail;
    private uword length;

    public StringBuilder() { head = tail = null; length = 0; }

    public void concatenate(char[] string) {
        Node n = new Node(string);
        if(head == null) { head = tail = n; }
        else { tail = tail.next = n; }
        for(uword i = 0; string[0] != 0; i++) { }
        length += i;
    }

    public void merge(StringBuilder s) {
        if(s.head == null) { return; }
        if(head == null) { head = s.head; }
        else { tail.next = s.head; }
        tail = s.tail;
        s.head = s.tail = null;
    }

    public char[] toString() {
        uword pos = 0;
        char[] string = new char[length];
        for(Node n = head; n != null; n = n.next) {
            for(uword i = 0; n.string != 0; i++) {
                string[pos++] = n.string;
            }
        }
        return string;
    }
}

abstract class Object {
    public abstract void printTo([char[]] handler);

    public StringBuilder toString() { // intentionally misleading
        StringBuilder s = new StringBuilder();
        printTo(s.concatenate);
        return s;
    }
}

interface Comparable<T> where T : Comparable<T> {
    byte compareTo(T other); // interface members are inherently public abstract


// The compiler then makes these conversions (and pretends that the resulting StringBuilder is "returned" by each):

char[] str;
StringBuilder sb;
...
sb  + sb;  // => sb.merge(sb);
sb  + str; // => sb.concatenate(str);
str + str; // => str.toString().concatenate(str);
str + sb;  // => str.toString().merge(sb);
str = sb;  // => str = sb.toString();
sb  = str; // => sb = new StringBuilder(); sb.concatenate(str);
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on January 02, 2012, 05:11:09 pm
REGARDING PASSING VALUES (to functions):

Previously, function parameters were to be stored (in reverse order) in a static block of memory just before the function body / entry point, so as to be locate-able even from a function-pointer. However, I found that it would be more efficient to allocate the arguments per call and pass the address of the entire allocation. In other words, here is the difference in the old and new process of passing values:

old method:
- Store arguments 1,2,...,n in (func_address - 1), (... - 2), ..., (... - n)
- Call the function
- Arguments are accessed within the function directly, since they are stored in predetermined addresses

new method:
- Store arguments in some static memory location (unique to each call), and store the address of this in the IX register
- Call the function
- Arguments are accessed as offsets of the address stored in IX

This might seem like it takes up more memory because the arguments are allocated per call. The reason this is efficient is that (1) only one value needs to actually be passed, (2) arguments which can be resolved to predetermined values can be preloaded at compile time, (3) once the values are extracted from IX, they can live in registers (i.e. the compiler will convert expressions to SSA form anyway), and (4) this means that when a function is called via a function-pointer, the arguments can be loaded statically rather than determining their location as an offset of the function-address.

Originally, I decided that function arguments should go into static memory addresses (like other variables) because I was under the assumption that the compiler must pick a location for a variable and stick with it. However, the compiler will let the "address" of a variable shift around as it moves from register to register (and to memory as needed). I avoid the loop-hole of "what if a variable is pointed-to by a pointer?" conundrum by not allowing variables to be pointed-to, except when passed to "ref" or "out" parameters (i.e. passed "by reference", which assumes a saved state until the function returns). To clarify, pointers are allowed, and they can point to new allocations and allocations referenced by other pointers; but not to other variables of the same base-type (i.e. without the "pointer" part), unless that variable is declared "final".

I have to credit Ben Ryves for suggesting to use IX rather than HL for passing an address (to allow for offset access), which he says is the way that BBC BASIC passes values.

I do plan to actually pass values within registers, but that is a bit complex, and I want to get it working before I hammer out a complex way of determining which registers to use for which scenarios ... for now though, I can easily let functions which take a single byte or word to use A or HL though (since this is how values are returned anyway).
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on January 02, 2012, 05:53:24 pm
=== AND NOW FOR A MAJOR CHANGE TO THE LANGUAGE ===

THIS IS WHERE I CHANGED THE LANGUAGE SIGNIFICANTLY TO BE
MORE LIKE GOOGLE'S "GO" LANGUAGE AND LESS LIKE JAVA/C#:

Basically I replaced classes & inheritance with a more powerful, flexible, light-weight model for interfaces & composition. This is a what makes Google's Go language a "fast, statically typed, compiled language that feels like a dynamically typed, interpreted language." It's a different approach to polymorphism, involving these changes:

(1) Replace classes with plain structs, but allow them to embed "anonymous" types which simulate a some inheritance using composition.
(2) Methods are declared separately (externally), and can thus be declared as needed and on ANY type.
(3) A datatype automatically implements an interface simply by having the required methods. For example, a function could taking a "Writer" interface could be given ANYTHING that has a "write()" method (like "duck typing"). This allows datatypes (structs) to implement interfaces without even "knowing" it, and without any overhead added to the type (struct).

It would have been silly NOT to do (2) and (3), since they simplify and add power to the language without any major underlying changes. The argument for (1) is that the "class" is removed because it becomes redundant: If you remove the method table from a class and store it separately, you have an "interface" (see chart below).

Class-based model (* denotes a pointer):

struct := [all the data of the struct]
table := [*method, *method, *method, ... ]
class := [*table, struct]
interface := [*table, *class]

New model: (same, but without "class", and *class becomes *object)

This new model provides better access to the underlying mechanisms, and results in simpler code! At the most fundamental level, polymorphism simply involves the use of method-pointers, which is what "virtual" methods are anyway. Thus, one could do it all manually just by storing or passing method-pointers directly (and given (2), method pointers would just be function-pointers, since the "this" argument would be explicit). However, passing an object along with it's methods is EXACTLY what the "interface" is already!

Here is some example code, with some obvious syntax changes made:

   byte x,y,z = a,b,c; // assignment in parallel
   *byte ptr; // ptr is a pointer-to-byte variable
   [5]byte arr; // arr is a static array of 5 elements (not a reference)
   []byte arrP; // arrP is a reference to an array (unassigned)
   *[]byte p2a; // pointer to array
   []*byte aop; // array of pointers
   a,b,c := 1,"yo",ptr; // declaration with type-inference (byte, []char, *byte).

   func f1(byte a, b : char) { ... } // function f1 takes bytes a & b, and returns a char
   func f2( : byte, char) { ... } // function f2 takes nothing, returns a byte and char
   func f3(byte a, b) { ... } // function f3 takes bytes a & b, returns nothing
   func(byte,byte,byte) x; // pointer to some func(byte a,b,c)
   func(byte a,b,c) y; // Same as above (using name-holders)
   x = func(byte a,b,c) { ... }; // anonymous function is declared and assigned to x

   struct A { byte x; } // an A has an x (someA.x)
   struct B { A; byte y; } // Composure: someB.x is short for someB.A.x

   interface foo { // interface foo defined as anything containing:
      foo1(:byte); // a method called foo1 which returns a byte
      foo2(byte); // ...foo2 which takes a byte and returns nothing
   }

   func A.foo1(:byte) { ... } // method for A implementing foo.foo1
   func A.foo2(byte b) { ... } // ... implementing foo.foo2

   A a; ... foo f = foo(a); // interface-instances are constructed around valid vars
   B b; ... f = foo(b); // Invalid, because b.foo1 is really b.A.foo1
   f = foo(blah,blahX,blahY); // overloaded interface instance:
   f.foo1(); f.foo2(5); // calls blah.blahX() and blah.blahY(5)

I later decided that I could allow functions to be declared within structs to designate "virtual functions". By doing so, a function-pointer is actually stored within the struct, with a default value pointing to the provided method body. Virtual methods CAN be used to fulfill interface requirements:

   struct Thing {
      byte x, y;
      func act(); // no method body (in list)
      func compute(:byte) {
         return x*y;
      }
   }

   func Thing.add(:byte) { return x+y; }
   func Thing.sub(:byte) { return x-y; }

   a := Thing{1,2,Thing.add};
   b := Thing(3,4,Thing.sub};

   a.act();   // calls a.add()
   b.act();    // calls b.sub()
   a.compute(); // calls Thing.compute() on a
   a.compute = Thing.add;
   a.compute(); // now calls Thing.add() on a
   b.act = a.compute;
   b.act();   // calls Thing.add on b
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on January 02, 2012, 05:56:39 pm
COFUNCTIONS (Closures, Iterators, Coroutines):

Cofunctions are function-objects which are stored like objects (structs), but invoked (called) like functions. The yield command is used to return values, but continue from the same spot on the next call. Cofunctions are declared with colons separating the initializer arguments (for creating instances), invokation arguments (for passing values on each call), and return type(s):

   // simulating a closure on x
   cofunc counter(byte x : : byte) {
      x = x+1;
      return x;
   }

   counter c1, c2 = counter(3), counter(1);
   c1(); c1(); c1(); // 4,5,6
   c2(); c2(); c2(); // 2,3,4

   // using yield to simulate a generator
   cofunc rotatingSeq( : byte add : byte) {
      byte last = add; // last will be stored internally
      yield add;
      yield add+last;
      return add-last; // next call starts back at top
   }

   rotatingSeq r = rotatingSeq();
   r(1); r(2); r(3); // 1,3,2
   r(4); r(5); r(6); // 4,9,2
   r(7); // 7, (see f3 below)

   // Cofunctions are valid as function-pointers:

   func(:byte) f1,f2 = c1,counter(0);
   f1(); f1(); f1(); // 7,8,9
   f2(); f2(); f2(); // 1,2,3

   func(byte:byte) f3,f4 = r,rotatingSeq();
   f3(1); f3(2); f3(3); // continuing from r: 8,-5,3
   f4(1); f4(2); f4(3); // starting fresh: 1,3,2

The compiler accomplishes all of this by making the following modifications:
(1) The underlying function is modified to take a pointer to a cofunction-instance in addition to its per-call arguments.
(2) Each confunction-instance is stored as a tail-call (a "goto") to the underlying function (thus allowing the cofunction to be called as if it was the function itself), followed by any information needing to be stored between calls.
(3) When the yield command is used, the underlying function directly modifies the tail-call in the confunction to jump to where the function left off (rather than to the start of the function).
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on January 02, 2012, 06:06:51 pm
...And there it is. This forum should now be caught up (though much discussion is missing, I provided all the key points). The changes from Java/C# style (btw, I think C# is the best OOP language yet...) to a more Go-ish style (..but Go seemed more simplified and flexible, and more powerful at the low-level; and therefor more suitable for a z80 language) results in less overhead, MUCH less keywords, and NO TYPE HIERARCHY (as inheritance imposes)! In keeping with this simplification, I removed the public/private/protected mechanisms, and simply provide that lowercase entities are only visible within the namespace they are declared in (files may start with "namespace BLAH;"), structs & interfaces etc. may not be declared within eachother, nor may they contain "static" variables/entities (instead, these are declared directly within the same namespace). I was going to disallow nested namespaces and remove the "using [someNamespace]" mechanisms, but I think I can allow that anyway, since it would be the only real way to nest "static" things in a modular way ... but without having to use the "static" keyword :)

As always, all current documentation can be found at http://tinyurl.com/z80opia , but I will try to keep up to date here as well. You can view the source there and test it as you please (which would be much appreciated). Thanks everyone for participating :)
Title: Re: OPIA - A full OOP language for z80
Post by: DJ Omnimaga on January 02, 2012, 06:34:42 pm
Sorry DJ ... I began posting about it in both places, and got a decent initial response in both. However, it only REALLY took off at Cemetech, and thus decided to keep most of the posts there (they are time consuming, because they are thought out). Rather than just abandon [these people] altogether, I left notifications ... but I see how that could be a problem. I don't want to "steal" followers from one site to another, and I suppose I could have just copied posts and reposted them here. So much information was interchanged at Cemetech that I found it would be an overwhelming task to keep it all in both places; however, to give SOMETHING of substance, perhaps I will go back and take the key points and put them in a post here. That way there is a glimpse of what's going on, and some of the key discussion.

However, my project is hosted at google code ( http://code.google.com/p/opia/ ), and even when I discuss it anywhere, I leave links there regularly, because that is where one must go to see the language documentation and source etc. (I am not going to host it in multiple places). I will, however, go back and put a lot of the key discussion here as well.

Sorry for the misunderstanding! ... I promise a lot of information HERE soon.
Aaah ok, I guess I kinda misinterpreted it then. I thought your Google site had a discussion board and it seemed that on Cemetech you constantly encouraged people to go there, so I thought it was to move the entire discussion there instead of an established board. It's always good to have some major updates on big sites too (even if not all of them) so it rejoins as many community members as possible. Of course since on Omnimaga the language is in direct competition with two on-calc languages the audience might be a bit harder to convince, though, although we never know.

Anyway nice updates and I'm glad this is still progressing. :)

Also holy sixtuple-post batman! O.O
Title: Re: OPIA - A full OOP language for z80
Post by: BlakPilar on January 03, 2012, 04:42:00 pm
I haven't read all of this yet because I haven't had time, but I skimmed over the cofunctions section because I didn't understand them from the Wiki. From what I'm getting, they're the same as anonymous functions?

EDIT: I'm looking at the source, and in the Token file, should "volitale" be "volatile"?
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on January 03, 2012, 05:25:50 pm
I have corrected the spelling of "volatile", thanks :) (I really thought it was spelled that way!)

As for my "cofunctions", you will actually get a more accurate explanation if you look up "coroutine". The reason I chose "cofunctions" anyway was that "cofunc" looked more intuitive to me than "coro", since they can be used a "funcs". ... But it is more accurately a coroutine. A coroutine is a function which can do something, pause and return a value, and then continue where it left off when it is called again. It's like having a subprogram which you can switch between! ...and there are many other uses, one of which is that of an iterator/generator. This is a superior approach to making an iterator object as a class, because those have to store information as well, but also reenter the same methods and check the same things again, etc. The reason that coroutines have to be created as variables is that this allows for multiple "instances" of them to be in use at one time (and the same mechanisms are required anyway; so might as well just attach the data to a variable).

A "closure" is when a function is declared inside of another function, and it uses some of the local variables that were declared inside of the outer function. Languages that support this can do one of two things: (1) allow the variables to be modified directly, (2) make a copy of those variables, and that function gets it's own copy of them to modify as it pleases. Closures are used in class-less languages like JavaScript to simulate OOP-ish structures, or to create specific functions (e.g. a function-making function).

Because coroutines and closures both require additional storage, I combined them into what I call "cofunctions" (which are really just coroutines). These can be used as closures by, instead of capturing variables in the outer-context automatically, you just pass those variables (or values) to the "initialization arguments" of the cofunction. The "initialization" arguments are stored as part of the cofunction object, and can be used and modified each time (and they are used to create an instance variable of the confunctions); and the per-call arugments are the arguments that are passed each time the cofunction is called. Rather than have a stange { a,b = yield stuff; } syntax, I just have the per-call arguments have variable names attached to them (just like how return values do NOT have names attached to them).

I hope that helps; but if not, look up coroutines, generators, and closures. There is also a very nice (but very in depth) analysis of coroutines ("Revisiting Coroutines") which convinced me to allow them and helped me decide the best way to implement them, which I made a short-link for as: http://tinyurl.com/revcor

Anonymous functions are just nameless functions which are immediately assigned to function-pointers. It's the equivalent to creating a "new" function, in the same way someone would create a "new" anything else in Java/C#/C++. This is convenient because you can pass a literal function declaration to a function-pointer argument, rather than having to declare a function elsewhere and then reference it. This is why I am allowing anonymous functions to be declared in other functions (where else are they going to go?), but I am on the fence as to whether or not I will allow this for other functions as well, or whether or not either of them can refer to local variables declared in their surrounding functions (if they CAN, then they will modify them directly, since (1) that is useful and most efficient in some cases, and (2) variables can already be "captured" by passing them to the initialization arguments of a "cofunc").

SIDE NOTE/QUESTION: What are people's feelings about my changes from the Java/C# style to the Go-ish style? (Compare the old and current overviews from http://code.google.com/p/opia/w/list )
Title: Re: OPIA - A full OOP language for z80
Post by: BlakPilar on January 03, 2012, 05:33:07 pm
Ahh, okay, now I understand. I was beginning to think that cofunctions and anonymous functions were synonymous, but now I see what they're for. That's really cool, actually. I'll definitely have to try something soon! :D
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on January 05, 2012, 04:24:37 pm
EDIT: All you really need to look at is this table (and yes, I did just totally scrap the old post for this):
   switch(value) { case 1: ... 2: ... 3: ... }

   ---Jump Table---   --Look-Up-Table--   --Direct_Address--
    ld a,(value) ;3    ld hl,cases   ;3    ld hl,(value)  ;3
    ld ($+4),a   ;3    ld bc,(value) ;4    jp (hl)        ;1
    jr N         ;2    add hl,bc     ;1
    jp case_1          jp (hl)       ;1
    jp case_2         cases:
    jp case_3          .dw case_1
                       .dw case_2
                       .dw case_3
   ----------------   -----------------   ------------------
   = 8 (+3 per case)  = 9 (+2 per case)   = 4 bytes used (+0)
Since a jump-table is clearly the worst choice, the only real choice now is whether I want uber-efficiency (using direct addresses) or flexibility (using look up tables). I either I provide enums with even values (and hidden) so that they are efficient to use with switches, or I provide "selectors" which are each to be used with exactly ONE switch each, and contain actual case-addresses as values. The big difference is that an enum could be USED in any switch, but a selector IS the control for a particular switch. ... Perhaps I could provide both? Enums are flexible and better as values (being one byte each), while selectors are uber-efficient when used as case-selectors. A selector would be declared somewhat like an inline enum:
enum eFoo {X,Y,Z} ... eFoo a; a = eFoo.X;
selector(X,Y,Z) sFoo; sFoo = X;

(My previous suggestion about modeling a switch as a function with multiple entry points comes from the idea that modifying an address directly and jumping to it sounds just like a function-pointer; but since switch-cases can fall through to the next case, perhaps a function with multiple entry-points, being several functions smashed together but with an entry-table as well (stored as a function-pointer-array) ... but I resolved that by just using a look-up-table instead).

EDIT-EDIT: Here is a possible solution: I could provide both simply by providing the enum, and "switch on an enum" variables:
   // enum usage
   enum Foo {X,Y,Z}
   Foo f1 = Foo.X;
   f2 := Foo.X;

   // switch "on Foo"
   switch(Foo) g1 = g1.X; // "g1.X" because g1 uses specific case-addresses
   g2 := switch(Foo).X; // g2 uses case-addresses that DIFFER from g1...
   g1 = g2; // ...which means that THIS IS NOT ALLOWED

   // switch on anonymous enum
   switch{X,Y,Z} h1 = h1.X;
   h2 := switch{X,Y,Z}.X;

   // Later on, g1 is used in a switch statement:
   switch(g1) {
     case X: ...
     case Y: ...
     case Z: ...
     // NO default code (all cases are explicit)
   }

The switch "on enum" variables only use the values of the specified enum as labels for addresses of a specific switch-construct. Therefor, each switch variable has its own set of values, and thus they cannot be assigned each other's values (hence the "varA = varA.value", and the type is singular to each variable). Each switch variable may only be used in ONE switch-statement.

Note: The parser can tell the difference between each use of "switch" by the placement of parenthesis, brackets, and identifiers:
 - switch(ident) ident
 - switch{list} ident
 - switch(ident) {
Title: Re: OPIA - A full OOP language for z80
Post by: BlakPilar on January 07, 2012, 12:53:24 pm
Personally I would think look-up tables are the best (I normally go for flexibility), but seeing as this is on the calculator, I would say direct addresses.
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on January 07, 2012, 01:20:28 pm
How do you feel about using both though (i.e. the "EDIT-EDIT" section)? That way, an enum can be used as an enum, but also for a switch (so long as it only receives values from its own value-set). By stating a variable as a "switch" rather than an enum, you are saying very specifically "this is for a switch" (or that the selection part of a particular switch is being treated as a directly-modifiable variable). The cool thing is that this functionality exists on the functional level in the form of function-pointers :)
Title: Re: OPIA - A full OOP language for z80
Post by: BlakPilar on January 07, 2012, 01:31:00 pm
I was a little confused about that part (using switch statements as variables). If I had something like switch(Foo) g1 = g1.X; is that essentially initializing g1 as the type Foo while setting its value to Foo.X (i.e. Foo g1(Foo.X); in C++)? Then if I did switch(g1), case X would be the one executed?
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on January 07, 2012, 02:04:09 pm
Sort of... they are different types altogether. A 'Foo' can be assigned values from the enum declaration (or from other Foo variables). A 'switch(Foo)' just borrows the labels of Foo, but assigns separate values (i.e. addresses of actual cases in a switch somewhere). In fact, given two 'switch(Foo)' variables g1 and g2, g1 and g2 use DIFFERENT values because they are associated with different switches. That is, g1.X is the address of "case X" where g1 is switched on (switch(g1) { case X: ... }), and g2.X is the address of "case X" where g2 is switched on. Therefor, though they appear to have the same type, g1 and g2 cannot be assigned each other's values, neither can they take values from a 'Foo'.

Code: [Select]
enum Foo {X,Y,Z}
switch(Foo) g1, g2;
Foo f;
...
switch(f) { ... } // f is used as an INDEX for a look-up-table for this switch
...
switch(f) { ... } // ...and again in this switch.
...
switch(g1) { // No index. This is simply 'goto (g1)'
   case X: // g1.X refers to the address of this location in code
   case Y: // g1.Y refers to this address, etc.
   ...
}
...
switch(g2) { ... } // Likewise, g2 will have it's own switch, and it's own X,Y,Z
...
switch(g2) { ... } // ILLEGAL! (g1 and g2 are variables for ONE specific switch)
...
g1 = g2.X // ILLEGAL, because that would cause the switch on g1 to goto g2's "case X"

... There is really no point in defining an enum just to make a switch variable on it. The code above might as well have just said 'switch{X,Y,Z} g1, g2;'. The only reason I allow it is that, supposing you already HAD an enum defined, and the cases were related conceptually to the enum, then you might as well just use the same labels (and rather than copying each label, you can just plop the enum name into the switch-variable type). Again, a switch "on" an enum only mimics that enum by using the same labels for its values. ... But since it's only a mimic (switch variables cannot interact with other variables because they each use a unique set of case-addresses), is it worth allowing the mimic at all? That is, I could just allow the switch{X,Y,Z} g1 type of declaration if that would be less confusing.
Title: Re: OPIA - A full OOP language for z80
Post by: BlakPilar on January 07, 2012, 02:15:22 pm
Ooohhh, okay, I understand now. That would be awesome if there were both ways!

Also, another question that I've been meaning to ask is will you provide built-in methods for things math and output? Like in .NET there's the static Math class where you can do things like Math.Pow(2, 6); which is the same as 26. And by output, I mean like Print, PrintLn, turning pixels on buffers on/off, etc.
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on January 09, 2012, 03:06:19 am
The core language will only contain the mechanisms that are fundamental to the language. In other words, there will be no built-in math, input/output, or other utility functions etc. built in. The only exception might be some string-manipulation (there should be a post somewhere about a "StringBuilder" which can be used to concatenate strings) and possibly some array-copy stuff.

HOWEVER, once the CORE language is finished, then libraries can be written for that kind of stuff. ... And that is where I will need a lot of help (or just let it loose and see what flies) :)

EDIT: On a side note, IS NOBODY DISAPPOINTED THAT I DROPPED THE JAVA/C#-ish VERSION OF OPIA? (I just want to make sure everyone is still good with it; or be able to convince otherwise). I do intend for OPIA to be much faster and more versatile (and much more optimizing) than Axe or Grammer, or anything else aside from pure assembly :)

I have recommitted my source (http://code.google.com/p/opia/source/browse/) with some error-fixes. Preprocessing should not be complete, with errors marked correctly. The result is a list of tokens (which the syntax-tree-building portion of the compiler is to process), containing (in order):
 - Error tokens (if any)
 - #allocate and #assembly statements (as applicable to environment)
 - all other source tokens (as applicable to environment)
 - Token.EOS (the "end of source" token).

EDIT-EDIT: I adapted some code from Google Go (http://golang.org/doc/go_tutorial.html#tmp_359) into OPIA code as a demonstration of what OPIA can do (and how to adapt their "gofuncs" and channels into cofuncs, and how cofuncs can be used as asynchronous processes). This is a prime-number sieve:
Code: [Select]
cofunc generate(:word) { for(i := 2; true; i++) { yield i; } }

cofunc filter { func(:word) in; word prime; } (:word) {
    while(true) { i := in(); if(i % prime != 0) { yield i; } }
}

cofunc sieve(:word) {
    in := new generate{};
    while(true) {
        prime := in(); yield prime;
        in = new filter{in, prime};
    }
}

func main() {
    nextPrime := sieve{}; // Print first 100 primes:
    for(i := 0; i < 100; i++) { Print(nextPrime()); }
}
Title: Re: OPIA - A full OOP language for z80
Post by: BlakPilar on January 09, 2012, 04:58:38 pm
Ahh, okay. What language would the libraries be written in? OPIA, ASM, other?

As for the language drop, I'm okay with it; I like learning new languages :) (I'm studying Russian by myself right now ;D)

As for the example, do we not need to declare a value's type? (nextPrime, prime)
Title: Re: OPIA - A full OOP language for z80
Post by: C0deH4cker on January 09, 2012, 05:29:43 pm
I believe that those do not need have their respective types declared because prime and nextPrime are instances of cofunctions, due to the new statement.
Title: Re: OPIA - A full OOP language for z80
Post by: BlakPilar on January 09, 2012, 05:31:35 pm
Ahh, okay, I didn't look hard enough lol. Thanks.
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on January 09, 2012, 09:05:27 pm
Actually, they do need to (and did) have their types declared, just like any other variable. The ":=" operator tells the compiler that a variable is being both declared and initialized, and to infer the type from the initialization value. At first I was not sure about having both "=" and ":=" operators, but I've found that it indeed makes it easier to code! :)

Code: [Select]
cofunc generate(...) { ...i := 2;... } // word i = 2;

cofunc filter(func(:word) in ...) { ...i := in();... } // word i = in();

cofunc sieve(...) {
   ...in := new generate();... // *generate in = new generate();
   ...prime := in();... // word prime = in();
}

func main() { ...nextPrime := sieve();... } // sieve nextPrime = sieve();
The only bearing on "new" is that, without it, that function would overwrite the same static variable each time; so I used "new" to say "allocate new memory for this" (which actually makes the variable a pointer, since that returns an address ... another nice thing about automatic stuff like that) :)
Title: Re: OPIA - A full OOP language for z80
Post by: BlakPilar on January 09, 2012, 09:18:18 pm
Woah, that's a really helpful feature!
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on January 10, 2012, 01:46:15 am
What's more, it can also tell when dereferencing (*) and addressing (&) is implied. If you give the current overview a good look, you might find some surprises like that (I am a bit brief in it sometimes) :)

http://code.google.com/p/opia/wiki/Overview

EDIT: Here is another change:
   // ===== Previous setup for cofuncs =====

   cofunc ABC(a:b:c) { ... } // a,b,c represent init args, call args, returns

   cofunc B(b) { ... }    // short for  B( :b: )
   cofunc C(:c) { ... }   // short for  C( : :c)
   cofunc BC(b:c) { ... } // short for BC( :b:c)

   cofunc AB(a:b: ) { ... } // no short form for this
   cofunc AC(a: :c) { ... } // no short form for this

   func(b:c) f = BC(); // funcs declared with same call-args & returns

   // ===== Current setup for cofuncs =====

   cofunc ABC{a}(b:c) { ... } // a,b,c represent init args, call args, returns

   cofunc B(b) { ... }      // previously  B( :b: )
   cofunc C(:c) { ... }     // previously  C( : :c)
   cofunc BC(b:c) { ... }   // previously BC( :b:c)
   cofunc AB{a}(b) { ... }  // previously AB(a:b: )
   cofunc AC{a}(:c) { ... } // previously AC(a: :c)
   func(b:c) f = ABC{a}; // func declaration matches that of cofunc ABC

   // ===== Example of using cofuncs as struct-funcs =====

   cofunc blah { byte x, y; } (byte z : char) { ... }

   b := blah{1,2}; // Just like a struct!
   b.x = 5;

   char c = b(3);  // Just like a func!
   func(byte:char) f = c;
   func(byte:char) f2 = blah{3,4};
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on January 12, 2012, 10:09:54 pm
(whole post edited ... again)

Ok, I am going to reinforce some new rules:

(1) Struct members with default values must come last in the struct. When initializing a struct instance, the initial value for a particular data member may be left out of the list only if the values after it are also left out of the list. This includes function bodies for virtual methods (though "= null" or "= otherFunc" may be used as default values for member-functions). Also, default values can be expressions (e.g. the sum of the other values)

(2) Cofunctions are declared as a combination of a struct and a function: "cofunc name { members } (args : returns) { body }", but "{members}" may be left out. They are initialized the same as structs.

(3) Switch-variables may be declared directly, but not "on" other enums (just "switch{X,Y,Z} foo"). Values will be assigned directly by name ("foo=X" rather than "foo=foo.X"). The ":=" operator is not allowed for switch variables, since the initial value can be given directly by name anyway ("switch{X,Y,Z} foo = X"). The compiler will treat these assignments specially, so that "foo=X" does not interfere with some other "X".

(4) "Methods" are only allowed for structs, cofuncs, and interfaces ("single identifier" types), so as to avoid strange dot-expressions on functions and numbers, etc. This does not stop anyone from making a struct containing some other type as a work-around though (since the storage an manipulation would be the same; especially if the member is anonymous)
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on January 23, 2012, 07:21:14 pm
Ok, I've made an update (http://code.google.com/p/opia/wiki/Overview):

 * Anonymous fields DO bring their methods into the containing struct (i.e. they can be used to fulfill interface requirements)

 * Changed "virtual methods" to "method pointers", and altered the syntax from "func blah(...)" to "func(this,...) blah" (so that they just act as special function-pointers). There is also no "declared within" paradigm (i.e. the "with or without a body" thing), though they MAY be given a default value just like anything else (e.g. " ... = func(...) { ... }").

 * Made some minor formatting adjustments with the changes (shortened some examples, but added some others)

I did not mention it in the overview (http://code.google.com/p/opia/wiki/Overview), but bridge-functions will have to be used to map non-initial anonymous fields to their methods when they are used with interfaces.
Title: Re: OPIA - A full OOP language for z80
Post by: NanoWar on January 27, 2012, 05:48:46 am
Rather than getting bombed with your short brainstormed ideas you post here every week, I would love to see how you manage to provide basic functionality like any assembler (flow control, primitive data types, ...). I'm just getting lost in you project when I see "func(this,...) blah" all over. I might have gotten this wrong, but to me it seems too big of a project to master on your own.

Write a pong game in OPIA for TI84+, that would be a good starter to get people's interest (as you can see, barely anybody replies to your posts here, but this should change eventually).

I am however hugely impressed by this project, I just don't see it very clear. Do you have a feature breakdown? I dont want to browse your overview (http://code.google.com/p/opia/wiki/Overview) that you link to in every post ;) .

Keep up your work.
Title: Re: OPIA - A full OOP language for z80
Post by: DJ Omnimaga on January 27, 2012, 10:15:21 pm
(as you can see, barely anybody replies to your posts here, but this should change eventually).
I think it's more due to the post lenght. A lot of people tend to be busy, have troubles following long text or in Omnimaga case, have language barrier to overcome. There are also the ones who are lazier or are not as tech-savy and can't help as much. As a result, they go TL;DR on the posts. Those that do will usually skim through them and do short replies.

When Iambian posted Escheron: Shadow Over Rangaroth RPG updates, unless his post included a screenshot, he rarely got any reply because his posts were too long, even though it had grayscale graphics and lots of features.

That said I myself would like to see the language in action eventually, even if just small programs.
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on January 27, 2012, 10:46:35 pm
Since I am still developing it, I use my Overview to lay out every single aspect (in detail) as a representation of what I have so far (that way, none of it just becomes lost thought) ... I've been working on designing a language since 2004 now (that means tons of research and experimentation). This is going to be the language that I've meant for previous attempts to be, and much more ... Trust me, I'm being thorough because I know what it takes; not because I'm crapping out ideas left and right (though I started there) :)

These posts are a way for people to see my thoughts as I design this, and contribute responses (e.g. intelligent opinions about what is/isn't useful/understandable/etc.). This is helpful because I hope to offer a dimension of z80 Calc programming not yet realized. However, I understand that my examples are too abstract for most people (focusing more on intricacies than realistic usage, because THOSE are the details I have yet to polish up). ... The purpose of my discussion is not so much to discuss how to use OPIA, but to discuss compiler/language design/theory directly, with OPIA being a realization of that design. Some of it is very dry and lacking explanation because I figure that people can look at the (constantly updated) overview to reference what I mean (that is partially the point of the overview right now).

However, I am SO close to having it all set, so I will try to wrap it up. Hopefully you'll see more coding being done soon (on the compiler, I mean; it currently only has some very foundational stuff). As I have more testable stuff, then perhaps I can focus more on giving people something that actually DOES something (and yes, example programs like PONG or something). I do apologize for all the convoluted code; I've been hammering out intricacies rather than trying to provide realistic examples. I figure that the overview provides all details, but is not meant to teach people how to program (so it's very dry) ... I realize that the lack of useful examples makes it difficult though, so maybe I will have to do better at that :P ... I kinda like the overview to be cut and dry though, since it's meant to be "THE" language definition. Perhaps I can make some tutorials/examples/etc. as things progress though.

By the way, there has been responses and discussion on some of these topics (especially anonymous fields) on other sites. I post it all everywhere though so that nobody is left out from knowing what is being discussed or changed. I will stop posting links everywhere though (I had my reasons; but now I have reason not to, thanks).
Title: Re: OPIA - A full OOP language for z80
Post by: NanoWar on January 29, 2012, 08:28:13 am
Hey I didn't expect some good comments on my *rant*, very cool (constructive post, Mr DJO!).

What I wanted to get across is that if you provided simple approaches to OPIA more people (programmers, unfamiliar with compiler theory) would join the conversation. I would say that community support and help is the key requirement to finish such a huge project, as you can see with Axe. Axe in particular was build from the view of the users, the programmers. OPIA looks like a language build from fewer people and from a more theoretical point of view, which is just different.

I dont know with techniques other people would *like* to use for programming TI calculators, but asking them to participate in building a language sounds very good to me. How many people know your ideas from 2004?

Cemetech is more with you I guess, since they are techies :P, but omnimaga for example is a game oriented community (isn't it?) and showing Pong in OPIA would raise my attention enormously, and maybe other's too. Furthermore, good luck.
Title: Re: OPIA - A full OOP language for z80
Post by: Nick on January 29, 2012, 08:38:00 am
that's true, certainly..  if you would keep your post to the point (in lists or so, instead of sentencces) it will be read more, and examples of games or other programs (simple ones though) would be greatly appreciated, and would get much more attention, since this is the point of omnimage i think..
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on January 30, 2012, 01:57:52 am
Thanks for clarifying (I just thought that Omnimaga & Cemetech were just different sites, though both more communal that ticalc.org). I think that your suggestions would do me/OPIA well when it is ready to present. However, it's not ready to say "here it is!" ... but in announcing that it is upcoming, or allowing other to participate in the design (or discussion thereof), it would be beneficial to make it more readable / visual / involved / etc. Let me take just ONE paragraph to explain why this has not been much of the case yet (and then I will explain where/when this will come into play more):

The reason that my approach is so different from that of Axe (etc.) is that it is NOT a bunch of features crammed together. I have done my best to analyze features for their power, efficiency, usability, etc., doing my best not to include anything just because it looks nice or is familiar, etc. ... I am using strong principles of programming language and compiler theory to design a language that is as simple, expressive, powerful, understandable, and unrestricted as possible (which means "Ooh, can you put X into the language? I like X" has less sway than all those other factors). For example (skip rest of paragraph if you don't want one), questions about closures and coroutines led me to consider their necessity versus other techniques versus efficiency. Upon finding that they require the same internal mechanisms, I provided the "cofunc" as a clean and efficient way to do either, removing some of the headache and overlap that either present in their typical usage.

WHEN THE LANGUAGE IS IN PLACE (and at least on its WAY to being developed [e.g. the design already resolved]), then the language will need a LOT of contribution! Unlike Axe & Grammer, OPIA will NOT have any functions or libraries built into it. Using the core language, libraries (for graphics, input/output, math, OS calls, etc.) be written to extend the language by (1) tying directly into other tools/OS's, (2) providing direct access to other assembly resources, (3) embedding (hiding) assembly code into functions, or (4) using pure OPIA code to design new constructs, tools, etc. One is NOT required to know anything of assembly in order to use OPIA, since such integration techniques are only provided so that it CAN tie directly into other already existing tools (no matter where they came from). When I can provide something which can generate runnable code, I will provide some basic functionality for printing etc.; but I intend to involve as many people as want to participate when it comes time to come up with some sort of standard(s) and/or write some of the libraries that people are going to want. THIS is where people can be actively and freely involved in developing the language (through expansion) ... I, however, will design the core language (which I am mostly done with anyway). I will most certainly need to provide some more friendly documentation.

So far, I've decided that posting updates and opening things up for discussion is better than just doing it in the dark, since (1) I can get meaningful feedback from anyone willing to discuss internal theory/design, (2) perhaps I can find what would/would not be "acceptable" for people wanting to use the language, (3) people can see active design and get an idea for what is to come, while (4) building up a larger group of followers who will be anxious to help test it and develop the language further :)

EDIT: Perhaps I will provide some better examples before then though, so people can see what it would look like etc.
Title: Re: OPIA - A full OOP language for z80
Post by: BlakPilar on January 30, 2012, 07:06:31 am
I know I'm coming in late to this (I didn't get the emails for some reason), but NanoWar, this isn't completely done. He wanted to get his ideas out there and see if they were something that people would use. If not, then he would have to change certain aspects of the language. I know how hard it is to structure a language in a way that is practical while still being fun (see Alpha.NET in my signature). That being said, it's not as simple as "just [writing] a pong game" for an incomplete language project ;) I do agree with you, however, that Omnimaga is more game-oriented while Cemetech is more hardware-/technology-oriented (though I do not frequent there as often as here).
Title: Re: OPIA - A full OOP language for z80
Post by: Scipi on January 30, 2012, 03:46:33 pm
Hmm. I'd rather see what an actual programs source code would look like with what is done with OPIA thus far than an actual executable. That way, I think more programmers would be able to suggest what seems simple and what might be over complicated, and so on.
Title: Re: OPIA - A full OOP language for z80
Post by: BlakPilar on January 30, 2012, 04:00:33 pm
Well, I know it's not a full program structure, but shkaboinka has examples of all of the features on the wiki overview (http://code.google.com/p/opia/wiki/Overview).
Title: Re: OPIA - A full OOP language for z80
Post by: Quigibo on January 30, 2012, 04:52:13 pm
There are advantages and disadvantages of both design techniques.  Certainly by spending more time engineering a well thought-out syntax you end up with a more consistent language.  There are definitely several areas of Axe that I wish I had planned out more before it became too late to change such as Boolean operators, function call syntax, variable referencing, and even token choice.  You do however get the advantage of instant feedback by releasing earlier, not from a feature standpoint, but from an efficiency/trade-off one.

I think the best thing to at least build the parse tree part of the compiler (without releasing it) and add the features you have designed so far.  If you're programming it correctly in a massively inheritable object oriented way, this should be extremely easy to add and remove features at around the same speed you can come up with them on paper.  It also allows you to program in your language and get a feeling for how the actual flow will end up in the parse tree.  Just a suggestion :)
Title: Re: OPIA - A full OOP language for z80
Post by: BlakPilar on January 30, 2012, 04:58:07 pm
I think the best thing to at least build the parse tree part of the compiler (without releasing it) and add the features you have designed so far.  If you're programming it correctly in a massively inheritable object oriented way, this should be extremely easy to add and remove features at around the same speed you can come up with them on paper.

I completely agree. This is exactly what I'm doing with Alpha.NET, though I haven't had much time to work on it lately. From what I do have done, though, trees are much easier to navigate, parse, and optimize than arrays or lists.
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on January 31, 2012, 04:59:26 am
Quigibo: I've had a few premature run-throughs with compilers before. Last time, I went through and changed some key rules which really affected parsing and verification rules for classes & interfaces. I do have a couple aspects already in place; However, the new design is free of MUCH of that red tape (since it lacks a type-hierarchy), so I might be able to put more up sooner (school etc. permitting)

BlakPilar: There will be a Tokenizer, Preprocessor, and a Parse-Tree (which indeed makes it worlds easier to parse and optimize. I will go a step further by tracing values across variables and allowing things to be marked as "interpreted"). Each will be modularized so that other tools can use them the compiler itself to analyze code at different levels. This compiler will NOT be tied into a GUI, but will allow optional arguments to specify file-paths, extra files to include, and which environment to use. Allowing these as compiler arguments means that they don't HAVE to be present in the source code (e.g. so that other tools/editors can organize things however they like, and then pass that information on to the compiler).

[General]: I want to reemphasize that OPIA is not "better" than other languages, though I do intend for it to be the most versatile and (computationally) powerful. I do this by carefully choosing flexible and efficient mechanisms necessary to make the language "limitless", while making the design as simple as possible. Unlike Axe or Grammer, OPIA does not offer a fully integrated environment with most of the tools you need to make a game; but OPIA is extensible to allow such things to be coded-in/linked-in so as to seamlessly integrate directly with/into any environment (and that is where people can contribute)!
Title: Re: OPIA - A full OOP language for z80
Post by: Quigibo on January 31, 2012, 10:18:10 pm
Quigibo: I've had a few premature run-throughs with compilers before. Last time, I went through and changed some key rules which really affected parsing and verification rules for classes & interfaces. I do have a couple aspects already in place; However, the new design is free of MUCH of that red tape (since it lacks a type-hierarchy), so I might be able to put more up sooner (school etc. permitting)

How are you creating the parser?  Changing rules should be simply a matter of changing a line or so of code.  When I wrote my python compiler, it was programmed as an LR parser using Bison as my Parser-Generator.  You simply tell it the rules line by line and it generates an abstract syntax tree from any source or gives an error if it cannot match.  Here is an example of what rules look like for a simple language:

Code: [Select]
input:
      expr TOKEN_SEMICOLON

expr:
      expr TOKEN_PLUS expr
    | expr TOKEN_MULTIPLY expr
    | var TOKEN_ASSIGN expr
    | var

var:
      char
    | char var

char:
      TOKEN_A
    | TOKEN_B
    etc.

Changing a rule should be very very easy in Bison, even extreme changes!  Again, I'm not sure what method you're using, but if you're doing recursive decent or some other inefficient method, I would recommend switching because a compiler-compiler will produce code that is faster and more accurate than a human would write, and its way easier.
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on February 01, 2012, 02:39:23 am
Those tools certainly make stable and effective parsers; but I've seen the code for some of them (I do not recall which), and it looked very generated ... I prefer to do it on my own for the same reason that some people prefer to code in assembly. Sure those tools make it a lot easier and are already proven to work perfectly, but I don't think that necessarily makes them "better". Thought it is ridiculous code everything from scratch when the tools are already provided and proven; but being able to master those techniques means that you know when it might be better to make a custom version yourself (e.g I use my own LinkedList class because I found that java.util.LinkedList concatenates lists by converting them to arrays first!). Also, sometimes its better to have a custom structure that has all the general purpose features removed or works as needed without having extra layers ... but lets just settle on that I am doing it all manually because that's part of what makes it mine. And trust me, I know what it takes (experience and research) to make a solid parser & compiler, and how to do it efficiently (e.g. recursive decent, predefined Tokens with flags marking precomputed aspects, good parse-tree constructs, and keeping things modular). ... If anyone can do it, I can. I want to DO this.

The "change in grammar" from before was also a big change in the semantics of the grammar. The language was also particular about what could be contained where (e.g. whether classes, functions, etc. were abstract, virtual, static, etc.). After it was parsed, I also had to check for integrity between classes in regards to inheritance (things that had to be consistent or exclusive, etc.). This is also a sign that the grammar was not of a simple form ... which is one of many reasons that I like the Go-ish style much better than the C++/C#/Java style for a polymorphic language (especially one geared to such a low-level!) :)
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on February 02, 2012, 06:41:31 am
I discovered something fundamentally wrong with how I present "confuncs" in my language: They are METHODS! ... In other words, I cannot just embed a function-call at the start and say it acts like a function. Therefor, I propose a new scheme which allows cofuncs to act as embedded-methods of a struct:

Code: [Select]
struct S {
   byte x;
   cofunc f(...) { ... } // f and g may contain yields
   cofunc g(...) { ... } // f and g have access to each other and x
}

s := S{1};
s.f(...);
s.g(...);

And there is a short form as well:

Code: [Select]
struct T { cofunc(...) { ... } } // the cofunc is an anonymous field of T
cofunc T(...) { ... } // This is a shorthand for the same thing above

t := T{};
t();

The benefits of this approach:
 - A struct may embed multiple cofuncs like this (anonymous ones referred to as ".cofunc")
 - These cofuncs count as methods (and are thus compatible with function-pointers and interfaces)
 - These cofuncs may call each other or access other members of the struct (they "are" the struct)

On a side note, would it be nice to have ".x" be a shorthand for "this.x"?
Title: Re: OPIA - A full OOP language for z80
Post by: BlakPilar on February 02, 2012, 03:00:32 pm
It all seems well and good to me, but could you explain the last two lines of the example to me? (The shorthand and the one below it.) I don't quite understand them.

As for the .foo() or whatever being shorthand for this.foo(), I think that's a great idea.
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on February 03, 2012, 01:33:44 am
EDIT: I am going to change the form a bit to be closer to how it was before (i.e. still use the "cofunc" keyword). I am going to update the overview to reflect this, and modify this (and previous posts) to reflect it. TO ANSWER THE QUESTION (with modifications applied):

Code: [Select]
cofunc T(byte x : byte) { // THIS SHORT-HAND FORM...
   for(byte last = 0; true; last += x) {
      yield last;
   }
}

struct T { // ...REALLY MEANS THIS
   cofunc(byte x : byte) {
      for(byte last = 0; true; last += x) {
         yield last;
      }
   }
}

t := T{}; // make a T variable
t(1); // 0+1 = 1
t(2); // 1+2 = 3

You can also name cofuncs, and have multiple of them in one struct:

Code: [Select]
struct Foo {
   byte x;
   cofunc f(byte y) { ... }
   cofunc g(char c) { ... }
}

f := Foo{1}; // x
f.f(2); // y
f.g('H'); // c

Embedding cofunc-definitions in a struct causes the struct to store the data needed to allow "yield" commands to work (i.e. local variables [like "last"], and the point of execution to continue from after the yield). In this case, the cofunc is anonymous (has no name), hence "t(1)" in the first part versus f.f(2) in the second.
Title: Re: OPIA - A full OOP language for z80
Post by: BlakPilar on February 03, 2012, 10:41:58 pm
Ahh, okay, now I get it. Now, will func still be valid, or is it just cofunc? EDIT: Nevermind ;D
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on February 04, 2012, 01:39:54 am
BlakPilar: Just to be very clear on what's what and usage:

Code: [Select]
struct S {
   func fp(byte); // function-pointer
   func mp(this, byte); // method-pointer (caller is passed to "this" automatically)
   cofunc cf(byte x) { ... } // member cofunc ("this" is implied)
   // NOTE: cf is NOT directly modifiable (it changes after each 'yield')
}

func f(*S, byte x) { ... } // non-member function
func S.m(byte x) { ... } // non-member method

s := S{f,m}; // cf is not in the list (not a pointer)

// To show that they are all of type func(*S,byte):
s.fp = s.mp = f; // all point to f
s.fp = s.mp = S.m; // all point to S.m
s.fp = s.mp = s.cf; // ... (Yes, even the cofunc!)

// To show how call syntax differs:
s.fp(s,5); // pass an *S directly (does not have to be s!)
s.mp(5); // s is automatically as "this"
s.cf(5); // s is automatically passed as "this"

NOTE: cofuncs cause the containing struct to contain a tail-call to the underlying function (and any other data needed to be saved between 'yield' commands). However, the containing struct is passed as "this" (rather than just the cofunc itself). This allows the cofunc to access the other members of the struct (i.e. the implication of declaring a cofunc WITHIN a struct is that you are giving a function-behavior the actual STRUCT rather than to some separate cofunc WITHIN the struct). You COULD declare a cofunc separately and then have a struct contain one, but then the cofunc takes a reference to itself rather than the struct:

Code: [Select]
cofunc CF(byte x) { ... } // cannot access y in there
struct S { byte y; CF cf; }
s := S{5,CF{}};
s.cf(5);
ptr := s.cf; // ptr is a func(*CF, byte), rather than a func(*S,byte)
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on February 14, 2012, 02:32:03 am
A few days ago, I made a post (elsewhere) re-debating the syntax for using & declaring arrays and pointers; but I take it back (post deleted)! :) ... I was about to replace it with a post asking opinions on whether to use standard order (e.g. {*a[j]} is resolved to either {(*a)[j]} or {*(a[j])} depending on the datatype); but I just answered that question by myself when I realized that OPIA inserts derferences etc. automatically if the context is clear. This means that {a*[j]} can be shortened to {a[j]}, assuming that "a" is a pointer to an array so that the compiler would know that the "*" is implied. The reasons for not allowing "*" to be in front and "[]" to be in back (even though the compiler could determine the correct order of evaluation from the type) is the following: since {a*[j]*} can be shortened to {a[j]*}, then the other form would have to mean that {**a[j]} can be shortened to {*a[j]}, which means that something like {*a[j] = *b[k]} would could be ambiguous!!

If all that is confusing, then just consider this a recap on the syntax for array & pointer declaration/usage:
Code: [Select]
*[]byte x; // pointer to array of bytes
[]*byte y; // array of pointers to byte
byte b;

x[i] = b; // short for x*[i] = b;
y[i] = b; // short for y[i] = &b;
y[i]* = b; // no shorthand

b = x[i]; // short for b = x*[i];
b = y[i]; // short for b = y[i]*;
The rule is to FIRST insert derferences "*" so that array-indexing "[]" (and dot ".") makes sense (thus {x[j]} is ALWAYS {x*[j]}), and SECONDLY to make the right-side suitable for the left side. The only issue with this it creates asymmetry (note the differences between {y[j] = b} and {b = y[j]}). This is not fixable because {&b = ...} is illegal anyway, and I'm set about having assignment-to-pointer always give an address (plus it allows values to be passed "by reference" more transparently).
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on February 16, 2012, 12:15:02 am
To make my point about what I am about to propose, first look at each construct to see if its obvious enough what each would mean:

Code: [Select]
for { ... }

for(test) { ... }

for(init; test; next) { ... }

for(var : a, b) { ... }

for(var : a, b, i) { ... }

for(var : arr) { ... }

for(num) { ... }

What I am proposing is to just use "for" for every kind of loop ("loop" didn't look as good, and "repeat" feels like the weird cousin of "while"). The idea is that there are fewer keywords, and the context would be easy enough anyway. The answers are (smashed together here so that people can guess first):
while(true) { ... }
while(test) { ... }
init; while(test) { ... next; }
for(var = a; var < b; var++) { ... }
for(var = a; var < b; var += i) { ... }
for(ix = 0; ix < size; ix++) { var = arr[ix]; ... }
for(blah = number; blah > 0; blah--) { ... } // uses DJNZ
Of course, I could throw out the last one if that's going a bit far (and I'd probably implement some of these only once everything else is in place), but I wanted to include several examples to make my point :)

...Opinions on this? (i.e. instead of having while/until/etc.)
Title: Re: OPIA - A full OOP language for z80
Post by: DJ Omnimaga on February 16, 2012, 12:20:21 am
Hmm, I'M unsure if it's a good idea, because most people are used to having while/repeat or do/loop, along with For, and for them, being forced to always use For might be a major hassle. Also what is "arr"?
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on February 16, 2012, 05:11:16 am
You are probably right. One reason I liked it (other than that Go uses it) is that the infinite loop is just "loop { ... }", but without another keyword. Otherwise "while(true) { ... }" is easily detectable. "Arr" is some array variable. In other languages this sometimes looks like "foreach(var in arr)" (I used shortened names so as to not totally give away stuff; but perhaps people have seen that mechanism, or perhaps the code itself would make it clear enough). I do think that perhaps a version of the "for" that mirrors TI-BASIC could coexist and make some code easier to write (e.g. "for(x,1,10)" versus "for(x=1;x<=10;x++)"). To keep things simple, the for is also used for "foreach" loops in some languages; and with that, I figured that allowing it to have just a condition (or perhaps have nothing to signify a "forever" loop) would not be much of a stretch ... but I admit that things like "while" and "do while" read much better.

I can stick with the standard setup, but perhaps keep extra options for "for":

Code: [Select]
while(c) { ... } // loop while c is true
until(c) { ... } // loop until c is true
do { ... } while(c); // do ... and then repeat while c is true
do { ... } until(c); // do ... and then repeat until c is true
do { ... } // do "forever" (useful)
for(init; test; update) { ... } // C++/Java/C# "for"
for(var, start, end, inc) { ... } // BASIC "for" (optional "inc")
for(var : array) { ... } // "foreach" (probably added in later); possibly also
// work with funcs/cofuncs where the last of the return-values is a bool

One thing I would like to provide is a way to start a loop in the middle somewhere to avoid having to use duplicate code before the loop and within the loop (trust me, everybody runs into this sooner or later):

Code: [Select]
// "A" (a large chunk of code) is duplicated to do this:
A;
while(C) {
   B;
   A;
}

// My solution (just as it reads, i.e. begin at label "start"):
do(start) {
   B;
start:
   A;
} while(C); // ...but repeat the WHOLE loop "while C" is true

// A common solution (but requiring "loop manipulation"):
do { A; if(!C){break;} B; } // !C is evil
Title: Re: OPIA - A full OOP language for z80
Post by: Quigibo on February 16, 2012, 05:15:27 am
A "do" without a "while" is a common way to infinite loop in a clean syntax:  "do { ... }".  I forgot if C supports this or not, but I have definitely seen it in some dialects of Basic.

EDIT: Nevermind, I missed that you already suggested it :)
Title: Re: OPIA - A full OOP language for z80
Post by: BlakPilar on February 16, 2012, 07:18:06 am
I agree with DJ on this one. Using "for" as the keyword for every kind of loop would get too confusing, especially for people who use whiles or do...whiles a lot. Personally I favor for loops, but the other two do have their uses. You could certainly keep the other options for "for," though. I just think the purpose of certain code would be easier to figure out if the typical words are used.
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on February 16, 2012, 08:50:36 am
Agreed :) (and do-for would be bizarre...). I retract my suggestion about just having "for" ... any opinions about my follow-up comment though? :)
Title: Re: OPIA - A full OOP language for z80
Post by: BlakPilar on February 16, 2012, 11:21:43 am
About starting at a specific space in a loop? I think it's a good idea. If you want to skip the first few lines of code from a loop for the first pass or some other pass it'd be nice. Are labels/goto's allowed outside of loops?
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on February 16, 2012, 12:15:09 pm
No gotos. Instead, I try to provide constructs/commands that should make them unnecessary if you know how to structure your code decently. I do provide labels and labelled-break/continue:

Code: [Select]
foo: while(...) {
   bar: while(...) {
      while(...) {
         break; // break from the innermost loop (or switch)
         continue; // continue the innermost loop (or switch)
         break foo; // break from the "foo" loop (or switch)
         continue bar; // continue (skip to next iteration of) the "bar" loop (or switch)
      }
   }
}

One person suggested that "do goto start { ... }" would be more readable, though personally I prefer to leave that word out of the language. I suggested "do @ start {" or "do start {" ... I like "do start" or "do(start)" because I think it reads well enough (and yeah, you might have to know about this construct in the first place; but that's what it means to know a language. Stuff can be obvious "enough" without having to have a built-in readme I think). ... Nevertheless, opinions?
Title: Re: OPIA - A full OOP language for z80
Post by: BlakPilar on February 16, 2012, 12:46:51 pm
I definitely think there should be some designated way to show that the loop is starting at a label, so "do(start) {...}" or "do @start {...}" is fine with me (though I'd prefer the first way).
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on March 07, 2012, 11:04:17 am
Recent Updates (language/discussion):

Gotos - I determined that you can ALWAYS create structures in place of gotos, so long as the gotos are forward and don't jump "in" (at the very worst, you can use a "do...while(false)" as a container to break from) ... and then I determined that it was cleaner just to allow such gotos. The rules for gotos are that you can only jump foward, within the same function, and never INTO another construct (out of is ok). The "do(start) { .. }" is the only exception, which is provided specifically (see previous posts). You can still "break" and "continue" and even "break foo" or "continue foo"; constructs are labeled just by placing a label before them (though I prefer this to be on the previous line so as not to mess up the indentation and to match the format of other labels).

"Flattened" Hierarchy - I want to prevent programs/source from getting layered by keeping everything (aside from local and member variables) at the top level. This means two things: (1) No "nested" definitions: Entities such as structs, funcs, etc. cannot be defined inside of eachother (with the exception of methods and cofuncs being defined in structs). (2) Namespaces cannot be "nested" (they are declared at the top of the file, like a package declaration); and no more "using" keyword either (shorter namespace names are preferred).

Default values for function arguments - Although it is sort of contrary to parallel assignments, default values are given to function arguments as most people would expect (noting that only the last arguments in a function can have default values):

Code: [Select]
func Foo(byte a, b=2, char x='Y', y='Z') { ... }
Foo(1,2,'a','b'); // Normal usage
Foo(1,2,'a');   // Short for Foo(1,2,'a','Z');
Foo(1,2);     // Short for Foo(1,2,'Y','Z');
Foo(1);     // Short for Foo(1,2,'Y','Z');

Multiple Assignments - Basically, "each(a,b,c)=d;" replaces "a=b=c=d;". This can get complex with lists of values:

Code: [Select]
each(a,b,c) = x; // Instead of (a=b=c=x;)
each(a,b,c),d = x,y; // Instead of (a=b=c=x; d=y;) or (a,_ = b,_ = c,d = x,y;)
NOTE: A more likely case than (...=x,y;) is a function which returns multiple values (...=twoValues();).

Method Declarations - Methods can be declared directly within structs as an alternative to begin declared with "structName." in front (both forms will be valid). I feel that this more compact syntax is easier to read in many cases. Nevertheless, you can use either form, and they mean the same thing:

Code: [Select]
struct Foo { func Bar(...) { ... } } // declared internally
func Foo.Bar(...) { ... } // declared externally

Choosing Explicit Variable Addresses - This is done by placing the "@address" after the variable name. Use a string literal to specify an assembly-coded address, or another variable to share memory (overlap) with. Variables can be declared inside of array literals, though I have not chosen a good syntax yet (that might sound bizarre but it's actually very useful):

Code: [Select]
word cursor@"curcol"; // cursor will refer to "currow" in the assembly code.
byte curCo1@cursor; // curCol now refers to the leading byte of cursor
byte curRow@cursor+1; // refers to the trailing byte of cursor. WE CAN DISCUSS THIS SYNTAX
func() f@"routine"; // f() now calls an assembly routine directly

// Embedding variables within an array:
values := [6]byte{0,1,2,3,4,5};
byte a@values[2]; // a is literally stored at value[2]
byte b@values[3]; // b is literally stored at value[3]
a = 1; // values[2] is now 1;
values[3] = 2; // b is now 2;

// More compact way of embedding variables in an array can be one of these:
values := [6]byte{0, 1, a=2, b=3, 4};
values := [6]byte{0, 1, a@2, b@3, 4};
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on March 22, 2012, 12:31:34 pm
MORE Recent Updates:

After some long discussion (with elfprince13 and merthsoft over on Cemetech), I have decided to make 2 major changes (and to clarify/discuss a third point):

Function Syntax - Function (and function-pointer) declarations have now been changed so that the return value(s) are AFTER the argument-parenthesis, and multiple return values must be grouped by another set of parenthesis. It was decided that this is clearer for single-valued returns, and that multiple returns match the new "tuple" convention anyway (see the next section):

Code: [Select]
func(byte a, b):byte // Takes two bytes (a and b) and returns a byte
func(byte a, b):(byte,byte) // ...Returns TWO bytes
func():char // Takes nothing, returns a char

It was also agreed that more complex functions are easier to read this way. For example, compare the old and new syntaxes for declaring a function which takes an A and a [function which takes a B and returns a C] and returns a [function which takes nothing and returns a (function which takes and returns nothing)]:

Code: [Select]
func(A, func(B : C) : func( : func())) // Old "inner" setup
func(A, func(B) : C) : func() : func() // New "outer" setup

// A simpler example (can you tell what it does by looking?):

func( : func( : func(A : B))) // Old "inner" setup
func() : func() : func(A) : B // New "outer" setup

Tuples (in place of parallel assignment) - ASSIGNMENT IS NO LONGER IN PARALLEL! However, you can still operate on multiple values at once by grouping them together with parenthesis (as a "tuple"). A "tuple" in OPIA will be an abstract representation solely for the purpose of grouping values together (i.e. no tuple-variables: A function would return a "tuple" of values rather than one value which is "a tuple"). Any list of comma-separated values is a "tuple", and a tuple is just a list of values.
 - Assignment (and all else) has precedence over a comma; but parenthesis may be used to group things as normal.
 - A Tuple does not "bind" into a separate entity (i.e. stays "unpacked"). A "tuple within a tuple" is just one larger tuple. The benefit of this rule is simplicity: no "lists of lists" or "packing" to deal with (this also means that if you embed a call to [a function which returns two values] inside of another function call, then it fills two places of the argument list). The main motivation for this is so that (((X))) resolves to X as expected (rather than a tuple-tuple-tuple of X).

Code: [Select]
byte a, b = c, d;     // same as: byte a, (b = c), d;
byte (a, b) = (c, d); // same as: byte a = c, b = d;
byte a = (((b)));     // same as: byte a = b; (as expected)
(a,b,c) = ((x,y),z);  // same as: (a,b,c) = (x,y,z)
(a,b) = ((x,y),z);    // INCORRECT: (x,y) is still TWO items

It has been suggested that I allow "tuples of tuples" so that that "incorrect" example would be valid, by requiring "1-tuples" to be indicated by a comma: "(x,)" is a 1-tuple, while "(x)" is just x in parenthesis ... However, I still fail to see how this would be useful in a static and compiled language (versus it's usefulness in a dynamic and interpreted language like Python).

Interpreted Aspects (aka "This $ business") - The compiler will precompute whatever it can (e.g. so that you can use actual code to embed a computed value), but the $ operator REQUIRES the compiler be able to do this on something (and grants more liberties to do so, such as loop-unrolling). Here is an example:

Code: [Select]
byte a = 5, b = a+7;

if(a+b < 15) { doA(); }
else { doB(); }

while(a < 100) { a += a; }
$while(b < 100) { b += b; }

return $(a+b);

// The compiler precomputes that code, resulting in THIS code:

byte a = 5; // b = 12, but is never DIRECTLY needed, so it is removed

doB(); // 5+12 is clearly not less than 15

while(a < 100) { a += a; } // The compiler leaves loop alone,
// ... unless TOLD ($) to: b=12+12 ...24+24 ...96+96 ... b is 192

return $(a+192); // ERROR! (value of a is unknown; cannot evaluate)

More specifically, "$x" would mean "give me the actual value of x (assuming that you know it)", regardless of how "x" was declared; but declaring "byte $x" has the same effect as putting the $ on each and every occurrence of that "x". The same goes for functions as well (e.g. inline it and require the result to resolve to a determinable value). One of the major points to debate for this case is whether "interpreting" a function can result in some runtime code being left in, even if it the resulting value can be determined at compile time. I'm leaning on having it be strict, since a simple function ought to be automatically inlined anyway, so I don't mind letting people just assume that a 1 or 2 statement function would be inlined (unless the compiler decides that it's better not to anyway).
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on March 24, 2012, 06:44:22 pm
*.*EVEN MORE Recent Updates (Note: I had to use "d,e,f" instead of "a,b,c" or "x,y,z" because those turn into tags):

There has been discussion about using an [d,e,f] syntax for multidimensional arrays like in C# (These would be TRULY multidimensional, rather than being arrays of pointers to arrays, etc.). This sparked a lot of possible changes, which I am just going to paste in here:

I'd like to consider something similar for OPIA, but there are some issues that would need addressing if I do: (1) To keep [,] rectangular (versus the jagged [][]), There would have to be a way to embed (or specify) size information (OPIA does not currently do this for native-compatibility reasons). (2) To avoid ambiguity, [d][e] should mean something different than [d,e]. ... Let's look at this step by step so we can decide on a good setup altogether:

Code: [Select]
// Current setup:

[]byte // Points to a byte-array
[5]byte // IS a (static) byte-array (5 values)
[_]byte // Same as above, but size is determined from usage
*[5]byte // Same as []byte, but requires/assumes the underlying array is 5 bytes

[5][5]byte // An array of five [5]byte values (no pointers!)
[5][]byte // (static) Array of five []byte values (five pointers)
[][5]byte // Points to an array of five [5]byte values
[][]byte // Points to an array of pointers to arrays

I could deal with (issue 1) by providing a way to explicitly embed size information at the front of an array:

Code: [Select]
// Hypothetical way to embed size-information:
[byte]byte // A (static) byte-array, prefixed by a byte to store the size
[word]byte // A (static) byte-array, prefixed by a word to store the size
*[byte]byte // Pointer to such an array

I could deal with (issue 2) by making every inner set of square brackets [...] become a pointer (e.g. make [d][e] ALWAYS "jagged" and [d,e] ALWAYS rectangular); and for symmetry, I could have the outermost [...] ONLY be a pointer if the * is used. It would like like this (I will just say "array" for "static array", and "pointer to array" otherwise):

Code: [Select]
[]byte // Array of (some determinable number of) bytes (previously indicated as [_]byte)
[5]byte // Array of 5 bytes
[byte]byte // Array of bytes (prefixed with a byte to indicate the size)

*[]byte // Pointer to an array of bytes
*[5]byte // Pointer to an array of 5 bytes
*[byte]byte // Pointer to a (byte-) size-prefixed array of bytes

[][]byte // Array of *[]byte values.
[5][5]byte // Array of five *[5]byte values.
[5,5]byte // Array of five [5]byte values (no pointers)
[5][5,5]byte // Array of five *[5,5]byte values
[5,5,5,5]byte // A 4-Dimensional array of bytes (no pointers)
[5,5][5,5]byte // 2D array of pointers to [5,5]byte values

This seems all well and good so far ([]T has become *[]T, but [5]*[5]T has also become just [5][5]T, and [5][5]T has become [5,5]T). However, since you cannot even COMPUTE a 2D index without at least knowing the inner-most dimensions of a multidimensional array (since it is all internally stored as a 1D array), you would have to specify (at least some of) the dimensions when working with pointers:

Code: [Select]
[,]byte // Static 2D array (NOTE: the sizes have to be determinable!)
*[,]byte // ERROR! (cannot even COMPUTE where [d,e] is without the inner dimension)
*[,5]byte // Pointer to a [?,5]byte (ok: [d,e] is [5*d+e])
*[,byte]byte // (also ok, since [d,e] is [SIZE*d+e], and size is stored as a leading byte)
*[byte,]byte // ERROR! (It's the inner dimension that matters)
*[5,5]byte // Pointer to a [5,5]byte -- Very ok

I'd be ok with allowing a multidimensional array to be treated as an array with fewer dimensions:

Code: [Select]
[3,4,5]byte arr;
*[3,4,5]byte p3 = &arr; // p3[d,e,f] refers to arr[d,e,f]
*[,5]byte p2 = &arr; // treat arr as a [12,5]byte (e.g. p2[4*d + e, f])
*[]byte p1 = &arr; // treat arr as a [60]byte (e.g. p1[5*4*d + 5*e + f])

// I'd like NOT to allow this:
arr[d] // gives the dth [4,5]byte value
arr[d,e] // gives the [d,e]th [5]byte value
// ... because it means that arr[d][e][f] is the same as arr[d,e,f]
Title: Re: OPIA - A full OOP language for z80
Post by: NanoWar on March 25, 2012, 07:21:42 am
Multi arrays with [] seems like a must.  Instead of touples, can't you just return an array?

Very detailed, as always! :)
Title: Re: OPIA - A full OOP language for z80
Post by: DJ Omnimaga on March 25, 2012, 12:32:50 pm
By the way, even if you make the language similar to standard languages, when this comes out, you should really start writing a good tutorial for it. Preferably make one for people with no coding experience, so that for BASIC coders (the ones usually looking for alternatives) can easily pick up OPIA.
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on March 25, 2012, 09:29:41 pm
Multi arrays with [] seems like a must. Instead of tuples, can't you just return an array?

Multidimensional arrays are awesome :)
...and you could return an array if you really liked...
Code: [Select]
byte (x,y) = foo(1,2);
func foo(byte a, b): (byte,byte) {
   return (m,n);
}

[2]byte xy = bar([2]byte{1,2});
func foo([2]byte ab): [2]byte {
  return [2]{m,n};
}

[1]byte z = boo([1]byte{1});
func boo([1]byte c) {
   return [1]byte{m};
}
...but I think tuples are a worthwhile feature :) (and yes, they are loose enough to be equivalent to a list of function arguments).

By the way, even if you make the language similar to standard languages, when this comes out, you should really start writing a good tutorial for it. Preferably make one for people with no coding experience, so that for BASIC coders (the ones usually looking for alternatives) can easily pick up OPIA.

I try to design everything in the best fashion regardless of other languages; though when I use a feature that other languages have, I try to reflect forms that are common if I can; but sometimes I find "better" forms (the cofunc combines what other languages present as closures and generators/iterators). ... But I definitely plan on focusing on other details after the language and compiler are designed (documentation, tutorials, GUI tools, defining standard libraries. NOTE: These are the things that people can be VERY involved in later on!!) :)
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on March 26, 2012, 09:52:31 am
Ok, here are some bottom lines for arrays that I want to stick with (you can forget what I said so far if this makes it simpler):

(1) The first part of any array (e.g. the [X] part of [X][Y][Z]T) will be static if all of it's dimensions are given; otherwise it will be an array to a pointer:

Code: [Select]
   [5][Y][Z]T // Static array of 5 [Y][Z]T values
   [ ][Y][Z]T // Pointer to array of (some number N of) [Y][Z]T values
 [5,5][Y][Z]T // Static array of 5x5 [Y][Z]T values
 [ ,5][Y][Z]T // Pointer to an array of Nx5 [Y][Z]T values
  *[5][Y][Z]T // Pointer to (because of *) array of 5 [Y][Z]T values
  *[ ][Y][Z]T // Pointer to pointer to array of N [Y][Z]T values

(2) Any pattern of [X][Y][Z] should create a jagged array and [X,Y,Z] should create a rectangular array. This is done by making all "inner" [...] values be pointers -- REGARDLESS of what dimensions are given:

Code: [Select]
   [5][ ]T // Array of 5 (pointer to array of T) values
   [5][5]T // Array of 5 (pointer to array of 5 T) values

(3) "Inner dimensions" (e.g. the x's in [,x]T or [,x,x]T) must be given explicitly (as numbers). I'd LIKE to allow types like [,]T, but it just is not feasible without either providing a clunky mechanism or adding assumptive overhead (which will fail to match native system structures). However, this CAN be done manually as in (4):

(4) Multidimensional arrays (not jagged arrays) can be treated as one dimensional arrays (since that is how they are actually stored). For completeness, I could allow other conversions as well (that is, if you can go from MxN to N, you should be able to go from N to MxN; thus if you can go from LxMxN to N to MxN, you might as well go from LxMxN to MxN, etc.):

Code: [Select]
   [L,M,N]T arr; // An LxMxN array of T values
   [ ,M,N]T p3 = arr; // Pointer to an ?xMxN array (3D)
   [   ,N]T p2 = arr; // Pointer to an ?xN array (2D)
   [     ]T p1 = arr; // Pointer to an (N) array (1D)
   p3[x,y,z] == p2[x*M+y, z] == p1[(x*M+y)*N+z] == arr[x,y,z]
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on April 04, 2012, 12:25:24 pm
I have updated the Overview (http://code.google.com/p/opia/wiki/Overview) to reflect my changes for arrays, tuples, functions, and default arguments.

As for interpreted stuff ($), I think that I want it to always be "deep" (recursive). That is, "$foo(...)" will cause ALL of foo to be interpreted, and "$while(...) { ... }" would cause everything in the loop to be interpreted (including inner constructs). This means that all variables declared within must be determinable, but external variables referenced may be affected at runtime.

The reasons for choosing a "deep" evaluation (versus just that "layer") are that (1) it's easier to mark a section, and (2) this is the more likely use anyway. I'd rather let single layers be optimized by the compiler rather than see people put $'s all over the place where they think that an optimization can occur ... but I do like to allow "Hey, interpret that whole thing ... I just didn't want to compute the values and embed them all by hand".

One other thing: I think I want to replace "const" values with a "final" modifier, on the grounds that a "final" value is actually embedded in the program as an (immutable) variable (e.g. embed "BIG_UGLY_STRING" as a final value, rather than once for EACH time it is used) -- as in Java. As for value-holders, you can use $ to indicate this anyway. How does that sound?
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on April 07, 2012, 09:55:10 pm
THE TIME HAS COME! (the walrus said) ... I have reviewed all comments, topics, posts, etc. all the way back until before I switched the language to a "Go-ish" layout, and I finally feel that OPIA is fully (syntactically and semantically) defined and decided (or at least, as much as it can be before it is coded) -- which I wanted to do before I did anything huge with the compiler.

My plans (when time permits between school, work, moving, and my soon to be first-child) are as follows:

(1) lay out a careful plan for the compiler pipeline/design. This has already been 90% grasped in my head alone (after having poured over compiler books and articles and mental experiments "for fun"), but I have recently re-read most of the chapters in Modern Compiler Implementation In Java (http://www.cs.princeton.edu/~appel/modern/java/) (it's the BEST!), and been charting out a careful comparison of my design versus what everyone else swears by -- and it turns out that I am not deviating terribly much. Expect an analysis and layout of the plan from me in the future (I have it mostly set).

(2) Update the Language Overview (http://code.google.com/p/opia/wiki/Overview) as much as I see fit (I don't want to be too picky with it, but I do want to make sure that every aspect is well documented so nothing falls through the cracks).

(3) Jump into the coding. I will keep everyone updated as that progresses. The exciting thing is that I will release it in modules, so that you can see everything up to the tokenizing & preprocessing (this is it's current state, though I may rework that a bit to be SLIGHTLY more modular), parsing/tree-building, etc. Every aspect of the pipeline will be explained, as in (1).

Anyone is welcome to ask questions about anything they think is lacking or confusing, and I am still open to considering some changes/additions; but I don't foresee anything that would change the language enough to put of coding it now.

Side note: as for interpreted aspects, the default will be to precompute as much as possible without unraveling loops or recursive calls (unless the contents clearly have no runtime side-effects), and that the $ operator will be "deep"/recursive, causing a thing (and ALL of it's contents, except for references to externally defined entities) to be fully precomputed.
Title: Re: OPIA - A full OOP language for z80
Post by: DJ Omnimaga on April 07, 2012, 10:44:36 pm
Question, will the language allow people to be a bit loose on the syntax or will it be extremely picky, like when you forget a ; in some languages or more like when you forget to close a parhentesis in TI-83+ BASIC?
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on April 08, 2012, 01:39:38 am
Well, you can put as many spaces and tabs where-ever you want :)
Sorry, TI-BASIC is one of very few languages I know of which is that "loose"; though I might consider whether or not I really need to require semicolons -- there were places where they were necessary, but I'll look at it again. I am going to have it give very nice error messages (specific, location, and give lots of error messages rather than just quit).
Title: Re: OPIA - A full OOP language for z80
Post by: DJ Omnimaga on April 08, 2012, 07:15:45 pm
Ok. I was just wondering, because it's not a good idea if a language is too loose, since it makes it harder to find errors, as the coder gets weird errors for absolute no reason. However there are some languages, not necessarily programming, that were just way too picky, such as PHP, where one single unnoticeable typo would always cause a syntax error or something.
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on April 12, 2012, 05:08:26 pm
Some final notes before I begin in (May or June?). THESE ARE DECIDED (tentatively):

The new numeric datatypes are byte, sbyte, int, and uint.

String literals can take on different forms:
::: "null terminated string"
::: b"byte-prefixed string"
::: i"int-prefixed string"
::: r"raw string"

Numeric literals are of type "int" by default. Type-casts can be used to be explicit: (byte)5;
Hexadecimal and Binary literals are prefixes with 0x and 0b, respectively, and default to type "byte" or "uint" types according to the number of digits used (so as to reflect a literal bit representation).

Dereferencing is now on the right-side:
::: *[]byte pa;    (*pa)[idx];
::: []*byte ap;    *(ap[idx]); // or just *ap[idx]

Constant (immutable) variables are defined with "const" in addition to the datatype.
Constant expressions (pasted in like macros) are defined with "const" alone.
It is illegal to mix "const" or "volatile" with the ":=" operator.

There are standard-, BASIC-, and iterator-style for-loops:
::: for(init; condition; update)
::: for(var: start, end, inc) (inc is optional)
::: for(var: array); for(var: someYieldyCofunc)

The inferred type of an array literal works as follows:
::: []T{...} = A static array of the given values
::: &[]T{...} = Pointer to the given static array
::: new [n]T = Pointer to a new (uninitialized) array allocation
::: new []T{...} = Pointer to a new array allocation (values copied from static array)

Arrays with the (first) dimension omitted ([]T or [,n]T) are pointers.
Arrays of the form [ , ,...] are rectangular (stored in one static allocation).
Arrays of the form [][][]... are jagged (the "inner" arrays are stored as pointers).
Arr[3..6] is a shorthand for the tuple expression (Arr[3], Arr[4], Arr[5]).
Tuples will remain "auto-unpacked", and no tuple-variables allowed.

Method receivers ("this") are ALWAYS (intrinsic) pointers.

Methods may be defined within structs, just as in Java/C# (compact/familiar).

There will be an "x@value" syntax for embedding variables within array literals.

Addressing goes on the LHS and applies to the whole RHS (e.g. &a[n] is &(a[n])).

Entities may not be defined within each other (e.g. no structs within structs, etc.).

Expressions cannot contain statements (declarations, assignments, calls, var++/var--).

Anonymous functions may may not refer to (non- static/const) external local variables.

All code is precomputed as much as possible (without unrolling loops or recursive calls).

The $ operator Requires something to be interpreted, including loops and recursive calls.

Bridge methods will be inserted for multiple "inheritance" of anonymous fields, as needed.

Control-flow constructs will indeed require parenthesis (avoids parsing conflicts with literals).

No "static" members of anything (but static local vars and static initialization blocks are allowed).

Entites Have Global Accessibility If They Are Capitalized, and namespace accessibility otherwise.

Look-Up-Tables (rather than Jump Tables) will be used with switches and if-else chains as possible.

Methods can only be defined for "identifier" types (structs, primitives, etc., but not funcs, arrays, etc.).

Namespaces may be nested ("Outer.Inner" syntax), and there will be a "using Namespace" mechanism.

Self-Modifying code will be used with cofuncs and switch-variables (Will consider an option to disable it).

Explicit variable addresses can be nominal (@"address") or refer to another variable (@x or @arr[n].foo).

No exception-handling or "try-catch" mechanism (use multiple return values or create an "Exit()" instead).

Type-casts will be represented traditionally (e.g. "(byte)(a+b)").

"Extra" Parenthesis are not allowed within datatypes ("func(...)" requires them, but []*T are *[]T are unambiguous).

Function pointers without any return values may point to functions with return values (e.g. func(byte) pointing to func(byte):byte).

Values will be passed/returned in registers such that any two functions with the same pattern of arguments will use the same registers for them.

Default arguments (and struct members) must come last, and will be embedded in functions so they can be pointed-to as their reduced versions.

An anonymous (nameless) struct/interface/cofunc/func within a namespace will take on the name of the namespace (e.g. "List myList" rather than "ListNameSpace.ListStruct myList"). This also gives namespace values ("List.staticValue") the feel of Java/C#'s static class members.
Title: Re: OPIA - A full OOP language for z80
Post by: aeTIos on April 12, 2012, 09:01:42 pm
woah at first i was like tldr but the content is pretty impressive :D
Really waiting for this, pity that you cannot work on it till may.
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on April 16, 2012, 03:40:19 pm
I just want to note that I've been updating/revising that list in my previous post (as well as cleaning it up and making it MORE READABLE) ... Any opinions?
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on April 21, 2012, 03:56:59 pm
I am considering the possibility of having OPIA build for various platforms (z80, 68k, whatever the NSpire and CSX are), so I need to design with that option in mind (your input would greatly help; keep reading). This most directly affects datatypes:

One option would be to use the standard byte, short, int, long types (8, 16, 32, 64 bits). The up side is that type-sizes would be consistent across platforms. The down side is that it would feel goofy using "shorts" (and "bytes") for z80, and using other types from other platforms.

The option I'm considering is to just use "byte" and "int", with "int" being whatever the "word size" is. Type sizes would not be consistent, but each processor is probably best suited to work with it's word-sized ints anyway.

I don't know if I will actually make it for more than just the z80, but I do want to design so that this could happen easily and without affecting how the language is defined. IT WOULD HELP TREMENDOUSLY IF ANYONE COULD TELL ME WHAT SIZES OF VALUES THE DIFFERENT PROCESSORS WORK WITH, AND THE LIMITATIONS OF EACH (68k, nspire, casio) (e.g. the z80 works best with 8-bit values, but has a 16-bit word size and can work with them as well; though some operations require multiple instructions). ... I just want to be able to make informed decisions :)
Title: Re: OPIA - A full OOP language for z80
Post by: aeTIos on April 25, 2012, 06:47:12 am
You know the stuff for teh z80 no?
Title: Re: OPIA - A full OOP language for z80
Post by: jsj795 on April 25, 2012, 07:25:58 am
sadly I'm pretty clueless when it comes to these stuff x.x
But I do plan on learning C++ and when I do, I can probably code in OPIA since it looks really similar! :D

Anyways, great job so far
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on May 09, 2012, 08:37:32 pm
Ok, how is this setup for datatypes and literals?

byte, char, bool: unsigned 8-bit values
sbyte: signed 8-bit values
int: signed 16-bit values
uint: unsigned 16-bit values

Numeric Literals would be resolved (by default) as follows:
55: int
(55i: int)
55u: uint
55b: byte
55s: sbyte

Hexadecimal and Binary literals would depend on the number of digits for how it resolves (by default), but explicit indicators can be used as well:
0x1: byte (1 or 2 digits)
0x001: uint (3 or 4 digits)
0x001b: byte (b indicator)
0x1i: int (i indicator)

0b1: byte (8 or less digits)
0b000000001: uint (8+ digits)
0b1u uint (u indicator)

...Note that those are DEFAULT evaluations (e.g. "X := 5" makes X an int); but a clear context may result in a different type (e.g. perhaps the compiler can tell that looping from 1 to 10 only needs a byte).

For string literals:
"null terminated string"
r"raw string literal"
b"byte-prefixed string"
u"uint-prefixed string"

... How does that all sound?
Title: Re: OPIA - A full OOP language for z80
Post by: BlakPilar on May 09, 2012, 08:54:49 pm
By byte- and uint-prefixed strings, do you mean that number would be the length of the string?
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on May 09, 2012, 09:28:16 pm
By byte- and uint-prefixed strings, do you mean that number would be the length of the string?

Correct:
"banana" // .db "banana",0
r"banana" // .db "banana"
b"banana" // .db 6,"banana"
i"banana" // .db 6,0,"banana" ;z80 is "Little-Endian"
Title: Re: OPIA - A full OOP language for z80
Post by: BlakPilar on May 09, 2012, 09:39:19 pm
Alright, that's what I thought. Everything seems good to me!
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on May 26, 2012, 12:10:24 am
Ok, I've basically finalized all the (more than very trivial) language issues ... I am just going to repost:

Some final notes before I begin in (May or June?). THESE ARE DECIDED (tentatively):

The new numeric datatypes are byte, sbyte, int, and uint.

String literals can take on different forms:
::: "null terminated string"
::: b"byte-prefixed string"
::: i"int-prefixed string"
::: r"raw string"

Numeric literals are of type "int" by default. Type-casts can be used to be explicit: (byte)5;
Hexadecimal and Binary literals are prefixes with 0x and 0b, respectively, and default to type "byte" or "uint" types according to the number of digits used (so as to reflect a literal bit representation).

Dereferencing is now on the right-side:
::: *[]byte pa;    (*pa)[idx];
::: []*byte ap;    *(ap[idx]); // or just *ap[idx]

Constant (immutable) variables are defined with "const" in addition to the datatype.
Constant expressions (pasted in like macros) are defined with "const" alone.
It is illegal to mix "const" or "volatile" with the ":=" operator.

There are standard-, BASIC-, and iterator-style for-loops:
::: for(init; condition; update)
::: for(var: start, end, inc) (inc is optional)
::: for(var: array); for(var: someYieldyCofunc)

The inferred type of an array literal works as follows:
::: []T{...} = A static array of the given values
::: &[]T{...} = Pointer to the given static array
::: new [n]T = Pointer to a new (uninitialized) array allocation
::: new []T{...} = Pointer to a new array allocation (values copied from static array)

Arrays with the (first) dimension omitted ([]T or [,n]T) are pointers.
Arrays of the form [ , ,...] are rectangular (stored in one static allocation).
Arrays of the form [][][]... are jagged (the "inner" arrays are stored as pointers).
Arr[3..6] is a shorthand for the tuple expression (Arr[3], Arr[4], Arr[5]).
Tuples will remain "auto-unpacked", and no tuple-variables allowed.

Method receivers ("this") are ALWAYS (intrinsic) pointers.

Methods may be defined within structs, just as in Java/C# (compact/familiar).

There will be an "x@value" syntax for embedding variables within array literals.

Addressing goes on the LHS and applies to the whole RHS (e.g. &a[n] is &(a[n])).

Entities may not be defined within each other (e.g. no structs within structs, etc.).

Expressions cannot contain statements (declarations, assignments, calls, var++/var--).

Anonymous functions may may not refer to (non- static/const) external local variables.

All code is precomputed as much as possible (without unrolling loops or recursive calls).

The $ operator Requires something to be interpreted, including loops and recursive calls.

Bridge methods will be inserted for multiple "inheritance" of anonymous fields, as needed.

Control-flow constructs will indeed require parenthesis (avoids parsing conflicts with literals).

No "static" members of anything (but static local vars and static initialization blocks are allowed).

Entites Have Global Accessibility If They Are Capitalized, and namespace accessibility otherwise.

Look-Up-Tables (rather than Jump Tables) will be used with switches and if-else chains as possible.

Methods can only be defined for "identifier" types (structs, primitives, etc., but not funcs, arrays, etc.).

Namespaces may be nested ("Outer.Inner" syntax), and there will be a "using Namespace" mechanism.

Self-Modifying code will be used with cofuncs and switch-variables (Will consider an option to disable it).

Explicit variable addresses can be nominal (@"address") or refer to another variable (@x or @arr[n].foo).

No exception-handling or "try-catch" mechanism (use multiple return values or create an "Exit()" instead).

Type-casts will be represented traditionally (e.g. "(byte)(a+b)").

"Extra" Parenthesis are not allowed within datatypes ("func(...)" requires them, but []*T are *[]T are unambiguous).

Function pointers without any return values may point to functions with return values (e.g. func(byte) pointing to func(byte):byte).

Values will be passed/returned in registers such that any two functions with the same pattern of arguments will use the same registers for them.

Default arguments (and struct members) must come last, and will be embedded in functions so they can be pointed-to as their reduced versions.

An anonymous (nameless) struct/interface/cofunc/func within a namespace will take on the name of the namespace (e.g. "List myList" rather than "ListNameSpace.ListStruct myList"). This also gives namespace values ("List.staticValue") the feel of Java/C#'s static class members.
Title: Re: OPIA - A full OOP language for z80
Post by: DJ Omnimaga on May 26, 2012, 12:20:26 am
I didn't check everything out, but is for(init; condition; update) kinda like the start value, then a boolean condition (eg A == 50) then the operation to do if it is (and exiting the loop)?

When stuff is finalized about the language itself, it would be great if you made some document to include with OPIA release that gave syntax examples of the language. (If you ever have a site about the language doc, animated screenshots + program examples would definitively be cool too.
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on May 26, 2012, 04:46:57 pm
I plan on re-documenting the language once it is done or underway. I do want it to be a concise reference, but I will probably give better (more realistic) examples. The compiler will only be a command-line interface, so there will not be anything visual to show for. However, this will allow it to be integrated into whatever other program (like how different things link into Notepad++, etc.). I will probably make a visual editor; but this way the core language/compiler (and all of it's inner modules) stay modular / pluggable.
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on June 17, 2012, 01:35:14 am
I am putting together the Grammar for OPIA, as can be seen in the link below. The compiler will have a portion of syntax-tree-building code corresponding to each rule. In the past, I've made different "versions" of similar rules so that they can work properly in their respective contexts (e.g. variable declarations follow a preset form, but have different restrictions in global, local, and object-member contexts). HOWEVER, my plan this time is to leave the rules more broad (e.g. use the same rule for "lists" of values as function arguments, array values, and variable declarations), but then inspect the contents of the resulting syntax structures to make sure that they are consistent with the context (e.g. variable declarations can contain a "list" of "assignments", but assignments are not allowed within other expressions; Function declarations take a list of variable declarations for arguments, but function pointers take a list of JUST datatypes; etc.). This will also allow complex portions of code to be parsed correctly, even when placed in a context which would otherwise not now what to do with it (which means better error messages). For this reason, I am starting the rules in a very general sense by using "E" values as a placeholder until I narrow everything down.

PLEASE LOOK AT THE GRAMMAR IF YOU CAN: Feedback will be GREATLY appreciated as I work on them, and will help ensure that OPIA's compiler is designed well (and sooner). Here are some new links, along with the link to the grammar:

Intro: http://tinyurl.com/z80opia (http://tinyurl.com/z80opia)
Overview: http://tinyurl.com/z80opiaO (http://tinyurl.com/z80opiaO)
Grammar: http://tinyurl.com/z80opiaG (http://tinyurl.com/z80opiaG)
Title: Re: OPIA - A full OOP language for z80
Post by: BlakPilar on June 17, 2012, 12:21:16 pm
Are you using something like ANTLR, or are you making a custom parser?
Title: Re: OPIA - A full OOP language for z80
Post by: Matrefeytontias on June 17, 2012, 12:33:13 pm
Do you have the compiler working ? Can you post an example of code and its executable ?
Title: Re: OPIA - A full OOP language for z80
Post by: BlakPilar on June 17, 2012, 12:34:10 pm
He's only on the grammar right now, so no, the compiler is not currently working.
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on June 17, 2012, 06:11:06 pm
Everything will be custom-written. In the past, I've kinda cowboy'd it and written classes for function-, class-, etc.- entities and worked down from there. However, this time I am making a clear grammar first, and even going as far as listing what kinds of classes will be needed to represent each. Compiler tools are great, but it is entirely practical, legit, and rewarding to actually make the compiler yourself. I will likely do that from start to finish, though I MIGHT consider something for optimizing intermediate ("3 instruction") code.

Once I have all the grammar rules down (along with additional semantic rules and associated classes), coding it will be a snap -- most rules will translate directly to code (though similar ones might use the same code with a branch in it).
Title: Re: OPIA - A full OOP language for z80
Post by: BlakPilar on June 17, 2012, 06:18:24 pm
Yeah, that's what I'm doing with my compiler. I was using ANTLR, but I wasn't satisfied with its error reporting for the C# port, so I decided to write everything myself. I love the freedom of being able to customize everything. My lexer is done, and I'm working on the parser right now. My only problem is I don't have an exact syntax for it yet lol.

I took a quick look at your grammar before, and it looks good so far. I'll be able to take a better look at it later, though.
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on June 17, 2012, 06:28:31 pm
Ooh... Can I have a look at it sometime? At least eventually, I'd love to swap code. I have not yet come across somebody actively coding a compiler, and I'd like to compare approaches / techniques. All I have in place right now though is the Tokenizing and Preprocessing; though I am thinking about redoing some of that as well for modularization reasons.
Title: Re: OPIA - A full OOP language for z80
Post by: BlakPilar on June 17, 2012, 06:36:11 pm
Sure! But yes, now wouldn't exactly be a good time for me either. My code isn't exactly the neatest as of right now. My language doesn't need a preprocessor, but the way I have everything set up, I'd like to think implementing one wouldn't be too hard. Plus my lexer isn't 100% done; it's more like 97%. I just need to add support for decimals / floats and hex.
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on June 18, 2012, 04:12:31 am
UPDATE: I basically have all the structural classes (for the syntax tree) figured out now! :D Take a look (http://tinyurl.com/z80opiaG)!
Title: Re: OPIA - A full OOP language for z80
Post by: BlakPilar on June 18, 2012, 12:26:45 pm
Nice! That's similar to what I'm doing, except I only have statements and expressions. I have a method I created for extracting token patterns that I found is pretty useful, at least for namespaces. Yours is looking good, though! :)
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on June 18, 2012, 03:21:33 pm
I feel it worth sharing a conversation from another thread:

Quote from: merthsoft
It looks good to me. Though I can't help but point at that examples are always a good idea, even if you think it's readable. Not everyone is you. What you and Kerm basically just did is an example of intellectual exceptionalism--you more-or-less said "it's easy to understand if you're not dumb".
Thanks for bringing this to light, because the fact that it appears that way means that I was not clear about what I posted and why (oops!): The Grammar is something that I posted as a necessary aid in designing the compiler, rather than as a medium I chose to explain the language to everybody (that's what the overview is for). However, in the spirit of open source development (and to involve the community), I document everything and try to keep it as clear as possible for what it is (e.g. I try to keep the source code easy to read if you know Java).

However, given the involvement/interest in the community, the usefulness of a grammar, and in light merth's point (thanks), posting a section about how the grammar works would be very helpful in general as well as providing the opportunity for more people to see how the compiler/language is directly put together (and for those so inclined, I provide those very same classes in the compiler with external access as a Java API).
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on June 27, 2012, 03:49:44 pm
*Bump!*

I've updated the Grammar (http://tinyurl.com/z80opiaG) a good deal, take a look! The next step is to throw in all the statement-level items, which will help me finish all the namespace-level items. Notice that I've finally incorporated lambda expressions, anonymous functions, and literal constructs into the expression-web (which was hard because I had to provide a way for "types" to exist as expressions, including all I just mentioned).
Title: Re: OPIA - A full OOP language for z80
Post by: BlakPilar on June 27, 2012, 04:13:24 pm
Hazzah for lambda expressions and anonymous functions! :D

One question, though: I just noticed bit rotation. Is that where 0b00100110 >>> 3 == 0b11000100?
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on June 27, 2012, 05:24:16 pm
Hazzah for lambda expressions and anonymous functions! :D

One question, though: I just noticed bit rotation. Is that where 0b00100110 >>> 3 == 0b11000100?

Indeed it is! :) I figured that it's useful enough in z80 programming to just make it a direct operator. I know that Java uses ">>>" for "unsigned left shift", but that's only because it does not allow for unsigned variables. In OPIA (and other languages), you can just use a type-cast to affect the operation anyway :)
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on June 30, 2012, 01:58:23 am
All the grammar rules are now in place! I just have to revise the example a bit more, and perhaps add in some more "notes / additional semantics" (which I have kinda been glossing over).
Title: Re: OPIA - A full OOP language for z80
Post by: shkaboinka on July 02, 2012, 06:01:06 pm
I have finally completed the grammar!

I was very thorough in including notes, explanations, additional semantics, and examples. The grammar gives a technical definition of OPIA syntax in detail, but I have also included a list of classes used and an explanation of how they are used, and a very integrated (and thorough, though somewhat shortened) example of how the parsing works with the classes used.

Please take a look! (http://tinyurl.com/z80opiaG) (and let me know if anybody can find anything wrong with it, thanks) :)

Note: Due to current circumstances, designing the compiler may have to take a back seat for a while (job search, baby coming due). HOWEVER, please also note that the grammar is already a very complete definition of MUCH of the compiler internals. ... When I can find significant time, it will be much a matter of writing code to match the rules (almost exactly as they are described).
Title: OPIA - NAME CHANGE!
Post by: shkaboinka on July 09, 2012, 05:02:45 pm
I am considering changing the name of the OPIA language, since it has already left the classic OOP paradigm (it is still object based, but the polymorphic behavior is provided separately from objects), and to define it in its own terms (i.e. not a "revised" Antidisassemblage).

SOME POSSIBILITIES:

OPIL - Objective Pre-Interpreted Language
OPPIL - Objective Polymorphic Pre-Interpreted Language
PIOBL - Pre-Interpreted Object-Based Language
PIOL - Pre-Interpreted Objective Language
PIOPL - Pre-Interpreted Objective Polymorphic Language
PIOZL - Pre-Interpreted Objective z80 Language
PIPL - Pre-Interpreted Polymorphic Language
POBL - Polymorphic (or Pre-interpreted) Object Based Language
POL - Polymorphic (or Pre-interpreted) Objective Language
POPIL - Polymorphic Objective Pre-Interpreted Language
POPL - (same as above, or flip the P's around)
POPIZL - Polymorphic Objective Pre-Interpreted z80 Language
POZL - Polymorphic (or Pre-Interpreted) Objective z80 Language
PPIL - Polymorphic Pre-Interpreted Language ("P Pill")
ZOPIL - z80 Objective Pre-Interpreted Language
ZOPPIL - z80 Objective Polymorphic Pre-Interpreted Language
ZPIOL - z80 Pre-Interpreted Objective Language
ZPIPL - z80 Pre-Interpreted Polymorphic Language
ZPOL - z80 Polymorphic (or Pre-Interpreted) Objective Language
ZPOPIL - z80 Polymorphic Objective Pre-Interpreted Language
ZPOPL - (same as above, or flip the P's around)
ZPPIL - z80 Polymorphic Pre-Interpreted Language
ZPPL - (same as above, or flip the P's around)

Notes:
 - "Objects" and "Polymorphism" kind of imply each other.
 - "Pre-Interpreted" could be "Partially interpreted" instead.
 - "Objective" and "Object Based" are mostly interchangeable.
 - I am also considering how the name "sounds" (though some like ZPPL would just be read letter by letter).
 - The following languages already exist: PIPL OPL ZOPL PPL.

OPINIONS (for or against) ARE APPRECIATED!
Title: Re: Antelope (formerly "OPIA") - A Polymorphic z80 language
Post by: shkaboinka on July 10, 2012, 07:09:44 pm
Further discussion suggested I choose a random name that "sounds" better. I considered "tadpole", "polywog", and "caterpillar" (since my language is simple, polymorphic, and will hopefully grow into something big); I threw out other ideas from constructed languages (nevermind!); and then finally I just asked my wife (who has nothing to do with programming), and she immediately referred to my little friend:

(http://sphotos.xx.fbcdn.net/hphotos-ash4/403952_10151273642874546_820865579_n.jpg)
(http://tinyurl.com/AntelopePic (http://tinyurl.com/AntelopePic))

It looks like my little friend ("The Antelope") just accidentally became a programming language mascot: I think I'm going to stick with "Antelope"! :) (..and I changed the thread name to match..)

HERE ARE THE NEW LINKS:

http://tinyurl.com/antelopeHome (http://tinyurl.com/antelopeHome) - Antelope Home page
http://tinyurl.com/antelopeOverview (http://tinyurl.com/antelopeOverview) - Antelope Overview page
http://tinyurl.com/antelopeGrammar (http://tinyurl.com/antelopeGrammar) - Antelope Grammar page
http://tinyurl.com/antelopeSource (http://tinyurl.com/antelopeSource) - Antelope Source Code page
http://tinyurl.com/antelopeCode (http://tinyurl.com/antelopeCode) - Source Code (again)

I have also left a link on the old OPIA page (http://tinyurl.com/z80opia), though I have yet to actually import everything over (but do see what I've done with the home/intro page).

EDIT: All the (relevant) documentation and code has been ported over (enjoy)! I will delete the old project eventually.
Title: Re: Antelope (formerly "OPIA") - A Polymorphic z80 language
Post by: TIfanx1999 on July 11, 2012, 05:05:01 am
That is a much better name than before. OPIA always made me think of what the plural version of opium would be. :/
Title: Re: Antelope (formerly "OPIA") - A Polymorphic z80 language
Post by: NanoWar on July 11, 2012, 08:10:52 pm
Hmm I like POL or OPIA hehe. I like uppercase names for programming languages...
Title: Re: Antelope (formerly "OPIA") - A Polymorphic z80 language
Post by: shkaboinka on July 12, 2012, 06:48:47 pm
Well, being as that I finally fixed up that image so it doesn't look like a stuffed animal...
(http://i.imgur.com/mgaSg.png)
...I think I am sticking with Antelope. But thanks for supporting my cause! :)
Title: Re: Antelope (formerly "OPIA") - A Polymorphic z80 language
Post by: Deep Toaster on July 13, 2012, 12:43:23 am
That is a much better name than before. OPIA always made me think of what the plural version of opium would be. :/
Unfortunately that's how it was for me <_< Antelope's a nice name. I like it. Language names don't have to have anything to do with what they're like—heck, just look at Python (http://docs.python.org/tutorial/appetite.html) and Lua (http://www.lua.org/about.html) :D (By the way, what did OPIA even stand for? I don't see it anywhere except possibly that long list of acronyms in your post about possible names, but that list doesn't contain "OPIA." But then I haven't read much of this topic yet, so sorry if it's in some random place.)

I hadn't really looked at your project until now (sadly), but the more I read on the Grammar wiki page the more excited I'm getting about it. (Who knows, maybe it's the name change XD)
Title: Re: Antelope (formerly "OPIA") - A Polymorphic z80 language
Post by: BlakPilar on July 18, 2012, 01:43:43 pm
Woah, looks like I missed a few posts. I don't know why, but I wasn't receiving emails.

Anywho, the grammar looks good! I'll have to take a gander at the source sometime soon ;)
Title: Re: Antelope (formerly "OPIA") - A Polymorphic z80 language
Post by: shkaboinka on July 18, 2012, 03:17:36 pm
Woah, looks like I missed a few posts. I don't know why, but I wasn't receiving emails.

Anywho, the grammar looks good! I'll have to take a gander at the source sometime soon ;)
Awesome, you guys! Thanks!
By the way, the source will need some redoing; but feel free to see it anyway. I will have to make sure the Token class matches everything now, and there are other changes (reserved words do not currently "count" as identifiers, which might result in confusing error messages). Also, the Tokenizer class (previously "Preprocessor") is going to be highly revised so that it can spit out one thing at a time (like the Token.nextToken()) rather than messing with Lists (so as to make it play nice as an API). I am planning on perhaps making a "TokenSource" interface so that things OTHER than Token.nextToken() can be used to get tokens, with Tokenizer acting as an intermediary which uses that and preprocesses at the same time.

...I have an interesting conundrum to resolve as well, and posted about it in Cemetech; but it's REALLY long...
Title: Re: Antelope (formerly "OPIA") - A Polymorphic z80 language
Post by: BlakPilar on July 18, 2012, 05:50:20 pm
Before I took a break from my compiler, I had my tokenizer run through a .NextToken() basis. However, I may need to do some looking ahead, so I think I may put all of the read tokens into an array when I get back to it. As for the reserved words bit, maybe you could have special types of reserved words? As in some way to see if they would return a value ("typeof" or "sizeof," for instance, though I'm not sure if you're using those in particular).

Could you perhaps link to your conundrum?
Title: Re: Antelope (formerly "OPIA") - A Polymorphic z80 language
Post by: shkaboinka on July 19, 2012, 01:13:09 am
Because I took a couple pages to say it in detail (and because I've been told not to link to other forums), I will just sum it up:

With the switch from a C# style to a Go style, I figured that interfaces provide enough dynamic behavior to be alright without providing parametric types ("templates" in C++, "generics" in Java), since you can just use an interface to store data of any type. The empty interface ("interface any{ }") acts as a pointer to anything without any method requirements (like "void*" in C++ or "Object" in Java).

The problem is that using a more complete interface means that each entry is larger, since the relevant function pointers are stored alongside them. For example, each item in "data" below contains a pointer to some object, AND pointers to all the methods of the interface:

Code: [Select]
interface Printer { Print(); }
struct Foo { []Printer data; }

One solution would be to use Parametric types as a convention for storing the method-pointers separately. It would look something like this, with "<T:Printer>" designating that the struct separately stores ONE copy of method-pointers for the "Printer" interface, and designating "T" as a stand-in for something that counts as a "Printer" (i.e. something with a Print method, but not an actual "Printer" itself):

Code: [Select]
interface Printer { Print(); }
struct Foo<T:Printer> { []T data; }

This would require each "T" to be stored as a pointer (rather than a whole "Printer") so that the same struct (or any parameterized entity)can be used for anything.  Otherwise there would have to be a different "version" for each type, and it would be pointless to actually store implicit method pointers for the interface, since each version could have the "right one" hard-coded in. In either case though, this struct would be used with a datatype plugged into it, which the compiler would use to restrict what can be stored in it:

Code: [Select]
Foo<int> list; // list may only work with ints (and stores an int.Print pointer)
Foo<Bar> list2; // list2 only works with Bars (stores a single Bar.Print pointer)

The issue is two things (and a couple of trivial things that I will leave out):

The first is that it does not parse well ("x<y,z>w" could be a tuple of two boolean comparisons, it it could be saying that "w" is somthing of type "x<y,z>"). This can be solved by using an unconventional syntax, or by requiring the "tuple version" to use extra parenthesis to work properly, or by reparameterizing each parametric type (e.g. "x<y><z>").

The second is just whether to use the "generic" form (all parametric types are pointers) or the "template" form (the compiler makes a copy of everything for EACH type used). The first only uses one version of everything and provides true dynamic entities. The second makes multiple copies which are hard-coded per type, but each is more efficient; however, the copies depend on what is used per compile, and there cannot be one precompiled version (set of methods), so it could not exist as a runtime library unless the "generics" setup is used.
Title: Re: Antelope (formerly "OPIA") - A Polymorphic z80 language
Post by: BlakPilar on July 19, 2012, 04:04:35 pm
If it's my understanding, then this:
Code: [Select]
interface Printer { Print(); }
struct Foo<T:Printer> { []T data; }
could just as easily be this:
Code: [Select]
interface Printer { Print(); }
struct Foo<Printer> { []Printer data; }
because inheriting from Printer would automatically make it a Printer type. Having something like struct Foo<T:Printer> ... is far more complicated than necessary because if something has a Print() method, but is not yet a Printer, it would be just as easy to simply make it inherit from Printer.

As for the parsing bit ("x<y,z>w"), maybe you could adopt a sort of Lisp syntax for that and drop the comma ("x<y z>w")?

Also, interfaces are kind of templates by definition, at least in C#. Not every Print() method would be the same for every Printer. They would each contain a definition for the method, but the bodies may be different, so I would say go with the template form. (That is, unless I'm understanding this wrong.)
Title: Re: Antelope (formerly "OPIA") - A Polymorphic z80 language
Post by: shkaboinka on July 20, 2012, 04:56:54 pm
If it's my understanding, then "struct Foo<T:Printer> { []T data; }" and "struct Foo<Printer> { []Printer data; }" are basically the same. ... Not every Print() method would be the same for every Printer.

Sort of... The intention is that, where the Print() method is the same, you would only have to store one of them. For example, a Foo<Bar> would be a "Foo" containing "Bar" values, and therefor each using the same "Bar.Print" method. If you want a structure of mixed "Printers", then you would just use the Interface directly:

Code: [Select]
interface Printer { Print(); }

// Using "mixed" Printers ("<>" is unnecessary)
struct Mixed { []Printer data; }
Mixed m = {{someBar, someCar, someDar}};
//m is: {{Printer{someBar,Bar.Print}, Printer{someCar,Car.Print}, Printer{someDar,Dar.Print}}}
m.data[i].Print(); // Calls the "Print" of data[i] on the Printer-object of data[i]

// Using only same-typed Printers:
struct Same<T:Printer> { []T data; }
Same<Bar> s = {{bar1, bar2, bar3}};
// s is: {{bar1,bar2,bar3}, Bar.Print}
s.data[i].Print(); // Calls the single embedded Bar.Print on data[i]

The idea with this style is that the parameterization (<T:Printer>) just acts as a way to base a structure on some type which qualifies as some interface, but to store it as is and use the relevant method. The method must still be stored (since the structure does not know which type it ever since, being a generic structure based on a pointer to "something"), but is stored separately for efficiency. However, if you want a bunch of Printers (not things based on Printers, but actual Printers), then just use the Printer type directly!

The conundrum again is as follows:

This "generic" style has the "win" of providing a more efficient "generic" version. You could even have a plain "Foo" as a function argument, and pass it either a "Foo<Bar>" or a "Foo<int>", and it will work all the same using the same function, because the relevant method is embedded. Besides, a "templated" form is a convenience which CAN be coded by hand. That is, if you want a structure of int values, then go ahead and make one.

HOWEVER, without a "template"-based setup, it is impossible to make a standard library for such. For example, someone could make a very nice tree structure based on a "generic" type, or even just on an int; but if you wanted one made JUST for strings, you would have to code it all over again just for strings. So a "templated" setup has a win there; but would then not allow for the generic behavior I just described, result in multiple vesions of everything (bloat), and it would be impossible to have a runtime (precompiled) library of such, since every possible type cannot be anticipated that way.

C# actually uses something between the two forms (it uses one definition of everything, but the "reifies" them at runtime ... something like that) ... I am going to go read more on how C# does it and see if I get any ideas; though Antelope does not use a virtual environment and JIT is not applicable.

By the way, that "<A B>" syntax might not be a bad idea; though it would be the only thing in the language which does not use a separator (comma or semicolon) between arguments...
Title: Re: Antelope (formerly "OPIA") - A Polymorphic z80 language
Post by: BlakPilar on July 20, 2012, 11:16:01 pm
Oh okay. I see what you mean. But then again, instead of "<T:Printer>," you could just make Printer an abdtract class with a default method and only make a new instance of the code body if it overridden in a class that inherits from Printer.

Also, are you sure Foo and Foo<T> would have the same methods? The former would be of type Foo, but the latter's type would probably be something like IEnumerable<T>.
Title: Re: Antelope (formerly "OPIA") - A Polymorphic z80 language
Post by: shkaboinka on July 22, 2012, 06:18:48 pm
1) you could just make Printer an abstract class with a default method
2) Also, are you sure Foo and Foo<T> would have the same methods?
3) Foo<T>'s type would probably be something like IEnumerable<T>.

1) There are no classes in Antelope, and no "abstract" mechanism. There are just structs, interfaces, and methods, which are all separate features (to be very technical, nothing "has" methods, but there may "be" methods "for" something; they are given additionally). However, you can use embedded function-pointers to simulate some of that behavior:

Code: [Select]
struct abstract {
   int x, y;
   meth := func(this, int a, int b) { x=a; y=b; };
}

a1 = abstract{1, 2}; // uses defualt method
a2 = abstract{1, 2, someOtherMethod};

2) I am actually leaning toward the "templating" setup, so that if there is a "Foo<T>", then it will be incorrect to have a plain "Foo". The compiler will generate different methods for each type used, but will share methods which would be exactly the same. This means that you can use a pointer to keep everything generic:

Code: [Select]
struct Foo<T> { *T value; } // always the same size
func Foo<T>.Bar<T>() { ... } // always the same everything
func Foo<int>.Bar() { ... } // THIS one is specific to ints.

c := Foo<char>{'5'};
b := Foo<bool>{true};
i := Foo<int>{123};

c.Bar(); // inferred as c.Bar<char>, or Foo<T>.Bar<T> where T = char
b.Bar(); // inferred as b.Bar<bool>, or Foo<T>.Bar<T> where T = bool
i.Bar(); // inferred as i.Bar<int>, or the separate Foo<int>.Bar

// --- Another just to clarify: ---
func A<T>(T arg) { ... } // Different per type-size (and per differing operations on T)
func B<T>(*T arg) { ... } // Same per type, so long as nothing type-specific happens

3) ...Nothing would be quite like "IEnumerable<T>"; though yes, they share the same kind of generic idea. On a side note though, Antelope abandons the concept of "iterators" as they are in Java, C++. Instead, you'd iterate over things directly within a cofunc (which, by the way, was inspired by the "enumerators" or C# and the coroutines of Lua):

Code: [Select]
struct Tree<T> { T value; *Tree<T> left, right; }

cofunc Tree<T>.InOrder<T>():T {
   if(left != null)
      for(int i : new left.InOrder{}) { yield i; }
   yield value;
   if(right != null)
      for(int i : new right.InOrder{}) { yield i; }
}

Tree<int> tree; // Tree of int values
...
for(int i : tree.InOrder{}) { Print(i); }

EDIT: I actually found that using function-pointers as "visitors" is a MUCH more efficient pattern:

Code: [Select]
struct Tree<T> { T value; *Tree<T> left, right; }

func Tree<T>.InOrder<T>(func(T) process) {
   if(left != null) { left.InOrder(process); }
   process(value);
   if(right != null) { right.InOrder(process); }
}

Tree<int> tree;
...
tree.InOrder(Print);
// Or: tree.InOrder(i => somethingElse(i));
(SEE MY NEXT POST)
Title: Re: Antelope (formerly "OPIA") - A Polymorphic z80 language
Post by: BlakPilar on July 22, 2012, 08:30:25 pm
Ahh okay, I think I understand this all now.
Title: Re: Antelope (formerly "OPIA") - A Polymorphic z80 language
Post by: shkaboinka on July 23, 2012, 04:56:53 pm
*Bump* - Here are some new changes:

I have reverted the "cofunc" syntax back so that they cannot be embedded within structs, but they can hold data like structs. This is slightly less flexible (only because bizarre"siamese" cofuncs are no longer possible), but is more intuitive:

Code: [Select]
// Old setup:
struct Counter { int n; cofunc( ):int { n++; return n; } }
c := Counter{5};
c(); c(); c(); // 6, 7, 8

// New setup:
cofunc Counter { int n; } ( ):int { n++; return n; }
c := Counter{5};
c(); c(); c(); // 6, 7, 8

I have also decided to go with the "Templating" form of parametric types (though I still need to choose an unambiguous syntax for multiple parameters), but I will have templated things share the same functions when they are the same. This means that you can still use POINTERS to keep things generic for all types :)

Code: [Select]
struct Link<T> { T value; *Link<T> next = null; }
struct List<T> { *Link<T> head = null, tail = null; length = 0; }

func Tree<T>.Size<T>():int { return length; }

func Tree<T>.add<T>(T val) {
   l := new Link<T>{val};
   if(head == null) { head = tail = l; }
   else { tail = tail.next = l; }
   length++;
}

List<int> list; // an int list
list.add(1); ist.add(1); ist.add(3);
If it were "*T value" rather than "T value" in Link, then there'd only one version of everything, since pointers are the same size. Also, you can be specific, such that a "func List<int>.Foo()" would take ONLY int-lists (which is why the extra "<T>" is needed in "List<T>.add<T>").

I have also added the option of an extra "this" for cofuncs, removed the empty parenthesis from no-argument lambdas, allowed lambdas to have full {bodies}, ... and in the process, I have discovered that passing a function-pointer is MUCH more efficient than using a cofunc as an "iterator". Here is an example of all (riding off that "List" code):

Code: [Select]
List<int> list;

cofunc List<T>.Iterator<T>():*T {
   for(l := head; l != null; l = l.next) yield l.value;
}

func List<T>.Each<T>(func(*T) process) {
   for(l := head; l != null; l = l.next) process(l.value);
}

// Cofunc iteration (uses two loops!)
for(int i: list.Iterator{}) { ...do stuff with i... }
// Func-pointer iteration (much more efficient)
list.Each(i => {...do stuff with i...});

The only thing is that you cannot encapsulate everything into a function; though perhaps I can allow direct access to local variables, but then disallow such funcs from "escaping" the embedded function by restricting their use (e.g. cannot be assigned to external variables or passed into external routines).
Title: Re: Antelope (formerly "OPIA") - A Polymorphic z80 language
Post by: shkaboinka on July 26, 2012, 05:14:22 pm
I have made all recently mentioned changes to the grammar!

 - Templated types (e.g. Foo<T:Printer> { ... } )
 - Extra "this" type for cofuncs.
 - No more embedding of funcs or cofuncs within structs or cofuncs (enforces clarity)
 - You can now be more liberal with the "dot" access (A.func(...), B.(*type), etc.).

Have a look (http://tinyurl.com/antelopeGrammar) :)
Title: Re: Antelope (formerly "OPIA") - A Polymorphic z80 language
Post by: BlakPilar on July 26, 2012, 09:42:00 pm
Lookin' good ;)

Quote
- No more embedding of funcs or cofuncs within structs or cofuncs (enforces clarity)

Does this mean we have to use C++ style method declaration? I.e.
Code: [Select]
struct Foo { ... }
func Foo::Bar() : byte { ... }
Title: Re: Antelope (formerly "OPIA") - A Polymorphic z80 language
Post by: shkaboinka on July 27, 2012, 04:38:48 am
Does this mean we have to use C++ style method declaration? I.e.
   struct Foo { ... }
   func Foo::Bar() : byte { ... }

Yes, this has always been the case (so that you can add new methods you as needed, without affecting the "definition" of a struct). Allowing them inside of structs was something I had added for familiarity with Java/C# as well. However, since you can embed function pointers inside structs (and make them act as virtual methods as well), I thought it would minimize confusion (and simplify the language) to just stick with one convention:

Code: [Select]
struct Foo {
   func(*Foo,...) fp; // embedded function pointer
   func(this,...) mp; // just like fp, but counts as a "method"
}

func f(*Foo,...) { ... } // function (not embedded in Foo)
func Foo.m(...) { ... } // method (same as f, but is a method)

Foo foo, foo2;
foo.fp(foo,...); // foo EXPLICITLY passed as 1st arg
foo.fp(foo2,...); // same deal (can pass ANY Foo)
foo.mp(...); // "method" = foo IMPLICITLY passed as 1st arg ("this")
f(foo,...); // same deal as fp, but not a func-pointer
foo.m(...); // same deal as mp, but not a func-pointer

// They all STORED as func(*Foo,...) though;
// and since fp and mp are pointers, you can do this:
foo.fp = foo.mp = f; foo.fp = foo.mp = m;

I honestly prefer the "inside" form myself; but it's not hard to get used to, and you have the following benefits:
 * The struct JUST contains what it actually consists of (e.g. it "is" its "constructor"; the end).
 * This is simpler than in C++: You use "." insteaf of "::", and only declare it once (no "headers").
If enough people are not appeased by these benefits (and my other reasoning), then I might reconsider. I do want to make a language that people like as well.
Title: Re: Antelope (formerly "OPIA") - A Polymorphic z80 language
Post by: shkaboinka on July 29, 2012, 11:48:09 am
*Bump* - I have made changes to the Overview (http://code.google.com/p/antelope/wiki/Overview), with the following changes:

 - Tuples can now have empty items (e.g. use "(,x,)" instead of "(_,x,_)").
 - Added a detailed section just for namespaces.
 - Changed the preprocessor directives to be more traditional
 - Elaborated on how default values work (not the same as in other languages!)
 - Gave example of how anonymous entities in a namespaces take on the namespace name.
Title: Re: Antelope (formerly "OPIA") - A Polymorphic z80 language
Post by: BlakPilar on July 29, 2012, 12:07:00 pm
Cool. I like the preprocessor directives especially since I'm starting to understand their usefulness (remember, I have mostly confined myself to C# where they are largely unnecessary). Do you plan to add #pragma, or would that not be needed?

Also, with the outside struct method declaration, I don't mind it. I would more than likely keep structs in their own files, though, then.
Title: Re: Antelope (formerly "OPIA") - A Polymorphic z80 language
Post by: shkaboinka on July 29, 2012, 05:08:35 pm
Cool. I like the preprocessor directives especially since I'm starting to understand their usefulness (remember, I have mostly confined myself to C# where they are largely unnecessary). Do you plan to add #pragma, or would that not be needed?
No pragma, because I intend on having my compiler be "the" compiler for Antelope (like how java uses "javac" as the core compiler, but various IDE's can be built off of it). Instead, by exposing the guts of the compiler as an API, other tools can "intercept" code between phases and do whatever else they want (including intercepting a "#pragma" anyway).

Also, I will have the compiler strictly allow each file to be used only once, with context of usage not playing any significant role (other than referring to relative file-locations). However, I'd like to allow URL's in #includes too! :) I will probably let the compiler take an argument to specify default url paths as well as default file paths, so that other tools (IDE's) can provide environment control separately from the source code.

On a side note, "projects" could be managed simply enough by creating one file with an "#include" for everything else; and since this can be done with "#define" as well, perhaps it might be worth providing a "#nodef" or "#ignore" directive to veto specific things beforehand.
Title: Antelope - New Syntax for OOP Idioms!
Post by: shkaboinka on August 09, 2012, 04:19:58 pm
NEW SYNTAX FOR OOP IDIOMS!

To test the feel of everything, I compared a simple OOP example from Java/C# with the "equivalent" Antelope code, and found it to be bulky and nasty. Therefor, I am wanting to rework some of the syntax relating specifically to "inheritance" idioms, as follows (with "..." indicating "no change"):
Code: [Select]
PSUEDO-JAVA/C#        | | ANTELOPE (new syntax) | | ANTELOPE (old syntax)   
========================================================================
class Fooer {         | | struct Fooer {        | | ...                     
  void Foo() {        <1>   func Foo() {        <1> func(this) Foo = func(this) {
    Print("Foo ");    | |     Print("Foo");     | |   ...                   
  }                   | |   }                   | | }                       
}                     | | }                     | | ...                     
                      | |                       | | ...                     
class FooID : Fooer { <2> struct FooID {        <2> ...                     
  int id;             | |   int id;             | | ...                     
                      | |                       | | ...                     
                      <3>   Fooer {             <3> Fooer = Fooer {         
  void Foo() {        <4>     func Foo() {      <4>   func(this) {         
    Print("Foo ");    | |       Print("Foo ");  | |     ...                 
    Print(id);        | |       Print(id);      | |     ...                 
  }                   | |     }                 | |   }                     
                      | |   }                   | | }                       
}                     | | }                     | | ...                     
1) I'd previously given the "func(this..." syntax for declaring function-pointers "as methods" (i.e. "f.Foo(f)" shortens to "f.Foo()"), which allowed "virtual" (late-bound) methods to be "simulated". However, letting these be declared directly as "internal methods" looks much cleaner, matches the common OOP idiom/paradigm, and still gives control over where they are stored in the struct.

2) Antelope rejects traditional "inheritance" in favor of composition (http://en.wikipedia.org/wiki/Composition_over_inheritance). Instead, anonymous members provide transparent access to their internals, as if they were "inherited" directly into the containing struct. Thus, the "inherited" Fooer appears in the body of the struct rather than at the top (as in 3).

3) Since anonymous members exist soley to "simulate inheritance", it is just redundant to have to repeat the anonymous type twice when a more compact form will do. This form is suggestive of embedding an "anonymous class" within a struct, which is exactly the intent (as in 6).

4) Since "inheritance" is simulated by composition, the new "Foo" function must be embedded directly in the anonymous Fooer. However, the only safe option is to use a "Fooer" method (since a "FooID" method could have misalignment issues) declared anonymously (to hide it from "Fooers" outside of FooID) and then type-cast to "FooID" within the method. This new form takes a non-method function definition for overriding (replacing) "inherited" methods, which then does these things automatically (using offsets if necessary). These can be given anywhere in the initialization list, and are skipped if omitted.
Code: [Select]
PSUEDO-JAVA/C#        | | ANTELOPE (new syntax) | | ANTELOPE (old syntax)
======================================================================
Fooer foo = Fooer();  <5> Fooer foo = Fooer{};  <5> ...                   
FooID fid = FooID(5); | | FooID fid = FooID{5}; | | ...                   
                      | |                       | | ...                   
Fooer moo = Fooer() { <6> Fooer moo = Fooer {   <6> ...                   
  void Foo() {        | |   func Foo() {        | | func(*Fooer f) {     
    super.Foo();      | |     Fooer.Foo(this);  | |   Fooer.Foo(f);       
    Print(" Moo!");   | |     Print(" Moo!");   | |   ...                 
  }                   | |   }                   | | }                     
}                     | | }                     | | ...                   
5) Initialization values are given directly "{...}" rather than via a constructor "(...)". The first variable declaration can be simplified to either "Fooer foo = {5};" or  "foo := Fooer{5};" for conciseness.

6) "Inner" methods are normally skipped in initialization, but new versions can be defined for them (in any order) (as in 4). This very closely resembles an "abstract class" declaration in Java, which likewise creates an instance with "new" methods (only the Antelope version does not require a "new version" of the struct: this is merely a regular initialization which passes an anonymous function to the function-pointer "Foo").
Code: [Select]
PSUEDO-JAVA/C#               | | ANTELOPE (nothing new here)
=============================================================
void FooFooer(Foo f) {       <7> func FooFooer(*Foo f) {     
  f.Foo();                   | |   f.Foo();                 
}                            | | }                           
                             | |                             
FooFooer(foo); // "Foo"      <8> FooFooer(foo); // "Foo"     
FooFooer(fid); // "Foo 5"    | | FooFooer(fid); // "Foo 5"   
FooFooer(moo); // "Foo Moo!" | | FooFooer(moo); // "Foo Moo!"
7) In Java/C#, pointers ("references") are automatic. In Antelope you have to use them specifically (and you should, because they are more efficient).

8) The compiler will automatically pass the address of these variables so as to match the type. Otherwise, this code is exactly the same. Alternatively, FooFooer could have been written as a method ("func Fooer.FooFooer()").

NOTE: Although there were short forms (e.g. "Foo :=" rather than "func(this) Foo =" (at 1), or "Foo := Fooer{}" or "Fooer Foo = {}" (at 5)), I used the fully expanded forms for a more complete comparison of the fully written out forms.
Title: Re: Antelope (formerly "OPIA") - A Polymorphic z80 language
Post by: shkaboinka on September 27, 2012, 06:21:01 pm
(I posted this elsewhere a while ago) Potential Major Change:

TRAITS (http://tinyurl.com/ooptraits) seem to solve most of the problems not solved (or caused) by inheritance (single or multiple, or using mixins). Traits are like interfaces, except you can provide default implementations for functions ("methods"). They would keep their original functionality as interfaces without any added bulk or framework, but with the addition that structs can "use" them and gain all their methods for free! This provides a clean model for code reuse without affecting any underlying framework!

Code: [Select]
trait Wargler {
  Foo(int);
  Bar():int;
  Wargle() { Foo(Bar()); }
  Talk() { Print("Wargle!"); }
}

trait Fargler {
  Boo();
  Bar() = Moo(5); // { return Moo(5); }
  Fargle() { Moo(Bar()); }
  Talk() { Print("Fargle!"); }
}

struct A : Wargler { ... }
struct B : Fargler { ... }
struct C : Wargler, Fargler { ... }

In this example, structs A, B, and C use above traits, causing the implemented methods (functions) of those traits to be automatically added as (static) methods of those structs. The struct is required to implement the other methods itself (and may also re-implement any of the others). Multiple traits can be combined (as with struct C), and implement each-other's methods (but if more than one trait implements the same method, then it must be redefined in the struct).

The following methods are required for this trait usage:

Code: [Select]
func A.Foo(int) { ... }
func A.Bar():int { ... }
func B.Boo() { ... }
func C.Foo(int) { ... }
func C.Bar():int { ... }
func C.Boo() { ... }
func C.Talk() { ... } // Overlaps both traits

The following methods are generated automatically from this trait usage:

Code: [Select]
func A.Wargle() { Foo(Bar()); } // func Wargle(A* a) { A.Foo(a, A.Bar(a)); }
func C.Wargle() { Foo(Bar()); } // ...etc...
func B.Fargle() { Moo(Bar()); }
func C.Fargle() { Moo(Bar()); }
func A.Talk() { Print("Wargle!"); }
func B.Talk() { Print("Fargle!"); }

Traits still work like interfaces:

Code: [Select]
func Warg(Wargler w) { w.Wargle(); }
func Farg(Fargler f) { f.Fargle(); }

(a,b,c) := (A{...}, B{...}, C{...});

Warg(a); // wa := Wargler{a}; Warg(wa);
Farg(b); // ...etc...
Warg(c);
Farg(c);

Traits can build off of each other in the same manner (e.g. trait X : traitY { ... }). Trait methods can also be aliased to avoid collisions or link to different methods (e.g. "struct X : Wargle(Other = Foo)" gives "Other" as an alias for Wargle's "Foo" method within struct X).

Note: I have also added that syntax as a short-hand for a function body which just returns a value (i.e. "= value" rather than "{ return value; }").
Title: Re: Antelope (formerly "OPIA") - A Polymorphic z80 language
Post by: shkaboinka on September 27, 2012, 06:39:50 pm
I've decided to forego the idea of traits for Antelope. It's a great idea, but I found that most of the same expressiveness is already available from the fact that methods are declared separately, interfaces are applied automatically, and parametric types fill in the rest.

Some other changes I may make:
 * Namespaces may have type-parameters (namespace Foo<T>;) so as to build setups more generically (not only would you not have to do this to every method, but you could also have static/global T values).
 * Optional Constructors: This would change construction to use parenthesis, and optional constructors (and destructors?) would be declared within structs:
Code: [Select]
struct Foo {
   int x; int y;

   new(int xArg, int yArg = 5) { // Constructor
      x = xArg;
      y = yArg + x; // Now you can map values differently
   }

   delete { ... } // Destructor
}

f1 := Foo(1,2); // x=1, y=1+2
f2 := Foo(1); // x=1, y=1+(5)

struct Bar { int x,y,z; } // Constructors not required.
b := Bar(1,2,3);
(Another option would be Kotlin's approach (http://www.youtube.com/watch?v=sP9R9Nc3sRA#t=21m40s))

Some other ideas I'm toying with:
 * Changing lambda syntax from (args)=>code to { args => code } (and from =>code to { code }). I'd only do this so I could allow these to come AFTER function-calls when it is the last argument (Kotlin (http://blog.jetbrains.com/kotlin/) does some fancy stuff this way). Call(1,2,=>{code}) would become Call(1,2) { code }
 * Singleton objects (e.g. "object x { ... }" declares x like a struct, but that x is also the one and only instance of it)
 * "Class (struct) objects" as in Kotlin (http://blog.jetbrains.com/kotlin/) - a struct may contain a singleton object, which is referred to externally by the class name itself. This can be used to encapsulate "static members", but be referred to as a variable. This object can compose (inherit) from another struct for added functionality.
 * Change variable syntax so that types come after a colon (func f(x:int, y:int, z:int = 3) { ... }). This matches how return-values are given, and would make parsing types much easier (which is also true with constructors, since then Foo{1,2} becomes Foo(1,2) and can be parsed as a function-call). Also, this makes "A := B" more sensible for type-inference, since the type is "left out".

The only other thing I am debating is whether "virtual" functions should be stored directly within structs, or accumulate in an array as a "vtable" (C++) aka "class descriptor" (Java). I'm wanting to just keep them as pointers, because I want the language to be VERY oriented around using interfaces INSTEAD of using that kind of "inheritance". This allows embedded function-pointers to count as methods, and it is still POSSIBLE to construct a vtable (e.g. to mirror some hypothetically already compiled setup if necessary).

Thoughts?
Title: Re: Antelope (formerly "OPIA") - A Polymorphic z80 language
Post by: aeTIos on September 28, 2012, 06:18:46 am
This is coming along quite nicely. Do you have any ideas when you might release a beta? (stab me if you said anything about this in previous pages)
Title: Re: Antelope (formerly "OPIA") - A Polymorphic z80 language
Post by: shkaboinka on September 28, 2012, 02:10:48 pm
It will probably be a while: Now that I have a full-time software development job and a newborn baby, this project is officially on the back-burner (though I still poke at it between the cracks when I can).
Title: Re: Antelope (formerly "OPIA") - A Polymorphic z80 language
Post by: shkaboinka on September 29, 2012, 12:02:27 pm
Clarification of changes:

 * Namespaces will be allowed to have type-parameters.
 * Constructors will be as just explained in previous posts.
 * "Virtual functions" are stored directly in their container as function-pointers.
 * Functions can be mapped to other functions without relisting arguments (we can discuss syntax: "func x = y" or "func x(args) = y").
 * Interface functions may have default bodies; Interfaces may also contain data members (stored "by value"), which may have default values. This might result in the "func" keyword being required in interfaces again though.
 * CONSIDERATION: I'd like to remove "anonymous members" from structs, and instead (1) Allow datatype names to be used as variable names, and (2) Have structs automatically "inherit" the properties (i.e. members and functions) of ALL their inner members (with any conflicts having to be resolved explicitly):

Code: [Select]
// OLD:
struct A { int x, y; }
struct B { A; int y; }
b := B(A(1,2),3);
// b.x == b.A.x == 1
// b.A.y == 2
// b.y == 3

// NEW:
struct B { A A; int y; }
// ...Everything else is the same
Title: Re: Antelope (formerly "OPIA") - A Polymorphic z80 language
Post by: shkaboinka on October 17, 2014, 02:28:01 am
... So it's been quite a while (getting married, having two kids, and a dog, and starting a career tends to change priorities), but I've been keeping this project going occasionally, and paying a lot more attention to it in recent months. There have been LOTS of changes (again), and I've been posting on Cemetech and made lots of updates to the language grammar tinyurl.com/z80antelope (though everything else is way out of date). Maybe sometime I'll post a synopsis of what has changed, and bring this thread back life, too!

Anyway, I do intend to (eventually) finish this, and at least have fun along the way discussing and sharing my thoughts/adventure in programming language design :)
Title: Re: Antelope (formerly "OPIA") - A Polymorphic z80 language
Post by: Matrefeytontias on October 18, 2014, 08:53:42 am
Wow, that's a lot of change O.O

Nice to see you back on it, do you have any idea when we will be able to generate a simple executable written in Antelope ?

Also, do you think this could be used to write KnightOS programs ? That would be awesome !
Title: Re: Antelope (formerly "OPIA") - A Polymorphic z80 language
Post by: DJ Omnimaga on November 04, 2014, 01:36:17 am
It's nice to see you back indeed. Also congrats on getting married and the carreer stuff. :) Also Matref brings up a good point. On TI-OS, it will be very hard to compete against Axe, TI-BASIC and ASM (even C can barely even do it), but KnightOS lacks a programming language for now, as far as I know, so this could be a good opportunity to make Antelope KOS-compatible. Of course, TI-OS compatibility would be nice too for a bigger audience.
Title: Re: Antelope (formerly "OPIA") - A Polymorphic z80 language
Post by: Scipi on November 05, 2014, 12:15:58 am
I was wondering a few months ago what became of this. Great to hear it's still alive!
Title: Re: Antelope (formerly "OPIA") - A Polymorphic z80 language
Post by: aeTIos on November 08, 2014, 09:38:09 pm
Great to hear this isn't dead. I'm still quite excited to see how programming in this language is gonna be :)
Title: Re: Antelope (formerly "OPIA") - A Polymorphic z80 language
Post by: shkaboinka on November 02, 2017, 04:04:36 pm
Great to hear this isn't dead. I'm still quite excited to see how programming in this language is gonna be :)

I regret to inform that this is dead; but mainly because I have something better.
I hope you'll be excited to see what programming (or computering at all) in a fully-dynamic system is like.

To save time, I'm going to paste what I've said elsewhere about the end of Antelope and the start of SomethingNew (2 posts).





(Pasted from elsewhere):

Sorry for abandoning this, especially after all that went into it. This is mainly because life happened. However, there is much learning/thought to reflect on; so here are some of my reflections:

1. Top features I've identified that I'd love to have in a language:
A  - First-order functions & lambda syntax (C# linq queries simplify even further!)
B - Functions that can yield values and resume from the same point (aka "coroutines", "generators", or C#'s "enumerators").  My "cofunctions" (not the same as the mathematical term) took this a step further by reifying the function-object ("functors" in other languages) allowing direct inspection/mofification of the entry-points and current "position", and also letting these function-objects to be emedded within other objects with full access to other members and vice versa.
C - Code that is interpreted / pre-compiled at compile time. I found this is BEST done in terms of all the built-in language features, rather than providing a separate syntax/language JUST for interpreted code. LISP does this by allowing macros that have the full power of the full language & other code. The D language does this very well by allowing meta-operations on the code using regular D code itself.
D.i - Use of "interfaces" to allow objects of ANY type to be used somewhere, so long as it has the correct members (Google's "Go" does this well). This provides the feel of dynamic "duck" typing, but with compile-time static type-checking.
D.ii - Ability to provide "default" members of interfaces.
E - "Traits" - that is, reusable blocks of code (object definitions) that can be combined statically, but WITHOUT introducing an inheritance relationship; it's just a clean mechanism for code-reuse. Traits are more refined than "Mixins", because you have full control over how to resolve conflicting names when combining multiple traits, and you can also map things differently (e.g. use a trait that provides behavior X and requires behavior Y, but provide "Z" in place of Y, or take X but call it "W"). Scala's "traits" are actually Mixins, because they do NOT allow any control over mappings, and they manipulate runtime inheritance hierarchies rather than combine code statically.
F - Reflection using "attributes" (as in C#; "annotations" in Java). This essentially treats the parts of a program like objects, allowing you to attach custom properties and behaviors to parts of the AST (e.g. to a "class"), without any impact on the RUNTIME entities that the relate to. In C#, this is done by creating runtime representations of everything (e.g. you can inspect classes and their members dynamically at runtime); but I was having this all be accessible at RUNTIME. That is code, code that can manipulate / be conditional on other code at compile-time. The D language does this very well. Languages that are self-hosting ("bootstrapped") like LISP or REBOL do not NEED reflection, because everything is already in the same "layer".
G - Default arguments for functions. My special technique for this is to insert the assignments of default values as extra instructions at the top of the function, and have multiple entry points in the function. To use all defaults, the function is entered at the "top"; when one default value is overridden, the function is entered "after" that default assignment. This not only saves code space, but allows the function to be referenced as EVERY sub-set of function type by referring to the correct entry point (e.g. F(A, B=X) is an F(A) and an F(A,B)). C# handles defaults by manually inserting the default values at all the call-sites, which means that the calling code can be "wrong" if the actual function-definition is separately recompiled with different defaults.
H - Function closures. I accomplished this through the "cofunction" implementation (B), though I had decided to remove them as an explicit language feature and instead have the compiler "detect" when to use them. That is, any function declared inside another function or class that references contextual data would automatically create a function-object to track it (or embed this data in the parent object, as applicable).
I - Generalization between functions and methods. Most languages do this by making methods a generalization of functions (e.g. the D language) by having the "this" argument count as the "first" argument (e.g. an O.F(A,B) is also an F(O,A,B)); but I did this by making functions a generalization of methods (e.g. an F(A,B) is also an <null>.F(A,B)) by reserving a special register (IX for z80) for passing the "this". This allows something that takes an F(A,B) to take an O.F(A,B) (JavaScript allows this by resolving "this" separately the function arguments). This also ties into J:
J - Generalizing all aspects of a source program into an object model. That is, a "class" and its static members are actually stored as an "object" which can be passed around or even inherit from other classes. Namespaces (including the default one) are also objects like this, and so all global/namespace-level declarations are members of some object (and thus all functions are "methods" -- but the passing of "this" is optimized out of the compiled code, because the allocation of these namespace "objects" is statically determined and thus so are it's members). This also allows one to define the namespace of a whole program (or part of one) to inherit from another class or compose traits into it, thus bringing OOP facilities to the level of the whole program.

...The above started as a 3 item list of 3 sentences. I forgot how much I put into this!...

2. I'm glad to see other languages/tools available, even though I didn't finish this one.
When I started, there was NOTHING like this, and mostly I really wanted to introduce a more general/full/open-ended language than the built in TI-BASIC (without assembler being the only other choice) so that others could experience the joy of programming on a fully-programmable device that is accessible to many. ... But since then, there is AXE, GRAMMER, and perhaps others, and that makes me happy and reduces my urgency. Big props to Xeda and Kevin for that!

3. ...I've had a bit of a perspective change on "language", which makes it hard to want to invest too much into one. I've been following past/present key figures such as Jim Coplien, Rich Hickey, Bret Victor, Alan Kay, Christopher Alexander, Richard P Gabriel, etc. (I actually found a GOLD MINE (http://www.ybrikman.com/writing/2014/05/29/must-see-tech-talks-for-every-programmer) with lots of videos from many of these guys), and traced some of the roots of OOP and modern software paradigms to their origins to find that much of current view of what software & programming is, is a reduced form of a once grander picture. I've been one of many to try to find the next better language, paradigm, tools, etc. ... but this is just the software culture chasing its own tail. What needs to change is how software ITSELF is thought of, and the tools we use to do that cannot do that for us. My first wake-up call was recognizing this delimma as called out by Jim Coplien (http://www.infoq.com/interviews/coplien-dci-architecture) (and it took a year of study to for me to finally see what he's talking about), but Bret Victor (https://vimeo.com/71278954) does an excellent job of pointing this out (and demonstrating one way (https://vimeo.com/36579366) this could change), as does Rich Hickey (http://www.infoq.com/presentations/Simple-Made-Easy) (especially if you consider his statements of simple representation in a GENERAL sense, rather than just promoting functional programming or Clojure), and Alan Kay (https://www.youtube.com/watch?v=FvmTSpJU-Xc) has a lot to say, but is very abstract. ... You cannot language or unit-test or TDD or tool your way into good software design; you have to think about software design itself, which means understanding HUMAN models of software. THAT should shape language & programming paradigm, but instead the software industry has let the opposite happen. ... places like THIS do a lot of good though in supporting open-ended exploration & learning; but there are nonetheless some DEEPLY ingrained views that come with being a programmer nowadays, and a lot of it is upside-down, but it's hard to change or even challenge.

... I see a world of software in which "language" becomes a malleable thing that can be adapted and mixed selectively or on the fly, rather than as a rigid distinction between one language or another. Ideally, you want to be able to create whatever software you want using whatever paradigms and language tools you want, without having to have had someone package it up into this static thing called a "language". Less like choosing between Legos or K'nex and more like being free to use any of all of paint, markers, crayons, pencils, charcoal, clippings, staples, glue, etc. etc. on your paper, and not even being limited to those things, or even to paper.



A lot of this was me trying to make the "perfect" general purpose language, and I was never satisfied with it 100%, so it never got done. Now that I have kids and a career, I see no priority for something this big; though I enjoy the discussion, and maybe someday I will use these ideas somehow. I've also had some changes of heart as to what to pursue in software, it's put me off of pursuing "language" too strongly. It's like Jim Cope says about language (http://www.infoq.com/interviews/coplien-dci-architecture).

Anyway, I'm still all about the ideas, but I have nothing to offer beyond that at this time.

As for "the old one" (I assume you are talking about Antidisassemblage / SquirrelBox), yes that was a precursor. It was largely a first-time crash-course attempt at a language & compiler (which I'm still somewhat proud of); but over time I've learned that I could do SO much better! ... But I don't know if it will come to be in any time span that anyone is willing to wait for.

Anyway, I'll add further thoughts to my previous post (which I left "in progress")

Thanks for following my work though!





If anyone is interested in what I "moved on" to, here it is: https://github.com/d-cook/Objects

The idea is a software system that escapes the rigid boundaries of traditional languages and software tools, by empowering the end-user to create whatever things & behaviors they desire. It will act as a tool with a UI for creating and manipulating data & code in the form of objects, including all parts of the system itself (interpreter, UI, etc.). This will work the system will be made out of the same components that it edits, which can all be live-edited.

One idea for how this can be used is to replace traditional software development (code in language-X, depends on compiler- or IDE-Y, etc.), a software project can be its own self-contained tool that is its own editor, compiler, and UI for whatever software is being developed. All these pieces can be used on each other, and you can thus create the ideal everything (language, UI, etc.) for the thing being developed, and it's all just part of "the code". And it need not be uniform through-out (e.g. a chunk of code that contains its own interpreter or UI just for that part). That is one example, but the possibilities are endless.

...

Beyond that, as I am not the only one doing "this kind of stuff" (https://programmingmadecomplicated.wordpress.com/2017/08/13/language-isnt-everything/), I've actually formed a collaboration with others who are seeking to redefine software in similar ways. Check it out (it has its own brief explanation / history): https://github.com/d-cook/SomethingNew

Edit (Eeems): Merged triple post
Title: Re: Antelope (formerly "OPIA") - A Polymorphic z80 language
Post by: Xeda112358 on November 04, 2017, 09:55:09 am
I'll be honest, I have no clue what a lot of that means. I've played with OOPLs here and there, but I've never managed to really "get it." However, I know for many programmers it is more natural and it would be cool to have such a language available on the (e)Z80 calculators.

I totally get being busy, but maybe you'll be lucky enough to pull a JamesV and come back in ten years with renewed energy/time/motivation.
Title: Re: Antelope (formerly "OPIA") - A Polymorphic z80 language
Post by: shkaboinka on November 17, 2017, 02:30:10 pm
It's hard to explain the whole thing, but I can explain what I mean by escaping "language" (or at least escaping compiled language):

Instead of writing a program in language-A or language-B and being limited to using only the features of one language, you should instead be able to mix and match whatever language features you want, even ones that you create yourself. Or you should be able to modify those features just for your program. So how do you do this?

Instead of using (or writing) a compiler for some language, you write your own program to generate the program you want. This would be more doable if you take the code that normally would be in a compiler, and instead make it part of a library. A compiler creates structural representations (AST) of the code that it compiles, so instead the library would be a tool to build parts of that representation and give them back to you. You could then modify them, or create your own somehow; and then you hand them back and say "ok, build the program from these".

Think of uncompiled source code (written in a compiled-language) as a program that makes an executable program, and the compiler as the interpreter of that program. When viewed in this way, declarations within code (classes, functions, variables) act as imperative commands to create components of a program. Replacing these "commands" with an API & user-defined functions would allow programs to be generated with any components & mechanisms, rather than from a fixed set of "language features". No more language restrictions!

::instead of this:: class Foo { Bar b }
::you write this:: myClass = MakeClass("Foo"); myClass.AddMember("b", myBarClass)

::another example:: myTrait = new MyVeryOwnTraitsImplementation("ResizableThing"); myTrait.ApplyTo(myClass)

This is what makes languages like JavaScript so powerful: many things that are "declarations" in other languages are actually imperative calls to user-defined functions. This is why people have been able to make so many different kinds of object-models (etc.) in it. This makes things like compiler hooks and reflection mostly obsolete.

----

Now you might notice that the program that is generated by your program has whatever features and structure you want; but what about the program that did the generating; what language is that written in? Two possible answers are:
(1) It doesn't really matter, so long as you can generate whatever you want from it.
... However, since it just has to "run" once, it is more important for that code to have good expression than for it to be efficient, and that screams "interpreted language". Also, why would you want to have your source program, feed it into another program called a compiler, which generates an executable program, which you run to have it generate the program that you care about? Why not just run an interpreted program that generates the output program? So though it really does not matter what language the program-generating-program is written in, a compiled-language has no gain here, but the advantages of an interpreted language do apply.
(2) The only other option is to "close the loop" with some meta-circularness. That is, a software system or tool that is self-defining, self-modifying, etc., which is only possible if everyrthing (interpreter, code structure, etc.) is accessible at runtime. That is what my Objects (https://github.com/d-cook/Objects) project is about, except that it will do more than just that (e.g. a UI through which all things can be viewed or changed at runtime by the user, including the workings of the UI itself).