Skip to content

Commit 0d5b1a1

Browse files
committedAug 15, 2021
PIE development
1 parent 20d0e75 commit 0d5b1a1

File tree

20 files changed

+143
-93
lines changed

20 files changed

+143
-93
lines changed
 

‎pie/pie/2 Designing a language/Commands.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ String operations are also quite straightforward. To assign a string value, use
1313
```
1414
put `This is a string` into Title
1515
```
16-
To append to an existing string you can use the _add_ keyword, but your compiler will need to check if it's being asked to do an arithmetic or a string operation, which may not be easy if your variables can hold either type. So it's probably better to use `append`:
16+
To append to an existing string you can use the `add` keyword, but your compiler will need to check if it's being asked to do an arithmetic or a string operation, which may not be easy if your variables can hold either type. So it's probably better to use `append`:
1717
```
1818
append `Some more text` to MyText
1919
```
@@ -28,7 +28,7 @@ When you're programming browser-based apps you'll almost certainly want concurre
2828

2929
Some other things you're likely to want at some point (some more important than others):
3030
- a set of REST commands so you can GET data from your own or remote websites and POST data back again
31-
- commands for handling JSON data; creating JSON objects adding and removing items from them etc.
31+
- commands for handling JSON data; creating JSON objects, adding and removing items from them etc.
3232
- commands for handling forms
3333
- a Google Maps module
3434
- floating-point arithmetic

‎pie/pie/2 Designing a language/Environment.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ The other decision concerns where the code is to run. If your compiler is coded
88

99
Some might prefer to code in C++ or Java. Many compilers are written in C++ so there's something to be said for that, though if you want to distribute your efforts you'll have to do versions for Windows, for Mac and for Linux.
1010

11-
There are many, many other alternatives but the one that stands out is JavaScript, because it runs in every browser on the planet. Many people, most notably Chromebook owners, rarely venture outside the browser. Your apps can reside on a webserver and be available simply by typing a URL. Add to this a superb graphics environment and the case is unanswerable.
11+
There are many, many other alternatives but JavaScript stands out because it runs in every browser on the planet. Many people, most notably Chromebook owners, rarely venture outside the browser. Your apps can reside on a webserver and be available simply by typing a URL. Add to this a superb graphics environment and the case is unanswerable.
1212

1313
In this book I will assume the browser is the environment and JavaScript is what we'll use to write the new language. JavaScript, as noted above, is incredibly powerful and is well up to the job of being an "assembly language" in which to code higher-level software.
1414

‎pie/pie/2 Designing a language/Example code.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Before I launch into a description of the actual arithmetic functions I'll first
66

77
## Constants, values and variables
88

9-
A _constant_ is an entity whose value is fixed for all time, such as 14, 3996 or "Kg". Some computer languages let you give a name to a constant (these are called _manifest constants_); this helps if you use the same constant in many places and later want to give it a different value; it saves having to hunt down every occurrence.
9+
A _constant_ is an entity whose value is fixed for all time, such as 14, 3996, "37.02" or "Kg". Some computer languages let you give a name to a constant (these are called _manifest constants_); this helps if you use the same constant in many places and later want to give it a different value; it saves having to hunt down every occurrence.
1010

1111
A _value_ is any entity that can be used as part of a calculation or other language command. It might be a constant as defined above, it might be the contents of a variable as defined next, or it might be something else that is only valid at the point you actually use it, such as the time of day or the size of a file. To cope with all this variation we'll implement a "value" as a _specification_ of how to obtain the actual numeric, boolean or textual value to use in the command.
1212

‎pie/pie/3 Compilation/Compiler.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ Looking at each of the functions in turn:
9292

9393
`rewindTo(index)` restores the current index to a specified value.
9494

95-
A keyword processor consists mainly of calls to these functions as it works its way along the token list After a while you will become very familiar with using many of them. The operation of your compiler should be very easy to follow and new functionality is easy to add.
95+
A keyword processor consists mainly of calls to these functions as it works its way along the token list. After a while you will become very familiar with using many of them. The operation of your compiler should be very easy to follow and new functionality is easy to add.
9696

9797
The rest of the main compiler module comprises functions to manage progress along the token list. Before describing these I'll introduce the concept of _domains_.
9898

