Parser stuff
This commit is contained in:
parent
7acaa9df76
commit
abbd4a74ef
|
@ -0,0 +1,20 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ShintenScript
|
||||||
|
{
|
||||||
|
public class ASTNodeAdd : ASTNodeBinaryNumericOperator
|
||||||
|
{
|
||||||
|
public ASTNodeAdd(IASTNode lhs, IASTNode rhs) : base(lhs, rhs) { }
|
||||||
|
|
||||||
|
public override object CreateFunction11(Func<ExecutionContext, float> left, Func<ExecutionContext, float> right)
|
||||||
|
{
|
||||||
|
return (Func<ExecutionContext, float>)(ctx => left(ctx) + right(ctx));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string Op() => "+";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ShintenScript
|
||||||
|
{
|
||||||
|
public abstract class ASTNodeBinaryNumericOperator : IASTNode
|
||||||
|
{
|
||||||
|
public IASTNode lhs, rhs;
|
||||||
|
|
||||||
|
protected ASTNodeBinaryNumericOperator(IASTNode lhs, IASTNode rhs)
|
||||||
|
{
|
||||||
|
this.lhs = lhs;
|
||||||
|
this.rhs = rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Const()
|
||||||
|
{
|
||||||
|
return lhs.Const() && rhs.Const();
|
||||||
|
}
|
||||||
|
|
||||||
|
public object CreateFunction()
|
||||||
|
{
|
||||||
|
SSType lhst = lhs.Type();
|
||||||
|
SSType rhst = rhs.Type();
|
||||||
|
|
||||||
|
if (lhst == SSType.real && rhst == SSType.real)
|
||||||
|
{
|
||||||
|
Func<ExecutionContext, float> left = (Func<ExecutionContext, float>)lhs.CreateFunction();
|
||||||
|
Func<ExecutionContext, float> right = (Func<ExecutionContext, float>)rhs.CreateFunction();
|
||||||
|
return CreateFunction11(left, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Exception("This should be unreachable");
|
||||||
|
}
|
||||||
|
|
||||||
|
public SSType Type()
|
||||||
|
{
|
||||||
|
SSType lhst = lhs.Type();
|
||||||
|
SSType rhst = rhs.Type();
|
||||||
|
|
||||||
|
if (lhst == SSType.real && rhst == SSType.real)
|
||||||
|
return SSType.real;
|
||||||
|
|
||||||
|
throw new TypeException($"Unsupported types for operator '{Op()}': {lhst} and {rhst}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract string Op();
|
||||||
|
public abstract object CreateFunction11(Func<ExecutionContext, float> left, Func<ExecutionContext, float> right);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,96 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ShintenScript
|
||||||
|
{
|
||||||
|
public class ASTNodeBlock : IASTNode
|
||||||
|
{
|
||||||
|
public IList<IASTNode> statements;
|
||||||
|
|
||||||
|
public ASTNodeBlock(IList<IASTNode> statements)
|
||||||
|
{
|
||||||
|
this.statements = statements;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IASTNode.Const() => false;
|
||||||
|
|
||||||
|
object IASTNode.CreateFunction()
|
||||||
|
{
|
||||||
|
SSType type = ((IASTNode)this).Type();
|
||||||
|
|
||||||
|
if (type == SSType.none)
|
||||||
|
{
|
||||||
|
List<Action<ExecutionContext>> actions = new List<Action<ExecutionContext>>();
|
||||||
|
|
||||||
|
foreach (IASTNode statement in statements)
|
||||||
|
{
|
||||||
|
object func = statement.CreateFunction();
|
||||||
|
if (func is Action<ExecutionContext> action)
|
||||||
|
actions.Add(action);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Func<ExecutionContext, object> ofunc = (Func<ExecutionContext, object>)func;
|
||||||
|
actions.Add(ctx => ofunc.DynamicInvoke(ctx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (Action<ExecutionContext>)(ctx =>
|
||||||
|
{
|
||||||
|
foreach (Action<ExecutionContext> action in actions)
|
||||||
|
action(ctx);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Action<ExecutionContext>> actionsm1 = new List<Action<ExecutionContext>>();
|
||||||
|
|
||||||
|
foreach (IASTNode statement in statements)
|
||||||
|
{
|
||||||
|
if (actionsm1.Count == statements.Count - 1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
object func = statement.CreateFunction();
|
||||||
|
if (func is Action<ExecutionContext> action)
|
||||||
|
actionsm1.Add(action);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Delegate ofunc = (Delegate)func;
|
||||||
|
actionsm1.Add(ctx => ofunc.DynamicInvoke(ctx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == SSType.real)
|
||||||
|
{
|
||||||
|
Func<ExecutionContext, float> final = (Func<ExecutionContext, float>)statements[statements.Count - 1].CreateFunction();
|
||||||
|
return (Func<ExecutionContext, float>)(ctx =>
|
||||||
|
{
|
||||||
|
foreach (Action<ExecutionContext> action in actionsm1)
|
||||||
|
action(ctx);
|
||||||
|
|
||||||
|
return final(ctx);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == SSType.boolean)
|
||||||
|
{
|
||||||
|
Func<ExecutionContext, bool> final = (Func<ExecutionContext, bool>)statements[statements.Count - 1].CreateFunction();
|
||||||
|
return (Func<ExecutionContext, bool>)(ctx =>
|
||||||
|
{
|
||||||
|
foreach (Action<ExecutionContext> action in actionsm1)
|
||||||
|
action(ctx);
|
||||||
|
|
||||||
|
return final(ctx);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Exception("This should be unreachable");
|
||||||
|
}
|
||||||
|
|
||||||
|
SSType IASTNode.Type()
|
||||||
|
{
|
||||||
|
return statements[statements.Count - 1].Type();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,134 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ShintenScript
|
||||||
|
{
|
||||||
|
public class ASTNodeComparison : IASTNode
|
||||||
|
{
|
||||||
|
public readonly IList<IASTNode> nodes;
|
||||||
|
public readonly IList<Token.Type> comparisons;
|
||||||
|
|
||||||
|
public ASTNodeComparison(IList<IASTNode> nodes, IList<Token.Type> comparisons)
|
||||||
|
{
|
||||||
|
this.nodes = nodes;
|
||||||
|
this.comparisons = comparisons;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Const()
|
||||||
|
{
|
||||||
|
return nodes.All(node => node.Const());
|
||||||
|
}
|
||||||
|
|
||||||
|
public object CreateFunction()
|
||||||
|
{
|
||||||
|
SSType argType = nodes[0].Type();
|
||||||
|
|
||||||
|
if (comparisons.Count == 1)
|
||||||
|
{
|
||||||
|
if (argType == SSType.boolean)
|
||||||
|
{
|
||||||
|
Func<ExecutionContext, bool> left = (Func<ExecutionContext, bool>)nodes[0].CreateFunction();
|
||||||
|
Func<ExecutionContext, bool> right = (Func<ExecutionContext, bool>)nodes[1].CreateFunction();
|
||||||
|
|
||||||
|
switch (comparisons[0])
|
||||||
|
{
|
||||||
|
case Token.Type.EQ: return (Func<ExecutionContext, bool>)(ctx => left(ctx) == right(ctx));
|
||||||
|
case Token.Type.NE: return (Func<ExecutionContext, bool>)(ctx => left(ctx) != right(ctx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argType == SSType.real)
|
||||||
|
{
|
||||||
|
Func<ExecutionContext, float> left = (Func<ExecutionContext, float>)nodes[0].CreateFunction();
|
||||||
|
Func<ExecutionContext, float> right = (Func<ExecutionContext, float>)nodes[1].CreateFunction();
|
||||||
|
|
||||||
|
switch (comparisons[0])
|
||||||
|
{
|
||||||
|
case Token.Type.EQ: return (Func<ExecutionContext, bool>)(ctx => left(ctx) == right(ctx));
|
||||||
|
case Token.Type.NE: return (Func<ExecutionContext, bool>)(ctx => left(ctx) != right(ctx));
|
||||||
|
case Token.Type.LT: return (Func<ExecutionContext, bool>)(ctx => left(ctx) < right(ctx));
|
||||||
|
case Token.Type.GT: return (Func<ExecutionContext, bool>)(ctx => left(ctx) > right(ctx));
|
||||||
|
case Token.Type.LE: return (Func<ExecutionContext, bool>)(ctx => left(ctx) <= right(ctx));
|
||||||
|
case Token.Type.GE: return (Func<ExecutionContext, bool>)(ctx => left(ctx) >= right(ctx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Exception("This should be unreachable");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argType == SSType.boolean)
|
||||||
|
{
|
||||||
|
Func<ExecutionContext, bool>[] args = nodes.Select(node => (Func<ExecutionContext, bool>)node.CreateFunction()).ToArray();
|
||||||
|
|
||||||
|
return (Func<ExecutionContext, bool>)(ctx =>
|
||||||
|
{
|
||||||
|
bool against = args[0](ctx);
|
||||||
|
|
||||||
|
for (int i = 1; i < args.Length; i++)
|
||||||
|
{
|
||||||
|
bool vs = args[i](ctx);
|
||||||
|
|
||||||
|
if ((against == vs) ^ (comparisons[i - 1] == Token.Type.EQ))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
against = vs;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argType == SSType.real)
|
||||||
|
{
|
||||||
|
Func<ExecutionContext, float>[] args = nodes.Select(node => (Func<ExecutionContext, float>)node.CreateFunction()).ToArray();
|
||||||
|
|
||||||
|
return (Func<ExecutionContext, bool>)(ctx =>
|
||||||
|
{
|
||||||
|
float against = args[0](ctx);
|
||||||
|
|
||||||
|
for (int i = 1; i < args.Length; i++)
|
||||||
|
{
|
||||||
|
float vs = args[i](ctx);
|
||||||
|
|
||||||
|
switch (comparisons[i - 1])
|
||||||
|
{
|
||||||
|
case Token.Type.EQ: if (vs != against) return false; break;
|
||||||
|
case Token.Type.NE: if (vs == against) return false; break;
|
||||||
|
case Token.Type.GT: if (vs >= against) return false; break;
|
||||||
|
case Token.Type.LT: if (vs <= against) return false; break;
|
||||||
|
case Token.Type.GE: if (vs > against) return false; break;
|
||||||
|
case Token.Type.LE: if (vs < against) return false; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
against = vs;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Exception("This should be unreachable");
|
||||||
|
}
|
||||||
|
|
||||||
|
public SSType Type()
|
||||||
|
{
|
||||||
|
bool ord = !comparisons.All(cmp => cmp == Token.Type.EQ || cmp == Token.Type.NE);
|
||||||
|
|
||||||
|
SSType argType = nodes[0].Type();
|
||||||
|
|
||||||
|
if (argType == SSType.none)
|
||||||
|
throw new TypeException("Cannot compare null");
|
||||||
|
|
||||||
|
if (nodes.Skip(1).Any(node => node.Type() != argType))
|
||||||
|
throw new TypeException("Cannot compare different types");
|
||||||
|
|
||||||
|
if (ord && argType != SSType.real)
|
||||||
|
throw new TypeException($"Type {argType} cannot be ordered");
|
||||||
|
|
||||||
|
return SSType.boolean;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ShintenScript
|
||||||
|
{
|
||||||
|
public class ASTNodeDivide : ASTNodeBinaryNumericOperator
|
||||||
|
{
|
||||||
|
public ASTNodeDivide(IASTNode lhs, IASTNode rhs) : base(lhs, rhs) { }
|
||||||
|
|
||||||
|
public override object CreateFunction11(Func<ExecutionContext, float> left, Func<ExecutionContext, float> right)
|
||||||
|
{
|
||||||
|
return (Func<ExecutionContext, float>)(ctx => left(ctx) / right(ctx));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string Op() => "/";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ShintenScript
|
||||||
|
{
|
||||||
|
public class ASTNodeLiteral : IASTNode
|
||||||
|
{
|
||||||
|
public readonly object value;
|
||||||
|
|
||||||
|
public ASTNodeLiteral(object value)
|
||||||
|
{
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Const() => true;
|
||||||
|
|
||||||
|
public object CreateFunction()
|
||||||
|
{
|
||||||
|
SSType type = Type();
|
||||||
|
|
||||||
|
if (type == SSType.none) return (Action<ExecutionContext>)(ctx => { });
|
||||||
|
|
||||||
|
if (type == SSType.boolean) return (bool)value ? (Func<ExecutionContext, bool>)(ctx => true) : ctx => false;
|
||||||
|
|
||||||
|
if (type == SSType.real)
|
||||||
|
{
|
||||||
|
float real = (float)value;
|
||||||
|
return (Func<ExecutionContext, float>)(ctx => real);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Exception("This should be unreachable");
|
||||||
|
}
|
||||||
|
|
||||||
|
public SSType Type()
|
||||||
|
{
|
||||||
|
if (value == null) return SSType.none;
|
||||||
|
if (value is bool) return SSType.boolean;
|
||||||
|
if (value is float) return SSType.real;
|
||||||
|
|
||||||
|
throw new Exception("This should be unreachable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ShintenScript
|
||||||
|
{
|
||||||
|
public class ASTNodeMultiply : ASTNodeBinaryNumericOperator
|
||||||
|
{
|
||||||
|
public ASTNodeMultiply(IASTNode lhs, IASTNode rhs) : base(lhs, rhs) { }
|
||||||
|
|
||||||
|
public override object CreateFunction11(Func<ExecutionContext, float> left, Func<ExecutionContext, float> right)
|
||||||
|
{
|
||||||
|
return (Func<ExecutionContext, float>)(ctx => left(ctx) * right(ctx));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string Op() => "*";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ShintenScript
|
||||||
|
{
|
||||||
|
public class ASTNodeNegative : IASTNode
|
||||||
|
{
|
||||||
|
public IASTNode node;
|
||||||
|
|
||||||
|
public ASTNodeNegative(IASTNode of)
|
||||||
|
{
|
||||||
|
node = of;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Const()
|
||||||
|
{
|
||||||
|
return node.Const();
|
||||||
|
}
|
||||||
|
|
||||||
|
public object CreateFunction()
|
||||||
|
{
|
||||||
|
Func<ExecutionContext, float> func = (Func<ExecutionContext, float>)node.CreateFunction();
|
||||||
|
return (Func<ExecutionContext, float>)(ctx => -func(ctx));
|
||||||
|
}
|
||||||
|
|
||||||
|
public SSType Type()
|
||||||
|
{
|
||||||
|
if (node.Type() != SSType.real)
|
||||||
|
throw new TypeException($"Unary '-' operator not supported for {node.Type()}");
|
||||||
|
|
||||||
|
return SSType.real;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ShintenScript
|
||||||
|
{
|
||||||
|
public class ASTNodeSubtract : ASTNodeBinaryNumericOperator
|
||||||
|
{
|
||||||
|
public ASTNodeSubtract(IASTNode lhs, IASTNode rhs) : base(lhs, rhs) { }
|
||||||
|
|
||||||
|
public override object CreateFunction11(Func<ExecutionContext, float> left, Func<ExecutionContext, float> right)
|
||||||
|
{
|
||||||
|
return (Func<ExecutionContext, float>)(ctx => left(ctx) - right(ctx));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string Op() => "-";
|
||||||
|
}
|
||||||
|
}
|
|
@ -390,19 +390,19 @@ a.percentagebar {
|
||||||
<col />
|
<col />
|
||||||
</colgroup>
|
</colgroup>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr><th>Generated on:</th><td>1/27/2023 - 10:02:10 AM</td></tr>
|
<tr><th>Generated on:</th><td>2/2/2023 - 2:01:44 PM</td></tr>
|
||||||
<tr><th>Parser:</th><td>CoberturaParser</td></tr>
|
<tr><th>Parser:</th><td>CoberturaParser</td></tr>
|
||||||
<tr><th>Assemblies:</th><td>2</td></tr>
|
<tr><th>Assemblies:</th><td>2</td></tr>
|
||||||
<tr><th>Classes:</th><td>4</td></tr>
|
<tr><th>Classes:</th><td>20</td></tr>
|
||||||
<tr><th>Files:</th><td>4</td></tr>
|
<tr><th>Files:</th><td>20</td></tr>
|
||||||
<tr><th>Covered lines:</th><td>165</td></tr>
|
<tr><th>Covered lines:</th><td>532</td></tr>
|
||||||
<tr><th>Uncovered lines:</th><td>50</td></tr>
|
<tr><th>Uncovered lines:</th><td>188</td></tr>
|
||||||
<tr><th>Coverable lines:</th><td>215</td></tr>
|
<tr><th>Coverable lines:</th><td>720</td></tr>
|
||||||
<tr><th>Total lines:</th><td>355</td></tr>
|
<tr><th>Total lines:</th><td>1289</td></tr>
|
||||||
<tr><th>Line coverage:</th><td>76.7% (165 of 215)</td></tr>
|
<tr><th>Line coverage:</th><td>73.8% (532 of 720)</td></tr>
|
||||||
<tr><th>Covered branches:</th><td>44</td></tr>
|
<tr><th>Covered branches:</th><td>112</td></tr>
|
||||||
<tr><th>Total branches:</th><td>68</td></tr>
|
<tr><th>Total branches:</th><td>232</td></tr>
|
||||||
<tr><th>Branch coverage:</th><td>64.7% (44 of 68)</td></tr>
|
<tr><th>Branch coverage:</th><td>48.2% (112 of 232)</td></tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<h1>Risk Hotspots</h1>
|
<h1>Risk Hotspots</h1>
|
||||||
|
@ -427,16 +427,32 @@ a.percentagebar {
|
||||||
</colgroup>
|
</colgroup>
|
||||||
<thead><tr><th>Name</th><th class="right">Covered</th><th class="right">Uncovered</th><th class="right">Coverable</th><th class="right">Total</th><th class="center" colspan="2">Line coverage</th><th class="right">Covered</th><th class="right">Total</th><th class="center" colspan="2">Branch coverage</th></tr></thead>
|
<thead><tr><th>Name</th><th class="right">Covered</th><th class="right">Uncovered</th><th class="right">Coverable</th><th class="right">Total</th><th class="center" colspan="2">Line coverage</th><th class="right">Covered</th><th class="right">Total</th><th class="center" colspan="2">Branch coverage</th></tr></thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr><th>ShintenScript</th><th class="right">113</th><th class="right">50</th><th class="right">163</th><th class="right">288</th><th title="LineCoverage: 113/163" class="right">69.3%</th><th><table class="coverage"><tr><td class="green covered69"> </td><td class="red covered31"> </td></tr></table></th><th class="right">44</th><th class="right">68</th><th class="right" title="44/68">64.7%</th><th><table class="coverage"><tr><td class="green covered65"> </td><td class="red covered35"> </td></tr></table></th></tr>
|
<tr><th>ShintenScript</th><th class="right">320</th><th class="right">181</th><th class="right">501</th><th class="right">939</th><th title="LineCoverage: 320/501" class="right">63.8%</th><th><table class="coverage"><tr><td class="green covered64"> </td><td class="red covered36"> </td></tr></table></th><th class="right">103</th><th class="right">216</th><th class="right" title="103/216">47.6%</th><th><table class="coverage"><tr><td class="green covered48"> </td><td class="red covered52"> </td></tr></table></th></tr>
|
||||||
<tr><td><a href="ShintenScript_Lexer.html">ShintenScript.Lexer</a></td><td class="right">105</td><td class="right">40</td><td class="right">145</td><td class="right">217</td><td title="LineCoverage: 105/145" class="right">72.4%</td><td><table class="coverage"><tr><td class="green covered72"> </td><td class="red covered28"> </td></tr></table></td><td class="right">35</td><td class="right">50</td><td class="right" title="35/50">70%</td><td><table class="coverage"><tr><td class="green covered70"> </td><td class="red covered30"> </td></tr></table></td></tr>
|
<tr><td><a href="ShintenScript_ASTNodeAdd.html">ShintenScript.ASTNodeAdd</a></td><td class="right">4</td><td class="right">1</td><td class="right">5</td><td class="right">20</td><td title="LineCoverage: 4/5" class="right">80%</td><td><table class="coverage"><tr><td class="green covered80"> </td><td class="red covered20"> </td></tr></table></td><td class="right">0</td><td class="right">0</td><td class="right" title="-"></td><td><table class="coverage"><tr><td class="gray covered100"> </td></tr></table></td></tr>
|
||||||
|
<tr><td><a href="ShintenScript_ASTNodeBinaryNumericOperator.html">ShintenScript.ASTNodeBinaryNumericOperator</a></td><td class="right">20</td><td class="right">5</td><td class="right">25</td><td class="right">53</td><td title="LineCoverage: 20/25" class="right">80%</td><td><table class="coverage"><tr><td class="green covered80"> </td><td class="red covered20"> </td></tr></table></td><td class="right">4</td><td class="right">10</td><td class="right" title="4/10">40%</td><td><table class="coverage"><tr><td class="green covered40"> </td><td class="red covered60"> </td></tr></table></td></tr>
|
||||||
|
<tr><td><a href="ShintenScript_ASTNodeBlock.html">ShintenScript.ASTNodeBlock</a></td><td class="right">33</td><td class="right">30</td><td class="right">63</td><td class="right">96</td><td title="LineCoverage: 33/63" class="right">52.3%</td><td><table class="coverage"><tr><td class="green covered52"> </td><td class="red covered48"> </td></tr></table></td><td class="right">5</td><td class="right">12</td><td class="right" title="5/12">41.6%</td><td><table class="coverage"><tr><td class="green covered42"> </td><td class="red covered58"> </td></tr></table></td></tr>
|
||||||
|
<tr><td><a href="ShintenScript_ASTNodeComparison.html">ShintenScript.ASTNodeComparison</a></td><td class="right">5</td><td class="right">86</td><td class="right">91</td><td class="right">134</td><td title="LineCoverage: 5/91" class="right">5.4%</td><td><table class="coverage"><tr><td class="green covered5"> </td><td class="red covered95"> </td></tr></table></td><td class="right">0</td><td class="right">64</td><td class="right" title="0/64">0%</td><td><table class="coverage"><tr><td class="red covered100"> </td></tr></table></td></tr>
|
||||||
|
<tr><td><a href="ShintenScript_ASTNodeDivide.html">ShintenScript.ASTNodeDivide</a></td><td class="right">4</td><td class="right">1</td><td class="right">5</td><td class="right">20</td><td title="LineCoverage: 4/5" class="right">80%</td><td><table class="coverage"><tr><td class="green covered80"> </td><td class="red covered20"> </td></tr></table></td><td class="right">0</td><td class="right">0</td><td class="right" title="-"></td><td><table class="coverage"><tr><td class="gray covered100"> </td></tr></table></td></tr>
|
||||||
|
<tr><td><a href="ShintenScript_ASTNodeLiteral.html">ShintenScript.ASTNodeLiteral</a></td><td class="right">18</td><td class="right">3</td><td class="right">21</td><td class="right">46</td><td title="LineCoverage: 18/21" class="right">85.7%</td><td><table class="coverage"><tr><td class="green covered86"> </td><td class="red covered14"> </td></tr></table></td><td class="right">10</td><td class="right">20</td><td class="right" title="10/20">50%</td><td><table class="coverage"><tr><td class="green covered50"> </td><td class="red covered50"> </td></tr></table></td></tr>
|
||||||
|
<tr><td><a href="ShintenScript_ASTNodeMultiply.html">ShintenScript.ASTNodeMultiply</a></td><td class="right">4</td><td class="right">1</td><td class="right">5</td><td class="right">20</td><td title="LineCoverage: 4/5" class="right">80%</td><td><table class="coverage"><tr><td class="green covered80"> </td><td class="red covered20"> </td></tr></table></td><td class="right">0</td><td class="right">0</td><td class="right" title="-"></td><td><table class="coverage"><tr><td class="gray covered100"> </td></tr></table></td></tr>
|
||||||
|
<tr><td><a href="ShintenScript_ASTNodeNegative.html">ShintenScript.ASTNodeNegative</a></td><td class="right">12</td><td class="right">4</td><td class="right">16</td><td class="right">37</td><td title="LineCoverage: 12/16" class="right">75%</td><td><table class="coverage"><tr><td class="green covered75"> </td><td class="red covered25"> </td></tr></table></td><td class="right">1</td><td class="right">2</td><td class="right" title="1/2">50%</td><td><table class="coverage"><tr><td class="green covered50"> </td><td class="red covered50"> </td></tr></table></td></tr>
|
||||||
|
<tr><td><a href="ShintenScript_ASTNodeSubtract.html">ShintenScript.ASTNodeSubtract</a></td><td class="right">4</td><td class="right">1</td><td class="right">5</td><td class="right">20</td><td title="LineCoverage: 4/5" class="right">80%</td><td><table class="coverage"><tr><td class="green covered80"> </td><td class="red covered20"> </td></tr></table></td><td class="right">0</td><td class="right">0</td><td class="right" title="-"></td><td><table class="coverage"><tr><td class="gray covered100"> </td></tr></table></td></tr>
|
||||||
|
<tr><td><a href="ShintenScript_Lexer.html">ShintenScript.Lexer</a></td><td class="right">132</td><td class="right">20</td><td class="right">152</td><td class="right">228</td><td title="LineCoverage: 132/152" class="right">86.8%</td><td><table class="coverage"><tr><td class="green covered87"> </td><td class="red covered13"> </td></tr></table></td><td class="right">51</td><td class="right">62</td><td class="right" title="51/62">82.2%</td><td><table class="coverage"><tr><td class="green covered82"> </td><td class="red covered18"> </td></tr></table></td></tr>
|
||||||
<tr><td><a href="ShintenScript_LexingException.html">ShintenScript.LexingException</a></td><td class="right">0</td><td class="right">3</td><td class="right">3</td><td class="right">16</td><td title="LineCoverage: 0/3" class="right">0%</td><td><table class="coverage"><tr><td class="red covered100"> </td></tr></table></td><td class="right">0</td><td class="right">0</td><td class="right" title="-"></td><td><table class="coverage"><tr><td class="gray covered100"> </td></tr></table></td></tr>
|
<tr><td><a href="ShintenScript_LexingException.html">ShintenScript.LexingException</a></td><td class="right">0</td><td class="right">3</td><td class="right">3</td><td class="right">16</td><td title="LineCoverage: 0/3" class="right">0%</td><td><table class="coverage"><tr><td class="red covered100"> </td></tr></table></td><td class="right">0</td><td class="right">0</td><td class="right" title="-"></td><td><table class="coverage"><tr><td class="gray covered100"> </td></tr></table></td></tr>
|
||||||
<tr><td><a href="ShintenScript_Token.html">ShintenScript.Token</a></td><td class="right">8</td><td class="right">7</td><td class="right">15</td><td class="right">55</td><td title="LineCoverage: 8/15" class="right">53.3%</td><td><table class="coverage"><tr><td class="green covered53"> </td><td class="red covered47"> </td></tr></table></td><td class="right">9</td><td class="right">18</td><td class="right" title="9/18">50%</td><td><table class="coverage"><tr><td class="green covered50"> </td><td class="red covered50"> </td></tr></table></td></tr>
|
<tr><td><a href="ShintenScript_Parser.html">ShintenScript.Parser</a></td><td class="right">73</td><td class="right">13</td><td class="right">86</td><td class="right">146</td><td title="LineCoverage: 73/86" class="right">84.8%</td><td><table class="coverage"><tr><td class="green covered85"> </td><td class="red covered15"> </td></tr></table></td><td class="right">23</td><td class="right">28</td><td class="right" title="23/28">82.1%</td><td><table class="coverage"><tr><td class="green covered82"> </td><td class="red covered18"> </td></tr></table></td></tr>
|
||||||
<tr><th>ShintenScriptTest</th><th class="right">52</th><th class="right">0</th><th class="right">52</th><th class="right">67</th><th title="LineCoverage: 52/52" class="right">100%</th><th><table class="coverage"><tr><td class="green covered100"> </td></tr></table></th><th class="right">0</th><th class="right">0</th><th class="right" title="-"></th><th><table class="coverage"><tr><td class="gray covered100"> </td></tr></table></th></tr>
|
<tr><td><a href="ShintenScript_ParsingException.html">ShintenScript.ParsingException</a></td><td class="right">0</td><td class="right">3</td><td class="right">3</td><td class="right">16</td><td title="LineCoverage: 0/3" class="right">0%</td><td><table class="coverage"><tr><td class="red covered100"> </td></tr></table></td><td class="right">0</td><td class="right">0</td><td class="right" title="-"></td><td><table class="coverage"><tr><td class="gray covered100"> </td></tr></table></td></tr>
|
||||||
<tr><td><a href="ShintenScriptTest_LexerTests.html">ShintenScriptTest.LexerTests</a></td><td class="right">52</td><td class="right">0</td><td class="right">52</td><td class="right">67</td><td title="LineCoverage: 52/52" class="right">100%</td><td><table class="coverage"><tr><td class="green covered100"> </td></tr></table></td><td class="right">0</td><td class="right">0</td><td class="right" title="-"></td><td><table class="coverage"><tr><td class="gray covered100"> </td></tr></table></td></tr>
|
<tr><td><a href="ShintenScript_SSType.html">ShintenScript.SSType</a></td><td class="right">3</td><td class="right">0</td><td class="right">3</td><td class="right">15</td><td title="LineCoverage: 3/3" class="right">100%</td><td><table class="coverage"><tr><td class="green covered100"> </td></tr></table></td><td class="right">0</td><td class="right">0</td><td class="right" title="-"></td><td><table class="coverage"><tr><td class="gray covered100"> </td></tr></table></td></tr>
|
||||||
|
<tr><td><a href="ShintenScript_Token.html">ShintenScript.Token</a></td><td class="right">8</td><td class="right">7</td><td class="right">15</td><td class="right">56</td><td title="LineCoverage: 8/15" class="right">53.3%</td><td><table class="coverage"><tr><td class="green covered53"> </td><td class="red covered47"> </td></tr></table></td><td class="right">9</td><td class="right">18</td><td class="right" title="9/18">50%</td><td><table class="coverage"><tr><td class="green covered50"> </td><td class="red covered50"> </td></tr></table></td></tr>
|
||||||
|
<tr><td><a href="ShintenScript_TypeException.html">ShintenScript.TypeException</a></td><td class="right">0</td><td class="right">3</td><td class="right">3</td><td class="right">16</td><td title="LineCoverage: 0/3" class="right">0%</td><td><table class="coverage"><tr><td class="red covered100"> </td></tr></table></td><td class="right">0</td><td class="right">0</td><td class="right" title="-"></td><td><table class="coverage"><tr><td class="gray covered100"> </td></tr></table></td></tr>
|
||||||
|
<tr><th>ShintenScriptTest</th><th class="right">212</th><th class="right">7</th><th class="right">219</th><th class="right">350</th><th title="LineCoverage: 212/219" class="right">96.8%</th><th><table class="coverage"><tr><td class="green covered97"> </td><td class="red covered3"> </td></tr></table></th><th class="right">9</th><th class="right">16</th><th class="right" title="9/16">56.2%</th><th><table class="coverage"><tr><td class="green covered56"> </td><td class="red covered44"> </td></tr></table></th></tr>
|
||||||
|
<tr><td><a href="ShintenScriptTest_EvaluationTest.html">ShintenScriptTest.EvaluationTest</a></td><td class="right">41</td><td class="right">0</td><td class="right">41</td><td class="right">91</td><td title="LineCoverage: 41/41" class="right">100%</td><td><table class="coverage"><tr><td class="green covered100"> </td></tr></table></td><td class="right">0</td><td class="right">0</td><td class="right" title="-"></td><td><table class="coverage"><tr><td class="gray covered100"> </td></tr></table></td></tr>
|
||||||
|
<tr><td><a href="ShintenScriptTest_LexerTests.html">ShintenScriptTest.LexerTests</a></td><td class="right">60</td><td class="right">0</td><td class="right">60</td><td class="right">79</td><td title="LineCoverage: 60/60" class="right">100%</td><td><table class="coverage"><tr><td class="green covered100"> </td></tr></table></td><td class="right">0</td><td class="right">0</td><td class="right" title="-"></td><td><table class="coverage"><tr><td class="gray covered100"> </td></tr></table></td></tr>
|
||||||
|
<tr><td><a href="ShintenScriptTest_ParserTest.html">ShintenScriptTest.ParserTest</a></td><td class="right">102</td><td class="right">7</td><td class="right">109</td><td class="right">153</td><td title="LineCoverage: 102/109" class="right">93.5%</td><td><table class="coverage"><tr><td class="green covered94"> </td><td class="red covered6"> </td></tr></table></td><td class="right">7</td><td class="right">14</td><td class="right" title="7/14">50%</td><td><table class="coverage"><tr><td class="green covered50"> </td><td class="red covered50"> </td></tr></table></td></tr>
|
||||||
|
<tr><td><a href="ShintenScriptTest_ScaffoldLexer.html">ShintenScriptTest.ScaffoldLexer</a></td><td class="right">9</td><td class="right">0</td><td class="right">9</td><td class="right">27</td><td title="LineCoverage: 9/9" class="right">100%</td><td><table class="coverage"><tr><td class="green covered100"> </td></tr></table></td><td class="right">2</td><td class="right">2</td><td class="right" title="2/2">100%</td><td><table class="coverage"><tr><td class="green covered100"> </td></tr></table></td></tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</coverage-info>
|
</coverage-info>
|
||||||
<div class="footer">Generated by: ReportGenerator 4.7.1.0<br />1/27/2023 - 10:02:10 AM<br /><a href="https://github.com/danielpalme/ReportGenerator">GitHub</a> | <a href="http://www.palmmedia.de">www.palmmedia.de</a></div></div></div>
|
<div class="footer">Generated by: ReportGenerator 4.7.1.0<br />2/2/2023 - 2:01:44 PM<br /><a href="https://github.com/danielpalme/ReportGenerator">GitHub</a> | <a href="http://www.palmmedia.de">www.palmmedia.de</a></div></div></div>
|
||||||
<script type="text/javascript">/* <![CDATA[ */ /* Chartist.js 0.11.0
|
<script type="text/javascript">/* <![CDATA[ */ /* Chartist.js 0.11.0
|
||||||
* Copyright © 2017 Gion Kunz
|
* Copyright © 2017 Gion Kunz
|
||||||
* Free to use under either the WTFPL license or the MIT license.
|
* Free to use under either the WTFPL license or the MIT license.
|
||||||
|
@ -663,14 +679,30 @@ var assemblies = [
|
||||||
{
|
{
|
||||||
"name": "ShintenScript",
|
"name": "ShintenScript",
|
||||||
"classes": [
|
"classes": [
|
||||||
{ "name": "ShintenScript.Lexer", "rp": "ShintenScript_Lexer.html", "cl": 105, "ucl": 40, "cal": 145, "tl": 217, "ct": "LineCoverage", "mc": "-", "cb": 35, "tb": 50, "lch": [], "bch": [], "hc": [] },
|
{ "name": "ShintenScript.ASTNodeAdd", "rp": "ShintenScript_ASTNodeAdd.html", "cl": 4, "ucl": 1, "cal": 5, "tl": 20, "ct": "LineCoverage", "mc": "-", "cb": 0, "tb": 0, "lch": [], "bch": [], "hc": [] },
|
||||||
|
{ "name": "ShintenScript.ASTNodeBinaryNumericOperator", "rp": "ShintenScript_ASTNodeBinaryNumericOperator.html", "cl": 20, "ucl": 5, "cal": 25, "tl": 53, "ct": "LineCoverage", "mc": "-", "cb": 4, "tb": 10, "lch": [], "bch": [], "hc": [] },
|
||||||
|
{ "name": "ShintenScript.ASTNodeBlock", "rp": "ShintenScript_ASTNodeBlock.html", "cl": 33, "ucl": 30, "cal": 63, "tl": 96, "ct": "LineCoverage", "mc": "-", "cb": 5, "tb": 12, "lch": [], "bch": [], "hc": [] },
|
||||||
|
{ "name": "ShintenScript.ASTNodeComparison", "rp": "ShintenScript_ASTNodeComparison.html", "cl": 5, "ucl": 86, "cal": 91, "tl": 134, "ct": "LineCoverage", "mc": "-", "cb": 0, "tb": 64, "lch": [], "bch": [], "hc": [] },
|
||||||
|
{ "name": "ShintenScript.ASTNodeDivide", "rp": "ShintenScript_ASTNodeDivide.html", "cl": 4, "ucl": 1, "cal": 5, "tl": 20, "ct": "LineCoverage", "mc": "-", "cb": 0, "tb": 0, "lch": [], "bch": [], "hc": [] },
|
||||||
|
{ "name": "ShintenScript.ASTNodeLiteral", "rp": "ShintenScript_ASTNodeLiteral.html", "cl": 18, "ucl": 3, "cal": 21, "tl": 46, "ct": "LineCoverage", "mc": "-", "cb": 10, "tb": 20, "lch": [], "bch": [], "hc": [] },
|
||||||
|
{ "name": "ShintenScript.ASTNodeMultiply", "rp": "ShintenScript_ASTNodeMultiply.html", "cl": 4, "ucl": 1, "cal": 5, "tl": 20, "ct": "LineCoverage", "mc": "-", "cb": 0, "tb": 0, "lch": [], "bch": [], "hc": [] },
|
||||||
|
{ "name": "ShintenScript.ASTNodeNegative", "rp": "ShintenScript_ASTNodeNegative.html", "cl": 12, "ucl": 4, "cal": 16, "tl": 37, "ct": "LineCoverage", "mc": "-", "cb": 1, "tb": 2, "lch": [], "bch": [], "hc": [] },
|
||||||
|
{ "name": "ShintenScript.ASTNodeSubtract", "rp": "ShintenScript_ASTNodeSubtract.html", "cl": 4, "ucl": 1, "cal": 5, "tl": 20, "ct": "LineCoverage", "mc": "-", "cb": 0, "tb": 0, "lch": [], "bch": [], "hc": [] },
|
||||||
|
{ "name": "ShintenScript.Lexer", "rp": "ShintenScript_Lexer.html", "cl": 132, "ucl": 20, "cal": 152, "tl": 228, "ct": "LineCoverage", "mc": "-", "cb": 51, "tb": 62, "lch": [], "bch": [], "hc": [] },
|
||||||
{ "name": "ShintenScript.LexingException", "rp": "ShintenScript_LexingException.html", "cl": 0, "ucl": 3, "cal": 3, "tl": 16, "ct": "LineCoverage", "mc": "-", "cb": 0, "tb": 0, "lch": [], "bch": [], "hc": [] },
|
{ "name": "ShintenScript.LexingException", "rp": "ShintenScript_LexingException.html", "cl": 0, "ucl": 3, "cal": 3, "tl": 16, "ct": "LineCoverage", "mc": "-", "cb": 0, "tb": 0, "lch": [], "bch": [], "hc": [] },
|
||||||
{ "name": "ShintenScript.Token", "rp": "ShintenScript_Token.html", "cl": 8, "ucl": 7, "cal": 15, "tl": 55, "ct": "LineCoverage", "mc": "-", "cb": 9, "tb": 18, "lch": [], "bch": [], "hc": [] },
|
{ "name": "ShintenScript.Parser", "rp": "ShintenScript_Parser.html", "cl": 73, "ucl": 13, "cal": 86, "tl": 146, "ct": "LineCoverage", "mc": "-", "cb": 23, "tb": 28, "lch": [], "bch": [], "hc": [] },
|
||||||
|
{ "name": "ShintenScript.ParsingException", "rp": "ShintenScript_ParsingException.html", "cl": 0, "ucl": 3, "cal": 3, "tl": 16, "ct": "LineCoverage", "mc": "-", "cb": 0, "tb": 0, "lch": [], "bch": [], "hc": [] },
|
||||||
|
{ "name": "ShintenScript.SSType", "rp": "ShintenScript_SSType.html", "cl": 3, "ucl": 0, "cal": 3, "tl": 15, "ct": "LineCoverage", "mc": "-", "cb": 0, "tb": 0, "lch": [], "bch": [], "hc": [] },
|
||||||
|
{ "name": "ShintenScript.Token", "rp": "ShintenScript_Token.html", "cl": 8, "ucl": 7, "cal": 15, "tl": 56, "ct": "LineCoverage", "mc": "-", "cb": 9, "tb": 18, "lch": [], "bch": [], "hc": [] },
|
||||||
|
{ "name": "ShintenScript.TypeException", "rp": "ShintenScript_TypeException.html", "cl": 0, "ucl": 3, "cal": 3, "tl": 16, "ct": "LineCoverage", "mc": "-", "cb": 0, "tb": 0, "lch": [], "bch": [], "hc": [] },
|
||||||
]},
|
]},
|
||||||
{
|
{
|
||||||
"name": "ShintenScriptTest",
|
"name": "ShintenScriptTest",
|
||||||
"classes": [
|
"classes": [
|
||||||
{ "name": "ShintenScriptTest.LexerTests", "rp": "ShintenScriptTest_LexerTests.html", "cl": 52, "ucl": 0, "cal": 52, "tl": 67, "ct": "LineCoverage", "mc": "-", "cb": 0, "tb": 0, "lch": [], "bch": [], "hc": [] },
|
{ "name": "ShintenScriptTest.EvaluationTest", "rp": "ShintenScriptTest_EvaluationTest.html", "cl": 41, "ucl": 0, "cal": 41, "tl": 91, "ct": "LineCoverage", "mc": "-", "cb": 0, "tb": 0, "lch": [], "bch": [], "hc": [] },
|
||||||
|
{ "name": "ShintenScriptTest.LexerTests", "rp": "ShintenScriptTest_LexerTests.html", "cl": 60, "ucl": 0, "cal": 60, "tl": 79, "ct": "LineCoverage", "mc": "-", "cb": 0, "tb": 0, "lch": [], "bch": [], "hc": [] },
|
||||||
|
{ "name": "ShintenScriptTest.ParserTest", "rp": "ShintenScriptTest_ParserTest.html", "cl": 102, "ucl": 7, "cal": 109, "tl": 153, "ct": "LineCoverage", "mc": "-", "cb": 7, "tb": 14, "lch": [], "bch": [], "hc": [] },
|
||||||
|
{ "name": "ShintenScriptTest.ScaffoldLexer", "rp": "ShintenScriptTest_ScaffoldLexer.html", "cl": 9, "ucl": 0, "cal": 9, "tl": 27, "ct": "LineCoverage", "mc": "-", "cb": 2, "tb": 2, "lch": [], "bch": [], "hc": [] },
|
||||||
]},
|
]},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ShintenScript
|
||||||
|
{
|
||||||
|
public class ExecutionContext
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ShintenScript
|
||||||
|
{
|
||||||
|
public interface IASTNode
|
||||||
|
{
|
||||||
|
bool Const();
|
||||||
|
SSType Type();
|
||||||
|
//IASTNode OptPass1();
|
||||||
|
object CreateFunction();
|
||||||
|
}
|
||||||
|
}
|
27
Lexer.cs
27
Lexer.cs
|
@ -20,6 +20,7 @@ namespace ShintenScript
|
||||||
("*=", Token.Type.ASTERISKASSIGN),
|
("*=", Token.Type.ASTERISKASSIGN),
|
||||||
("/=", Token.Type.SLASHASSIGN),
|
("/=", Token.Type.SLASHASSIGN),
|
||||||
|
|
||||||
|
(";", Token.Type.SEMICOLON),
|
||||||
("+", Token.Type.PLUS),
|
("+", Token.Type.PLUS),
|
||||||
("-", Token.Type.MINUS),
|
("-", Token.Type.MINUS),
|
||||||
("*", Token.Type.ASTERISK),
|
("*", Token.Type.ASTERISK),
|
||||||
|
@ -51,7 +52,7 @@ namespace ShintenScript
|
||||||
|
|
||||||
Token current = new Token { type = Token.Type.NULL };
|
Token current = new Token { type = Token.Type.NULL };
|
||||||
|
|
||||||
Token ParseOne()
|
public virtual Token ParseOne()
|
||||||
{
|
{
|
||||||
if (EOF())
|
if (EOF())
|
||||||
return new Token { type = Token.Type.EOF };
|
return new Token { type = Token.Type.EOF };
|
||||||
|
@ -77,7 +78,7 @@ namespace ShintenScript
|
||||||
{
|
{
|
||||||
StringBuilder identifierBuilder = new StringBuilder();
|
StringBuilder identifierBuilder = new StringBuilder();
|
||||||
|
|
||||||
while (char.IsLetterOrDigit(code[index]))
|
while (!EOF() && char.IsLetterOrDigit(code[index]))
|
||||||
{
|
{
|
||||||
identifierBuilder.Append(code[index]);
|
identifierBuilder.Append(code[index]);
|
||||||
index++;
|
index++;
|
||||||
|
@ -97,10 +98,15 @@ namespace ShintenScript
|
||||||
if (char.IsNumber(code[index]))
|
if (char.IsNumber(code[index]))
|
||||||
{
|
{
|
||||||
StringBuilder numberBuilder = new StringBuilder();
|
StringBuilder numberBuilder = new StringBuilder();
|
||||||
|
bool seenLetter = false;
|
||||||
|
|
||||||
while (char.IsLetterOrDigit(code[index]) || code[index] == '.' || (code[index] == '-' && (code[index - 1] == 'e' || code[index - 1] == 'E')))
|
while (!EOF() && (char.IsLetterOrDigit(code[index]) || code[index] == '.' || (!seenLetter && code[index] == '-' && (code[index - 1] == 'e' || code[index - 1] == 'E'))))
|
||||||
{
|
{
|
||||||
numberBuilder.Append(code[index]);
|
numberBuilder.Append(code[index]);
|
||||||
|
|
||||||
|
if (char.IsLetter(code[index]) && code[index] != 'e' && code[index] != 'E')
|
||||||
|
seenLetter = true;
|
||||||
|
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,24 +193,29 @@ namespace ShintenScript
|
||||||
|
|
||||||
if (types.Length == 1)
|
if (types.Length == 1)
|
||||||
{
|
{
|
||||||
throw new LexingException($"Encountered {token.type} when expecting {types[0]}");
|
throw new ParsingException($"Encountered {token.type} when expecting {types[0]}");
|
||||||
}
|
}
|
||||||
else if (types.Length == 2)
|
else if (types.Length == 2)
|
||||||
{
|
{
|
||||||
throw new LexingException($"Encountered {token.type} when expecting one of {types[0]} or {types[1]}");
|
throw new ParsingException($"Encountered {token.type} when expecting one of {types[0]} or {types[1]}");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
string list = string.Join(", ", types.Take(types.Length - 1));
|
string list = string.Join(", ", types.Take(types.Length - 1));
|
||||||
throw new LexingException($"Encountered {token.type} when expecting one of {list}, or {types[types.Length - 1]}");
|
throw new ParsingException($"Encountered {token.type} when expecting one of {list}, or {types[types.Length - 1]}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<Token> TokenStream()
|
public IEnumerable<Token> TokenStream()
|
||||||
{
|
{
|
||||||
while (!EOF())
|
while (true)
|
||||||
{
|
{
|
||||||
yield return Pop();
|
Token token = Pop();
|
||||||
|
|
||||||
|
if (token.type == Token.Type.EOF)
|
||||||
|
break;
|
||||||
|
|
||||||
|
yield return token;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,146 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ShintenScript
|
||||||
|
{
|
||||||
|
public class Parser
|
||||||
|
{
|
||||||
|
protected readonly Lexer lexer;
|
||||||
|
|
||||||
|
public Parser(Lexer lexer)
|
||||||
|
{
|
||||||
|
this.lexer = lexer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IASTNode ParseExpression()
|
||||||
|
{
|
||||||
|
if (lexer.Accept(Token.Type.SEMICOLON))
|
||||||
|
{
|
||||||
|
lexer.Pop();
|
||||||
|
return new ASTNodeLiteral(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ParseExpressionAssignLevel();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IASTNode ParseExpressionAssignLevel()
|
||||||
|
{
|
||||||
|
IASTNode lhs = ParseExpressionComparisonLevel();
|
||||||
|
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IASTNode ParseExpressionComparisonLevel()
|
||||||
|
{
|
||||||
|
List<IASTNode> nodes = new List<IASTNode>();
|
||||||
|
List<Token.Type> comparisons = new List<Token.Type>();
|
||||||
|
|
||||||
|
nodes.Add(ParseExpressionAdditiveLevel());
|
||||||
|
|
||||||
|
while (lexer.Accept(Token.Type.EQ, Token.Type.NE, Token.Type.LT, Token.Type.GT, Token.Type.LE, Token.Type.GE))
|
||||||
|
{
|
||||||
|
comparisons.Add(lexer.Pop().type);
|
||||||
|
nodes.Add(ParseExpressionAdditiveLevel());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nodes.Count == 1)
|
||||||
|
return nodes[0];
|
||||||
|
|
||||||
|
return new ASTNodeComparison(nodes, comparisons);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IASTNode ParseExpressionAdditiveLevel()
|
||||||
|
{
|
||||||
|
IASTNode lhs = ParseExpressionMultiplicativeLevel();
|
||||||
|
|
||||||
|
if (lexer.Accept(Token.Type.PLUS, Token.Type.MINUS))
|
||||||
|
{
|
||||||
|
bool isAddition = lexer.Pop().type == Token.Type.PLUS;
|
||||||
|
IASTNode rhs = ParseExpressionAdditiveLevel();
|
||||||
|
|
||||||
|
if (isAddition)
|
||||||
|
return new ASTNodeAdd(lhs, rhs);
|
||||||
|
else
|
||||||
|
return new ASTNodeSubtract(lhs, rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IASTNode ParseExpressionMultiplicativeLevel()
|
||||||
|
{
|
||||||
|
IASTNode lhs = ParseExpressionWithPrefix();
|
||||||
|
|
||||||
|
if (lexer.Accept(Token.Type.ASTERISK, Token.Type.SLASH))
|
||||||
|
{
|
||||||
|
bool isMultiplication = lexer.Pop().type == Token.Type.ASTERISK;
|
||||||
|
IASTNode rhs = ParseExpressionMultiplicativeLevel();
|
||||||
|
|
||||||
|
if (isMultiplication)
|
||||||
|
return new ASTNodeMultiply(lhs, rhs);
|
||||||
|
else
|
||||||
|
return new ASTNodeDivide(lhs, rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IASTNode ParseExpressionWithPrefix()
|
||||||
|
{
|
||||||
|
if (lexer.Accept(Token.Type.PLUS))
|
||||||
|
lexer.Pop();
|
||||||
|
|
||||||
|
if (lexer.Accept(Token.Type.MINUS))
|
||||||
|
{
|
||||||
|
lexer.Pop();
|
||||||
|
return new ASTNodeNegative(ParseExpressionPrimary());
|
||||||
|
}
|
||||||
|
|
||||||
|
return ParseExpressionPrimary();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IASTNode ParseExpressionPrimary()
|
||||||
|
{
|
||||||
|
if (lexer.Accept(Token.Type.NUMBER))
|
||||||
|
return new ASTNodeLiteral(lexer.Pop().data);
|
||||||
|
|
||||||
|
if (lexer.Accept(Token.Type.LPAREN))
|
||||||
|
return ParseExpressionParenthesised();
|
||||||
|
|
||||||
|
if (lexer.Accept(Token.Type.LBRACE))
|
||||||
|
return ParseBlock();
|
||||||
|
|
||||||
|
throw new ParsingException("Expected expression");
|
||||||
|
}
|
||||||
|
|
||||||
|
public IASTNode ParseExpressionParenthesised()
|
||||||
|
{
|
||||||
|
lexer.Expect(Token.Type.LPAREN);
|
||||||
|
IASTNode expression = ParseExpression();
|
||||||
|
lexer.Expect(Token.Type.RPAREN);
|
||||||
|
return expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IASTNode ParseBlock()
|
||||||
|
{
|
||||||
|
lexer.Expect(Token.Type.LBRACE);
|
||||||
|
|
||||||
|
List<IASTNode> statements = new List<IASTNode>();
|
||||||
|
|
||||||
|
while (!lexer.Accept(Token.Type.RBRACE))
|
||||||
|
{
|
||||||
|
statements.Add(ParseExpression());
|
||||||
|
}
|
||||||
|
|
||||||
|
lexer.Pop();
|
||||||
|
|
||||||
|
if (statements.Count == 0)
|
||||||
|
return new ASTNodeLiteral(null);
|
||||||
|
|
||||||
|
return new ASTNodeBlock(statements);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ShintenScript
|
||||||
|
{
|
||||||
|
public class ParsingException : Exception
|
||||||
|
{
|
||||||
|
public ParsingException(string message) : base(message)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ShintenScript
|
||||||
|
{
|
||||||
|
public class SSType
|
||||||
|
{
|
||||||
|
public static readonly SSType none = new SSType();
|
||||||
|
public static readonly SSType real = new SSType();
|
||||||
|
public static readonly SSType boolean = new SSType();
|
||||||
|
}
|
||||||
|
}
|
|
@ -41,10 +41,25 @@
|
||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="ASTNodeAdd.cs" />
|
||||||
|
<Compile Include="ASTNodeBinaryNumericOperator.cs" />
|
||||||
|
<Compile Include="ASTNodeBlock.cs" />
|
||||||
|
<Compile Include="ASTNodeComparison.cs" />
|
||||||
|
<Compile Include="ASTNodeDivide.cs" />
|
||||||
|
<Compile Include="ASTNodeLiteral.cs" />
|
||||||
|
<Compile Include="ASTNodeMultiply.cs" />
|
||||||
|
<Compile Include="ASTNodeNegative.cs" />
|
||||||
|
<Compile Include="ASTNodeSubtract.cs" />
|
||||||
|
<Compile Include="ExecutionContext.cs" />
|
||||||
|
<Compile Include="IASTNode.cs" />
|
||||||
<Compile Include="Lexer.cs" />
|
<Compile Include="Lexer.cs" />
|
||||||
<Compile Include="LexingException.cs" />
|
<Compile Include="LexingException.cs" />
|
||||||
|
<Compile Include="Parser.cs" />
|
||||||
|
<Compile Include="ParsingException.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="SSType.cs" />
|
||||||
<Compile Include="Token.cs" />
|
<Compile Include="Token.cs" />
|
||||||
|
<Compile Include="TypeException.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
</Project>
|
</Project>
|
|
@ -0,0 +1,91 @@
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using ShintenScript;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ShintenScriptTest
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class EvaluationTest
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void TestBlock()
|
||||||
|
{
|
||||||
|
IASTNode ast = new ASTNodeBlock(new List<IASTNode>()
|
||||||
|
{
|
||||||
|
new ASTNodeLiteral(1f),
|
||||||
|
new ASTNodeLiteral(true),
|
||||||
|
new ASTNodeLiteral(5f)
|
||||||
|
});
|
||||||
|
|
||||||
|
Assert.AreEqual(SSType.real, ast.Type());
|
||||||
|
|
||||||
|
Func<ExecutionContext, float> func = (Func<ExecutionContext, float>)ast.CreateFunction();
|
||||||
|
|
||||||
|
Assert.AreEqual(5f, func(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TestAdd()
|
||||||
|
{
|
||||||
|
IASTNode ast = new ASTNodeAdd(new ASTNodeLiteral(2f), new ASTNodeLiteral(3f));
|
||||||
|
|
||||||
|
Assert.AreEqual(SSType.real, ast.Type());
|
||||||
|
|
||||||
|
Func<ExecutionContext, float> func = (Func<ExecutionContext, float>)ast.CreateFunction();
|
||||||
|
|
||||||
|
Assert.AreEqual(5f, func(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TestMul()
|
||||||
|
{
|
||||||
|
IASTNode ast = new ASTNodeMultiply(new ASTNodeLiteral(2f), new ASTNodeLiteral(3f));
|
||||||
|
|
||||||
|
Assert.AreEqual(SSType.real, ast.Type());
|
||||||
|
|
||||||
|
Func<ExecutionContext, float> func = (Func<ExecutionContext, float>)ast.CreateFunction();
|
||||||
|
|
||||||
|
Assert.AreEqual(6f, func(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TestSub()
|
||||||
|
{
|
||||||
|
IASTNode ast = new ASTNodeSubtract(new ASTNodeLiteral(2f), new ASTNodeLiteral(3f));
|
||||||
|
|
||||||
|
Assert.AreEqual(SSType.real, ast.Type());
|
||||||
|
|
||||||
|
Func<ExecutionContext, float> func = (Func<ExecutionContext, float>)ast.CreateFunction();
|
||||||
|
|
||||||
|
Assert.AreEqual(-1f, func(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TestDiv()
|
||||||
|
{
|
||||||
|
IASTNode ast = new ASTNodeDivide(new ASTNodeLiteral(7f), new ASTNodeLiteral(2f));
|
||||||
|
|
||||||
|
Assert.AreEqual(SSType.real, ast.Type());
|
||||||
|
|
||||||
|
Func<ExecutionContext, float> func = (Func<ExecutionContext, float>)ast.CreateFunction();
|
||||||
|
|
||||||
|
Assert.AreEqual(3.5f, func(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TestNegative()
|
||||||
|
{
|
||||||
|
IASTNode ast = new ASTNodeNegative(new ASTNodeLiteral(7f));
|
||||||
|
|
||||||
|
Assert.AreEqual(SSType.real, ast.Type());
|
||||||
|
|
||||||
|
Func<ExecutionContext, float> func = (Func<ExecutionContext, float>)ast.CreateFunction();
|
||||||
|
|
||||||
|
Assert.AreEqual(-7f, func(null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,6 +19,7 @@ namespace ShintenScriptTest
|
||||||
1.5e6
|
1.5e6
|
||||||
2.4e-6
|
2.4e-6
|
||||||
|
|
||||||
|
;
|
||||||
( ) { }
|
( ) { }
|
||||||
+ - * /
|
+ - * /
|
||||||
> < == >= <= !=
|
> < == >= <= !=
|
||||||
|
@ -36,6 +37,7 @@ namespace ShintenScriptTest
|
||||||
new Token { type = Token.Type.NUMBER, data = 1.5e6f },
|
new Token { type = Token.Type.NUMBER, data = 1.5e6f },
|
||||||
new Token { type = Token.Type.NUMBER, data = 2.4e-6f },
|
new Token { type = Token.Type.NUMBER, data = 2.4e-6f },
|
||||||
|
|
||||||
|
new Token { type = Token.Type.SEMICOLON },
|
||||||
new Token { type = Token.Type.LPAREN },
|
new Token { type = Token.Type.LPAREN },
|
||||||
new Token { type = Token.Type.RPAREN },
|
new Token { type = Token.Type.RPAREN },
|
||||||
new Token { type = Token.Type.LBRACE },
|
new Token { type = Token.Type.LBRACE },
|
||||||
|
@ -59,8 +61,18 @@ namespace ShintenScriptTest
|
||||||
new Token { type = Token.Type.IF },
|
new Token { type = Token.Type.IF },
|
||||||
new Token { type = Token.Type.WHILE },
|
new Token { type = Token.Type.WHILE },
|
||||||
new Token { type = Token.Type.FN },
|
new Token { type = Token.Type.FN },
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
new Token { type = Token.Type.EOF },
|
[TestMethod]
|
||||||
|
public void TestHexExponent()
|
||||||
|
{
|
||||||
|
Lexer lexer = new Lexer(@"0xcafe-1337");
|
||||||
|
|
||||||
|
Assert.IsTrue(lexer.TokenStream().SequenceEqual(new Token[] {
|
||||||
|
new Token { type = Token.Type.NUMBER, data = 51966f },
|
||||||
|
new Token { type = Token.Type.MINUS },
|
||||||
|
new Token { type = Token.Type.NUMBER, data = 1337f },
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,153 @@
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using ShintenScript;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ShintenScriptTest
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class ParserTest
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void TestBlock()
|
||||||
|
{
|
||||||
|
Lexer lexer = new ScaffoldLexer(new Token[]
|
||||||
|
{
|
||||||
|
new Token { type = Token.Type.LBRACE },
|
||||||
|
new Token { type = Token.Type.NUMBER, data = 1f },
|
||||||
|
new Token { type = Token.Type.NUMBER, data = 2f },
|
||||||
|
new Token { type = Token.Type.NUMBER, data = 3f },
|
||||||
|
new Token { type = Token.Type.RBRACE },
|
||||||
|
});
|
||||||
|
|
||||||
|
IASTNode ast = new Parser(lexer).ParseExpression();
|
||||||
|
|
||||||
|
if (ast is ASTNodeBlock block)
|
||||||
|
{
|
||||||
|
Assert.AreEqual(3, block.statements.Count);
|
||||||
|
Assert.IsInstanceOfType(block.statements[0], typeof(ASTNodeLiteral));
|
||||||
|
Assert.IsInstanceOfType(block.statements[1], typeof(ASTNodeLiteral));
|
||||||
|
Assert.IsInstanceOfType(block.statements[2], typeof(ASTNodeLiteral));
|
||||||
|
}
|
||||||
|
else Assert.Fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TestComparison()
|
||||||
|
{
|
||||||
|
Lexer lexer = new ScaffoldLexer(new Token[]
|
||||||
|
{
|
||||||
|
new Token { type = Token.Type.NUMBER, data = 1f },
|
||||||
|
new Token { type = Token.Type.LE },
|
||||||
|
new Token { type = Token.Type.NUMBER, data = 2f },
|
||||||
|
new Token { type = Token.Type.NE },
|
||||||
|
new Token { type = Token.Type.NUMBER, data = 3f },
|
||||||
|
});
|
||||||
|
|
||||||
|
IASTNode ast = new Parser(lexer).ParseExpression();
|
||||||
|
|
||||||
|
if (ast is ASTNodeComparison comp)
|
||||||
|
{
|
||||||
|
Assert.AreEqual(3, comp.nodes.Count);
|
||||||
|
Assert.AreEqual(2, comp.comparisons.Count);
|
||||||
|
Assert.IsInstanceOfType(comp.nodes[0], typeof(ASTNodeLiteral));
|
||||||
|
Assert.IsInstanceOfType(comp.nodes[1], typeof(ASTNodeLiteral));
|
||||||
|
Assert.IsInstanceOfType(comp.nodes[2], typeof(ASTNodeLiteral));
|
||||||
|
Assert.AreEqual(Token.Type.LE, comp.comparisons[0]);
|
||||||
|
Assert.AreEqual(Token.Type.NE, comp.comparisons[1]);
|
||||||
|
}
|
||||||
|
else Assert.Fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TestDivision()
|
||||||
|
{
|
||||||
|
Lexer lexer = new ScaffoldLexer(new Token[]
|
||||||
|
{
|
||||||
|
new Token { type = Token.Type.NUMBER, data = 1f },
|
||||||
|
new Token { type = Token.Type.SLASH },
|
||||||
|
new Token { type = Token.Type.NUMBER, data = 2f },
|
||||||
|
});
|
||||||
|
|
||||||
|
IASTNode ast = new Parser(lexer).ParseExpression();
|
||||||
|
|
||||||
|
Assert.IsInstanceOfType(ast, typeof(ASTNodeDivide));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TestMinus()
|
||||||
|
{
|
||||||
|
Lexer lexer = new ScaffoldLexer(new Token[]
|
||||||
|
{
|
||||||
|
new Token { type = Token.Type.MINUS },
|
||||||
|
new Token { type = Token.Type.NUMBER, data = 2f },
|
||||||
|
new Token { type = Token.Type.MINUS },
|
||||||
|
new Token { type = Token.Type.NUMBER, data = 3f },
|
||||||
|
});
|
||||||
|
|
||||||
|
IASTNode ast = new Parser(lexer).ParseExpression();
|
||||||
|
|
||||||
|
if (ast is ASTNodeSubtract sub)
|
||||||
|
{
|
||||||
|
Assert.IsInstanceOfType(sub.lhs, typeof(ASTNodeNegative));
|
||||||
|
Assert.IsInstanceOfType(sub.rhs, typeof(ASTNodeLiteral));
|
||||||
|
}
|
||||||
|
else Assert.Fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TestOrderOfOperations()
|
||||||
|
{
|
||||||
|
Lexer lexer = new ScaffoldLexer(new Token[]
|
||||||
|
{
|
||||||
|
new Token { type = Token.Type.NUMBER, data = 1f },
|
||||||
|
new Token { type = Token.Type.PLUS },
|
||||||
|
new Token { type = Token.Type.NUMBER, data = 2f },
|
||||||
|
new Token { type = Token.Type.ASTERISK },
|
||||||
|
new Token { type = Token.Type.NUMBER, data = 3f },
|
||||||
|
});
|
||||||
|
|
||||||
|
IASTNode ast = new Parser(lexer).ParseExpression();
|
||||||
|
|
||||||
|
if (ast is ASTNodeAdd add)
|
||||||
|
{
|
||||||
|
Assert.IsInstanceOfType(add.lhs, typeof(ASTNodeLiteral));
|
||||||
|
|
||||||
|
if (add.rhs is ASTNodeMultiply mul)
|
||||||
|
{
|
||||||
|
Assert.IsInstanceOfType(mul.lhs, typeof(ASTNodeLiteral));
|
||||||
|
Assert.IsInstanceOfType(mul.rhs, typeof(ASTNodeLiteral));
|
||||||
|
}
|
||||||
|
else Assert.Fail();
|
||||||
|
}
|
||||||
|
else Assert.Fail();
|
||||||
|
|
||||||
|
lexer = new ScaffoldLexer(new Token[]
|
||||||
|
{
|
||||||
|
new Token { type = Token.Type.NUMBER, data = 1f },
|
||||||
|
new Token { type = Token.Type.ASTERISK },
|
||||||
|
new Token { type = Token.Type.NUMBER, data = 2f },
|
||||||
|
new Token { type = Token.Type.PLUS },
|
||||||
|
new Token { type = Token.Type.NUMBER, data = 3f },
|
||||||
|
});
|
||||||
|
|
||||||
|
ast = new Parser(lexer).ParseExpression();
|
||||||
|
|
||||||
|
if (ast is ASTNodeAdd add2)
|
||||||
|
{
|
||||||
|
Assert.IsInstanceOfType(add2.rhs, typeof(ASTNodeLiteral));
|
||||||
|
|
||||||
|
if (add2.lhs is ASTNodeMultiply mul)
|
||||||
|
{
|
||||||
|
Assert.IsInstanceOfType(mul.lhs, typeof(ASTNodeLiteral));
|
||||||
|
Assert.IsInstanceOfType(mul.rhs, typeof(ASTNodeLiteral));
|
||||||
|
}
|
||||||
|
else Assert.Fail();
|
||||||
|
}
|
||||||
|
else Assert.Fail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
using ShintenScript;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ShintenScriptTest
|
||||||
|
{
|
||||||
|
class ScaffoldLexer : Lexer
|
||||||
|
{
|
||||||
|
Queue<Token> tokenQueue;
|
||||||
|
|
||||||
|
public ScaffoldLexer(IEnumerable<Token> queue) : base("")
|
||||||
|
{
|
||||||
|
tokenQueue = new Queue<Token>(queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Token ParseOne()
|
||||||
|
{
|
||||||
|
if (tokenQueue.Count == 0)
|
||||||
|
return new Token { type = Token.Type.EOF };
|
||||||
|
|
||||||
|
return tokenQueue.Dequeue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -49,8 +49,11 @@
|
||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="EvaluationTest.cs" />
|
||||||
<Compile Include="LexerTests.cs" />
|
<Compile Include="LexerTests.cs" />
|
||||||
|
<Compile Include="ParserTest.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="ScaffoldLexer.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="packages.config" />
|
<None Include="packages.config" />
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
LexerTests
|
LexerTests
|
||||||
Tests in group: 1
|
Tests in group: 13
|
||||||
Total Duration: 31ms
|
Total Duration: 28ms
|
||||||
|
|
||||||
Outcomes
|
Outcomes
|
||||||
1 Passed
|
13 Passed
|
1
Token.cs
1
Token.cs
|
@ -15,6 +15,7 @@ namespace ShintenScript
|
||||||
IDENTIFIER,
|
IDENTIFIER,
|
||||||
NUMBER,
|
NUMBER,
|
||||||
|
|
||||||
|
SEMICOLON,
|
||||||
LPAREN, RPAREN, LBRACE, RBRACE,
|
LPAREN, RPAREN, LBRACE, RBRACE,
|
||||||
PLUS, MINUS, ASTERISK, SLASH,
|
PLUS, MINUS, ASTERISK, SLASH,
|
||||||
GT, LT, EQ, GE, LE, NE,
|
GT, LT, EQ, GE, LE, NE,
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ShintenScript
|
||||||
|
{
|
||||||
|
public class TypeException : Exception
|
||||||
|
{
|
||||||
|
public TypeException(string message) : base(message)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue