(Strings) and arrays

This chapter is more technical. PostScript does also have to deal with strings and arrays, so we have to add support for them.

Strings are enclosed by paranthesises () and arrays by square brackets [], this is the easy part. But we also have to deal with an implementation detail of PostScript. Strings, arrays (and also procedures) are composite data types, and these data types are not stored by value, but by reference. If you assign (string) to foo, then you only add a reference to (string) to foo. If you assign foo to bar, there is no copy of (string), only the references is copied. So if you modify (string) itself with operators like put or putinterval, you modify both the value of foo and bar.

It's strange but we have to live with that. PostScript could have developed operators that combine strings and return new strings. This would have be a pure functional approach. But in the 1980s memory was expensive and they decided to go the reference way.

Our context needs therefore also to maintain a heap array to store the value. We implement the heap as a simple array. The position in the array is the reference.

We now have many datatypes: number, string, name, procedure and array. Many occasions to make type errors. We add to the context a function arguments context.pop() that gets all arguments for the operators, checks their types and returns them as an array.

Javascript

The code for the operators becomes very cleaner.

operators.add = function(context) {
const [b, a] = context.pop("number", "number");
if (!b) return context;
context.stack.push(new rpnNumber(a.value + b.value));
return context;
};

In the first line, we use the Javascript feature that allows you to assign array elements directly to constant. If there was any error, the first constant will be undefined and the operator stops.
In the following lines, the operator calculates the result and pushes it back to the stack.
The operator always returns the context to be reused.

Javascript

We adapt postScriptEditor to show the values correctly and to the heap

Javascript

We try it out.

Javascript Editor

The main operators on strings and arrays are length, get, getinterval, put, putinterval. Get returns the character code of one character, getinterval returns an entire string. Put sets the character code at a position in the string and putinterval replaces a substring. Note that put and putinterval operate on the original string which keeps the same length.

Javascript

We try it out.

Javascript Editor

The heap fills up with text which is not referenced any more so it should be freed. We will do that later.

And for put we see the change in heap affects also the original variable

Javascript Editor

code stack dict heap
/a /a  
(foo) /a (foo) (foo)
def a = (foo) (foo)
/b /b a = (foo) (foo)
a /b (foo) a = (foo) (foo)
def a = (foo) b = (foo) (foo)
b (foo) a = (foo) b = (foo) (foo)
1 (foo) 1 a = (foo) b = (foo) (foo)
get 111 a = (foo) b = (foo) (foo)
1 111 1 a = (foo) b = (foo) (foo)
add 112 a = (foo) b = (foo) (foo)
b 112 (foo) a = (foo) b = (foo) (foo)
exch (foo) 112 a = (foo) b = (foo) (foo)
1 (foo) 112 1 a = (foo) b = (foo) (foo)
exch (foo) 1 112 a = (foo) b = (foo) (foo)
put a = (fpo) b = (fpo) (fpo)
a (fpo) a = (fpo) b = (fpo) (fpo)

The new code is entirely rewritten and has 625 lines ps20240629.js

My Journey to PostScript