23.4 Expressions

620acat: ExpressionType 620a  (613)
define ExpressionType: Category == with {
        PrimitiveType;
        OutputType;
        SetCategory;
        extree: % -> ExpressionTree;
    default {
        coerce(x: %): OutputForm == coerce(extree x)$ExpressionTree;
        (tw: TextWriter) << (x: %): TextWriter == {
                import from ExpressionTree;
                tw << extree x;
        }
    }
}

Defines:
ExpressionType, used in chunk 430.

Uses ExpressionTree 624a and OutputType 570.
620bcat: ExpressionTypeOperator 620b  (613)
define ExpressionTreeOperator: Category == with {
        name: Symbol;
}

Defines:
ExpressionTreeOperator, used in chunks 455, 621, 622, 624, and 625.

Uses name 198.
621adom: ExpressionTreePlus 621a  (613)
ExpressionTreePlus: ExpressionTreeOperator == add {
        import from String;
        name: Symbol == - "+";
}

Defines:
ExpressionTreePlus, never used.

Uses ExpressionTreeOperator 620b, name 198, and String 65.
621bdom: ExpressionTreeTimes 621b  (613)
ExpressionTreeTimes: ExpressionTreeOperator == add {
        import from String;
        name: Symbol == - "*";
}

Defines:
ExpressionTreeTimes, never used.

Uses ExpressionTreeOperator 620b, name 198, and String 65.
621cdom: ExpressionTreeExpt 621c  (613)
ExpressionTreeExpt: ExpressionTreeOperator == add {
        import from String;
        name: Symbol == - "^";
}

Defines:
ExpressionTreeExpt, never used.

Uses ExpressionTreeOperator 620b, name 198, and String 65.
622dom: ExpressionTreePrefix 622  (613)
ExpressionTreePrefix(s: Symbol): ExpressionTreeOperator == add {
        name: Symbol == s;
}

Defines:
ExpressionTreePrefix, used in chunks 442, 447, and 730.

Uses ExpressionTreeOperator 620b and name 198.
623dom: 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.
624adom: 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.
624bimplementation: ExpressionTree 624b  (624a)  625
apply(op: ExpressionTreeOperator, args: ACList %): % == {
        import from Record(op: ExpressionTreeOperator, args: ACList %);
        per union [op, args];
}
extree(leaf: ExpressionTreeLeaf): % == per union leaf;

arguments(t: %): ACList % == (rep t).tree.args;

operator(t: %): ExpressionTreeOperator == (rep t).tree.op;

leaf(t: %): ExpressionTreeLeaf == (rep t).leaf;

leaf?(t: %): Boolean == ((rep t) case leaf);

Uses ACList 588b, ExpressionTreeLeaf 623, and ExpressionTreeOperator 620b.

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.

625implementation: 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.