3 <TITLE>Rune Language Overview</TITLE>
6 <CENTER><H2><B>Rune Language Overview</B></H2></CENTER>
7 <CENTER><H3><B>(c)Copyright 1996-2018, Matthew Dillon</B></H3></CENTER>
9 <H2><B>(I) History</B></H2>
12 Well, the story of Rune is long. My desire to write a language began in
13 the late 1980's after I had learned C and started looking for something
14 better. Many years later people will note that I am still a hard-core
15 C programmer, working mainly on the DragonFly kernel code base. You
16 might think (if you didn't know me) that I'd be able to find *something*
17 out there that would satisfy me language-wise, other than C. But I
20 For various reasons I have very little love for most of the programming
21 languages out in the world today. I hate the design-by-committee mess
22 people call C++, I hate the kitchen-sink-control-the-programmer approach
23 taken by Eiffel, the cacophony that is perl, the limited Objective-C,
24 the ever-changing typeless lets-break-everyone-again TCL (though I will
25 admit that, of late, it seems to have settled down. Still, TCL isn't
26 for me!). I'm not interested in the politics associated with Java
27 that has destroyed it as a viable programming language, or the wordy
28 semantics and constructs (Java is a toy that should never have seen
29 the light of day IMHO). I don't mind some of the newer mostly interpreted
30 languages but for one reason or another they aren't really my cup of tea.
31 I hate leaving performance on the table or having core language constructs
32 such as expandable arrays fall down on the job of managing memory well.
33 Languages like Scheme, Python, and Ruby are better, but have a number
34 of show-stopper quirks (like the crazy indenting mechanics of python,
35 for example), and nobody seems to be able to handle locking or threading
36 properly. As a kernel programmer I want something which can handle
37 threading and locking in as non-invasive and natural manner as possible.
38 And when I say threading, I don't mean a few dozen threads.... I want a
39 language that can handle a million light-weight threads.
41 I'm a great believer in the concept of a class hierarchy and in
42 object-centric design, and yet as you can see I have done little but
43 write in C in my life which is kinda like the wild west when it comes
44 to object-centric programming.
46 Of course, another reason I have not switched to a more object-oriented
47 language is simply because every time I try I find myself constantly
48 comparing it to my internalized ideal.
50 Rune is culmination of almost everything I want in a language. It
51 has gone down many paths, retreated, gone down again, retreated.
52 Pointers began as very fat objects which I then tried to collapse by
53 internalizing type and lock data, which failed. So they became fat
54 again and now in this iteration I am attempting to reduce them to
55 something inbetween... two machine fields rather than five.
57 Throughout this period, I began thinking of my dream language
58 as "D" in my head, but I was ambivalent about trying to name it that
59 as a public release. I finally came up with a great name, "Rune", after
60 running through literally a thousand different possibilities. I don't
61 care if it's already being used for other things... so is virtually
62 every other interesting word in the dictionary. "Rune" is the name of
65 So why has it taken so long to write Rune? Well, there are many
66 reasons. Some of you might remember the 'DICE' system I wrote for
67 the Amiga and sold as shareware in the early 90's. DICE was a full
68 ANSI-C compiler (circa that period), preprocessor, assembler, and
69 linker, and included a full set of standard C libraries.
70 I wrote it all, for the 68000.
72 Unfortunately this points to a severe character flaw of mine when it
73 comes to me and writing code... I am a bit of a perfectionist when it
74 comes to my own personal work, and other people's work rarely achieves
75 a level of robustness that I am comfortable with. I was able to build
76 DICE quickly because the C language standard already existed, as well
77 as standards for all the other necessary pieces, so I just had to
78 start coding it up. But Rune is a different matter. With Rune I am
79 designing the language as well as implementing it, and that amplifies
80 the character flaw. I want to give people as good a base as possible.
82 Over these many years my language has evolved. I have added many
83 features and removed many more. I have written over two dozen drafts
84 of the grammer but it has only been the last five or so years that
85 it's settled down into something I consider to be reasonable. Another
86 time factor is what I call the 'Dillon' factor. When I set out to
87 design something I expect to be able to grasp and hold the entirety
88 of the project in my head without external references. Rune is complex
89 enough that it has taken quite a while to achieve this state of mind.
90 I want to be able to scale simple concepts into extremely sophisticated
93 I've been especially hard-nosed on this project, but I believe quite
94 strongly that getting the core right can have a thousand-fold payback
95 down the line. I will say, right off the bat, that Rune is not for
96 everyone. It is not meant to be a kitchen-sink language. For example,
97 it is more systems-oriented and less abstract.
99 So that's the history in a nutshell. I've left out what few discussions
100 I have had with friends and my many attempts to kick the process (multiple
101 times, over the years). In the end it's only the final draft that matters,
102 and this is it (at least as of this moment :-)). This is the end of the
103 beginning and the beginning of something new.
105 <H2><B>(II) Language Features and 'why I did it that way'</B></H2>
108 I absolutely can't stand languages that try to implement <I>everything</I>.
109 Kitchen sink languages tend to be so complex that they wind up being
110 unusable or unreadable or unlearnable or unmaintainable. When a
111 programmer is able to implement some concept ten thousand different ways,
112 you will wind up with ten thousand different implementations and you can
113 huck any efficient, collaborative development right out the window.
114 I have thought long and hard in regards to which concepts I should
115 include. Should I have inheritance, multiple-inheritance, subclassing,
116 organization of class hierarchies, and so forth? I've thrown out a lot
117 of concepts as simply not meshing well with the rest of Rune.
119 For example, you will not find multiple-inheritance in Rune. Why?
120 Because multiple inheritance almost always results in unreadable code.
121 Well-designed programs just don't need it. Abstraction is good to a
122 point. Take it too far and code might as well be gobbly-gook to anyone
123 who wasn't the original author.
125 Similarly I have considered many exception-handling schemes but as yet
126 I have not come across anything I really like. I consider contracts
127 to really just be assertions, and I am in the school of thought where
128 a failed assertion is a bug and should abort the program. Actual bugs
129 should assert, period. The last thing you want to do is to try to catch
130 a bug and unwind code with yet more potentially buggy, untested exception
131 handlers. Code paths which rarely run are also rarely bug-free.
133 Nominal errors... something which can happen under normal operating
134 conditions that you want to process... those are the real problem.
135 I would *like* to have language constructs to facilitate error handling,
136 but I don't want something which makes the code too much more complex
137 than the nominal case we might see in a simple C call such as read().
138 Plus there are many situations where an error simply should not be
139 handled by the deepest caller receiving it, and which may or may not
140 effect operation of the call stack leading up to it.
142 The biggest problem with most error handling is that implementations
143 return too many possible errors when they should be asserting and
144 panicing on most of them instead. You don't coddle software bugs,
145 you stamp them out and nothing stamps out bugs faster than an
146 assertion and core dump.
148 Lets take a simple example. Lets say you have a routine to load a
149 font by name which returns a 'Font *' to the caller. An error occurs
150 if the font does not exist. The question is then how to handle it and
151 who should handle it? I would argue that the best way to handle it is
152 to have an error code embedded in the Font structure itself, and instead
153 of the font loader returning NULL the font loader instead sets an error
154 in the font structure and never returns NULL. For arguments sake,
155 the caller could even allocate the structure:
161 font->loadFont("fubar");
164 The advantage of this mechanic is that the caller might not necessarily
165 be in a position to handle the error, but some higher-level routine in
166 the call stack, or even some other part of the program might. The caller
167 has the option of simply proceeding as if nothing bad happened and leaving
168 the error for someone more suited to handle it (say, the GUI user
169 requestor that the user originally typed the font name into!). This
170 is the type of flexibility I want to see in any language-supported
171 exception-handling. As you should be able to see already, there's no
172 single error code or single error path. Errors could, in fact, bifurcate
173 on the way back up the call stack simply by registering them within the
175 Not all errors can be handled this way of course, but there is a whole
176 class of errors that can. Possibly not the best example I could come up
179 And this is why Rune does not have anything yet, because I haven't come
180 across a mechanism that I really like. You'll find many drafts and
181 attempts in the spec history, but nothing implemented in this first
184 You will not find a formal single-root class hierarchy. Been there, done
185 that, stupid idea. Nor will you find complex overloading features. Rune
186 is designed in a manner that avoids most potential namespace conflicts
187 without over-burdening the programmer with long dotted identifier
188 sequences or complex specifications. Since most conflicts are naturally
189 avoided in the first place, Rune doesn't need sophisticated overloading or
190 conflict handling features. What will you find in Rune? Read on!
192 * Import mechanism. Rune uses an import mechanism to collect project
193 files and libraries together into a program. There is NO include
194 mechanism, and there is currently no pre-processor mechanic (though
195 I am considering it).
196 If you import a directory then Rune will locate "$directory/main.d"
197 and import that. "main.d" then typically imports whatever libraries are
198 required as well as the other project files and provides a <B>main()</B>
199 to start execution of the program. Library-library dependancies are
200 typically resolved simply by having the library itself import whatever
201 other libraries it needs (and as a welcome side effect this makes
202 libraries self contained). Duplicate imports of self-contained entities
203 are allowed, will be shared, and do not result in any significant extra
206 * Semantic search is not class-hierarchical. Rune locates an identifier
207 through a semantic search based on how you stack and name imports.
208 Within a procedure the semantic search begins in a manner similar to C,
209 where the search checks local declarations within the procedure
210 and then within the current file. If the identifier cannot be found
211 the semantic search progresses upward through the import hierarchy
212 until it hits the root (of the import hierarchy) -- the original file
213 that kicked the whole thing off in the first place. There is no object
214 root. Identifiers are searched level-by-level and can be forward
215 referenced (Rune makes no distinction between backward and forward
216 references except in one parse-time convenience case).
218 You can push down into an import, type, or class, by using a dotted
219 sequence of identifiers. For example, if <B>main.d</B> imports
220 "File" (file support library) and "a.d", "b.d", and "c.d", then code
221 sitting in "c.d" can access the file support library simply with a
222 construct like <B>File.FILE *fi = ....;</B>. Rune also includes
223 a mechanism which allows semantic searches to automatically push into
224 an import without specifying the import's id, by using double quotes
225 in the import name instead of angle-brackets.
226 Secondly, an <B>alias</B> mechanic allows you to pull up oft-used
227 identifiers without pulling up the entire namespace.
229 The <B>limport</B> mechanism is typically used only to collect tightly
230 integrated source files together... for example, source files in a
231 subdirectory. The main system library is typically imported by a
232 project this way, but externaal library imports in general are almost
233 universally named entities (imported using angle-brackets) and not
234 imported using double-quotes, in order to avoid namespace conflicts.
236 * Context-sensitive semantic search. Complex classes often have many
237 constants associated with them. Under certain circumstances Rune
238 provides direct visibility into any global fields defined for a class
239 in the context of a method call made to that class. An example of
240 this would be something like <B>fd.open("fubar", O_RDONLY)</B>,
241 where the O_RDONLY constant is directly accessible when used as
242 an argument to the <B>open</B> method call (and otherwise would be
243 accessible via a dotted <B>fd</B> or <B>Fd</B> expression).
245 * Typedefs. Rune supports typedefs. Typedefs are used to 'alias'
246 classes, with or without modification, making them available as simple
247 identifiers or via mulitple semantic paths. A typedef can be placed
248 anywhere a declaration can be placed: At the top level, in a
249 <B>class</B> definition, in a procedure... even inside a compound
250 type if you want (though I might call you crazy). Typedefs are
251 extremely convenient constructs which allow you to short-cut complex
252 types to avoid having to specify class paths with lots of dots. For
253 example, if your project uses <B>File.FILE</B> a lot, you could
254 simply <B>typedef File.FILE FILE;</B> in your project's "main.d"
255 source file and just use <B>FILE</B> in all the project source
258 Typedefs can also be used to change default assignments. For
259 example, <B>typedef myint int a = 4;</B> creates a new type
260 <B>myint</B>. When you instantiate <B>myint</B> the object content
261 will default to a value of 4 unless you specifically give it another
264 * Classes. Rune supports a class mechanism. All types except compound
265 types are based on a class somewhere. This includes core Rune types
266 such as <B>int</B>. What you know as an <B>int</B> in C serves the
267 same function in Rune with the same physical size, but <B>int</B> is
268 in fact a full-blown class in Rune.
269 Classes contain declarations: typedefs, storage declarations,
270 operators, procedures, and constants. <B>It is important to note
271 that Rune uses a C-like pass-by-value model. Rune also supports bounded
272 pointers and so can pass objects by reference, and also supports passing
273 and returning an object by <I>lvalue</I>. An <I>lvalue</I> is
274 effectively an object which appears to be passed by value but is
275 actually passed by reference, allowing the procedure to modify it.
276 <I>lvalue</I> is necessary to implement operators like "++" and "+=".
277 Rune makes no distinction between core classes and user-defined
280 * Subclasses. Rune supports a subclassing mechanism. A subclass is
281 basically a merge of its superclass plus additional declarations
282 and/or refinements to declarations inherited from the superclass.
283 Namespace overloading is explicit.. if you declare something using
284 an identifier that conflicts with a declaration in the superclass
285 and you do not explicitly say that you are refining the superclass
286 declaration, then your declaration will be used by anything you
287 define in your subclass but the 'hidden' declaration in the superclass
288 will be used by anything defined by the superclass. Rune allows you
289 to refine methods, typedefs, and storage (changing the size of
290 preexisting storage elements in an object). However, because I have
291 no wish to force the entire language to be dynamically typed at run
292 time only subclasses which refine procedures, extend existing storage,
293 and adjust default assignments are compatible with dynamically bound
294 reference pointers (see later). The base fields of subclass which
295 match the superclass must be compatible with an accessor running
296 through the superclass.
298 * Refinement. When you subclass a class you can refine declarations
299 made in the superclass. You can only refine declarations by making
300 them more specific. For example, if the declaration in the
301 superclass is <B>Integer x = 4;</B> then you could refine it to
302 be <B>int8 x;</B> but you could not refine it to be <B>float x;</B>.
303 You can refine types and default values and you can partially
304 resolve procedure arguments (and/or refine argument and return types).
305 <B>Refinement is an extremely powerful mechanism. The core library
306 uses refinement to declare all of Numeric's operators in the Numeric
307 superclass using a typedef'd type called 'T'. The core library then
308 simply refines the typedef T in various subclasses in order to
309 automatically re-form the supeclass operators and procedures into
310 more specific operators -- without having to redeclare the operators
311 or procedures at all.</B> This means, in effect, that you can write
312 generic procedures in the superclass that operate on declarations
313 defined by the superclass in the context of the subclass.
314 <FONT COLOR="darkgreen">Subclass refinement is one of the most
315 sophisticated and important features of the Rune language</FONT>.
317 Refinement also works well with <B>method</B> procedures. These are
318 procedures which execute with an object context called <B>this</B>.
319 If you create a subclass which refines a superclass declaration,
320 and then call an unrefined superclass method, the superclass method
321 will use your refined declaration(s). Superclass procedures which
322 are overriden by subclass refinement are not automatically called.
323 Instead your refined procedure must use the
324 <B>super-><I>funcname(...)</I></B> mechanism to chain the
327 * Pass-by-value and embedded objects. Rune uses the C pass-by-value
328 and embedded-type model. In C you can embed one structure inside
329 another. You can do the same with classes in Rune. Rune also has what
330 we call an <I>lvalue</I> extension which allows a procedure to
331 enforce a pass-by-reference and/or return-by-reference for an object
332 that is passed to it literally, which Rune operators use to implement
333 variable-modifying behavior (such as <B>++x</B>) and which you will
334 be able to use to for the same purpose.
336 * Forward referenced identifiers. Rune does not impose any requirements
337 on the ordering of declarations within a file or between files and
338 libraries. The only thing you cannot do is directly embed classes
339 in a way that forms a loop (class A into class B and class B into
340 class A). You can, of course, embed mutual pointers.
342 * Bounded pointers. Rune's interpreter uses bounded pointers. For
343 example, a pointer into an array can be manipulated with addition
344 and subtraction, just like C. But Rune will not allow the pointer
345 to be accessed if it goes out of bounds. Rune also does not allow you
346 to arbitrarily cast pointers from types containing pointers to other
347 types or vise-versa. Casts are allowed only between types whos contents
348 do not contain pointers.
350 This does mean that Rune pointers can be relatively expensive if misused,
351 but the multiple features of a Rune pointer are not to be triffled with
352 and this will ultimately be something that can be optimized heavily by
353 the language implementation.
355 * Dynamically bound pointers (known as reference types). In Rune something
356 like 'Frame *x;' represents a pointer to a frame. A dynamically bound
357 reference is something like 'Frame @x;'. This creates a pointer object
358 that can be bound to the specified class or any compatible subclass of
359 the specified class at run-time. You can only access the fields whos
360 API is defined by the superclass (Frame in this case) through a
361 reference type, but that's why we have refinement. Your method calls
362 will call into the version of the procedures refined by the associated
363 subclass, for example. Subclasses can do other cool things like
364 change default values, and the access via the superclass will of
365 course see the different default.
367 * Constant optimizations. Both the interpreter and the code generator
368 do VERY serious constant optimizations. The interpreter will shortcut
369 constant expressions on the fly after evaluation so the next use
370 can simply return the constant. The code generator will use hints
371 from the resolver to determine that an expression should return a
372 constant and execute the interpreter at code-generation time to
373 obtain the constant. Constant optimizations are far more than just
374 being able to evaluate simple operators, they also include making calls
375 to 'pure' functions with constant arguments with any level of
376 sophistication. This means that you can have something like sin()
377 (take the sine of a floating point value) and if you pass it a
378 constant the result will be evaluated at compile-time by the
379 code generator rather than at run-time, and will be evaluated just
380 once by the interpreter and then replaced by a constant.
382 * Constant evaluation for global default initialization. When
383 generating code, the interpreter is invoked to resolve default
384 assignments. In Rune you can initialize a global using expressions
385 which would not normally be considered constant expressions in a
386 language like C. However, there are limits to the complexity allowed.
387 Any address assignments must resolve to an assembly symbol and offset,
388 and any circular assignments, such as the one shown below, will
389 give indeterminant results which may change depending on whether
390 the program is compiled or interpreted. This Rune specification does
391 not allow circular default assignments, but might not error-out
392 if you choose to use them. In addition, global pointer variables
393 are not available at compile-time.
395 global int a = b + 1;
396 global int b = a + 1;
399 * A global variable assignment's initialization is resolved at
400 compile-time. A global variable initialized via a global
401 constructor is resolved at run-time.
403 * Automatic zeroing. Stack declarations are automatically initialized
404 to zero if not otherwise assigned (pointers are initialized to a
405 typed-NULL). Allocations are always zerod unless explicitly told not
406 to. Only allocations of structures which do not contain pointers,
407 lvalues, or references can request an uninitialized allocation.
408 Pointers are always initialized and cannot be optionally told not
411 * There is no union. Believe me, this is a feature. The subclassing
412 mechanism should be plenty good enough to handle nominal union-like
413 situations and Rune allows content casting as long as the content
414 contains no lvalues, pointers, or references.
416 * User-defined operators. All operators in Rune are physically declared.
417 Even Rune's core operators on integers and other types are declared
418 in the core Rune "sys" library. You can define your own unary and binary
419 operators and you can use almost any sequence of operatic characters
420 to do it. Rune imposes one bit of sanity, however. You cannot specify
421 the precedence. The precedence of an operator is fixed based on
422 the characters making up the operator. All C-like operators wind
423 up with C-like precedences. Your own operators will wind up with
424 C-like precedences too, using simple rules defined in the Rune grammer.
427 User-defined operators can be emplaced in any class belonging to the
428 arguments you supply to the operator when you use it, and may also be
429 emplaced in your main semantic search path. So, for example, you
430 cannot add a new operator to the core <B>Integer</B> class but you
431 can certainly add a new operator that operates on various kinds of
432 ints semantically, such as in your <B>main.d</B> module. </FONT>
434 * Pure functions - A 'pure' function with constant arguments will
435 be interpreted at compile-time and replaced with its result. For
436 example, most math operators and trig functions are defined as being
437 pure. So if you have a bit of code that, say, runs cos(1.5), the
438 run-time overhead will be the same as for a constant.
440 * LValue operators and procedures (deserves separate mention). An
441 LValue operator is capable of assigning the
442 left hand side as well as returning a result. The left hand
443 side must be an lvalue. For example, the C "+=" and "++" operators
444 are LValue operators, while "+" is a normal RValue operator which
445 returns a temporary result. LValue operators allow Rune to implement
446 almost the full complement of C operators and additionally allows you to
447 build your own user operators with similar characteristics.
449 * User-defined casts. All casts in Rune are physically declared, including
450 core castings such as int8->int16. The Rune class library implements
451 the more common casts but does not implement all casts. The language
452 also builds-in certain casts for conveniences. For example, a pointer
453 will auto-cast to a bool in order to allow <B>if (ptr) ...</B>.
455 Rune is a bit more strict when it comes to auto-casting integral and
456 floating point constants and variables to other integral or floating
457 point types. Rune generally only auto-casts when the target type is
458 well known, such as the argument type in a procedure call. Rune
459 generally will not auto-cast intermediate results to match operators.
460 This tends to be non-deterministic (in C the rules are just too flexible
461 and allow for very sloppy coding). Rune will usually complain if you
462 mix integral and floating types together in an expression.
464 * Method calls. A method call is something like <B>fp->setmode(10)</B>.
465 That is, making a call through an object. In Rune a method declarations
466 or call is similar to a procedure call passing the object as an lvalue
467 as the first argument to the procedure and, in fact, the Rune resolver
468 converts method declarations and calls to exactly that. You can also
469 create <I>global</I> method calls. These can be called through the
470 object or through the object's type, but rather then passing an object
471 as the first argument the type is passed instead. Something like
472 <B>FILE *fi = FILE.fopen(...)</B> is an example of a global method
475 Rune normally constructs the first argument for a method call silently
476 and automatically. The argument is named <B>this</B> and will represent
477 the object itself (not a pointer), so nominal accesses are via '.'.
478 Normal method calls require a valid non-NULL object which has the
479 side effect of allowing the method procedure to access the contents of
480 the object without further bounds-checking.
482 However, there are cases where you might want to declare the <B>this</B>
483 argument yourself. Specifically there are cases where you may wish to
484 pass an lvalue pointer to an object rather then the lvalue object in
485 order to be able to allocate or otherwise replace the pointer.
486 To do this, you must declare an lvalue pointer to the object as the
487 first argument and name it "this". An example of this would be the
488 <B>Frame.createFrame()</B> method in "classes/gfx/window.d".
490 * Rune does not implement multiple-inheritance, on purpose. The main
491 reason is that implementations of multiple inheritance abstract what
492 is actually going on so much that they often make code unreadable
493 and unmaintainable. In Runeland we would prefer that code be relatively
494 easy to understand and maintain. The subclass mechanism is not perfect,
495 but it is sufficient.
497 * Declaration/Class merging. You do not have to build all the declarations
498 making up a class in the <B>class</B> definition itself. You can place
499 the declarations outside the class definition and even place them in
500 other source files as long as <B>library</B> scope is adhered to and
501 the declarations do not forward-reference the class (this is because
502 the merge occurs at parse time rather then resolve-time). This allows
503 very large classes to be built without ruining the readability of the
504 source code. You cannot merge a declaration into a class outside
505 of the library defining the class, but you can of course create a
506 subclass and add elements to the subclass (remember the part where I
507 said being able to do something a thousand different ways is not a good
508 idea? Well, this is one of those).
510 * Very little magical type promotion. Rune does not automatically
511 promote integer types for standard operators. If you add two
512 <B>int8</B>'s together the result is going to be another <B>int8</B>.
513 Rune will not allow you to compare an <B>int8</B> against an
514 <B>int32</B> without a cast unless you create a specific operator
515 to do it. You must decide or cast (casting is preferred). My intent
516 here is to remove the single largest problem C has when porting
517 between architectures (including tiny 8-bit architectures), which is
518 that C redefines its core types to suit the architecture in order to
519 reduce auto casts that would otherwise not be optimal for that
520 architecture, resulting in less portable code.
522 This allows Rune to be used across the entire range of platforms,
523 from 8 bit cpu's to 128 bit cpu's, without having to make incompatible
524 changes to the core language specification.
526 Automatic type promotion is not the convience you might think it is.
527 I have occassionally tried to compare or assign integers with characters
528 while programming in Rune but fixing the cases have not been a burden.
529 In fact I believe requiring the specificity has resulted in a higher
530 level of clarity for Rune code in general without creating an undue
531 burden on the programmer.
534 I do intend to make an exception for constants. This has not been
535 entirely coded yet so Rune will complain about mismatches against
536 constants of the wrong type in some cases (mostly for operators) and
537 not in others at the moment. As long as the constant is compatible
538 I think it is perfectly reasonable to auto-promote or auto-demote it.
539 If you hit these problems give your constants the correct suffix for
540 the expression.</FONT>
542 * Inherent casts. If Rune knows the type an expression needs to be,
543 for example an argument to a procedure, it will attempt to
544 cast your expression to that type. Rune can only cast based on
545 cast operators in the class hierarchy, so Rune can automatically cast,
546 say, an <B>int8</B> to an <B>int32</B> but cannot automatically
547 cast an <B>int8</B> to a <B>uint32</B> without a little help from
548 the programmer. <B>Keep in mind the such casting occurs after
549 the expression has been evaluated. If you add two int8's together,
550 you will get an int8 result and that result might then be cast to
551 something larger. The cast will not change the fact that the
552 "+" operator in this case still returns an int8 result.</B>
554 * Object-oriented. Everything is an object and eventually bases at
555 some class or compound type. Oh wait, I said that. Ok, I'll say
556 it again. Even the lowly <B>int</B> is a class. All of the operators
557 for base classes are defined in the classes/* subdirectory and have
558 internal tie-ins. There is no way around having internal tie-ins,
559 otherwise the interpreter and generator wouldn't know what to do!
561 <FONT color="red">Internal tie-ins are only allowed in the
562 rune-distributed classes directory, programmers should never use
563 them in their own code and Rune will eventually (even soon) generate
564 a resolve-time error if you try. But it doesn't yet.</FONT>
567 * Partial procedure argument resolution. This allows you to make a
568 more complex procedure compatible with a less complex call interface
569 by pre-evaluating and pre-supplying missing arguments. For example,
570 a library that takes a procedure callback does not need to know about
571 additional information you supply with the procedure, such as
572 application-specific structures and pointers. Partial resolution
573 looks like a procedure call in C but you take the address of the call.
574 For example, if you have a function that takes two arguments you can
575 turn it into a function taking one argument by partially resolving
576 the other, like '<B>&func(a:23)</B>'. <B>alias</B> can also be used
577 to partially resolve a procedure.
580 * Memory and code efficiency. I stick to a model that does not require
581 bloating instantiated object structures. Rune transplants as few of
582 the resolve-time structures into the binary and run-time as possible
583 (basically Type, Declaration, and SemGroup structures). Rune threads
584 are N:M and have minimal overhead.
586 * Built-in Interpreter. My intention with Rune is to be able to
587 interpret it, compile it, and even do an on-the-fly hybrid of the
588 two. The compilation process itself may have to interpret pieces of
589 code anyway to collapse constants, so it is only natural. I also
590 intend to eventually allow dynamic compilation... loading and
591 unloading source modules on the fly. For now we have just the
592 interpreter and the x86 compiler backend.
594 * No #includes. No preprocessor, but a few very simple preprocessor
595 directives to block-out debugging and testing code, or non-operational
596 musings. This is a feature, but it still needs work. The C preprocessor
597 is ridiculously useful in many situations, but also ridiculously
598 invasive. The language implements an import mechanism for glueing
599 together source modules. You pull everything.
601 There is no export mechanism but there are three levels of semantic
602 scope: <B>private</B>, <B>library</B>, and <B>public</B>.
603 <FONT color="red">My intention is to give the lexer a simple
604 preprocessing capability, similar to what you might find in
605 <B>make</B>, but I have no intention of having a full
606 fledged C-like preprocessor (even though I could just borrow
607 the one from DICE) because I believe that preprocessing, and most
608 especially #include files, take what could be a nice modular
609 object-oriented application and library set and turns it into a
610 nightmare of semantic collisions. I might lose the argument on this
611 front, though.</FONT>.
614 * Compartmentalized lexer, parser, interpreter, compiler, and library
615 manager. At each stage the intention is to be able to save an image
616 to the file that can be mmap()'d and accessed directly in a later
617 stage, eventually allowing whole projects to be partially pre-parsed,
618 pre-compiled, etc. The features will also be necessary when we
619 allow code modification on the fly.
622 * Threads. Very cool threads. The traditional problem one has with
623 threading is that one must explicitly declare all sorts of
624 infrastructure to create and manage multiple threads and related
625 data structures. Rune simplifies this greatly by introducing
626 the concept of a threaded procedure call. If thread A calls the
627 threaded procedure X, thread A will be suspended until the threaded
628 procedure X issues a <B>result(exp);</B> statement. The value is
629 returned to A and A's thread resumes execution. The threaded procedure
630 also continues to run. <B>For example, a threaded procedure could
631 allocate and return an object representing the thread to the caller, then
632 continue running as the new thread.</B>
634 Rune threads are synchronous by default, meaning they share the same
635 machine context of their caller and are thus very low-overhead and very
636 fast-switching. A Rune thread may be qualified <B>async</B> to
637 generate an actual new machine thread (similar to a posix thread).
638 A good example of the use of synchronous threads is for, say, a GUI
639 gadget library where each gadget is implemented as a Rune thread.
640 Since only one gadget is typically being manipulated at any given
641 moment it is a serious waste of resources to give each gadget a full
642 machine thread. Instead you would run all the gadgets as synchronous
643 threads within a single async gadget-handling thread.
645 * Compound types and expressions. Rune implements compound types and
646 expressions via a clever use of parenthesis and commas. <B>There is
647 no C-like comma-operator in Rune. Also, note that the arguments
648 to a procedure are, in fact, interpreted as one big compound type.</B>
649 Instead, there is the concept of the compound expression. A compound
650 expression is something like this: <B>(1, 2, 3)</B>. Additionally,
651 the elements of a compound type can be named in a manner similar
652 to the declaration of a procedure's arguments. For example,
655 <P>(int a = 2, int b, int c) x = (b:23, c:44);
659 Now is that cool or what? As with any declaration you can specify
660 default values. When you make a call to a procedure which
661 returns a compound type you can either store the result into
662 a compatible compound type (throwing away elements you don't
663 request), or you can store the result into a normal type
664 in which case only the first element of the returned compound
665 type is retained. When building a compound type any elements
666 which have defaults are optional, and since a procedure's
667 argument set is a compound type you can extend a procedure in a
668 backwards compatible fashion by adding a new argument to it and
669 giving it a default. 'Older' users of the procedure who don't
670 supply the argument are still ok.
672 you can also set defaults for procedure arguments in the procedure
673 declaration, and the default expressions can access other procedure
674 arguments by name. If you are declaring a method procedure this means
675 that default expressions can access the object via <B>this</B>.
677 * Multi-valued returns. If you haven't guessed yet, a multi-valued
678 return is simply a compound type. I've flip-flopped a number of
679 times on whether to implement critical error handling via a multi-valued
680 return mechanism or via exception handling, but ultimately came to the
681 conclusion that trying to implement it via the multi-valued return
682 mechanism would lead to code that was just too messy.
685 * Exception-handling. Rune does not currently implement exception
687 <B>raise</B>/<B>catch</B> mechanism documented in red, but I probably
688 won't implement it. This mechanism would distinguis between
689 nominal status returns such as a file EOF or non-blocking status
690 and more serious error conditions or aborts that warrant an exception.
691 The exception-handling mechanism gives subsystems a relatively painless
692 semi in-band way to back-out of situations without having to process
693 error codes from every single procedure call made. The mechanism is
694 similar to what TCL uses in some respects. Currently not implemented
695 (and might never be)</FONT>
697 * Constructors and Destructors. Classes may have any number of
698 constructors and destructors. A constructor or destructor is a method
699 procedure that takes no arguments.
701 Constructors are automatically called when an object is instantiated,
702 after any type and declarative defaults are set. Destructors are called
703 when the last reference to an object goes away. The constructors
704 and destructors associated with the superclass will be called
705 before the constructors and destructors associated with a subclass.
706 Constructors and destructors are called in order, first to last.
708 Destructors are called when the last ref on an object's storage goes
709 away, prior to type-based deinitialization. The runtime will
710 REF+LOCK the storage (giving it 1 ref) and call its destructors,
711 then proceed with type-based deinitialization. Resurrection of the
712 object during its destruction is possible but frowned upon and
713 does not cause an early-return of the destruction sequence.
715 Type-based deinitialization consists of releasing all pointers contained
716 in the object (if any) and may trigger the destruction of additional
719 A destructor can resurrect an object by assigning a pointer to it (such
720 as a global or as part of some other data structure). In this situation
721 the REFs on the storage will be > 1 and the runtime will not free or
722 unmap the object. You will likely wind up with a dead object which
723 then needs to be reinitialized.
725 Note that constructors must be cognizant of the partially-initialized
726 nature of the object and destructors must be cognizant of the same,
727 plus potential redestruction races by other threads (usually by doing
728 a final check before returning). Additional issues may arise when
729 multiple constructors and destructors are present. In particular, note
730 that ALL destructors are called on an object even if one resurrects it,
731 so these may need to make additional checks in more complex coding
734 Rune will not recurse releases (which can easily lead to stack
735 overflows). Instead the related RefStors will be moved to a list and
736 acted upon by the current thread when the destruction of the current
739 * Heap storage via pointers. You may call <B>ptr.new()</B> on any
740 pointer to call the runtime to allocate and assign an object to that
741 pointer. You can also declare objects directly using <B>heap</B>
742 scope which is similar. The object is freed when the last reference
745 Rune also has <B>persist</B> scope which mmap()s the object from a
746 persistent file, allowing it to survive program invocations.
747 <FONT COLOR="red">The RefStor is not memory-mapped, but 256 bytes is
748 set-aside in the file for a future shared RefStor implementation.
749 The programmer must be cognizant that discrete copies of the program
750 sharing the same persistent store will not be able to lock against
753 <B>Note that Rune does not detect unreachable cycles.
754 I consider creating an unreachable cycle to be sloppy programming.
755 Also note that Rune does not (currently) garbage collect and will
756 act on last-drops immediately. I am loath to give this up. Last-drop
757 handling can be a very powerful programming mechanic, it is not
758 something to be discarded lightly. Garbage collection has always been
759 extremely messy and non-deterministic and generally not a desirable
763 * Scripting. Rune supplies a nifty little #! scripting mechanism which
764 makes writing a program in Rune and executing it via the interpreter
765 trivial. Rune's interpreter is not JIT but it is heavily optimized
766 and snappy. Be sure to put a -x in your #! script to prevent Rune
767 from misinterpreting user command line arguments as rune options
768 (presumably you want those to be passed through to the Rune program).
770 * No version control. Rune does not attempt to integrate version control
771 mechanisms into the language. Folks, the plain fact of the matter is
772 that even the most robust Eiffel-like version control mechanism does not
773 make up for actually testing a project with the latest set of so-and-so
774 library. In fact, I strongly believe that integrating such features into
775 a language create more problems then they solve because, like
776 exceptions, it results in code paths which are virtually untestable
777 and as likely to blow up as to work the first time they occur in real
778 life. In balancing one evil against the other I would much prefer
779 documentation over enforced language-level compatibility. Rune provides
780 mechanisms, such as argument defaulting, that allow you to create
781 backwards compatible enhancements but Rune does not require that you
782 use them. There is also nothing preventing you from including a major
783 version number in the names of the libraries you import, nor is there
784 anything preventing you from importing different versions of the same
785 library (though the usability of doing so is suspect). Rune is
786 designed to facilitiate, but not enforce, backwards compatibility.
788 * Automatic object locking and ref-counting in Rune has gone through an
789 enormous amount of work and rework. Generally speaking I want Rune
790 to do much of the object locking necessary to create a safe
791 multi-threaded environment automatically. At the very least it
792 is important to guarantee field stability for pointer safety.
793 Idealy we also want to provide ordering determinism for objects.
795 There are two primary types of locks available: <B>hard</B> and
796 <B>soft</B>. A hard-lock works traditionally, enforces
797 determinism, but is vulnerable to deadlock situations. A soft-lock
798 is a type of lock which can be 'lost' when a thread voluntarily blocks
799 and will be reacquired upon resumption. Soft locks avoid the deadlock
800 problem but also lose ordering and reentrancy determinism between
803 Rune does not implement the locking type in the lock structure but
804 instead implements it in the threading model. By default, most locking
805 is <B>soft</B> (thus guaranteeing only field stability). Only method
806 object locks during method calls are <B>hard</B> by default.
807 Any pointer declared on the thread stack acquires a soft-lock for
808 the object it is pointing to by default. Reassigning the pointer
809 releases any prior lock and acquires the new lock.
810 Indirections through structures which produce temporary
811 pointers (for example, <B>a->b->c</B> where <B>b</B> is a pointer)
812 will temporarily lock and release the underlying object as needed.
813 The act of acquiring new locks may block and thus temporarily release
814 and then reacquire any soft-locks already held.
816 The programmer may implement a <B>hard</B> code section for any
817 bit of code which requires more determinism. A <B>hard</B> code
818 section causes all existing or acquired locks to operate as if
819 they were hard until the end of the section, after which they revert
820 to their previous state. This feature simply bumps an all-hard counter
821 in the thread structure. This feature can be dangerous and what you
822 do inside a hard-code section must be very carefully thought out.
824 The locking mode is stacked on a per-procedure basis. If hard-locked
825 code calls a soft-locked procedure any new locks acquired within the
826 soft-locked procedure will be soft-locked instead of hard-locked, while
827 all locks already held 'hard' by the caller remain hard.
829 The trade-offs with these choices are as follows: First, locks
830 have to be 'soft' by default to avoid deadlock potential in 'most'
831 of the code written by the programmer. Second, the act of locking an
832 object can block, so any existing soft-held locks can be temporarily
833 lost in the normal flow of code in ways that are unexpected. This
834 creates a serialization problem if the programmer isn't careful.
835 Third, the code generation cost of constantly lock+ref/unlock+dropping
836 objects is enormous, much higher than it would be using a garbage
837 collection scheme. However, there are actually very few use-cases where
838 where the locking overhead impacts performance in a meaningful way.
839 Finally, the lock+ref state of local variables vs stored fields created
840 significant compatibility problems for double-indirected pointers and
841 confusion with arrays.
843 The language has added various scope keywords to allow the programmer
844 to optimize locking operations, controlling how fields are accessed.
845 These keywords are primarily meant only for those bits of code which
846 must be highly performant.
848 The lock structure itself is associated with the object's storage,
849 not embedded in the object, so the sizeof() an object is always as
852 Races due to unsafe program behavior are far more common than most
853 programmers believe. Rune tries to bridge the gap by making
854 multi-threading a natural, even highly desireable part of the language,
855 but leaves the door open for programmer-directed optimizations.
857 * Rune Pointers. All pointers in rune consist of two raw fields
858 The first is a pointer to the actual object, the second
859 is a pointer to a PointerInfo structure.
861 The PointerInfo structure is a fat structure which contains numerous
862 bits of information needed to operate on a Rune pointer. This includes
863 array bounds, type, and refstor, all of which are raw low-level pointers.
864 The PointerInfo is typically dynamically allocated. In situations where
865 the type and pointer bonafides are entirely known and the RefStor is
866 known by other means, the code generator will omit the PointerInfo
869 The RefStor structure is a fat structure which contains meta-data
870 associated with the supervising structure's allocation and disposal,
871 lock, and ref-count. It is not specific to the type the pointer points
872 to. For example, a procedure's stack is represented by a single RefStor.
874 The RefStor structure contains the lock and information on how the
875 object was allocated. It may encompass whole environments. For
876 example, the RefStor for a procedure's stack context.
880 <H2><B>(III) Native types and operators</B></H2>
883 Please refer to the Rune core class module,
884 <A HREF="../classes/sys/class.d">../classes/sys/class.d</A>.
886 Generally speaking core types are as you might expect coming from
887 a C environment, with some significant exceptions as shown below.
888 Non-pointer types in Rune are deterministic and not adjusted to fit
889 the architecture. Instead, the code generator is expected to produce
890 the correct code for the type specified.
893 * There is no 'char' type in Rune. Instead you must specify
894 'uchar' or 'schar', or use 'uint8_t' or 'int8_t'. This is
895 to avoid common confusion with C. In Rune, strings are always
896 arrays of unsigned chars (aka uchar *) and encodings are always
897 UTF-8. However, basic functions like strlen() still count 8-bit
898 octets and can be used with memcpy, bcopy, etc, not 'characters'
899 in the international coding sense. This is because such code
900 almost universally needs to know the physical string length in
901 bytes, not the number of international characters. The distinct
902 UTF library may be used for international parsing, length, and so
905 * int is always a signed 32-bit quantity regardless of the
906 architecture. The Rune programmer can always assume that an
909 * long is always a signed 64-bit quantity regardless of the
910 architecture. The Rune programmer can always assume that a
913 * bool is a subclass of Numeric, NOT a subclass of Integer.
914 bool can be cast to or from an integer so conditionals (which
915 require bools) work pretty much as they would in C. This is done
916 on purpose as it allows booleans to be special-cased by the
917 code generator and makes certain optimizations easier to
918 propagate. Otherwise, though, boolean storage is either going to be
919 an 8-bit object or stored in a (potentially not 8-bit) machine
920 register or as a condition code. Bitfields are not implemented in
921 Rune's language (on purpose) <FONT color="red">but adjacent
922 booleans will overload onto 8, 16, 32, or 64 bit fields
923 in-structure as possible</FONT>.
925 * size_t is a signed 32-bit or signed 64-bit quantity of the same
926 width as a machine pointer and will be architecture-specific.
927 Rune programmers can depend on it being signed. This required
928 some thought but honestly any C programmer has hit up against
929 (many times) issues when wanting to use out-of-band values for
930 indexes such as -1 to mean special things, or to represent
931 error conditions, or there are system calls which can return -1,
932 or you want to have a signed range when doing arithmatic on size
933 and length fields, or pointer arithmatic, or in order to perform
934 certain conditionals. It just makes more sense for size_t to
937 size_t is the same width as a machine pointer by definition.
939 Because size_t is signed, all allocations and structures must be
940 sized less than 1/2 the size of the machine address space. Use
941 usize_t if you need an unsigned value.
943 * off_t is always a signed 64-bit quantity regardless of the
944 architecture, even if the architecture only supports 32-bit file
945 offsets. The Rune programmer can always assume that off_t is
946 64-bits regardless of the architecture.
948 Rune does not support 128-bit file offsets. This starts to get
949 into silly-land where a focus on the abstraction exceeds the value
955 <H2><B>(IV) Operational Stages</B></H2>
961 The Rune lexer converts a Rune source file into a stream of tokens.
962 The lexer is responsible for detecting and skipping comments and
963 whitespace, and for separting tokens out.
965 The Rune lexer is writen directly in C, uses mmap(), and is designed
966 to not have to deal with 0-terminated strings. Thise makes it
968 Tokens are tracked through a token_t structure which is typically
969 manipulated by reference, and an integer identifier is returned
970 along with the new token. The parser switches on this identifier
971 almost universally. The lexer has a look-ahead capability which
972 the parser uses on occassion.
978 The Rune parser takes a stream of tokens from the lexer and (well
979 Duhhh!) parses the language. The Rune parser will also recursively
980 open and parse lexical streams related to <B>import</B> statements.
982 The Rune parser is recursive-descent, written directly in C. Parser
983 elements are simply procedures. However, the language is LALR(1)
984 (or LALR(2) depending on how you look at it) and the parser never
985 has to back up. This makes the parser extremely fast.
987 The Rune parser constructs a hierarchy of statements, expressions, and
988 declarations on the fly. The primary hierarchical component that
989 glues everything together is the statement. For example,
990 the statement representing an import will have a reference to
993 However, declarations are used as the cornerstone of the semantic
994 identifier search and management subsystem. Any identifier that
995 can be looked up will have an associated declaration somewhere.
996 Declarations also earmark storage offsets within structures,
997 compound objects, procedures, and procedure arguments.
999 <B>The Rune parser does not attempt resolve identifiers at parse-time.
1000 This is one reason why Rune can have forward-referenced identifiers.
1001 Identifiers representing definitions are hashed at parse time,
1002 however. The parser holds identifiers in domains and collapses
1003 them when possible, but it is really up to the resolver pass to
1004 truly collapse identifiers.</B>
1010 The resolver is responsible for taking a parse set and turning it
1011 into something that can be interpreted or compiled. The Resolver
1012 is extremely sophisticated and must take at least three passes on
1015 <B>* Pass 1 -</B> Resolve subclass hierarchy. The resolver
1016 must first integrate declarations from the superclass into the
1017 subclass. Refinement issues are handled at this time. Note
1018 that the statement, expression, and declaration subhierarchies
1019 are duplicated for each subclass in order to allow Rune to optimize
1020 the refined procedures on a subclass-by-subclass basis. This
1021 greatly simplifies the job of the interpreter and compiler.
1023 Resolving the subclass hierarchy is a recursive affair. For
1024 example, the declarations in <B>Numeric</B> must be integrated
1025 with the declarations in <B>Integer</B> and from there integrated
1026 with the declarations in, say, <B>int8_t</B>.
1028 <B>* Pass 2 -</B> Resolve types, expressions, and declarations.
1029 This pass is responsible for assigning an intermediate type to
1030 each expression, resolving the types (figuring out actual
1031 storage and alignment requirements for a type), and resolving
1032 non-procedural declarations (figuring out the actual storage
1033 requirements for a declaration). This includes completely
1034 resolving compound types, the top-level, and classes, all of
1035 which are really just a list of declarations.
1037 This pass is responsible for looking up and resolving operators,
1038 procedures, and for enforcing casts. All of these operations
1039 involve manipulation of the expression hierarchy.
1041 <B>* Pass 3 -</B> Resolve temporary storage requirements. The
1042 interpreter and compiler needs to know about temporary
1043 storage requirements for expressions and aggregate
1044 storage requirements for procedures. For example, if you
1045 do something like <B>int a = (b + c) * d;</B> then we need
1046 to store the intermediate result from (b + c) somewhere.
1047 This pass figures out what those requirements are so the
1048 interpreter can allocate the necessary space.
1050 This pass allows the interpreter or compiler to know how much
1051 space a procedure requires to operate inclusive of variable
1052 declarations and temporary space. The Rune intepreter will
1053 reserve the space for the entire procedure up-front, on the
1054 stack, when the procedure is called. The resolver is also able
1055 to figure out legal overlappings for storage so when you
1056 have multiple executable blocks in a procedure, like this:
1057 <B>{ int a; ... } { int b; ... }</B>, Rune will only
1058 need to allocate 4 bytes of actual stack space to represent
1059 both <B>a</B> and <B>b</B>. The same goes for temporary
1060 space used by an expression. The resolver is aware of the
1061 difference between lvalue and non-lvalue intermediate storage
1062 and only needs to allocate actual space for non-lvalue storage.
1065 * Interpreter (selected resolver backend)
1068 The interpreter will execute a Rune program. It provides internal
1069 tie-ins to core classes, operators, and system calls, which are
1070 implemented by the interpreter itself rather then in Rune code.
1071 For example, adding two integers together ("+" on two ints)
1072 requires tie-ins to a native in-interpreter implementation of the
1075 The Rune interpreter will do on-the-fly optimization of the statement
1076 and expression hierarchy. For example, if you have a
1077 constant-producing procedure and you call it, the
1078 interpreter will interpret the procedure, recognize the
1079 constant result, and then shortcut the expression hierarchy so
1080 the constant can simply be supplied directly the next time that
1081 particular call is made. Another example is our internal
1082 bindings. When the interpreter sees an operator bound
1083 to an internal function it will resolve the binding and from then
1084 on simply call the function directly.
1086 Other common optimizations are things like <B>variable + constant</B>
1087 operations, which Rune will do for certain selected types. In most
1088 cases the interpreter simply changes the ex_Func function
1089 vector in the expression or st_Func function vector in the statement
1090 to achieve the optimization.
1092 Currently the Rune interpreter runs all Rune threads in a single
1093 pthread (N:1), owing to on-the-fly optimization model. Eventually
1094 it should be able to do SMP.
1097 * Code generator (selected resolver backend)
1100 The compiler will do partial interpretation to resolve constants
1101 and then generate pseudo-assembly output. This output is then
1102 run through a translator and finally the native assembler and linker,
1103 and linked against the Rune runtime library.
1105 The compiler generates RAS (Rune assembly) output. I am also
1106 attempting to generate LLVM output but I am having trouble with
1107 the LLVM backend taking enormous amounts of time to compile it
1108 (sometimes 10+ minutes for a simple program).
1110 Rune assembly output is pseudo-assembly designed to be easily
1111 translated into instructions for the target machine. It supports
1112 implied, 1-op, 2-op, and 3-op forms (1-op and 2-op for unary
1113 instructions, 2-op and 3-op for binary instructions). It also
1114 supports cache tagging to allow the target translator to registerize
1115 variables. Being pseudo-assembly it is weakly-typed... basically
1116 just 8, 16, 32, 64, and 128-bit operands (128 bits for floating point
1117 only, they aren't currently implemented for integers).
1119 The pseudo-instruction set and EA forms are orthogonal... it is the
1120 translator's job to convert the forms.
1123 * RAS Assembler (selected resolver backend)
1126 RAS converts pseudo-assembly into machine target assembly, currently
1127 just 64-bit x86-64. RAS is responsible for variable-life calculations,
1128 registerization, and certain instruction optimizations such as doing
1129 conditional reversals and inversions.
1132 * Linker (selected resolver backend)
1135 We use the system's native assembler and linker in the final stage
1136 of compilation to produce a native Rune binary. The native rune
1137 binary links against the Rune runtime library which provides basic
1138 threading, locking, ref-counting, heap, and system-call support.