Intel sponsors gamedev.net search:   
The Bag of HoldingBy ApochPiQ      
Apoch's Avatar

Apoch
XP: 64,738
Inventory
Special Items: Shpongle | XBox Live
My brain is built of paths and slides and ladders and lasers and I have invited all of you to enter its pavilion. My brain, as you enter, will smell of tangerines and brand-new running shoes.
Page:   1 2 »»

Saturday, August 30, 2008
Unicode
Had a good discussion over the last couple of days regarding Unicode handling in Epoch. As of now my plan for supporting Unicode is to add yet another pass to the lexer/parser system (woohoo for multipass compilation... C++, eat your blackened little heart out).

Essentially, the first pass will read the source code, strip out all Unicode strings, and replace them with ANSI placeholders. This will make it possible to run boost::spirit on the remaining text. The original Unicode text will be preserved in a lookup table, allowing the parser to dump the original Unicode symbols to the user if an error occurs, for example. Aside from that, the main area of support is Unicode-aware string objects, which should be fairly straightforward to implement given the way I've written the StringVariable class.

All that will wait until the future, though, because I'd rather see core language features get done first. It's also a perfect candidate for opening up the project to other programmers with actual Unicode experience, so they can ensure the Unicode handling is robust. In my dream world where everything goes perfectly, another programmer or three will show up and contribute some patches to the open-source project, which enable Unicode support.

Unicode is one of those features that seems like it'd be hard (or impossible) to bolt onto a language post-hoc, but with this plan, I think it should actually be pretty painless.


Flow Control
The break and return functions are now implemented. These builtins do pretty much exactly what you'd expect.

One quirk between Epoch and most languages is that return() accepts no parameters. It assumes that the return values are properly set using the standard return-variable method prior to exiting the function. I might add some syntactic sugar to change this in the future, but for now it seems to be fine. Of course, I also haven't written any nontrivial Epoch software yet, so it may turn out to be very much not fine. We shall see


Structures
As I write this I'm about to go start hacking on structures. Thus far I have a two stage plan: first, refactor the Tuple code to use a base class, CompositeType. Then, extend CompositeType to support both tuples and structures. Once structs are done, we're looking at a nice shiny Release 4.


Release 4
R4 is easily going to be the biggest jump forward in Epoch's progress yet. The power of the language has increased so dramatically it's kind of hard to really grasp. This thing is growing faster than I ever expected, and it's great to watch the project balloon into something that I'd actually love to code in.

I continue to make small tweaks every now and then to various things like the syntax error response mechanisms. For instance, a lot of errors are currently fatal that should be recoverable by the parser; this allows the parser to report multiple syntax errors instead of just stopping at the first one it sees. So far the syntax error handling is pretty precise and usually very informative, so I'm happy about that. One thing I've always hated about C/C++ is the habit of compiler writers to leave very cryptic syntax errors.

Of course, Epoch is also deliberately designed to be easy to parse, which is very much unlike C++ - so, to be fair, I've got a much simpler job


I still hope to get R4 out in the next couple of days. Hold on to your pants!



Status Report - 0054 hours
The basics of structures are now in place. The two big pieces remaining are the padding logic (which should be easy) and logic to pass pointers to structures to external APIs, mainly the Win32 API. That one isn't going to be so simple I suspect; but it shouldn't prove too difficult.

I think I'm going to cash in for the night, so these additions will probably come later on over the weekend. As soon as those two things are done, I'll start tying up loose ends and prepping for R4.

Comments: 0 - Leave a Comment

Link


Took a few minutes this evening and hacked in while loops to the Epoch language. This is the second loop type, following up do/while loops which have been in for quite some time.

Part of implementing a while loop correctly involves elegantly skipping the loop body's instructions when the condition evaluates to false on the first iteration. In order to get this, I built in a new result value that is returned from every operation; this value acts as a flow control sentinel.

Any operation is free to modify this sentinel, although only one currently does, and that is a helper operation that while loops use to check their conditions. When the sentinel value is set appropriately, the currently executing loop will exit. This can also be extended trivially to allow early function returns.

The upshot is that break and return keywords will be laughably easy to implement, which I will probably do sometime tomorrow. This will significantly improve the power and flexibility of the language.

In addition, this mechanism should make it pretty simple to implement stack unwinding when it comes time to implement exceptions.


For the technically curious, here's a simple demo program and the VM bytecode it generates:

//
// FLOWCONTROL.EPOCH
//
// Demonstration of basic flow control elements in Epoch
//