‎pie/pie/3 Compilation/DOM.txt

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,36 @@ Here's the handler for a `div` variable:
145145
```
146146
Most of the work is done by `compiler.compileVariable(domain, keyword, isVHolder, extra)`, which is described on the ~tid:Variables~ page.
147147

148-
The remaining functions are not themselves DOM objects but have roles that work with the DOM and with other browser features. Some are simple, like `enable` and `disable` but some are quite lengthy and repetitive, with many different variants of syntax to handle. If you've been following things this far there's little need to work laboriously through an example here; better to study the code in the _**EasyCoder**_ repository.
148+
The remaining functions are not themselves DOM objects but have roles that work with the DOM and with other browser features. Some are simple, like `enable` and `disable` but some are quite lengthy and repetitive, with many different variants of syntax to handle. I'll just give a single example here:
149+
```
150+
} else if (token === `class`) {
151+
if (compiler.nextTokenIs(`of`)) {
152+
if (compiler.nextIsSymbol()) {
153+
const symbol = compiler.getSymbolRecord();
154+
if (symbol.extra === `dom`) {
155+
if (compiler.nextTokenIs(`to`)) {
156+
const value = compiler.getNextValue();
157+
compiler.addCommand({
158+
domain: `browser`,
159+
keyword: `set`,
160+
lino,
161+
type: `setClass`,
162+
symbolName: symbol.name,
163+
value
164+
});
165+
return true;
166+
}
167+
}
168+
}
169+
}
170+
}
171+
```
172+
This fragment is for the command
173+
```
174+
set the class of <DOM variable> to <class>
175+
```
176+
The compiler has already recognized `set` to get to this function, skipped over `the` and is now running down a list of all the things that might follow. (In some cases a `switch` might work better than a chained `if`.) Having seen `class` it checks that `of` follows then picks up the symbol name, gets its record from the symbol table and checks it's a valid DOM variable. Then it moves over `to` and gets the value that follows. Finally it builds a command object , posts it into the program array and returns `true`.
177+
178+
Most of the DOM commands compile in much the same way so I won't work laboriously through the entire domain module, which is in the _**EasyCoder**_ repository as `Browser.js`.
149179

150180
~pn:3 Compilation/Multitasking:Multitasking:3 Compilation/Values:Value handlers~

‎pie/pie/3 Compilation/Domains.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,6 @@ One of the most important features of this system is the way it tries domains in
4141
throw new Error(`I don't understand '${token}...'`);
4242
},
4343
```
44-
The function iterates the names of the domains, calling `getHandler()` on each one. If the domain is able to process the keyword it returns a handler function, which the compiler then calls to compile the token. This permits several domains to handle different variants of the same keyword. As soon as one of them returns `true` the function can return, knowing that the domain will have posted its compiled code into the program list. Note the way that `mark()` and `rewind()` are used to back up and try the same token with a different domain. If all of them fail it's an error and compilation stops.
44+
In the above, `this.domain` is a list of domain modules indexed by their names. The function iterates these, calling `getHandler()` on each one. If the domain is able to process the keyword it returns a handler function, which the compiler then calls to compile the token. This permits several domains to handle different variants of the same keyword. As soon as one of them returns `true` the function can return, knowing that the domain will have posted its compiled code into the program list. Note the way that `mark()` and `rewind()` are used to back up and try the same token with a different domain. If all of them fail it's an error and compilation stops.
4545

4646
~pn:3 Compilation/Compiler:Building a compiler:3 Compilation/Variables:Compiling variables~

‎pie/pie/3 Compilation/If.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
The second example is a handler for the `if` statement; a vital part of any language. The full spec is this:
44

55
```
6-
if <condition> then <command> else <command>
6+
if <condition> then <command> [else <command>]
77
```
88
where the `else` clause may or may not be present. Here's the current _**EasyCoder**_ code for the `if` handler:
99
```

‎pie/pie/3 Compilation/Multitasking.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@ Here's the code to compile a `go` command:
4343
The first part of the code gets the line number as usual, then checks if `go` is followed by an optional `to`. You might also arrange for `goto` (without a space) to call the same compiler function. Next it gets the next token, which is assumed to be the name of a label, and returns a command object with the relevant information.
4444

4545
## Subroutines
46-
Here's another legacy from good old BASIC. In those days subroutines were there to allow the same code to be called from several different places, avoiding repetition. Today we have _functions_, which as as different to subroutines as the Taj Mahal is to a house brick. Unfortunately, it's rather hard to devise a syntax for functions that can be easily understood when read out loud, but it's quite easy to do for a subroutine. So let's keep things simple.
46+
Here's another legacy from good old BASIC. In those days subroutines were there to allow the same code to be called from several different places, avoiding repetition. Today we have _functions_, which are as different to subroutines as the Taj Mahal is to a house brick. Unfortunately, it's rather hard to devise a syntax for functions that can be easily understood when read out loud, but it's quite easy to do for a subroutine. So let's keep things simple.
4747

48-
The simplest form of a subroutines is just a section of code terminated with a `return` command. You can enter it at any point above that as there's nothing special happening in the way it would for a modern function. No parameters, no local variables. To call the subroutine we use a `gosub` command. This is identical to `go` except for the name of the keyword.
48+
The simplest form of a subroutine is just a section of code terminated with a `return` command. You can enter it at any point above that as there's nothing special happening in the way it would for a modern function. No parameters, no local variables. To call the subroutine we use a `gosub` command. The compiler part of this is identical to `go` except for the name of the keyword.
4949

5050
## Multitasking
5151
JavaScript is a single-threaded programming language, which means it can only do one thing at a time, but your custom language can be built in such as way as to 'appear' to be able to multi-task.
@@ -122,10 +122,10 @@ Loop2:
122122
print `buzz`
123123
end
124124
```
125-
There are two loops, each one of which waits for a length of time then prints a message to the console. The `fork` command starts the second loop, but instead of waiting for that to finish as `gosub` would do, it then goes into the first loop. Each time a loop hits its `wait` command the other loop gets a chance to run. The result on the console is a series of _fizz_ and _buzz_ lines, the one appearing more frequently than the other.
125+
There are two loops, each one of which waits for a length of time then prints a message to the console. The `fork` command starts the second loop, but instead of waiting for that to finish as `gosub` would do, it then goes into the first loop. Each time a loop hits its `wait` command the other loop gets a chance to run. The result on the console is a series of _fizz_ and _buzz_ lines, the one appearing more frequently than the other. (If you try this in the _**EasyCoder**_ Codex or on your own web page you'll need to open a browser console window to see the output.)
126126

127127
The `fork` handler is identical to `go` and `gosub` except for the name of the keyword.
128128

129-
As noted, `go`, `gosub` and `fork` are all compiled identically. The differences come in the runtime, which we'll come to later in the book.
129+
As noted, `go`, `gosub` and `fork` are all compile identically. The differences come in the runtime, which we'll come to later in the book.
130130

131131
~pn:3 Compilation/If:The `if` handler:3 Compilation/DOM:Domain Object Model commands~

‎pie/pie/3 Compilation/Values.txt

Lines changed: 66 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
11
# Value handlers
22

3-
In your new language, a _value_ is a single integer, boolean or string quantity. (By single, I mean that map coordinates specifying a given location are not a value; they're a pair of values.) The language has a number of variable types that can be treated as having values according this definition. It also permits the inclusion of variable types that hold other data types such as coordinates or floating-point quantities. To keep things simple I'll ignore these in the following discussion.
3+
In your new language, a _value_ is a single integer, boolean, string or object. (By single, I mean that map coordinates specifying a given location are not a value unless they are held as the object `{latitude, longitude}`.) The language has a number of variable types that can be treated as having simple numeric or string values, but it also permits the inclusion of variable types that hold data types such as coordinates (as just shown) or floating-point quantities. To keep things simple I'll ignore these in the following discussion.
44

5-
A value is a specification of what must be done to retrieve the quantity represented by that value. The distinction is important; the specification is fixed and has a meaning at compile time as well as runtime, but it can only be applied at runtime to retrieve the quantity it represents. A good example might be a value that represents the current timestamp - the number of seconds elapsed since January 1st 1970. This obviously increases every second so its value at compile time is not very useful.
5+
A value is a _specification_ of what must be done to retrieve the quantity represented by that value. The distinction is important; the specification is fixed and has a meaning at compile time as well as runtime, but it can only be applied at runtime to retrieve the quantity it represents. A good example might be a value that represents the current timestamp - the number of seconds elapsed since January 1st 1970. This obviously increases every second so its value at compile time is not very useful.
66

77
Each specification has a number of properties; how many depends on the type of the value. Here are some of those found in the _**EasyCoder**_ language; your own language may well have its own set depending on your concept of what it means for something to have a value.
88

99
`domain` - the current compilation unit. The language permits plug-in extensions to handle unlimited variations in syntax; each plugin deals with a set of commands for a particular domain such as general programming, the DOM, JSON handling, REST, Google Maps etc. This property identifies where the runtime engine should look in order to find a runtime handler for the given value. The domain may be omitted where the value is intrinsic to the core of the compiler.
1010

1111
`type` - the type of this value. Examples are
1212

13-
`constant`, which denotes a numeric or string value. This is an intrinsic type.
13+
> `constant`, which denotes a numeric or string value. This is an intrinsic type.
1414

15-
`left`, which returns a specified number of characters from a string. This comes from the core package, dealing with general-purpose programming.
15+
> `left`, which returns a specified number of characters from a string. This comes from the core package, dealing with general-purpose programming.
1616

17-
`screenWidth`, which returns the screen screen width. This is a browser DOM value.
17+
> `screenWidth`, which returns the screen screen width. This is a browser DOM value.
1818

19-
`latitude`, which might return a floating-point value or a string representation of one. This might be found in a Maps plugin.
19+
> `latitude`, which might return a floating-point value or a string representation of one. This might be found in a Maps plugin.
2020

21-
A value object may have no properties other than `type` itself - an example being `screenWidth` - or it may have several; some fixed and others evaluated at runtime. Ordinary numeric/string values have a flag to say which data type is being held in the variable and the actual content itself.
21+
A value object might have no properties other than `type` itself - an example being `screenWidth` - or it could have several; some fixed and others evaluated at runtime. Ordinary numeric/string values have a flag to say which data type is being held in the variable and the actual content itself.
2222

2323
When building your own language you may decide to follow the structure of _**EasyCoder**_ or to go for something completely different.
2424

@@ -58,64 +58,65 @@ If `null` is returned, signifying a failure to compile, it doesn't automatically
5858
Here's the first part of the `value.compile` function in _**EasyCoder**_'s `core` domain:
5959

6060
```
61-
compile: compiler => {
62-
if (compiler.isSymbol()) {
63-
const name = compiler.getToken();
64-
const symbolRecord = compiler.getSymbolRecord();
65-
switch (symbolRecord.keyword) {
66-
case `module`:
67-
compiler.next();
68-
return {
69-
domain: `core`,
70-
type: `module`,
71-
name
72-
};
73-
case `variable`:
74-
const type = compiler.nextToken();
75-
if ([`format`, `modulo`].includes(type)) {
76-
const value = compiler.getNextValue();
77-
return {
78-
domain: `core`,
79-
type,
80-
name,
81-
value
82-
};
83-
}
84-
return {
85-
domain: `core`,
86-
type: `symbol`,
87-
name
88-
};
89-
}
90-
return null;
91-
}
92-
93-
var token = compiler.getToken();
94-
if (token === `true`) {
95-
compiler.next();
96-
return {
97-
domain: `core`,
98-
type: `boolean`,
99-
content: true
100-
};
101-
}
102-
if (token === `false`) {
103-
compiler.next();
104-
return {
105-
domain: `core`,
106-
type: `boolean`,
107-
content: false
108-
};
109-
}
110-
if (token === `random`) {
111-
compiler.next();
112-
const range = compiler.getValue();
113-
return {
114-
domain: `core`,
115-
type: `random`,
116-
range
117-
};
118-
}
61+
compile: compiler => {
62+
if (compiler.isSymbol()) {
63+
const name = compiler.getToken();
64+
const symbolRecord = compiler.getSymbolRecord();
65+
switch (symbolRecord.keyword) {
66+
case `module`:
67+
compiler.next();
68+
return {
69+
domain: `core`,
70+
type: `module`,
71+
name
72+
};
73+
case `variable`:
74+
const type = compiler.nextToken();
75+
if ([`format`, `modulo`].includes(type)) {
76+
const value = compiler.getNextValue();
77+
return {
78+
domain: `core`,
79+
type,
80+
name,
81+
value
82+
};
83+
}
84+
return {
85+
domain: `core`,
86+
type: `symbol`,
87+
name
88+
};
89+
}
90+
return null;
91+
}
92+
93+
var token = compiler.getToken();
94+
if (token === `true`) {
95+
compiler.next();
96+
return {
97+
domain: `core`,
98+
type: `boolean`,
99+
content: true
100+
};
101+
}
102+
if (token === `false`) {
103+
compiler.next();
104+
return {
105+
domain: `core`,
106+
type: `boolean`,
107+
content: false
108+
};
109+
}
110+
if (token === `random`) {
111+
compiler.next();
112+
const range = compiler.getValue();
113+
return {
114+
domain: `core`,
115+
type: `random`,
116+
range
117+
};
118+
}
119+
...
119120
```
120121
It starts by checking if the current token is a symbol. The `core` domain only has 2 variable types - `module` and `variable`. The first of these has a value being the name of the module; the second either has the value of its content or it might be one of
121122
```

‎pie/pie/3 Compilation/Variables.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ It starts by checking for a duplicate token name, then adds an entry to the symb
4040

4141
`isSymbol` - a boolean value that confirms this command contains a symbol.
4242

43-
`used` - a boolan value that starts `false` and is changed to `true` as soon as the compiler comes across a command that assigns it a value. This allows a post-compilation check to be made for unused variables. Note that simply reading a variable does not set the flag (this would defeat the purpose of identifying it as unused). Unused variables are a frequent source of errors when you come to run your program.
43+
`used` - a boolean value that starts `false` and is changed to `true` as soon as the compiler comes across a command that assigns it a value. This allows a post-compilation check to be made for unused variables. Note that writing to a variable does not set the flag as this does not count as using it. Unused variables are a frequent source of errors when you come to run your program.
4444

4545
`isVHolder` - tells the compiler that this variable is able to hold a numeric or a string value. Many variable types do not so this permits another compilation check to be made that a script is not attempting to assign a value to one of them.
4646

‎pie/pie/3 Compilation/content.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@
66

77
Before embarking on the design of a compiler it's probably best to settle what it should do. In the old days the main choice was between an _interpreter_ and a _compiler_. The first of these takes instructions directly from the source text, works out what they mean and performs the desired functions one at a time according to the program flow. This avoids the need to wait for the entire program to compile (something that used to take rather a long time) but has several disadvantages. Firstly, no error checking is done before the program runs. Secondly, if instructions are repeated (in _for_ loops for example) they are re-interpreted each time. This will usually make the language slow. Thirdly, flow control statements such as _if_, _while_ or _for_ require the progam to choose a path that depends on the outcome of a test. A simple interpreter has no knowledge of where execution should resume, other than by scanning the entire program to find out. This is extremely time-consuming.
88

9-
The second choice used to be a compiler, which examines the entire program and converts it into the machine-level code needed for the processor to execute it. The program will run far more quickly but you have to wait for compilation to complete before it starts. Once the compiled code is running you have no control over it, unlike with an interpreter which is still managing things as the program runs.
9+
The second choice used to be a compiler, which examines the entire program and converts it into the machine-level code needed for the processor to execute it. The program will run far more quickly but you have to wait for compilation to complete before it starts and the compiler is usually a completely separate program. It's rare to see a compiler that runs inside the browser. Once the compiled code is loaded and running you have no control over it, unlike with an interpreter which is still managing things as the program runs.
1010

1111
That was the old days. Today the choices are far more nuanced. Interpreters can "learn as they go" so although the program may start slowly it will pick up speed as the interpreter re-uses parts of the code, having left information that will help it the next time it encounters the same code.
1212

1313
Another big change is that compilers don't have to generate "machine code" specific to any given processor architecture. Many compilers, most notably Java, generate code for a hypothetical machine that rarely exists as an actual computing device. A separate run-time engine then "pretends to be" that device and runs the code on whatever hardware it's installed on. The runtime engine is in effect an interpreter, but the code it's running is optimized for speed and efficiency. This approach gives us the best of both worlds.
1414

15-
The compiler I will describe here will generate code that can easily be interpreted and run in a browser.
15+
The compiler I will describe here will run in the browser itself and generate code that will run instantly in the same browser using a runtime interpreter.
1616

1717
## Compiler strategy
1818

@@ -38,7 +38,7 @@ There are several points along the way where more than one possibility branches
3838

3939
And this is essence is how our compiler will do its job; by working its way along a command, trying all the possibilities at each step, backing up and retrying when none match and declaring success or failure at the end. This may sound terribly inefficient but actually it's not. There are a number of advantages to the strategy. One is it needs only a single pass through the source code. Another is it creates code for the hypothetical target machine as it goes. And thirdly is it's very easy to follow and to enhance as new syntax needs to be added.
4040

41-
However, all of the above assumes the program is presented to the compiler as a series of tokens. So we'll have to do a little work on the source script before we can give it to the compiler. This is the job of the _tokenizer_. But before we look at that, here's a note about how to choose good function names.
41+
All of the above assumes the program is presented to the compiler as a series of tokens. So we'll have to do a little work on the source script before we can give it to the compiler. This is the job of the _tokenizer_. But before we look at that, here's a note about how to choose good function names.
4242

4343
## Function naming
4444

‎pie/pie/4 Runtime/DOM.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ As before, first we get the command, then the symbol table record for the target
2929

3030
When we create a DOM object we can make it a direct child of the page BODY or of another DOM element. In the latter case, the parent will have been specified in the script, so we can get its record, and from that the actual DOM element (which will only exist if the parent has also been `create`d or has been `attach`ed to a suitable element in the document).
3131

32-
Now we create a new element, giving it the type, e.g. `dom`. We must give it an ID that is guaranteed to be unique; I choose to use a 3-part name comprising the variable name, its array index and a global serial number that increments for every DOM element. This combination ID is very useful when using the browser debugger as it becomes quite clear how any element relates to the script. So a typical ID looks like
32+
Now we create a new element, giving it the type, e.g. `div`. We must give it an ID that is guaranteed to be unique; I choose to use a 3-part name comprising the variable name, its array index and a global serial number that increments for every DOM element created. This combination ID is very useful when using the browser debugger as it becomes quite clear how any element relates to the script. So a typical ID looks like
3333
```
3434
MyDiv-0-392
3535
```
@@ -78,7 +78,7 @@ In _**EasyCoder**_ it's common to create an array of DOM variables that respond
7878

7979
Three items of information need to be retrieved when a mouse click occurs, so these are added to the DOM element as properties. Bear in mind that at the point this code runs there hasn't yet been a mouse click; we're just setting up for when they do happen.
8080

81-
Next we set up the `onclick` listener. The content of this is what will handle the actual click. We set up a global record to record the target element and the click location; this is needed for drag and drop operations. We 'blur' everything except radio buttons (to remove the focus), then we set the index of the DOM variable to the one that was clicked, allowing the `<do something>` code to know which element it's dealing with.
81+
Next we set up the `onclick` listener. The content of this is what will handle the actual click. We set up the global record `clickData` to record the target element and the click location; this is needed for drag and drop operations. We 'blur' everything except radio buttons (to remove the focus), then we set the index of the DOM variable to the one that was clicked, allowing the `<do something>` code to know which element it's dealing with.
8282

8383
Finally, we request a new execution thread for the actions resulting from the click. It's best to do this after a short pause, otherwise the display doesn't have time to update before the actions start to take effect.
8484

‎pie/pie/4 Runtime/Handlers.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ Every keyword has a runtime handler function alongside the compiler function des
3434
return command.pc + 1;
3535
}
3636
```
37-
We start by extracting the command from the program (passed in as the single parameter) at the index given by `program.pc`. Then we get from it the two values to be added and the name of the _target_ variable - that is, where the result is going. Next we get the symbol table record for that variable and check if it's able to hold a value. If not, we throw an error.
37+
We start by extracting the command from the program (passed in as the single parameter) at the index given by `program.pc`. Then we get from it the two values to be added and the name of the _target_ variable - that is, where the result is going. Next we get the symbol table record for _target_ and check if it's able to hold a value. If not, we throw an error.
3838

3939
Next we get the current value of the target, by using its array index. Remember that every variable is an array although most only ever have a single element.
4040

‎pie/pie/4 Runtime/content.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ We've all done it; we've set up a program loop and forgotten to increment the lo
3535

3636
### Trace and debug
3737

38-
If you add a `trace` command you can arrange for the program to stop at each command and post information about itself into a special on-screen `<div>`, then permit the user to interact with the tracer to single-step, do further inspection of variables or resume execution. This can be a very valuable tool during development. You still have the browser debugger abvailable to show you what's happening to your JavaScript, but the tracer operates with knowledge of variable names that aren't easy to find in the low-level debugger.
38+
If you add a `trace` command you can arrange for the program to stop at each command and post information about itself into a special on-screen `<div>`, then permit the user to interact with the tracer to single-step, do further inspection of variables or resume execution. This can be a very valuable tool during development. You still have the browser debugger available to show you what's happening to your JavaScript, but the tracer operates with knowledge of variable names that aren't easy to find in the low-level debugger.
3939

4040
Trace/debug is implemented in _**EasyCoder**_. The code is all in the `Run.js` file and there's a page in the [Codex](https://easycoder.github.io?s=step10) describing the tracer and how to use it.
4141

‎pie/pie/5 Plugins/Export and import.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ On the receiving side, the child script would start with something like this:
2727
```
2828
import variable Opcode and variable Arg1 and variable Arg2
2929
```
30-
The names of the variable don't have to match what they were called in the parent script, but their types must match, as must the number of shared variables. Here's the code to handle importing:
30+
The names of the variables don't have to match what they were called in the parent script, but their types must match, as must the number of shared variables. Here's the code to handle importing:
3131
```
3232
Import: {
3333

@@ -77,4 +77,4 @@ This iterates the imports. For each one, we get its record from the symbol table
7777

7878
Next we pull out the record for the variable as `newRecord` and add information from the exported variable. The important thing is to ensure the two records keep in step with each other and there are a couple of different strategies to ensure this. One is to share the actual content of the parent and child; the other is to synchronize every time the variable is read or altered. When I translated this code from Java back in 2018 I was still new to JavaScript and I couldn't figure if sharing was even possible, so I went for the second strategy. You should not assume that _**EasyCoder**_ does it the best way; the code has been subsequently governed by the rule "If it ain't broke, don't fix it".
7979

80-
~pn:5 Plugins/Handling plugins:Handling plugins~
80+
~pn:5 Plugins/Handling plugins:Handling plugins:home/Conclusion:Conclusion~

‎pie/pie/5 Plugins/Handling plugins.txt

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,12 @@ This is a fairly complex part of the language but well worth implementing as it
44

55
In order to compile a script, all of the domain handlers for the keywords it contains must already be present. A script can't request a plugin for its own code because by then the compiler is already running, and to add a new domain would mean suspending compilation while the new domain is loading. Not impossible, perhaps, but I'm assuming this is not implemented. So instead we use a 2-stage bootstrap where the extra domain(s) are called in by a boot script which loads the main script, compiles and runs it.
66

7-
For this we need 2 keywords: `require` and `run`, plus a `module` variable type in the core language module. The first looks like this:
7+
For this we need 2 keywords: `require` and `run`, plus a `module` variable type in the core language module. The `require` syntax looks like this:
8+
```
9+
require js <url>
10+
require css <url>
11+
```
12+
and the compiler code is as follows:
813
```
914
Require: {
1015

@@ -39,7 +44,7 @@ For this we need 2 keywords: `require` and `run`, plus a `module` variable type
3944
```
4045
Note that the final `return 0` causes program execution to halt while the load is happening, and `program.run(command.pc + 1)` in the callback function resumes execution once the load has completed.
4146

42-
The `program.require()` function used by `run(program)` looks like this:
47+
The `program.require()` function called by `run(program)` looks like this:
4348
```
4449
require: function(type, src, callback) {
4550
let prefix = ``;
@@ -67,7 +72,7 @@ The `program.require()` function used by `run(program)` looks like this:
6772
document.head.appendChild(element);
6873
},
6974
```
70-
This can load either CSS or JS files, so as well as your domains being load-on-demand capable, so also can be your CSS scripts.
75+
This can load either CSS or JS files, so as well as your domains being load-on-demand capable, so also can be your CSS scripts. Note the use of a leading `/` on the URL to load from a path that starts at the top-level of your website URL. This makes for portability.
7176

7277
## Running a child script
7378

‎pie/pie/5 Plugins/content.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Plugins and child scripts
22

3-
Plugins are JavaScript files containing domain handler code in a fixed format. The best way of illustrating this format is to write a plugin for a hypothetical domain. Let's assume your problem domain is that of logistics, and that one of your custom variable types is a `box`, which has features that make it useful when packing items for transport. The `box` has dimensions and weight so we need to be able to create a box, set up its properties and return information when requested. Here's a simple script that exercises all the features:
3+
Plugins are JavaScript files containing domain handler code in a fixed format. The best way of illustrating this format is to write a plugin for a hypothetical domain. Let's assume your problem domain is that of logistics, and that one of your custom variable types is a `box`, which has features that make it useful when computing how to pack items for transport. The `box` has dimensions and weight so we need to be able to create a box, set up its properties and return information when requested. Here's a simple unit test script that exercises some of the features:
44
```
55
box Box52
66

@@ -216,13 +216,13 @@ Next there are handler objects for the 2 keywords implemented in this domain; `b
216216

217217
The `box` command is a variable declaration and is implemented in a standard way.
218218

219-
The `create` command accepts the syntax shown in the example at the top of this section, where the item is first named and then followed by a set of attributes, which can be given in any order. The function returns an object with all these items.
219+
The `create` command accepts the syntax shown in the example script at the top of this page, where the item is first named and then followed by a set of attributes, which can be given in any order. The function returns an object with all these items.
220220

221221
At runtime, the command is read from the program array and the various items are extracted. An object is built to contain the current values of the 3 properties and is written to the variable.
222222

223223
Next we have the value handler object. This contains the compiler function `compile(compiler)` and the runtime function `get(program, value)`. Between them they provide the means to access any of the properties of the box variable, plus the volume, which is computed on the fly at runtime.
224224

225-
After this is the condition handler object. This contains the compiler function `compile(compiler)` and the runtime function `test(program, condition)`. Between then they implement a single test, which returns `true` if the box weight exceeds a fixed value. Note that the core condition handler will already have checked for `not`, which if given will negate the test, as in `if Box52 is not heavy ...`
225+
After this is the condition handler object. This contains the compiler function `compile(compiler)` and the runtime function `test(program, condition)`. Together they implement a single test, which returns `true` if the box weight exceeds a fixed value. Note that the core condition handler will already have checked for `not`, which if given will negate the test, as in `if Box52 is not heavy ...`
226226

227227
Now we come to the `getHandler(name)`, the dispatcher function, which returns the handler object for any given keyword in this domain (or null if an unknown keyword is given).
228228

‎pie/pie/home/Conclusion.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Conclusion
2+
3+
This is the end of the book. I hope that you have found it both interesting and useful. Feedback is welcome; you can email the author at [gtanyware@gmail.com](mailto:gtanyware@gmail.com). If you go ahead and create your own language using some of the techniques decribed, or if you decide to adapt _**EasyCoder**_ for your own purposes, I will be delighted to hear how you get on.
4+
5+
Graham Trott
6+
Leeds, UK, August 2021
7+
8+
~pn:5 Plugins/Handling plugins:Handling plugins~

‎pie/pie/home/content.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
~img:cookie.jpg:center 75%!nolink~
2+
13
# Programming In English
24

35
This book describes how to build a versatile computer language whose scripts look like a series of step-by-step English commands with a syntax similar to cookery recipes, navigation instructions or car maintenance manuals. The syntax will be English stripped to the minimum; terse but understandable by anyone familiar with the problem domain. The environment will be that of a web browser and the language will be a comprehensive, capable and easy to use replacement for JavaScript, permitting scripts to be embedded in any web page then compiled and run on the fly as the page loads. Here is a list of key requirements:
@@ -53,10 +55,14 @@ This book can be read in a linear fashion; at the bottom of each page is a link
5355

5456
I'm assuming you have some experience with JavaScript and ES6. You don't need to be an expert but complete beginners will find it a little hard going in places as I expect you to be able to read sections of code without my having to spell out everything line by line. When I started the _**EasyCoder**_ project my level of JS knowledge was pretty low, and it shows in places. I keep promising myself I'll do a major refactoring exercise but the time never seems to be available.
5557

58+
Photo by <a href="https://unsplash.com/@cookiethepom?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Cookie the Pom</a> on <a href="https://unsplash.com/s/photos/computer?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>
59+
5660
~pn:::2 Designing a language:Designing a language~
5761

5862
<hr>
5963

64+
# Contents
65+
6066
~sid:2 Designing a language:Designing a language~
6167

6268
> ~stid:2 Designing a language/Environment:The coding environment~

‎pie/pie/home/images/cookie.jpg

80.2 KB
Loading

0 commit comments

Comments
 (0)
Please sign in to comment.