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 programs in Huey, it would be convenient if we were able to evolve colors through a sequence of expressions. This requires the ability to change the state of a local variable and have the new value reflected in subsequent expressions.
This version of Huey includes sequences of assignments as color expressions. They will be useful 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, blocks with local variables, and blocks with assignment statements. Here is the BNF description of the language:
<color> ::= (rgb <byte> <byte> <byte> ) | <varref> | ( <unary-op> <color> ) | ( <color> <2color-op> <color> ) | ( <color> <1color-op> <number> ) | ( color <var> = <color> in <color> ) | ( do <assignment>* <color> ) ; new <assignment> ::= ( <varref> <= <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
, =
,
in
, do
, and
<=
are keywords. They cannot be used as the
names of variables.
Example Expressions
These are all still legal Huey expressions:
white (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) (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)))
These are now also legal Huey expressions: — new
(do (rgb 255 0 0)) (color c = (rgb 0 255 0) in (do (c <= (c mix (rgb 0 0 255))) (c <= (invert blue-green)) (c shift 5))) (color c = (rgb 0 255 0) in (color d = (rgb 0 0 255) in (do (c <= (c mix d)) (d <= (c mix d)) ((c mix d) shift 5))))
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
-
white
, bound to the value(rgb 255 255 255)
-
black
, bound to the value(rgb 0 0 0)
Blocks with Local Variables
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.
Sequences with State — new
do
expression consists of 0 or more
assignment statements followed by a color expression. The value
of a do
expression is the value of that final color.
An assignment statement changes the value of an existing variable. An attempt to assign a value to a variable that has not been defined by a containing
color/in
expression
is an error.
Note that the
<=
operator does not behave
like other operators in the language, because the variable on
the lefthand side of the expression is not evaluated.
Instead, it is the target of the assignment. The color
expression on the righthand side of the statement is
evaluated, including any variables it contains.
A
do
expression behaves as follows:
-
Evaluate the assignment statements in order. For each:
- evaluate the color expression on the righthand side of the statement, and
- update the value of the variable on the lefthand side in the current environment.
-
Evaluate the final color expression in the current
environment and return that value as the value of the
do
expression.
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.