From: Glenn Hutchings Date: Fri, 22 Apr 2016 16:24:59 +0000 (+0100) Subject: Revert to original minimal Inform lexer. X-Git-Url: https://jxself.org/git/?p=ibg.git;a=commitdiff_plain;h=a94081289bc21041a8daac44d8c8b6714a831281 Revert to original minimal Inform lexer. - Much more forgiving of incomplete files - Handles the !-inside-string case properly --- diff --git a/chapters/02.rst b/chapters/02.rst index 32f06a1..d8590cc 100644 --- a/chapters/02.rst +++ b/chapters/02.rst @@ -36,7 +36,7 @@ in which you initially write the game doesn't bear much resemblance to the text which the interpreter ultimately displays. For example, the "William Tell" game, in the form that we wrote it, starts like this: -.. code-block:: inform6 +.. code-block:: inform !============================================================================ Constant Story "William Tell"; @@ -53,7 +53,7 @@ Tell" game, in the form that we wrote it, starts like this: Class Room has light; - ! ... + ... You will never need to look at it in the form produced by the compiler:: diff --git a/chapters/03.rst b/chapters/03.rst index aff3993..517540f 100644 --- a/chapters/03.rst +++ b/chapters/03.rst @@ -50,7 +50,7 @@ that we design will start out like this. Follow these steps: #. In that folder, use your text editor to create this source file ``Heidi.inf``: - .. code-block:: inform6 + .. code-block:: inform !% -SD !============================================================================ @@ -200,7 +200,7 @@ looking at the source file. character. On this line, the first ``!`` is part of the sequence (or **string**) of characters to be displayed: - .. code-block:: inform6 + .. code-block:: inform print "Hello world!"; ! <- is the start of this comment @@ -208,7 +208,7 @@ looking at the source file. space (except when the spaces are part of a character string). So, these two rules tell us that we *could* have typed the source file like this: - .. code-block:: inform6 + .. code-block:: inform Constant Story "Heidi"; Constant Headline @@ -231,11 +231,11 @@ looking at the source file. * Every game needs the three lines which ``Include`` the standard library files -- that is, they merge those files' contents into your source file: - .. code-block:: inform6 + .. code-block:: inform Include "Parser"; Include "VerbLib"; - ! ... + ... Include "Grammar"; They always have to be in this order, with ``Parser`` and ``VerbLib`` @@ -244,7 +244,7 @@ looking at the source file. * Every game needs to define an ``Initialise`` routine (note the British spelling): - .. code-block:: inform6 + .. code-block:: inform [ Initialise; ]; @@ -259,7 +259,7 @@ looking at the source file. that's why we were able to take three lines to define the ``Headline`` constant - .. code-block:: inform6 + .. code-block:: inform Constant Headline "^A simple Inform example @@ -287,7 +287,7 @@ In IF, we talk about each of these locations as a **room**, even though in this example none of them has four walls. So let's use Inform to define those rooms. Here's a first attempt: -.. code-block:: inform6 +.. code-block:: inform Object "In front of a cottage" with description @@ -381,7 +381,7 @@ clearing. Now, although our descriptions mention or imply these available routes, we also need to explicitly add them to the room definitions in a form that the game itself can make sense of. Like this: -.. code-block:: inform6 +.. code-block:: inform Object before_cottage "In front of a cottage" with description @@ -471,7 +471,7 @@ At this stage, you should study the four room definitions, comparing them with the sketch map until you're comfortable that you understand how to create simple rooms and define the connections between them. -.. code-block:: inform6 +.. code-block:: inform !============================================================================ Constant Story "Heidi"; @@ -544,7 +544,7 @@ Given what we said earlier, you won't be surprised to hear that both the bird and its nest are Inform objects. We'll start their definitions like this: -.. code-block:: inform6 +.. code-block:: inform Object bird "baby bird" with description "Too young to fly, the nestling tweets helplessly.", @@ -572,7 +572,7 @@ relevant vocabulary so that the player can use whatever term seems appropriate to her, with a good chance of it being understood. We add a line to each definition: -.. code-block:: inform6 +.. code-block:: inform Object bird "baby bird" with description "Too young to fly, the nestling tweets helplessly.", @@ -624,7 +624,7 @@ that the player can type PUT (or INSERT) BIRD IN (or INTO) NEST. Furthermore, we label it as ``open``; this prevents the interpreter from asking us to open it before putting in the bird. -.. code-block:: inform6 +.. code-block:: inform Object nest "bird's nest" with description "The nest is carefully woven of twigs and moss.", @@ -636,7 +636,7 @@ To do this, we need to choose the locations where the player will find them. Let's say that the bird is found in the forest, while the nest is in the clearing. This is how we set this up: -.. code-block:: inform6 +.. code-block:: inform Object bird "baby bird" forest with description "Too young to fly, the nestling tweets helplessly.", @@ -658,7 +658,7 @@ but you'll find it convenient to insert them following the rooms where they're found. This means adding the bird just after the forest, and the nest just after the clearing. Here's the middle piece of the source file: -.. code-block:: inform6 +.. code-block:: inform !============================================================================ ! The game objects @@ -720,7 +720,7 @@ Adding the tree and the branch The description of the clearing mentions a tall sycamore tree, up which the player character supposedly "climbs". We'd better define it: -.. code-block:: inform6 +.. code-block:: inform Object tree "tall sycamore tree" clearing with description @@ -737,7 +737,7 @@ labelling the tree as ``scenery`` we suppress that, and also prevent it from being picked up by the player character. One final object: the branch at the top of the tree. Again, not many surprises in this definition: -.. code-block:: inform6 +.. code-block:: inform Object branch "wide firm bough" top_of_tree with description "It's flat enough to support a small object.", @@ -753,7 +753,7 @@ other objects *onto* the branch. (In passing, we'll mention that an object can't normally be both a ``container`` *and* a ``supporter``.) And so here are our objects again: -.. code-block:: inform6 +.. code-block:: inform !============================================================================ ! The game objects @@ -821,7 +821,7 @@ carrying the bird and the nest separately: we want the player character to put the bird into the nest first. One easy way to enforce this is by adding a line near the top of the file: -.. code-block:: inform6 +.. code-block:: inform !============================================================================ Constant Story "Heidi"; @@ -843,7 +843,7 @@ to put the bird in the nest, take the nest to the top of the tree, and place it on the branch; when that happens, the game should be over. This is one way of making it happen: -.. code-block:: inform6 +.. code-block:: inform Object branch "wide firm bough" top_of_tree with description "It's flat enough to support a small object.", diff --git a/chapters/04.rst b/chapters/04.rst index 62d471b..1010f26 100644 --- a/chapters/04.rst +++ b/chapters/04.rst @@ -2,6 +2,8 @@ Reviewing the basics ====================== +.. highlight:: inform + .. epigraph:: | *G was a gamester, who had but ill-luck;* diff --git a/chapters/05.rst b/chapters/05.rst index ca11e0b..f1342a9 100644 --- a/chapters/05.rst +++ b/chapters/05.rst @@ -64,7 +64,7 @@ LISTEN TO NEST or LISTEN TO TREE, but fairly inappropriate here; we really need to substitute a more relevant response after LISTEN TO BIRD. Here's how we do it: -.. code-block:: inform6 +.. code-block:: inform Object bird "baby bird" forest with description "Too young to fly, the nestling tweets helplessly.", @@ -133,7 +133,7 @@ false`` then the interpreter carries on to perform the default action as though it hadn't been intercepted. Sometimes that's what you want it to do, but not here: if instead we'd written this: -.. code-block:: inform6 +.. code-block:: inform Object bird "baby bird" forest with description "Too young to fly, the nestling tweets helplessly.", @@ -180,7 +180,7 @@ might lead her to believe that she can go inside: Again, that isn't perhaps the most appropriate response, but it's easy to change: -.. code-block:: inform6 +.. code-block:: inform Object before_cottage "In front of a cottage" with description @@ -221,7 +221,7 @@ receives the obviously nonsensical reply "You can't see any such thing". That's easy to fix; we can add a new ``cottage`` object, making it a piece of ``scenery`` just like the ``tree``: -.. code-block:: inform6 +.. code-block:: inform Object cottage "tiny cottage" before_cottage with description "It's small and simple, but you're very happy here.", @@ -244,7 +244,7 @@ response: The situation here is similar to our LISTEN TO BIRD problem, and the solution we adopt is similar as well: -.. code-block:: inform6 +.. code-block:: inform Object cottage "tiny cottage" before_cottage with description "It's small and simple, but you're very happy here.", @@ -282,7 +282,7 @@ currently gives the completely misleading response "I don't think much is to be achieved by that"). Yet another opportunity to use a ``before`` property, but now with a difference. -.. code-block:: inform6 +.. code-block:: inform Object tree "tall sycamore tree" clearing with description @@ -346,7 +346,7 @@ interception not on an object-by-object basis, as we have been doing so far, but instead for every ``Drop`` which takes place in our troublesome ``top_of_tree`` room. This is what we have to write: -.. code-block:: inform6 +.. code-block:: inform Object top_of_tree "At the top of the tree" with description "You cling precariously to the trunk.", @@ -427,7 +427,7 @@ Of course, you might think that the standard message "Dropped" is slightly unhelpful in these non-standard circumstances. If you prefer to hint at what's just happened, you could use this alternative solution: -.. code-block:: inform6 +.. code-block:: inform Object top_of_tree "At the top of the tree" with description "You cling precariously to the trunk.", @@ -454,7 +454,7 @@ nest, or vice versa. It would be better not to end the game until we'd checked for the bird actually being in the nest; fortunately, that's easy to do: -.. code-block:: inform6 +.. code-block:: inform Object branch "wide firm bough" top_of_tree with description "It's flat enough to support a small object.", diff --git a/chapters/06.rst b/chapters/06.rst index c93c887..f706c86 100644 --- a/chapters/06.rst +++ b/chapters/06.rst @@ -2,7 +2,7 @@ William Tell: a tale is born ============================== -.. highlight:: inform6 +.. highlight:: inform .. epigraph:: @@ -223,7 +223,7 @@ like this:: A track heads to the northeast.", has light; - ! ... + ... and we explained that just about *every* room needs that ``light`` attribute, or else the player would be literally in the dark. It's a bit @@ -245,7 +245,7 @@ write this:: A track heads to the northeast.", has ; - ! ... + ... We've done four things: @@ -333,7 +333,7 @@ and here is how we could have used it in "Heidi":: "Through the dense foliage, you glimpse a building to the west. A track heads to the northeast."; - ! ... + ... You'll notice that, if an object has no block of attributes, the semicolon which terminates its definition simply moves to the end of its last @@ -421,7 +421,7 @@ Let's see an example of this in action; here's a ``Prop`` object from Prop "south gate" street with name 'south' 'southern' 'wooden' 'gate', description "The large wooden gate in the town walls is wide open.", - ! ... + ... If players type EXAMINE GATE, they'll see "The large wooden gate..."; if they type CLOSE GATE then the gate's ``before`` property will step in and diff --git a/chapters/07.rst b/chapters/07.rst index 521fa7c..4a8031b 100644 --- a/chapters/07.rst +++ b/chapters/07.rst @@ -2,7 +2,7 @@ William Tell: the early years =============================== -.. highlight:: inform6 +.. highlight:: inform .. epigraph:: @@ -644,7 +644,7 @@ all of them loop statements that we don't encounter in this guide). if (condition) { statement; statement; - ! ... + ... } but other designers have their own preferences, including:: @@ -652,20 +652,20 @@ all of them loop statements that we don't encounter in this guide). if (condition) { statement; statement; - ! ... + ... } if (condition) { statement; statement; - ! ... + ... } if (condition) { statement; statement; - ! ... + ... } Although we've not yet needed to use it, now would probably be a good time diff --git a/chapters/08.rst b/chapters/08.rst index cf3f53a..656baa4 100644 --- a/chapters/08.rst +++ b/chapters/08.rst @@ -2,7 +2,7 @@ William Tell: in his prime ============================ -.. highlight:: inform6 +.. highlight:: inform .. epigraph:: diff --git a/chapters/09.rst b/chapters/09.rst index 6ce9f60..67f7aa5 100644 --- a/chapters/09.rst +++ b/chapters/09.rst @@ -2,7 +2,7 @@ William Tell: the end is nigh =============================== -.. highlight:: inform6 +.. highlight:: inform .. epigraph:: diff --git a/chapters/10.rst b/chapters/10.rst index d0c9638..1f1d4b2 100644 --- a/chapters/10.rst +++ b/chapters/10.rst @@ -65,7 +65,7 @@ Fade up on: a nondescript city street The game starts with meek John Covarth walking down the street. We set up the game as usual: -.. code-block:: inform6 +.. code-block:: inform !% -SD !============================================================================ @@ -132,7 +132,7 @@ up the game as usual: Almost everything is familar, apart from a few details: -.. code-block:: inform6 +.. code-block:: inform Constant MANUAL_PRONOUNS; Constant MAX_SCORE 2; @@ -166,7 +166,7 @@ we've decided to modestly award one point for each. By the way, the use of an equals sign ``=`` is optional with ``Constant``; these two lines have identical effect: -.. code-block:: inform6 +.. code-block:: inform Constant ROOM_SCORE 1; @@ -176,7 +176,7 @@ Another difference has to do with a special short-hand method that Inform provides for displaying strings of text. Until now, we have shown you: -.. code-block:: inform6 +.. code-block:: inform print "And now for something completely different...^"; return true; ... @@ -187,7 +187,7 @@ newline character, and return true. As you have seen in the previous example games, this happens quite a lot, so there is a yet shorter way of achieving the same result: -.. code-block:: inform6 +.. code-block:: inform "And now for something completely different..."; @@ -204,7 +204,7 @@ statement instead. You'll notice that -- unusually for a room -- our ``street`` object has a ``name`` property: -.. code-block:: inform6 +.. code-block:: inform Room street "On the street" with name 'city' 'buildings' 'skyscrapers' 'shops' 'apartments' 'cars', @@ -227,7 +227,7 @@ a normal room, it would seem logical that the phone booth is actually a big box on the sidewalk; therefore we define a ``container`` set in the street, which players may enter: -.. code-block:: inform6 +.. code-block:: inform Appliance booth "phone booth" street with name 'old' 'red' 'picturesque' 'phone' 'booth' 'cabin' @@ -270,7 +270,7 @@ intercept this attempt and redirect it (while we're at it, we add a connection to the as-yet-undefined café room and a default message for the movement which is not allowed): -.. code-block:: inform6 +.. code-block:: inform Room street "On the street" with name city' 'buildings' 'skyscrapers' 'shops' 'apartments' 'cars', @@ -284,12 +284,6 @@ the movement which is not allowed): "No time now for exploring! You'll move much faster in your Captain FATE costume."; -.. todo:: - - Notice how the syntax coloring thinks that the exclaimation point - above is a comment. This is another problem with the built-in inform6 - syntax highlighter. - That takes care of entering the booth. But what about leaving it? Players may type EXIT or OUT while they are inside an enterable container and the interpreter will oblige but, again, they might type @@ -297,7 +291,7 @@ NORTH. This is a problem, since we are actually in the street (albeit inside the booth) and to the north we have the café. We may provide for this condition in the room's ``before`` property: -.. code-block:: inform6 +.. code-block:: inform before [; Go: @@ -310,7 +304,7 @@ connection. However, that would be an ambiguous command, for it could also refer to the café, so we express our bafflement and force the player to try something else: -.. code-block:: inform6 +.. code-block:: inform n_to cafe, s_to [; <>; ], @@ -342,7 +336,7 @@ the ``inside_description`` of the container. If the library decides we can’t see outside the container, only the inside_description is displayed. Take for instance the following (simplified) example: -.. code-block:: inform6 +.. code-block:: inform Room stage "On stage" with description @@ -388,7 +382,7 @@ property of the ``street`` room a bit more complex, and change its value: instead of a string, we write an embedded routine. Here's the (almost) finished room: -.. code-block:: inform6 +.. code-block:: inform Room street "On the street" with name 'city' 'buildings' 'skyscrapers' 'shops' 'apartments' 'cars', @@ -415,7 +409,7 @@ value: instead of a string, we write an embedded routine. Here's the The description while inside the booth mentions the sidewalk, which might invite the player to EXAMINE it. No problem: -.. code-block:: inform6 +.. code-block:: inform Appliance "sidewalk" street with name sidewalk' 'pavement' 'street', @@ -432,7 +426,7 @@ result of a LOOK action (which will have to do with the way the café looks from the *inside*); but while we are on the street we need something else to describe it: -.. code-block:: inform6 +.. code-block:: inform Appliance outside_of_cafe "Benny's cafe" street with name 'benny^s' 'cafe' 'entrance', @@ -462,7 +456,7 @@ something else to describe it: by defining the ``description`` property as any of these: - .. code-block:: inform6 + .. code-block:: inform description "The town's favourite for a quick snack, Benny's caf@'e has a 50's @@ -498,7 +492,7 @@ out that it would be neater to handle the actual movement of the player in just one place of our code, because this helps clarity. To achieve this, we redirect the street's ``n_to`` property thus: -.. code-block:: inform6 +.. code-block:: inform n_to [; <>; ], @@ -546,7 +540,7 @@ responses. If nothing else, this adds to the general atmosphere, a nicety that many players regard as important. For this mission, we make use of the ``LibraryMessages`` object. -.. code-block:: inform6 +.. code-block:: inform Include "Parser"; @@ -599,16 +593,11 @@ of responses. The variable ``lm_n`` holds the current value of the number of the message to be displayed, so you can change the default with a test like this: -.. code-block:: inform6 +.. code-block:: inform if (lm_n == 39) "That's not something you need to refer to in order to SAVE the day."; -.. todo:: - - That block of code above should be colored. Is there a defect in the - syntax highlighting code? - where 39 is the number for the standard message "That's not something you need to refer to in the course of this game" -- displayed when the player mentions a noun which is listed in a room's name property, as we @@ -616,11 +605,11 @@ did for the ``street``. .. note:: - remember that when we are testing for different values of the + Remember that when we are testing for different values of the same variable, we can also use the switch statement. For the Miscellany entry, the following code would work just as nicely: - .. code-block:: inform6 + .. code-block:: inform ... Miscellany: diff --git a/chapters/11.rst b/chapters/11.rst index 2601971..49e2080 100644 --- a/chapters/11.rst +++ b/chapters/11.rst @@ -41,7 +41,7 @@ the door seems to be locked. We define the café room in simple form: -.. code-block:: inform6 +.. code-block:: inform Room cafe "Inside Benny's cafe" with description @@ -58,7 +58,7 @@ define the door object which lies between the café and the toilet. We've mentioned a counter: -.. code-block:: inform6 +.. code-block:: inform Appliance counter "counter" cafe with name 'counter' 'bar', @@ -108,7 +108,7 @@ NEST. Receive and LetGo are examples of what’s called a **fake action**. arrows are the only acceptable contents (recollect that ``~~``, to be read as "not", turns true into false and vice versa): - .. code-block:: inform6 + .. code-block:: inform before [; Drop,Give: @@ -128,7 +128,7 @@ way for the player to accomplish this. We've also mentioned some customers. These are treated as NPCs, reacting to our hero’s performance. -.. code-block:: inform6 +.. code-block:: inform Object customers "customers" cafe with name 'customers' 'people' 'customer' 'men' 'women', @@ -248,7 +248,7 @@ customers are -- so we need to make certain that the daemon does something interesting only while the player stays in the right place (and hasn’t wandered, say, back into the toilet): -.. code-block:: inform6 +.. code-block:: inform if (location ~= cafe) return; @@ -262,7 +262,7 @@ control the sequence of customers' remarks. When the Captain enters the café room from the toilet for the first time, the value of the property should be zero, so the statement block under the test: -.. code-block:: inform6 +.. code-block:: inform if (self.number_of_comments == 0) { self.number_of_comments = 1; @@ -280,7 +280,7 @@ daemon will continue normally to the next line. We want the customers to indulge in witticisms once they see the costumed Captain, but not on a completely predictable basis. -.. code-block:: inform6 +.. code-block:: inform if (random(2) == 1) ... @@ -311,7 +311,7 @@ the café in their Captain’s outfit, they’ll be coming from the toilet. As a consequence of all this, we add an ``after`` property to the café room object: -.. code-block:: inform6 +.. code-block:: inform Room cafe "Inside Benny's cafe" ... @@ -338,7 +338,7 @@ the player just came from the toilet, so we use an ``after`` property. The first line: -.. code-block:: inform6 +.. code-block:: inform if (noun ~= s_obj) return false; @@ -364,7 +364,7 @@ A door to adore Door objects require some specific properties and attributes. Let's first code a simple door: -.. code-block:: inform6 +.. code-block:: inform Object toilet_door "toilet door" cafe name name 'red' 'toilet' 'door', @@ -422,7 +422,7 @@ and its possible states affect both sides. However, the coding gets a little bit complicated and you''ll have to define routines for most properties: -.. code-block:: inform6 +.. code-block:: inform Object toilet_door "toilet door" with name 'red' 'toilet' 'door', @@ -462,7 +462,7 @@ the cafe", depending on the side we are facing. For this, a ``short_name property`` is the thing. We have already talked about the external name defined as part of an object's header information: -.. code-block:: inform6 +.. code-block:: inform Object toilet_door "toilet door" @@ -470,7 +470,7 @@ That ``toilet door`` will be the name displayed by the game at run-time to refer to the door. With identical effect, this could also have been coded thus: -.. code-block:: inform6 +.. code-block:: inform Object toilet_door with short_name "toilet door", @@ -481,7 +481,7 @@ retain the same external name throughout the game -- and the header information method is perfect in that case -- but if it needs to change, it's easy to write a routine as the value of ``short_name``: -.. code-block:: inform6 +.. code-block:: inform Object toilet_door with name 'red' 'toilet' 'door' @@ -508,7 +508,7 @@ adjectives -- perhaps a shining/flickering/fading/useless lantern. identifier within parentheses; that is, with no external name and no ``short_name`` property, we might see: - .. code-block:: inform6 + .. code-block:: inform You open the (toilet_door). @@ -517,7 +517,7 @@ adjectives -- perhaps a shining/flickering/fading/useless lantern. of our ``print`` statement, and then the standard rules would display the internal ID: - .. code-block:: inform6 + .. code-block:: inform You open the door to the toilet(toilet_door). @@ -544,7 +544,7 @@ If a few lines of code can make the life of the player easier, it's worth a shot. Let's provide a few improvements to our toilet door in ``before`` and ``after`` properties: -.. code-block:: inform6 +.. code-block:: inform before [ ks; Open: @@ -616,7 +616,7 @@ safely restore it afterwards. You’ll remember that a local variable in a standalone routine is declared between the routine’s name and the semicolon: -.. code-block:: inform6 +.. code-block:: inform [ BeenToBefore this_room; @@ -624,7 +624,7 @@ In exactly the same way, a local variable in an embedded routine is declared between the ``[`` starting marker of the routine and the semicolon: -.. code-block:: inform6 +.. code-block:: inform before [ ks; @@ -632,7 +632,7 @@ You can declare up to fifteen variables this way -- just separated by spaces -- which are usable only within the embedded routine. When we assign it thus: -.. code-block:: inform6 +.. code-block:: inform ks = keep_silent; @@ -641,7 +641,7 @@ has (either ``true`` or ``false``; we actually don't care). We then set ``keep_silent`` to ``true``, make the desired silent actions, and we assign: -.. code-block:: inform6 +.. code-block:: inform keep_silent = ks; @@ -660,7 +660,7 @@ So far, we have the player in front of a locked door leading to the toilet. A dead end? No, the description mentions a scribbled note on its surface. This one should offer no problem: -.. code-block:: inform6 +.. code-block:: inform Object "scribbled note" cafe with name 'scribbled' 'note', @@ -701,7 +701,7 @@ to ask for it, just as the note explains. Although we'll define Benny in detail throughout the next chapter, here we present a basic definition, largely so that the key has a parent object. -.. code-block:: inform6 +.. code-block:: inform Object benny "Benny" cafe with name 'benny', @@ -742,7 +742,7 @@ to belong to Benny"; however, the same wouldn't apply to other commands like TOUCH KEY and TASTE KEY . So, to prevent any interaction with the key while it’s in Benny’s pockets, we define a ``before`` property. -.. code-block:: inform6 +.. code-block:: inform before [; if (self in benny) @@ -766,7 +766,7 @@ continues unhindered. (In fact, the hat-on-a-pole ``Prop`` introduced on page 91 had this all-exclusive ``before`` property: -.. code-block:: inform6 +.. code-block:: inform before [; default: @@ -791,7 +791,7 @@ choose to examine the café from the outside. While it's unlikely that they'll try to examine the toilet room from the outside, it takes very little effort to offer a sensible output just in case: -.. code-block:: inform6 +.. code-block:: inform Object outside_of_toilet "toilet" cafe with name 'toilet' 'bath' 'rest' 'room' 'bathroom' 'restroom', diff --git a/chapters/12.rst b/chapters/12.rst index 7b632e4..4e8654a 100644 --- a/chapters/12.rst +++ b/chapters/12.rst @@ -125,7 +125,7 @@ It seems simple enough. So, following steps one and two, we add those ``pname.h`` right after it. ``Replace`` tells the compiler that we're providing replacements for some standard routines. -.. code-block:: inform6 +.. code-block:: inform Constant Story "Captain Fate"; Constant Headline @@ -155,7 +155,7 @@ relevant lines for the toilet door and the toilet key: Maybe specially highlight the lines using pname? -.. code-block:: inform6 +.. code-block:: inform Object toilet_door with pname '.x' 'red' '.x' 'toilet' 'door', @@ -169,7 +169,7 @@ relevant lines for the toilet door and the toilet key: while leaving the ``outside_of_toilet`` unchanged: -.. code-block:: inform6 +.. code-block:: inform Object outside_of_toilet "toilet" cafe with name 'toilet' 'bath' 'rest' 'room' 'bathroom' 'restroom', @@ -223,7 +223,7 @@ a coin near the lavatory, enough cash to pay for the coffee. And that about sums it all up; pretty simple to describe -- not so simple to code. Remember Benny's basic definition from the previous chapter: -.. code-block:: inform6 +.. code-block:: inform Object benny "Benny" cafe with name 'benny', @@ -236,7 +236,7 @@ code. Remember Benny's basic definition from the previous chapter: We can now add some complexity, beginning with a ``life`` property. In generic form: -.. code-block:: inform6 +.. code-block:: inform life [; Give: !... code for giving objects to Benny @@ -248,7 +248,7 @@ generic form: We have seen some of these actions before. We'll take care of the easier ones: -.. code-block:: inform6 +.. code-block:: inform Attack: if (costume has worn) { @@ -286,7 +286,7 @@ the coffee has been paid for, and whether the toilet key has been returned. The solution, yet again (this really is a most useful capability), is more local property variables: -.. code-block:: inform6 +.. code-block:: inform Object benny "Benny" cafe with name 'benny', @@ -305,7 +305,7 @@ which deals with commands like GIVE THE KEY TO BENNY (in a moment, we'll come to the ``Give`` action of the ``orders`` property, which deals with commands like BENNY, GIVE ME THE KEY): -.. code-block:: inform6 +.. code-block:: inform Give: switch (noun) { @@ -334,7 +334,7 @@ The Give action in the ``life`` property holds the variable ``noun`` as the object offered to the NPC. Remember that we can use the ``switch`` statement as shorthand for: -.. code-block:: inform6 +.. code-block:: inform if (noun == costume) { whatever }; if (noun == clothes) { whatever }; @@ -377,7 +377,7 @@ demands. The ``Give`` action in an ``orders`` property deals with inputs like ASK BENNY FOR THE KEY or BENNY, GIVE ME THE KEY. The syntax is similar to that of the ``life`` property: -.. code-block:: inform6 +.. code-block:: inform orders [; ! handles ASK BENNY FOR X and BENNY, GIVE ME XXX Give: @@ -468,7 +468,7 @@ indeed he will. But where? We must revisit the café room object: -.. code-block:: inform6 +.. code-block:: inform Room cafe "Inside Benny's cafe" with description @@ -537,7 +537,7 @@ chapter, this technique lets you trap the player who is about to exit a room before the movement actually takes place, a good moment to interfere if we want to prevent escape. The first line: -.. code-block:: inform6 +.. code-block:: inform if (noun ~= s_obj) return false; @@ -559,7 +559,7 @@ attempt to leave: The first three are covered by the test: -.. code-block:: inform6 +.. code-block:: inform if (benny.coffee_not_paid == true || benny.key_not_returned == true) ... diff --git a/chapters/13.rst b/chapters/13.rst index 3eb00a7..16b4283 100644 --- a/chapters/13.rst +++ b/chapters/13.rst @@ -26,7 +26,7 @@ Additional catering garnish We must not forget a couple of tiny details in the café room: -.. code-block:: inform6 +.. code-block:: inform Object food "Benny's snacks" cafe with name 'food' 'pastry' 'pastries' 'sandwich' 'sandwiches' 'snack' @@ -49,7 +49,7 @@ We must not forget a couple of tiny details in the café room: And a not-so-trivial object: -.. code-block:: inform6 +.. code-block:: inform Object coffee "cup of coffee" benny with name 'cup' 'of' 'coffee' 'steaming' 'cappuccino' @@ -121,7 +121,7 @@ erm, bogged down with details of the room's function or plumbing. There's not a lot about the toilet room and its contents, though there will be some tricky side effects: -.. code-block:: inform6 +.. code-block:: inform Room toilet "Unisex toilet" with description @@ -190,7 +190,7 @@ there's no light to see by. However, let's define first the light switch mentioned in the room's description to aid players in their dressing duties. -.. code-block:: inform6 +.. code-block:: inform Appliance light_switch "light switch" toilet with name 'light' 'switch', @@ -235,7 +235,7 @@ attribute, which is set or cleared automatically as needed. You can, of course, set or clear it manually like any other attribute, with the ``give`` statement: -.. code-block:: inform6 +.. code-block:: inform give self on; @@ -243,7 +243,7 @@ course, set or clear it manually like any other attribute, with the and check if a ``switchable`` object is on or off with the test: -.. code-block:: inform6 +.. code-block:: inform if (light_switch has on) ... @@ -252,14 +252,14 @@ and check if a ``switchable`` object is on or off with the test: A ``switchable`` object is OFF by default. However, you’ll notice that the has line of the object definition includes ``~on`` : -.. code-block:: inform6 +.. code-block:: inform has switchable ~on; Surely that’s saying "not-on"? Surely that's what would have happened anyway if the line hadn't mentioned the attribute at all? -.. code-block:: inform6 +.. code-block:: inform has switchable; @@ -318,7 +318,7 @@ perhaps it would be a good idea to append a little code to the door object to account for this. A couple of lines in the after property will suffice: -.. code-block:: inform6 +.. code-block:: inform after [ ks; Unlock: @@ -422,7 +422,7 @@ example to fix our particular problem. In the section "``Entry point routines``" of our game -- after the ``Initialise`` routine, for instance -- include the following lines: -.. code-block:: inform6 +.. code-block:: inform [ InScope person; if (person == player && location == thedark && real_location == toilet) { @@ -451,7 +451,7 @@ player is in *even when there is no light to see by*. So the test: -.. code-block:: inform6 +.. code-block:: inform if (person == player && location == thedark && real_location == toilet) ... @@ -518,7 +518,7 @@ every object that the player has picked up at one time in the game; have ``moved``. Here is the reworked ``InScope`` routine. There are a couple of new concepts to look at: -.. code-block:: inform6 +.. code-block:: inform [ InScope person item; if (person == player && location == thedark && real_location == toilet) { @@ -557,7 +557,7 @@ objects in the same room as the player, so we instead code: What is the actual :samp:`{statement}` that we'll repeatedly execute? -.. code-block:: inform6 +.. code-block:: inform if (item has moved) PlaceInScope(item); @@ -582,7 +582,7 @@ Amazing techicolour dreamcoats This leaves us the clothing items themselves, which will require a few tailored actions. Let's see first the ordinary garments of John Covarth: -.. code-block:: inform6 +.. code-block:: inform Object clothes "your clothes" with name 'ordinary' 'street' 'clothes' 'clothing', @@ -683,7 +683,7 @@ change into the hero's suit, after which we'll prevent a change back into ordinary clothes. So now we are dealing with a Captain Fate in full costume: -.. code-block:: inform6 +.. code-block:: inform Object costume "your costume" with name 'captain' 'captain^s' 'fate' 'fate^s' 'costume' 'suit', @@ -725,7 +725,7 @@ All the objects of our game are defined. Now we must add a couple of lines to the ``Initialise`` routine to make sure that the player does not start the game naked: -.. code-block:: inform6 +.. code-block:: inform [ Initialise; #Ifdef DEBUG; pname_verify(); #Endif; ! suggested by pname.h @@ -752,7 +752,7 @@ The designer of the package has made a debugging tool (a routine) to check for errors when using his library, and he tells us how to use it. So we include the suggested lines into our ``Initialise`` routine: -.. code-block:: inform6 +.. code-block:: inform #Ifdef DEBUG; pname_verify(); #Endif; @@ -788,7 +788,7 @@ line. Therefore, we must define a ``DeathMessage`` routine as we did in "William Tell", to write our customised messages and assign them to ``deadflag`` values greater than 2. -.. code-block:: inform6 +.. code-block:: inform [ DeathMessage; if (deadflag == 3) print "Your secret identity has been revealed"; @@ -802,7 +802,7 @@ Finally, we need to extend the existing grammar, to allow for a couple of things. We have already seen that we need a verb CHANGE. We'll make it really simple: -.. code-block:: inform6 +.. code-block:: inform [ ChangeSub; if (noun has pluralname) print "They're"; @@ -828,7 +828,7 @@ One might reasonably imagine that the ``default`` line at the end of the ``Give`` action in the orders property handles every input not already specified: -.. code-block:: inform6 +.. code-block:: inform orders [; Give: @@ -845,7 +845,7 @@ specified: Not so. The library grammar that deals with ASK BENNY FOR... is this (specifically, the last line): -.. code-block:: inform6 +.. code-block:: inform Verb 'ask' * creature 'about' topic -> Ask @@ -866,7 +866,7 @@ takes very little to allow Benny to use his default line for *any* undefined input from the player. We need to extend the existing ASK grammar: -.. code-block:: inform6 +.. code-block:: inform Extend 'ask' * creature 'for' topic -> AskFor; diff --git a/chapters/14.rst b/chapters/14.rst index 5cc4dca..234f502 100644 --- a/chapters/14.rst +++ b/chapters/14.rst @@ -99,7 +99,7 @@ use the placeholder ``statement_block`` to represent either a single We might need some custom syntax highlighting here -.. code-block:: inform6 +.. code-block:: inform statement; @@ -110,7 +110,7 @@ use the placeholder ``statement_block`` to represent either a single Our games have used these statements, about half of the Inform possibilities: -.. code-block:: inform6 +.. code-block:: inform give obj_id attribute; give obj_id attribute attribute ... attribute; @@ -158,7 +158,7 @@ possibilities: Although our example games haven't needed to use them, these looping statements are sometimes useful: -.. code-block:: inform6 +.. code-block:: inform break; continue; @@ -173,7 +173,7 @@ On the other hand, we suggest that you put the following statements on hold for now; they're not immediately relevant to everyday code and have mostly to do with printing and formatting: -.. code-block:: inform6 +.. code-block:: inform box font @@ -223,7 +223,7 @@ We've used all of these directives; note that for ``Class``, ``Extend``, ``Object`` and ``Verb`` the full supported syntax is more sophisticated than the basic form presented here: -.. code-block:: inform6 +.. code-block:: inform Class class_id with property value, @@ -274,7 +274,7 @@ than the basic form presented here: There's only a handful of useful directives which we haven't needed to use: -.. code-block:: inform6 +.. code-block:: inform Attribute attribute; @@ -288,7 +288,7 @@ use: but there's a whole load which are of fairly low importance for now: -.. code-block:: inform6 +.. code-block:: inform Abbreviate Array @@ -322,7 +322,7 @@ by using them within an object definition. You can create and initialise a property in an object's ``with`` segment: -.. code-block:: inform6 +.. code-block:: inform property, ! set to zero / false @@ -333,7 +333,7 @@ You can create and initialise a property in an object's ``with`` segment: In each case, the ``value`` is either a compile-time ``expression``, or an embedded routine: -.. code-block:: inform6 +.. code-block:: inform property expression, @@ -342,7 +342,7 @@ an embedded routine: You can refer to the value of a property: -.. code-block:: inform6 +.. code-block:: inform self.property ! only within that same object @@ -350,7 +350,7 @@ You can refer to the value of a property: and you can test whether an object definition includes a given property: -.. code-block:: inform6 +.. code-block:: inform (obj_id provides property) ! is true or false @@ -364,13 +364,13 @@ Inform provides standalone routines and embedded routines. Standalone routines are defined like this: -.. code-block:: inform6 +.. code-block:: inform [ routine_id; statement; statement; ... statement; ]; and called like this: -.. code-block:: inform6 +.. code-block:: inform routine_id() @@ -378,13 +378,13 @@ and called like this: These are embedded as the value of an object's property: -.. code-block:: inform6 +.. code-block:: inform property [; statement; statement; ... statement; ], and are usually called automatically by the library, or manually by: -.. code-block:: inform6 +.. code-block:: inform self.property() ! only within that same object @@ -397,7 +397,7 @@ which can be used only by the statements within the routine, and which are automatically initialised to zero every time that the routine is called: -.. code-block:: inform6 +.. code-block:: inform [ routine_id var_id var_id ... var_id; statement; statement; ... statement; ]; @@ -408,7 +408,7 @@ arguments within the parentheses when you call the routine. The effect is simply to initialise the matching local variables to the argument values rather than to zero: -.. code-block:: inform6 +.. code-block:: inform routine_id(expression, expression, ... expression) @@ -422,7 +422,7 @@ when calling the routine. Every routine returns a single value, which is supplied either explicitly by some form of return statement: -.. code-block:: inform6 +.. code-block:: inform [ routine_id; statement; statement; ... return expr; ]; ! returns expr @@ -432,13 +432,13 @@ or implicitly when the routine runs out of statements. If none of these ``statements`` is one -- ``return``, ``print_ret``, ``"..."` or ``<<...>>`` -- that causes an explicit return, then: -.. code-block:: inform6 +.. code-block:: inform [ routine_id; statement; statement; ... statement; ]; returns ``true`` and -.. code-block:: inform6 +.. code-block:: inform property [; statement; statement; ... statement; ] @@ -451,14 +451,14 @@ return False. Here's an example standalone routine which returns the larger of its two argument values: -.. code-block:: inform6 +.. code-block:: inform [ Max a b; if (a > b) return a; else return b; ]; and here are some examples of its use (note that the first example, though legal, does nothing useful whatsoever): -.. code-block:: inform6 +.. code-block:: inform Max(x,y); @@ -477,7 +477,7 @@ files, which you can optionally call from your source file if you require the functionality which the routine provides. We've mentioned these library routines: -.. code-block:: inform6 +.. code-block:: inform IndirectlyContains(parent_obj_id, obj_id) @@ -494,7 +494,7 @@ By contrast, an entry point routine is a routine which you can provide in your source file, in which case the library calls it at an appropriate time. We've mentioned these optional entry point routines: -.. code-block:: inform6 +.. code-block:: inform DeathMessage() @@ -502,7 +502,7 @@ appropriate time. We've mentioned these optional entry point routines: And this, the only mandatory one: -.. code-block:: inform6 +.. code-block:: inform Initialise() @@ -539,7 +539,7 @@ This is doubly true if you ever contemplate sharing a library extension with the rest of the community. This example, with the name changed, is from a file in the Archive: -.. code-block:: inform6 +.. code-block:: inform [xxxx i j; if (j==0) rtrue; @@ -569,7 +569,7 @@ Here's the same routine after a few minutes spent purely on making it more comprehensible; we haven't actually tested that it (still) works, though that second ``else`` looks suspicious: -.. code-block:: inform6 +.. code-block:: inform [ xxxx i j; if (i in player || i has static or scenery || j == nothing) return true; @@ -597,7 +597,7 @@ you'll come across. * These five lines all do the same thing: - .. code-block:: inform6 + .. code-block:: inform return true; return 1; @@ -607,7 +607,7 @@ you'll come across. * These four lines all do the same thing: - .. code-block:: inform6 + .. code-block:: inform return false; return 0; @@ -616,7 +616,7 @@ you'll come across. * These four lines all do the same thing: - .. code-block:: inform6 + .. code-block:: inform print "string"; new_line; return true; print "string^"; return true; @@ -625,28 +625,28 @@ you'll come across. * These lines are the same: - .. code-block:: inform6 + .. code-block:: inform print value1; print value2; print value3; print value1, value2, value3; * These lines are the same: - .. code-block:: inform6 + .. code-block:: inform ; return true; <>; * These lines are also the same: - .. code-block:: inform6 + .. code-block:: inform print "^"; new_line; * These ``if`` statements are equivalent: - .. code-block:: inform6 + .. code-block:: inform if (MyVar == 1 || MyVar == 3 || MyVar == 7) ... @@ -654,7 +654,7 @@ you'll come across. * These ``if`` statements are equivalent as well: - .. code-block:: inform6 + .. code-block:: inform if (MyVar ~= 1 && MyVar ~= 3 && MyVar ~= 7) ... if (MyVar ~= 1 or 3 or 7) ... @@ -663,7 +663,7 @@ you'll come across. expression; all that matters is its value: zero (false) or anything else (true). For example, these statements are equivalent: - .. code-block:: inform6 + .. code-block:: inform if (MyVar ~= false) ... if (~~(MyVar == false)) ... @@ -675,7 +675,7 @@ you'll come across. contains ``true`` (1), *not* whether its value is anything other than zero. - .. code-block:: inform6 + .. code-block:: inform if (MyVar == true) ... @@ -683,7 +683,7 @@ you'll come across. ``++MyVar;`` work the same as ``MyVar = MyVar + 1;`` For example, these lines are equivalent: - .. code-block:: inform6 + .. code-block:: inform MyVar = MyVar + 1; if (MyVar == 3) ... if (++MyVar == 3) ... @@ -699,7 +699,7 @@ you'll come across. cases the value of ``MyVar`` afterwards is 3. As another example, this code (from Helga in "William Tell"): - .. code-block:: inform6 + .. code-block:: inform Talk: self.times_spoken_to = self.times_spoken_to + 1; switch (self.times_spoken_to) { @@ -712,7 +712,7 @@ you'll come across. could have been written more succinctly like this: - .. code-block:: inform6 + .. code-block:: inform Talk: switch (++self.times_spoken_to) { 1: score++; @@ -725,7 +725,7 @@ you'll come across. * Similarly, the statements ``MyVar--;`` and ``--MyVar;`` work the same as ``MyVar = MyVar - 1;`` Again, these lines are equivalent: - .. code-block:: inform6 + .. code-block:: inform MyVar = MyVar - 1; if (MyVar == 7) ... if (--MyVar == 7) ... @@ -756,7 +756,7 @@ page 147 gives every object a ``pname`` property and a ``phrase_matched`` attribute). To create them, you would use these directives near the start of your source file: -.. code-block:: inform6 +.. code-block:: inform Attribute attribute; @@ -782,7 +782,7 @@ twenty-seven objects; omitting those which used ``found_in`` to define their placement at the start of the game, we're left with object definitions starting like this: -.. code-block:: inform6 +.. code-block:: inform Room street "A street in Altdorf" @@ -821,7 +821,7 @@ There's an alternative object syntax which is available to achieve the same object tree, using "arrows". That is, we could have defined those parent-and-child objects as: -.. code-block:: inform6 +.. code-block:: inform Room below_square "Further along the street" Furniture -> stall "fruit and vegetable stall" @@ -858,7 +858,7 @@ to illustrate how it works, imagine that at the start of the game the potatoes and the other fruit and vegetables where actually *on* the stall. Then we might have used: -.. code-block:: inform6 +.. code-block:: inform Room below_square "Further along the street" Furniture -> stall "fruit and vegetable stall" @@ -905,7 +905,7 @@ Perhaps somewhat unfortunately, Inform allows you to blur this clean distinction: you can use double quotes in name properties and Verb directives: -.. code-block:: inform6 +.. code-block:: inform NPC stallholder "Helga" below_square with name "stallholder" "greengrocer" "monger" "shopkeeper" "merchant" diff --git a/chapters/15.rst b/chapters/15.rst index 8004552..238c68f 100644 --- a/chapters/15.rst +++ b/chapters/15.rst @@ -108,7 +108,7 @@ alongside your lines if you wish, and will usually let you jump to a given line number. In this case, the error was caused by a semicolon after the description string, instead of a comma: -.. code-block:: inform6 +.. code-block:: inform Prop "assorted stalls" with name 'assorted' 'stalls', @@ -168,7 +168,7 @@ One common incident is to return in the middle of a statement block, before the rest of statements can be reached. This is not always as evident as it looks, for instance in a case like this: -.. code-block:: inform6 +.. code-block:: inform if (steel_door has open) { print_ret "The breeze blows out your lit match."; @@ -231,7 +231,7 @@ technique is then to divide it into a number of sections, each stored in a separate file, which you Include into a short master game file. For example: -.. code-block:: inform6 +.. code-block:: inform !============================================================================ Constant Story "War and Peace"; @@ -299,7 +299,7 @@ Debug mode off (just remove the ``-D``) when you release your game to the public. This is fortunately very easy to check, since the game banner ends with the letter "D" if the game was compiled in Debug mode: -.. code-block:: inform6 +.. code-block:: transcript Captain Fate A simple Inform example @@ -310,13 +310,11 @@ Switches are case sensitive, so you get different effects from ``-x`` and ``-X``. Some of the more useful switches are: :samp:`-~S` - Set compiler Strict mode off. This deactivates some additional error checking features when it reads your source file. Strict mode is on by default. :samp:`-v5 -v8` - Compile to this version of story file. Versions 5 (on by default) and 8 are the only ones you should ever care about; they produce, respectively, story files with the extensions .z5 and .z8 . Version 5 @@ -327,24 +325,20 @@ and ``-X``. Some of the more useful switches are: similar to Version 5 but allows a 512 Kbytes file size. :samp:`-D -X` - Include respectively the debugging verbs and the Infix debugger in the story file (see "Debugging your game" on page 197). :samp:`-h1 -h2` - Display help information about the compiler. ``-h1`` produces information about file naming, and ``-h2`` about the available switches. :samp:`-n -j` - ``-n`` displays the number of declared attributes, properties and actions. ``-j`` lists objects as they are being read and constructed in the story file. :samp:`-s` - Offer game statistics. This provides a lot of information about your game, including the number of objects, verbs, dictionary entries, memory usage, etc., while at the same time indicating the maximum @@ -352,7 +346,6 @@ and ``-X``. Some of the more useful switches are: nearing the limits of Inform. :samp:`-r` - Record all the text of the game into a temporary file, useful to check all your descriptions and messages by running them through a spelling checker. diff --git a/chapters/16.rst b/chapters/16.rst index 35c8f06..dbbd704 100644 --- a/chapters/16.rst +++ b/chapters/16.rst @@ -145,7 +145,7 @@ SHOWVERB *verb* library. The last line, however, is the direct consequence of our tailored ``Extend``: - .. code-block:: inform6 + .. code-block:: inform Extend 'give' * 'homage' 'to' noun -> Salute; diff --git a/conf.py b/conf.py index ec350ae..5d882f2 100644 --- a/conf.py +++ b/conf.py @@ -22,12 +22,12 @@ import codecs # documentation root, use os.path.abspath to make it absolute, like shown here. sys.path.insert(0, ".") -from tools.int_fiction import Inform6Lexer +from tools.inform import InformLexer from tools.transcript import TranscriptLexer # Setup function. def setup(app): - app.add_lexer('inform', Inform6Lexer()) + app.add_lexer('inform', InformLexer()) app.add_lexer('transcript', TranscriptLexer()) # -- General configuration ------------------------------------------------ @@ -108,7 +108,7 @@ default_role = "any" #show_authors = False # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'default' +pygments_style = 'friendly' # The default Pygments highlight language. highlight_language = 'none' diff --git a/tools/inform.py b/tools/inform.py new file mode 100644 index 0000000..94b4b03 --- /dev/null +++ b/tools/inform.py @@ -0,0 +1,109 @@ +""" +Inform 6 syntax highlighting. + +This is an ultra-minimal version compared to the standard Pygments Inform6 +lexer, but is much more forgiving of syntax errors. And it handles the +exclamation-inside-string case properly. +""" + +from pygments.lexer import RegexLexer +from pygments.token import (Text, Comment, Operator, Keyword, Name, + String, Number, Punctuation, Token) + +objects = ["Class", "Nearby", "Object"] + +directives = ["Abbreviate", "Array", "Attribute", "Btrace", "Class", + "Constant", "Default", "Dictionary", "End", "Endif", "Etrace", + "Extend", "Fake_action", "Global", "Ifdef", "Iffalse", + "Ifndef", "Ifnot", "Iftrue", "Ifv3", "Ifv5", "Import", + "Include", "Link", "Listsymbols", "Listdict", "Listverbs", + "Lowstring", "Ltrace", "Message", "Nearby", "Nobtrace", + "Noetrace", "Noltrace", "Notrace", "Object", "Property", + "Release", "Replace", "Serial", "Statusline", "Stub", + "Switches", "System_file", "Trace", "Verb", "Version", + "Zcharacter"] + +defining = ["[", "array", "attribute", "class", "constant", "fake_action", + "global", "lowstring", "nearby", "object", "property"] + +attributes = ["absent", "animate", "clothing", "concealed", "container", + "door", "edible", "enterable", "female", "general", "light", + "lockable", "locked", "male", "moved", "neuter", "on", "open", + "openable", "pluralname", "proper", "scenery", "scored", + "static", "supporter", "switchable", "talkable", "transparent", + "visited", "workflag", "worn"] + +properties = ["n_to", "s_to", "e_to", "w_to", "ne_to", "se_to", "nw_to", + "sw_to", "u_to", "d_to", "in_to", "out_to", "add_to_scope", + "after", "article", "articles", "before", "cant_go", "capacity", + "daemon", "describe", "description", "door_dir", "door_to", + "each_turn", "found_in", "grammar", "initial", + "inside_description", "invent", "life", "list_together", + "name", "number", "orders", "parse_name", "plural", + "react_after", "react_before", "short_name", "short_name_indef", + "time_left", "time_out", "when_closed", "when_open", "when_on", + "when_off", "with_key"] + +keywords = ["box", "break", "continue", "do", "else", "font off", "font on", + "for", "give", "has", "hasnt", "if", "in", "inversion", "jump", + "move", "new_line", "notin", "objectloop", "ofclass", "or", + "print", "print_ret", "provides", "quit", "read", "remove", + "restore", "return", "rfalse", "rtrue", "save", "spaces", + "string", "style bold", "style fixed", "style reverse", + "style roman", "style underline", "switch", "to", "until", + "while", "with"] + +constants = ["false", "true"] + +def wordlist(list): + return "(" + "|".join(list) + r")\b" + +class InformLexer(RegexLexer): + """ + Inform code lexer. + """ + + name = 'Inform 6' + aliases = ['inform', 'inform6', 'i6'] + filenames = ['*.inf'] + mimetypes = ['text/x-inform', 'application/x-inform'] + + tokens = { + 'root': [ + (r'"', String.Double, 'stringdouble'), + (r"'", String.Single, 'stringsingle'), + + (r'\n', Text), + (r'[^\S\n]+', Text), + (r'!.*$', Comment.Single), + (r'\\\n', Text), + (r'\\', Text), + (r'=', Operator), + (r"[A-Za-z_,]+:", Name.Label), + (r"<<\S+>>", Name.Label), + + (wordlist(objects), Name.Class), + (wordlist(keywords), Token.Keyword.Reserved), + (wordlist(properties), Name.Builtin), + (wordlist(directives), Name.Entity), + (wordlist(attributes), Name.Attribute), + (wordlist(constants), Name.Constant), + + (r'[a-zA-Z_][a-zA-Z0-9_.]*', Name), + (r'(\d+\.?\d*|\d*\.\d+)([eE][+-]?[0-9]+)?', Number.Float), + (r'\d+', Number.Integer), + + (r'.', Punctuation), + ], + + 'stringdouble': [ + (r'"', String.Double, '#pop'), + (r'.', String.Double), + (r'\n', String.Double), + ], + + 'stringsingle': [ + (r"'", String.Single, '#pop'), + (r'.', String.Single), + ], + }