entrypoint : () -> ()
{
	integer(foo, 10)

	while(greater(foo, 0))
	{
		debugwritestring(cast(string, foo))
		assign(foo, subtract(foo, 1))
	}
}


00887A5C SCOPE
PARENT 00000000
STACK 0
ISCLONE 0
VARS 0
GHOSTS 0
FUNCTIONS 1
entrypoint 0088F328
0088EF90 SCOPE
PARENT 00000000
STACK 0
ISCLONE 0
VARS 0
GHOSTS 0
FUNCTIONS 0
TUPLETYPES 0
TUPLEHINTS 0
0088F020 TYPEDATA 0
0088EBC0 SCOPE
PARENT 00000000
STACK 0
ISCLONE 0
VARS 0
GHOSTS 0
FUNCTIONS 0
TUPLETYPES 0
TUPLEHINTS 0
0088EC50 TYPEDATA 0
BLOCK
00C803F8 SCOPE
PARENT 00887A5C
STACK 0
ISCLONE 0
VARS 1
foo 1
GHOSTS 0
FUNCTIONS 0
TUPLETYPES 0
TUPLEHINTS 0
00C80488 TYPEDATA 0
00C81088 PUSH_INT 10
00C81110 WRITE foo
00C808C0 WHILE
BLOCK
00C811A0 SCOPE
PARENT 00C803F8
STACK 0
ISCLONE 0
VARS 0
GHOSTS 0
FUNCTIONS 0
TUPLETYPES 0
TUPLEHINTS 0
00C81230 TYPEDATA 0
00C809E8 PUSH 00C817C0 READ foo
00C81BA8 PUSH_INT 0
00C81628 PUSH 00C815E0 GT
00C810D0 CONDITIONAL_BREAK
00C81BF0 PUSH 00C816D0 READ foo
00C81990 PUSH 00C81718 INT_TO_STRING
00C81520 DEBUG_WRITE
00C81B58 PUSH 00C81EE8 READ foo
00C82268 PUSH_INT 1
00C819D8 PUSH 00C81DC0 SUB_INT
00C80878 WRITE foo
ENDBLOCK
ENDBLOCK
TUPLETYPES 0
TUPLEHINTS 0
00887AEC TYPEDATA 0
STATIC_STR_POOL 2
10 entrypoint
3 foo
VAR_STR_POOL 0
TUPLEINFO
IDCOUNTER 0
0


The interesting bits are as follows:

BLOCK
...
00C809E8 PUSH 00C817C0 READ foo
00C81BA8 PUSH_INT 0
00C81628 PUSH 00C815E0 GT
00C810D0 CONDITIONAL_BREAK
00C81BF0 PUSH 00C816D0 READ foo
00C81990 PUSH 00C81718 INT_TO_STRING
00C81520 DEBUG_WRITE
00C81B58 PUSH 00C81EE8 READ foo
00C82268 PUSH_INT 1
00C819D8 PUSH 00C81DC0 SUB_INT
00C80878 WRITE foo
ENDBLOCK


This snippet of bytecode is the while loop body. Note the READ and PUSH_INT instructions at the top; these are the parameters to the greater function, which is a builtin invoked by the GT instruction.

The greater function will leave a boolean value on the stack: true if foo is greater than 0, false if not. This boolean value is then read off the stack by the CONDITIONAL_BREAK instruction. If the boolean is true, the loop body executes. Otherwise, the flow control sentinel flag is set to the "break" value, the loop body is skipped, and the loop itself is exited.


I consider this a fairly clean implementation since the VM is not technically a von Neumann architecture - code and data do not share memory space in the VM environment. In fact, code instructions do not have memory addresses like they would on a typical von Neumann system. This means that simple goto or jmp style instructions are impossible, since we can't specify a destination address.


So there's your daily peek into the progress and inner workings of Epoch

Release 4 is more or less on track; I've been distracted by the while loop stuff today, so structures aren't quite done yet. But it should still be easy to get them done over the long weekend. Definitely look for R4 sometime next week at the latest.

Comments: 1 - Leave a Comment

Link



Thursday, August 28, 2008
Much to my chagrin, I realized earlier this evening that tuple members are being stored backwards in memory.

This is because of some laziness on my part in the grammar. Function parameters are passed in reverse order (i.e. the first parameter gets pushed onto the stack first, and the last parameter therefore has the lowest stack address). And, since constructing a tuple is handled by a function, it gets its members in backwards order.

I actually ran into the problem earlier, and thought I'd fixed it - but then it occurred to me that my fix had been to read tuple members backwards, rather than to fix the function parameter side of things.

