TIL I can set the automatic formatting of opening braces in VS. What
have I been doing all this time??
This commit is contained in:
arookas 2015-12-28 03:37:10 -05:00
parent f5394f56d0
commit 2f9b251fd8
19 changed files with 589 additions and 1332 deletions

View file

@ -4,16 +4,13 @@ using System.Collections.Generic;
namespace arookas
{
public class sunSourceLocation
{
public class sunSourceLocation {
public string File { get; private set; }
public int Line { get; private set; }
public int Column { get; private set; }
public sunSourceLocation(string file, int line, int column)
{
if (file == null)
{
public sunSourceLocation(string file, int line, int column) {
if (file == null) {
throw new ArgumentNullException("file");
}
File = file;
@ -21,14 +18,10 @@ namespace arookas
Column = column;
}
public override string ToString()
{
return String.Format("\"{0}\", ({1},{2})", File, Line, Column);
}
public override string ToString() { return String.Format("\"{0}\", ({1},{2})", File, Line, Column); }
}
class sunNode : IEnumerable<sunNode>
{
class sunNode : IEnumerable<sunNode> {
List<sunNode> mChildren;
public sunNode Parent { get; private set; }
@ -41,27 +34,20 @@ namespace arookas
public bool IsBranch { get { return Count > 0; } }
public bool IsLeaf { get { return Count < 1; } }
public int MaxLocalCount
{
get
{
public int MaxLocalCount {
get {
int locals = 0;
int maxChildLocals = 0;
foreach (var child in this)
{
if (child is sunVariableDeclaration || child is sunVariableDefinition)
{
foreach (var child in this) {
if (child is sunVariableDeclaration || child is sunVariableDefinition) {
++locals;
}
else if (child is sunCompoundStatement)
{
else if (child is sunCompoundStatement) {
locals += child.MaxLocalCount; // HACK: compound statements aren't their own scope
}
else if (!(child is sunFunctionDefinition)) // don't recurse into function bodies
{
else if (!(child is sunFunctionDefinition)) { // don't recurse into function bodies
int childLocals = child.MaxLocalCount;
if (childLocals > maxChildLocals)
{
if (childLocals > maxChildLocals) {
maxChildLocals = childLocals;
}
}
@ -70,60 +56,47 @@ namespace arookas
}
}
public sunNode(sunSourceLocation location)
{
public sunNode(sunSourceLocation location) {
mChildren = new List<sunNode>(5);
Location = location;
}
public void Add(sunNode node)
{
if (node == null)
{
public void Add(sunNode node) {
if (node == null) {
throw new ArgumentNullException("node");
}
if (node.Parent != null)
{
if (node.Parent != null) {
node.Parent.Remove(node);
}
node.Parent = this;
mChildren.Add(node);
}
public void Remove(sunNode node)
{
if (node == null)
{
public void Remove(sunNode node) {
if (node == null) {
throw new ArgumentNullException("node");
}
if (node.Parent == this)
{
if (node.Parent == this) {
mChildren.Remove(node);
node.Parent = null;
}
}
public void Clear()
{
foreach (var child in this)
{
public void Clear() {
foreach (var child in this) {
child.Parent = null;
}
mChildren.Clear();
}
public virtual void Compile(sunContext context)
{
public virtual void Compile(sunContext context) {
// Simply compile all children nodes by default. This is here for the transcient nodes' implementations
// (sunStatement, sunCompoundStatement, etc.) so I only have to type this once. sunExpression is careful
// to override this with the custom shunting-yard algorithm implementation.
foreach (var child in this)
{
foreach (var child in this) {
child.Compile(context);
}
}
protected bool TryCompile(sunNode node, sunContext context)
{
if (node != null)
{
protected bool TryCompile(sunNode node, sunContext context) {
if (node != null) {
node.Compile(context);
return true;
}
@ -134,14 +107,10 @@ namespace arookas
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
}
abstract class sunToken<TValue> : sunNode
{
abstract class sunToken<TValue> : sunNode {
public TValue Value { get; protected set; }
protected sunToken(sunSourceLocation location)
: base(location)
{
}
: base(location) { }
}
}

View file

@ -2,114 +2,84 @@
using System.Collections.Generic;
using System.Linq;
namespace arookas
{
class sunExpression : sunNode
{
namespace arookas {
class sunExpression : sunNode {
public sunExpression(sunSourceLocation location)
: base(location)
{
: base(location) { }
}
public override void Compile(sunContext context)
{
public override void Compile(sunContext context) {
Stack<sunOperator> operatorStack = new Stack<sunOperator>(32);
AnalyzeExpression(context, this, operatorStack);
}
void AnalyzeExpression(sunContext context, sunExpression expression, Stack<sunOperator> operatorStack)
{
void AnalyzeExpression(sunContext context, sunExpression expression, Stack<sunOperator> operatorStack) {
// this implementation assumes that the expression production child list alternates between operand and operator
// we can safely assume this as the grammar "operand {binary_operator operand}" enforces it
int stackCount = operatorStack.Count;
foreach (var node in expression)
{
if (node is sunOperand)
{
foreach (var node in expression) {
if (node is sunOperand) {
var operand = node as sunOperand;
// term
var term = operand.Term;
if (term is sunExpression)
{
if (term is sunExpression) {
AnalyzeExpression(context, term as sunExpression, operatorStack);
}
else
{
else {
term.Compile(context);
}
var unaryOperators = operand.UnaryOperators;
if (unaryOperators != null)
{
if (unaryOperators != null) {
unaryOperators.Compile(context);
}
}
else if (node is sunOperator)
{
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))
{
(operatorNode.IsRightAssociative && operatorNode.Precedence < operatorStack.Peek().Precedence)) {
operatorStack.Pop().Compile(context);
}
operatorStack.Push(operatorNode);
}
}
while (operatorStack.Count > stackCount)
{
while (operatorStack.Count > stackCount) {
operatorStack.Pop().Compile(context);
}
}
}
class sunOperand : sunNode
{
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)
{
}
: base(location) { }
// operands are compiled in sunExpression.Compile
}
class sunUnaryOperatorList : sunNode
{
class sunUnaryOperatorList : sunNode {
public sunUnaryOperatorList(sunSourceLocation location)
: base(location)
{
: base(location) { }
}
public override void Compile(sunContext context)
{
foreach (var child in this.Reverse())
{
public override void Compile(sunContext context) {
foreach (var child in this.Reverse()) {
// compile unary operators in reverse order
child.Compile(context);
}
}
}
class sunTernaryOperator : sunNode
{
class sunTernaryOperator : sunNode {
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)
{
: base(location) { }
}
public override void Compile(sunContext context)
{
public override void Compile(sunContext context) {
Condition.Compile(context);
var falsePrologue = context.Text.GotoIfZero();
TrueBody.Compile(context);
@ -121,94 +91,66 @@ namespace arookas
}
// increment/decrement
class sunPostfixAugment : sunOperand
{
class sunPostfixAugment : sunOperand {
public sunIdentifier Variable { get { return this[0] as sunIdentifier; } }
public sunAugment Augment { get { return this[1] as sunAugment; } }
public sunPostfixAugment(sunSourceLocation location)
: base(location)
{
: base(location) { }
}
public override void Compile(sunContext context)
{
public override void Compile(sunContext context) {
var symbol = context.MustResolveStorable(Variable);
if (symbol is sunConstantSymbol)
{
if (symbol is sunConstantSymbol) {
throw new sunAssignConstantException(Variable);
}
if (Parent is sunOperand)
{
if (Parent is sunOperand) {
symbol.CompileGet(context);
}
Augment.Compile(context, symbol);
}
}
class sunPrefixAugment : sunOperand
{
class sunPrefixAugment : sunOperand {
public sunAugment Augment { get { return this[0] as sunAugment; } }
public sunIdentifier Variable { get { return this[1] as sunIdentifier; } }
public sunPrefixAugment(sunSourceLocation location)
: base(location)
{
: base(location) { }
}
public override void Compile(sunContext context)
{
public override void Compile(sunContext context) {
var symbol = context.MustResolveStorable(Variable);
if (symbol is sunConstantSymbol)
{
if (symbol is sunConstantSymbol) {
throw new sunAssignConstantException(Variable);
}
Augment.Compile(context, symbol);
if (Parent is sunOperand)
{
if (Parent is sunOperand) {
symbol.CompileGet(context);
}
}
}
abstract class sunAugment : sunNode
{
abstract class sunAugment : sunNode {
protected sunAugment(sunSourceLocation location)
: base(location)
{
}
: base(location) { }
public abstract void Compile(sunContext context, sunStorableSymbol symbol);
}
class sunIncrement : sunAugment
{
class sunIncrement : sunAugment {
public sunIncrement(sunSourceLocation location)
: base(location)
{
: base(location) { }
}
public override void Compile(sunContext context, sunStorableSymbol symbol)
{
public override void Compile(sunContext context, sunStorableSymbol symbol) {
symbol.CompileInc(context);
symbol.CompileSet(context);
}
}
class sunDecrement : sunAugment
{
class sunDecrement : sunAugment {
public sunDecrement(sunSourceLocation location)
: base(location)
{
: base(location) { }
}
public override void Compile(sunContext context, sunStorableSymbol symbol)
{
public override void Compile(sunContext context, sunStorableSymbol symbol) {
symbol.CompileDec(context);
symbol.CompileSet(context);
}

View file

@ -1,50 +1,38 @@
using PerCederberg.Grammatica.Runtime;
using System.Linq;
namespace arookas
{
class sunIf : sunNode
{
namespace arookas {
class sunIf : sunNode {
public sunExpression Condition { get { return this[0] as sunExpression; } }
public sunNode TrueBody { get { return this[1]; } }
public sunNode FalseBody { get { return this[2]; } }
public sunIf(sunSourceLocation location)
: base(location)
{
: base(location) { }
}
public override void Compile(sunContext context)
{
public override void Compile(sunContext context) {
Condition.Compile(context);
var trueBodyEpilogue = context.Text.GotoIfZero();
TrueBody.Compile(context);
var falseBody = FalseBody;
if (falseBody != null)
{
if (falseBody != null) {
var falseBodyEpilogue = context.Text.Goto();
context.Text.ClosePoint(trueBodyEpilogue);
falseBody.Compile(context);
context.Text.ClosePoint(falseBodyEpilogue);
}
else
{
else {
context.Text.ClosePoint(trueBodyEpilogue);
}
}
}
abstract class sunLoop : sunNode
{
abstract class sunLoop : sunNode {
public bool IsNamed { get { return NameLabel != null; } }
public sunNameLabel NameLabel { get { return this[0] as sunNameLabel; } }
protected sunLoop(sunSourceLocation location)
: base(location)
{
}
: base(location) { }
}
class sunWhile : sunLoop
@ -53,13 +41,9 @@ namespace arookas
public sunNode Body { get { return this[Count - 1]; } }
public sunWhile(sunSourceLocation location)
: base(location)
{
: base(location) { }
}
public override void Compile(sunContext context)
{
public override void Compile(sunContext context) {
context.Loops.Push(IsNamed ? NameLabel.Label.Value : null);
var bodyPrologue = context.Text.OpenPoint();
var continuePoint = context.Text.OpenPoint();
@ -79,13 +63,9 @@ namespace arookas
public sunExpression Condition { get { return this[Count - 1] as sunExpression; } }
public sunDo(sunSourceLocation location)
: base(location)
{
: base(location) { }
}
public override void Compile(sunContext context)
{
public override void Compile(sunContext context) {
context.Loops.Push(IsNamed ? NameLabel.Label.Value : null);
var bodyPrologue = context.Text.OpenPoint();
Body.Compile(context);
@ -99,21 +79,16 @@ namespace arookas
}
}
class sunFor : sunLoop
{
class sunFor : sunLoop {
public sunForDeclaration Declaration { get { return this.FirstOrDefault(i => i is sunForDeclaration) as sunForDeclaration; } }
public sunForCondition Condition { get { return this.FirstOrDefault(i => i is sunForCondition) as sunForCondition; } }
public sunForIteration Iteration { get { return this.FirstOrDefault(i => i is sunForIteration) as sunForIteration; } }
public sunNode Body { get { return this[Count - 1]; } }
public sunFor(sunSourceLocation location)
: base(location)
{
: base(location) { }
}
public override void Compile(sunContext context)
{
public override void Compile(sunContext context) {
context.Scopes.Push(context.Scopes.Top.Type);
context.Loops.Push(IsNamed ? NameLabel.Label.Value : null);
TryCompile(Declaration, context);
@ -130,93 +105,62 @@ namespace arookas
context.Scopes.Pop();
}
}
class sunForDeclaration : sunNode
{
class sunForDeclaration : sunNode {
public sunForDeclaration(sunSourceLocation location)
: base(location)
{
}
: base(location) { }
}
class sunForCondition : sunNode
{
class sunForCondition : sunNode {
public sunForCondition(sunSourceLocation location)
: base(location)
{
}
: base(location) { }
}
class sunForIteration : sunNode
{
class sunForIteration : sunNode {
public sunForIteration(sunSourceLocation location)
: base(location)
{
}
: base(location) { }
}
class sunReturn : sunNode
{
class sunReturn : sunNode {
public sunExpression Expression { get { return this[0] as sunExpression; } }
public sunReturn(sunSourceLocation location)
: base(location)
{
: base(location) { }
}
public override void Compile(sunContext context)
{
public override void Compile(sunContext context) {
var expression = Expression;
if (expression != null)
{
if (expression != null) {
expression.Compile(context);
context.Text.ReturnValue();
}
else
{
else {
context.Text.ReturnVoid();
}
}
}
class sunBreak : sunNode
{
class sunBreak : sunNode {
public bool IsNamed { get { return Count > 0; } }
public sunIdentifier NameLabel { get { return this[0] as sunIdentifier; } }
public sunBreak(sunSourceLocation location)
: base(location)
{
: base(location) { }
}
public override void Compile(sunContext context)
{
public override void Compile(sunContext context) {
var point = context.Text.Goto();
if (!context.Loops.AddBreak(point, IsNamed ? NameLabel.Value : null))
{
if (!context.Loops.AddBreak(point, IsNamed ? NameLabel.Value : null)) {
throw new sunBreakException(this);
}
}
}
class sunContinue : sunNode
{
class sunContinue : sunNode {
public bool IsNamed { get { return Count > 0; } }
public sunIdentifier NameLabel { get { return this[0] as sunIdentifier; } }
public sunContinue(sunSourceLocation location)
: base(location)
{
: base(location) { }
}
public override void Compile(sunContext context)
{
public override void Compile(sunContext context) {
var point = context.Text.Goto();
if (!context.Loops.AddContinue(point, IsNamed ? NameLabel.Value : null))
{
if (!context.Loops.AddContinue(point, IsNamed ? NameLabel.Value : null)) {
throw new sunContinueException(this);
}
}

View file

@ -1,95 +1,70 @@
using System.Collections.Generic;
using System.Linq;
namespace arookas
{
class sunBuiltinDeclaration : sunNode
{
namespace arookas {
class sunBuiltinDeclaration : sunNode {
public sunIdentifier Builtin { get { return this[0] as sunIdentifier; } }
public sunParameterList Parameters { get { return this[1] as sunParameterList; } }
public sunBuiltinDeclaration(sunSourceLocation location)
: base(location)
{
: base(location) { }
}
public override void Compile(sunContext context)
{
public override void Compile(sunContext context) {
context.DeclareBuiltin(this);
}
}
class sunFunctionDefinition : sunNode
{
class sunFunctionDefinition : sunNode {
public sunIdentifier Function { get { return this[0] as sunIdentifier; } }
public sunParameterList Parameters { get { return this[1] as sunParameterList; } }
public sunNode Body { get { return this[2]; } }
public sunFunctionDefinition(sunSourceLocation location)
: base(location)
{
: base(location) { }
}
public override void Compile(sunContext context)
{
public override void Compile(sunContext context) {
context.DefineFunction(this); // possibly counter intuitively, this defines the function in the context; it doesn't compile the definition body
}
}
class sunFunctionCall : sunNode
{
class sunFunctionCall : sunNode {
public sunIdentifier Function { get { return this[0] as sunIdentifier; } }
public sunNode Arguments { get { return this[1] as sunNode; } }
bool IsStatement { get { return !(Parent is sunOperand); } }
public sunFunctionCall(sunSourceLocation location)
: base(location)
{
: base(location) { }
}
public override void Compile(sunContext context)
{
public override void Compile(sunContext context) {
var callableInfo = context.MustResolveCallable(this);
if (!callableInfo.Parameters.ValidateArgumentCount(Arguments.Count))
{
if (!callableInfo.Parameters.ValidateArgumentCount(Arguments.Count)) {
throw new sunArgumentCountException(this, callableInfo);
}
Arguments.Compile(context);
callableInfo.OpenCallSite(context, Arguments.Count);
if (IsStatement)
{
if (IsStatement) {
context.Text.Pop();
}
}
}
class sunParameterList : sunNode
{
class sunParameterList : sunNode {
public IEnumerable<sunIdentifier> Parameters { get { return this.OfType<sunIdentifier>(); } }
public bool IsVariadic { get { return Count > 0 && this[Count - 1] is sunEllipsis; } }
public sunParameterInfo ParameterInfo { get { return new sunParameterInfo(Parameters, IsVariadic); } }
public sunParameterList(sunSourceLocation location)
: base(location)
{
: base(location) {
int count = this.Count(i => i is sunEllipsis);
if (count > 1 || (count > 0 && !(this[Count - 1] is sunEllipsis)))
{
if (count > 1 || (count > 0 && !(this[Count - 1] is sunEllipsis))) {
throw new sunVariadicParameterListException(this);
}
}
}
class sunEllipsis : sunNode
{
class sunEllipsis : sunNode {
public sunEllipsis(sunSourceLocation location)
: base(location)
{
}
: base(location) { }
}
}

View file

@ -2,91 +2,70 @@
using System.Globalization;
using System.Text;
namespace arookas
{
class sunIntLiteral : sunToken<int> // base-10 integer
{
namespace arookas {
class sunIntLiteral : sunToken<int> { // base-10 integer
public sunIntLiteral(sunSourceLocation location, string literal)
: base(location)
{
: base(location) {
Value = Int32.Parse(literal);
}
protected sunIntLiteral(sunSourceLocation location)
: base(location)
{
// this overload lets protected classes set the value to something else
}
public override void Compile(sunContext context)
{
context.Text.PushInt(Value);
}
// this overload lets protected classes set the value to something else
protected sunIntLiteral(sunSourceLocation location)
: base(location) { }
public override void Compile(sunContext context) { context.Text.PushInt(Value); }
}
class sunHexLiteral : sunIntLiteral // base-16 integer
{
class sunHexLiteral : sunIntLiteral { // base-16 integer
public sunHexLiteral(sunSourceLocation location, string literal)
: base(location)
{
: base(location) {
// because .NET's hex parsing is gay and doesn't support
// leading signs, manually detect negative literals
var neg = (literal[0] == '-');
var trim = neg ? 3 : 2;
var digits = literal.Substring(trim); // trim the '0x' prefix before parsing
Value = Int32.Parse(literal.Substring(2), NumberStyles.AllowHexSpecifier);
if (neg)
{
if (neg) {
Value = -Value;
}
}
}
class sunFloatLiteral : sunToken<float>
{
class sunFloatLiteral : sunToken<float> {
public sunFloatLiteral(sunSourceLocation location, string literal)
: base(location)
{
: base(location) {
Value = Single.Parse(literal);
}
public override void Compile(sunContext context)
{
public override void Compile(sunContext context) {
context.Text.PushFloat(Value);
}
}
class sunStringLiteral : sunToken<string>
{
class sunStringLiteral : sunToken<string> {
public sunStringLiteral(sunSourceLocation location, string literal)
: base(location)
{
: base(location) {
Value = UnescapeString(literal.Substring(1, literal.Length - 2)); // remove enclosing quotes
}
public override void Compile(sunContext context)
{
public override void Compile(sunContext context) {
context.Text.PushData(context.DataTable.Add(Value));
}
// string unescaping utility
string UnescapeString(string value)
{
string UnescapeString(string value) {
// based on Hans Passant's code
StringBuilder sb = new StringBuilder(value.Length);
for (int i = 0; i < value.Length;)
{
for (int i = 0; i < value.Length;) {
int j = value.IndexOf('\\', i);
if (j < 0 || j >= value.Length - 1)
{
if (j < 0 || j >= value.Length - 1) {
j = value.Length;
}
sb.Append(value, i, j - i);
if (j >= value.Length)
{
if (j >= value.Length) {
break;
}
switch (value[j + 1])
{
switch (value[j + 1]) {
case '\'': sb.Append('\''); break;
case '"': sb.Append('"'); break;
case '\\': sb.Append('\\'); break;
@ -106,16 +85,13 @@ namespace arookas
}
return sb.ToString();
}
char UnescapeHex(string value, int start, out int end)
{
if (start > value.Length)
{
char UnescapeHex(string value, int start, out int end) {
if (start > value.Length) {
throw new sunEscapeSequenceException(this); // we need at least one digit
}
StringBuilder sb = new StringBuilder(4);
int digits = 0;
while (digits < 4 && start < value.Length && IsHexDigit(value[start]))
{
while (digits < 4 && start < value.Length && IsHexDigit(value[start])) {
sb.Append(value[start]);
++digits;
++start;
@ -123,46 +99,37 @@ namespace arookas
end = start;
return (char)Int32.Parse(sb.ToString(), NumberStyles.AllowHexSpecifier);
}
char UnescapeUnicodeCodeUnit(string value, int start, out int end)
{
if (start >= value.Length - 4)
{
char UnescapeUnicodeCodeUnit(string value, int start, out int end) {
if (start >= value.Length - 4) {
throw new sunEscapeSequenceException(this); // we need four digits
}
end = start + 4;
return (char)Int32.Parse(value.Substring(start, 4), NumberStyles.AllowHexSpecifier);
}
string UnescapeUnicodeSurrogatePair(string value, int start, out int end)
{
if (start >= value.Length - 8)
{
string UnescapeUnicodeSurrogatePair(string value, int start, out int end) {
if (start >= value.Length - 8) {
throw new sunEscapeSequenceException(this); // we need eight digits
}
char high = (char)Int32.Parse(value.Substring(start, 4), NumberStyles.AllowHexSpecifier);
char low = (char)Int32.Parse(value.Substring(start + 4, 4), NumberStyles.AllowHexSpecifier);
if (!Char.IsHighSurrogate(high) || !Char.IsLowSurrogate(low))
{
if (!Char.IsHighSurrogate(high) || !Char.IsLowSurrogate(low)) {
throw new sunEscapeSequenceException(this); // characters are not a surrogate pair
}
end = start + 8;
return String.Concat(high, low);
}
static bool IsHexDigit(char c)
{
static bool IsHexDigit(char c) {
return (c >= '0' && c <= '9') ||
(c >= 'A' && c <= 'F') ||
(c >= 'a' && c <= 'f');
}
}
class sunIdentifier : sunToken<string>
{
class sunIdentifier : sunToken<string> {
public sunIdentifier(sunSourceLocation location, string identifier)
: base(location)
{
: base(location) {
// make sure it is a valid identifier name (i.e. not a keyword)
if (sunParser.IsKeyword(identifier))
{
if (sunParser.IsKeyword(identifier)) {
throw new sunIdentifierException(this);
}
Value = identifier;
@ -171,20 +138,16 @@ namespace arookas
// identifiers are compiled on a per-context basis (i.e. at a higher level)
}
class sunTrue : sunIntLiteral
{
class sunTrue : sunIntLiteral {
public sunTrue(sunSourceLocation location)
: base(location)
{
: base(location) {
Value = 1;
}
}
class sunFalse : sunIntLiteral
{
class sunFalse : sunIntLiteral {
public sunFalse(sunSourceLocation location)
: base(location)
{
: base(location) {
Value = 0;
}
}

View file

@ -1,15 +1,12 @@
using PerCederberg.Grammatica.Runtime;
namespace arookas
{
enum Associativity
{
namespace arookas {
enum Associativity {
Left,
Right,
}
abstract class sunOperator : sunNode
{
abstract class sunOperator : sunNode {
public virtual Associativity Associativity { get { return Associativity.Left; } }
public abstract int Precedence { get; }
@ -17,297 +14,208 @@ namespace arookas
public bool IsRightAssociative { get { return Associativity == Associativity.Right; } }
protected sunOperator(sunSourceLocation location)
: base(location)
{
}
: base(location) { }
}
// precedence 0
class sunLogOR : sunOperator
{
class sunLogOR : sunOperator {
public override int Precedence { get { return 0; } }
public sunLogOR(sunSourceLocation location)
: base(location)
{
}
: base(location) { }
public override void Compile(sunContext context) { context.Text.LogOR(); }
}
// precedence 1
class sunLogAND : sunOperator
{
class sunLogAND : sunOperator {
public override int Precedence { get { return 1; } }
public sunLogAND(sunSourceLocation location)
: base(location)
{
}
: base(location) { }
public override void Compile(sunContext context) { context.Text.LogAND(); }
}
// precedence 2
class sunBitOR : sunOperator
{
class sunBitOR : sunOperator {
public override int Precedence { get { return 2; } }
public sunBitOR(sunSourceLocation location)
: base(location)
{
}
: base(location) { }
public override void Compile(sunContext context) { context.Text.BitOR(); }
}
// precedence 3
class sunBitAND : sunOperator
{
class sunBitAND : sunOperator {
public override int Precedence { get { return 3; } }
public sunBitAND(sunSourceLocation location)
: base(location)
{
}
: base(location) { }
public override void Compile(sunContext context) { context.Text.BitAND(); }
}
// precedence 4
class sunEq : sunOperator
{
class sunEq : sunOperator {
public override int Precedence { get { return 4; } }
public sunEq(sunSourceLocation location)
: base(location)
{
}
: base(location) { }
public override void Compile(sunContext context) { context.Text.Eq(); }
}
class sunNtEq : sunOperator
{
class sunNtEq : sunOperator {
public override int Precedence { get { return 4; } }
public sunNtEq(sunSourceLocation location)
: base(location)
{
}
: base(location) { }
public override void Compile(sunContext context) { context.Text.NtEq(); }
}
// precedence 5
class sunLt : sunOperator
{
class sunLt : sunOperator {
public override int Precedence { get { return 5; } }
public sunLt(sunSourceLocation location)
: base(location)
{
}
: base(location) { }
public override void Compile(sunContext context) { context.Text.Lt(); }
}
class sunLtEq : sunOperator
{
class sunLtEq : sunOperator {
public override int Precedence { get { return 5; } }
public sunLtEq(sunSourceLocation location)
: base(location)
{
}
: base(location) { }
public override void Compile(sunContext context) { context.Text.LtEq(); }
}
class sunGt : sunOperator
{
class sunGt : sunOperator {
public override int Precedence { get { return 5; } }
public sunGt(sunSourceLocation location)
: base(location)
{
}
: base(location) { }
public override void Compile(sunContext context) { context.Text.Gt(); }
}
class sunGtEq : sunOperator
{
class sunGtEq : sunOperator {
public override int Precedence { get { return 5; } }
public sunGtEq(sunSourceLocation location)
: base(location)
{
}
: base(location) { }
public override void Compile(sunContext context) { context.Text.GtEq(); }
}
// precedence 6
class sunBitLsh : sunOperator
{
class sunBitLsh : sunOperator {
public override int Precedence { get { return 6; } }
public sunBitLsh(sunSourceLocation location)
: base(location)
{
}
: base(location) { }
public override void Compile(sunContext context) { context.Text.ShL(); }
}
class sunBitRsh : sunOperator
{
class sunBitRsh : sunOperator {
public override int Precedence { get { return 6; } }
public sunBitRsh(sunSourceLocation location)
: base(location)
{
}
: base(location) { }
public override void Compile(sunContext context) { context.Text.ShR(); }
}
// precedence 7
class sunAdd : sunOperator
{
class sunAdd : sunOperator {
public override int Precedence { get { return 7; } }
public sunAdd(sunSourceLocation location)
: base(location)
{
}
: base(location) { }
public override void Compile(sunContext context) { context.Text.Add(); }
}
class sunSub : sunOperator
{
class sunSub : sunOperator {
public override int Precedence { get { return 7; } }
public sunSub(sunSourceLocation location)
: base(location)
{
}
: base(location) { }
public override void Compile(sunContext context) { context.Text.Sub(); }
}
// precedence 8
class sunMul : sunOperator
{
class sunMul : sunOperator {
public override int Precedence { get { return 8; } }
public sunMul(sunSourceLocation location)
: base(location)
{
}
: base(location) { }
public override void Compile(sunContext context) { context.Text.Mul(); }
}
class sunDiv : sunOperator
{
class sunDiv : sunOperator {
public override int Precedence { get { return 8; } }
public sunDiv(sunSourceLocation location)
: base(location)
{
}
: base(location) { }
public override void Compile(sunContext context) { context.Text.Div(); }
}
class sunMod : sunOperator
{
class sunMod : sunOperator {
public override int Precedence { get { return 8; } }
public sunMod(sunSourceLocation location)
: base(location)
{
}
: base(location) { }
public override void Compile(sunContext context) { context.Text.Mod(); }
}
// precedence 9
class sunLogNOT : sunOperator
{
class sunLogNOT : sunOperator {
public override int Precedence { get { return 9; } }
public sunLogNOT(sunSourceLocation location)
: base(location)
{
}
: base(location) { }
public override void Compile(sunContext context) { context.Text.LogNOT(); }
}
class sunNeg : sunOperator
{
class sunNeg : sunOperator {
public override int Precedence { get { return 9; } }
public sunNeg(sunSourceLocation location)
: base(location)
{
}
: base(location) { }
public override void Compile(sunContext context) { context.Text.Neg(); }
}
// assignment operators
class sunAssign : sunOperator
{
class sunAssign : sunOperator {
public override Associativity Associativity { get { return Associativity.Right; } }
public override int Precedence { get { return -1; } }
public sunAssign(sunSourceLocation location)
: base(location)
{
: base(location) { }
}
public virtual void Compile(sunContext context, sunStorableSymbol symbol, sunExpression expression)
{
public virtual void Compile(sunContext context, sunStorableSymbol symbol, sunExpression expression) {
expression.Compile(context);
symbol.CompileSet(context);
}
}
class sunAssignAdd : sunAssign
{
class sunAssignAdd : sunAssign {
public sunAssignAdd(sunSourceLocation location)
: base(location)
{
: base(location) { }
}
public override void Compile(sunContext context, sunStorableSymbol symbol, sunExpression expression)
{
public override void Compile(sunContext context, sunStorableSymbol symbol, sunExpression expression) {
symbol.CompileGet(context);
expression.Compile(context);
context.Text.Add();
@ -315,16 +223,11 @@ namespace arookas
}
}
class sunAssignSub : sunAssign
{
class sunAssignSub : sunAssign {
public sunAssignSub(sunSourceLocation location)
: base(location)
{
: base(location) { }
}
public override void Compile(sunContext context, sunStorableSymbol symbol, sunExpression expression)
{
public override void Compile(sunContext context, sunStorableSymbol symbol, sunExpression expression) {
symbol.CompileGet(context);
expression.Compile(context);
context.Text.Sub();
@ -332,16 +235,11 @@ namespace arookas
}
}
class sunAssignMul : sunAssign
{
class sunAssignMul : sunAssign {
public sunAssignMul(sunSourceLocation location)
: base(location)
{
: base(location) { }
}
public override void Compile(sunContext context, sunStorableSymbol symbol, sunExpression expression)
{
public override void Compile(sunContext context, sunStorableSymbol symbol, sunExpression expression) {
symbol.CompileGet(context);
expression.Compile(context);
context.Text.Mul();
@ -349,16 +247,11 @@ namespace arookas
}
}
class sunAssignDiv : sunAssign
{
class sunAssignDiv : sunAssign {
public sunAssignDiv(sunSourceLocation location)
: base(location)
{
: base(location) { }
}
public override void Compile(sunContext context, sunStorableSymbol symbol, sunExpression expression)
{
public override void Compile(sunContext context, sunStorableSymbol symbol, sunExpression expression) {
symbol.CompileGet(context);
expression.Compile(context);
context.Text.Div();
@ -366,16 +259,11 @@ namespace arookas
}
}
class sunAssignMod : sunAssign
{
class sunAssignMod : sunAssign {
public sunAssignMod(sunSourceLocation location)
: base(location)
{
: base(location) { }
}
public override void Compile(sunContext context, sunStorableSymbol symbol, sunExpression expression)
{
public override void Compile(sunContext context, sunStorableSymbol symbol, sunExpression expression) {
symbol.CompileGet(context);
expression.Compile(context);
context.Text.Mod();
@ -383,16 +271,11 @@ namespace arookas
}
}
class sunAssignBitAND : sunAssign
{
class sunAssignBitAND : sunAssign {
public sunAssignBitAND(sunSourceLocation location)
: base(location)
{
: base(location) { }
}
public override void Compile(sunContext context, sunStorableSymbol symbol, sunExpression expression)
{
public override void Compile(sunContext context, sunStorableSymbol symbol, sunExpression expression) {
symbol.CompileGet(context);
expression.Compile(context);
context.Text.BitAND();
@ -400,16 +283,11 @@ namespace arookas
}
}
class sunAssignBitOR : sunAssign
{
class sunAssignBitOR : sunAssign {
public sunAssignBitOR(sunSourceLocation location)
: base(location)
{
: base(location) { }
}
public override void Compile(sunContext context, sunStorableSymbol symbol, sunExpression expression)
{
public override void Compile(sunContext context, sunStorableSymbol symbol, sunExpression expression) {
symbol.CompileGet(context);
expression.Compile(context);
context.Text.BitOR();
@ -417,16 +295,11 @@ namespace arookas
}
}
class sunAssignBitLsh : sunAssign
{
class sunAssignBitLsh : sunAssign {
public sunAssignBitLsh(sunSourceLocation location)
: base(location)
{
: base(location) { }
}
public override void Compile(sunContext context, sunStorableSymbol symbol, sunExpression expression)
{
public override void Compile(sunContext context, sunStorableSymbol symbol, sunExpression expression) {
symbol.CompileGet(context);
expression.Compile(context);
context.Text.ShL();
@ -434,16 +307,11 @@ namespace arookas
}
}
class sunAssignBitRsh : sunAssign
{
class sunAssignBitRsh : sunAssign {
public sunAssignBitRsh(sunSourceLocation location)
: base(location)
{
: base(location) { }
}
public override void Compile(sunContext context, sunStorableSymbol symbol, sunExpression expression)
{
public override void Compile(sunContext context, sunStorableSymbol symbol, sunExpression expression) {
symbol.CompileGet(context);
expression.Compile(context);
context.Text.ShR();

View file

@ -1,59 +1,39 @@
namespace arookas
{
class sunCompoundStatement : sunNode
{
namespace arookas {
class sunCompoundStatement : sunNode {
public sunCompoundStatement(sunSourceLocation location)
: base(location)
{
}
: base(location) { }
}
class sunStatementBlock : sunNode
{
class sunStatementBlock : sunNode {
public sunStatementBlock(sunSourceLocation location)
: base(location)
{
: base(location) { }
}
public override void Compile(sunContext context)
{
public override void Compile(sunContext context) {
context.Scopes.Push(context.Scopes.Top.Type);
base.Compile(context);
context.Scopes.Pop();
}
}
class sunImport : sunNode
{
class sunImport : sunNode {
public sunStringLiteral ImportFile { get { return this[0] as sunStringLiteral; } }
public sunImport(sunSourceLocation location)
: base(location)
{
: base(location) { }
}
public override void Compile(sunContext context)
{
public override void Compile(sunContext context) {
var result = context.Import(ImportFile.Value);
switch (result)
{
switch (result) {
case sunImportResult.Missing:
case sunImportResult.FailedToLoad: throw new sunMissingImportException(this);
}
}
}
class sunNameLabel : sunNode
{
class sunNameLabel : sunNode {
public sunIdentifier Label { get { return this[0] as sunIdentifier; } }
public sunNameLabel(sunSourceLocation location)
: base(location)
{
}
: base(location) { }
}
}

View file

@ -1,151 +1,105 @@
namespace arookas
{
class sunYield : sunNode
{
namespace arookas {
class sunYield : sunNode {
public sunYield(sunSourceLocation location)
: base(location)
{
: base(location) { }
}
public override void Compile(sunContext context)
{
public override void Compile(sunContext context) {
var builtinInfo = context.ResolveSystemBuiltin("yield");
context.Text.CallBuiltin(builtinInfo.Index, 0);
context.Text.Pop();
}
}
class sunExit : sunNode
{
class sunExit : sunNode {
public sunExit(sunSourceLocation location)
: base(location)
{
: base(location) { }
}
public override void Compile(sunContext context)
{
public override void Compile(sunContext context) {
var builtinInfo = context.ResolveSystemBuiltin("exit");
context.Text.CallBuiltin(builtinInfo.Index, 0);
context.Text.Pop();
}
}
class sunDump : sunNode
{
class sunDump : sunNode {
public sunDump(sunSourceLocation location)
: base(location)
{
: base(location) { }
}
public override void Compile(sunContext context)
{
public override void Compile(sunContext context) {
var builtinInfo = context.ResolveSystemBuiltin("dump");
context.Text.CallBuiltin(builtinInfo.Index, 0);
context.Text.Pop();
}
}
class sunLock : sunNode
{
class sunLock : sunNode {
public sunLock(sunSourceLocation location)
: base(location)
{
: base(location) { }
}
public override void Compile(sunContext context)
{
public override void Compile(sunContext context) {
var builtinInfo = context.ResolveSystemBuiltin("lock");
context.Text.CallBuiltin(builtinInfo.Index, 0);
context.Text.Pop();
}
}
class sunUnlock : sunNode
{
class sunUnlock : sunNode {
public sunUnlock(sunSourceLocation location)
: base(location)
{
: base(location) { }
}
public override void Compile(sunContext context)
{
public override void Compile(sunContext context) {
var builtinInfo = context.ResolveSystemBuiltin("unlock");
context.Text.CallBuiltin(builtinInfo.Index, 0);
context.Text.Pop();
}
}
class sunIntCast : sunNode
{
class sunIntCast : sunNode {
public sunExpression Argument { get { return this[0] as sunExpression; } }
public sunIntCast(sunSourceLocation location)
: base(location)
{
: base(location) { }
}
public override void Compile(sunContext context)
{
public override void Compile(sunContext context) {
var builtinInfo = context.ResolveSystemBuiltin("int");
Argument.Compile(context);
context.Text.CallBuiltin(builtinInfo.Index, 1);
}
}
class sunFloatCast : sunNode
{
class sunFloatCast : sunNode {
public sunExpression Argument { get { return this[0] as sunExpression; } }
public sunFloatCast(sunSourceLocation location)
: base(location)
{
: base(location) { }
}
public override void Compile(sunContext context)
{
public override void Compile(sunContext context) {
var builtinInfo = context.ResolveSystemBuiltin("float");
Argument.Compile(context);
context.Text.CallBuiltin(builtinInfo.Index, 1);
}
}
class sunTypeofCast : sunNode
{
class sunTypeofCast : sunNode {
public sunExpression Argument { get { return this[0] as sunExpression; } }
public sunTypeofCast(sunSourceLocation location)
: base(location)
{
: base(location) { }
}
public override void Compile(sunContext context)
{
public override void Compile(sunContext context) {
var builtinInfo = context.ResolveSystemBuiltin("typeof");
Argument.Compile(context);
context.Text.CallBuiltin(builtinInfo.Index, 1);
}
}
class sunPrint : sunNode
{
class sunPrint : sunNode {
public sunNode ArgumentList { get { return this[0]; } }
public sunPrint(sunSourceLocation location)
: base(location)
{
: base(location) { }
}
public override void Compile(sunContext context)
{
public override void Compile(sunContext context) {
var builtinInfo = context.ResolveSystemBuiltin("print");
ArgumentList.Compile(context);
context.Text.CallBuiltin(builtinInfo.Index, ArgumentList.Count);

View file

@ -1,33 +1,22 @@
namespace arookas
{
class sunStorableReference : sunNode
{
namespace arookas {
class sunStorableReference : sunNode {
public sunIdentifier Storable { get { return this[0] as sunIdentifier; } }
public sunStorableReference(sunSourceLocation location)
: base(location)
{
: base(location) { }
}
public override void Compile(sunContext context)
{
public override void Compile(sunContext context) {
context.MustResolveStorable(Storable).Compile(context);
}
}
class sunVariableDeclaration : sunNode
{
class sunVariableDeclaration : sunNode {
public sunIdentifier Variable { get { return this[0] as sunIdentifier; } }
public sunVariableDeclaration(sunSourceLocation location)
: base(location)
{
: base(location) { }
}
public override void Compile(sunContext context)
{
public override void Compile(sunContext context) {
context.DeclareVariable(Variable);
}
}
@ -39,13 +28,9 @@
public sunExpression Expression { get { return this[2] as sunExpression; } }
public sunVariableDefinition(sunSourceLocation location)
: base(location)
{
: base(location) { }
}
public override void Compile(sunContext context)
{
public override void Compile(sunContext context) {
var symbol = context.DeclareVariable(Variable);
Operator.Compile(context, symbol, Expression);
}
@ -58,16 +43,11 @@
public sunExpression Expression { get { return this[2] as sunExpression; } }
public sunStorableAssignment(sunSourceLocation location)
: base(location)
{
: base(location) { }
}
public override void Compile(sunContext context)
{
public override void Compile(sunContext context) {
var symbol = context.MustResolveStorable(Storable);
if (symbol is sunConstantSymbol)
{
if (symbol is sunConstantSymbol) {
throw new sunAssignConstantException(Storable);
}
Operator.Compile(context, symbol, Expression);
@ -80,13 +60,9 @@
public sunExpression Expression { get { return this[2] as sunExpression; } }
public sunConstantDefinition(sunSourceLocation location)
: base(location)
{
: base(location) { }
}
public override void Compile(sunContext context)
{
public override void Compile(sunContext context) {
context.DeclareConstant(Constant, Expression);
}
}

View file

@ -2,46 +2,35 @@
using System.Diagnostics;
using System.IO;
namespace arookas
{
public class sunCompiler
{
public sunCompilerResults Compile(string name, Stream output)
{
namespace arookas {
public class sunCompiler {
public sunCompilerResults Compile(string name, Stream output) {
return Compile(name, output, sunImportResolver.Default);
}
public sunCompilerResults Compile(string name, Stream output, sunImportResolver resolver)
{
if (name == null)
{
public sunCompilerResults Compile(string name, Stream output, sunImportResolver resolver) {
if (name == null) {
throw new ArgumentNullException("name");
}
if (output == null)
{
if (output == null) {
throw new ArgumentNullException("output");
}
if (resolver == null)
{
if (resolver == null) {
throw new ArgumentNullException("resolver");
}
var context = new sunContext();
var results = new sunCompilerResults();
var timer = Stopwatch.StartNew();
try
{
try {
context.Open(output, resolver);
var result = context.Import(name);
if (result != sunImportResult.Loaded)
{
if (result != sunImportResult.Loaded) {
throw new sunImportException(name, result);
}
context.Text.Terminate(); // NOTETOSELF: don't do this via sunNode.Compile because imported files will add this as well
foreach (var function in context.SymbolTable.Functions)
{
foreach (var function in context.SymbolTable.Functions) {
function.Compile(context);
}
foreach (var function in context.SymbolTable.Functions)
{
foreach (var function in context.SymbolTable.Functions) {
function.CloseCallSites(context);
}
results.DataCount = context.DataTable.Count;
@ -51,8 +40,7 @@ namespace arookas
results.VariableCount = context.SymbolTable.VariableCount;
context.Close();
}
catch (sunCompilerException ex)
{
catch (sunCompilerException ex) {
results.Error = ex;
}
timer.Stop();
@ -61,8 +49,7 @@ namespace arookas
}
}
public class sunCompilerResults
{
public class sunCompilerResults {
// success
public bool Success { get { return Error == null; } }
public sunCompilerException Error { get; internal set; }

View file

@ -4,10 +4,8 @@ using System.IO;
using System.Linq;
using System.Text;
namespace arookas
{
class sunContext
{
namespace arookas {
class sunContext {
bool mOpen;
aBinaryWriter mWriter;
uint mTextOffset, mDataOffset, mSymbolOffset;
@ -19,8 +17,7 @@ namespace arookas
public sunLoopStack Loops { get; private set; }
public sunImportResolver ImportResolver { get; private set; }
public sunContext()
{
public sunContext() {
DataTable = new sunDataTable();
SymbolTable = new sunSymbolTable();
Scopes = new sunScopeStack();
@ -28,22 +25,15 @@ namespace arookas
}
// open/close
public void Open(Stream output)
{
Open(output, sunImportResolver.Default);
}
public void Open(Stream output, sunImportResolver importResolver)
{
if (mOpen)
{
public void Open(Stream output) { Open(output, sunImportResolver.Default); }
public void Open(Stream output, sunImportResolver importResolver) {
if (mOpen) {
throw new InvalidOperationException();
}
if (output == null)
{
if (output == null) {
throw new ArgumentNullException("output");
}
if (importResolver == null)
{
if (importResolver == null) {
throw new ArgumentNullException("importResolver");
}
mOpen = true;
@ -73,10 +63,8 @@ namespace arookas
DeclareSystemBuiltin("typeof", false, "x");
DeclareSystemBuiltin("print", true);
}
public void Close()
{
if (!mOpen)
{
public void Close() {
if (!mOpen) {
throw new InvalidOperationException();
}
mWriter.PopAnchor();
@ -90,26 +78,21 @@ namespace arookas
}
// imports/compilation
public sunImportResult Import(string name)
{
if (name == null)
{
public sunImportResult Import(string name) {
if (name == null) {
throw new ArgumentNullException("name");
}
sunScriptFile file;
var result = ImportResolver.ResolveImport(name, out file);
if (result == sunImportResult.Loaded)
{
try
{
if (result == sunImportResult.Loaded) {
try {
ImportResolver.EnterFile(file);
var parser = new sunParser();
var tree = parser.Parse(file);
tree.Compile(this);
ImportResolver.ExitFile(file);
}
finally
{
finally {
file.Dispose();
}
}
@ -117,82 +100,68 @@ namespace arookas
}
// callables
public sunBuiltinSymbol DeclareBuiltin(sunBuiltinDeclaration node)
{
if (SymbolTable.Callables.Any(i => i.Name == node.Builtin.Value))
{
public sunBuiltinSymbol DeclareBuiltin(sunBuiltinDeclaration node) {
if (SymbolTable.Callables.Any(i => i.Name == node.Builtin.Value)) {
throw new sunRedeclaredBuiltinException(node);
}
var symbol = new sunBuiltinSymbol(node.Builtin.Value, node.Parameters.ParameterInfo, SymbolTable.Count);
SymbolTable.Add(symbol);
return symbol;
}
public sunFunctionSymbol DefineFunction(sunFunctionDefinition node)
{
if (node.Parameters.IsVariadic)
{
public sunFunctionSymbol DefineFunction(sunFunctionDefinition node) {
if (node.Parameters.IsVariadic) {
throw new sunVariadicFunctionException(node);
}
if (SymbolTable.Callables.Any(i => i.Name == node.Function.Value))
{
if (SymbolTable.Callables.Any(i => i.Name == node.Function.Value)) {
throw new sunRedefinedFunctionException(node);
}
var symbol = new sunFunctionSymbol(node.Function.Value, node.Parameters.ParameterInfo, node.Body);
SymbolTable.Add(symbol);
return symbol;
}
public sunCallableSymbol ResolveCallable(sunFunctionCall node)
{
public sunCallableSymbol ResolveCallable(sunFunctionCall node) {
var symbol = SymbolTable.Callables.FirstOrDefault(i => i.Name == node.Function.Value);
if (symbol == null)
{
if (symbol == null) {
throw new sunUndefinedFunctionException(node);
}
return symbol;
}
public sunCallableSymbol MustResolveCallable(sunFunctionCall node)
{
public sunCallableSymbol MustResolveCallable(sunFunctionCall node) {
var symbol = ResolveCallable(node);
if (symbol == null)
{
if (symbol == null) {
throw new sunUndefinedFunctionException(node);
}
return symbol;
}
public sunBuiltinSymbol DeclareSystemBuiltin(string name, bool variadic, params string[] parameters)
{
public sunBuiltinSymbol DeclareSystemBuiltin(string name, bool variadic, params string[] parameters) {
var symbol = SymbolTable.Builtins.FirstOrDefault(i => i.Name == name);
if (symbol == null)
{
if (symbol == null) {
symbol = new sunBuiltinSymbol(name, new sunParameterInfo(parameters, variadic), SymbolTable.Count);
SymbolTable.Add(symbol);
}
return symbol;
}
public sunBuiltinSymbol ResolveSystemBuiltin(string name)
{
public sunBuiltinSymbol ResolveSystemBuiltin(string name) {
return SymbolTable.Builtins.FirstOrDefault(i => i.Name == name);
}
// storables
public sunVariableSymbol DeclareVariable(sunIdentifier node)
{
public sunVariableSymbol DeclareVariable(sunIdentifier node) {
#if SSC_RESOLVEVAR_NEST
if (Scopes.Top.GetIsDeclared(node.Value))
#else
if (Scopes.Any(i => i.GetIsDeclared(node.Value)))
#endif
{
if (Scopes.Top.GetIsDeclared(node.Value)) {
throw new sunRedeclaredVariableException(node);
}
#else
if (Scopes.Any(i => i.GetIsDeclared(node.Value))) {
throw new sunRedeclaredVariableException(node);
}
#endif
var symbol = Scopes.DeclareVariable(node.Value);
if (Scopes.Top.Type == sunScopeType.Script) // global-scope variables are added to the symbol table
{
if (Scopes.Top.Type == sunScopeType.Script) { // global-scope variables are added to the symbol table
#if SSC_RESOLVEVAR_NEST
// only add the variable symbol if there isn't one with this index already
if (!SymbolTable.Variables.Any(i => i.Index == symbol.Index))
{
if (!SymbolTable.Variables.Any(i => i.Index == symbol.Index)) {
SymbolTable.Add(new sunVariableSymbol(String.Format("global{0}", symbol.Index), symbol.Display, symbol.Index));
}
#else
@ -201,68 +170,52 @@ namespace arookas
}
return symbol;
}
public sunConstantSymbol DeclareConstant(sunIdentifier node, sunExpression expression)
{
public sunConstantSymbol DeclareConstant(sunIdentifier node, sunExpression expression) {
#if SSC_RESOLVEVAR_NEST
if (Scopes.Top.GetIsDeclared(node.Value))
#else
if (Scopes.Any(i => i.GetIsDeclared(node.Value)))
#endif
{
if (Scopes.Top.GetIsDeclared(node.Value)) {
throw new sunRedeclaredVariableException(node);
}
#else
if (Scopes.Any(i => i.GetIsDeclared(node.Value))) {
throw new sunRedeclaredVariableException(node);
}
#endif
return Scopes.DeclareConstant(node.Value, expression);
}
public sunStorableSymbol ResolveStorable(sunIdentifier node)
{
for (int i = Scopes.Count - 1; i >= 0; --i)
{
public sunStorableSymbol ResolveStorable(sunIdentifier node) {
for (int i = Scopes.Count - 1; i >= 0; --i) {
var symbol = Scopes[i].ResolveStorable(node.Value);
if (symbol != null)
{
if (symbol != null) {
return symbol;
}
}
return null;
}
public sunVariableSymbol ResolveVariable(sunIdentifier node)
{
return ResolveStorable(node) as sunVariableSymbol;
}
public sunConstantSymbol ResolveConstant(sunIdentifier node)
{
return ResolveStorable(node) as sunConstantSymbol;
}
public sunStorableSymbol MustResolveStorable(sunIdentifier node)
{
public sunVariableSymbol ResolveVariable(sunIdentifier node) { return ResolveStorable(node) as sunVariableSymbol; }
public sunConstantSymbol ResolveConstant(sunIdentifier node) { return ResolveStorable(node) as sunConstantSymbol; }
public sunStorableSymbol MustResolveStorable(sunIdentifier node) {
var symbol = ResolveStorable(node);
if (symbol == null)
{
if (symbol == null) {
throw new sunUndeclaredVariableException(node);
}
return symbol;
}
public sunVariableSymbol MustResolveVariable(sunIdentifier node)
{
public sunVariableSymbol MustResolveVariable(sunIdentifier node) {
var symbol = ResolveVariable(node);
if (symbol == null)
{
if (symbol == null) {
throw new sunUndeclaredVariableException(node);
}
return symbol;
}
public sunConstantSymbol MustResolveConstant(sunIdentifier node)
{
public sunConstantSymbol MustResolveConstant(sunIdentifier node) {
var symbol = ResolveConstant(node);
if (symbol == null)
{
if (symbol == null) {
throw new sunUndeclaredVariableException(node);
}
return symbol;
}
void WriteHeader()
{
void WriteHeader() {
mWriter.WriteString("SPCB");
mWriter.Write32(mTextOffset);
mWriter.Write32(mDataOffset);

View file

@ -2,19 +2,15 @@
using System.Collections;
using System.Collections.Generic;
namespace arookas
{
class sunDataTable : IEnumerable<string>
{
namespace arookas {
class sunDataTable : IEnumerable<string> {
List<string> data = new List<string>(10);
public int Count { get { return data.Count; } }
public int Add(string value)
{
public int Add(string value) {
int index = data.IndexOf(value);
if (index < 0)
{
if (index < 0) {
index = data.Count;
data.Add(value);
}
@ -22,17 +18,14 @@ namespace arookas
}
public void Clear() { data.Clear(); }
public void Write(aBinaryWriter writer)
{
public void Write(aBinaryWriter writer) {
int ofs = 0;
foreach (var value in this)
{
foreach (var value in this) {
writer.WriteS32(ofs);
var length = writer.Encoding.GetByteCount(value);
ofs += length + 1; // include terminator
}
foreach (var value in this)
{
foreach (var value in this) {
writer.WriteString(value, aBinaryStringFormat.NullTerminated);
}
}

View file

@ -1,67 +1,53 @@
using PerCederberg.Grammatica.Runtime;
using System;
namespace arookas
{
namespace arookas {
// base exception type
public class sunCompilerException : Exception
{
public sunCompilerException()
{
public class sunCompilerException : Exception {
public sunCompilerException() {
}
public sunCompilerException(string format, params object[] args)
: base(String.Format(format, args))
{
: base(String.Format(format, args)) {
}
}
// exceptions that have a location in the source
public abstract class sunSourceException : sunCompilerException
{
public abstract class sunSourceException : sunCompilerException {
public abstract sunSourceLocation Location { get; }
public sunSourceException()
{
public sunSourceException() {
}
public sunSourceException(string format, params object[] args)
: base(format, args)
{
: base(format, args) {
}
}
public class sunImportException : sunCompilerException
{
public class sunImportException : sunCompilerException {
public string Name { get; private set; }
public sunImportResult Result { get; private set; }
public override string Message
{
get
{
public override string Message {
get {
string format;
switch (Result)
{
case sunImportResult.Loaded: format = "Script '{0}' loaded successfully."; break; // Error: Success!
case sunImportResult.Skipped: format = "Script '{0}' was skipped."; break;
case sunImportResult.Missing: format = "Script '{0}' could not be found."; break;
case sunImportResult.FailedToLoad: format = "Script '{0}' failed to load."; break;
default: format = "Name: {0}, Result: {1}"; break;
switch (Result) {
case sunImportResult.Loaded: format = "Script '{0}' loaded successfully."; break; // Error: Success!
case sunImportResult.Skipped: format = "Script '{0}' was skipped."; break;
case sunImportResult.Missing: format = "Script '{0}' could not be found."; break;
case sunImportResult.FailedToLoad: format = "Script '{0}' failed to load."; break;
default: format = "Name: {0}, Result: {1}"; break;
}
return String.Format(format, Name, Result);
}
}
public sunImportException(string name, sunImportResult result)
{
if (name == null)
{
public sunImportException(string name, sunImportResult result) {
if (name == null) {
throw new ArgumentNullException("name");
}
if (!result.IsDefined())
{
if (!result.IsDefined()) {
throw new ArgumentOutOfRangeException("name");
}
Name = name;
@ -70,22 +56,18 @@ namespace arookas
}
// wrapper around Grammatica exceptions
class sunParserException : sunSourceException
{
class sunParserException : sunSourceException {
string file;
public ParseException Info { get; private set; }
public override string Message { get { return Info.ErrorMessage; } }
public override sunSourceLocation Location { get { return new sunSourceLocation(file, Info.Line, Info.Column); } }
public sunParserException(string file, ParseException info)
{
if (file == null)
{
public sunParserException(string file, ParseException info) {
if (file == null) {
throw new ArgumentNullException("file");
}
if (info == null)
{
if (info == null) {
throw new ArgumentNullException("info");
}
this.file = file;
@ -94,143 +76,114 @@ namespace arookas
}
// node exceptions
abstract class sunNodeException<TNode> : sunSourceException where TNode : sunNode
{
abstract class sunNodeException<TNode> : sunSourceException where TNode : sunNode {
public TNode Node { get; private set; }
public override sunSourceLocation Location { get { return Node.Location; } }
protected sunNodeException(TNode node)
{
if (node == null)
{
protected sunNodeException(TNode node) {
if (node == null) {
throw new ArgumentNullException("node");
}
Node = node;
}
}
class sunRedeclaredBuiltinException : sunNodeException<sunBuiltinDeclaration>
{
class sunRedeclaredBuiltinException : sunNodeException<sunBuiltinDeclaration> {
public override string Message { get { return String.Format("Redeclared builtin '{0}'.", Node.Builtin.Value); } }
public sunRedeclaredBuiltinException(sunBuiltinDeclaration node)
: base(node)
{
: base(node) {
}
}
class sunUndefinedFunctionException : sunNodeException<sunFunctionCall>
{
class sunUndefinedFunctionException : sunNodeException<sunFunctionCall> {
public override string Message { get { return String.Format("Undefined function or builtin '{0}'.", Node.Function.Value); } }
public sunUndefinedFunctionException(sunFunctionCall node)
: base(node)
{
: base(node) {
}
}
class sunRedefinedFunctionException : sunNodeException<sunFunctionDefinition>
{
class sunRedefinedFunctionException : sunNodeException<sunFunctionDefinition> {
public override string Message { get { return String.Format("Redefined function '{0}'.", Node.Function.Value); } }
public sunRedefinedFunctionException(sunFunctionDefinition node)
: base(node)
{
: base(node) {
}
}
class sunUndeclaredVariableException : sunNodeException<sunIdentifier>
{
class sunUndeclaredVariableException : sunNodeException<sunIdentifier> {
public override string Message { get { return String.Format("Undeclared variable '{0}'.", Node.Value); } }
public sunUndeclaredVariableException(sunIdentifier node)
: base(node)
{
: base(node) {
}
}
class sunRedeclaredVariableException : sunNodeException<sunIdentifier>
{
class sunRedeclaredVariableException : sunNodeException<sunIdentifier> {
public override string Message { get { return String.Format("Redeclared variable '{0}'.", Node.Value); } }
public sunRedeclaredVariableException(sunIdentifier node)
: base(node)
{
: base(node) {
}
}
class sunAssignConstantException : sunNodeException<sunIdentifier>
{
class sunAssignConstantException : sunNodeException<sunIdentifier> {
public override string Message { get { return String.Format("Constant '{0}' is read-only.", Node.Value); } }
public sunAssignConstantException(sunIdentifier node)
: base(node)
{
: base(node) {
}
}
class sunRedeclaredParameterException : sunNodeException<sunIdentifier>
{
class sunRedeclaredParameterException : sunNodeException<sunIdentifier> {
public override string Message { get { return String.Format("Redeclared parameter '{0}'.", Node.Value); } }
public sunRedeclaredParameterException(sunIdentifier node)
: base(node)
{
: base(node) {
}
}
class sunVariadicFunctionException : sunNodeException<sunFunctionDefinition>
{
class sunVariadicFunctionException : sunNodeException<sunFunctionDefinition> {
public override string Message { get { return String.Format("Function '{0}' is defined as a variadic function (only builtins may be variadic).", Node.Function.Value); } }
public sunVariadicFunctionException(sunFunctionDefinition node)
: base(node)
{
: base(node) {
}
}
class sunEscapeSequenceException : sunNodeException<sunStringLiteral>
{
class sunEscapeSequenceException : sunNodeException<sunStringLiteral> {
public override string Message { get { return String.Format("Bad escape sequence in string."); } }
public sunEscapeSequenceException(sunStringLiteral node)
: base(node)
{
: base(node) {
}
}
class sunVariadicParameterListException : sunNodeException<sunParameterList>
{
class sunVariadicParameterListException : sunNodeException<sunParameterList> {
public override string Message { get { return String.Format("Bad variadic parameter list."); } }
public sunVariadicParameterListException(sunParameterList node)
: base(node)
{
: base(node) {
}
}
class sunArgumentCountException : sunNodeException<sunFunctionCall>
{
class sunArgumentCountException : sunNodeException<sunFunctionCall> {
public sunCallableSymbol CalledSymbol { get; private set; }
public int ArgumentMinimum { get { return CalledSymbol.Parameters.Minimum; } }
public int ArgumentCount { get { return Node.Arguments.Count; } }
public override string Message
{
get
{
public override string Message {
get {
string format;
if (CalledSymbol.Parameters.IsVariadic)
{
if (CalledSymbol.Parameters.IsVariadic) {
// assuming to be missing because there's only a minimum
format = "Missing {0} argument(s) (expected at least {1}; got {2}).";
}
else if (Node.Arguments.Count < CalledSymbol.Parameters.Minimum)
{
else if (Node.Arguments.Count < CalledSymbol.Parameters.Minimum) {
format = "Missing {0} argument(s) (expected {1}; got {2})."; // missing arguments
}
else
{
else {
format = "Too many arguments (expected {1}; got {2})."; // extra arguments
}
return String.Format(format, ArgumentMinimum - ArgumentCount, ArgumentMinimum, ArgumentCount);
@ -238,52 +191,42 @@ namespace arookas
}
public sunArgumentCountException(sunFunctionCall node, sunCallableSymbol calledSymbol)
: base(node)
{
if (calledSymbol == null)
{
: base(node) {
if (calledSymbol == null) {
throw new ArgumentNullException("calledSymbol");
}
CalledSymbol = calledSymbol;
}
}
class sunIdentifierException : sunNodeException<sunIdentifier>
{
class sunIdentifierException : sunNodeException<sunIdentifier> {
public override string Message { get { return String.Format("Invalid identifier '{0}'.", Node.Value); } }
public sunIdentifierException(sunIdentifier node)
: base(node)
{
: base(node) {
}
}
class sunMissingImportException : sunNodeException<sunImport>
{
class sunMissingImportException : sunNodeException<sunImport> {
public override string Message { get { return String.Format("Could not find import file '{0}'.", Node.ImportFile.Value); } }
public sunMissingImportException(sunImport node)
: base(node)
{
: base(node) {
}
}
class sunBreakException : sunNodeException<sunBreak>
{
class sunBreakException : sunNodeException<sunBreak> {
public override string Message { get { return "Break statements must be placed within a loop statement."; } }
public sunBreakException(sunBreak node)
: base(node)
{
: base(node) {
}
}
class sunContinueException : sunNodeException<sunContinue>
{
class sunContinueException : sunNodeException<sunContinue> {
public override string Message { get { return "Continue statements must be placed within a loop statement."; } }
public sunContinueException(sunContinue node)
: base(node)
{
: base(node) {
}
}

View file

@ -3,10 +3,8 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace arookas
{
public abstract class sunImportResolver
{
namespace arookas {
public abstract class sunImportResolver {
static sunImportResolver defaultResolver = new sunDefaultImportResolver();
public static sunImportResolver Default { get { return defaultResolver; } }
@ -15,60 +13,49 @@ namespace arookas
public abstract sunImportResult ResolveImport(string name, out sunScriptFile file);
// default implementation
sealed class sunDefaultImportResolver : sunImportResolver
{
sealed class sunDefaultImportResolver : sunImportResolver {
List<sunScriptFile> imports = new List<sunScriptFile>(10);
Stack<sunScriptFile> current = new Stack<sunScriptFile>(5);
string rootDirectory, currentDirectory;
string CurrentDirectory { get { return current.Count > 0 ? Path.GetDirectoryName(current.Peek().Name) : currentDirectory; } }
public sunDefaultImportResolver()
{
public sunDefaultImportResolver() {
rootDirectory = AppDomain.CurrentDomain.BaseDirectory;
currentDirectory = Directory.GetCurrentDirectory();
}
public override void EnterFile(sunScriptFile file) { current.Push(file); }
public override void ExitFile(sunScriptFile file) { current.Pop(); }
public override sunImportResult ResolveImport(string name, out sunScriptFile file)
{
public override sunImportResult ResolveImport(string name, out sunScriptFile file) {
file = null;
string fullPath;
if (Path.IsPathRooted(name))
{
if (Path.IsPathRooted(name)) {
// if the path is absolute, just use it directly
fullPath = name;
if (!File.Exists(fullPath))
{
if (!File.Exists(fullPath)) {
return sunImportResult.Missing;
}
}
else
{
else {
// check if the file exists relative to the current one;
// if it's not there, check the root directory
fullPath = Path.Combine(CurrentDirectory, name);
if (!File.Exists(fullPath))
{
if (!File.Exists(fullPath)) {
fullPath = Path.Combine(rootDirectory, name);
if (!File.Exists(fullPath))
{
if (!File.Exists(fullPath)) {
return sunImportResult.Missing;
}
}
}
// make sure the file has not been imported yet
if (imports.Any(i => i.Name == fullPath))
{
if (imports.Any(i => i.Name == fullPath)) {
return sunImportResult.Skipped;
}
// open the file
try
{
try {
file = new sunScriptFile(name, File.OpenRead(fullPath));
}
catch
{
catch {
return sunImportResult.FailedToLoad;
}
imports.Add(file);
@ -77,44 +64,36 @@ namespace arookas
}
}
public enum sunImportResult
{
public enum sunImportResult {
Loaded,
Skipped,
Missing,
FailedToLoad,
}
public class sunScriptFile : IDisposable
{
public class sunScriptFile : IDisposable {
public string Name { get; private set; }
public Stream Stream { get; private set; }
public sunScriptFile(string name, Stream stream)
{
if (name == null)
{
public sunScriptFile(string name, Stream stream) {
if (name == null) {
throw new ArgumentNullException("name");
}
if (stream == null)
{
if (stream == null) {
throw new ArgumentNullException("stream");
}
if (!stream.CanRead)
{
if (!stream.CanRead) {
throw new ArgumentException("Stream does not support reading.", "stream");
}
Name = name;
Stream = stream;
}
public void Dispose()
{
public void Dispose() {
Stream.Dispose();
}
public TextReader GetReader()
{
public TextReader GetReader() {
return new StreamReader(Stream);
}
}

View file

@ -1,10 +1,8 @@
using System.Collections.Generic;
using System.Linq;
namespace arookas
{
class sunLoopStack
{
namespace arookas {
class sunLoopStack {
Stack<sunLoop> loops = new Stack<sunLoop>(5);
sunLoop Top { get { return loops.Peek(); } }
@ -13,14 +11,11 @@ namespace arookas
public void Push() { Push(null); }
public void Push(string name) { loops.Push(new sunLoop(name)); }
public void Pop(sunContext context, sunPoint breakPoint, sunPoint continuePoint)
{
foreach (var _break in Top.Breaks)
{
public void Pop(sunContext context, sunPoint breakPoint, sunPoint continuePoint) {
foreach (var _break in Top.Breaks) {
context.Text.ClosePoint(_break, breakPoint.Offset);
}
foreach (var _continue in Top.Continues)
{
foreach (var _continue in Top.Continues) {
context.Text.ClosePoint(_continue, continuePoint.Offset);
}
loops.Pop();
@ -30,48 +25,39 @@ namespace arookas
public bool AddBreak(sunPoint point) { return AddBreak(point, null); }
public bool AddContinue(sunPoint point) { return AddContinue(point, null); }
public bool AddBreak(sunPoint point, string name)
{
if (Count < 1)
{
public bool AddBreak(sunPoint point, string name) {
if (Count < 1) {
return false;
}
var loop = name == null ? Top : this[name];
if (loop == null)
{
if (loop == null) {
return false;
}
loop.Breaks.Add(point);
return true;
}
public bool AddContinue(sunPoint point, string name)
{
if (Count < 1)
{
public bool AddContinue(sunPoint point, string name) {
if (Count < 1) {
return false;
}
var loop = name == null ? Top : this[name];
if (loop == null)
{
if (loop == null) {
return false;
}
loop.Continues.Add(point);
return true;
}
class sunLoop
{
class sunLoop {
public string Name { get; private set; }
public List<sunPoint> Breaks { get; private set; }
public List<sunPoint> Continues { get; private set; }
public sunLoop()
: this(null)
{
: this(null) {
}
public sunLoop(string name)
{
public sunLoop(string name) {
Name = name;
Breaks = new List<sunPoint>(5);
Continues = new List<sunPoint>(5);

View file

@ -1,12 +1,9 @@
using PerCederberg.Grammatica.Runtime;
using System.Linq;
namespace arookas
{
class sunParser
{
static string[] keywords =
{
namespace arookas {
class sunParser {
static string[] keywords = {
"import",
"builtin", "function", "var", "const",
"if", "while", "do", "for",
@ -15,48 +12,37 @@ namespace arookas
"true", "false",
};
public sunNode Parse(sunScriptFile file)
{
using (var input = file.GetReader())
{
try
{
public sunNode Parse(sunScriptFile file) {
using (var input = file.GetReader()) {
try {
var parser = new __sunParser(input);
var node = parser.Parse();
return CreateAst(file.Name, node);
}
catch (ParserLogException ex)
{
catch (ParserLogException ex) {
throw new sunParserException(file.Name, ex[0]);
}
}
}
static sunNode CreateAst(string file, Node node)
{
static sunNode CreateAst(string file, Node node) {
var ast = ConvertNode(file, node);
if (ast == null)
{
if (ast == null) {
return null;
}
// children
if (node is Production)
{
if (node is Production) {
var production = node as Production;
for (int i = 0; i < production.Count; ++i)
{
for (int i = 0; i < production.Count; ++i) {
var child = CreateAst(file, production[i]);
if (child != null)
{
if (child != null) {
ast.Add(child);
}
}
}
// transcience
if (ast.Count == 1)
{
switch (GetId(node))
{
if (ast.Count == 1) {
switch (GetId(node)) {
case __sunConstants.ROOT_STATEMENT:
case __sunConstants.STATEMENT:
case __sunConstants.COMPOUND_STATEMENT:
@ -69,26 +55,22 @@ namespace arookas
case __sunConstants.TERM:
case __sunConstants.PARAMETER:
case __sunConstants.ARGUMENT_LIST:
case __sunConstants.ARGUMENT:
{
return ast[0];
}
case __sunConstants.ARGUMENT: {
return ast[0];
}
}
}
return ast;
}
static sunNode ConvertNode(string file, Node node)
{
static sunNode ConvertNode(string file, Node node) {
var location = new sunSourceLocation(file, node.StartLine, node.StartColumn);
string token = null;
if (node is Token)
{
if (node is Token) {
token = (node as Token).Image;
}
// statements
switch (GetId(node))
{
switch (GetId(node)) {
case __sunConstants.SCRIPT: return new sunNode(location);
case __sunConstants.ROOT_STATEMENT: return new sunNode(location);
case __sunConstants.STATEMENT: return new sunNode(location);
@ -108,8 +90,7 @@ namespace arookas
}
// literals
switch (GetId(node))
{
switch (GetId(node)) {
case __sunConstants.INT_NUMBER: return new sunIntLiteral(location, token);
case __sunConstants.HEX_NUMBER: return new sunHexLiteral(location, token);
case __sunConstants.DEC_NUMBER: return new sunFloatLiteral(location, token);
@ -121,17 +102,14 @@ namespace arookas
}
// operators
switch (GetId(node))
{
switch (GetId(node)) {
case __sunConstants.ADD: return new sunAdd(location);
case __sunConstants.SUB:
{
if (GetId(node.Parent) == __sunConstants.UNARY_OPERATOR)
{
return new sunNeg(location);
case __sunConstants.SUB: {
if (GetId(node.Parent) == __sunConstants.UNARY_OPERATOR) {
return new sunNeg(location);
}
return new sunSub(location);
}
return new sunSub(location);
}
case __sunConstants.MUL: return new sunMul(location);
case __sunConstants.DIV: return new sunDiv(location);
case __sunConstants.MOD: return new sunMod(location);
@ -175,12 +153,11 @@ namespace arookas
}
// expressions
switch (GetId(node))
{
switch (GetId(node)) {
case __sunConstants.EXPRESSION: return new sunExpression(location);
case __sunConstants.OPERAND: return new sunOperand(location);
case __sunConstants.TERM: return new sunNode(location);
case __sunConstants.UNARY_OPERATOR_LIST: return new sunUnaryOperatorList(location);
case __sunConstants.INT_CAST: return new sunIntCast(location);
@ -192,14 +169,12 @@ namespace arookas
}
// builtins
switch (GetId(node))
{
switch (GetId(node)) {
case __sunConstants.BUILTIN_DECLARATION: return new sunBuiltinDeclaration(location);
}
// functions
switch (GetId(node))
{
switch (GetId(node)) {
case __sunConstants.FUNCTION_DEFINITION: return new sunFunctionDefinition(location);
case __sunConstants.FUNCTION_CALL: return new sunFunctionCall(location);
@ -210,8 +185,7 @@ namespace arookas
}
// variables
switch (GetId(node))
{
switch (GetId(node)) {
case __sunConstants.VARIABLE_REFERENCE: return new sunStorableReference(location);
case __sunConstants.VARIABLE_DECLARATION: return new sunVariableDeclaration(location);
case __sunConstants.VARIABLE_DEFINITION: return new sunVariableDefinition(location);
@ -220,14 +194,12 @@ namespace arookas
}
// constants
switch (GetId(node))
{
switch (GetId(node)) {
case __sunConstants.CONST_DEFINITION: return new sunConstantDefinition(location);
}
// flow control
switch (GetId(node))
{
switch (GetId(node)) {
case __sunConstants.IF_STATEMENT: return new sunIf(location);
case __sunConstants.WHILE_STATEMENT: return new sunWhile(location);
case __sunConstants.DO_STATEMENT: return new sunDo(location);
@ -242,8 +214,7 @@ namespace arookas
}
// cleanup keywords punctuation
switch (GetId(node))
{
switch (GetId(node)) {
// keywords
case __sunConstants.IMPORT:
case __sunConstants.BUILTIN:
@ -286,22 +257,19 @@ namespace arookas
case __sunConstants.COMMA:
case __sunConstants.DOT:
// case __sunConstants.ELLIPSIS: // do not exclude ellipsis for variadic parameters
case __sunConstants.QMARK:
{
return null;
}
case __sunConstants.QMARK: {
return null;
}
}
// emergency fallback
return null;
}
static __sunConstants GetId(Node node)
{
static __sunConstants GetId(Node node) {
return (__sunConstants)node.Id;
}
public static bool IsKeyword(string name)
{
public static bool IsKeyword(string name) {
return keywords.Contains(name);
}
}

View file

@ -2,10 +2,8 @@
using System.Collections.Generic;
using System.Linq;
namespace arookas
{
class sunScopeStack : IEnumerable<sunScope>
{
namespace arookas {
class sunScopeStack : IEnumerable<sunScope> {
List<sunScope> Stack { get; set; }
public int Count { get { return Stack.Count; } }
@ -24,25 +22,20 @@ namespace arookas
public sunScope this[int index] { get { return Stack[index]; } }
public sunScopeStack()
{
public sunScopeStack() {
Stack = new List<sunScope>(8);
Push(sunScopeType.Script); // push global scope
}
public void Push(sunScopeType type)
{
public void Push(sunScopeType type) {
Stack.Add(new sunScope(type));
}
public void Pop()
{
if (Count > 1)
{
public void Pop() {
if (Count > 1) {
Stack.RemoveAt(Count - 1);
}
}
public void Clear()
{
public void Clear() {
Stack.Clear();
Push(sunScopeType.Script); // add global scope
}
@ -52,36 +45,29 @@ namespace arookas
public void ResetLocalCount() { LocalCount = 0; }
#endif
public sunVariableSymbol DeclareVariable(string name)
{
switch (Top.Type)
{
public sunVariableSymbol DeclareVariable(string name) {
switch (Top.Type) {
case sunScopeType.Script: return DeclareGlobal(name);
case sunScopeType.Function: return DeclareLocal(name);
}
return null;
}
public sunConstantSymbol DeclareConstant(string name, sunExpression expression)
{
public sunConstantSymbol DeclareConstant(string name, sunExpression expression) {
return Top.DeclareConstant(name, expression);
}
sunVariableSymbol DeclareGlobal(string name)
{
sunVariableSymbol DeclareGlobal(string name) {
var symbol = Top.DeclareVariable(name, 0, GlobalCount);
#if !SSC_PACK_VARS
if (symbol != null)
{
if (symbol != null) {
++GlobalCount;
}
#endif
return symbol;
}
sunVariableSymbol DeclareLocal(string name)
{
sunVariableSymbol DeclareLocal(string name) {
var symbol = Top.DeclareVariable(name, 1, LocalCount);
#if !SSC_PACK_VARS
if (symbol != null)
{
if (symbol != null) {
++LocalCount;
}
#endif
@ -92,15 +78,13 @@ namespace arookas
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
}
class sunScope
{
class sunScope {
List<sunStorableSymbol> Storables { get; set; }
IEnumerable<sunVariableSymbol> Variables { get { return Storables.OfType<sunVariableSymbol>(); } }
IEnumerable<sunConstantSymbol> Constants { get { return Storables.OfType<sunConstantSymbol>(); } }
public sunScopeType Type { get; private set; }
public sunScope(sunScopeType type)
{
public sunScope(sunScopeType type) {
Storables = new List<sunStorableSymbol>(10);
Type = type;
}
@ -111,20 +95,16 @@ namespace arookas
public bool GetIsDeclared(string name) { return Storables.Any(v => v.Name == name); }
public sunVariableSymbol DeclareVariable(string name, int display, int index)
{
if (GetIsDeclared(name))
{
public sunVariableSymbol DeclareVariable(string name, int display, int index) {
if (GetIsDeclared(name)) {
return null;
}
var symbol = new sunVariableSymbol(name, display, index);
Storables.Add(symbol);
return symbol;
}
public sunConstantSymbol DeclareConstant(string name, sunExpression expression)
{
if (GetIsDeclared(name))
{
public sunConstantSymbol DeclareConstant(string name, sunExpression expression) {
if (GetIsDeclared(name)) {
return null;
}
var symbol = new sunConstantSymbol(name, expression);
@ -137,8 +117,7 @@ namespace arookas
public sunConstantSymbol ResolveConstant(string name) { return Constants.FirstOrDefault(i => i.Name == name); }
}
enum sunScopeType
{
enum sunScopeType {
Script, // outside of a function
Function, // inside of a function
}

View file

@ -5,10 +5,8 @@ using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace arookas
{
class sunSymbolTable : IEnumerable<sunSymbol>
{
namespace arookas {
class sunSymbolTable : IEnumerable<sunSymbol> {
List<sunSymbol> Symbols { get; set; }
public int Count { get { return Symbols.Count; } }
@ -26,19 +24,16 @@ namespace arookas
public IEnumerable<sunVariableSymbol> Variables { get { return Symbols.OfType<sunVariableSymbol>(); } }
public IEnumerable<sunConstantSymbol> Constants { get { return Symbols.OfType<sunConstantSymbol>(); } }
public sunSymbolTable()
{
public sunSymbolTable() {
Symbols = new List<sunSymbol>(10);
}
public void Add(sunSymbol symbol) { Symbols.Add(symbol); }
public void Clear() { Symbols.Clear(); }
public void Write(aBinaryWriter writer)
{
public void Write(aBinaryWriter writer) {
int ofs = 0;
foreach (var sym in this)
{
foreach (var sym in this) {
writer.WriteS32((int)sym.Type);
writer.WriteS32(ofs);
writer.Write32(sym.Data);
@ -49,8 +44,7 @@ namespace arookas
ofs += writer.Encoding.GetByteCount(sym.Name) + 1; // include null terminator
}
foreach (var sym in this)
{
foreach (var sym in this) {
writer.WriteString(sym.Name, aBinaryStringFormat.NullTerminated);
}
}
@ -59,32 +53,28 @@ namespace arookas
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
}
abstract class sunSymbol
{
abstract class sunSymbol {
public string Name { get; private set; }
// symbol table
public abstract sunSymbolType Type { get; }
public abstract uint Data { get; }
protected sunSymbol(string name)
{
protected sunSymbol(string name) {
Name = name;
}
public abstract void Compile(sunContext context);
}
abstract class sunCallableSymbol : sunSymbol
{
abstract class sunCallableSymbol : sunSymbol {
public sunParameterInfo Parameters { get; private set; }
protected List<sunPoint> CallSites { get; private set; }
public bool HasCallSites { get { return CallSites.Count > 0; } }
protected sunCallableSymbol(string name, sunParameterInfo parameterInfo)
: base(name)
{
: base(name) {
Parameters = parameterInfo;
CallSites = new List<sunPoint>(10);
}
@ -93,8 +83,7 @@ namespace arookas
public abstract void CloseCallSites(sunContext context);
}
class sunBuiltinSymbol : sunCallableSymbol
{
class sunBuiltinSymbol : sunCallableSymbol {
public int Index { get; private set; }
// symbol table
@ -102,27 +91,20 @@ namespace arookas
public override uint Data { get { return (uint)Index; } }
public sunBuiltinSymbol(string name, sunParameterInfo parameters, int index)
: base(name, parameters)
{
: base(name, parameters) {
Index = index;
}
public override void Compile(sunContext context)
{
public override void Compile(sunContext context) {
throw new InvalidOperationException("Cannot compile builtins.");
}
public override void OpenCallSite(sunContext context, int argumentCount)
{
public override void OpenCallSite(sunContext context, int argumentCount) {
context.Text.CallBuiltin(Index, argumentCount);
}
public override void CloseCallSites(sunContext context)
{
// do nothing
}
public override void CloseCallSites(sunContext context) { }
}
class sunFunctionSymbol : sunCallableSymbol
{
class sunFunctionSymbol : sunCallableSymbol {
sunNode Body { get; set; }
public uint Offset { get; private set; }
@ -131,18 +113,15 @@ namespace arookas
public override uint Data { get { return (uint)Offset; } }
public sunFunctionSymbol(string name, sunParameterInfo parameters, sunNode body)
: base(name, parameters)
{
: base(name, parameters) {
Body = body;
}
public override void Compile(sunContext context)
{
public override void Compile(sunContext context) {
Offset = context.Text.Offset;
context.Scopes.Push(sunScopeType.Function);
context.Scopes.ResetLocalCount();
foreach (var parameter in Parameters)
{
foreach (var parameter in Parameters) {
context.Scopes.DeclareVariable(parameter); // since there is no AST node for these, they won't affect MaxLocalCount
}
context.Text.StoreDisplay(1);
@ -151,46 +130,38 @@ namespace arookas
context.Text.ReturnVoid();
context.Scopes.Pop();
}
public override void OpenCallSite(sunContext context, int argumentCount)
{
public override void OpenCallSite(sunContext context, int argumentCount) {
var point = context.Text.CallFunction(argumentCount);
CallSites.Add(point);
}
public override void CloseCallSites(sunContext context)
{
foreach (var callSite in CallSites)
{
public override void CloseCallSites(sunContext context) {
foreach (var callSite in CallSites) {
context.Text.ClosePoint(callSite, Offset);
}
}
}
class sunParameterInfo : IEnumerable<string>
{
class sunParameterInfo : IEnumerable<string> {
string[] Parameters { get; set; }
public int Minimum { get { return Parameters.Length; } }
public bool IsVariadic { get; private set; }
public sunParameterInfo(IEnumerable<sunIdentifier> parameters, bool variadic)
{
public sunParameterInfo(IEnumerable<sunIdentifier> parameters, bool variadic) {
// validate parameter names
var duplicate = parameters.FirstOrDefault(a => parameters.Count(b => a.Value == b.Value) > 1);
if (duplicate != null)
{
if (duplicate != null) {
throw new sunRedeclaredParameterException(duplicate);
}
Parameters = parameters.Select(i => i.Value).ToArray();
IsVariadic = variadic;
}
public sunParameterInfo(IEnumerable<string> parameters, bool variadic)
{
public sunParameterInfo(IEnumerable<string> parameters, bool variadic) {
// validate parameter names
Parameters = parameters.ToArray();
IsVariadic = variadic;
}
public bool ValidateArgumentCount(int count)
{
public bool ValidateArgumentCount(int count) {
return IsVariadic ? count >= Minimum : count == Minimum;
}
@ -198,36 +169,26 @@ namespace arookas
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
}
abstract class sunStorableSymbol : sunSymbol
{
abstract class sunStorableSymbol : sunSymbol {
protected sunStorableSymbol(string name)
: base(name)
{
: base(name) { }
}
public override void Compile(sunContext context)
{
CompileGet(context); // compile get by default
}
public override void Compile(sunContext context) { CompileGet(context); } // compile get by default
public abstract void CompileGet(sunContext context);
public abstract void CompileSet(sunContext context);
public virtual void CompileInc(sunContext context)
{
public virtual void CompileInc(sunContext context) {
CompileGet(context);
context.Text.PushInt(1);
context.Text.Add();
}
public virtual void CompileDec(sunContext context)
{
public virtual void CompileDec(sunContext context) {
CompileGet(context);
context.Text.PushInt(1);
context.Text.Sub();
}
}
class sunVariableSymbol : sunStorableSymbol
{
class sunVariableSymbol : sunStorableSymbol {
public int Display { get; private set; }
public int Index { get; private set; }
@ -236,32 +197,18 @@ namespace arookas
public override uint Data { get { return (uint)Index; } }
public sunVariableSymbol(string name, int display, int index)
: base(name)
{
: base(name) {
Display = display;
Index = index;
}
public override void CompileGet(sunContext context)
{
context.Text.PushVariable(Display, Index);
}
public override void CompileSet(sunContext context)
{
context.Text.StoreVariable(Display, Index);
}
public override void CompileInc(sunContext context)
{
context.Text.IncVariable(Display, Index);
}
public override void CompileDec(sunContext context)
{
context.Text.DecVariable(Display, Index);
}
public override void CompileGet(sunContext context) { context.Text.PushVariable(Display, Index); }
public override void CompileSet(sunContext context) { context.Text.StoreVariable(Display, Index); }
public override void CompileInc(sunContext context) { context.Text.IncVariable(Display, Index); }
public override void CompileDec(sunContext context) { context.Text.DecVariable(Display, Index); }
}
class sunConstantSymbol : sunStorableSymbol
{
class sunConstantSymbol : sunStorableSymbol {
sunExpression Expression { get; set; }
// symbol table
@ -269,28 +216,23 @@ namespace arookas
public override uint Data { get { return 0; } }
public sunConstantSymbol(string name, sunExpression expression)
: base(name)
{
if (expression == null)
{
: base(name) {
if (expression == null) {
throw new ArgumentNullException("expression");
}
Expression = expression;
}
public override void CompileGet(sunContext context)
{
public override void CompileGet(sunContext context) {
Expression.Compile(context);
}
public override void CompileSet(sunContext context)
{
public override void CompileSet(sunContext context) {
// checks against this have to be implemented at a higher level
throw new InvalidOperationException();
}
}
enum sunSymbolType
{
enum sunSymbolType {
Builtin,
Function,
Variable,

View file

@ -1,88 +1,59 @@
using arookas.IO.Binary;
namespace arookas
{
class sunWriter
{
namespace arookas {
class sunWriter {
aBinaryWriter writer;
public uint Offset { get { return (uint)writer.Position; } }
public sunWriter(aBinaryWriter writer)
{
public sunWriter(aBinaryWriter writer) {
this.writer = writer;
}
public sunPoint OpenPoint() { return new sunPoint(Offset); }
public void ClosePoint(sunPoint point)
{
ClosePoint(point, (uint)writer.Position);
}
public void ClosePoint(sunPoint point, uint offset)
{
public void ClosePoint(sunPoint point) { ClosePoint(point, (uint)writer.Position); }
public void ClosePoint(sunPoint point, uint offset) {
writer.Keep();
writer.Goto(point.Offset);
writer.Write32(offset);
writer.Back();
}
public void PushInt(int value)
{
switch (value) // shortcut commands
{
public void PushInt(int value) {
switch (value) { // shortcut commands
case 0: writer.Write8(0x25); return;
case 1: writer.Write8(0x26); return;
}
writer.Write8(0x00);
writer.WriteS32(value);
}
public void PushFloat(float value)
{
public void PushFloat(float value) {
writer.Write8(0x01);
writer.WriteF32(value);
}
public void PushData(int dataIndex)
{
public void PushData(int dataIndex) {
writer.Write8(0x02);
writer.WriteS32(dataIndex);
}
public void PushAddress(int value)
{
public void PushAddress(int value) {
writer.Write8(0x03);
writer.WriteS32(value);
}
public void PushVariable(sunVariableSymbol variableInfo)
{
PushVariable(variableInfo.Display, variableInfo.Index);
}
public void PushVariable(int display, int variableIndex)
{
public void PushVariable(sunVariableSymbol variableInfo) { PushVariable(variableInfo.Display, variableInfo.Index); }
public void PushVariable(int display, int variableIndex) {
writer.Write8(0x04);
writer.WriteS32(display);
writer.WriteS32(variableIndex);
}
public void Nop()
{
writer.Write8(0x05);
}
public void IncVariable(sunVariableSymbol variableInfo)
{
IncVariable(variableInfo.Display, variableInfo.Index);
}
public void DecVariable(sunVariableSymbol variableInfo)
{
DecVariable(variableInfo.Display, variableInfo.Index);
}
public void IncVariable(int display, int variableIndex)
{
public void Nop() { writer.Write8(0x05); }
public void IncVariable(sunVariableSymbol variableInfo) { IncVariable(variableInfo.Display, variableInfo.Index); }
public void DecVariable(sunVariableSymbol variableInfo) { DecVariable(variableInfo.Display, variableInfo.Index); }
public void IncVariable(int display, int variableIndex) {
writer.Write8(0x06);
writer.WriteS32(display);
writer.WriteS32(variableIndex);
}
public void DecVariable(int display, int variableIndex)
{
public void DecVariable(int display, int variableIndex) {
writer.Write8(0x07);
writer.WriteS32(display);
writer.WriteS32(variableIndex);
@ -94,12 +65,8 @@ namespace arookas
public void Div() { writer.Write8(0x0B); }
public void Mod() { writer.Write8(0x0C); }
public void StoreVariable(sunVariableSymbol variableInfo)
{
StoreVariable(variableInfo.Display, variableInfo.Index);
}
public void StoreVariable(int display, int variableIndex)
{
public void StoreVariable(sunVariableSymbol variableInfo) { StoreVariable(variableInfo.Display, variableInfo.Index); }
public void StoreVariable(int display, int variableIndex) {
writer.Write8(0x0D);
writer.Write8(0x04); // unused (skipped over by TSpcInterp)
writer.WriteS32(display);
@ -121,34 +88,29 @@ namespace arookas
public void ShL() { writer.Write8(0x1A); }
public void ShR() { writer.Write8(0x1B); }
public sunPoint CallFunction(int argumentCount)
{
public sunPoint CallFunction(int argumentCount) {
writer.Write8(0x1C);
sunPoint point = OpenPoint();
writer.Write32(0); // dummy
writer.WriteS32(argumentCount);
return point;
}
public void CallFunction(sunPoint point, int argumentCount)
{
public void CallFunction(sunPoint point, int argumentCount) {
writer.Write8(0x1C);
writer.Write32(point.Offset);
writer.WriteS32(argumentCount);
}
public void CallBuiltin(int symbolIndex, int argumentCount)
{
public void CallBuiltin(int symbolIndex, int argumentCount) {
writer.Write8(0x1D);
writer.WriteS32(symbolIndex);
writer.WriteS32(argumentCount);
}
public void DeclareLocal(int count)
{
public void DeclareLocal(int count) {
writer.Write8(0x1E);
writer.WriteS32(count);
}
public void StoreDisplay(int display)
{
public void StoreDisplay(int display) {
writer.Write8(0x1F);
writer.WriteS32(display);
}
@ -156,27 +118,23 @@ namespace arookas
public void ReturnValue() { writer.Write8(0x20); }
public void ReturnVoid() { writer.Write8(0x21); }
public sunPoint GotoIfZero()
{
public sunPoint GotoIfZero() {
writer.Write8(0x22);
sunPoint point = OpenPoint();
writer.Write32(0); // dummy
return point;
}
public sunPoint Goto()
{
public sunPoint Goto() {
writer.Write8(0x23);
sunPoint point = OpenPoint();
writer.Write32(0); // dummy
return point;
}
public void GotoIfZero(sunPoint point)
{
public void GotoIfZero(sunPoint point) {
writer.Write8(0x22);
writer.Write32(point.Offset);
}
public void Goto(sunPoint point)
{
public void Goto(sunPoint point) {
writer.Write8(0x23);
writer.Write32(point.Offset);
}
@ -185,13 +143,11 @@ namespace arookas
public void Terminate() { writer.Write8(0x27); }
}
struct sunPoint
{
struct sunPoint {
readonly uint offset;
public uint Offset { get { return offset; } }
public sunPoint(uint offset)
{
public sunPoint(uint offset) {
this.offset = offset;
}
}