23.4 Expressions
623⟨dom: ExpressionTreeLeaf 623⟩≡ (613)
ExpressionTreeLeaf: with {
PrimitiveType;
OutputType;
SetCategory;
leaf: String -> %;
string: % -> String;
leaf: Integer -> %;
integer: % -> Integer;
leaf: Symbol -> %;
symbol: % -> Symbol;
} == add {
Rep == Union(int: Integer, str: String, sym: Symbol);
import from Rep;
leaf(s: String): % == per union s;
string(l: %): String == (rep l).str;
leaf(i: Integer): % == per union i;
integer(l: %): Integer == (rep l).int;
leaf(s: Symbol): % == per union s;
symbol(l: %): Symbol == (rep l).sym;
(l: %) = (m: %): Boolean == {
import from String, Integer, Symbol;
rl == rep l;
rm == rep m;
(rl case int and rm case int and rl.int = rm.int) or
(rl case str and rm case str and rl.str = rm.str) or
(rl case sym and rm case sym and rl.sym = rm.sym);
}
(tw: TextWriter) << (x: %): TextWriter == {
rl == rep x;
(rl case int) => tw << rl.int;
(rl case str) => tw << rl.str;
(rl case sym) => tw << rl.sym;
never;
}
}
Defines:
ExpressionTreeLeaf, used in chunks 441, 447, 455, 624, and 730.
Uses Integer 66, OutputType 570, and String 65.
624a⟨dom: ExpressionTree 624a⟩≡ (613)
ExpressionTree: with {
PrimitiveType;
OutputType;
SetCategory;
apply: (ExpressionTreeOperator, ACList %) -> %;
extree: ExpressionTreeLeaf -> %;
arguments: % -> ACList(%);
operator: % -> ExpressionTreeOperator;
leaf: % -> ExpressionTreeLeaf;
leaf?: % -> Boolean;
} == add {
Rep == Union(leaf: ExpressionTreeLeaf,
tree: Record(op: ExpressionTreeOperator, args: ACList %));
import from Rep;
⟨implementation: ExpressionTree 624b⟩
}
Defines:
ExpressionTree, used in chunks 440–42, 446, 447, 454, 455, 458, 461, 620a, 730,
and 732.
Uses ACList 588b, ExpressionTreeLeaf 623, ExpressionTreeOperator 620b,
and OutputType 570.
For = and coerce we are going to need the function name$(operator s) for some
ExpressionTree s.
Note however that (operator s) in name$(operator s)is in type context and may thus
be evaluated at any time the compiler likes. We thus follow the advice given by Christian
Aistleitner in http://sourceforge.net/mailarchive/message.php?msg_id=15776706,
and introduce a local function getName, that serves as a wrapper.
625⟨implementation: ExpressionTree 624b⟩+
≡ (624a) ⊲624b
local getName(op: ExpressionTreeOperator): Symbol == name$op;
(s: %) = (t: %): Boolean == {
import from Symbol, Generator Boolean, Generator %;
leaf? s => leaf? t and leaf s = leaf t;
leaf? t => false;
getName operator s ~= getName operator t => false;
S := arguments s; T := arguments t;
while not empty? S and not empty? T repeat {
if first S ~= first T then return false;
S := rest S;
T := rest T;
}
empty? S and empty? T; -- argument list must have the same size
}
coerce(t: %): OutputForm == {
import from Symbol;
leaf? t => leaf(t) :: OutputForm;
args: List OutputForm == [x::OutputForm for x in arguments t];
op: OutputForm == getName(operator t) :: OutputForm;
hconcat(op, paren args);
}
(tw: TextWriter) << (x: %): TextWriter == hconcat(tw, x::OutputForm);
Uses ExpressionTreeOperator 620b, Generator 617, and name 198.