Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - shkaboinka

Pages: 1 2 [3] 4 5 6
31
TI Z80 / Re: OPIA - A full OOP language for z80
« 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.

32
TI Z80 / Re: OPIA - A full OOP language for z80
« 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"

33
TI Z80 / Re: OPIA - A full OOP language for z80
« 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?

34
TI Z80 / Re: OPIA - A full OOP language for z80
« 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 :)

35
TI Z80 / Re: OPIA - A full OOP language for z80
« 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?

36
TI Z80 / Re: OPIA - A full OOP language for z80
« 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.

37
TI Z80 / Re: OPIA - A full OOP language for z80
« 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).

38
TI Z80 / Re: OPIA - A full OOP language for z80
« 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 (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 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.

39
TI Z80 / Re: OPIA - A full OOP language for z80
« on: April 04, 2012, 12:25:24 pm »
I have updated the 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?

40
TI Z80 / Re: OPIA - A full OOP language for z80
« 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]

41
TI Z80 / Re: OPIA - A full OOP language for z80
« 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!!) :)

42
TI Z80 / Re: OPIA - A full OOP language for z80
« 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]

43
TI Z80 / Re: Core Wars
« on: March 22, 2012, 01:59:06 pm »
I've been thinking of making a game based on this idea: It would involve robots moving around on a grid which would have "instructions" in various locations. The instructions would be collected into a program, which can then be dropped onto the grid as an instruction of it's own. There might be multiple robots that can influence eachother ... I haven't decided the objective though :/

44
TI Z80 / Re: OPIA - A full OOP language for z80
« 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).

45
TI Z80 / Re: OPIA - A full OOP language for z80
« 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};

Pages: 1 2 [3] 4 5 6