So my project for tonight is to readjust the grammar (or, more likely, just put a hack in the parser) so that it effectively passes parameters in reverse order when a tuple or struct is being constructed. This will ensure that the memory layout of tuple/struct members matches the layout specified in the type definition.


Aside from that, I've implemented equality/inequality checks for tuples/structs, which currently by default does a by-member comparison. I also did some random tinkering about which I can't remember the details of offhand; but rest assured that something got improved


Status report - 0025 hours
Got the reversed order finished and working nicely. Along the way I squished a nasty bug that was causing weird behaviour with strings; it was vaguely related to undefined/uninitialized values on the stack. The technical details aren't really interesting unless you've been digging real deep into the Fugue code.

This leaves structure support and some error message cleanup as the main things left before Release 4 is ready. I'm going to go ahead and try to fix the error messages tonight before bed, since it should go pretty fast.

With any luck I'll be able to get structs finished this weekend, so expect R4 sometime around Sunday or Monday night.

Comments: 0 - Leave a Comment

Link


Tuples are most of the way implemented in Epoch now. I'm continually (and pleasantly) surprised by how much easier it is to do things than I would have guessed. Thus far most of the language features have taken far less time to implement than I would have predicted.

So either I'm making a monumental number of mistakes, or I've finally spent enough time in the programming world to really grok how languages work under the skin. Either way, the last time I did a language (a simple scripting language) it took a lot more effort and stress.


I'm sure you're all on the edges of your seats waiting to find out what tuples look like in Epoch. Well, here you go - a nice shiny example program from the upcoming Release 4 distribution:

//
// TUPLES.EPOCH
//
// Simple demonstration of how to use tuple types in Epoch
//

tuple demotype : (integer(intvalue), string(strvalue))

entrypoint : () -> ()
{
	demotype(test, 0, "")
	assign(test, foofunction())

	debugwritestring(cast(string, readtuple(test, intvalue)))
	debugwritestring(readtuple(test, strvalue))
}

foofunction : () -> (integer(intvalue, 0), string(strvalue, ""))
{
	assign(intvalue, 42)
	assign(strvalue, "test")
}



There's a few odds and ends left to polish up (you can't do much with tuples aside from read values out of them; equality comparisons don't work yet, for example) but the bulk of the grunt work is finished.

The next phase is to implement structures. As I noted before, the main difference between a tuple and a structure in Epoch is that a structure is automatically padded, whereas a tuple is automatically packed. (That, and structures will use the structure keyword instead of the tuple keyword.)


Once that stuff is done, I'll be making a last pass over the code to take care of some assorted TODOs and improving a handful of error messages. (It's not really useful to have your program die with the cryptic "Not implemented" error, for instance.)


For now, though, I'm just stoked that the basics of tuples are all in place. I'm also quite tired, and I need to quit staying up late to hack on this project. It's just too much fun

Comments: 3 - Leave a Comment

Link



Wednesday, August 27, 2008
I had a quick ponder earlier today about what all would be necessary in order to write a full Win32 app in Epoch.

Structures are obviously very widely used, so I've been planning on doing them for one of the next releases for quite a while. However, something I overlooked was function callbacks. I'll need to implement a way to tell the Win32 API to call back into Epoch code.

Thankfully, because of the way the Windows message pump system works, I don't have to worry too much about re-entrancy in the VM; but I won't get into the technical details of that for now. Suffice it to say that actually getting a callback and responding to it are fairly trivial.

What's not so simple is handling parameter passing and return values. The callback mechanism will have to properly read the parameters sent in by the caller, and properly return a value back.

Problem is, Epoch runs in a virtual machine at the moment; so there will have to be some kind of marshalling layer that allows the user to define a function signature, define a function matching that signature, and then pass off the function's address for use as a callback.


What I realized, after thinking about this briefly, is that the obvious solution is to implement first-class functions first, because stuff like lambdas and higher order functions will need pretty much the exact same infrastructure as callbacks. Once first-class functions are finished, adding the callback system should be trivial.


So yet again my Epoch roadmap gets discarded, in favor of a totally new one:

  • Release 4 - improved syntax error handling, serialization, tuple and structure support

  • Release 5 - First-class functions

  • Release 6 - callbacks and the Scribble application


