Huey, An Extended Language for Colors
Motivation
This document specifies an extended version of the Huey language we created for Homework 9, which was motivated by a common web programming task. When you know how to write language interpreters, a language becomes a practical option for solving such problems.
To write more complex expressions in Huey, it would be convenient to be able to create new kinds of operators and colors. This requires the ability to name an expression that computes a particular value and use the name as a value in a larger expression.
This version of Huey includes named colors as expressions. They will be useful both for writing programs that compute more ambitious colors using Huey's operators.
Language Grammar
The extended version of the language consists of RGB values, variable references, unary expressions, two-color binary expressions, one-color binary expressions, and blocks with local variables. Here is the BNF description of the language:
<color> ::= (rgb <byte> <byte> <byte> ) | <varref> ; new | ( <unary-op> <color> ) | ( <color> <2color-op> <color> ) | ( <color> <1color-op> <number> ) | ( color <var> = <color> in <color> ) ; new <unary-op> ::= invert | darker <2color-op> ::= + | - | mix <1color-op> ::= * | shift
A <number>
can be any real number,
positive or negative, including integers. As noted
Homework 9,
a <byte>
is an 8-bit integer in the range
[0..255]. The semantics of the values and operators is defined
below.
The symbols rgb
, color
, =
,
and in
are keywords. They cannot be used as the names
of variables.
Example Expressions
These are all still legal Huey expressions:
(rgb 0 255 0) (invert (rgb 4 4 4)) ((rgb 0 255 0) + (rgb 4 4 4)) (rgb 255 0 255) mix ((rgb 0 255 0) + (rgb 4 4 4)) ((rgb 255 0 255) * 1.2) ((rgb 255 0 255) shift -10)
These are now also legal Huey expressions: — new
white (color purple = ((rgb 255 0 0) mix (rgb 0 0 255)) in (darker purple)) (color green = (rgb 0 255 0) in (color blue-green = (green mix (rgb 0 0 255)) in (invert blue-green)))
As the grammar indicates, expressions nest arbitrarily deeply.
Semantics
RGB Values
Racket does not provide an 8-bit integer type, but we can use Racket's
byte?
type predicate to validate the components of an RGB value. The
constructor for an RGB value should ensure that all values fall
in the legal range. Any value larger than 255 maps to 255, and
any value less than 0 maps to 0.
Unary Expressions
-
(invert operand)
returns a color whose RGB components are 255 minus the corresponding components ofoperand
.
(invert (rgb 150 99 42))
equals(rgb 105 156 213)
. -
(darker operand)
returns a color whose RGB components are one-half the corresponding components ofoperand
.
(darker (rgb 150 99 42))
equals(rgb 75 49 21)
.
Two-Color Expressions
-
(color1 + color2)
returns a color whose RGB components are the sums of the corresponding components of its two operands.
((rgb 150 99 42) + (rgb 50 18 241))
equals(rgb 200 117 255)
. -
(color1 - color2)
returns a color whose RGB components are the differences of the corresponding components of its two operands.
((rgb 150 99 42) - (rgb 50 108 21))
equals(rgb 100 0 21)
. -
(color1 mix color2)
returns a color whose RGB components are 50-50 blends of the corresponding components of its two operands.
((rgb 150 99 42) mix (rgb 50 108 21))
equals(rgb 100 103 31)
.
One-Color Expressions
-
(color * number)
returns a color whose RGB components arenumber
times the corresponding components of its color operand.
((rgb 150 99 42) * 1.6)
equals(rgb 240 158 67)
. -
(color shift number)
returns a color whose RGB components arenumber
plus the corresponding components of its color operand.
((rgb 150 99 42) shift -50)
equals(rgb 100 49 0)
.
Primitive Values — new
-
white
, bound to the value(rgb 255 255 255)
-
black
, bound to the value(rgb 0 0 0)
Blocks with Local Variables — new
color/in
expression that declares the
variable. It is not meaningful in the value being
assigned to the variable.
A reference to a variable that has not been defined either in
the initial environment or in a containing
color/in
expression is an error.
A color/in
expression behaves as follows:
- First, the value of the variable is evaluated in the current environment.
- Then, a new environment is created by extending the current environment with the new variable/value pair.
- Finally, the body of the expression is evaluated in the new environment.
Syntactic Sugar
All of the features defined above are part of the core of the Huey language except:
-
(color1 mix color2)
... which is a syntactic abstraction of((color1 * 0.5) + (color2 * 0.5))
-
(darker color)
... which is a syntactic abstraction of(color * 0.5)
In Huey, syntactic abstractions are preprocessed away before expressions are evaluated.