Added code so far.
This commit is contained in:
parent
12301380a2
commit
4f1e820006
22 changed files with 3397 additions and 0 deletions
16
AssemblyInfo.cs
Normal file
16
AssemblyInfo.cs
Normal file
|
@ -0,0 +1,16 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
[assembly: AssemblyTitle("ssc")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("ssc")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2015 arookas")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
[assembly: Guid("5413c8e1-aefa-43bc-9fe5-c95f221da8c5")]
|
||||
[assembly: AssemblyVersion("0.1.0.0")]
|
||||
[assembly: AssemblyFileVersion("0.1.0.0")]
|
127
ast/nodes.cs
Normal file
127
ast/nodes.cs
Normal file
|
@ -0,0 +1,127 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace arookas
|
||||
{
|
||||
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)
|
||||
{
|
||||
File = file;
|
||||
Line = line;
|
||||
Column = column;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Format("\"{0}\", ({1},{2})", File, Line, Column);
|
||||
}
|
||||
}
|
||||
|
||||
class sunNode : IEnumerable<sunNode>
|
||||
{
|
||||
List<sunNode> children;
|
||||
|
||||
public sunNode Parent { get; private set; }
|
||||
public sunSourceLocation Location { get; private set; }
|
||||
|
||||
public int Count { get { return children.Count; } }
|
||||
public sunNode this[int index] { get { return index >= 0 && index < Count ? children[index] : null; } }
|
||||
|
||||
public bool IsRoot { get { return Parent == null; } }
|
||||
public bool IsBranch { get { return Count > 0; } }
|
||||
public bool IsLeaf { get { return Count < 1; } }
|
||||
|
||||
public sunNode(sunSourceLocation location)
|
||||
{
|
||||
children = new List<sunNode>(5);
|
||||
Location = location;
|
||||
}
|
||||
|
||||
public void Add(sunNode node)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
throw new ArgumentNullException("node");
|
||||
}
|
||||
if (node.Parent != null)
|
||||
{
|
||||
node.Parent.Remove(node);
|
||||
}
|
||||
node.Parent = this;
|
||||
children.Add(node);
|
||||
}
|
||||
public void Remove(sunNode node)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
throw new ArgumentNullException("node");
|
||||
}
|
||||
if (node.Parent == this)
|
||||
{
|
||||
children.Remove(node);
|
||||
node.Parent = null;
|
||||
}
|
||||
}
|
||||
public void Clear()
|
||||
{
|
||||
foreach (var child in this)
|
||||
{
|
||||
child.Parent = null;
|
||||
}
|
||||
children.Clear();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
child.Compile(context);
|
||||
}
|
||||
}
|
||||
protected bool TryCompile(sunNode node, sunContext context)
|
||||
{
|
||||
if (node != null)
|
||||
{
|
||||
node.Compile(context);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public IEnumerator<sunNode> GetEnumerator() { return children.GetEnumerator(); }
|
||||
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
|
||||
}
|
||||
|
||||
abstract class sunToken<TValue> : sunNode
|
||||
{
|
||||
public TValue Value { get; private set; }
|
||||
|
||||
protected sunToken(sunSourceLocation location, string token)
|
||||
: base(location)
|
||||
{
|
||||
Value = ParseValue(token);
|
||||
}
|
||||
|
||||
protected abstract TValue ParseValue(string token);
|
||||
}
|
||||
|
||||
abstract class sunRawToken : sunToken<string>
|
||||
{
|
||||
protected sunRawToken(sunSourceLocation location, string token)
|
||||
: base(location, token)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override string ParseValue(string token) { return token; }
|
||||
}
|
||||
}
|
122
ast/nodes.expressions.cs
Normal file
122
ast/nodes.expressions.cs
Normal file
|
@ -0,0 +1,122 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace arookas
|
||||
{
|
||||
class sunExpression : sunNode
|
||||
{
|
||||
public sunExpression(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
var operand = node as sunOperand;
|
||||
|
||||
// term
|
||||
var term = operand.Term;
|
||||
if (term is sunExpression)
|
||||
{
|
||||
AnalyzeExpression(context, term as sunExpression, operatorStack);
|
||||
}
|
||||
else
|
||||
{
|
||||
term.Compile(context);
|
||||
}
|
||||
var unaryOperators = operand.UnaryOperators;
|
||||
if (unaryOperators != null)
|
||||
{
|
||||
unaryOperators.Compile(context);
|
||||
}
|
||||
}
|
||||
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(context);
|
||||
}
|
||||
operatorStack.Push(operatorNode);
|
||||
}
|
||||
}
|
||||
while (operatorStack.Count > stackCount)
|
||||
{
|
||||
operatorStack.Pop().Compile(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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(sunContext context)
|
||||
{
|
||||
foreach (var child in this.Reverse())
|
||||
{
|
||||
// compile unary operators in reverse order
|
||||
child.Compile(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 node)
|
||||
: base(node)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context)
|
||||
{
|
||||
Condition.Compile(context);
|
||||
var falsePrologue = context.Text.GotoIfZero();
|
||||
TrueBody.Compile(context);
|
||||
var trueEpilogue = context.Text.Goto();
|
||||
context.Text.ClosePoint(falsePrologue);
|
||||
FalseBody.Compile(context);
|
||||
context.Text.ClosePoint(trueEpilogue);
|
||||
}
|
||||
}
|
||||
}
|
224
ast/nodes.flow.cs
Normal file
224
ast/nodes.flow.cs
Normal file
|
@ -0,0 +1,224 @@
|
|||
using PerCederberg.Grammatica.Runtime;
|
||||
using System.Linq;
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context)
|
||||
{
|
||||
Condition.Compile(context);
|
||||
var trueBodyEpilogue = context.Text.GotoIfZero();
|
||||
TrueBody.Compile(context);
|
||||
var falseBody = FalseBody;
|
||||
if (falseBody != null)
|
||||
{
|
||||
var falseBodyEpilogue = context.Text.Goto();
|
||||
context.Text.ClosePoint(trueBodyEpilogue);
|
||||
falseBody.Compile(context);
|
||||
context.Text.ClosePoint(falseBodyEpilogue);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Text.ClosePoint(trueBodyEpilogue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class sunWhile : sunLoop
|
||||
{
|
||||
public sunExpression Condition { get { return this[Count - 2] as sunExpression; } }
|
||||
public sunNode Body { get { return this[Count - 1]; } }
|
||||
|
||||
public sunWhile(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context)
|
||||
{
|
||||
context.Loops.Push(IsNamed ? NameLabel.Label.Value : null);
|
||||
var bodyPrologue = context.Text.OpenPoint();
|
||||
var continuePoint = context.Text.OpenPoint();
|
||||
Condition.Compile(context);
|
||||
var bodyEpilogue = context.Text.GotoIfZero();
|
||||
Body.Compile(context);
|
||||
context.Text.Goto(bodyPrologue);
|
||||
context.Text.ClosePoint(bodyEpilogue);
|
||||
var breakPoint = context.Text.OpenPoint();
|
||||
context.Loops.Pop(context, breakPoint, continuePoint);
|
||||
}
|
||||
}
|
||||
|
||||
class sunDo : sunLoop
|
||||
{
|
||||
public sunNode Body { get { return this[Count - 2]; } }
|
||||
public sunExpression Condition { get { return this[Count - 1] as sunExpression; } }
|
||||
|
||||
public sunDo(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context)
|
||||
{
|
||||
context.Loops.Push(IsNamed ? NameLabel.Label.Value : null);
|
||||
var bodyPrologue = context.Text.OpenPoint();
|
||||
Body.Compile(context);
|
||||
var continuePoint = context.Text.OpenPoint();
|
||||
Condition.Compile(context);
|
||||
var bodyEpilogue = context.Text.GotoIfZero();
|
||||
context.Text.Goto(bodyPrologue);
|
||||
context.Text.ClosePoint(bodyEpilogue);
|
||||
var breakPoint = context.Text.OpenPoint();
|
||||
context.Loops.Pop(context, breakPoint, continuePoint);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context)
|
||||
{
|
||||
context.Scopes.Push();
|
||||
context.Loops.Push(IsNamed ? NameLabel.Label.Value : null);
|
||||
TryCompile(Declaration, context);
|
||||
var bodyPrologue = context.Text.OpenPoint();
|
||||
TryCompile(Condition, context);
|
||||
var bodyEpilogue = context.Text.GotoIfZero();
|
||||
Body.Compile(context);
|
||||
var continuePoint = context.Text.OpenPoint();
|
||||
TryCompile(Iteration, context);
|
||||
context.Text.Goto(bodyPrologue);
|
||||
context.Text.ClosePoint(bodyEpilogue);
|
||||
var breakPoint = context.Text.OpenPoint();
|
||||
context.Loops.Pop(context, breakPoint, continuePoint);
|
||||
context.Scopes.Pop();
|
||||
}
|
||||
}
|
||||
class sunForDeclaration : sunNode
|
||||
{
|
||||
public sunForDeclaration(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
class sunForCondition : sunNode
|
||||
{
|
||||
public sunForCondition(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
class sunForIteration : sunNode
|
||||
{
|
||||
public sunForIteration(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class sunReturn : sunNode
|
||||
{
|
||||
public sunExpression Expression { get { return this[0] as sunExpression; } }
|
||||
|
||||
public sunReturn(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context)
|
||||
{
|
||||
var expression = Expression;
|
||||
if (expression != null)
|
||||
{
|
||||
expression.Compile(context);
|
||||
context.Text.ReturnValue();
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Text.ReturnVoid();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context)
|
||||
{
|
||||
var point = context.Text.Goto();
|
||||
if (!context.Loops.AddBreak(point, IsNamed ? NameLabel.Value : null))
|
||||
{
|
||||
throw new sunBreakException(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context)
|
||||
{
|
||||
var point = context.Text.Goto();
|
||||
if (!context.Loops.AddContinue(point, IsNamed ? NameLabel.Value : null))
|
||||
{
|
||||
throw new sunContinueException(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
95
ast/nodes.functions.cs
Normal file
95
ast/nodes.functions.cs
Normal file
|
@ -0,0 +1,95 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context)
|
||||
{
|
||||
context.DeclareBuiltin(this);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context)
|
||||
{
|
||||
var callableInfo = context.ResolveCallable(this);
|
||||
if (!callableInfo.Parameters.ValidateArgumentCount(Arguments.Count))
|
||||
{
|
||||
throw new sunArgumentCountException(this, callableInfo);
|
||||
}
|
||||
Arguments.Compile(context);
|
||||
callableInfo.OpenCallSite(context, Arguments.Count);
|
||||
if (IsStatement)
|
||||
{
|
||||
context.Text.Pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
int count = this.Count(i => i is sunEllipsis);
|
||||
if (count > 1 || (count > 0 && !(this[Count - 1] is sunEllipsis)))
|
||||
{
|
||||
throw new sunVariadicParameterListException(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class sunEllipsis : sunNode
|
||||
{
|
||||
public sunEllipsis(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
201
ast/nodes.literals.cs
Normal file
201
ast/nodes.literals.cs
Normal file
|
@ -0,0 +1,201 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
namespace arookas
|
||||
{
|
||||
class sunIntLiteral : sunToken<int> // base-10 integer
|
||||
{
|
||||
public sunIntLiteral(sunSourceLocation location, string token)
|
||||
: base(location, token)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override int ParseValue(string token) { return Int32.Parse(token); }
|
||||
|
||||
public override void Compile(sunContext context)
|
||||
{
|
||||
context.Text.PushInt(Value);
|
||||
}
|
||||
}
|
||||
|
||||
class sunHexLiteral : sunIntLiteral // base-16 integer
|
||||
{
|
||||
public sunHexLiteral(sunSourceLocation location, string token)
|
||||
: base(location, token)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override int ParseValue(string token)
|
||||
{
|
||||
// because .NET's hex parsing is gay and doesn't support
|
||||
// leading signs, manually detect negative literals
|
||||
var neg = (token[0] == '-');
|
||||
var trim = neg ? 3 : 2;
|
||||
var digits = token.Substring(trim); // trim the '0x' prefix before parsing
|
||||
var value = Int32.Parse(token.Substring(2), NumberStyles.AllowHexSpecifier);
|
||||
if (neg)
|
||||
{
|
||||
value = -value;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
class sunFloatLiteral : sunToken<float>
|
||||
{
|
||||
public sunFloatLiteral(sunSourceLocation location, string token)
|
||||
: base(location, token)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override float ParseValue(string image) { return Single.Parse(image); }
|
||||
|
||||
public override void Compile(sunContext context)
|
||||
{
|
||||
context.Text.PushFloat(Value);
|
||||
}
|
||||
}
|
||||
|
||||
class sunStringLiteral : sunToken<string>
|
||||
{
|
||||
public sunStringLiteral(sunSourceLocation location, string token)
|
||||
: base(location, token)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override string ParseValue(string image) { return UnescapeString(image.Substring(1, image.Length - 2)); } // remove enclosing quotes
|
||||
|
||||
public override void Compile(sunContext context)
|
||||
{
|
||||
context.Text.PushData(context.DataTable.Add(Value));
|
||||
}
|
||||
|
||||
// string unescaping utility
|
||||
string UnescapeString(string value)
|
||||
{
|
||||
// based on Hans Passant's code
|
||||
StringBuilder sb = new StringBuilder(value.Length);
|
||||
for (int i = 0; i < value.Length;)
|
||||
{
|
||||
int j = value.IndexOf('\\', i);
|
||||
if (j < 0 || j >= value.Length - 1)
|
||||
{
|
||||
j = value.Length;
|
||||
}
|
||||
sb.Append(value, i, j - i);
|
||||
if (j >= value.Length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
switch (value[j + 1])
|
||||
{
|
||||
case '\'': sb.Append('\''); break;
|
||||
case '"': sb.Append('"'); break;
|
||||
case '\\': sb.Append('\\'); break;
|
||||
case '0': sb.Append('\0'); break;
|
||||
case 'a': sb.Append('\a'); break;
|
||||
case 'b': sb.Append('\b'); break;
|
||||
case 'f': sb.Append('\f'); break;
|
||||
case 'n': sb.Append('n'); break;
|
||||
case 't': sb.Append('\t'); break;
|
||||
case 'v': sb.Append('\v'); break;
|
||||
case 'x': sb.Append(UnescapeHex(value, j + 2, out i)); continue;
|
||||
case 'u': sb.Append(UnescapeUnicodeCodeUnit(value, j + 2, out i)); continue;
|
||||
case 'U': sb.Append(UnescapeUnicodeSurrogatePair(value, j + 2, out i)); continue;
|
||||
default: throw new sunEscapeSequenceException(this);
|
||||
}
|
||||
i = j + 2;
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
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]))
|
||||
{
|
||||
sb.Append(value[start]);
|
||||
++digits;
|
||||
++start;
|
||||
}
|
||||
end = start;
|
||||
return (char)Int32.Parse(sb.ToString(), NumberStyles.AllowHexSpecifier);
|
||||
}
|
||||
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)
|
||||
{
|
||||
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))
|
||||
{
|
||||
throw new sunEscapeSequenceException(this); // characters are not a surrogate pair
|
||||
}
|
||||
end = start + 8;
|
||||
return String.Concat(high, low);
|
||||
}
|
||||
static bool IsHexDigit(char c)
|
||||
{
|
||||
return (c >= '0' && c <= '9') ||
|
||||
(c >= 'A' && c <= 'F') ||
|
||||
(c >= 'a' && c <= 'f');
|
||||
}
|
||||
}
|
||||
|
||||
class sunIdentifier : sunRawToken
|
||||
{
|
||||
public sunIdentifier(sunSourceLocation location, string token)
|
||||
: base(location, token)
|
||||
{
|
||||
// make sure it is a valid identifier name (i.e. not a keyword)
|
||||
if (sunParser.IsKeyword(Value))
|
||||
{
|
||||
throw new sunIdentifierException(this);
|
||||
}
|
||||
}
|
||||
|
||||
// identifiers are compiled on a per-context basis (i.e. at a higher level)
|
||||
}
|
||||
|
||||
class sunTrue : sunIntLiteral
|
||||
{
|
||||
public sunTrue(sunSourceLocation location, string token)
|
||||
: base(location, token)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override int ParseValue(string token) { return 1; }
|
||||
}
|
||||
|
||||
class sunFalse : sunIntLiteral
|
||||
{
|
||||
public sunFalse(sunSourceLocation location, string token)
|
||||
: base(location, token)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override int ParseValue(string token) { return 0; }
|
||||
}
|
||||
}
|
453
ast/nodes.operators.cs
Normal file
453
ast/nodes.operators.cs
Normal file
|
@ -0,0 +1,453 @@
|
|||
using PerCederberg.Grammatica.Runtime;
|
||||
|
||||
namespace arookas
|
||||
{
|
||||
enum Associativity
|
||||
{
|
||||
Left,
|
||||
Right,
|
||||
}
|
||||
|
||||
abstract class sunOperator : sunNode
|
||||
{
|
||||
public virtual Associativity Associativity { get { return Associativity.Left; } }
|
||||
public abstract int Precedence { get; }
|
||||
|
||||
public bool IsLeftAssociative { get { return Associativity == Associativity.Left; } }
|
||||
public bool IsRightAssociative { get { return Associativity == Associativity.Right; } }
|
||||
|
||||
protected sunOperator(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// precedence 0
|
||||
class sunLogOR : sunOperator
|
||||
{
|
||||
public override int Precedence { get { return 0; } }
|
||||
|
||||
public sunLogOR(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context) { context.Text.LogOR(); }
|
||||
}
|
||||
|
||||
// precedence 1
|
||||
class sunLogAND : sunOperator
|
||||
{
|
||||
public override int Precedence { get { return 1; } }
|
||||
|
||||
public sunLogAND(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context) { context.Text.LogAND(); }
|
||||
}
|
||||
|
||||
// precedence 2
|
||||
class sunBitOR : sunOperator
|
||||
{
|
||||
public override int Precedence { get { return 2; } }
|
||||
|
||||
public sunBitOR(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context) { context.Text.BitOR(); }
|
||||
}
|
||||
|
||||
// precedence 3
|
||||
class sunBitAND : sunOperator
|
||||
{
|
||||
public override int Precedence { get { return 3; } }
|
||||
|
||||
public sunBitAND(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context) { context.Text.BitAND(); }
|
||||
}
|
||||
|
||||
// precedence 4
|
||||
class sunEq : sunOperator
|
||||
{
|
||||
public override int Precedence { get { return 4; } }
|
||||
|
||||
public sunEq(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context) { context.Text.Eq(); }
|
||||
}
|
||||
|
||||
class sunNtEq : sunOperator
|
||||
{
|
||||
public override int Precedence { get { return 4; } }
|
||||
|
||||
public sunNtEq(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context) { context.Text.NtEq(); }
|
||||
}
|
||||
|
||||
// precedence 5
|
||||
class sunLt : sunOperator
|
||||
{
|
||||
public override int Precedence { get { return 5; } }
|
||||
|
||||
public sunLt(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context) { context.Text.Lt(); }
|
||||
}
|
||||
|
||||
class sunLtEq : sunOperator
|
||||
{
|
||||
public override int Precedence { get { return 5; } }
|
||||
|
||||
public sunLtEq(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context) { context.Text.LtEq(); }
|
||||
}
|
||||
|
||||
class sunGt : sunOperator
|
||||
{
|
||||
public override int Precedence { get { return 5; } }
|
||||
|
||||
public sunGt(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context) { context.Text.Gt(); }
|
||||
}
|
||||
|
||||
class sunGtEq : sunOperator
|
||||
{
|
||||
public override int Precedence { get { return 5; } }
|
||||
|
||||
public sunGtEq(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context) { context.Text.GtEq(); }
|
||||
}
|
||||
|
||||
// precedence 6
|
||||
class sunBitLsh : sunOperator
|
||||
{
|
||||
public override int Precedence { get { return 6; } }
|
||||
|
||||
public sunBitLsh(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context) { context.Text.ShL(); }
|
||||
}
|
||||
|
||||
class sunBitRsh : sunOperator
|
||||
{
|
||||
public override int Precedence { get { return 6; } }
|
||||
|
||||
public sunBitRsh(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context) { context.Text.ShR(); }
|
||||
}
|
||||
|
||||
// precedence 7
|
||||
class sunAdd : sunOperator
|
||||
{
|
||||
public override int Precedence { get { return 7; } }
|
||||
|
||||
public sunAdd(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context) { context.Text.Add(); }
|
||||
}
|
||||
|
||||
class sunSub : sunOperator
|
||||
{
|
||||
public override int Precedence { get { return 7; } }
|
||||
|
||||
public sunSub(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context) { context.Text.Sub(); }
|
||||
}
|
||||
|
||||
// precedence 8
|
||||
class sunMul : sunOperator
|
||||
{
|
||||
public override int Precedence { get { return 8; } }
|
||||
|
||||
public sunMul(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context) { context.Text.Mul(); }
|
||||
}
|
||||
|
||||
class sunDiv : sunOperator
|
||||
{
|
||||
public override int Precedence { get { return 8; } }
|
||||
|
||||
public sunDiv(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context) { context.Text.Div(); }
|
||||
}
|
||||
|
||||
class sunMod : sunOperator
|
||||
{
|
||||
public override int Precedence { get { return 8; } }
|
||||
|
||||
public sunMod(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context) { context.Text.Mod(); }
|
||||
}
|
||||
|
||||
// precedence 9
|
||||
class sunLogNOT : sunOperator
|
||||
{
|
||||
public override int Precedence { get { return 9; } }
|
||||
|
||||
public sunLogNOT(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context) { context.Text.LogNOT(); }
|
||||
}
|
||||
class sunNeg : sunOperator
|
||||
{
|
||||
public override int Precedence { get { return 9; } }
|
||||
|
||||
public sunNeg(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context) { context.Text.Neg(); }
|
||||
}
|
||||
|
||||
// assignment operators
|
||||
class sunAssign : sunOperator
|
||||
{
|
||||
public override Associativity Associativity { get { return Associativity.Right; } }
|
||||
public override int Precedence { get { return -1; } }
|
||||
|
||||
public sunAssign(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public virtual void Compile(sunContext context, sunVariableInfo variableInfo, sunExpression expression)
|
||||
{
|
||||
expression.Compile(context);
|
||||
context.Text.StoreVariable(variableInfo);
|
||||
}
|
||||
}
|
||||
|
||||
class sunAssignAdd : sunAssign
|
||||
{
|
||||
public sunAssignAdd(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context, sunVariableInfo variableInfo, sunExpression expression)
|
||||
{
|
||||
context.Text.PushVariable(variableInfo);
|
||||
expression.Compile(context);
|
||||
context.Text.Add();
|
||||
context.Text.StoreVariable(variableInfo);
|
||||
}
|
||||
}
|
||||
|
||||
class sunAssignSub : sunAssign
|
||||
{
|
||||
public sunAssignSub(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context, sunVariableInfo variableInfo, sunExpression expression)
|
||||
{
|
||||
context.Text.PushVariable(variableInfo);
|
||||
expression.Compile(context);
|
||||
context.Text.Sub();
|
||||
context.Text.StoreVariable(variableInfo);
|
||||
}
|
||||
}
|
||||
|
||||
class sunAssignMul : sunAssign
|
||||
{
|
||||
public sunAssignMul(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context, sunVariableInfo variableInfo, sunExpression expression)
|
||||
{
|
||||
context.Text.PushVariable(variableInfo);
|
||||
expression.Compile(context);
|
||||
context.Text.Mul();
|
||||
context.Text.StoreVariable(variableInfo);
|
||||
}
|
||||
}
|
||||
|
||||
class sunAssignDiv : sunAssign
|
||||
{
|
||||
public sunAssignDiv(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context, sunVariableInfo variableInfo, sunExpression expression)
|
||||
{
|
||||
context.Text.PushVariable(variableInfo);
|
||||
expression.Compile(context);
|
||||
context.Text.Div();
|
||||
context.Text.StoreVariable(variableInfo);
|
||||
}
|
||||
}
|
||||
|
||||
class sunAssignMod : sunAssign
|
||||
{
|
||||
public sunAssignMod(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context, sunVariableInfo variableInfo, sunExpression expression)
|
||||
{
|
||||
context.Text.PushVariable(variableInfo);
|
||||
expression.Compile(context);
|
||||
context.Text.Mod();
|
||||
context.Text.StoreVariable(variableInfo);
|
||||
}
|
||||
}
|
||||
|
||||
class sunAssignBitAND : sunAssign
|
||||
{
|
||||
public sunAssignBitAND(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context, sunVariableInfo variableInfo, sunExpression expression)
|
||||
{
|
||||
context.Text.PushVariable(variableInfo);
|
||||
expression.Compile(context);
|
||||
context.Text.BitAND();
|
||||
context.Text.StoreVariable(variableInfo);
|
||||
}
|
||||
}
|
||||
|
||||
class sunAssignBitOR : sunAssign
|
||||
{
|
||||
public sunAssignBitOR(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context, sunVariableInfo variableInfo, sunExpression expression)
|
||||
{
|
||||
context.Text.PushVariable(variableInfo);
|
||||
expression.Compile(context);
|
||||
context.Text.BitOR();
|
||||
context.Text.StoreVariable(variableInfo);
|
||||
}
|
||||
}
|
||||
|
||||
class sunAssignBitLsh : sunAssign
|
||||
{
|
||||
public sunAssignBitLsh(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context, sunVariableInfo variableInfo, sunExpression expression)
|
||||
{
|
||||
context.Text.PushVariable(variableInfo);
|
||||
expression.Compile(context);
|
||||
context.Text.ShL();
|
||||
context.Text.StoreVariable(variableInfo);
|
||||
}
|
||||
}
|
||||
|
||||
class sunAssignBitRsh : sunAssign
|
||||
{
|
||||
public sunAssignBitRsh(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context, sunVariableInfo variableInfo, sunExpression expression)
|
||||
{
|
||||
context.Text.PushVariable(variableInfo);
|
||||
expression.Compile(context);
|
||||
context.Text.ShR();
|
||||
context.Text.StoreVariable(variableInfo);
|
||||
}
|
||||
}
|
||||
}
|
50
ast/nodes.statements.cs
Normal file
50
ast/nodes.statements.cs
Normal file
|
@ -0,0 +1,50 @@
|
|||
namespace arookas
|
||||
{
|
||||
class sunStatementBlock : sunNode
|
||||
{
|
||||
public sunStatementBlock(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context)
|
||||
{
|
||||
context.Scopes.Push();
|
||||
base.Compile(context);
|
||||
context.Scopes.Pop();
|
||||
}
|
||||
}
|
||||
|
||||
class sunImport : sunNode
|
||||
{
|
||||
public sunStringLiteral ImportFile { get { return this[0] as sunStringLiteral; } }
|
||||
|
||||
public sunImport(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context)
|
||||
{
|
||||
var file = context.Imports.ResolveImport(this);
|
||||
if (file == null)
|
||||
{
|
||||
return; // the file has already been imported
|
||||
}
|
||||
context.Compile(file);
|
||||
}
|
||||
}
|
||||
|
||||
class sunNameLabel : sunNode
|
||||
{
|
||||
public sunIdentifier Label { get { return this[0] as sunIdentifier; } }
|
||||
|
||||
public sunNameLabel(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
155
ast/nodes.system.cs
Normal file
155
ast/nodes.system.cs
Normal file
|
@ -0,0 +1,155 @@
|
|||
namespace arookas
|
||||
{
|
||||
class sunYield : sunNode
|
||||
{
|
||||
public sunYield(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context)
|
||||
{
|
||||
var builtinInfo = context.ResolveSystemBuiltin("yield");
|
||||
context.Text.CallBuiltin(builtinInfo.Index, 0);
|
||||
context.Text.Pop();
|
||||
}
|
||||
}
|
||||
|
||||
class sunExit : sunNode
|
||||
{
|
||||
public sunExit(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context)
|
||||
{
|
||||
var builtinInfo = context.ResolveSystemBuiltin("exit");
|
||||
context.Text.CallBuiltin(builtinInfo.Index, 0);
|
||||
context.Text.Pop();
|
||||
}
|
||||
}
|
||||
|
||||
class sunDump : sunNode
|
||||
{
|
||||
public sunDump(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context)
|
||||
{
|
||||
var builtinInfo = context.ResolveSystemBuiltin("dump");
|
||||
context.Text.CallBuiltin(builtinInfo.Index, 0);
|
||||
context.Text.Pop();
|
||||
}
|
||||
}
|
||||
|
||||
class sunLock : sunNode
|
||||
{
|
||||
public sunLock(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context)
|
||||
{
|
||||
var builtinInfo = context.ResolveSystemBuiltin("lock");
|
||||
context.Text.CallBuiltin(builtinInfo.Index, 0);
|
||||
context.Text.Pop();
|
||||
}
|
||||
}
|
||||
|
||||
class sunUnlock : sunNode
|
||||
{
|
||||
public sunUnlock(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context)
|
||||
{
|
||||
var builtinInfo = context.ResolveSystemBuiltin("unlock");
|
||||
context.Text.CallBuiltin(builtinInfo.Index, 0);
|
||||
context.Text.Pop();
|
||||
}
|
||||
}
|
||||
|
||||
class sunIntCast : sunNode
|
||||
{
|
||||
public sunExpression Argument { get { return this[0] as sunExpression; } }
|
||||
|
||||
public sunIntCast(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context)
|
||||
{
|
||||
var builtinInfo = context.DeclareSystemBuiltin("int", false, "x");
|
||||
Argument.Compile(context);
|
||||
context.Text.CallBuiltin(builtinInfo.Index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
class sunFloatCast : sunNode
|
||||
{
|
||||
public sunExpression Argument { get { return this[0] as sunExpression; } }
|
||||
|
||||
public sunFloatCast(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context)
|
||||
{
|
||||
var builtinInfo = context.ResolveSystemBuiltin("float");
|
||||
Argument.Compile(context);
|
||||
context.Text.CallBuiltin(builtinInfo.Index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
class sunTypeofCast : sunNode
|
||||
{
|
||||
public sunExpression Argument { get { return this[0] as sunExpression; } }
|
||||
|
||||
public sunTypeofCast(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context)
|
||||
{
|
||||
var builtinInfo = context.ResolveSystemBuiltin("typeof");
|
||||
Argument.Compile(context);
|
||||
context.Text.CallBuiltin(builtinInfo.Index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
class sunPrint : sunNode
|
||||
{
|
||||
public sunNode ArgumentList { get { return this[0]; } }
|
||||
|
||||
public sunPrint(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context)
|
||||
{
|
||||
var builtinInfo = context.ResolveSystemBuiltin("print");
|
||||
ArgumentList.Compile(context);
|
||||
context.Text.CallBuiltin(builtinInfo.Index, ArgumentList.Count);
|
||||
context.Text.Pop();
|
||||
}
|
||||
}
|
||||
}
|
96
ast/nodes.variables.cs
Normal file
96
ast/nodes.variables.cs
Normal file
|
@ -0,0 +1,96 @@
|
|||
namespace arookas
|
||||
{
|
||||
class sunVariableReference : sunNode
|
||||
{
|
||||
public sunIdentifier Variable { get { return this[0] as sunIdentifier; } }
|
||||
|
||||
public sunVariableReference(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context)
|
||||
{
|
||||
sunVariableInfo variableInfo;
|
||||
sunConstInfo constInfo;
|
||||
context.ResolveVariableOrConstant(Variable, out variableInfo, out constInfo);
|
||||
if (variableInfo != null)
|
||||
{
|
||||
context.Text.PushVariable(variableInfo);
|
||||
}
|
||||
if (constInfo != null)
|
||||
{
|
||||
constInfo.Expression.Compile(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class sunVariableDeclaration : sunNode
|
||||
{
|
||||
public sunIdentifier Variable { get { return this[0] as sunIdentifier; } }
|
||||
|
||||
public sunVariableDeclaration(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context)
|
||||
{
|
||||
var variableInfo = context.DeclareVariable(Variable);
|
||||
context.Text.DeclareLocal(1);
|
||||
}
|
||||
}
|
||||
|
||||
class sunVariableDefinition : sunVariableAssignment
|
||||
{
|
||||
public sunVariableDefinition(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context)
|
||||
{
|
||||
var variableInfo = context.DeclareVariable(Variable);
|
||||
context.Text.DeclareLocal(1);
|
||||
base.Compile(context);
|
||||
}
|
||||
}
|
||||
|
||||
class sunVariableAssignment : sunVariableDeclaration
|
||||
{
|
||||
public sunAssign Operator { get { return this[1] as sunAssign; } }
|
||||
public sunExpression Expression { get { return this[2] as sunExpression; } }
|
||||
|
||||
public sunVariableAssignment(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context)
|
||||
{
|
||||
var variableInfo = context.ResolveVariable(Variable);
|
||||
Operator.Compile(context, variableInfo, Expression);
|
||||
}
|
||||
}
|
||||
|
||||
class sunConstDefinition : sunNode
|
||||
{
|
||||
public sunIdentifier Constant { get { return this[0] as sunIdentifier; } }
|
||||
public sunExpression Expression { get { return this[2] as sunExpression; } }
|
||||
|
||||
public sunConstDefinition(sunSourceLocation location)
|
||||
: base(location)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context)
|
||||
{
|
||||
var constInfo = context.DeclareConstant(Constant, Expression);
|
||||
}
|
||||
}
|
||||
}
|
81
compiler.cs
Normal file
81
compiler.cs
Normal file
|
@ -0,0 +1,81 @@
|
|||
using PerCederberg.Grammatica.Runtime;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
||||
namespace arookas
|
||||
{
|
||||
public class sunCompiler
|
||||
{
|
||||
Stack<string> files;
|
||||
string defaultRootDir, rootDir;
|
||||
public string RootDir
|
||||
{
|
||||
get { return rootDir ?? defaultRootDir; }
|
||||
set { rootDir = value; }
|
||||
}
|
||||
|
||||
public sunCompiler()
|
||||
{
|
||||
defaultRootDir = AppDomain.CurrentDomain.BaseDirectory;
|
||||
}
|
||||
|
||||
public sunCompilerResults Compile(string file, Stream output)
|
||||
{
|
||||
var results = new sunCompilerResults();
|
||||
var timer = Stopwatch.StartNew();
|
||||
try
|
||||
{
|
||||
files = new Stack<string>(5);
|
||||
sunContext context = new sunContext(output, RootDir);
|
||||
context.EnterFile += EnterFile;
|
||||
context.ExitFile += ExitFile;
|
||||
context.Compile(file);
|
||||
context.Text.Terminate(); // NOTETOSELF: don't do this in sunScript because imported files will add this as well
|
||||
foreach (var function in context.SymbolTable.Functions)
|
||||
{
|
||||
function.Compile(context);
|
||||
}
|
||||
foreach (var function in context.SymbolTable.Functions)
|
||||
{
|
||||
function.CloseCallSites(context);
|
||||
}
|
||||
results.SymbolCount = context.SymbolTable.Count;
|
||||
results.BuiltinCount = context.SymbolTable.BuiltinCount;
|
||||
results.FunctionCount = context.SymbolTable.FunctionCount;
|
||||
results.VariableCount = context.SymbolTable.VariableCount;
|
||||
context.Dispose();
|
||||
}
|
||||
catch (sunCompilerException ex)
|
||||
{
|
||||
results.Error = ex;
|
||||
}
|
||||
catch (ParserLogException ex)
|
||||
{
|
||||
results.Error = new sunParserException(files.Peek(), ex[0]);
|
||||
}
|
||||
timer.Stop();
|
||||
results.CompileTime = timer.Elapsed;
|
||||
return results;
|
||||
}
|
||||
|
||||
void EnterFile(object sender, sunFileArgs e) { files.Push(e.File); }
|
||||
void ExitFile(object sender, sunFileArgs e) { files.Pop(); }
|
||||
}
|
||||
|
||||
public class sunCompilerResults
|
||||
{
|
||||
// success
|
||||
public bool Success { get { return Error == null; } }
|
||||
public sunCompilerException Error { get; internal set; }
|
||||
|
||||
// statistics
|
||||
public int SymbolCount { get; internal set; }
|
||||
public int BuiltinCount { get; internal set; }
|
||||
public int FunctionCount { get; internal set; }
|
||||
public int VariableCount { get; internal set; }
|
||||
|
||||
public TimeSpan CompileTime { get; internal set; }
|
||||
}
|
||||
}
|
250
context.cs
Normal file
250
context.cs
Normal file
|
@ -0,0 +1,250 @@
|
|||
using arookas.IO.Binary;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace arookas
|
||||
{
|
||||
class sunContext : aDisposable
|
||||
{
|
||||
aBinaryWriter writer;
|
||||
uint textOffset, dataOffset, symbolOffset;
|
||||
|
||||
public sunWriter Text { get; private set; }
|
||||
public sunDataTable DataTable { get; private set; }
|
||||
public sunSymbolTable SymbolTable { get; private set; }
|
||||
public sunScopeStack Scopes { get; private set; }
|
||||
public sunLoopStack Loops { get; private set; }
|
||||
public sunImportTable Imports { get; private set; }
|
||||
|
||||
public event EventHandler<sunFileArgs> EnterFile;
|
||||
public event EventHandler<sunFileArgs> ExitFile;
|
||||
|
||||
// open/close
|
||||
public sunContext(Stream stream, string rootDir)
|
||||
{
|
||||
DataTable = new sunDataTable();
|
||||
SymbolTable = new sunSymbolTable();
|
||||
Scopes = new sunScopeStack();
|
||||
Loops = new sunLoopStack();
|
||||
Imports = new sunImportTable(rootDir);
|
||||
|
||||
writer = new aBinaryWriter(stream, Endianness.Big, Encoding.GetEncoding(932));
|
||||
Text = new sunWriter(writer);
|
||||
writer.PushAnchor();
|
||||
|
||||
WriteHeader(); // dummy header
|
||||
|
||||
// begin text block
|
||||
textOffset = (uint)writer.Position;
|
||||
writer.PushAnchor(); // match code offsets and writer offsets
|
||||
|
||||
// add system builtins
|
||||
DeclareSystemBuiltin("yield", false);
|
||||
DeclareSystemBuiltin("exit", false);
|
||||
DeclareSystemBuiltin("dump", false);
|
||||
DeclareSystemBuiltin("lock", false);
|
||||
DeclareSystemBuiltin("unlock", false);
|
||||
DeclareSystemBuiltin("int", false, "x");
|
||||
DeclareSystemBuiltin("float", false, "x");
|
||||
DeclareSystemBuiltin("typeof", false, "x");
|
||||
DeclareSystemBuiltin("print", true);
|
||||
}
|
||||
protected override bool Dispose(bool destructor)
|
||||
{
|
||||
if (!destructor)
|
||||
{
|
||||
writer.PopAnchor();
|
||||
dataOffset = (uint)writer.Position;
|
||||
DataTable.Write(writer);
|
||||
symbolOffset = (uint)writer.Position;
|
||||
SymbolTable.Write(writer);
|
||||
writer.Goto(0);
|
||||
WriteHeader();
|
||||
return true; // don't dispose the writer so the stream doesn't get disposed
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// imports
|
||||
public void Compile(string file)
|
||||
{
|
||||
Imports.PushDir(file);
|
||||
OnEnterFile(new sunFileArgs(file));
|
||||
var parser = new sunParser();
|
||||
var tree = parser.Parse(file);
|
||||
tree.Compile(this);
|
||||
OnExitFile(new sunFileArgs(file));
|
||||
Imports.PopDir();
|
||||
}
|
||||
|
||||
// builtins
|
||||
public sunBuiltinInfo DeclareBuiltin(sunBuiltinDeclaration node)
|
||||
{
|
||||
var symbolInfo = SymbolTable.Callables.FirstOrDefault(f => f.Name == node.Builtin.Value);
|
||||
if (symbolInfo != null)
|
||||
{
|
||||
throw new sunRedeclaredBuiltinException(node);
|
||||
}
|
||||
var builtinInfo = new sunBuiltinInfo(node.Builtin.Value, node.Parameters.ParameterInfo, SymbolTable.Count);
|
||||
SymbolTable.Add(builtinInfo);
|
||||
return builtinInfo;
|
||||
}
|
||||
public sunBuiltinInfo DeclareSystemBuiltin(string name, bool variadic, params string[] parameters)
|
||||
{
|
||||
var builtinInfo = SymbolTable.Builtins.FirstOrDefault(f => f.Name == name);
|
||||
if (builtinInfo == null)
|
||||
{
|
||||
builtinInfo = new sunBuiltinInfo(name, new sunParameterInfo(parameters, variadic), SymbolTable.Count);
|
||||
SymbolTable.Add(builtinInfo);
|
||||
}
|
||||
return builtinInfo;
|
||||
}
|
||||
public sunBuiltinInfo ResolveSystemBuiltin(string name)
|
||||
{
|
||||
return SymbolTable.Builtins.FirstOrDefault(f => f.Name == name);
|
||||
}
|
||||
|
||||
// functions
|
||||
public sunFunctionInfo DefineFunction(sunFunctionDefinition node)
|
||||
{
|
||||
if (node.Parameters.IsVariadic)
|
||||
{
|
||||
throw new sunVariadicFunctionException(node);
|
||||
}
|
||||
var symbolInfo = SymbolTable.Callables.FirstOrDefault(f => f.Name == node.Function.Value);
|
||||
if (symbolInfo != null)
|
||||
{
|
||||
throw new sunRedefinedFunctionException(node);
|
||||
}
|
||||
var functionInfo = new sunFunctionInfo(node.Function.Value, node.Parameters.ParameterInfo, node.Body);
|
||||
SymbolTable.Add(functionInfo);
|
||||
return functionInfo;
|
||||
}
|
||||
public sunCallableSymbolInfo ResolveCallable(sunFunctionCall node)
|
||||
{
|
||||
var symbolInfo = SymbolTable.Callables.FirstOrDefault(f => f.Name == node.Function.Value);
|
||||
if (symbolInfo == null)
|
||||
{
|
||||
throw new sunUndefinedFunctionException(node);
|
||||
}
|
||||
return symbolInfo;
|
||||
}
|
||||
|
||||
// variables
|
||||
public sunVariableInfo DeclareVariable(sunIdentifier node)
|
||||
{
|
||||
// assert variable is not already declared in current scope
|
||||
if (Scopes.Top.GetIsVariableDeclared(node.Value))
|
||||
{
|
||||
throw new sunRedeclaredVariableException(node);
|
||||
}
|
||||
var variableInfo = Scopes.Top.DeclareVariable(node.Value, Scopes.Count > 1 ? 1 : 0);
|
||||
if (Scopes.IsRoot)
|
||||
{
|
||||
// global-scope variables are added to the symbol table
|
||||
SymbolTable.Add(variableInfo);
|
||||
}
|
||||
return variableInfo;
|
||||
}
|
||||
public sunVariableInfo ResolveVariable(sunIdentifier node)
|
||||
{
|
||||
// walk the stack backwards to resolve to the variable's latest declaration
|
||||
for (int i = Scopes.Count - 1; i >= 0; --i)
|
||||
{
|
||||
var variableInfo = Scopes[i].ResolveVariable(node.Value);
|
||||
if (variableInfo != null)
|
||||
{
|
||||
return variableInfo;
|
||||
}
|
||||
}
|
||||
throw new sunUndeclaredVariableException(node);
|
||||
}
|
||||
|
||||
public sunVariableInfo DeclareParameter(string name) { return Scopes.Top.DeclareVariable(name, 1); }
|
||||
|
||||
// constants
|
||||
public sunConstInfo DeclareConstant(sunIdentifier node, sunExpression expression)
|
||||
{
|
||||
if (Scopes.Top.GetIsConstantDeclared(node.Value))
|
||||
{
|
||||
throw new sunRedeclaredVariableException(node);
|
||||
}
|
||||
var constInfo = Scopes.Top.DeclareConstant(node.Value, expression);
|
||||
return constInfo;
|
||||
}
|
||||
public sunConstInfo ResolveConstant(sunIdentifier node)
|
||||
{
|
||||
// walk the stack backwards to resolve to the variable's latest declaration
|
||||
for (int i = Scopes.Count - 1; i >= 0; --i)
|
||||
{
|
||||
var constInfo = Scopes[i].ResolveConstant(node.Value);
|
||||
if (constInfo != null)
|
||||
{
|
||||
return constInfo;
|
||||
}
|
||||
}
|
||||
throw new sunUndeclaredVariableException(node);
|
||||
}
|
||||
|
||||
public void ResolveVariableOrConstant(sunIdentifier node, out sunVariableInfo variableInfo, out sunConstInfo constInfo)
|
||||
{
|
||||
try
|
||||
{
|
||||
variableInfo = ResolveVariable(node);
|
||||
}
|
||||
catch
|
||||
{
|
||||
variableInfo = null;
|
||||
}
|
||||
try
|
||||
{
|
||||
constInfo = ResolveConstant(node);
|
||||
}
|
||||
catch
|
||||
{
|
||||
constInfo = null;
|
||||
}
|
||||
}
|
||||
|
||||
void WriteHeader()
|
||||
{
|
||||
writer.WriteString("SPCB");
|
||||
writer.Write32(textOffset);
|
||||
writer.Write32(dataOffset);
|
||||
writer.WriteS32(DataTable.Count);
|
||||
writer.Write32(symbolOffset);
|
||||
writer.WriteS32(SymbolTable.Count);
|
||||
writer.WriteS32(Scopes.Root.VariableCount);
|
||||
}
|
||||
|
||||
// events
|
||||
void OnEnterFile(sunFileArgs e)
|
||||
{
|
||||
var func = EnterFile;
|
||||
if (func != null)
|
||||
{
|
||||
func(this, e);
|
||||
}
|
||||
}
|
||||
void OnExitFile(sunFileArgs e)
|
||||
{
|
||||
var func = ExitFile;
|
||||
if (func != null)
|
||||
{
|
||||
func(this, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class sunFileArgs : EventArgs
|
||||
{
|
||||
public string File { get; private set; }
|
||||
|
||||
public sunFileArgs(string file)
|
||||
{
|
||||
File = file;
|
||||
}
|
||||
}
|
||||
}
|
42
data table.cs
Normal file
42
data table.cs
Normal file
|
@ -0,0 +1,42 @@
|
|||
using arookas.IO.Binary;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
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)
|
||||
{
|
||||
int index = data.IndexOf(value);
|
||||
if (index < 0)
|
||||
{
|
||||
index = data.Count;
|
||||
data.Add(value);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
public void Clear() { data.Clear(); }
|
||||
|
||||
public void Write(aBinaryWriter writer)
|
||||
{
|
||||
int ofs = 0;
|
||||
foreach (var value in this)
|
||||
{
|
||||
writer.WriteS32(ofs);
|
||||
ofs += value.Length + 1; // include terminator
|
||||
}
|
||||
foreach (var value in this)
|
||||
{
|
||||
writer.WriteString(value, aBinaryStringFormat.NullTerminated);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator<string> GetEnumerator() { return data.GetEnumerator(); }
|
||||
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
|
||||
}
|
||||
}
|
244
exceptions.cs
Normal file
244
exceptions.cs
Normal file
|
@ -0,0 +1,244 @@
|
|||
using PerCederberg.Grammatica.Runtime;
|
||||
using System;
|
||||
|
||||
namespace arookas
|
||||
{
|
||||
// base exception type
|
||||
public class sunCompilerException : Exception
|
||||
{
|
||||
public sunCompilerException()
|
||||
{
|
||||
|
||||
}
|
||||
public sunCompilerException(string format, params object[] args)
|
||||
: base(String.Format(format, args))
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// exceptions that have a location in the source
|
||||
public abstract class sunScriptException : sunCompilerException
|
||||
{
|
||||
public abstract sunSourceLocation Location { get; }
|
||||
|
||||
public sunScriptException()
|
||||
{
|
||||
|
||||
}
|
||||
public sunScriptException(string format, params object[] args)
|
||||
: base(format, args)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// wrapper around Grammatica exceptions
|
||||
class sunParserException : sunScriptException
|
||||
{
|
||||
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)
|
||||
{
|
||||
throw new ArgumentNullException("file");
|
||||
}
|
||||
if (info == null)
|
||||
{
|
||||
throw new ArgumentNullException("info");
|
||||
}
|
||||
this.file = file;
|
||||
Info = info;
|
||||
}
|
||||
}
|
||||
|
||||
// node exceptions
|
||||
abstract class sunNodeException<TNode> : sunScriptException where TNode : sunNode
|
||||
{
|
||||
public TNode Node { get; private set; }
|
||||
public override sunSourceLocation Location { get { return Node.Location; } }
|
||||
|
||||
protected sunNodeException(TNode node)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
throw new ArgumentNullException("node");
|
||||
}
|
||||
Node = node;
|
||||
}
|
||||
}
|
||||
|
||||
class sunRedeclaredBuiltinException : sunNodeException<sunBuiltinDeclaration>
|
||||
{
|
||||
public override string Message { get { return String.Format("Redeclared builtin '{0}'.", Node.Builtin.Value); } }
|
||||
|
||||
public sunRedeclaredBuiltinException(sunBuiltinDeclaration node)
|
||||
: base(node)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
class sunRedefinedFunctionException : sunNodeException<sunFunctionDefinition>
|
||||
{
|
||||
public override string Message { get { return String.Format("Redefined function '{0}'.", Node.Function.Value); } }
|
||||
|
||||
public sunRedefinedFunctionException(sunFunctionDefinition node)
|
||||
: base(node)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
class sunUndeclaredVariableException : sunNodeException<sunIdentifier>
|
||||
{
|
||||
public override string Message { get { return String.Format("Undeclared variable '{0}'.", Node.Value); } }
|
||||
|
||||
public sunUndeclaredVariableException(sunIdentifier node)
|
||||
: base(node)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
class sunRedeclaredVariableException : sunNodeException<sunIdentifier>
|
||||
{
|
||||
public override string Message { get { return String.Format("Redeclared variable '{0}'.", Node.Value); } }
|
||||
|
||||
public sunRedeclaredVariableException(sunIdentifier node)
|
||||
: base(node)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
class sunRedeclaredParameterException : sunNodeException<sunIdentifier>
|
||||
{
|
||||
public override string Message { get { return String.Format("Redeclared parameter '{0}'.", Node.Value); } }
|
||||
|
||||
public sunRedeclaredParameterException(sunIdentifier node)
|
||||
: base(node)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
class sunEscapeSequenceException : sunNodeException<sunStringLiteral>
|
||||
{
|
||||
public override string Message { get { return String.Format("Bad escape sequence in string."); } }
|
||||
|
||||
public sunEscapeSequenceException(sunStringLiteral node)
|
||||
: base(node)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
class sunVariadicParameterListException : sunNodeException<sunParameterList>
|
||||
{
|
||||
public override string Message { get { return String.Format("Bad variadic parameter list."); } }
|
||||
|
||||
public sunVariadicParameterListException(sunParameterList node)
|
||||
: base(node)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
class sunArgumentCountException : sunNodeException<sunFunctionCall>
|
||||
{
|
||||
public sunCallableSymbolInfo 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
|
||||
{
|
||||
string format;
|
||||
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)
|
||||
{
|
||||
format = "Missing {0} argument(s) (expected {1}; got {2})."; // missing arguments
|
||||
}
|
||||
else
|
||||
{
|
||||
format = "Too many arguments (expected {1}; got {2})."; // extra arguments
|
||||
}
|
||||
return String.Format(format, ArgumentMinimum - ArgumentCount, ArgumentMinimum, ArgumentCount);
|
||||
}
|
||||
}
|
||||
|
||||
public sunArgumentCountException(sunFunctionCall node, sunCallableSymbolInfo calledSymbol)
|
||||
: base(node)
|
||||
{
|
||||
if (calledSymbol == null)
|
||||
{
|
||||
throw new ArgumentNullException("calledSymbol");
|
||||
}
|
||||
CalledSymbol = calledSymbol;
|
||||
}
|
||||
}
|
||||
class sunIdentifierException : sunNodeException<sunIdentifier>
|
||||
{
|
||||
public override string Message { get { return String.Format("Invalid identifier '{0}'.", Node.Value); } }
|
||||
|
||||
public sunIdentifierException(sunIdentifier node)
|
||||
: base(node)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
58
import table.cs
Normal file
58
import table.cs
Normal file
|
@ -0,0 +1,58 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace arookas
|
||||
{
|
||||
class sunImportTable
|
||||
{
|
||||
List<string> imports = new List<string>(10);
|
||||
Stack<string> curDir = new Stack<string>(5);
|
||||
string RootDir { get; set; }
|
||||
|
||||
public sunImportTable(string rootDir)
|
||||
{
|
||||
RootDir = rootDir;
|
||||
}
|
||||
|
||||
public void PushDir(string dir) { curDir.Push(Path.GetDirectoryName(dir)); }
|
||||
public void PopDir() { curDir.Pop(); }
|
||||
|
||||
public string ResolveImport(sunImport import)
|
||||
{
|
||||
string fullPath;
|
||||
string file = import.ImportFile.Value;
|
||||
if (Path.IsPathRooted(file))
|
||||
{
|
||||
// if the path is absolute, just use it directly
|
||||
fullPath = file;
|
||||
if (!File.Exists(fullPath))
|
||||
{
|
||||
// could not find file
|
||||
throw new sunMissingImportException(import);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// check if the file exists relative to the current one;
|
||||
// if it's not there, check the root directory
|
||||
fullPath = Path.Combine(curDir.Peek(), file);
|
||||
if (!File.Exists(fullPath))
|
||||
{
|
||||
fullPath = Path.Combine(RootDir, file);
|
||||
if (!File.Exists(fullPath))
|
||||
{
|
||||
// could not find file
|
||||
throw new sunMissingImportException(import);
|
||||
}
|
||||
}
|
||||
}
|
||||
// make sure the file has not been imported yet
|
||||
if (imports.Contains(fullPath))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
imports.Add(fullPath);
|
||||
return fullPath;
|
||||
}
|
||||
}
|
||||
}
|
79
loop stack.cs
Normal file
79
loop stack.cs
Normal file
|
@ -0,0 +1,79 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace arookas
|
||||
{
|
||||
class sunLoopStack
|
||||
{
|
||||
Stack<sunLoop> loops = new Stack<sunLoop>(5);
|
||||
sunLoop Top { get { return loops.Peek(); } }
|
||||
|
||||
sunLoop this[string name] { get { return loops.FirstOrDefault(i => i.Name == name); } }
|
||||
public int Count { get { return loops.Count; } }
|
||||
|
||||
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)
|
||||
{
|
||||
context.Text.ClosePoint(_break, breakPoint.Offset);
|
||||
}
|
||||
foreach (var _continue in Top.Continues)
|
||||
{
|
||||
context.Text.ClosePoint(_continue, continuePoint.Offset);
|
||||
}
|
||||
loops.Pop();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var loop = name == null ? Top : this[name];
|
||||
if (loop == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
loop.Breaks.Add(point);
|
||||
return true;
|
||||
}
|
||||
public bool AddContinue(sunPoint point, string name)
|
||||
{
|
||||
if (Count < 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var loop = name == null ? Top : this[name];
|
||||
if (loop == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
loop.Continues.Add(point);
|
||||
return true;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
}
|
||||
public sunLoop(string name)
|
||||
{
|
||||
Name = name;
|
||||
Breaks = new List<sunPoint>(5);
|
||||
Continues = new List<sunPoint>(5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
70
main.cs
Normal file
70
main.cs
Normal file
|
@ -0,0 +1,70 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace arookas
|
||||
{
|
||||
static class SSC
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
string inFile = args[0];
|
||||
var compiler = new sunCompiler();
|
||||
using (var output = OpenWrite(Path.ChangeExtension(inFile, ".sb")))
|
||||
{
|
||||
var results = compiler.Compile(inFile, output);
|
||||
if (!results.Success)
|
||||
{
|
||||
if (results.Error is sunScriptException)
|
||||
{
|
||||
var error = results.Error as sunScriptException;
|
||||
Console.WriteLine("ERROR:\n \"{0}\"\n pos ({1}, {2})\n{3}", error.Location.File, error.Location.Line, error.Location.Column, error.Message);
|
||||
Console.ReadKey();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
var error = results.Error;
|
||||
Console.WriteLine("ERROR:\n", error.Message);
|
||||
Console.ReadKey();
|
||||
return;
|
||||
}
|
||||
}
|
||||
Console.WriteLine("Finished compiling in {0:F2}ms.", results.CompileTime.TotalMilliseconds);
|
||||
Console.WriteLine("Symbol count: {0}", results.SymbolCount);
|
||||
Console.WriteLine(" - builtins: {0}", results.BuiltinCount);
|
||||
Console.WriteLine(" - functions: {0}", results.FunctionCount);
|
||||
Console.WriteLine(" - variables: {0}", results.VariableCount);
|
||||
Console.ReadKey();
|
||||
}
|
||||
}
|
||||
|
||||
static FileStream OpenRead(string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
return File.OpenRead(path);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Console.WriteLine("Failed to open the file '{0}'.\nPlease make sure the file exists and is not currently in use.", Path.GetFileName(path));
|
||||
Console.ReadKey();
|
||||
Environment.Exit(1);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
static FileStream OpenWrite(string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
return File.Create(path);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Console.WriteLine("Failed to create the file '{0}'.", Path.GetFileName(path));
|
||||
Console.ReadKey();
|
||||
Environment.Exit(1);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
322
parser.cs
Normal file
322
parser.cs
Normal file
|
@ -0,0 +1,322 @@
|
|||
using PerCederberg.Grammatica.Runtime;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace arookas
|
||||
{
|
||||
class sunParser
|
||||
{
|
||||
static string[] keywords =
|
||||
{
|
||||
"import",
|
||||
"builtin", "function", "var", "const",
|
||||
"if", "while", "do", "for",
|
||||
"return", "break", "continue",
|
||||
"yield", "exit", "dump", "lock", "unlock", "int", "float", "typeof", "print",
|
||||
"true", "false",
|
||||
};
|
||||
|
||||
public sunNode Parse(string file)
|
||||
{
|
||||
using (var input = new StreamReader(file))
|
||||
{
|
||||
var parser = new __sunParser(input);
|
||||
var node = parser.Parse();
|
||||
return CreateAst(file, node);
|
||||
}
|
||||
}
|
||||
|
||||
static sunNode CreateAst(string file, Node node)
|
||||
{
|
||||
var ast = ConvertNode(file, node);
|
||||
if (ast == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
// children
|
||||
if (node is Production)
|
||||
{
|
||||
var production = node as Production;
|
||||
for (int i = 0; i < production.Count; ++i)
|
||||
{
|
||||
var child = CreateAst(file, production[i]);
|
||||
if (child != null)
|
||||
{
|
||||
ast.Add(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
// transcience
|
||||
switch ((__sunConstants)node.Id)
|
||||
{
|
||||
case __sunConstants.STATEMENT:
|
||||
case __sunConstants.COMPOUND_STATEMENT:
|
||||
case __sunConstants.COMPOUND_STATEMENT_ITEM:
|
||||
case __sunConstants.ASSIGNMENT_OPERATOR:
|
||||
case __sunConstants.BINARY_OPERATOR:
|
||||
case __sunConstants.UNARY_OPERATOR:
|
||||
case __sunConstants.TERM:
|
||||
case __sunConstants.PARAMETER:
|
||||
case __sunConstants.ARGUMENT_LIST:
|
||||
case __sunConstants.ARGUMENT:
|
||||
{
|
||||
return Transcient(ast);
|
||||
}
|
||||
}
|
||||
return ast;
|
||||
}
|
||||
static sunNode ConvertNode(string file, Node node)
|
||||
{
|
||||
var location = new sunSourceLocation(file, node.StartLine, node.StartColumn);
|
||||
string token = null;
|
||||
if (node is Token)
|
||||
{
|
||||
token = (node as Token).Image;
|
||||
}
|
||||
|
||||
// statements
|
||||
switch (GetId(node))
|
||||
{
|
||||
case __sunConstants.SCRIPT: return new sunNode(location);
|
||||
case __sunConstants.STATEMENT: return new sunNode(location);
|
||||
case __sunConstants.STATEMENT_BLOCK: return new sunStatementBlock(location);
|
||||
case __sunConstants.COMPOUND_STATEMENT: return new sunNode(location);
|
||||
case __sunConstants.COMPOUND_STATEMENT_ITEM: return new sunNode(location);
|
||||
|
||||
case __sunConstants.IMPORT_STATEMENT: return new sunImport(location);
|
||||
case __sunConstants.NAME_LABEL: return new sunNameLabel(location);
|
||||
|
||||
case __sunConstants.YIELD_STATEMENT: return new sunYield(location);
|
||||
case __sunConstants.EXIT_STATEMENT: return new sunExit(location);
|
||||
case __sunConstants.DUMP_STATEMENT: return new sunDump(location);
|
||||
case __sunConstants.LOCK_STATEMENT: return new sunLock(location);
|
||||
case __sunConstants.UNLOCK_STATEMENT: return new sunUnlock(location);
|
||||
case __sunConstants.PRINT_STATEMENT: return new sunPrint(location);
|
||||
}
|
||||
|
||||
// literals
|
||||
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);
|
||||
case __sunConstants.STRING: return new sunStringLiteral(location, token);
|
||||
case __sunConstants.IDENTIFIER: return new sunIdentifier(location, token);
|
||||
case __sunConstants.ELLIPSIS: return new sunEllipsis(location);
|
||||
case __sunConstants.TRUE: return new sunTrue(location, token);
|
||||
case __sunConstants.FALSE: return new sunFalse(location, token);
|
||||
}
|
||||
|
||||
// operators
|
||||
switch (GetId(node))
|
||||
{
|
||||
case __sunConstants.ADD: return new sunAdd(location);
|
||||
case __sunConstants.SUB:
|
||||
{
|
||||
if (GetId(node.Parent) == __sunConstants.UNARY_OPERATOR)
|
||||
{
|
||||
return new sunNeg(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);
|
||||
|
||||
case __sunConstants.BIT_AND: return new sunBitAND(location);
|
||||
case __sunConstants.BIT_OR: return new sunBitOR(location);
|
||||
case __sunConstants.BIT_LSH: return new sunBitLsh(location);
|
||||
case __sunConstants.BIT_RSH: return new sunBitRsh(location);
|
||||
|
||||
case __sunConstants.LOG_AND: return new sunLogAND(location);
|
||||
case __sunConstants.LOG_OR: return new sunLogOR(location);
|
||||
case __sunConstants.LOG_NOT: return new sunLogNOT(location);
|
||||
|
||||
case __sunConstants.EQ: return new sunEq(location);
|
||||
case __sunConstants.NEQ: return new sunNtEq(location);
|
||||
case __sunConstants.LT: return new sunLt(location);
|
||||
case __sunConstants.GT: return new sunGt(location);
|
||||
case __sunConstants.LTEQ: return new sunLtEq(location);
|
||||
case __sunConstants.GTEQ: return new sunGtEq(location);
|
||||
|
||||
case __sunConstants.ASSIGN: return new sunAssign(location);
|
||||
case __sunConstants.ASSIGN_ADD: return new sunAssignAdd(location);
|
||||
case __sunConstants.ASSIGN_SUB: return new sunAssignSub(location);
|
||||
case __sunConstants.ASSIGN_MUL: return new sunAssignMul(location);
|
||||
case __sunConstants.ASSIGN_DIV: return new sunAssignDiv(location);
|
||||
case __sunConstants.ASSIGN_MOD: return new sunAssignMod(location);
|
||||
|
||||
case __sunConstants.ASSIGN_BIT_AND: return new sunAssignBitAND(location);
|
||||
case __sunConstants.ASSIGN_BIT_OR: return new sunAssignBitOR(location);
|
||||
case __sunConstants.ASSIGN_BIT_LSH: return new sunAssignBitLsh(location);
|
||||
case __sunConstants.ASSIGN_BIT_RSH: return new sunAssignBitRsh(location);
|
||||
|
||||
case __sunConstants.ASSIGNMENT_OPERATOR: return new sunNode(location);
|
||||
case __sunConstants.TERNARY_OPERATOR: return new sunTernaryOperator(location);
|
||||
case __sunConstants.BINARY_OPERATOR: return new sunNode(location);
|
||||
case __sunConstants.UNARY_OPERATOR: return new sunNode(location);
|
||||
}
|
||||
|
||||
// expressions
|
||||
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);
|
||||
case __sunConstants.FLOAT_CAST: return new sunFloatCast(location);
|
||||
case __sunConstants.TYPEOF_CAST: return new sunTypeofCast(location);
|
||||
}
|
||||
|
||||
// builtins
|
||||
switch (GetId(node))
|
||||
{
|
||||
case __sunConstants.BUILTIN_DECLARATION: return new sunBuiltinDeclaration(location);
|
||||
}
|
||||
|
||||
// functions
|
||||
switch (GetId(node))
|
||||
{
|
||||
case __sunConstants.FUNCTION_DEFINITION: return new sunFunctionDefinition(location);
|
||||
case __sunConstants.FUNCTION_CALL: return new sunFunctionCall(location);
|
||||
|
||||
case __sunConstants.PARAMETER_LIST: return new sunParameterList(location);
|
||||
case __sunConstants.PARAMETER: return new sunNode(location);
|
||||
case __sunConstants.ARGUMENT_LIST: return new sunNode(location);
|
||||
case __sunConstants.ARGUMENT: return new sunNode(location);
|
||||
}
|
||||
|
||||
// variables
|
||||
switch (GetId(node))
|
||||
{
|
||||
case __sunConstants.VARIABLE_REFERENCE: return new sunVariableReference(location);
|
||||
case __sunConstants.VARIABLE_DECLARATION: return new sunVariableDeclaration(location);
|
||||
case __sunConstants.VARIABLE_DEFINITION: return new sunVariableDefinition(location);
|
||||
case __sunConstants.VARIABLE_ASSIGNMENT: return new sunVariableAssignment(location);
|
||||
}
|
||||
|
||||
// constants
|
||||
switch (GetId(node))
|
||||
{
|
||||
case __sunConstants.CONST_DEFINITION: return new sunConstDefinition(location);
|
||||
}
|
||||
|
||||
// flow control
|
||||
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);
|
||||
case __sunConstants.FOR_STATEMENT: return new sunFor(location);
|
||||
case __sunConstants.FOR_DECLARATION: return new sunForDeclaration(location);
|
||||
case __sunConstants.FOR_CONDITION: return new sunForCondition(location);
|
||||
case __sunConstants.FOR_ITERATION: return new sunForIteration(location);
|
||||
|
||||
case __sunConstants.RETURN_STATEMENT: return new sunReturn(location);
|
||||
case __sunConstants.BREAK_STATEMENT: return new sunBreak(location);
|
||||
case __sunConstants.CONTINUE_STATEMENT: return new sunContinue(location);
|
||||
}
|
||||
|
||||
// cleanup keywords punctuation
|
||||
switch (GetId(node))
|
||||
{
|
||||
// keywords
|
||||
case __sunConstants.IMPORT:
|
||||
case __sunConstants.BUILTIN:
|
||||
case __sunConstants.FUNCTION:
|
||||
case __sunConstants.VAR:
|
||||
case __sunConstants.CONST:
|
||||
|
||||
case __sunConstants.IF:
|
||||
case __sunConstants.ELSE:
|
||||
case __sunConstants.DO:
|
||||
case __sunConstants.WHILE:
|
||||
case __sunConstants.FOR:
|
||||
|
||||
case __sunConstants.RETURN:
|
||||
case __sunConstants.BREAK:
|
||||
case __sunConstants.CONTINUE:
|
||||
|
||||
case __sunConstants.YIELD:
|
||||
case __sunConstants.EXIT:
|
||||
case __sunConstants.DUMP:
|
||||
case __sunConstants.LOCK:
|
||||
case __sunConstants.UNLOCK:
|
||||
case __sunConstants.INT:
|
||||
case __sunConstants.FLOAT:
|
||||
case __sunConstants.TYPEOF:
|
||||
case __sunConstants.PRINT:
|
||||
|
||||
case __sunConstants.TRUE:
|
||||
case __sunConstants.FALSE:
|
||||
|
||||
// punctuation
|
||||
case __sunConstants.L_BRACE:
|
||||
case __sunConstants.R_BRACE:
|
||||
case __sunConstants.L_PAREN:
|
||||
case __sunConstants.R_PAREN:
|
||||
case __sunConstants.L_BRACKET:
|
||||
case __sunConstants.R_BRACKET:
|
||||
case __sunConstants.COLON:
|
||||
case __sunConstants.SEMICOLON:
|
||||
case __sunConstants.COMMA:
|
||||
case __sunConstants.DOT:
|
||||
// case __sunConstants.ELLIPSIS: // do not exclude ellipsis for variadic parameters
|
||||
case __sunConstants.QMARK:
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// emergency fallback
|
||||
return null;
|
||||
}
|
||||
static sunSourceLocation GetSourceLocation(string file, Node node)
|
||||
{
|
||||
if (file == null)
|
||||
{
|
||||
throw new ArgumentNullException("file");
|
||||
}
|
||||
if (node == null)
|
||||
{
|
||||
throw new ArgumentNullException("node");
|
||||
}
|
||||
if (node is Production)
|
||||
{
|
||||
var production = node as Production;
|
||||
if (production.Count > 0)
|
||||
{
|
||||
return GetSourceLocation(file, production[0]);
|
||||
}
|
||||
throw new ArgumentException("node is a child-less production.", "node");
|
||||
}
|
||||
else if (node is Token)
|
||||
{
|
||||
var token = node as Token;
|
||||
return new sunSourceLocation(file, token.StartLine, token.StartColumn);
|
||||
}
|
||||
throw new ArgumentException("node is an unsupported type.", "node");
|
||||
}
|
||||
static sunNode Transcient(sunNode node)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
throw new ArgumentNullException("node");
|
||||
}
|
||||
return node.Count == 1 ? node[0] : node;
|
||||
}
|
||||
static __sunConstants GetId(Node node)
|
||||
{
|
||||
return (__sunConstants)node.Id;
|
||||
}
|
||||
|
||||
public static bool IsKeyword(string name)
|
||||
{
|
||||
return keywords.Contains(name);
|
||||
}
|
||||
}
|
||||
}
|
93
scope stack.cs
Normal file
93
scope stack.cs
Normal file
|
@ -0,0 +1,93 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace arookas
|
||||
{
|
||||
class sunScopeStack : IEnumerable<sunScope>
|
||||
{
|
||||
List<sunScope> stack = new List<sunScope>(8);
|
||||
|
||||
public int Count { get { return stack.Count; } }
|
||||
public bool IsRoot { get { return Count == 1; } }
|
||||
|
||||
public sunScope Root { get { return this[0]; } }
|
||||
public sunScope Top { get { return this[Count - 1]; } }
|
||||
|
||||
public sunScope this[int index] { get { return stack[index]; } }
|
||||
|
||||
public sunScopeStack()
|
||||
{
|
||||
Push(); // push global scope
|
||||
}
|
||||
|
||||
public void Push()
|
||||
{
|
||||
stack.Add(new sunScope());
|
||||
}
|
||||
public void Pop()
|
||||
{
|
||||
if (!IsRoot)
|
||||
{
|
||||
stack.RemoveAt(Count - 1);
|
||||
}
|
||||
}
|
||||
public void Clear()
|
||||
{
|
||||
stack.Clear();
|
||||
Push(); // add global scope
|
||||
}
|
||||
|
||||
public bool GetIsVariableDeclared(string name) { return stack.Any(i => i.GetIsVariableDeclared(name)); }
|
||||
|
||||
public IEnumerator<sunScope> GetEnumerator() { return stack.GetEnumerator(); }
|
||||
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
|
||||
}
|
||||
|
||||
class sunScope
|
||||
{
|
||||
List<sunVariableInfo> variables = new List<sunVariableInfo>(10);
|
||||
List<sunConstInfo> constants = new List<sunConstInfo>(10);
|
||||
|
||||
public int VariableCount { get { return variables.Count; } }
|
||||
public int ConstantCount { get { return constants.Count; } }
|
||||
|
||||
public bool GetIsVariableDeclared(string name) { return variables.Any(v => v.Name == name); }
|
||||
public sunVariableInfo DeclareVariable(string name, int display)
|
||||
{
|
||||
if (GetIsVariableDeclared(name) || GetIsConstantDeclared(name))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var variableInfo = new sunVariableInfo(name, display, variables.Count);
|
||||
variables.Add(variableInfo);
|
||||
return variableInfo;
|
||||
}
|
||||
public sunVariableInfo ResolveVariable(string name) { return variables.FirstOrDefault(v => v.Name == name); }
|
||||
|
||||
public bool GetIsConstantDeclared(string name) { return constants.Any(c => c.Name == name); }
|
||||
public sunConstInfo DeclareConstant(string name, sunExpression expression)
|
||||
{
|
||||
if (GetIsVariableDeclared(name) || GetIsConstantDeclared(name))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var constInfo = new sunConstInfo(name, expression);
|
||||
constants.Add(constInfo);
|
||||
return constInfo;
|
||||
}
|
||||
public sunConstInfo ResolveConstant(string name) { return constants.FirstOrDefault(c => c.Name == name); }
|
||||
}
|
||||
|
||||
class sunConstInfo
|
||||
{
|
||||
public string Name { get; private set; }
|
||||
public sunExpression Expression { get; private set; }
|
||||
|
||||
public sunConstInfo(string name, sunExpression expression)
|
||||
{
|
||||
Name = name;
|
||||
Expression = expression;
|
||||
}
|
||||
}
|
||||
}
|
219
sunscript.grammar
Normal file
219
sunscript.grammar
Normal file
|
@ -0,0 +1,219 @@
|
|||
%header%
|
||||
|
||||
GRAMMARTYPE = "LL"
|
||||
|
||||
DESCRIPTION = "A grammar for SunScript."
|
||||
|
||||
AUTHOR = "arookas"
|
||||
VERSION = "1.1"
|
||||
DATE = "2015/11/29"
|
||||
|
||||
LICENSE = "No license."
|
||||
|
||||
COPYRIGHT = "Copyright (c) 2015 arookas"
|
||||
|
||||
%tokens%
|
||||
|
||||
// whitespace
|
||||
WHITESPACE = <<[ \t\r\n]+>> %ignore%
|
||||
|
||||
// comments
|
||||
SINGLE_LINE_COMMENT = <<//.*>> %ignore%
|
||||
MULTI_LINE_COMMENT = <</\*([^*]|\*+[^*/])*\*+/>> %ignore%
|
||||
|
||||
// keywords
|
||||
IMPORT = "import"
|
||||
|
||||
BUILTIN = "builtin"
|
||||
FUNCTION = "function"
|
||||
VAR = "var"
|
||||
CONST = "const"
|
||||
|
||||
IF = "if"
|
||||
ELSE = "else"
|
||||
DO = "do"
|
||||
WHILE = "while"
|
||||
FOR = "for"
|
||||
|
||||
RETURN = "return"
|
||||
BREAK = "break"
|
||||
CONTINUE = "continue"
|
||||
|
||||
YIELD = "yield"
|
||||
EXIT = "exit"
|
||||
DUMP = "dump"
|
||||
LOCK = "lock"
|
||||
UNLOCK = "unlock"
|
||||
INT = "int"
|
||||
FLOAT = "float"
|
||||
TYPEOF = "typeof"
|
||||
PRINT = "print"
|
||||
|
||||
TRUE = "true"
|
||||
FALSE = "false"
|
||||
|
||||
// punctuation
|
||||
L_BRACE = "{"
|
||||
R_BRACE = "}"
|
||||
L_PAREN = "("
|
||||
R_PAREN = ")"
|
||||
L_BRACKET = "["
|
||||
R_BRACKET = "]"
|
||||
COLON = ":"
|
||||
SEMICOLON = ";"
|
||||
COMMA = ","
|
||||
DOT = "."
|
||||
ELLIPSIS = "..."
|
||||
QMARK = "?"
|
||||
|
||||
// operators
|
||||
ADD = "+"
|
||||
SUB = "-" // doubles as the negation operator
|
||||
MUL = "*"
|
||||
DIV = "/"
|
||||
MOD = "%"
|
||||
|
||||
BIT_AND = "&"
|
||||
BIT_OR = "|"
|
||||
BIT_LSH = "<<"
|
||||
BIT_RSH = ">>"
|
||||
|
||||
LOG_NOT = "!"
|
||||
LOG_AND = "&&"
|
||||
LOG_OR = "||"
|
||||
|
||||
EQ = "=="
|
||||
NEQ = "!="
|
||||
LT = "<"
|
||||
LTEQ = "<="
|
||||
GT = ">"
|
||||
GTEQ = ">="
|
||||
|
||||
ASSIGN = "="
|
||||
ASSIGN_ADD = "+="
|
||||
ASSIGN_SUB = "-="
|
||||
ASSIGN_MUL = "*="
|
||||
ASSIGN_DIV = "/="
|
||||
ASSIGN_MOD = "%="
|
||||
ASSIGN_BIT_AND = "&="
|
||||
ASSIGN_BIT_OR = "|="
|
||||
ASSIGN_BIT_LSH = "<<="
|
||||
ASSIGN_BIT_RSH = ">>="
|
||||
|
||||
// literals
|
||||
IDENTIFIER = <<[_A-Za-z][_A-Za-z0-9]*>>
|
||||
DEC_NUMBER = <<-?[0-9]+\.[0-9]+>>
|
||||
HEX_NUMBER = <<-?0x[0-9A-Fa-f]+>>
|
||||
INT_NUMBER = <<-?[0-9]+>>
|
||||
STRING = <<"(\\.|[^"])*">>
|
||||
|
||||
%productions%
|
||||
|
||||
script = statement+;
|
||||
|
||||
// statements
|
||||
statement =
|
||||
import_statement SEMICOLON |
|
||||
compound_statement SEMICOLON |
|
||||
function_definition |
|
||||
builtin_declaration SEMICOLON |
|
||||
if_statement |
|
||||
while_statement |
|
||||
do_statement SEMICOLON |
|
||||
for_statement |
|
||||
return_statement SEMICOLON |
|
||||
break_statement SEMICOLON |
|
||||
continue_statement SEMICOLON |
|
||||
yield_statement SEMICOLON |
|
||||
exit_statement SEMICOLON |
|
||||
dump_statement SEMICOLON |
|
||||
lock_statement SEMICOLON |
|
||||
unlock_statement SEMICOLON |
|
||||
statement_block;
|
||||
compound_statement = compound_statement_item {COMMA compound_statement_item};
|
||||
compound_statement_item =
|
||||
const_definition |
|
||||
variable_definition |
|
||||
variable_declaration |
|
||||
variable_assignment |
|
||||
print_statement |
|
||||
function_call;
|
||||
statement_block = L_BRACE {statement} R_BRACE;
|
||||
|
||||
import_statement = IMPORT STRING;
|
||||
yield_statement = YIELD;
|
||||
exit_statement = EXIT;
|
||||
dump_statement = DUMP;
|
||||
lock_statement = LOCK;
|
||||
unlock_statement = UNLOCK;
|
||||
print_statement = PRINT argument_list;
|
||||
|
||||
name_label = IDENTIFIER COLON;
|
||||
|
||||
// operators
|
||||
assignment_operator = ASSIGN | ASSIGN_ADD | ASSIGN_SUB | ASSIGN_MUL | ASSIGN_DIV | ASSIGN_MOD | ASSIGN_BIT_AND | ASSIGN_BIT_OR | ASSIGN_BIT_LSH | ASSIGN_BIT_RSH;
|
||||
ternary_operator = expression QMARK expression COLON expression;
|
||||
binary_operator =
|
||||
ADD | SUB | MUL | DIV | MOD | // arithmetic
|
||||
BIT_AND | BIT_OR | BIT_LSH | BIT_RSH | // bitwise
|
||||
EQ | NEQ | LT | LTEQ | GT | GTEQ | // comparison
|
||||
LOG_AND | LOG_OR; // logical
|
||||
unary_operator = LOG_NOT | SUB;
|
||||
|
||||
// expressions
|
||||
expression = operand {binary_operator operand};
|
||||
operand = [unary_operator_list] term;
|
||||
term =
|
||||
int_cast |
|
||||
float_cast |
|
||||
typeof_cast |
|
||||
function_call |
|
||||
variable_reference |
|
||||
STRING |
|
||||
DEC_NUMBER |
|
||||
HEX_NUMBER |
|
||||
INT_NUMBER |
|
||||
TRUE |
|
||||
FALSE |
|
||||
L_PAREN expression R_PAREN |
|
||||
L_BRACKET ternary_operator R_BRACKET; // HACK: the brackets remove ambiguity
|
||||
|
||||
unary_operator_list = unary_operator+;
|
||||
|
||||
int_cast = INT L_PAREN expression R_PAREN;
|
||||
float_cast = FLOAT L_PAREN expression R_PAREN;
|
||||
typeof_cast = TYPEOF L_PAREN expression R_PAREN;
|
||||
|
||||
// constants
|
||||
const_definition = CONST IDENTIFIER ASSIGN expression;
|
||||
|
||||
// variables
|
||||
variable_reference = IDENTIFIER; // used in expressions
|
||||
variable_declaration = VAR IDENTIFIER;
|
||||
variable_definition = VAR IDENTIFIER assignment_operator expression;
|
||||
variable_assignment = IDENTIFIER assignment_operator expression;
|
||||
|
||||
// functions
|
||||
function_definition = FUNCTION IDENTIFIER parameter_list statement_block;
|
||||
function_call = IDENTIFIER argument_list;
|
||||
|
||||
parameter_list = L_PAREN [parameter {COMMA parameter}] R_PAREN; // e.g. (a, b, ...)
|
||||
parameter = IDENTIFIER | ELLIPSIS;
|
||||
argument_list = L_PAREN [argument {COMMA argument}] R_PAREN;
|
||||
argument = expression;
|
||||
|
||||
// builtins
|
||||
builtin_declaration = BUILTIN IDENTIFIER parameter_list;
|
||||
|
||||
// flow control
|
||||
if_statement = [name_label] IF expression statement [ELSE statement];
|
||||
while_statement = [name_label] WHILE expression statement;
|
||||
do_statement = [name_label] DO statement WHILE expression;
|
||||
for_statement = [name_label] FOR L_PAREN [for_declaration] SEMICOLON [for_condition] SEMICOLON [for_iteration] R_PAREN statement;
|
||||
for_declaration = compound_statement;
|
||||
for_condition = expression;
|
||||
for_iteration = compound_statement;
|
||||
|
||||
return_statement = RETURN [expression];
|
||||
break_statement = BREAK [IDENTIFIER];
|
||||
continue_statement = CONTINUE [IDENTIFIER];
|
212
symbol table.cs
Normal file
212
symbol table.cs
Normal file
|
@ -0,0 +1,212 @@
|
|||
using arookas.Collections;
|
||||
using arookas.IO.Binary;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace arookas
|
||||
{
|
||||
class sunSymbolTable : IEnumerable<sunSymbolInfo>
|
||||
{
|
||||
List<sunSymbolInfo> symbols = new List<sunSymbolInfo>(10);
|
||||
|
||||
public int Count { get { return symbols.Count; } }
|
||||
public int BuiltinCount { get { return symbols.Count(sym => sym.Type == sunSymbolType.Builtin); } }
|
||||
public int FunctionCount { get { return symbols.Count(sym => sym.Type == sunSymbolType.Function); } }
|
||||
public int VariableCount { get { return symbols.Count(sym => sym.Type == sunSymbolType.Variable); } }
|
||||
|
||||
public IEnumerable<sunCallableSymbolInfo> Callables { get { return symbols.OfType<sunCallableSymbolInfo>(); } }
|
||||
public IEnumerable<sunBuiltinInfo> Builtins { get { return symbols.Where(sym => sym.Type == sunSymbolType.Builtin).Cast<sunBuiltinInfo>(); } }
|
||||
public IEnumerable<sunFunctionInfo> Functions { get { return symbols.Where(sym => sym.Type == sunSymbolType.Function).Cast<sunFunctionInfo>(); } }
|
||||
public IEnumerable<sunVariableInfo> Variables { get { return symbols.Where(sym => sym.Type == sunSymbolType.Variable).Cast<sunVariableInfo>(); } }
|
||||
|
||||
public void Add(sunSymbolInfo symbol) { symbols.Add(symbol); }
|
||||
public void Clear() { symbols.Clear(); }
|
||||
|
||||
public void Write(aBinaryWriter writer)
|
||||
{
|
||||
int ofs = 0;
|
||||
foreach (var sym in this)
|
||||
{
|
||||
writer.WriteS32((int)sym.Type);
|
||||
writer.WriteS32(ofs);
|
||||
writer.Write32(sym.Data);
|
||||
|
||||
// runtime fields
|
||||
writer.WriteS32(0);
|
||||
writer.WriteS32(0);
|
||||
|
||||
ofs += sym.Name.Length + 1; // include null terminator
|
||||
}
|
||||
foreach (var sym in this)
|
||||
{
|
||||
writer.WriteString(sym.Name, aBinaryStringFormat.NullTerminated);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator<sunSymbolInfo> GetEnumerator() { return symbols.GetEnumerator(); }
|
||||
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
|
||||
}
|
||||
|
||||
abstract class sunSymbolInfo
|
||||
{
|
||||
public string Name { get; private set; }
|
||||
|
||||
// symbol table
|
||||
public abstract sunSymbolType Type { get; }
|
||||
public abstract uint Data { get; }
|
||||
|
||||
protected sunSymbolInfo(string name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
}
|
||||
|
||||
abstract class sunCallableSymbolInfo : sunSymbolInfo
|
||||
{
|
||||
public sunParameterInfo Parameters { get; private set; }
|
||||
protected List<sunPoint> CallSites { get; private set; }
|
||||
|
||||
public bool HasCallSites { get { return CallSites.Count > 0; } }
|
||||
|
||||
protected sunCallableSymbolInfo(string name, sunParameterInfo parameterInfo)
|
||||
: base(name)
|
||||
{
|
||||
Parameters = parameterInfo;
|
||||
CallSites = new List<sunPoint>(10);
|
||||
}
|
||||
|
||||
public abstract void OpenCallSite(sunContext context, int argumentCount);
|
||||
public abstract void CloseCallSites(sunContext context);
|
||||
|
||||
public abstract void Compile(sunContext context);
|
||||
}
|
||||
|
||||
class sunBuiltinInfo : sunCallableSymbolInfo
|
||||
{
|
||||
public int Index { get; private set; }
|
||||
|
||||
// symbol table
|
||||
public override sunSymbolType Type { get { return sunSymbolType.Builtin; } }
|
||||
public override uint Data { get { return (uint)Index; } }
|
||||
|
||||
public sunBuiltinInfo(string name, sunParameterInfo parameters, int index)
|
||||
: base(name, parameters)
|
||||
{
|
||||
Index = index;
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context)
|
||||
{
|
||||
throw new InvalidOperationException("Cannot compile builtins.");
|
||||
}
|
||||
public override void OpenCallSite(sunContext context, int argumentCount)
|
||||
{
|
||||
context.Text.CallBuiltin(Index, argumentCount);
|
||||
}
|
||||
public override void CloseCallSites(sunContext context)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
class sunFunctionInfo : sunCallableSymbolInfo
|
||||
{
|
||||
sunNode Body { get; set; }
|
||||
public uint Offset { get; private set; }
|
||||
|
||||
// symbol table
|
||||
public override sunSymbolType Type { get { return sunSymbolType.Function; } }
|
||||
public override uint Data { get { return (uint)Offset; } }
|
||||
|
||||
public sunFunctionInfo(string name, sunParameterInfo parameters, sunNode body)
|
||||
: base(name, parameters)
|
||||
{
|
||||
Body = body;
|
||||
}
|
||||
|
||||
public override void Compile(sunContext context)
|
||||
{
|
||||
Offset = context.Text.Offset;
|
||||
context.Scopes.Push();
|
||||
foreach (var parameter in Parameters)
|
||||
{
|
||||
context.DeclareParameter(parameter);
|
||||
}
|
||||
context.Text.StoreDisplay(1);
|
||||
Body.Compile(context);
|
||||
context.Text.ReturnVoid();
|
||||
context.Scopes.Pop();
|
||||
}
|
||||
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)
|
||||
{
|
||||
context.Text.ClosePoint(callSite, Offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
// validate parameter names
|
||||
var duplicate = parameters.FirstOrDefault(a => parameters.Count(b => a.Value == b.Value) > 1);
|
||||
if (duplicate != null)
|
||||
{
|
||||
throw new sunRedeclaredParameterException(duplicate);
|
||||
}
|
||||
Parameters = parameters.Select(i => i.Value).ToArray();
|
||||
IsVariadic = variadic;
|
||||
}
|
||||
public sunParameterInfo(IEnumerable<string> parameters, bool variadic)
|
||||
{
|
||||
// validate parameter names
|
||||
Parameters = parameters.ToArray();
|
||||
IsVariadic = variadic;
|
||||
}
|
||||
|
||||
public bool ValidateArgumentCount(int count)
|
||||
{
|
||||
return IsVariadic ? count >= Minimum : count == Minimum;
|
||||
}
|
||||
|
||||
public IEnumerator<string> GetEnumerator() { return Parameters.GetArrayEnumerator(); }
|
||||
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
|
||||
}
|
||||
|
||||
class sunVariableInfo : sunSymbolInfo
|
||||
{
|
||||
public int Display { get; private set; }
|
||||
public int Index { get; private set; }
|
||||
|
||||
// symbol table
|
||||
public override sunSymbolType Type { get { return sunSymbolType.Variable; } }
|
||||
public override uint Data { get { return (uint)Index; } }
|
||||
|
||||
public sunVariableInfo(string name, int display, int index)
|
||||
: base(name)
|
||||
{
|
||||
Display = display;
|
||||
Index = index;
|
||||
}
|
||||
}
|
||||
|
||||
enum sunSymbolType
|
||||
{
|
||||
Builtin,
|
||||
Function,
|
||||
Variable,
|
||||
}
|
||||
}
|
188
writer.cs
Normal file
188
writer.cs
Normal file
|
@ -0,0 +1,188 @@
|
|||
using arookas.IO.Binary;
|
||||
|
||||
namespace arookas
|
||||
{
|
||||
class sunWriter
|
||||
{
|
||||
aBinaryWriter writer;
|
||||
|
||||
public uint Offset { get { return (uint)writer.Position; } }
|
||||
|
||||
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)
|
||||
{
|
||||
writer.Keep();
|
||||
writer.Goto(point.Offset);
|
||||
writer.Write32(offset);
|
||||
writer.Back();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
writer.Write8(0x01);
|
||||
writer.WriteF32(value);
|
||||
}
|
||||
public void PushData(int dataIndex)
|
||||
{
|
||||
writer.Write8(0x02);
|
||||
writer.WriteS32(dataIndex);
|
||||
}
|
||||
public void PushVariable(sunVariableInfo variableInfo)
|
||||
{
|
||||
PushVariable(variableInfo.Display, variableInfo.Index);
|
||||
}
|
||||
public void PushVariable(int display, int variableIndex)
|
||||
{
|
||||
writer.Write8(0x04);
|
||||
writer.WriteS32(display);
|
||||
writer.WriteS32(variableIndex);
|
||||
}
|
||||
|
||||
public void IncVariable(sunVariableInfo variableInfo)
|
||||
{
|
||||
IncVariable(variableInfo.Display, variableInfo.Index);
|
||||
}
|
||||
public void DecVariable(sunVariableInfo 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)
|
||||
{
|
||||
writer.Write8(0x07);
|
||||
writer.WriteS32(display);
|
||||
writer.WriteS32(variableIndex);
|
||||
}
|
||||
|
||||
public void Add() { writer.Write8(0x08); }
|
||||
public void Sub() { writer.Write8(0x09); }
|
||||
public void Mul() { writer.Write8(0x0A); }
|
||||
public void Div() { writer.Write8(0x0B); }
|
||||
public void Mod() { writer.Write8(0x0C); }
|
||||
|
||||
public void StoreVariable(sunVariableInfo 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);
|
||||
writer.WriteS32(variableIndex);
|
||||
}
|
||||
|
||||
public void Eq() { writer.Write8(0x0E); }
|
||||
public void NtEq() { writer.Write8(0x0F); }
|
||||
public void Gt() { writer.Write8(0x10); }
|
||||
public void Lt() { writer.Write8(0x11); }
|
||||
public void GtEq() { writer.Write8(0x12); }
|
||||
public void LtEq() { writer.Write8(0x13); }
|
||||
public void Neg() { writer.Write8(0x14); }
|
||||
public void LogNOT() { writer.Write8(0x15); }
|
||||
public void LogAND() { writer.Write8(0x16); }
|
||||
public void LogOR() { writer.Write8(0x17); }
|
||||
public void BitAND() { writer.Write8(0x18); }
|
||||
public void BitOR() { writer.Write8(0x19); }
|
||||
public void ShL() { writer.Write8(0x1A); }
|
||||
public void ShR() { writer.Write8(0x1B); }
|
||||
|
||||
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)
|
||||
{
|
||||
writer.Write8(0x1C);
|
||||
writer.Write32(point.Offset);
|
||||
writer.WriteS32(argumentCount);
|
||||
}
|
||||
public void CallBuiltin(int symbolIndex, int argumentCount)
|
||||
{
|
||||
writer.Write8(0x1D);
|
||||
writer.WriteS32(symbolIndex);
|
||||
writer.WriteS32(argumentCount);
|
||||
}
|
||||
|
||||
public void DeclareLocal(int count)
|
||||
{
|
||||
writer.Write8(0x1E);
|
||||
writer.WriteS32(count);
|
||||
}
|
||||
public void StoreDisplay(int display)
|
||||
{
|
||||
writer.Write8(0x1F);
|
||||
writer.WriteS32(display);
|
||||
}
|
||||
|
||||
public void ReturnValue() { writer.Write8(0x20); }
|
||||
public void ReturnVoid() { writer.Write8(0x21); }
|
||||
|
||||
public sunPoint GotoIfZero()
|
||||
{
|
||||
writer.Write8(0x22);
|
||||
sunPoint point = OpenPoint();
|
||||
writer.Write32(0); // dummy
|
||||
return point;
|
||||
}
|
||||
public sunPoint Goto()
|
||||
{
|
||||
writer.Write8(0x23);
|
||||
sunPoint point = OpenPoint();
|
||||
writer.Write32(0); // dummy
|
||||
return point;
|
||||
}
|
||||
public void GotoIfZero(sunPoint point)
|
||||
{
|
||||
writer.Write8(0x22);
|
||||
writer.Write32(point.Offset);
|
||||
}
|
||||
public void Goto(sunPoint point)
|
||||
{
|
||||
writer.Write8(0x23);
|
||||
writer.Write32(point.Offset);
|
||||
}
|
||||
public void Pop() { writer.Write8(0x24); }
|
||||
|
||||
public void Terminate() { writer.Write8(0x27); }
|
||||
}
|
||||
|
||||
struct sunPoint
|
||||
{
|
||||
readonly uint offset;
|
||||
public uint Offset { get { return offset; } }
|
||||
|
||||
public sunPoint(uint offset)
|
||||
{
|
||||
this.offset = offset;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue