Glass

From Esolang
Jump to navigation Jump to search

Glass is an esoteric programming language developed by Gregor Richards in 2005. It combines an unintuitive postfix notation with heavy object-orientation, requiring extensive juggling of a main stack combined with its object-oriented structure. No other language that the author knows of is implemented like this, because it would be idiotic.

Syntax

The language is parsed into distinctive elements, each one character long, with the exception of these groupings:

  • (name) or (number) is parsed as a single variable name or stack reference number.
  • "string" is parsed as a string value.
  • <number> is parsed as a numeric value (integer or floating-point).
  • 'comment' isn't parsed at all, it's a comment (non-nestable).

Parentheses () are optional around a single letter A-Z, a-z or digit 0-9. Therefore, the variable name a could be represented by both a and (a), but the name abc could only be represented as (abc).

A program consists of a sequence of class definitions.

Each class definition has the form

{class-name function-definitions}

The class-name must be the name of a global variable which becomes a reference to the class.

A function definition has the form

[function-name content]

The function-name must be the name of a class-local variable which becomes a reference to the function. The content is an arbitrary sequence of commands.

For example:

{M[m...]}

would declare a class M with a function named m which does ...

{(Main)[(main)...]}

would declare a class Main with a function named main which does ...

Execution

Execution starts by creating an instance of the class M and running the function M.m. That is, it is equivalent to the following sequence of commands:

(_t)M!(_t)m.?

Variables

There are four types of variables, partly separated by the format of their name:

  • Global variables, with names beginning with upper-case characters.
  • Variables local to a class, with names beginning with lower-case characters. These are immutable and must be looked up with the . command rather than the * command.
  • Variables local to an object, with names beginning with lower-case characters.
  • Variables local to the current invocation of a function, with names beginning with an underscore. (Note that names beginning with an underscore must be parenthesized.)

Variable names are only resolved in the context where they are actually used - that is, if you introduce the name _a in function a, and pass it back to the parent function, which uses the returned name, it will not refer to the variable _a of function a, but to the _a of the parent function. Autogenerated global variables are available to alleviate this issue. The contextual-ness of variable names is also why the . operator (seen later) works even though you push the name of a class-local variable - it resolves that variable in the context of the called class, not the caller.

Commands

Each command is listed in this form:

command : stack beforestack afterwards
description

In this notation (due to Forth), stack elements are separated by spaces, and the top of the stack (i.e. the most recently-pushed element) is listed last.

Command list

(name) : — name
Push a variable name onto the stack.
If name is a single letter from a-z, A-Z, then the parentheses are optional.
(number) : snumber ... s1 s0 — snumber ... s1 s0 snumber
Duplicate an element number positions down the stack to the top of the stack.
If number is a single digit 0-9, then the parentheses are optional.
"string" : — string
Push the string onto the stack.
<number> : — number
Push the number onto the stack.
, : value
Pop a value from the stack.
^ : —
Return (from function).
= : name value
Assign value to variable name. For composite values, only references are copied.
! : name cname
Assign a new instance of the class in variable cname to the variable name. Pop the names from the stack, then run the c__ (constructor) function of the newly instantiated object.
. : oname fnamefunction
Retrieve the function fname defined in the class of the object oname. The object becomes the current object of the retrieved function.
The variable oname is looked up in the current context, while fname is looked up in the context of the class of the object.
? : stack-before functionstack-afterwards
Pop the function from the stack, then run it. The effect on the stack depends on the function.
* : namevalue
Retrieve the value of variable name (in the current context).
$ : name
Assign the current object to variable name.
/(name)commands\ : stack-beforestack-afterwards
Repeat commands while the variable name has a "true" value. The effect on the stack depends on content.
Values are considered "true" if they are non-zero numbers or non-empty strings.

As an example of using commands, here is a segment of code to instantiate a class O into the variable _o, then run the function _o.o with "Hello World!" on the stack:

(_o)O!"Hello World!"(_o)o.?

So, to make a hello world program (assuming that the O class is built in to the system), do the following:

{M[m(_o)O!"Hello World!"(_o)o.?]}

Isn't that easy?!

Special definable functions

c__
Constructor function of a class, run whenever an object is created.
d__
Destructor function of a class, run when an object is garbage collected.
m
Function in class M, run to execute the whole program.

Built-in classes

Each built-in function is listed in the form

Class.function : stack beforestack afterwards
description

Note that Class.function is not legal Glass syntax for using the function, you need to do something like

(_C)Class!(_C)function.?

Class A (Arithmetic)

A.a : x yx+y
Addition
A.s : x yx-y
Subtraction
A.m : x yx*y
Multiplication
A.d : x yx/y
Division
A.mod : x y — (x mod y)
Modulus
A.f : x — floor(x)
Floor
A.e : x yx==y
Equality
A.ne : x yx!=y
Inequality
A.lt : x yx<y
Less than
A.le : x yx<=y
Less than or equal to
A.gt : x yx>y
Greater than
A.ge : x yx>=y
Greater than or equal to

Class S (Strings)

S.l : stringlength
Retrieve the length of string.
S.i : string ncharacter
Retrieve the nth character of string.
S.si : string n charnewstring
Replace the nth character of string with char.
S.a : s1 s2s1s2
Concatenate strings.
S.d : string poss1 s2
divide string at point pos, s1 is the first part, s2 is the second.
S.e : s1 s2s1==s2
String equality.
S.ns : numbercharacter
Convert a number to a character.
S.sn : characternumber
Convert a character to a number.

Class V (autogenerated Variables)

V.n : — newname
Push name of a new global variable.
V.d : name
Delete an autogenerated variable.