(As an aside, it feels great to be able to change the project's scheduling on a whim. Sure beats working under deadlines )


You may wonder, if you are in fact paying attention and not just skimming my journal looking for pretty pictures, what the difference between tuples and structures will be. Both pretty much are an ordered sequence of variable members, right?

Well, there's one minor hangup there - padding. Tuples in Epoch are unpadded, which means that some members might sit on awkward memory boundaries. It also makes tuples unsuitable for direct passing to external APIs, which usually expect padded structures. So a structure is basically equivalent to a tuple except a structure can include padding.

Implementing member padding will undoubtedly be a little sticky, but I should be able to manage.


You may also have noticed (again, presuming that anyone reads this muck) that I've moved structure/tuple support up to R4 instead of R5.

This is because the main goals of R4 were already done (namely, syntax error handling improvement, and serialization) but the release didn't really add much of interest to the language. Plus, it seemed rather wasteful to drop an entire release so soon after R3, over some fairly minor tweakings.

I also got inspired and half-finished tuples last night in a caffiene-fuelled blaze of glory, which is the main reason they got moved up to R4. Heh.



Epoch is already a project I can be proud of, and it's barely got a fraction of the functionality I have planned for it. I'm really looking forward to reaching a point where people can start using the language for real-world app implementations and such.

Comments: 1 - Leave a Comment

Link



Tuesday, August 26, 2008
Had a few spare minutes today, so I hacked up serialization and got it finished. Turns out it was a lot quicker of a job than I expected.

I also decided not to serialize directly to a binary format. Instead, the serialization process outputs an assembly language file that targets the Fugue virtual machine. Eventually, I'll write an assembler to convert that to a binary form; after that, all I need is a deserializer to load the binary bytecode back up into the VM, and I'll be all set to start distributing executable Epoch binaries.

Release 4 was supposed to basically be the serialization and disassembler tool; serialization is done and the disassembler is no longer necessary. So instead I'm taking some time to shore up the syntax error handling and get things working nicely.

Thus far I've fixed several cases where the parser would detect a syntax error, then get stuck in an infinite loop and perpetually report the same error over and over again. I'm also working on minimizing the number of errors that are fatal - that is, the parsing phase should do as much parsing as it possibly can, and report every error it detects. This means you don't have to re-compile your programs 50 times because you keep finding new errors.


I expected my little release roadmap to end up being more or less useless, but I didn't think it would happen this fast So here's a revised roadmap:

  • Release 4 - serialization to assembly language, improved syntax error handling, some new library functions

  • Release 5 - support for tuples and structures; Scribble demo app


Past that I haven't really thought of anything; I don't want to get too far ahead of myself. Besides, I expect that during the Scribble project I'll find plenty of things that need to be done, so R5 will probably guide me a long way towards what is needed in R6 and beyond.

That said, I still have a rough idea of what all I'd like to add to the language before I consider it finished:

  • Garbage collection

  • Manual memory management and pointer support

  • First-class functions and higher order functions

  • Some kind of object/message-passing model

  • Transparent, first-class multiprocessing support

  • At least one port to another platform



Definitely a lot of work ahead... but I'm enjoying the hell out of this project so far, so I don't suspect that the workload will be too much of a problem

Comments: 2 - Leave a Comment

Link



Monday, August 25, 2008
Alright, ladies and gents, it's time to clip the big red ribbon and unveil Epoch Release 3.

Included in today's festivities are a fully stack-based virtual machine, numerous tweaks and improvements to built-in functions, and a couple of back-stage odds and ends that you probably won't notice unless you haul out a copy of diff.

We're also proud to announce that we just got a nice, shiny new shipment of actual documentation. We've sprinkled it liberally around the Fugue source code for your enjoyment and edification.

So step right up, step right in, take this sum-bitch for a spin!


Epoch Release 3 - RAR, 148KB


Comments: 0 - Leave a Comment

Link


Had a quick hack on Fugue again this afternoon, and finally got everything working the way it should be with regards to the stack. One case I had missed was recursion; because of the way the bytecode is stored, it was possible for a recursive function to obliterate its parent call's stack information, thus leading to weird behavior.

That was easily fixed by being sure to clone the parameter and return variable information immediately prior to invoking the function. In other words, we went from having a shared stack frame descriptor for every function invocation, to having a unique descriptor copy for each invocation.

It's a tiny bit of overhead on every function call, but Fugue was never meant to be performant - just a reference implementation of the higher-level points of the language. So I don't really care


The upshot is that, for the first time in Epoch history, this code is valid and will function perfectly:

entrypoint : () -> ()
{
	recurse(3)
}

recurse : (integer(counter)) -> ()
{
	debugwritestring("n Bottles of Beer on the wall... where n is:")
	debugwritestring(cast(string, counter))

	if(notequal(counter, 0))
	{
		recurse(subtract(counter, 1))
	}	
}




Epoch doesn't yet detect tail recursion, so even this simple little program can smash the stack if the recursion depth is set too high. I'll have to do some serious studying up to learn how to deal intelligently with tail recursion; probably something that'll come way down the road, once more heavy-duty features are in place.


Depending on how long it takes me to finish the documentation and cleanup process, we should be seeing Release 3 in the next couple of days. Woohoo!


Ninja Update - 1936 hours
I only have 21 files left (out of 62) to document. If I stay as bored over the next hour as I did over the last, I should be able to get R3 out tonight.

More Ninja-Action - 2009 hours
Down to 10 files, but most of them are comparatively large. I've left them for last because I am lazy and worthless. R3 is still on track for later tonight... hopefully.

Comments: 1 - Leave a Comment

Link


I think I'll be posting Epoch Release 3 soon; I'd like to do some documentation work, and a bit of assorted cleanup, but once that's done, R3 will be ready to go. The big changes are of course related to making the VM stack-based rather than the old mutant thing it used to be

I mentioned earlier that I'd wanted to get serialization done for R3 as well, but I'm not sure about that now. I think serialization is a big enough project that, combined with the disassembler I want to write, it should be a release all to itself. There's also the fact that the stack related changes need to be tested out by people besides me, as soon as possible, in order to make sure the implementation is completely robust.


So for the moment, my tentative roadmap for Epoch looks like thus:

  • Release 3 - Stack based implementation, documentation and cleanup work

  • Release 4 - Completion of serialization, and inclusion of a separate disassembler tool

  • Release 5 - Implementation of tuples for multiple return values from functions, and first implementation of structures; first nontrivial Win32 app (Scribble)


That should keep me busy for at least another month

Once all that is taken care of, I'll have to do some serious thinking about what needs to be implemented in order to have a good package ready to demo by GDC '09. Of course the obvious elephant in the room is support for transparent parallel processing, which is one of the big reasons I'm implementing a language in the first place. Aside from that, though, I haven't done much scheming, so we'll have to see.

Another area that will need some major work is library functions for things like file I/O, basic mathematics functions, and whatnot. I'm still pondering how much of that to make first-class and how much should just be done by talking directly to the OS (using the DLL call support that's already in place).

