This fixes the ICE when attempting to compile address-cast without
optimization (just realized why, too: the assignment was optimized out
of existence).
This the fixes the incorrect flow analysis caused by the def being seen
to have the wrong size (structure field of structure def seen through a
constant pointer). Fixes the ICE, but the pointer constant is broken
somewhere in dags, presumably.
This fixes the problem of using nil for two different compound types
within the one expression. The problem is all compound types have the
same low-level type (ev_invalid) and this caused the two different nils
to have the same type when taken back up to expression level.
While expression symbols worked for what they are, they weren't so good
for ivar access because every ivar of a class (and its super classes)
would be accessed at method scope creation, generating spurious access
errors if any were private. That is, when the access checks worked at
all.
The end goal was to fix erroneous non-constant initializer errors for
the following (ie, nested initializer blocks):
typedef struct { int x; int y; } Point;
typedef struct { int width; int height; } Extent;
typedef struct Rect_s { Point offset; Extent extent; } Rect;
Rect makeRect (int xpos, int ypos, int xlen, int ylen)
{
Rect rect = {{xpos, ypos}, {xlen, ylen}};
return rect;
}
However, it turned out that nested initializer blocks for local
variables did not work at all in that the relocations were lost because
fake defs were being created for the generated instructions.
Thus, instead of creating fake defs, simply record the offset relative
to the base def, the type, and the basic type initializer expression,
then generate instructions that all refer to the correct def but with a
relative offset.
Other than using the new element system, static initializers are largely
unaffected.
This is for adding methods to classes and protocols via their interface,
not for adding methods by adding protocols (they still get copied).
Slightly more memory efficient.
Copying methods is done when adding protocols to classes (the current
use for adding regular methods is an incorrect solution to a different
problem). However, when a method is added to a class, the type of its
self parameter is set to be a pointer to the class. Thus, not only does
the method need to be copied, the self parameter does too, otherwise
the self parameter of methods added via protocols will have their type
set to be a pointer to the last class seen adding the protocol.
That is, if, while compiling the implementation for class A, but the
interface for class B is comes after the interface for class A, and both
A and B add protocol P, then all methods in protocol P will have self
pointing to B rather than A.
@protocol P
-method;
@end
@interface A <P>
@end
@interface B <P>
@end
@implementation A
-method {} // self is B, not A!
@end
Duplicate methods in an interface (especially across protocols and
between protocols and the interface) are both harmless and even to be
expected. They certainly should not cause the compiler to demand
duplicate method implementations :)
This is actually a double issue: when a class implementing a protocol
used the protocol in @protocol(), not only would the protocol get
emitted as part of the class data specifying that the class conforms to
the protocol, a second instance would be emitted again when @protocol()
was used. On top of that, only the instance referenced by @protocol()
would be initialized. Now, both class emission and @protocol() get their
protocol def from the same place and thus only one, properly
initialized, protocol instance is emitted.
The problem was an erroneous assumption that the methods had to be
defined. Any class implementing a protocol must implement (and thus
define) the methods, but a protocol declaration cannot: it merely
declares the methods, and it's entirely possible for a module to see
only the protocol definition and not any classes implementing the
protocol.
Unlike gcc, qfcc requires foo to be defined, not just declared (I
suspect this is a bug in gcc, or even the ObjC spec), because allowing
forward declarations causes an empty (no methods) protocol to be
emitted, and then when the protocol is actually defined, one with
methods, resulting in two different versions of the same protocol, which
comments in the gnu objc runtime specifically state is a problem but is
not checked because it "never happens in practice" (found while
investigating gcc's behavior with @protocol and just what some of the
comments about static instance lists meant).
It proved to be too fragile in its current implementation. It broke
pointers to incomplete structs and switch enum checking, and getting it
to work for other things was overly invasive. I still want the encoding,
but need to come up with something more robust.a
This fixes the dependency issues between qwaq and ruamoko. qwaq is
actually older than ruamoko. That little language feature test has come
a long way.
However, I'm considering moving to non-recursive make, but...
It doesn't look good, but it does have panel based windows working, and
using objects. Won't build reliably right now due to qwaq being in tools
and thus building before ruamoko, but I'll fix that next.
It seems that xterm automatically disables it when ncurses shuts down and
mate-terminal does not, or maybe a different version of something. Still,
good to clean up properly.
Now they reflect the curses functions they wrap. The externally visible
builtin names are not changed because the parameters are in x, y order
rather than curses' y, x order.
If the window is invalid and recovery is done, string ids will leak if
acquired before validation.
Afterwards, make the rest of the builtin wrappers consistent: extract
parameters, validate, [acquire resources], generate command.
Now that the initial prototype seems to be working well, it's time to
implement more commands. I might have to do some wrappers for actual
command writing (and result reading) as it looks like there will be a
lot of nearly identical code.
So far, no threading has been set up, and only window creation and
printing have been updated, but the basics of the design seem to be
sound.
The builtin functions now no longer call ncurses directly: the build
commands and write them to a command buffer.
Commands that have return values (eg, window creation) write their
results to a results buffer that the originating builtin function
reads. Builtin functions that expect a result "poll" the results buffer
for the correct result (marked by the same command). In a single
UI-thread environment, the results should always be in the same order as
the commands, and in a multi-UI-thread environment, things should
(fingers crossed) sort themselves out as ONE of the threads will be the
originator of the next available result.
Strings in commands (eg, for printing) are handled by acquiring a string
id (index into an array of dstring_t) and including the string id in the
written command. The string id is released upon completion of the
command.
Builtin functions write commands, acquire string ids, and read results.
The command processor reads commands, releases string ids, and writes
results.
Since commands, string ids, and results are all in ring buffers, and
assuming there is only one thread running the builtin functions and only
one thread processing commands (there can be only one because ncurses is
not thread-safe), then there should never be any contention on the
buffers. Of course, if there are multiple threads running the builtin
functions, then locking will be required on the builtin function side.
I expect I will need several messaging buffers, and ring buffers tend to
be quite robust. Replacing the event buffer code with the macros made
testing easy.
id and z seem to always be 0.
Ironically, it turns out that the work needed for "int id" and "large"
struct nil init wasn't strictly necessary to get to this point, but
without having done that work, I wouldn't know :)
Such declarations were being lost, thus in the following, the id field
never got added:
typedef struct qwaq_mevent_s {
int id;
int x, y, z;
int buttons;
} qwaq_mevent_t;
typedef is meant to create a simple renaming of a potentially complex
type, not create a new type. Keeping the parameter type alias info makes
the types effectively different when it comes to overloaded function
resolution, which is quite contrary to the goal. Does expose some
breakage elsewhere, though.
For technical reasons (programmer laziness), qfcc does not fix up local
def type encodings when writing the debug symbols file (type encoding
location not readily accessible).
The debug subsystem now uses the resources system to ensure it cleans
up, and its data is now semi-private. Unfortunately, PR_LoadDebug had to
remain public for qfprogs because using PR_RunLoadFuncs would cause
builtin resolution to complain.
It is now set to 0 when progs are loaded and every time
PR_ExecuteProgram() returns. This takes care of the default case, but
when setting parameters, pr_argc needs to be set correctly in case a
vararg function is called.
Attempting to define a variable with an incomplete type is an error, and
results in a default size 1 of allocated, but I forgot to set default
alignment when implementing alignment.
The addition of xdef data has made qfo_to_progs unusable in qfprogs,
resulting in various invalid memory accesses. It always was an ugly hack
anyway, so this is the first step to proper qfo support in qfprogs.
I was originally going to put it in the debug syms file, but I realized
that the data persistence code would need access to both def type and
certainly correct def offsets for defs in far data.
This far better reflects the actual meaning. It is very likely that
ty_none is a holdover from long before there was full type encoding and
it meant that the union in qfcc's type_t had no data. This is still
true for basic types, but only if not a function, field or pointer type.
If the type was function, field or pointer, it was not true, so it was
misnamed pretty much from the start.
It was long wrong anyway as it checked past the end of the function's
parameters, which caused a segfault when calling varargs functions with
no formal parameters.
The encoding is 3:5 giving 3 bits for alignment (log2) and 5 bits for
size, with alignment in the 3 most significant bits. This keeps the
format backwards compatible as until doubles were added, all types were
aligned to 1 word which gets encoded as 0, and the size is unaffected.
This fixed the uninitialized temp warning in HUD.r. The problem was
caused by the flow analyzer not being able to detect that the struct
temp was being initialized by the move statement due to the address of
the temp being in a pointer temp. While it would be good to use a
constant pointer for the address of the struct temp or improving the
flow analyzer to track actual data, avoiding the temp in the first place
results in nicer code as it removes a move statement.
With this, cast address initializers work. I have to wonder if the alias
value short-circuit was legacy from long before the rewrite, as it was
quite trivial to handle in the back-end.
All functions are stored in the overload functions table, even those
that are never explicitly overloaded, but only explicitly overloaded
functions (those with @overload) use the type-qualified naming.
Only as scalars, I still need to think about what to do for vectors and
quaternions due to param size issues. Also, doubles are not yet
guaranteed to be correctly aligned.
I plan on adding doubles, and so it's necessary to ensure that attempts
to align doubles in local or far data spaces remain aligned after final
linking.
I added Sys_RegisterShutdown years ago and never really did anything
with it: now any system that needs to be shutdown can ensure it gets
shutdown on program exit, and in the correct order (ie, reverse to init
order).
In order to keep enumerator type and enum type the same, the values need
to have their type set after the enum type is finalized, and then the
appropriate symbols created in the parent scope. This fixes the infinite
recursion when assigning an enum value to its own type.
It turns out the enumerator type and enum type wind up with different
instances of the same type (due to the way type chaining works). This
results in infinite recursion in assign_expr and check_types_compatible.
This is where constant folding should have happened all along. While
unary_expr should fold constants too, it seems to already try to do so
and it's a bit much of a mess to clean up right now.