Class O (Output)

O.o : string/name
Output string or name.
O.on : number
Output number.

Class I (Input)

I.l : — string
Retrieve a line of input.
I.c : — char
Retrieve a character from input.
I.e : — is-eof
Push 1 if end of input, 0 otherwise.

Examples

Hello, world! program

{M[m(_o)O!"Hello World!"(_o)o.?]}

Fibonacci sequence

{F[f(_a)A!(_o)O!(_t)$(_n)1=,(_isle)(_n)*<2>(_a)(le).?=/(_isle)<1>^\(_n)*<1>(_a)
s.?(_t)f.?(_n)*<2>(_a)s.?(_t)f.?(_a)a.?]}{M[m(_a)A!(_f)F!(_o)O!(_n)<1>=(_nlm)
<1>=/(_nlm)(_n)*(_f)f.?(_o)(on).?" "(_o)o.?(_n)(_n)*<1>(_a)a.?=(_nlm)(_n)*<20>
(_a)(le).?=\]}

Randomizer class

{(Rand)[(c__)s<5>=][(rand)(_a)A!ss*<1103515245>(_a)m.?<4294967295>(_a)(mod).?
<12345>(_a)a.?=s*<65535>(_a)d.?<32768>(_a)(mod).?][(seed)s1=,][(randi)(_a)A!
(_t)$(_min)2=(_max)1=,,(_min)*(_max)*(_min)*(_a)s.?<1>(_a)a.?(_t)(rand).?(_a)m.
?<32768>(_a)d.?(_a)a.?(_a)f.?]}

Quine

{M[m(_s)S!(_o)0O!o.<34>(_s)(ns).?"{M[m(_s)S!(_o)0O!o.<34>(_s)(ns).?"
"14?24?14?24?24?04?24?04?]}"14?24?14?24?24?04?24?04?]}

Cat

{M[maI!bO!cA!dae.?<1>c(ne).?=/dac.?bo.?dae.?<1>c(ne).?=\]}

99 bottles of beer

{B[b<99>^]}{P[(c__)oO!aA!][poo.?][b(_m)1=,(_x)<0>(_m)*ae.
?=(_y)<1>=/(_x)"No more"oo.?(_x)0=(_y)0=\/(_y)(_m)*o(on).
?(_y)0=\" bottle"oo.?(_x)<1>(_m)*ae.?=/(_x)^(_x)0=\"s"oo.
?]}{C[(c__)oO!aA!sS!pP!][gn*][xn1=,][dnn*<1>as.?=][vn*pb.
?" of beer on the wall,\n"pp.?n*pb.?qe" of beer,\n"pp.?
"Take one down, pass it around\n"pp.?ln*<1>as.?=l*pb.?wu
" of beer on the wall.\n\n"pp.?]}{M[moO!cC!bB!bb.?cx.?fc
g.?=/fcv.?cd.?fcg.?=\]}

brainfuck interpreter

{B[(c__)k<1>=j<1>=u<0>=][(af)/kkB!(_e)$(_e)*kv.?\k*][(ae)/jjB
!(_e)$(_e)*jw.?\j*][pu*][wk1=,][vj1=,][qu1=,]}{C[(c__)aA!iI!o
O!sS!r""(_f)ic.?=(_d)ie.?<0>ae.?=/(_d)(_f)*sa.?(_f)ic.?=(_d)i
e.?<0>ae.?=(_g)(_d)*=/(_g)(_d)(_f)*";"se.?<0>ae.?=(_g)<0>=\\=
tr*sl.?=b<0>=h$gB!][(ai)gp.?<1>as.?(_a)1<-1>ae.?=/(_a),<255>
(_a)<0>=\gq.?][(ah)(_a)b*t*a(lt).?=/(_a)h(ag).?b0*<1>a0.?=
(_a)b*t*a(lt).?=\][(ag)(_b)r*b*si.?=(_a)(_b)*"+"se.?=/(_a)h
(ad).?^\(_a)(_b)*"-"se.?=/(_a)h(ai).?^\(_a)(_b)*">"se.?=/(_a)
hy.?^\(_a)(_b)*"<"se.?=/(_a)hz.?^\(_a)(_b)*"["se.?=/(_a)h(ab)
.?^\(_a)(_b)*"]"se.?=/(_a)h(aa).?^\(_a)(_b)*"."se.?=/(_a)hx.?
^\(_a)(_b)*","se.?=/(_a)h(ac).?^\][(ad)gp.?<1>a0.?<256>a(mod)
.?gq.?][(ac)ic.?(_h)ie.?=/(_h)<0>gq.?,^\s(sn).?gq.?][(ab)(_a)
gp.?=/(_a)^\(_c)<1>=/(_c)b0*<1>a0.?=(_a)b*t*a(gt).?=/(_a)^\
(_b)r*b*si.?=(_a)(_b)*"["se.?=/(_a)(_c)0*<1>a0.?=(_a)<0>=\
(_a)(_b)*"]"se.?=/(_a)(_c)0*<1>as.?=(_a)<0>=\\][(aa)(_a)gp.?
<0>ae.?=/(_a)^\(_c)<1>=/(_c)b0*<1>as.?=(_a)b*<0>a(le).?=
/(_a)^\(_b)r*b*si.?=(_a)(_b)*"["se.?=/(_a)(_c)0*<1>as.?=(_a)
<0>=\(_a)(_b)*"]"se.?=/(_a)(_c)0*<1>a0.?=(_a)<0>=\\][zg(af).
?g1=,][yg(ae).?g1=,][xgp.?s(ns).?o0.?]}{M[m(_i)C!(_i)(ah).?]
}

External resources