One last thing to consider is the importance of code reuse, and a module system for promoting it. It'll take some tweaking to the system to get it to work across multiple files, but hopefully nothing too complex.


Anyways... the beer says I should be sleepy now, so don't fry your tulips before they hatch.


Comments: 0 - Leave a Comment

Link



Sunday, August 24, 2008
We're back on the air, baby!

As of some unholy hour this morning, I've gotten all the relevant stack-based changes made, so that the guessing game works once again. The pi computation program should be mere hours behind, but there's been a complication.


A lot of core-level guts have changed in the Fugue VM. One major change is that specific operations like if no longer bind directly to other operations; that is, previously, if (and most other builtins) would maintain a pointer to the expression that was to be used as the condition. Now, the conditional expression is evaluated separately, and its result is deposited onto the stack. Immediately afterwards, the if operation pops the value from the stack, and acts accordingly.

This simplifies the internals of the VM dramatically, which means there's probably a lot of loose ends I need to go back and tie up. It does sacrifice a tiny bit of performance since everything is shuffled on and off the stack fairly often, but that's the kind of thing I'm not going to worry about until the performance-tuning phase of the project (which is not for a long time from now). I'm putting off implementing registers in general for as long as possible for similar reasons.


Anyways, all that to say, function return values are currently broken. I was really hoping to get the pi calculator running again tonight so that I could totally sign off on the stack-based VM changes, but oh well.

The big problem appears to be in the parser end of things rather than the execution end, so it should be fairly easy to solve. The great part about solving issues in the parser is I can track all kinds of metadata about each bit of the program, allowing for some fairly nifty tricks. That kind of hackery - not to mention overhead - is something I'm trying very hard to keep away from the execution portion of the VM.

In brief, the trouble is in tracking the initialized value of return-value placeholders.

Let's look at the pi program code again for reference:

entrypoint : () -> ()
{
	debugwritestring(cast(string, pi()))
}

pi : () -> (real(retval, 0.0))   // <-- this line is what we care about today
{
	real(denominator, 1.0)
	boolean(isplus, true)

	do
	{
		real(div, 0.0)
		assign(div, divide(4.0, denominator))

		if(equal(isplus, true))
		{
			assign(retval, add(retval, div))
			assign(isplus, false)
		}
		else
		{
			assign(retval, subtract(retval, div))
			assign(isplus, true)
		}

		assign(denominator, add(denominator, 2.0))

	} while(less(denominator, 10000.0))
}



The marked line shows how return values are set up in the Epoch syntax. I pretty much ripped off algebraic notation for functions. A function definition "foo : (parameters) -> (return values)" is read as "foo such that foo maps (parameters) onto (return values)."

When the function scope is entered, a variable is created for each return value, and initialized to the correct value (specified in the function definition). This variable then acts like a regular variable throughout the function's scope.

(As a side note, eventually Epoch will allow multiple named return values, via a tuple mechanism. This is likely to be the precursor to structures in the language. I've been putting it off because I can't decide on a good syntax for how to read the tuple on the caller's end.)


The problem I've run into is that, previously, I was hijacking the lexical scope container that I built to store the list of return variables and their correct initial values. Now that lexical scopes require a stack to store anything, there's no way to continue with that hijacking.

As noted earlier, this problem lies in the parser, not the execution system; so I can just build another container to handle the issue. In many ways this is a good thing, since hijacking classes and bending them to multiple purposes is Poor Engineering.


However, it is also work, and it requires some brain juice - which I am, for the night at least, totally out of. For tonight it's almost time to crash... hopefully I'll get it all sorted out tomorrow, and that'll wrap up the big changes for Release 3.

As far as minor changes go for R3, I'm going to really shore up the documentation of the VM code, and hopefully get serialization working. Once serialization (to binary form) is done, I'll bang together a little C# disassembler to aid in debugging.

I think that once the Scribble demo is done, doing something serious like a disassembler for the serialized bytecode would be a great next step. It provides a nontrivial project that has to be completed, which in turn requires that the language be pretty robust; and it also provides a much-needed tool for working with the language itself. There've been several times during the stack-based updates when I wished for a good bytecode disassembly view of what exactly the VM was doing at various points in time.

Plus, that's a decent start on the route of building an Epoch debugger that hooks directly into the VM itself. That's definitely something that will be necessary some point down the line, and it certainly would require a robust language to build it in.

Even better, building Epoch development tools in Epoch is one of those nice little closed-curve self-referential thingies that makes my spine tingle



Right... I'll shut up for now, since I can barely type anymore.

Comments: 1 - Leave a Comment

Link



Saturday, August 23, 2008
I decided to take a few spare minutes and get back into working on Epoch, particularly on making things purely stack-based.

So far, so good; almost all of the arithmetic operations and other built-ins have been removed, awaiting reimplementation in stack-aware forms; but other than that, everything remains intact and functional.

The following Epoch program demonstrates the working stack:
entrypoint : () -> ()
{
	integer(test, 2)
	testfunction(test, 40, "Output, this is a test")
}

testfunction : (integer(foo), integer(bar), string(baz)) -> ()
{
	debugwritestring(baz)
	debugwritestring(cast(string, add(foo, bar)))
}


You may note that lexicalcast is gone, in favor of the more succinct and flexible cast operation. This operation will be the basis for all type conversions in the language, at least so far as I can foresee at the moment. With a small amount of work, real/integer and real/string conversions will be possible as well as string/integer conversions.


One of the trickier bits I had to wrap my head around was splitting the type checking into load-time rather than run-time. This is basically a crude bit of static analysis, done to ensure things maintain correct types; the stack itself contains no type annotations, just data, so it is mandatory that we are statically aware of what kind of data resides at each slot in the stack.

That seems to have been conquered, though, and leaves me with just a handful of minor reimplementation tasks before everything is back up to Release 2 levels of functionality. Woohoo!


As I think I've stated before, my next big project is a Scribble application, where you can draw neat little squigglies on a blank white window using the mouse. This will be a full test of several features, most notably structures, since structure support is required for communicating to most of the Win32 API.

At the moment, I have no idea how I'm going to implement structures, so I might content myself with making a tidy-up pass on the Fugue code and putting out a Release 3 to demo the stack-based changes.


So Epoch continues to progress. I'm not sure if I'll hit my goal of having a workable prototype language ready for GDC '09, but I should get pretty darn close. At the very least I'll have enough to prove that Epoch can be a viable real-world production language, given enough patience and grunt work - and that's all I really want to accomplish anyways.

Taking over the world is just a bonus.

Comments: 2 - Leave a Comment

Link



Wednesday, August 20, 2008
English is such a weird language. We can burn something up, burn something down, burn it in, or even burn it out. The semantics of the burning are modified entirely by the preposition. Some prepositions invoke literal flame, others give us a more metaphorical image.

I'm interested in one of those prepositions in particular these days - that is, burning out. Dealing with burnout is never an easy thing, even for otherwise healthy and well-adjusted people. Throwing something like bipolar disorder into the mixture makes it an extremely tricky issue.

Originally, prior to treatment, my bipolar episodes cycled with abnormal rapidity - I could shift from being wildly manic to deeply depressed in literally a matter of a few hours. One of the easiest ways to recognize an episode was to sleep it off; if, after napping for a couple hours, I felt different, chances are it was a bipolar spike.

One of the biggest effects that treatment has had on my symptoms is to slow down the cycling drastically. I now take several days to fully swing through an episode, although thankfully I've been largely symptom free for several months now.

At least, I hope so.


In the past couple of weeks, I've been grinding to a halt. My energy levels have dropped through the floor. I don't want to work on anything. I don't care about much. Aside from vegetating in front of Battlestar Galactica or Starcraft, I barely do anything outside of work.

And even work has suffered tremendously. My output has slowed down to a trickle. I find it difficult to focus for long, and lack the motivation to tackle any nontrivial problems. The result is a lot of false starts, tiny and insignificant efforts to assault major challenges.

I'm not hacking in my free time like I used to. After the brief burst of interest in Epoch, I've almost completely neglected the language, to the point that I don't really clearly remember what I was last working on.


For most people, this would just be classic burnout. The symptoms and causes are easy to recognize. I feel stifled and cramped in my current apartment, which is a large part of why I've been looking into moving out into a bigger house. I feel unmotivated and drained, with minimal support from a team who is all caught up being ridiculously busy on other issues. Worst of all, I've questioned my desire to even work in the computer field - which is a drastic step for me; computers have been my passion since age six.

Usually, there are stock solutions to burnout: exchange projects if possible. Change the working environment as much as can be done. Take a serious break. Look for communication breakdowns with teammates and coworkers.

Exchanging projects isn't an option; we don't have any other projects to work on, at least for the time being. The downside of being a small studio is that all the eggs lie in a single basket.

Changing my work environment is difficult. In a single-bedroom apartment, there's not much that can be done to rearrange furniture or the like. And although I am working on getting a house, that takes a lot of time - and, problematically, introduces a host of stresses all its own.

Taking a break sounds deeply attractive at the moment, but I fear that I'd end up feeling guilty partway through, and return to work prematurely. I've always had problems disciplining myself to get away from work, which ironically overall lowers my quality of work because I cook my brain too quickly.

Communication and support are just going to be permanent problems; it goes with the territory of working remotely. I can't lean over to the next guy and have him pair-program with me to solve some difficult issue. I can't sit down with the art team and have them directly evaluate the results of the procedural content generation stuff I'm working on; I have to wait days for them to get a free minute to read through my emails and respond. The whole setup is just fraught with teamwork landmines.


But the difficulties in treating vanilla burnout are not my biggest worry. By far the thing that concerns me the most is that this may not just be burnout, but rather the doldrums of a particularly nasty depressive episode. The medication has slowed down my cycles to the point where I can't just sleep through the worst of the symptoms; so if this is truly born of the disorder, I'm stuck in it for the long haul.


I know, deep down, that working in such a high-pressure industry - and in particular in such an awkward working arrangement - poses a serious risk for me. I take the chance every day of aggravating a serious and powerful disease, merely by showing up to work. It's less physically obvious but no less real than watching your lungs slowly eaten alive by coal dust, day after day in the mines.

But regardless of that danger, I'm not yet ready to let go of the career that I love. It may be a brutal struggle indeed, but I'm here to stay.

I just have to figure out how to survive without destroying my health and sanity along the way.

Comments: 5 - Leave a Comment

Link



Sunday, August 10, 2008
I would have finished the Stack Based Epoch changes tonight, but then I realized that I technically have several polymorphic built-in functions, and my head just doesn't want to deal with polymorphism and stacks.

So BAH to polymorphism. And just plain BAH in general.

Comments: 1 - Leave a Comment

Link



Saturday, August 9, 2008
9:01 PM
I bit the bullet this evening and started hacking on getting stack-based Epoch implemented. So far, progress has been good; local variables are pushed onto the stack when a scope is entered, and popped off the stack when the scope exits. I estimate that about 75% of the requisite work is finished at this point.

The next phase is to get function parameters working in a stack-based manner. I'm not entirely sure how to do this at the moment, given the way I've encapsulated function calling; but as with most things, the answer should become obvious once I've banged my head against it for a few minutes.


11:09 PM
The last couple of hours have been filled with a healthy mixture of scratching my head blankly, and procrastinating. Thus far, I have made no real progress in figuring out how to get function calling to work elegantly.

Pushing parameters onto the stack and then reading them is trivial, and in fact already implemented and (theoretically) working. The problem is associating names with parameters within the function scope. For example, consider this simple Epoch program:

entrypoint : () -> ()
{
	testfunction(2, 40)
}

testfunction : (integer(foo), integer(bar)) -> ()
{
	debugwritestring(lexicalcast(string, add(foo, bar)))
}


This should output 42. However, there's a minor hangup. foo and bar are variables within the context of testfunction, since they are by-value parameters. But they are not the same as local variables defined within testfunction - local variables need to reserve stack space, but parameters do not (their stack space is allocated by pushing parameters onto the stack prior to invoking the function).

The problem is that I need a clean way to enter both foo and bar into the local variable scope without flagging them as needing stack space. I'd like to avoid something as inelegant as a bool NeedsStackSpace kind of hack.

And thus the search for a solution continues...


11:38 PM
My standin solution for the time being (which may well end up being permanent) is a little magic called ghosts. The actual scope for a function doesn't actually "know" about its parameters or return values - instead, it just has a "ghost entry" that points to the real scope owning those values. The actual parameter and return value scopes are independent, and generated during the function prologue. This solves the issue of the function knowing about the parameters/return values.

However, somewhere in the mix, I've introduced a bug that's causing scopes to get deleted twice. Oops. Once that's fixed, I think I can safely say that the first (shaky) implementation of stack-based function calling is working.


11:51 PM
Bug squished! Turns out I had a nasty case of a default parameter being set to true when it shouldn't have, in fact, ever had a default value to begin with.

As of this moment, the test program listed above works correctly - integral literal values are passed across the stack. However, nothing else is passed on the stack yet; so I have a lot of work ahead.

Specifically:
  • All literals should be passed on the stack

  • Variables need to have a copy of their values pushed onto the stack

  • Return values need to be pushed on the stack to allow proper nested function calls, like foo(bar(baz()))

  • All built-in operations need to be converted to accept stack parameters


Whew! Looks like it'll be a while before Epoch is really alive again...

Comments: 1 - Leave a Comment

Link



Friday, August 8, 2008
Well, I finally ran into something major that will have to change in Epoch.

It's kind of a dumb oversight, really, and hopefully it won't be too big of a fix to make; but it's still the first significant thing I'll have to go back and redo in the VM.


At the moment, lexical scopes exist on the heap. This means that every scope always exists, from the moment the program starts to the moment it terminates. Even if you have a lexical scope that is never entered, any variables it allocates will be chewing up memory.

Worse, this means that recursion is impossible. A function has only one instance of its bound scope, regardless of how many times it gets invoked, or what the call chain looks like. Therefore, any program that tries to do recursive calculations will get incorrect results. Each time the function is invoked, it will just overwrite the existing single instance of the scope on the heap, rather than creating a new scope on the stack.


The fix, of course, is to introduce an execution stack to the VM, and have scopes enter and exit correctly on the stack. Technically everything should be stack allocated right now instead of heap allocated, since I have no explicit heap allocation mechanism built into the language yet.

Being naturally lazy, I'm not particularly excited about having to do all this redesign work. Moreover, I'm not entirely sure how to go about it just yet, since it represents a pretty significant overhaul.


Oh well. It was only a matter of time before I ran into some kind of serious mistake; I am technically a language design newbie, after all

Comments: 3 - Leave a Comment

Link

Page:   1 2 »»

All times are ET (US)

In locus hic, omnes res dementes sunt.
 
S
M
T
W
T
F
S
4
6
11
12
13
14
15
16
17
18
19
21
22

OPTIONS
Track this Journal

 RSS 

ARCHIVES
July, 2009
June, 2009
May, 2009
April, 2009
March, 2009
February, 2009
January, 2009
October, 2008
September, 2008
August, 2008
July, 2008
June, 2008
May, 2008
April, 2008
March, 2008
February, 2008
January, 2008
December, 2007
November, 2007
October, 2007
September, 2007
August, 2007
July, 2007
June, 2007
May, 2007
April, 2007
March, 2007
February, 2007
January, 2007
December, 2006
November, 2006
October, 2006
September, 2006
August, 2006
July, 2006
June, 2006
May, 2006
April, 2006
March, 2006
February, 2006
January, 2006
December, 2005
November, 2005
October, 2005