Author Topic: Antelope (formerly "OPIA") - A Polymorphic z80 language  (Read 47510 times)

0 Members and 2 Guests are viewing this topic.

Offline shkaboinka

  • LV3 Member (Next: 100)
  • ***
  • Posts: 86
  • Rating: +10/-1
    • View Profile
    • Antelope (polymorphic z80 language)
Re: OPIA - A full OOP language for z80
« Reply #75 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).
« Last Edit: February 14, 2012, 02:35:40 am by shkaboinka »

Offline shkaboinka

  • LV3 Member (Next: 100)
  • ***
  • Posts: 86
  • Rating: +10/-1
    • View Profile
    • Antelope (polymorphic z80 language)
Re: OPIA - A full OOP language for z80
« Reply #76 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.)
« Last Edit: February 16, 2012, 12:20:01 am by shkaboinka »

Offline DJ Omnimaga

  • Clacualters are teh gr33t
  • CoT Emeritus
  • LV15 Omnimagician (Next: --)
  • *
  • Posts: 55943
  • Rating: +3154/-232
  • CodeWalrus founder & retired Omnimaga founder
    • View Profile
    • Dream of Omnimaga Music
Re: OPIA - A full OOP language for z80
« Reply #77 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"?

Offline shkaboinka

  • LV3 Member (Next: 100)
  • ***
  • Posts: 86
  • Rating: +10/-1
    • View Profile
    • Antelope (polymorphic z80 language)
Re: OPIA - A full OOP language for z80
« Reply #78 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
« Last Edit: February 16, 2012, 05:38:30 am by shkaboinka »

Offline Quigibo

  • The Executioner
  • CoT Emeritus
  • LV11 Super Veteran (Next: 3000)
  • *
  • Posts: 2031
  • Rating: +1075/-24
  • I wish real life had a "Save" and "Load" button...
    • View Profile
Re: OPIA - A full OOP language for z80
« Reply #79 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 :)
« Last Edit: February 16, 2012, 05:17:11 am by Quigibo »
___Axe_Parser___
Today the calculator, tomorrow the world!

Offline BlakPilar

  • LV8 Addict (Next: 1000)
  • ********
  • Posts: 734
  • Rating: +44/-1
    • View Profile
Re: OPIA - A full OOP language for z80
« Reply #80 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.

Offline shkaboinka

  • LV3 Member (Next: 100)
  • ***
  • Posts: 86
  • Rating: +10/-1
    • View Profile
    • Antelope (polymorphic z80 language)
Re: OPIA - A full OOP language for z80
« Reply #81 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? :)

Offline BlakPilar

  • LV8 Addict (Next: 1000)
  • ********
  • Posts: 734
  • Rating: +44/-1
    • View Profile
Re: OPIA - A full OOP language for z80
« Reply #82 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?

Offline shkaboinka

  • LV3 Member (Next: 100)
  • ***
  • Posts: 86
  • Rating: +10/-1
    • View Profile
    • Antelope (polymorphic z80 language)
Re: OPIA - A full OOP language for z80
« Reply #83 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?

Offline BlakPilar

  • LV8 Addict (Next: 1000)
  • ********
  • Posts: 734
  • Rating: +44/-1
    • View Profile
Re: OPIA - A full OOP language for z80
« Reply #84 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).

Offline shkaboinka

  • LV3 Member (Next: 100)
  • ***
  • Posts: 86
  • Rating: +10/-1
    • View Profile
    • Antelope (polymorphic z80 language)
Re: OPIA - A full OOP language for z80
« Reply #85 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};
« Last Edit: March 22, 2012, 02:08:31 pm by shkaboinka »

Offline shkaboinka

  • LV3 Member (Next: 100)
  • ***
  • Posts: 86
  • Rating: +10/-1
    • View Profile
    • Antelope (polymorphic z80 language)
Re: OPIA - A full OOP language for z80
« Reply #86 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).
« Last Edit: March 24, 2012, 06:49:37 pm by shkaboinka »

Offline shkaboinka

  • LV3 Member (Next: 100)
  • ***
  • Posts: 86
  • Rating: +10/-1
    • View Profile
    • Antelope (polymorphic z80 language)
Re: OPIA - A full OOP language for z80
« Reply #87 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]
« Last Edit: March 26, 2012, 09:22:50 am by shkaboinka »

Offline NanoWar

  • LV4 Regular (Next: 200)
  • ****
  • Posts: 140
  • Rating: +18/-6
    • View Profile
Re: OPIA - A full OOP language for z80
« Reply #88 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! :)

Offline DJ Omnimaga

  • Clacualters are teh gr33t
  • CoT Emeritus
  • LV15 Omnimagician (Next: --)
  • *
  • Posts: 55943
  • Rating: +3154/-232
  • CodeWalrus founder & retired Omnimaga founder
    • View Profile
    • Dream of Omnimaga Music
Re: OPIA - A full OOP language for z80
« Reply #89 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.