ssc/ssc/ast/nodes.expressions.cs
2022-01-26 01:03:02 -06:00

205 lines
5.9 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace arookas {
interface sunTerm {
sunExpressionFlags GetExpressionFlags(sunContext context);
}
class sunExpression : sunNode, sunTerm {
public sunExpression(sunSourceLocation location)
: base(location) { }
public override void Compile(sunCompiler compiler) {
var operatorStack = new Stack<sunOperator>(32);
CompileExpression(compiler, this, operatorStack);
}
public sunExpressionFlags Analyze(sunContext context) {
return AnalyzeExpression(context, this);
}
static void CompileExpression(sunCompiler compiler, sunExpression expression, Stack<sunOperator> operatorStack) {
var stackCount = operatorStack.Count;
foreach (var node in expression) {
if (node is sunOperand) {
var operand = node as sunOperand;
// term
var term = operand.Term;
if (term is sunExpression) {
CompileExpression(compiler, term as sunExpression, operatorStack);
}
else {
term.Compile(compiler);
}
var unaryOperators = operand.UnaryOperators;
if (unaryOperators != null) {
unaryOperators.Compile(compiler);
}
}
else if (node is sunOperator) {
var operatorNode = node as sunOperator;
while (operatorStack.Count > stackCount &&
(operatorNode.IsLeftAssociative && operatorNode.Precedence <= operatorStack.Peek().Precedence) ||
(operatorNode.IsRightAssociative && operatorNode.Precedence < operatorStack.Peek().Precedence)) {
operatorStack.Pop().Compile(compiler);
}
operatorStack.Push(operatorNode);
}
}
while (operatorStack.Count > stackCount) {
operatorStack.Pop().Compile(compiler);
}
}
static sunExpressionFlags AnalyzeExpression(sunContext context, sunExpression expression) {
var flags = sunExpressionFlags.None;
foreach (var operand in expression.OfType<sunOperand>()) {
var term = operand.Term as sunTerm;
if (term != null) {
flags |= term.GetExpressionFlags(context);
}
}
return flags;
}
sunExpressionFlags sunTerm.GetExpressionFlags(sunContext context) {
return AnalyzeExpression(context, this);
}
}
[Flags]
enum sunExpressionFlags {
None = 0,
// contents
Literals = 1 << 0,
Variables = 1 << 1,
Augments = 1 << 2,
Calls = 1 << 3,
Constants = 1 << 4,
// description
Dynamic = 1 << 5,
}
class sunOperand : sunNode {
public sunNode UnaryOperators { get { return Count > 1 ? this[0] : null; } }
public sunNode Term { get { return this[Count - 1]; } }
public sunOperand(sunSourceLocation location)
: base(location) { }
// operands are compiled in sunExpression.Compile
}
class sunUnaryOperatorList : sunNode {
public sunUnaryOperatorList(sunSourceLocation location)
: base(location) { }
public override void Compile(sunCompiler compiler) {
foreach (var child in this.Reverse()) {
// compile unary operators in reverse order
child.Compile(compiler);
}
}
}
class sunTernaryOperator : sunNode, sunTerm {
public sunExpression Condition { get { return this[0] as sunExpression; } }
public sunExpression TrueBody { get { return this[1] as sunExpression; } }
public sunExpression FalseBody { get { return this[2] as sunExpression; } }
public sunTernaryOperator(sunSourceLocation location)
: base(location) { }
public override void Compile(sunCompiler compiler) {
Condition.Compile(compiler);
var falsePrologue = new sunJumpNotEqualSite(compiler.Binary);
TrueBody.Compile(compiler);
var trueEpilogue = new sunJumpSite(compiler.Binary);
falsePrologue.Relocate();
FalseBody.Compile(compiler);
trueEpilogue.Relocate();
}
sunExpressionFlags sunTerm.GetExpressionFlags(sunContext context) {
return Condition.Analyze(context) | TrueBody.Analyze(context) | FalseBody.Analyze(context);
}
}
// increment/decrement
class sunPostfixAugment : sunOperand, sunTerm {
public sunIdentifier Variable { get { return this[0] as sunIdentifier; } }
public sunAugment Augment { get { return this[1] as sunAugment; } }
public sunPostfixAugment(sunSourceLocation location)
: base(location) { }
public override void Compile(sunCompiler compiler) {
var symbol = compiler.Context.MustResolveStorable(Variable);
if (symbol is sunConstantSymbol) {
throw new sunAssignConstantException(Variable);
}
if (Parent is sunOperand) {
symbol.CompileGet(compiler);
}
Augment.Compile(compiler, symbol);
}
sunExpressionFlags sunTerm.GetExpressionFlags(sunContext context) {
return sunExpressionFlags.Augments;
}
}
class sunPrefixAugment : sunOperand, sunTerm {
public sunAugment Augment { get { return this[0] as sunAugment; } }
public sunIdentifier Variable { get { return this[1] as sunIdentifier; } }
public sunPrefixAugment(sunSourceLocation location)
: base(location) { }
public override void Compile(sunCompiler compiler) {
var symbol = compiler.Context.MustResolveStorable(Variable);
if (symbol is sunConstantSymbol) {
throw new sunAssignConstantException(Variable);
}
Augment.Compile(compiler, symbol);
if (Parent is sunOperand) {
symbol.CompileGet(compiler);
}
}
sunExpressionFlags sunTerm.GetExpressionFlags(sunContext context) {
return sunExpressionFlags.Augments;
}
}
abstract class sunAugment : sunNode {
protected sunAugment(sunSourceLocation location)
: base(location) { }
public abstract void Compile(sunCompiler compiler, sunStorableSymbol symbol);
}
class sunIncrement : sunAugment {
public sunIncrement(sunSourceLocation location)
: base(location) { }
public override void Compile(sunCompiler compiler, sunStorableSymbol symbol) {
symbol.CompileInc(compiler);
symbol.CompilePop(compiler);
}
}
class sunDecrement : sunAugment {
public sunDecrement(sunSourceLocation location)
: base(location) { }
public override void Compile(sunCompiler compiler, sunStorableSymbol symbol) {
symbol.CompileDec(compiler);
symbol.CompilePop(compiler);
}
}
}