mirror of
https://github.com/Cekis/SWG-ScriptConverter.git
synced 2026-01-15 21:04:23 -05:00
Add code
This commit is contained in:
@@ -1,2 +1,6 @@
|
||||
# SWG-ScriptConverter
|
||||
Some tool I made in 2015 to convert the original Star Wars Galaxies server scripts to Java.
|
||||
In 2015 someone asked me to make a tool to convert the original Star Wars Galaxies server scripts to Java. I believe it resulted in [this project](https://github.com/SWG-Source) as they have the scripts in Java form over there. That seems to be a fork though so it's probably in other places too.
|
||||
|
||||
The source they have on [their repo](https://github.com/SWG-Source/dsrc/tree/master/sku.0/sys.server/compiled/game/script) is missing all the fun comments that were in the original scripts. I didn't bother preserving them in the output from this tool.
|
||||
|
||||
Also I only got this to the point where you could compile the resulting Java source into class files. There is almost certainly a version out there that has additional fixes to this code.
|
||||
|
||||
22
ScriptConverter.sln
Normal file
22
ScriptConverter.sln
Normal file
@@ -0,0 +1,22 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 2013
|
||||
VisualStudioVersion = 12.0.31101.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScriptConverter", "ScriptConverter\ScriptConverter.csproj", "{3F560E64-ACCE-4520-B3E7-EA6502E20F49}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{3F560E64-ACCE-4520-B3E7-EA6502E20F49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3F560E64-ACCE-4520-B3E7-EA6502E20F49}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3F560E64-ACCE-4520-B3E7-EA6502E20F49}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3F560E64-ACCE-4520-B3E7-EA6502E20F49}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
6
ScriptConverter/App.config
Normal file
6
ScriptConverter/App.config
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
|
||||
</startup>
|
||||
</configuration>
|
||||
24
ScriptConverter/Ast/Declarations/Declaration.cs
Normal file
24
ScriptConverter/Ast/Declarations/Declaration.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using ScriptConverter.Parser;
|
||||
|
||||
namespace ScriptConverter.Ast.Declarations
|
||||
{
|
||||
abstract class Declaration
|
||||
{
|
||||
public readonly ScriptToken Start;
|
||||
public readonly ScriptToken End;
|
||||
|
||||
protected Declaration(ScriptToken start, ScriptToken end = null)
|
||||
{
|
||||
if (start == null)
|
||||
throw new ArgumentNullException("start");
|
||||
|
||||
Start = start;
|
||||
End = end ?? start;
|
||||
}
|
||||
|
||||
public abstract TDecl Accept<TDoc, TDecl, TStmt, TExpr>(IAstVisitor<TDoc, TDecl, TStmt, TExpr> visitor);
|
||||
|
||||
public abstract void SetParent();
|
||||
}
|
||||
}
|
||||
34
ScriptConverter/Ast/Declarations/FieldDeclaration.cs
Normal file
34
ScriptConverter/Ast/Declarations/FieldDeclaration.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using ScriptConverter.Ast.Expressions;
|
||||
using ScriptConverter.Parser;
|
||||
|
||||
namespace ScriptConverter.Ast.Declarations
|
||||
{
|
||||
class FieldDeclaration : Declaration
|
||||
{
|
||||
public ScriptType Type { get; private set; }
|
||||
public string Name { get; private set; }
|
||||
public Expression Value { get; private set; }
|
||||
public bool IsConstant { get; private set; }
|
||||
public bool IsPublic { get; private set; }
|
||||
|
||||
public FieldDeclaration(ScriptToken start, ScriptToken end, ScriptType type, string name, Expression value, bool isConst, bool isPublic)
|
||||
: base(start, end)
|
||||
{
|
||||
Type = type;
|
||||
Name = name;
|
||||
Value = value;
|
||||
IsConstant = isConst;
|
||||
IsPublic = isPublic;
|
||||
}
|
||||
|
||||
public override TDecl Accept<TDoc, TDecl, TStmt, TExpr>(IAstVisitor<TDoc, TDecl, TStmt, TExpr> visitor)
|
||||
{
|
||||
return visitor.Visit(this);
|
||||
}
|
||||
|
||||
public override void SetParent()
|
||||
{
|
||||
Value.SetParent(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
25
ScriptConverter/Ast/Declarations/IncludeDeclaration.cs
Normal file
25
ScriptConverter/Ast/Declarations/IncludeDeclaration.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using ScriptConverter.Parser;
|
||||
|
||||
namespace ScriptConverter.Ast.Declarations
|
||||
{
|
||||
class IncludeDeclaration : Declaration
|
||||
{
|
||||
public string Name { get; private set; }
|
||||
|
||||
public IncludeDeclaration(ScriptToken start, ScriptToken end, string name)
|
||||
: base(start, end)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public override TDecl Accept<TDoc, TDecl, TStmt, TExpr>(IAstVisitor<TDoc, TDecl, TStmt, TExpr> visitor)
|
||||
{
|
||||
return visitor.Visit(this);
|
||||
}
|
||||
|
||||
public override void SetParent()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
25
ScriptConverter/Ast/Declarations/InheritsDeclaration.cs
Normal file
25
ScriptConverter/Ast/Declarations/InheritsDeclaration.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using ScriptConverter.Parser;
|
||||
|
||||
namespace ScriptConverter.Ast.Declarations
|
||||
{
|
||||
class InheritsDeclaration : Declaration
|
||||
{
|
||||
public string Name { get; private set; }
|
||||
|
||||
public InheritsDeclaration(ScriptToken start, ScriptToken end, string name)
|
||||
: base(start, end)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public override TDecl Accept<TDoc, TDecl, TStmt, TExpr>(IAstVisitor<TDoc, TDecl, TStmt, TExpr> visitor)
|
||||
{
|
||||
return visitor.Visit(this);
|
||||
}
|
||||
|
||||
public override void SetParent()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
46
ScriptConverter/Ast/Declarations/MethodDeclaration.cs
Normal file
46
ScriptConverter/Ast/Declarations/MethodDeclaration.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using ScriptConverter.Ast.Statements;
|
||||
using ScriptConverter.Parser;
|
||||
|
||||
namespace ScriptConverter.Ast.Declarations
|
||||
{
|
||||
class MethodDeclaration : Declaration
|
||||
{
|
||||
public class Parameter
|
||||
{
|
||||
public ScriptType Type { get; private set; }
|
||||
public string Name { get; private set; }
|
||||
|
||||
public Parameter(ScriptType type, string name)
|
||||
{
|
||||
Type = type;
|
||||
Name = name;
|
||||
}
|
||||
}
|
||||
|
||||
public ScriptType ReturnType { get; private set; }
|
||||
public string Name { get; private set; }
|
||||
public ReadOnlyCollection<Parameter> Parameters { get; private set; }
|
||||
public BlockStatement Block { get; private set; }
|
||||
|
||||
public MethodDeclaration(ScriptToken start, ScriptToken end, ScriptType returnType, string name, List<Parameter> parameters, BlockStatement block)
|
||||
: base(start, end)
|
||||
{
|
||||
ReturnType = returnType;
|
||||
Name = name;
|
||||
Parameters = parameters.AsReadOnly();
|
||||
Block = block;
|
||||
}
|
||||
|
||||
public override TDecl Accept<TDoc, TDecl, TStmt, TExpr>(IAstVisitor<TDoc, TDecl, TStmt, TExpr> visitor)
|
||||
{
|
||||
return visitor.Visit(this);
|
||||
}
|
||||
|
||||
public override void SetParent()
|
||||
{
|
||||
Block.SetParent(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
19
ScriptConverter/Ast/Document.cs
Normal file
19
ScriptConverter/Ast/Document.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using ScriptConverter.Ast.Declarations;
|
||||
|
||||
namespace ScriptConverter.Ast
|
||||
{
|
||||
class Document
|
||||
{
|
||||
public ReadOnlyCollection<Declaration> Declarations { get; private set; }
|
||||
|
||||
public Document(IEnumerable<Declaration> declarations)
|
||||
{
|
||||
Declarations = declarations
|
||||
.ToList()
|
||||
.AsReadOnly();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using ScriptConverter.Parser;
|
||||
|
||||
namespace ScriptConverter.Ast.Expressions
|
||||
{
|
||||
class ArrayInitializerExpression : Expression
|
||||
{
|
||||
public ReadOnlyCollection<Expression> Values { get; private set; }
|
||||
|
||||
public ArrayInitializerExpression(ScriptToken start, ScriptToken end, List<Expression> values)
|
||||
: base(start, end)
|
||||
{
|
||||
Values = values.AsReadOnly();
|
||||
}
|
||||
|
||||
public override TExpr Accept<TDoc, TDecl, TStmt, TExpr>(IAstVisitor<TDoc, TDecl, TStmt, TExpr> visitor)
|
||||
{
|
||||
return visitor.Visit(this);
|
||||
}
|
||||
|
||||
public override void SetParent(Expression parent)
|
||||
{
|
||||
Parent = parent;
|
||||
|
||||
foreach (var expression in Values)
|
||||
{
|
||||
expression.SetParent(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
32
ScriptConverter/Ast/Expressions/BinaryOperatorExpression.cs
Normal file
32
ScriptConverter/Ast/Expressions/BinaryOperatorExpression.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using ScriptConverter.Parser;
|
||||
|
||||
namespace ScriptConverter.Ast.Expressions
|
||||
{
|
||||
class BinaryOperatorExpression : Expression
|
||||
{
|
||||
public ScriptTokenType Operation { get; private set; }
|
||||
public Expression Left { get; private set; }
|
||||
public Expression Right { get; private set; }
|
||||
|
||||
public BinaryOperatorExpression(ScriptTokenType op, Expression left, Expression right)
|
||||
: base(left.Start, right.End)
|
||||
{
|
||||
Operation = op;
|
||||
Left = left;
|
||||
Right = right;
|
||||
}
|
||||
|
||||
public override TExpr Accept<TDoc, TDecl, TStmt, TExpr>(IAstVisitor<TDoc, TDecl, TStmt, TExpr> visitor)
|
||||
{
|
||||
return visitor.Visit(this);
|
||||
}
|
||||
|
||||
public override void SetParent(Expression parent)
|
||||
{
|
||||
Parent = parent;
|
||||
|
||||
Left.SetParent(this);
|
||||
Right.SetParent(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
25
ScriptConverter/Ast/Expressions/BoolExpression.cs
Normal file
25
ScriptConverter/Ast/Expressions/BoolExpression.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using ScriptConverter.Parser;
|
||||
|
||||
namespace ScriptConverter.Ast.Expressions
|
||||
{
|
||||
class BoolExpression : Expression
|
||||
{
|
||||
public bool Value { get; private set; }
|
||||
|
||||
public BoolExpression(ScriptToken token, bool value)
|
||||
: base(token)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public override TExpr Accept<TDoc, TDecl, TStmt, TExpr>(IAstVisitor<TDoc, TDecl, TStmt, TExpr> visitor)
|
||||
{
|
||||
return visitor.Visit(this);
|
||||
}
|
||||
|
||||
public override void SetParent(Expression parent)
|
||||
{
|
||||
Parent = parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
36
ScriptConverter/Ast/Expressions/CallExpression.cs
Normal file
36
ScriptConverter/Ast/Expressions/CallExpression.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using ScriptConverter.Parser;
|
||||
|
||||
namespace ScriptConverter.Ast.Expressions
|
||||
{
|
||||
class CallExpression : Expression
|
||||
{
|
||||
public Expression Left { get; private set; }
|
||||
public ReadOnlyCollection<Expression> Parameters { get; private set; }
|
||||
|
||||
public CallExpression(ScriptToken end, Expression left, List<Expression> parameters)
|
||||
: base(left.Start, end)
|
||||
{
|
||||
Left = left;
|
||||
Parameters = parameters.AsReadOnly();
|
||||
}
|
||||
|
||||
public override TExpr Accept<TDoc, TDecl, TStmt, TExpr>(IAstVisitor<TDoc, TDecl, TStmt, TExpr> visitor)
|
||||
{
|
||||
return visitor.Visit(this);
|
||||
}
|
||||
|
||||
public override void SetParent(Expression parent)
|
||||
{
|
||||
Parent = parent;
|
||||
|
||||
Left.SetParent(this);
|
||||
|
||||
foreach (var expression in Parameters)
|
||||
{
|
||||
expression.SetParent(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
29
ScriptConverter/Ast/Expressions/CastExpression.cs
Normal file
29
ScriptConverter/Ast/Expressions/CastExpression.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using ScriptConverter.Parser;
|
||||
|
||||
namespace ScriptConverter.Ast.Expressions
|
||||
{
|
||||
class CastExpression : Expression
|
||||
{
|
||||
public ScriptType Type { get; private set; }
|
||||
public Expression Value { get; private set; }
|
||||
|
||||
public CastExpression(ScriptToken start, ScriptType type, Expression value)
|
||||
: base(start, value.End)
|
||||
{
|
||||
Type = type;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public override TExpr Accept<TDoc, TDecl, TStmt, TExpr>(IAstVisitor<TDoc, TDecl, TStmt, TExpr> visitor)
|
||||
{
|
||||
return visitor.Visit(this);
|
||||
}
|
||||
|
||||
public override void SetParent(Expression parent)
|
||||
{
|
||||
Parent = parent;
|
||||
|
||||
Value.SetParent(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
25
ScriptConverter/Ast/Expressions/Expression.cs
Normal file
25
ScriptConverter/Ast/Expressions/Expression.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using ScriptConverter.Parser;
|
||||
|
||||
namespace ScriptConverter.Ast.Expressions
|
||||
{
|
||||
abstract class Expression
|
||||
{
|
||||
public readonly ScriptToken Start;
|
||||
public readonly ScriptToken End;
|
||||
public Expression Parent { get; protected set; }
|
||||
|
||||
protected Expression(ScriptToken start, ScriptToken end = null)
|
||||
{
|
||||
if (start == null)
|
||||
throw new ArgumentNullException("start");
|
||||
|
||||
Start = start;
|
||||
End = end ?? start;
|
||||
}
|
||||
|
||||
public abstract TExpr Accept<TDoc, TDecl, TStmt, TExpr>(IAstVisitor<TDoc, TDecl, TStmt, TExpr> visitor);
|
||||
|
||||
public abstract void SetParent(Expression parent);
|
||||
}
|
||||
}
|
||||
29
ScriptConverter/Ast/Expressions/FieldExpression.cs
Normal file
29
ScriptConverter/Ast/Expressions/FieldExpression.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using ScriptConverter.Parser;
|
||||
|
||||
namespace ScriptConverter.Ast.Expressions
|
||||
{
|
||||
class FieldExpression : Expression
|
||||
{
|
||||
public Expression Left { get; private set; }
|
||||
public string Name { get; private set; }
|
||||
|
||||
public FieldExpression(Expression left, ScriptToken name)
|
||||
: base(left.Start, name)
|
||||
{
|
||||
Left = left;
|
||||
Name = name.Contents;
|
||||
}
|
||||
|
||||
public override TExpr Accept<TDoc, TDecl, TStmt, TExpr>(IAstVisitor<TDoc, TDecl, TStmt, TExpr> visitor)
|
||||
{
|
||||
return visitor.Visit(this);
|
||||
}
|
||||
|
||||
public override void SetParent(Expression parent)
|
||||
{
|
||||
Parent = parent;
|
||||
|
||||
Left.SetParent(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
25
ScriptConverter/Ast/Expressions/IdentifierExpression.cs
Normal file
25
ScriptConverter/Ast/Expressions/IdentifierExpression.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using ScriptConverter.Parser;
|
||||
|
||||
namespace ScriptConverter.Ast.Expressions
|
||||
{
|
||||
class IdentifierExpression : Expression
|
||||
{
|
||||
public string Name { get; private set; }
|
||||
|
||||
public IdentifierExpression(ScriptToken token)
|
||||
: base(token)
|
||||
{
|
||||
Name = token.Contents;
|
||||
}
|
||||
|
||||
public override TExpr Accept<TDoc, TDecl, TStmt, TExpr>(IAstVisitor<TDoc, TDecl, TStmt, TExpr> visitor)
|
||||
{
|
||||
return visitor.Visit(this);
|
||||
}
|
||||
|
||||
public override void SetParent(Expression parent)
|
||||
{
|
||||
Parent = parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
30
ScriptConverter/Ast/Expressions/IndexerExpression.cs
Normal file
30
ScriptConverter/Ast/Expressions/IndexerExpression.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using ScriptConverter.Parser;
|
||||
|
||||
namespace ScriptConverter.Ast.Expressions
|
||||
{
|
||||
class IndexerExpression : Expression
|
||||
{
|
||||
public Expression Left { get; private set; }
|
||||
public Expression Index { get; private set; }
|
||||
|
||||
public IndexerExpression(ScriptToken end, Expression left, Expression index)
|
||||
: base(left.Start, end)
|
||||
{
|
||||
Left = left;
|
||||
Index = index;
|
||||
}
|
||||
|
||||
public override TExpr Accept<TDoc, TDecl, TStmt, TExpr>(IAstVisitor<TDoc, TDecl, TStmt, TExpr> visitor)
|
||||
{
|
||||
return visitor.Visit(this);
|
||||
}
|
||||
|
||||
public override void SetParent(Expression parent)
|
||||
{
|
||||
Parent = parent;
|
||||
|
||||
Left.SetParent(this);
|
||||
Index.SetParent(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
29
ScriptConverter/Ast/Expressions/InstanceOfExpression.cs
Normal file
29
ScriptConverter/Ast/Expressions/InstanceOfExpression.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using ScriptConverter.Parser;
|
||||
|
||||
namespace ScriptConverter.Ast.Expressions
|
||||
{
|
||||
class InstanceOfExpression : Expression
|
||||
{
|
||||
public Expression Left { get; private set; }
|
||||
public ScriptType Type { get; private set; }
|
||||
|
||||
public InstanceOfExpression(ScriptToken end, Expression left, ScriptType type)
|
||||
: base(left.Start, end)
|
||||
{
|
||||
Left = left;
|
||||
Type = type;
|
||||
}
|
||||
|
||||
public override TExpr Accept<TDoc, TDecl, TStmt, TExpr>(IAstVisitor<TDoc, TDecl, TStmt, TExpr> visitor)
|
||||
{
|
||||
return visitor.Visit(this);
|
||||
}
|
||||
|
||||
public override void SetParent(Expression parent)
|
||||
{
|
||||
Parent = parent;
|
||||
|
||||
Left.SetParent(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
47
ScriptConverter/Ast/Expressions/NewExpression.cs
Normal file
47
ScriptConverter/Ast/Expressions/NewExpression.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using ScriptConverter.Parser;
|
||||
|
||||
namespace ScriptConverter.Ast.Expressions
|
||||
{
|
||||
class NewExpression : Expression
|
||||
{
|
||||
public string Type { get; private set; }
|
||||
public bool IsArray { get { return ArrayDimensions > 0; } }
|
||||
public int ArrayDimensions { get; private set; }
|
||||
public ReadOnlyCollection<Expression> Parameters { get; private set; }
|
||||
public ReadOnlyCollection<Expression> Initializer { get; private set; }
|
||||
|
||||
public NewExpression(ScriptToken start, ScriptToken end, string type, int arrayDimensions, List<Expression> parameters, List<Expression> initializer = null)
|
||||
: base(start, end)
|
||||
{
|
||||
Type = type;
|
||||
ArrayDimensions = arrayDimensions;
|
||||
Parameters = parameters.AsReadOnly();
|
||||
Initializer = initializer != null ? initializer.AsReadOnly() : null;
|
||||
}
|
||||
|
||||
public override TExpr Accept<TDoc, TDecl, TStmt, TExpr>(IAstVisitor<TDoc, TDecl, TStmt, TExpr> visitor)
|
||||
{
|
||||
return visitor.Visit(this);
|
||||
}
|
||||
|
||||
public override void SetParent(Expression parent)
|
||||
{
|
||||
Parent = parent;
|
||||
|
||||
foreach (var expression in Parameters)
|
||||
{
|
||||
expression.SetParent(this);
|
||||
}
|
||||
|
||||
if (Initializer != null)
|
||||
{
|
||||
foreach (var expression in Initializer)
|
||||
{
|
||||
expression.SetParent(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
23
ScriptConverter/Ast/Expressions/NullExpression.cs
Normal file
23
ScriptConverter/Ast/Expressions/NullExpression.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using ScriptConverter.Parser;
|
||||
|
||||
namespace ScriptConverter.Ast.Expressions
|
||||
{
|
||||
class NullExpression : Expression
|
||||
{
|
||||
public NullExpression(ScriptToken token)
|
||||
: base(token)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override TExpr Accept<TDoc, TDecl, TStmt, TExpr>(IAstVisitor<TDoc, TDecl, TStmt, TExpr> visitor)
|
||||
{
|
||||
return visitor.Visit(this);
|
||||
}
|
||||
|
||||
public override void SetParent(Expression parent)
|
||||
{
|
||||
Parent = parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
25
ScriptConverter/Ast/Expressions/NumberExpression.cs
Normal file
25
ScriptConverter/Ast/Expressions/NumberExpression.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using ScriptConverter.Parser;
|
||||
|
||||
namespace ScriptConverter.Ast.Expressions
|
||||
{
|
||||
class NumberExpression : Expression
|
||||
{
|
||||
public string Value { get; private set; }
|
||||
|
||||
public NumberExpression(ScriptToken token)
|
||||
: base(token)
|
||||
{
|
||||
Value = token.Contents;
|
||||
}
|
||||
|
||||
public override TExpr Accept<TDoc, TDecl, TStmt, TExpr>(IAstVisitor<TDoc, TDecl, TStmt, TExpr> visitor)
|
||||
{
|
||||
return visitor.Visit(this);
|
||||
}
|
||||
|
||||
public override void SetParent(Expression parent)
|
||||
{
|
||||
Parent = parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
29
ScriptConverter/Ast/Expressions/PostfixOperatorExpression.cs
Normal file
29
ScriptConverter/Ast/Expressions/PostfixOperatorExpression.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using ScriptConverter.Parser;
|
||||
|
||||
namespace ScriptConverter.Ast.Expressions
|
||||
{
|
||||
class PostfixOperatorExpression : Expression
|
||||
{
|
||||
public ScriptTokenType Operation { get; private set; }
|
||||
public Expression Left { get; private set; }
|
||||
|
||||
public PostfixOperatorExpression(ScriptToken end, Expression left)
|
||||
: base(left.Start, end)
|
||||
{
|
||||
Operation = end.Type;
|
||||
Left = left;
|
||||
}
|
||||
|
||||
public override TExpr Accept<TDoc, TDecl, TStmt, TExpr>(IAstVisitor<TDoc, TDecl, TStmt, TExpr> visitor)
|
||||
{
|
||||
return visitor.Visit(this);
|
||||
}
|
||||
|
||||
public override void SetParent(Expression parent)
|
||||
{
|
||||
Parent = parent;
|
||||
|
||||
Left.SetParent(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
29
ScriptConverter/Ast/Expressions/PrefixOperatorExpression.cs
Normal file
29
ScriptConverter/Ast/Expressions/PrefixOperatorExpression.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using ScriptConverter.Parser;
|
||||
|
||||
namespace ScriptConverter.Ast.Expressions
|
||||
{
|
||||
class PrefixOperatorExpression : Expression
|
||||
{
|
||||
public ScriptTokenType Operation { get; private set; }
|
||||
public Expression Right { get; private set; }
|
||||
|
||||
public PrefixOperatorExpression(ScriptToken start, Expression right)
|
||||
: base(start, right.End)
|
||||
{
|
||||
Operation = start.Type;
|
||||
Right = right;
|
||||
}
|
||||
|
||||
public override TExpr Accept<TDoc, TDecl, TStmt, TExpr>(IAstVisitor<TDoc, TDecl, TStmt, TExpr> visitor)
|
||||
{
|
||||
return visitor.Visit(this);
|
||||
}
|
||||
|
||||
public override void SetParent(Expression parent)
|
||||
{
|
||||
Parent = parent;
|
||||
|
||||
Right.SetParent(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
27
ScriptConverter/Ast/Expressions/StringExpression.cs
Normal file
27
ScriptConverter/Ast/Expressions/StringExpression.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using ScriptConverter.Parser;
|
||||
|
||||
namespace ScriptConverter.Ast.Expressions
|
||||
{
|
||||
class StringExpression : Expression
|
||||
{
|
||||
public string Value { get; private set; }
|
||||
public bool IsSingleQuote { get; private set; }
|
||||
|
||||
public StringExpression(ScriptToken token, bool singleQuote)
|
||||
: base(token)
|
||||
{
|
||||
Value = token.Contents;
|
||||
IsSingleQuote = singleQuote;
|
||||
}
|
||||
|
||||
public override TExpr Accept<TDoc, TDecl, TStmt, TExpr>(IAstVisitor<TDoc, TDecl, TStmt, TExpr> visitor)
|
||||
{
|
||||
return visitor.Visit(this);
|
||||
}
|
||||
|
||||
public override void SetParent(Expression parent)
|
||||
{
|
||||
Parent = parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
31
ScriptConverter/Ast/Expressions/TernaryExpression.cs
Normal file
31
ScriptConverter/Ast/Expressions/TernaryExpression.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
namespace ScriptConverter.Ast.Expressions
|
||||
{
|
||||
class TernaryExpression : Expression
|
||||
{
|
||||
public Expression Condition { get; private set; }
|
||||
public Expression TrueExpression { get; private set; }
|
||||
public Expression FalseExpression { get; private set; }
|
||||
|
||||
public TernaryExpression(Expression condition, Expression trueExpression, Expression falseExpression)
|
||||
: base(condition.Start, falseExpression.End)
|
||||
{
|
||||
Condition = condition;
|
||||
TrueExpression = trueExpression;
|
||||
FalseExpression = falseExpression;
|
||||
}
|
||||
|
||||
public override TExpr Accept<TDoc, TDecl, TStmt, TExpr>(IAstVisitor<TDoc, TDecl, TStmt, TExpr> visitor)
|
||||
{
|
||||
return visitor.Visit(this);
|
||||
}
|
||||
|
||||
public override void SetParent(Expression parent)
|
||||
{
|
||||
Parent = parent;
|
||||
|
||||
Condition.SetParent(this);
|
||||
TrueExpression.SetParent(this);
|
||||
FalseExpression.SetParent(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
48
ScriptConverter/Ast/IAstVisitor.cs
Normal file
48
ScriptConverter/Ast/IAstVisitor.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using ScriptConverter.Ast.Declarations;
|
||||
using ScriptConverter.Ast.Expressions;
|
||||
using ScriptConverter.Ast.Statements;
|
||||
|
||||
namespace ScriptConverter.Ast
|
||||
{
|
||||
interface IAstVisitor<out TDoc, out TDecl, out TStmt, out TExpr>
|
||||
{
|
||||
TDoc Visit(Document document);
|
||||
|
||||
TDecl Visit(FieldDeclaration declaration);
|
||||
TDecl Visit(IncludeDeclaration declaration);
|
||||
TDecl Visit(InheritsDeclaration declaration);
|
||||
TDecl Visit(MethodDeclaration declaration);
|
||||
|
||||
TStmt Visit(BlockStatement statement);
|
||||
TStmt Visit(BreakStatement statement);
|
||||
TStmt Visit(ContinueStatement statement);
|
||||
TStmt Visit(DoStatement statement);
|
||||
TStmt Visit(EmptyStatement statement);
|
||||
TStmt Visit(ForStatement statement);
|
||||
TStmt Visit(IfStatement statement);
|
||||
TStmt Visit(NakedStatement statement);
|
||||
TStmt Visit(ReturnStatement statement);
|
||||
TStmt Visit(SwitchStatement statement);
|
||||
TStmt Visit(ThrowStatement statement);
|
||||
TStmt Visit(TryStatement statement);
|
||||
TStmt Visit(VariableStatement statement);
|
||||
TStmt Visit(WhileStatement statement);
|
||||
|
||||
TExpr Visit(ArrayInitializerExpression expression);
|
||||
TExpr Visit(BinaryOperatorExpression expression);
|
||||
TExpr Visit(BoolExpression expression);
|
||||
TExpr Visit(CallExpression expression);
|
||||
TExpr Visit(CastExpression expression);
|
||||
TExpr Visit(FieldExpression expression);
|
||||
TExpr Visit(IdentifierExpression expression);
|
||||
TExpr Visit(IndexerExpression expression);
|
||||
TExpr Visit(InstanceOfExpression expression);
|
||||
TExpr Visit(NewExpression expression);
|
||||
TExpr Visit(NullExpression expression);
|
||||
TExpr Visit(NumberExpression expression);
|
||||
TExpr Visit(PostfixOperatorExpression expression);
|
||||
TExpr Visit(PrefixOperatorExpression expression);
|
||||
TExpr Visit(StringExpression expression);
|
||||
TExpr Visit(TernaryExpression expression);
|
||||
}
|
||||
}
|
||||
48
ScriptConverter/Ast/ScriptType.cs
Normal file
48
ScriptConverter/Ast/ScriptType.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using System.Linq;
|
||||
|
||||
namespace ScriptConverter.Ast
|
||||
{
|
||||
class ScriptType
|
||||
{
|
||||
public string Name { get; private set; }
|
||||
public bool IsArray { get { return ArrayDimensions > 0; } }
|
||||
public bool IsResizable { get; private set; }
|
||||
public int ArrayDimensions { get; private set; }
|
||||
|
||||
public ScriptType(string name, int arrayDimensions = 0, bool isResizable = false)
|
||||
{
|
||||
if (name == "unknown")
|
||||
name = "Object";
|
||||
|
||||
if (name == "string")
|
||||
name = "String";
|
||||
|
||||
if (name == "modifyable_int")
|
||||
name = "modifiable_int";
|
||||
|
||||
if (name == "modifyable _float")
|
||||
name = "modifiable_float";
|
||||
|
||||
if (name == "modifyable_string_id")
|
||||
name = "modifiable_string_id";
|
||||
|
||||
if (isResizable)
|
||||
arrayDimensions = 1;
|
||||
|
||||
Name = name;
|
||||
IsResizable = isResizable;
|
||||
ArrayDimensions = arrayDimensions;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (IsResizable)
|
||||
return "Vector";
|
||||
|
||||
if (!IsArray)
|
||||
return Name;
|
||||
|
||||
return Name + string.Join("", Enumerable.Repeat("[]", ArrayDimensions));
|
||||
}
|
||||
}
|
||||
}
|
||||
38
ScriptConverter/Ast/Statements/BlockStatement.cs
Normal file
38
ScriptConverter/Ast/Statements/BlockStatement.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using ScriptConverter.Parser;
|
||||
|
||||
namespace ScriptConverter.Ast.Statements
|
||||
{
|
||||
class BlockStatement : Statement
|
||||
{
|
||||
public ReadOnlyCollection<Statement> Statements { get; private set; }
|
||||
public bool IsSwitch { get; private set; }
|
||||
|
||||
public BlockStatement(ScriptToken start, ScriptToken end, List<Statement> statements, bool isSwitch = false)
|
||||
: base(start, end)
|
||||
{
|
||||
if (statements == null)
|
||||
throw new ArgumentNullException("statements");
|
||||
|
||||
Statements = statements.AsReadOnly();
|
||||
IsSwitch = isSwitch;
|
||||
}
|
||||
|
||||
public override TStmt Accept<TDoc, TDecl, TStmt, TExpr>(IAstVisitor<TDoc, TDecl, TStmt, TExpr> visitor)
|
||||
{
|
||||
return visitor.Visit(this);
|
||||
}
|
||||
|
||||
public override void SetParent(Statement parent)
|
||||
{
|
||||
Parent = parent;
|
||||
|
||||
foreach (var statement in Statements)
|
||||
{
|
||||
statement.SetParent(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
23
ScriptConverter/Ast/Statements/BreakStatement.cs
Normal file
23
ScriptConverter/Ast/Statements/BreakStatement.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using ScriptConverter.Parser;
|
||||
|
||||
namespace ScriptConverter.Ast.Statements
|
||||
{
|
||||
class BreakStatement : Statement
|
||||
{
|
||||
public BreakStatement(ScriptToken token)
|
||||
: base(token)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override TStmt Accept<TDoc, TDecl, TStmt, TExpr>(IAstVisitor<TDoc, TDecl, TStmt, TExpr> visitor)
|
||||
{
|
||||
return visitor.Visit(this);
|
||||
}
|
||||
|
||||
public override void SetParent(Statement parent)
|
||||
{
|
||||
Parent = parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
23
ScriptConverter/Ast/Statements/ContinueStatement.cs
Normal file
23
ScriptConverter/Ast/Statements/ContinueStatement.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using ScriptConverter.Parser;
|
||||
|
||||
namespace ScriptConverter.Ast.Statements
|
||||
{
|
||||
class ContinueStatement : Statement
|
||||
{
|
||||
public ContinueStatement(ScriptToken token)
|
||||
: base(token)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override TStmt Accept<TDoc, TDecl, TStmt, TExpr>(IAstVisitor<TDoc, TDecl, TStmt, TExpr> visitor)
|
||||
{
|
||||
return visitor.Visit(this);
|
||||
}
|
||||
|
||||
public override void SetParent(Statement parent)
|
||||
{
|
||||
Parent = parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
31
ScriptConverter/Ast/Statements/DoStatement.cs
Normal file
31
ScriptConverter/Ast/Statements/DoStatement.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using ScriptConverter.Ast.Expressions;
|
||||
using ScriptConverter.Parser;
|
||||
|
||||
namespace ScriptConverter.Ast.Statements
|
||||
{
|
||||
class DoStatement : Statement
|
||||
{
|
||||
public Expression Condition { get; private set; }
|
||||
public BlockStatement Block { get; private set; }
|
||||
|
||||
public DoStatement(ScriptToken start, ScriptToken end, Expression condition, BlockStatement block)
|
||||
: base(start, end)
|
||||
{
|
||||
Condition = condition;
|
||||
Block = block;
|
||||
}
|
||||
|
||||
public override TStmt Accept<TDoc, TDecl, TStmt, TExpr>(IAstVisitor<TDoc, TDecl, TStmt, TExpr> visitor)
|
||||
{
|
||||
return visitor.Visit(this);
|
||||
}
|
||||
|
||||
public override void SetParent(Statement parent)
|
||||
{
|
||||
Parent = parent;
|
||||
|
||||
Condition.SetParent(null);
|
||||
Block.SetParent(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
23
ScriptConverter/Ast/Statements/EmptyStatement.cs
Normal file
23
ScriptConverter/Ast/Statements/EmptyStatement.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using ScriptConverter.Parser;
|
||||
|
||||
namespace ScriptConverter.Ast.Statements
|
||||
{
|
||||
class EmptyStatement : Statement
|
||||
{
|
||||
public EmptyStatement(ScriptToken token)
|
||||
: base(token)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override TStmt Accept<TDoc, TDecl, TStmt, TExpr>(IAstVisitor<TDoc, TDecl, TStmt, TExpr> visitor)
|
||||
{
|
||||
return visitor.Visit(this);
|
||||
}
|
||||
|
||||
public override void SetParent(Statement parent)
|
||||
{
|
||||
Parent = parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
55
ScriptConverter/Ast/Statements/ForStatement.cs
Normal file
55
ScriptConverter/Ast/Statements/ForStatement.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using ScriptConverter.Ast.Expressions;
|
||||
using ScriptConverter.Parser;
|
||||
|
||||
namespace ScriptConverter.Ast.Statements
|
||||
{
|
||||
class ForStatement : Statement
|
||||
{
|
||||
public ReadOnlyCollection<Statement> Initializers { get; private set; }
|
||||
public Expression Condition { get; private set; }
|
||||
public ReadOnlyCollection<Expression> Increment { get; private set; }
|
||||
public BlockStatement Block { get; private set; }
|
||||
|
||||
public ForStatement(ScriptToken start, ScriptToken end, List<Statement> initializers, Expression condition, List<Expression> increment, BlockStatement block)
|
||||
: base(start, end)
|
||||
{
|
||||
Initializers = initializers != null ? initializers.AsReadOnly() : null;
|
||||
Condition = condition;
|
||||
Increment = increment != null ? increment.AsReadOnly() : null;
|
||||
Block = block;
|
||||
}
|
||||
|
||||
public override TStmt Accept<TDoc, TDecl, TStmt, TExpr>(IAstVisitor<TDoc, TDecl, TStmt, TExpr> visitor)
|
||||
{
|
||||
return visitor.Visit(this);
|
||||
}
|
||||
|
||||
public override void SetParent(Statement parent)
|
||||
{
|
||||
Parent = parent;
|
||||
|
||||
if (Initializers != null)
|
||||
{
|
||||
foreach (var statement in Initializers)
|
||||
{
|
||||
statement.SetParent(this);
|
||||
}
|
||||
}
|
||||
|
||||
if (Condition != null)
|
||||
Condition.SetParent(null);
|
||||
|
||||
if (Increment != null)
|
||||
{
|
||||
foreach (var expression in Increment)
|
||||
{
|
||||
expression.SetParent(null);
|
||||
}
|
||||
}
|
||||
|
||||
Block.SetParent(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
53
ScriptConverter/Ast/Statements/IfStatement.cs
Normal file
53
ScriptConverter/Ast/Statements/IfStatement.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using ScriptConverter.Ast.Expressions;
|
||||
using ScriptConverter.Parser;
|
||||
|
||||
namespace ScriptConverter.Ast.Statements
|
||||
{
|
||||
class IfStatement : Statement
|
||||
{
|
||||
public class Branch
|
||||
{
|
||||
public Expression Condition { get; private set; }
|
||||
public BlockStatement Block { get; private set; }
|
||||
|
||||
public Branch(Expression condition, BlockStatement block)
|
||||
{
|
||||
Condition = condition;
|
||||
Block = block;
|
||||
}
|
||||
}
|
||||
|
||||
public ReadOnlyCollection<Branch> Branches { get; private set; }
|
||||
public Branch DefaultBranch { get; private set; }
|
||||
|
||||
public IfStatement(ScriptToken start, ScriptToken end, List<Branch> branches, Branch defaultBranch)
|
||||
: base(start, end)
|
||||
{
|
||||
Branches = branches.AsReadOnly();
|
||||
DefaultBranch = defaultBranch;
|
||||
}
|
||||
|
||||
public override TStmt Accept<TDoc, TDecl, TStmt, TExpr>(IAstVisitor<TDoc, TDecl, TStmt, TExpr> visitor)
|
||||
{
|
||||
return visitor.Visit(this);
|
||||
}
|
||||
|
||||
public override void SetParent(Statement parent)
|
||||
{
|
||||
Parent = parent;
|
||||
|
||||
foreach (var branch in Branches)
|
||||
{
|
||||
branch.Condition.SetParent(null);
|
||||
branch.Block.SetParent(this);
|
||||
}
|
||||
|
||||
if (DefaultBranch != null)
|
||||
{
|
||||
DefaultBranch.Block.SetParent(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
27
ScriptConverter/Ast/Statements/NakedStatement.cs
Normal file
27
ScriptConverter/Ast/Statements/NakedStatement.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using ScriptConverter.Ast.Expressions;
|
||||
|
||||
namespace ScriptConverter.Ast.Statements
|
||||
{
|
||||
class NakedStatement : Statement
|
||||
{
|
||||
public Expression Expression { get; private set; }
|
||||
|
||||
public NakedStatement(Expression expression)
|
||||
: base(expression.Start, expression.End)
|
||||
{
|
||||
Expression = expression;
|
||||
}
|
||||
|
||||
public override TStmt Accept<TDoc, TDecl, TStmt, TExpr>(IAstVisitor<TDoc, TDecl, TStmt, TExpr> visitor)
|
||||
{
|
||||
return visitor.Visit(this);
|
||||
}
|
||||
|
||||
public override void SetParent(Statement parent)
|
||||
{
|
||||
Parent = parent;
|
||||
|
||||
Expression.SetParent(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
29
ScriptConverter/Ast/Statements/ReturnStatement.cs
Normal file
29
ScriptConverter/Ast/Statements/ReturnStatement.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using ScriptConverter.Ast.Expressions;
|
||||
using ScriptConverter.Parser;
|
||||
|
||||
namespace ScriptConverter.Ast.Statements
|
||||
{
|
||||
class ReturnStatement : Statement
|
||||
{
|
||||
public Expression Value { get; private set; }
|
||||
|
||||
public ReturnStatement(ScriptToken start, ScriptToken end, Expression value)
|
||||
: base(start, end)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public override TStmt Accept<TDoc, TDecl, TStmt, TExpr>(IAstVisitor<TDoc, TDecl, TStmt, TExpr> visitor)
|
||||
{
|
||||
return visitor.Visit(this);
|
||||
}
|
||||
|
||||
public override void SetParent(Statement parent)
|
||||
{
|
||||
Parent = parent;
|
||||
|
||||
if (Value != null)
|
||||
Value.SetParent(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
25
ScriptConverter/Ast/Statements/Statement.cs
Normal file
25
ScriptConverter/Ast/Statements/Statement.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using ScriptConverter.Parser;
|
||||
|
||||
namespace ScriptConverter.Ast.Statements
|
||||
{
|
||||
abstract class Statement
|
||||
{
|
||||
public readonly ScriptToken Start;
|
||||
public readonly ScriptToken End;
|
||||
public Statement Parent { get; protected set; }
|
||||
|
||||
protected Statement(ScriptToken start, ScriptToken end = null)
|
||||
{
|
||||
if (start == null)
|
||||
throw new ArgumentNullException("start");
|
||||
|
||||
Start = start;
|
||||
End = end ?? start;
|
||||
}
|
||||
|
||||
public abstract TStmt Accept<TDoc, TDecl, TStmt, TExpr>(IAstVisitor<TDoc, TDecl, TStmt, TExpr> visitor);
|
||||
|
||||
public abstract void SetParent(Statement parent);
|
||||
}
|
||||
}
|
||||
55
ScriptConverter/Ast/Statements/SwitchStatement.cs
Normal file
55
ScriptConverter/Ast/Statements/SwitchStatement.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using ScriptConverter.Ast.Expressions;
|
||||
using ScriptConverter.Parser;
|
||||
|
||||
namespace ScriptConverter.Ast.Statements
|
||||
{
|
||||
class SwitchStatement : Statement
|
||||
{
|
||||
public class Branch
|
||||
{
|
||||
public ReadOnlyCollection<Expression> Conditions { get; private set; }
|
||||
public BlockStatement Block { get; private set; }
|
||||
|
||||
public Branch(List<Expression> conditions, BlockStatement block)
|
||||
{
|
||||
Conditions = conditions.AsReadOnly();
|
||||
Block = block;
|
||||
}
|
||||
}
|
||||
|
||||
public Expression Expression { get; private set; }
|
||||
public ReadOnlyCollection<Branch> Branches { get; private set; }
|
||||
|
||||
public SwitchStatement(ScriptToken start, ScriptToken end, Expression expression, List<Branch> branches)
|
||||
: base(start, end)
|
||||
{
|
||||
Expression = expression;
|
||||
Branches = branches.AsReadOnly();
|
||||
}
|
||||
|
||||
public override TStmt Accept<TDoc, TDecl, TStmt, TExpr>(IAstVisitor<TDoc, TDecl, TStmt, TExpr> visitor)
|
||||
{
|
||||
return visitor.Visit(this);
|
||||
}
|
||||
|
||||
public override void SetParent(Statement parent)
|
||||
{
|
||||
Parent = parent;
|
||||
|
||||
Expression.SetParent(null);
|
||||
|
||||
foreach (var branch in Branches)
|
||||
{
|
||||
foreach (var expression in branch.Conditions)
|
||||
{
|
||||
if (expression != null)
|
||||
expression.SetParent(null);
|
||||
}
|
||||
|
||||
branch.Block.SetParent(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
28
ScriptConverter/Ast/Statements/ThrowStatement.cs
Normal file
28
ScriptConverter/Ast/Statements/ThrowStatement.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using ScriptConverter.Ast.Expressions;
|
||||
using ScriptConverter.Parser;
|
||||
|
||||
namespace ScriptConverter.Ast.Statements
|
||||
{
|
||||
class ThrowStatement : Statement
|
||||
{
|
||||
public Expression Value { get; private set; }
|
||||
|
||||
public ThrowStatement(ScriptToken start, Expression value)
|
||||
: base(start, value.End)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public override TStmt Accept<TDoc, TDecl, TStmt, TExpr>(IAstVisitor<TDoc, TDecl, TStmt, TExpr> visitor)
|
||||
{
|
||||
return visitor.Visit(this);
|
||||
}
|
||||
|
||||
public override void SetParent(Statement parent)
|
||||
{
|
||||
Parent = parent;
|
||||
|
||||
Value.SetParent(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
53
ScriptConverter/Ast/Statements/TryStatement.cs
Normal file
53
ScriptConverter/Ast/Statements/TryStatement.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using ScriptConverter.Parser;
|
||||
|
||||
namespace ScriptConverter.Ast.Statements
|
||||
{
|
||||
class TryStatement : Statement
|
||||
{
|
||||
public class Branch
|
||||
{
|
||||
public ScriptType Type { get; private set; }
|
||||
public string Name { get; private set; }
|
||||
public BlockStatement Block { get; private set; }
|
||||
|
||||
public Branch(ScriptType type, string name, BlockStatement block)
|
||||
{
|
||||
Type = type;
|
||||
Name = name;
|
||||
Block = block;
|
||||
}
|
||||
}
|
||||
|
||||
public BlockStatement Block { get; private set; }
|
||||
public ReadOnlyCollection<Branch> Branches { get; private set; }
|
||||
|
||||
public TryStatement(ScriptToken start, ScriptToken end, BlockStatement block, List<Branch> branches) : base(start, end)
|
||||
{
|
||||
if (branches.Count < 1)
|
||||
throw new ArgumentException("need at least 1 branch", "branches");
|
||||
|
||||
Block = block;
|
||||
Branches = branches.AsReadOnly();
|
||||
}
|
||||
|
||||
public override TStmt Accept<TDoc, TDecl, TStmt, TExpr>(IAstVisitor<TDoc, TDecl, TStmt, TExpr> visitor)
|
||||
{
|
||||
return visitor.Visit(this);
|
||||
}
|
||||
|
||||
public override void SetParent(Statement parent)
|
||||
{
|
||||
Parent = parent;
|
||||
|
||||
Block.SetParent(this);
|
||||
|
||||
foreach (var branch in Branches)
|
||||
{
|
||||
branch.Block.SetParent(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
56
ScriptConverter/Ast/Statements/VariableStatement.cs
Normal file
56
ScriptConverter/Ast/Statements/VariableStatement.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using ScriptConverter.Ast.Expressions;
|
||||
using ScriptConverter.Parser;
|
||||
|
||||
namespace ScriptConverter.Ast.Statements
|
||||
{
|
||||
class VariableStatement : Statement
|
||||
{
|
||||
public class Definition
|
||||
{
|
||||
public ScriptType Type { get; private set; }
|
||||
public string Name { get; private set; }
|
||||
public Expression Value { get; private set; }
|
||||
|
||||
public Definition(ScriptType type, string name, Expression value)
|
||||
{
|
||||
Type = type;
|
||||
Name = name;
|
||||
Value = value;
|
||||
}
|
||||
}
|
||||
|
||||
public ScriptType BaseType { get; private set; }
|
||||
public bool Final { get; private set; }
|
||||
public ReadOnlyCollection<Definition> Definitions { get; private set; }
|
||||
|
||||
public VariableStatement(ScriptToken start, ScriptToken end, ScriptType baseType, bool final, List<Definition> definitions)
|
||||
: base(start, end)
|
||||
{
|
||||
if (definitions.Count < 1)
|
||||
throw new ArgumentException("need at least 1 definition", "definitions");
|
||||
|
||||
BaseType = baseType;
|
||||
Final = final;
|
||||
Definitions = definitions.AsReadOnly();
|
||||
}
|
||||
|
||||
public override TStmt Accept<TDoc, TDecl, TStmt, TExpr>(IAstVisitor<TDoc, TDecl, TStmt, TExpr> visitor)
|
||||
{
|
||||
return visitor.Visit(this);
|
||||
}
|
||||
|
||||
public override void SetParent(Statement parent)
|
||||
{
|
||||
Parent = parent;
|
||||
|
||||
foreach (var definition in Definitions)
|
||||
{
|
||||
if (definition.Value != null)
|
||||
definition.Value.SetParent(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
31
ScriptConverter/Ast/Statements/WhileStatement.cs
Normal file
31
ScriptConverter/Ast/Statements/WhileStatement.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using ScriptConverter.Ast.Expressions;
|
||||
using ScriptConverter.Parser;
|
||||
|
||||
namespace ScriptConverter.Ast.Statements
|
||||
{
|
||||
class WhileStatement : Statement
|
||||
{
|
||||
public Expression Condition { get; private set; }
|
||||
public BlockStatement Block { get; private set; }
|
||||
|
||||
public WhileStatement(ScriptToken start, ScriptToken end, Expression condition, BlockStatement block)
|
||||
: base(start, end)
|
||||
{
|
||||
Condition = condition;
|
||||
Block = block;
|
||||
}
|
||||
|
||||
public override TStmt Accept<TDoc, TDecl, TStmt, TExpr>(IAstVisitor<TDoc, TDecl, TStmt, TExpr> visitor)
|
||||
{
|
||||
return visitor.Visit(this);
|
||||
}
|
||||
|
||||
public override void SetParent(Statement parent)
|
||||
{
|
||||
Parent = parent;
|
||||
|
||||
Condition.SetParent(null);
|
||||
Block.SetParent(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
1136
ScriptConverter/AstPrinter.cs
Normal file
1136
ScriptConverter/AstPrinter.cs
Normal file
File diff suppressed because it is too large
Load Diff
406
ScriptConverter/CoreAnnotations.cs
Normal file
406
ScriptConverter/CoreAnnotations.cs
Normal file
@@ -0,0 +1,406 @@
|
||||
/*
|
||||
* Copyright 2007-2011 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace JetBrains.Annotations
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates that marked element should be localized or not.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)]
|
||||
public sealed class LocalizationRequiredAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LocalizationRequiredAttribute"/> class.
|
||||
/// </summary>
|
||||
/// <param name="required"><c>true</c> if a element should be localized; otherwise, <c>false</c>.</param>
|
||||
public LocalizationRequiredAttribute(bool required)
|
||||
{
|
||||
Required = required;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether a element should be localized.
|
||||
/// <value><c>true</c> if a element should be localized; otherwise, <c>false</c>.</value>
|
||||
/// </summary>
|
||||
public bool Required { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether the value of the given object is equal to the current <see cref="LocalizationRequiredAttribute"/>.
|
||||
/// </summary>
|
||||
/// <param name="obj">The object to test the value equality of. </param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the value of the given object is equal to that of the current; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
var attribute = obj as LocalizationRequiredAttribute;
|
||||
return attribute != null && attribute.Required == Required;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the hash code for this instance.
|
||||
/// </summary>
|
||||
/// <returns>A hash code for the current <see cref="LocalizationRequiredAttribute"/>.</returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return base.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that marked method builds string by format pattern and (optional) arguments.
|
||||
/// Parameter, which contains format string, should be given in constructor.
|
||||
/// The format string should be in <see cref="string.Format(IFormatProvider,string,object[])"/> -like form
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Constructor | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
|
||||
public sealed class StringFormatMethodAttribute : Attribute
|
||||
{
|
||||
private readonly string myFormatParameterName;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes new instance of StringFormatMethodAttribute
|
||||
/// </summary>
|
||||
/// <param name="formatParameterName">Specifies which parameter of an annotated method should be treated as format-string</param>
|
||||
public StringFormatMethodAttribute(string formatParameterName)
|
||||
{
|
||||
myFormatParameterName = formatParameterName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets format parameter name
|
||||
/// </summary>
|
||||
public string FormatParameterName
|
||||
{
|
||||
get { return myFormatParameterName; }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the function argument should be string literal and match one of the parameters of the caller function.
|
||||
/// For example, <see cref="ArgumentNullException"/> has such parameter.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)]
|
||||
public sealed class InvokerParameterNameAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the marked method is assertion method, i.e. it halts control flow if one of the conditions is satisfied.
|
||||
/// To set the condition, mark one of the parameters with <see cref="AssertionConditionAttribute"/> attribute
|
||||
/// </summary>
|
||||
/// <seealso cref="AssertionConditionAttribute"/>
|
||||
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
|
||||
public sealed class AssertionMethodAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the condition parameter of the assertion method.
|
||||
/// The method itself should be marked by <see cref="AssertionMethodAttribute"/> attribute.
|
||||
/// The mandatory argument of the attribute is the assertion type.
|
||||
/// </summary>
|
||||
/// <seealso cref="AssertionConditionType"/>
|
||||
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)]
|
||||
public sealed class AssertionConditionAttribute : Attribute
|
||||
{
|
||||
private readonly AssertionConditionType myConditionType;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes new instance of AssertionConditionAttribute
|
||||
/// </summary>
|
||||
/// <param name="conditionType">Specifies condition type</param>
|
||||
public AssertionConditionAttribute(AssertionConditionType conditionType)
|
||||
{
|
||||
myConditionType = conditionType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets condition type
|
||||
/// </summary>
|
||||
public AssertionConditionType ConditionType
|
||||
{
|
||||
get { return myConditionType; }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specifies assertion type. If the assertion method argument satisifes the condition, then the execution continues.
|
||||
/// Otherwise, execution is assumed to be halted
|
||||
/// </summary>
|
||||
public enum AssertionConditionType
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates that the marked parameter should be evaluated to true
|
||||
/// </summary>
|
||||
IS_TRUE = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the marked parameter should be evaluated to false
|
||||
/// </summary>
|
||||
IS_FALSE = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the marked parameter should be evaluated to null value
|
||||
/// </summary>
|
||||
IS_NULL = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the marked parameter should be evaluated to not null value
|
||||
/// </summary>
|
||||
IS_NOT_NULL = 3,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the marked method unconditionally terminates control flow execution.
|
||||
/// For example, it could unconditionally throw exception
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
|
||||
public sealed class TerminatesProgramAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the value of marked element could be <c>null</c> sometimes, so the check for <c>null</c> is necessary before its usage
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.Delegate | AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
|
||||
public sealed class CanBeNullAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the value of marked element could never be <c>null</c>
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.Delegate | AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
|
||||
public sealed class NotNullAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the value of marked type (or its derivatives) cannot be compared using '==' or '!=' operators.
|
||||
/// There is only exception to compare with <c>null</c>, it is permitted
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Interface | AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = true)]
|
||||
public sealed class CannotApplyEqualityOperatorAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When applied to target attribute, specifies a requirement for any type which is marked with
|
||||
/// target attribute to implement or inherit specific type or types
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// [BaseTypeRequired(typeof(IComponent)] // Specify requirement
|
||||
/// public class ComponentAttribute : Attribute
|
||||
/// {}
|
||||
///
|
||||
/// [Component] // ComponentAttribute requires implementing IComponent interface
|
||||
/// public class MyComponent : IComponent
|
||||
/// {}
|
||||
/// </code>
|
||||
/// </example>
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
|
||||
[BaseTypeRequired(typeof(Attribute))]
|
||||
public sealed class BaseTypeRequiredAttribute : Attribute
|
||||
{
|
||||
private readonly Type[] myBaseTypes;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes new instance of BaseTypeRequiredAttribute
|
||||
/// </summary>
|
||||
/// <param name="baseType">Specifies which types are required</param>
|
||||
public BaseTypeRequiredAttribute(Type baseType)
|
||||
{
|
||||
myBaseTypes = new[] { baseType };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets enumerations of specified base types
|
||||
/// </summary>
|
||||
public IEnumerable<Type> BaseTypes
|
||||
{
|
||||
get { return myBaseTypes; }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the marked symbol is used implicitly (e.g. via reflection, in external library),
|
||||
/// so this symbol will not be marked as unused (as well as by other usage inspections)
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)]
|
||||
public sealed class UsedImplicitlyAttribute : Attribute
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public UsedImplicitlyAttribute()
|
||||
: this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default)
|
||||
{
|
||||
}
|
||||
|
||||
[UsedImplicitly]
|
||||
public UsedImplicitlyAttribute(ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags)
|
||||
{
|
||||
UseKindFlags = useKindFlags;
|
||||
TargetFlags = targetFlags;
|
||||
}
|
||||
|
||||
[UsedImplicitly]
|
||||
public UsedImplicitlyAttribute(ImplicitUseKindFlags useKindFlags)
|
||||
: this(useKindFlags, ImplicitUseTargetFlags.Default)
|
||||
{
|
||||
}
|
||||
|
||||
[UsedImplicitly]
|
||||
public UsedImplicitlyAttribute(ImplicitUseTargetFlags targetFlags)
|
||||
: this(ImplicitUseKindFlags.Default, targetFlags)
|
||||
{
|
||||
}
|
||||
|
||||
[UsedImplicitly]
|
||||
public ImplicitUseKindFlags UseKindFlags { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets value indicating what is meant to be used
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public ImplicitUseTargetFlags TargetFlags { get; private set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Should be used on attributes and causes ReSharper to not mark symbols marked with such attributes as unused (as well as by other usage inspections)
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
|
||||
public sealed class MeansImplicitUseAttribute : Attribute
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public MeansImplicitUseAttribute()
|
||||
: this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default)
|
||||
{
|
||||
}
|
||||
|
||||
[UsedImplicitly]
|
||||
public MeansImplicitUseAttribute(ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags)
|
||||
{
|
||||
UseKindFlags = useKindFlags;
|
||||
TargetFlags = targetFlags;
|
||||
}
|
||||
|
||||
[UsedImplicitly]
|
||||
public MeansImplicitUseAttribute(ImplicitUseKindFlags useKindFlags)
|
||||
: this(useKindFlags, ImplicitUseTargetFlags.Default)
|
||||
{
|
||||
}
|
||||
|
||||
[UsedImplicitly]
|
||||
public MeansImplicitUseAttribute(ImplicitUseTargetFlags targetFlags)
|
||||
: this(ImplicitUseKindFlags.Default, targetFlags)
|
||||
{
|
||||
}
|
||||
|
||||
[UsedImplicitly]
|
||||
public ImplicitUseKindFlags UseKindFlags { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets value indicating what is meant to be used
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public ImplicitUseTargetFlags TargetFlags { get; private set; }
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum ImplicitUseKindFlags
|
||||
{
|
||||
Default = Access | Assign | InstantiatedWithFixedConstructorSignature,
|
||||
|
||||
/// <summary>
|
||||
/// Only entity marked with attribute considered used
|
||||
/// </summary>
|
||||
Access = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates implicit assignment to a member
|
||||
/// </summary>
|
||||
Assign = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates implicit instantiation of a type with fixed constructor signature.
|
||||
/// That means any unused constructor parameters won't be reported as such.
|
||||
/// </summary>
|
||||
InstantiatedWithFixedConstructorSignature = 4,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates implicit instantiation of a type
|
||||
/// </summary>
|
||||
InstantiatedNoFixedConstructorSignature = 8,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specify what is considered used implicitly when marked with <see cref="MeansImplicitUseAttribute"/> or <see cref="UsedImplicitlyAttribute"/>
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum ImplicitUseTargetFlags
|
||||
{
|
||||
Default = Itself,
|
||||
|
||||
Itself = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Members of entity marked with attribute are considered used
|
||||
/// </summary>
|
||||
Members = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Entity marked with attribute and all its members considered used
|
||||
/// </summary>
|
||||
WithMembers = Itself | Members
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This attribute is intended to mark publicly available API which should not be removed and so is treated as used.
|
||||
/// </summary>
|
||||
[MeansImplicitUse]
|
||||
public sealed class PublicAPIAttribute : Attribute
|
||||
{
|
||||
public PublicAPIAttribute()
|
||||
{
|
||||
}
|
||||
|
||||
// ReSharper disable UnusedParameter.Local
|
||||
public PublicAPIAttribute(string comment)
|
||||
// ReSharper restore UnusedParameter.Local
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tells code analysis engine if the parameter is completely handled when the invoked method is on stack.
|
||||
/// If the parameter is delegate, indicates that delegate is executed while the method is executed.
|
||||
/// If the parameter is enumerable, indicates that it is enumerated while the method is executed.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Parameter, Inherited = true)]
|
||||
public sealed class InstantHandleAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that method doesn't contain observable side effects.
|
||||
/// The same as <see cref="System.Diagnostics.Contracts.PureAttribute"/>
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Method, Inherited = true)]
|
||||
public sealed class PureAttribute : Attribute { }
|
||||
}
|
||||
20
ScriptConverter/GenericComparer.cs
Normal file
20
ScriptConverter/GenericComparer.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ScriptConverter
|
||||
{
|
||||
public class GenericComparer<T> : IComparer<T>
|
||||
{
|
||||
private Func<T, T, int> _comparer;
|
||||
|
||||
public GenericComparer(Func<T, T, int> comparer)
|
||||
{
|
||||
_comparer = comparer;
|
||||
}
|
||||
|
||||
public int Compare(T x, T y)
|
||||
{
|
||||
return _comparer(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
63
ScriptConverter/IndentTextWriter.cs
Normal file
63
ScriptConverter/IndentTextWriter.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace ScriptConverter
|
||||
{
|
||||
public class IndentTextWriter : TextWriter
|
||||
{
|
||||
private readonly TextWriter _writer;
|
||||
private readonly string _indentStr;
|
||||
private bool _shouldIndent;
|
||||
|
||||
public int Indent { get; set; }
|
||||
|
||||
public IndentTextWriter(TextWriter writer, string indentStr = " ")
|
||||
{
|
||||
_writer = writer;
|
||||
_indentStr = indentStr;
|
||||
_shouldIndent = false;
|
||||
}
|
||||
|
||||
public override Encoding Encoding
|
||||
{
|
||||
get { return Encoding.Unicode; }
|
||||
}
|
||||
|
||||
public override IFormatProvider FormatProvider
|
||||
{
|
||||
get { return CultureInfo.InvariantCulture; }
|
||||
}
|
||||
|
||||
public override void Write(char value)
|
||||
{
|
||||
if (_shouldIndent)
|
||||
{
|
||||
_shouldIndent = false; // shouldIndent must be cleared first
|
||||
WriteIndent();
|
||||
}
|
||||
|
||||
_writer.Write(value);
|
||||
}
|
||||
|
||||
public override void WriteLine()
|
||||
{
|
||||
base.WriteLine();
|
||||
|
||||
_shouldIndent = true; // defer indenting until the next Write
|
||||
}
|
||||
|
||||
public override void WriteLine(string value)
|
||||
{
|
||||
Write(value);
|
||||
WriteLine();
|
||||
}
|
||||
|
||||
public void WriteIndent()
|
||||
{
|
||||
for (var i = 0; i < Indent; i++)
|
||||
Write(_indentStr);
|
||||
}
|
||||
}
|
||||
}
|
||||
13
ScriptConverter/Parser/CompilerError.cs
Normal file
13
ScriptConverter/Parser/CompilerError.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace ScriptConverter.Parser
|
||||
{
|
||||
static class CompilerError
|
||||
{
|
||||
public const string UnterminatedString = "Unterminated string";
|
||||
public const string UnexpectedEofString = "Unexpected end of file (bad escape sequence)";
|
||||
public const string InvalidEscapeSequence = "Invalid escape sequence '{0}'";
|
||||
public const string CharLiteralLength = "Character literals must be one byte long";
|
||||
public const string InvalidNumber = "Invalid {0} number '{1}'";
|
||||
|
||||
public const string ExpectedButFound = "Expected {0} but found {1}";
|
||||
}
|
||||
}
|
||||
21
ScriptConverter/Parser/CompilerException.cs
Normal file
21
ScriptConverter/Parser/CompilerException.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace ScriptConverter.Parser
|
||||
{
|
||||
public class CompilerException : Exception
|
||||
{
|
||||
protected CompilerException(string message)
|
||||
: base(message)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
[StringFormatMethod("format")]
|
||||
internal CompilerException(ScriptToken token, string format, params object[] args)
|
||||
: base(string.Format("{0}({1}): {2}", token.FileName ?? "null", token.RangeString, string.Format(format, args)))
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
60
ScriptConverter/Parser/Lexer.Static.cs
Normal file
60
ScriptConverter/Parser/Lexer.Static.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ScriptConverter.Parser
|
||||
{
|
||||
abstract partial class Lexer<TToken, TTokenType>
|
||||
{
|
||||
protected static TToken EofToken;
|
||||
|
||||
static Lexer()
|
||||
{
|
||||
EofToken = null;
|
||||
}
|
||||
|
||||
protected class OperatorDictionary<T> : IEnumerable<object>
|
||||
{
|
||||
private readonly GenericComparer<Tuple<string, T>> _comparer;
|
||||
private Dictionary<char, List<Tuple<string, T>>> _operatorDictionary;
|
||||
|
||||
public OperatorDictionary()
|
||||
{
|
||||
_comparer = new GenericComparer<Tuple<string, T>>((a, b) => b.Item1.Length - a.Item1.Length);
|
||||
_operatorDictionary = new Dictionary<char, List<Tuple<string, T>>>();
|
||||
}
|
||||
|
||||
public void Add(string op, T type)
|
||||
{
|
||||
List<Tuple<string, T>> list;
|
||||
if (!_operatorDictionary.TryGetValue(op[0], out list))
|
||||
{
|
||||
list = new List<Tuple<string, T>>();
|
||||
_operatorDictionary.Add(op[0], list);
|
||||
}
|
||||
|
||||
list.Add(Tuple.Create(op, type));
|
||||
list.Sort(_comparer);
|
||||
}
|
||||
|
||||
public IEnumerable<Tuple<string, T>> Lookup(char ch)
|
||||
{
|
||||
List<Tuple<string, T>> list;
|
||||
if (!_operatorDictionary.TryGetValue(ch, out list))
|
||||
return null;
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public IEnumerator<object> GetEnumerator()
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
224
ScriptConverter/Parser/Lexer.cs
Normal file
224
ScriptConverter/Parser/Lexer.cs
Normal file
@@ -0,0 +1,224 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace ScriptConverter.Parser
|
||||
{
|
||||
abstract partial class Lexer<TToken, TTokenType> : IEnumerable<TToken>
|
||||
where TToken : Token<TTokenType>
|
||||
{
|
||||
protected delegate bool LexerRule(char ch, out TToken token);
|
||||
|
||||
private readonly IEnumerable<char> _sourceEnumerable;
|
||||
private IEnumerator<char> _source;
|
||||
private int _length;
|
||||
private List<char> _read;
|
||||
private int _index;
|
||||
|
||||
protected string FileName { get; private set; }
|
||||
protected int Line { get; private set; }
|
||||
protected int Column { get; private set; }
|
||||
protected int StartLine { get; private set; }
|
||||
protected int StartColumn { get; private set; }
|
||||
|
||||
protected List<LexerRule> Rules { get; set; }
|
||||
|
||||
protected bool AtEof
|
||||
{
|
||||
get { return _index >= _length; }
|
||||
}
|
||||
|
||||
protected Lexer(IEnumerable<char> source, string fileName = null)
|
||||
{
|
||||
if (source == null)
|
||||
throw new ArgumentNullException("source");
|
||||
|
||||
FileName = fileName;
|
||||
_sourceEnumerable = source;
|
||||
}
|
||||
|
||||
public IEnumerator<TToken> GetEnumerator()
|
||||
{
|
||||
if (Rules == null)
|
||||
throw new Exception("Rules must be set");
|
||||
|
||||
if (EofToken == null)
|
||||
throw new Exception("EofToken must be set");
|
||||
|
||||
_length = int.MaxValue;
|
||||
_source = _sourceEnumerable.GetEnumerator();
|
||||
_read = new List<char>(16);
|
||||
|
||||
_index = 0;
|
||||
|
||||
Line = 1;
|
||||
Column = 1;
|
||||
|
||||
while (_index < _length)
|
||||
{
|
||||
SkipWhiteSpace();
|
||||
|
||||
if (SkipComment())
|
||||
continue;
|
||||
|
||||
if (_index >= _length)
|
||||
break;
|
||||
|
||||
StartLine = Line;
|
||||
StartColumn = Column;
|
||||
|
||||
var ch = PeekChar();
|
||||
TToken token = null;
|
||||
|
||||
if (!Rules.Any(rule => rule(ch, out token)))
|
||||
throw Error("Unexpected character '{0}'", ch);
|
||||
|
||||
yield return token;
|
||||
}
|
||||
|
||||
while (true)
|
||||
yield return EofToken;
|
||||
}
|
||||
|
||||
protected virtual bool SkipComment()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void SkipWhiteSpace()
|
||||
{
|
||||
while (_index < _length)
|
||||
{
|
||||
var ch = PeekChar();
|
||||
|
||||
if (!char.IsWhiteSpace(ch))
|
||||
break;
|
||||
|
||||
TakeChar();
|
||||
}
|
||||
}
|
||||
|
||||
protected bool TakeIfNext(string value)
|
||||
{
|
||||
if (!IsNext(value))
|
||||
return false;
|
||||
|
||||
for (var i = 0; i < value.Length; i++)
|
||||
TakeChar();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected bool IsNext(string value)
|
||||
{
|
||||
if (_index + value.Length > _length)
|
||||
return false;
|
||||
|
||||
return !value.Where((t, i) => PeekChar(i) != t).Any();
|
||||
}
|
||||
|
||||
protected string TakeWhile(Func<char, bool> condition)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
while (_index < _length)
|
||||
{
|
||||
var ch = PeekChar();
|
||||
|
||||
if (!condition(ch))
|
||||
break;
|
||||
|
||||
sb.Append(TakeChar());
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
protected char TakeChar()
|
||||
{
|
||||
var result = TakeCharImpl();
|
||||
|
||||
if (result == '\n')
|
||||
{
|
||||
Line++;
|
||||
Column = 0;
|
||||
}
|
||||
|
||||
if (result == '\r')
|
||||
{
|
||||
if (PeekChar() == '\n')
|
||||
TakeCharImpl();
|
||||
|
||||
Line++;
|
||||
Column = 0;
|
||||
}
|
||||
|
||||
Column++;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private char TakeCharImpl()
|
||||
{
|
||||
PeekChar();
|
||||
|
||||
var result = _read[0];
|
||||
_read.RemoveAt(0);
|
||||
_index++;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected string PeekString(int length)
|
||||
{
|
||||
if (length <= 0)
|
||||
throw new ArgumentOutOfRangeException("length", "distance must be at least 1");
|
||||
|
||||
var sb = new StringBuilder(length);
|
||||
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
sb.Append(PeekChar(i));
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
protected char PeekChar(int distance = 0)
|
||||
{
|
||||
if (distance < 0)
|
||||
throw new ArgumentOutOfRangeException("distance", "distance can't be negative");
|
||||
|
||||
while (_read.Count <= distance)
|
||||
{
|
||||
var success = _source.MoveNext();
|
||||
_read.Add(success ? _source.Current : '\0');
|
||||
|
||||
if (!success)
|
||||
_length = _index + _read.Count - 1;
|
||||
}
|
||||
|
||||
return _read[distance];
|
||||
}
|
||||
|
||||
[StringFormatMethod("format")]
|
||||
protected Exception Error(string format, params object[] args)
|
||||
{
|
||||
return new LexerException(FileName, new SourcePosition(Line, Column), format, args);
|
||||
}
|
||||
|
||||
[StringFormatMethod("format")]
|
||||
protected Exception ErrorStart(string format, params object[] args)
|
||||
{
|
||||
return new LexerException(FileName, new SourcePosition(StartLine, StartColumn), format, args);
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
15
ScriptConverter/Parser/LexerException.cs
Normal file
15
ScriptConverter/Parser/LexerException.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace ScriptConverter.Parser
|
||||
{
|
||||
class LexerException : Exception
|
||||
{
|
||||
[StringFormatMethod("format")]
|
||||
internal LexerException(string fileName, SourcePosition pos, string format, params object[] args)
|
||||
: base(string.Format("{0}({1}): {2}", fileName ?? "null", pos, string.Format(format, args)))
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using ScriptConverter.Ast;
|
||||
using ScriptConverter.Ast.Declarations;
|
||||
|
||||
namespace ScriptConverter.Parser.Parselets.Declarations
|
||||
{
|
||||
class ConstParselet : IDeclarationParselet
|
||||
{
|
||||
public Declaration Parse(ScriptParser parser, ScriptToken token)
|
||||
{
|
||||
ScriptType type;
|
||||
string name;
|
||||
parser.ParseNamedType(out type, out name);
|
||||
|
||||
parser.Take(ScriptTokenType.Assign);
|
||||
|
||||
var value = parser.ParseExpression();
|
||||
|
||||
parser.Take(ScriptTokenType.Semicolon);
|
||||
|
||||
return new FieldDeclaration(token, parser.Previous, type, name, value, true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using ScriptConverter.Ast.Declarations;
|
||||
|
||||
namespace ScriptConverter.Parser.Parselets.Declarations
|
||||
{
|
||||
class IncludeParselet : IDeclarationParselet
|
||||
{
|
||||
public Declaration Parse(ScriptParser parser, ScriptToken token)
|
||||
{
|
||||
var done = false;
|
||||
var tokens = parser.ParseSeparatedBy(ScriptTokenType.Dot, (_, first) =>
|
||||
{
|
||||
if (done)
|
||||
return null;
|
||||
|
||||
if (parser.Match(ScriptTokenType.Multiply))
|
||||
{
|
||||
done = true;
|
||||
return parser.Take(ScriptTokenType.Multiply);
|
||||
}
|
||||
|
||||
return parser.Take(ScriptTokenType.Identifier);
|
||||
});
|
||||
|
||||
var name = string.Join(".", tokens.Select(t => t.Contents));
|
||||
|
||||
if (!parser.MatchAndTake(ScriptTokenType.Semicolon))
|
||||
Console.WriteLine("JFjngkjasnholjhnaskl");
|
||||
|
||||
return new IncludeDeclaration(token, parser.Previous, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using ScriptConverter.Ast.Declarations;
|
||||
|
||||
namespace ScriptConverter.Parser.Parselets.Declarations
|
||||
{
|
||||
class InheritsParselet : IDeclarationParselet
|
||||
{
|
||||
public Declaration Parse(ScriptParser parser, ScriptToken token)
|
||||
{
|
||||
var tokens = parser.ParseSeparatedBy(ScriptTokenType.Dot, (_, first) => parser.Take(ScriptTokenType.Identifier));
|
||||
|
||||
var name = string.Join(".", tokens.Select(t => t.Contents));
|
||||
|
||||
if (!parser.MatchAndTake(ScriptTokenType.Semicolon))
|
||||
Console.WriteLine("fkshgnbkashnkhnasb");
|
||||
|
||||
return new InheritsDeclaration(token, parser.Previous, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using System.Linq;
|
||||
using ScriptConverter.Ast;
|
||||
using ScriptConverter.Ast.Declarations;
|
||||
|
||||
namespace ScriptConverter.Parser.Parselets.Declarations
|
||||
{
|
||||
class MethodParselet : IDeclarationParselet
|
||||
{
|
||||
public Declaration Parse(ScriptParser parser, ScriptToken token)
|
||||
{
|
||||
var returnType = parser.ParseType(token);
|
||||
var name = parser.Take(ScriptTokenType.Identifier).Contents;
|
||||
|
||||
if (parser.MatchAndTake(ScriptTokenType.Assign))
|
||||
{
|
||||
var value = parser.ParseExpression();
|
||||
parser.Take(ScriptTokenType.Semicolon);
|
||||
|
||||
return new FieldDeclaration(token, parser.Previous, returnType, name, value, false, false);
|
||||
}
|
||||
|
||||
parser.Take(ScriptTokenType.LeftParen);
|
||||
|
||||
var parameters = parser.ParseSeparatedBy(ScriptTokenType.Comma, (_, first) =>
|
||||
{
|
||||
if (parser.Match(ScriptTokenType.RightParen))
|
||||
return null;
|
||||
|
||||
ScriptType paramType;
|
||||
string paramName;
|
||||
parser.ParseNamedType(out paramType, out paramName);
|
||||
|
||||
return new MethodDeclaration.Parameter(paramType, paramName);
|
||||
}).ToList();
|
||||
|
||||
parser.Take(ScriptTokenType.RightParen);
|
||||
|
||||
var block = parser.ParseBlock(false);
|
||||
|
||||
return new MethodDeclaration(token, parser.Previous, returnType, name, parameters, block);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using ScriptConverter.Ast;
|
||||
using ScriptConverter.Ast.Declarations;
|
||||
|
||||
namespace ScriptConverter.Parser.Parselets.Declarations
|
||||
{
|
||||
class PublicParselet : IDeclarationParselet
|
||||
{
|
||||
public Declaration Parse(ScriptParser parser, ScriptToken token)
|
||||
{
|
||||
ScriptType type;
|
||||
string name;
|
||||
parser.ParseNamedType(out type, out name);
|
||||
|
||||
parser.Take(ScriptTokenType.Assign);
|
||||
|
||||
var value = parser.ParseExpression();
|
||||
|
||||
parser.Take(ScriptTokenType.Semicolon);
|
||||
|
||||
return new FieldDeclaration(token, parser.Previous, type, name, value, false, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using System.Linq;
|
||||
using ScriptConverter.Ast.Expressions;
|
||||
|
||||
namespace ScriptConverter.Parser.Parselets.Expressions
|
||||
{
|
||||
class ArrayInitializerParselet : IPrefixParselet
|
||||
{
|
||||
public Expression Parse(ScriptParser parser, ScriptToken token)
|
||||
{
|
||||
var values = parser.ParseSeparatedBy(ScriptTokenType.Comma, (_, first) =>
|
||||
{
|
||||
if (parser.Match(ScriptTokenType.RightBrace))
|
||||
return null;
|
||||
|
||||
return parser.ParseExpression();
|
||||
}).ToList();
|
||||
|
||||
parser.Take(ScriptTokenType.RightBrace);
|
||||
return new ArrayInitializerExpression(token, parser.Previous, values);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using ScriptConverter.Ast.Expressions;
|
||||
|
||||
namespace ScriptConverter.Parser.Parselets.Expressions
|
||||
{
|
||||
class BinaryOperatorParselet : IInfixParselet
|
||||
{
|
||||
private readonly bool _isRight;
|
||||
|
||||
public BinaryOperatorParselet(PrecedenceValue precedence, bool isRight)
|
||||
{
|
||||
_isRight = isRight;
|
||||
Precedence = (int)precedence;
|
||||
}
|
||||
|
||||
public int Precedence { get; private set; }
|
||||
|
||||
public Expression Parse(ScriptParser parser, Expression left, ScriptToken token)
|
||||
{
|
||||
var right = parser.ParseExpression(Precedence - (_isRight ? 1 : 0));
|
||||
return new BinaryOperatorExpression(token.Type, left, right);
|
||||
}
|
||||
}
|
||||
}
|
||||
19
ScriptConverter/Parser/Parselets/Expressions/BoolParselet.cs
Normal file
19
ScriptConverter/Parser/Parselets/Expressions/BoolParselet.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using ScriptConverter.Ast.Expressions;
|
||||
|
||||
namespace ScriptConverter.Parser.Parselets.Expressions
|
||||
{
|
||||
class BoolParselet : IPrefixParselet
|
||||
{
|
||||
private readonly bool _value;
|
||||
|
||||
public BoolParselet(bool value)
|
||||
{
|
||||
_value = value;
|
||||
}
|
||||
|
||||
public Expression Parse(ScriptParser parser, ScriptToken token)
|
||||
{
|
||||
return new BoolExpression(token, _value);
|
||||
}
|
||||
}
|
||||
}
|
||||
25
ScriptConverter/Parser/Parselets/Expressions/CallParselet.cs
Normal file
25
ScriptConverter/Parser/Parselets/Expressions/CallParselet.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System.Linq;
|
||||
using ScriptConverter.Ast.Expressions;
|
||||
|
||||
namespace ScriptConverter.Parser.Parselets.Expressions
|
||||
{
|
||||
class CallParselet : IInfixParselet
|
||||
{
|
||||
public int Precedence { get { return (int)PrecedenceValue.Suffix; } }
|
||||
|
||||
public Expression Parse(ScriptParser parser, Expression left, ScriptToken token)
|
||||
{
|
||||
var parameters = parser.ParseSeparatedBy(ScriptTokenType.Comma, (_, first) =>
|
||||
{
|
||||
if (first && parser.Match(ScriptTokenType.RightParen))
|
||||
return null;
|
||||
|
||||
return parser.ParseExpression();
|
||||
}).ToList();
|
||||
|
||||
parser.Take(ScriptTokenType.RightParen);
|
||||
|
||||
return new CallExpression(parser.Previous, left, parameters);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using ScriptConverter.Ast.Expressions;
|
||||
|
||||
namespace ScriptConverter.Parser.Parselets.Expressions
|
||||
{
|
||||
class FieldParselet : IInfixParselet
|
||||
{
|
||||
public int Precedence { get { return (int)PrecedenceValue.Suffix; } }
|
||||
|
||||
public Expression Parse(ScriptParser parser, Expression left, ScriptToken token)
|
||||
{
|
||||
var name = parser.Take(ScriptTokenType.Identifier);
|
||||
return new FieldExpression(left, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using ScriptConverter.Ast.Expressions;
|
||||
|
||||
namespace ScriptConverter.Parser.Parselets.Expressions
|
||||
{
|
||||
class GroupParselet : IPrefixParselet
|
||||
{
|
||||
public Expression Parse(ScriptParser parser, ScriptToken token)
|
||||
{
|
||||
if (IsCast(parser))
|
||||
{
|
||||
var type = parser.ParseType();
|
||||
parser.Take(ScriptTokenType.RightParen);
|
||||
var value = parser.ParseExpression((int)PrecedenceValue.Cast - 1);
|
||||
return new CastExpression(token, type, value);
|
||||
}
|
||||
|
||||
var expression = parser.ParseExpression();
|
||||
parser.Take(ScriptTokenType.RightParen);
|
||||
return expression;
|
||||
}
|
||||
|
||||
private static bool IsCast(ScriptParser parser)
|
||||
{
|
||||
var token = parser.Peek();
|
||||
if (token.Type != ScriptTokenType.Identifier)
|
||||
return false;
|
||||
|
||||
if (token.Contents == "resizeable")
|
||||
return true;
|
||||
|
||||
var i = 1;
|
||||
while (parser.Match(ScriptTokenType.Dot, i) && parser.Match(ScriptTokenType.Identifier, i + 1))
|
||||
{
|
||||
i += 2;
|
||||
}
|
||||
|
||||
var next1Type = parser.Peek(i).Type;
|
||||
var next2Type = parser.Peek(i + 1).Type;
|
||||
|
||||
return (next1Type == ScriptTokenType.RightParen && IsCastable(next2Type)) ||
|
||||
(next1Type == ScriptTokenType.LeftSquare && next2Type == ScriptTokenType.RightSquare);
|
||||
}
|
||||
|
||||
private static bool IsCastable(ScriptTokenType token)
|
||||
{
|
||||
return token == ScriptTokenType.Identifier ||
|
||||
token == ScriptTokenType.Number ||
|
||||
token == ScriptTokenType.Null ||
|
||||
token == ScriptTokenType.LeftParen ||
|
||||
token == ScriptTokenType.SingleString ||
|
||||
token == ScriptTokenType.String;
|
||||
}
|
||||
}
|
||||
}
|
||||
86
ScriptConverter/Parser/Parselets/Expressions/HashParselet.cs
Normal file
86
ScriptConverter/Parser/Parselets/Expressions/HashParselet.cs
Normal file
@@ -0,0 +1,86 @@
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using ScriptConverter.Ast.Expressions;
|
||||
|
||||
namespace ScriptConverter.Parser.Parselets.Expressions
|
||||
{
|
||||
class HashParselet : IPrefixParselet
|
||||
{
|
||||
public Expression Parse(ScriptParser parser, ScriptToken token)
|
||||
{
|
||||
var str = parser.Take(ScriptTokenType.String);
|
||||
var crc = (int)StringtoCrc(str.Contents);
|
||||
var crcStr = "0x" + crc.ToString("X8");
|
||||
return new NumberExpression(new ScriptToken(str, ScriptTokenType.Number, crcStr));
|
||||
}
|
||||
|
||||
private static uint StringtoCrc(string input)
|
||||
{
|
||||
byte[] bytes = Encoding.ASCII.GetBytes(input.ToArray());
|
||||
uint crc = 0xFFFFFFFF;
|
||||
|
||||
for (int i = 0; i < bytes.Length; ++i)
|
||||
{
|
||||
crc = _crcTable[(bytes[i] ^ (crc >> 24)) & 0x000000FF] ^ (crc << 8);
|
||||
}
|
||||
|
||||
return ~crc;
|
||||
}
|
||||
|
||||
private static uint[] _crcTable =
|
||||
{
|
||||
0x0000000,
|
||||
0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B,
|
||||
0x1A864DB2, 0x1E475005, 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6,
|
||||
0x2B4BCB61, 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD,
|
||||
0x4C11DB70, 0x48D0C6C7, 0x4593E01E, 0x4152FDA9, 0x5F15ADAC,
|
||||
0x5BD4B01B, 0x569796C2, 0x52568B75, 0x6A1936C8, 0x6ED82B7F,
|
||||
0x639B0DA6, 0x675A1011, 0x791D4014, 0x7DDC5DA3, 0x709F7B7A,
|
||||
0x745E66CD, 0x9823B6E0, 0x9CE2AB57, 0x91A18D8E, 0x95609039,
|
||||
0x8B27C03C, 0x8FE6DD8B, 0x82A5FB52, 0x8664E6E5, 0xBE2B5B58,
|
||||
0xBAEA46EF, 0xB7A96036, 0xB3687D81, 0xAD2F2D84, 0xA9EE3033,
|
||||
0xA4AD16EA, 0xA06C0B5D, 0xD4326D90, 0xD0F37027, 0xDDB056FE,
|
||||
0xD9714B49, 0xC7361B4C, 0xC3F706FB, 0xCEB42022, 0xCA753D95,
|
||||
0xF23A8028, 0xF6FB9D9F, 0xFBB8BB46, 0xFF79A6F1, 0xE13EF6F4,
|
||||
0xE5FFEB43, 0xE8BCCD9A, 0xEC7DD02D, 0x34867077, 0x30476DC0,
|
||||
0x3D044B19, 0x39C556AE, 0x278206AB, 0x23431B1C, 0x2E003DC5,
|
||||
0x2AC12072, 0x128E9DCF, 0x164F8078, 0x1B0CA6A1, 0x1FCDBB16,
|
||||
0x018AEB13, 0x054BF6A4, 0x0808D07D, 0x0CC9CDCA, 0x7897AB07,
|
||||
0x7C56B6B0, 0x71159069, 0x75D48DDE, 0x6B93DDDB, 0x6F52C06C,
|
||||
0x6211E6B5, 0x66D0FB02, 0x5E9F46BF, 0x5A5E5B08, 0x571D7DD1,
|
||||
0x53DC6066, 0x4D9B3063, 0x495A2DD4, 0x44190B0D, 0x40D816BA,
|
||||
0xACA5C697, 0xA864DB20, 0xA527FDF9, 0xA1E6E04E, 0xBFA1B04B,
|
||||
0xBB60ADFC, 0xB6238B25, 0xB2E29692, 0x8AAD2B2F, 0x8E6C3698,
|
||||
0x832F1041, 0x87EE0DF6, 0x99A95DF3, 0x9D684044, 0x902B669D,
|
||||
0x94EA7B2A, 0xE0B41DE7, 0xE4750050, 0xE9362689, 0xEDF73B3E,
|
||||
0xF3B06B3B, 0xF771768C, 0xFA325055, 0xFEF34DE2, 0xC6BCF05F,
|
||||
0xC27DEDE8, 0xCF3ECB31, 0xCBFFD686, 0xD5B88683, 0xD1799B34,
|
||||
0xDC3ABDED, 0xD8FBA05A, 0x690CE0EE, 0x6DCDFD59, 0x608EDB80,
|
||||
0x644FC637, 0x7A089632, 0x7EC98B85, 0x738AAD5C, 0x774BB0EB,
|
||||
0x4F040D56, 0x4BC510E1, 0x46863638, 0x42472B8F, 0x5C007B8A,
|
||||
0x58C1663D, 0x558240E4, 0x51435D53, 0x251D3B9E, 0x21DC2629,
|
||||
0x2C9F00F0, 0x285E1D47, 0x36194D42, 0x32D850F5, 0x3F9B762C,
|
||||
0x3B5A6B9B, 0x0315D626, 0x07D4CB91, 0x0A97ED48, 0x0E56F0FF,
|
||||
0x1011A0FA, 0x14D0BD4D, 0x19939B94, 0x1D528623, 0xF12F560E,
|
||||
0xF5EE4BB9, 0xF8AD6D60, 0xFC6C70D7, 0xE22B20D2, 0xE6EA3D65,
|
||||
0xEBA91BBC, 0xEF68060B, 0xD727BBB6, 0xD3E6A601, 0xDEA580D8,
|
||||
0xDA649D6F, 0xC423CD6A, 0xC0E2D0DD, 0xCDA1F604, 0xC960EBB3,
|
||||
0xBD3E8D7E, 0xB9FF90C9, 0xB4BCB610, 0xB07DABA7, 0xAE3AFBA2,
|
||||
0xAAFBE615, 0xA7B8C0CC, 0xA379DD7B, 0x9B3660C6, 0x9FF77D71,
|
||||
0x92B45BA8, 0x9675461F, 0x8832161A, 0x8CF30BAD, 0x81B02D74,
|
||||
0x857130C3, 0x5D8A9099, 0x594B8D2E, 0x5408ABF7, 0x50C9B640,
|
||||
0x4E8EE645, 0x4A4FFBF2, 0x470CDD2B, 0x43CDC09C, 0x7B827D21,
|
||||
0x7F436096, 0x7200464F, 0x76C15BF8, 0x68860BFD, 0x6C47164A,
|
||||
0x61043093, 0x65C52D24, 0x119B4BE9, 0x155A565E, 0x18197087,
|
||||
0x1CD86D30, 0x029F3D35, 0x065E2082, 0x0B1D065B, 0x0FDC1BEC,
|
||||
0x3793A651, 0x3352BBE6, 0x3E119D3F, 0x3AD08088, 0x2497D08D,
|
||||
0x2056CD3A, 0x2D15EBE3, 0x29D4F654, 0xC5A92679, 0xC1683BCE,
|
||||
0xCC2B1D17, 0xC8EA00A0, 0xD6AD50A5, 0xD26C4D12, 0xDF2F6BCB,
|
||||
0xDBEE767C, 0xE3A1CBC1, 0xE760D676, 0xEA23F0AF, 0xEEE2ED18,
|
||||
0xF0A5BD1D, 0xF464A0AA, 0xF9278673, 0xFDE69BC4, 0x89B8FD09,
|
||||
0x8D79E0BE, 0x803AC667, 0x84FBDBD0, 0x9ABC8BD5, 0x9E7D9662,
|
||||
0x933EB0BB, 0x97FFAD0C, 0xAFB010B1, 0xAB710D06, 0xA6322BDF,
|
||||
0xA2F33668, 0xBCB4666D, 0xB8757BDA, 0xB5365D03, 0xB1F740B4
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using ScriptConverter.Ast.Expressions;
|
||||
|
||||
namespace ScriptConverter.Parser.Parselets.Expressions
|
||||
{
|
||||
class IdentifierParselet : IPrefixParselet
|
||||
{
|
||||
public Expression Parse(ScriptParser parser, ScriptToken token)
|
||||
{
|
||||
return new IdentifierExpression(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using ScriptConverter.Ast.Expressions;
|
||||
|
||||
namespace ScriptConverter.Parser.Parselets.Expressions
|
||||
{
|
||||
class IndexerParselet : IInfixParselet
|
||||
{
|
||||
public int Precedence { get { return (int)PrecedenceValue.Suffix; } }
|
||||
|
||||
public Expression Parse(ScriptParser parser, Expression left, ScriptToken token)
|
||||
{
|
||||
var index = parser.ParseExpression();
|
||||
|
||||
parser.Take(ScriptTokenType.RightSquare);
|
||||
|
||||
return new IndexerExpression(parser.Previous, left, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using ScriptConverter.Ast.Expressions;
|
||||
|
||||
namespace ScriptConverter.Parser.Parselets.Expressions
|
||||
{
|
||||
class InstanceOfParselet : IInfixParselet
|
||||
{
|
||||
public int Precedence { get { return (int)PrecedenceValue.Relational; } }
|
||||
|
||||
public Expression Parse(ScriptParser parser, Expression left, ScriptToken token)
|
||||
{
|
||||
var type = parser.ParseType();
|
||||
return new InstanceOfExpression(parser.Previous, left, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
58
ScriptConverter/Parser/Parselets/Expressions/NewParselet.cs
Normal file
58
ScriptConverter/Parser/Parselets/Expressions/NewParselet.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ScriptConverter.Ast.Expressions;
|
||||
|
||||
namespace ScriptConverter.Parser.Parselets.Expressions
|
||||
{
|
||||
class NewParselet : IPrefixParselet
|
||||
{
|
||||
public Expression Parse(ScriptParser parser, ScriptToken token)
|
||||
{
|
||||
var type = string.Join(".", parser.ParseSeparatedBy(ScriptTokenType.Dot, (_, first) => parser.Take(ScriptTokenType.Identifier).Contents));
|
||||
|
||||
if (type == "string")
|
||||
type = "String";
|
||||
|
||||
var isArray = parser.Match(ScriptTokenType.LeftSquare);
|
||||
|
||||
parser.Take(isArray ? ScriptTokenType.LeftSquare : ScriptTokenType.LeftParen);
|
||||
|
||||
var parameters = parser.ParseSeparatedBy(ScriptTokenType.Comma, (_, first) =>
|
||||
{
|
||||
if (first && parser.Match(isArray ? ScriptTokenType.RightSquare : ScriptTokenType.RightParen))
|
||||
return null;
|
||||
|
||||
return parser.ParseExpression();
|
||||
}).ToList();
|
||||
|
||||
parser.Take(isArray ? ScriptTokenType.RightSquare : ScriptTokenType.RightParen);
|
||||
|
||||
List<Expression> values = null;
|
||||
if (isArray && parser.MatchAndTake(ScriptTokenType.LeftBrace))
|
||||
{
|
||||
values = parser.ParseSeparatedBy(ScriptTokenType.Comma, (_, first) =>
|
||||
{
|
||||
if (parser.Match(ScriptTokenType.RightBrace))
|
||||
return null;
|
||||
|
||||
return parser.ParseExpression();
|
||||
}).ToList();
|
||||
|
||||
parser.MatchAndTake(ScriptTokenType.RightBrace);
|
||||
}
|
||||
|
||||
int arrayDimensions = isArray ? 1 : 0;
|
||||
if (isArray)
|
||||
{
|
||||
while (parser.Match(ScriptTokenType.LeftSquare) && parser.Match(ScriptTokenType.RightSquare, 1))
|
||||
{
|
||||
parser.Take(ScriptTokenType.LeftSquare);
|
||||
parser.Take(ScriptTokenType.RightSquare);
|
||||
arrayDimensions++;
|
||||
}
|
||||
}
|
||||
|
||||
return new NewExpression(token, parser.Previous, type, arrayDimensions, parameters, values);
|
||||
}
|
||||
}
|
||||
}
|
||||
12
ScriptConverter/Parser/Parselets/Expressions/NullParselet.cs
Normal file
12
ScriptConverter/Parser/Parselets/Expressions/NullParselet.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using ScriptConverter.Ast.Expressions;
|
||||
|
||||
namespace ScriptConverter.Parser.Parselets.Expressions
|
||||
{
|
||||
class NullParselet : IPrefixParselet
|
||||
{
|
||||
public Expression Parse(ScriptParser parser, ScriptToken token)
|
||||
{
|
||||
return new NullExpression(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using ScriptConverter.Ast.Expressions;
|
||||
|
||||
namespace ScriptConverter.Parser.Parselets.Expressions
|
||||
{
|
||||
class NumberParselet : IPrefixParselet
|
||||
{
|
||||
public Expression Parse(ScriptParser parser, ScriptToken token)
|
||||
{
|
||||
return new NumberExpression(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using ScriptConverter.Ast.Expressions;
|
||||
|
||||
namespace ScriptConverter.Parser.Parselets.Expressions
|
||||
{
|
||||
class PostfixOperatorParselet : IInfixParselet
|
||||
{
|
||||
public PostfixOperatorParselet(PrecedenceValue precedence)
|
||||
{
|
||||
Precedence = (int)precedence;
|
||||
}
|
||||
|
||||
public int Precedence { get; private set; }
|
||||
|
||||
public Expression Parse(ScriptParser parser, Expression left, ScriptToken token)
|
||||
{
|
||||
return new PostfixOperatorExpression(token, left);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using ScriptConverter.Ast.Expressions;
|
||||
|
||||
namespace ScriptConverter.Parser.Parselets.Expressions
|
||||
{
|
||||
class PrefixOperatorParselet : IPrefixParselet
|
||||
{
|
||||
private readonly int _precedence;
|
||||
|
||||
public PrefixOperatorParselet(PrecedenceValue precedence)
|
||||
{
|
||||
_precedence = (int)precedence;
|
||||
}
|
||||
|
||||
public Expression Parse(ScriptParser parser, ScriptToken token)
|
||||
{
|
||||
var right = parser.ParseExpression(_precedence);
|
||||
return new PrefixOperatorExpression(token, right);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using ScriptConverter.Ast.Expressions;
|
||||
|
||||
namespace ScriptConverter.Parser.Parselets.Expressions
|
||||
{
|
||||
class StringParselet : IPrefixParselet
|
||||
{
|
||||
private readonly bool _singleQuote;
|
||||
|
||||
public StringParselet(bool singleQuote)
|
||||
{
|
||||
_singleQuote = singleQuote;
|
||||
}
|
||||
|
||||
public Expression Parse(ScriptParser parser, ScriptToken token)
|
||||
{
|
||||
return new StringExpression(token, _singleQuote);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using ScriptConverter.Ast.Expressions;
|
||||
|
||||
namespace ScriptConverter.Parser.Parselets.Expressions
|
||||
{
|
||||
class TernaryParselet : IInfixParselet
|
||||
{
|
||||
public int Precedence { get { return (int)PrecedenceValue.Ternary; } }
|
||||
|
||||
public Expression Parse(ScriptParser parser, Expression left, ScriptToken token)
|
||||
{
|
||||
var trueExpr = parser.ParseExpression();
|
||||
parser.Take(ScriptTokenType.Colon);
|
||||
var falseExpr = parser.ParseExpression();
|
||||
|
||||
return new TernaryExpression(left, trueExpr, falseExpr);
|
||||
}
|
||||
}
|
||||
}
|
||||
9
ScriptConverter/Parser/Parselets/IDeclarationParselet.cs
Normal file
9
ScriptConverter/Parser/Parselets/IDeclarationParselet.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using ScriptConverter.Ast.Declarations;
|
||||
|
||||
namespace ScriptConverter.Parser.Parselets
|
||||
{
|
||||
interface IDeclarationParselet
|
||||
{
|
||||
Declaration Parse(ScriptParser parser, ScriptToken token);
|
||||
}
|
||||
}
|
||||
11
ScriptConverter/Parser/Parselets/IInfixParselet.cs
Normal file
11
ScriptConverter/Parser/Parselets/IInfixParselet.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using ScriptConverter.Ast.Expressions;
|
||||
|
||||
namespace ScriptConverter.Parser.Parselets
|
||||
{
|
||||
interface IInfixParselet
|
||||
{
|
||||
int Precedence { get; }
|
||||
|
||||
Expression Parse(ScriptParser parser, Expression left, ScriptToken token);
|
||||
}
|
||||
}
|
||||
9
ScriptConverter/Parser/Parselets/IPrefixParselet.cs
Normal file
9
ScriptConverter/Parser/Parselets/IPrefixParselet.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using ScriptConverter.Ast.Expressions;
|
||||
|
||||
namespace ScriptConverter.Parser.Parselets
|
||||
{
|
||||
interface IPrefixParselet
|
||||
{
|
||||
Expression Parse(ScriptParser parser, ScriptToken token);
|
||||
}
|
||||
}
|
||||
9
ScriptConverter/Parser/Parselets/IStatementParselet.cs
Normal file
9
ScriptConverter/Parser/Parselets/IStatementParselet.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using ScriptConverter.Ast.Statements;
|
||||
|
||||
namespace ScriptConverter.Parser.Parselets
|
||||
{
|
||||
interface IStatementParselet
|
||||
{
|
||||
Statement Parse(ScriptParser parser, ScriptToken token, out bool trailingSemicolon);
|
||||
}
|
||||
}
|
||||
24
ScriptConverter/Parser/Parselets/Statements/BlockParselet.cs
Normal file
24
ScriptConverter/Parser/Parselets/Statements/BlockParselet.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System.Collections.Generic;
|
||||
using ScriptConverter.Ast.Statements;
|
||||
|
||||
namespace ScriptConverter.Parser.Parselets.Statements
|
||||
{
|
||||
class BlockParselet : IStatementParselet
|
||||
{
|
||||
public Statement Parse(ScriptParser parser, ScriptToken token, out bool trailingSemicolon)
|
||||
{
|
||||
trailingSemicolon = false;
|
||||
|
||||
var statements = new List<Statement>();
|
||||
|
||||
while (!parser.Match(ScriptTokenType.RightBrace))
|
||||
{
|
||||
statements.Add(parser.ParseStatement());
|
||||
}
|
||||
|
||||
parser.Take(ScriptTokenType.RightBrace);
|
||||
|
||||
return new BlockStatement(token, parser.Previous, statements);
|
||||
}
|
||||
}
|
||||
}
|
||||
13
ScriptConverter/Parser/Parselets/Statements/BreakParselet.cs
Normal file
13
ScriptConverter/Parser/Parselets/Statements/BreakParselet.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using ScriptConverter.Ast.Statements;
|
||||
|
||||
namespace ScriptConverter.Parser.Parselets.Statements
|
||||
{
|
||||
class BreakParselet : IStatementParselet
|
||||
{
|
||||
public Statement Parse(ScriptParser parser, ScriptToken token, out bool trailingSemicolon)
|
||||
{
|
||||
trailingSemicolon = true;
|
||||
return new BreakStatement(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using System.Collections.Generic;
|
||||
using ScriptConverter.Ast;
|
||||
using ScriptConverter.Ast.Statements;
|
||||
|
||||
namespace ScriptConverter.Parser.Parselets.Statements
|
||||
{
|
||||
class ConstVariableParselet : IStatementParselet
|
||||
{
|
||||
public Statement Parse(ScriptParser parser, ScriptToken token, out bool trailingSemicolon)
|
||||
{
|
||||
trailingSemicolon = true;
|
||||
|
||||
ScriptType type;
|
||||
string name;
|
||||
parser.ParseNamedType(out type, out name);
|
||||
|
||||
parser.Take(ScriptTokenType.Assign);
|
||||
|
||||
var value = parser.ParseExpression();
|
||||
|
||||
var definitions = new List<VariableStatement.Definition>()
|
||||
{
|
||||
new VariableStatement.Definition(type, name, value)
|
||||
};
|
||||
|
||||
return new VariableStatement(token, parser.Previous, type, true, definitions);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using ScriptConverter.Ast.Statements;
|
||||
|
||||
namespace ScriptConverter.Parser.Parselets.Statements
|
||||
{
|
||||
class ContinueParselet : IStatementParselet
|
||||
{
|
||||
public Statement Parse(ScriptParser parser, ScriptToken token, out bool trailingSemicolon)
|
||||
{
|
||||
trailingSemicolon = true;
|
||||
return new ContinueStatement(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
23
ScriptConverter/Parser/Parselets/Statements/DoParselet.cs
Normal file
23
ScriptConverter/Parser/Parselets/Statements/DoParselet.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using ScriptConverter.Ast.Statements;
|
||||
|
||||
namespace ScriptConverter.Parser.Parselets.Statements
|
||||
{
|
||||
class DoParselet : IStatementParselet
|
||||
{
|
||||
public Statement Parse(ScriptParser parser, ScriptToken token, out bool trailingSemicolon)
|
||||
{
|
||||
trailingSemicolon = true;
|
||||
|
||||
var block = parser.ParseBlock();
|
||||
|
||||
parser.Take(ScriptTokenType.While);
|
||||
parser.Take(ScriptTokenType.LeftParen);
|
||||
|
||||
var condition = parser.ParseExpression();
|
||||
|
||||
parser.Take(ScriptTokenType.RightParen);
|
||||
|
||||
return new DoStatement(token, parser.Previous, condition, block);
|
||||
}
|
||||
}
|
||||
}
|
||||
13
ScriptConverter/Parser/Parselets/Statements/EmptyParselet.cs
Normal file
13
ScriptConverter/Parser/Parselets/Statements/EmptyParselet.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using ScriptConverter.Ast.Statements;
|
||||
|
||||
namespace ScriptConverter.Parser.Parselets.Statements
|
||||
{
|
||||
class EmptyParselet : IStatementParselet
|
||||
{
|
||||
public Statement Parse(ScriptParser parser, ScriptToken token, out bool trailingSemicolon)
|
||||
{
|
||||
trailingSemicolon = false;
|
||||
return new EmptyStatement(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
49
ScriptConverter/Parser/Parselets/Statements/ForParselet.cs
Normal file
49
ScriptConverter/Parser/Parselets/Statements/ForParselet.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ScriptConverter.Ast.Expressions;
|
||||
using ScriptConverter.Ast.Statements;
|
||||
|
||||
namespace ScriptConverter.Parser.Parselets.Statements
|
||||
{
|
||||
class ForParselet : IStatementParselet
|
||||
{
|
||||
public Statement Parse(ScriptParser parser, ScriptToken token, out bool trailingSemicolon)
|
||||
{
|
||||
trailingSemicolon = false;
|
||||
|
||||
parser.Take(ScriptTokenType.LeftParen);
|
||||
|
||||
List<Statement> initializers = null;
|
||||
if (!parser.Match(ScriptTokenType.Semicolon))
|
||||
{
|
||||
initializers = parser.ParseSeparatedBy(ScriptTokenType.Comma, (_, first) =>
|
||||
{
|
||||
var stmt = parser.ParseStatement(false);
|
||||
|
||||
if (!(stmt is VariableStatement) && !(stmt is NakedStatement))
|
||||
throw new CompilerException(token, "bad for loop initializer");
|
||||
|
||||
return stmt;
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
parser.Take(ScriptTokenType.Semicolon);
|
||||
|
||||
Expression condition = null;
|
||||
if (!parser.Match(ScriptTokenType.Semicolon))
|
||||
condition = parser.ParseExpression();
|
||||
|
||||
parser.Take(ScriptTokenType.Semicolon);
|
||||
|
||||
List<Expression> increment = null;
|
||||
if (!parser.Match(ScriptTokenType.RightParen))
|
||||
increment = parser.ParseSeparatedBy(ScriptTokenType.Comma, (_, first) => parser.ParseExpression()).ToList();
|
||||
|
||||
parser.Take(ScriptTokenType.RightParen);
|
||||
|
||||
var block = parser.ParseBlock();
|
||||
|
||||
return new ForStatement(token, parser.Previous, initializers, condition, increment, block);
|
||||
}
|
||||
}
|
||||
}
|
||||
47
ScriptConverter/Parser/Parselets/Statements/IfParselet.cs
Normal file
47
ScriptConverter/Parser/Parselets/Statements/IfParselet.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System.Collections.Generic;
|
||||
using ScriptConverter.Ast.Expressions;
|
||||
using ScriptConverter.Ast.Statements;
|
||||
|
||||
namespace ScriptConverter.Parser.Parselets.Statements
|
||||
{
|
||||
class IfParselet : IStatementParselet
|
||||
{
|
||||
public Statement Parse(ScriptParser parser, ScriptToken token, out bool trailingSemicolon)
|
||||
{
|
||||
trailingSemicolon = false;
|
||||
|
||||
var first = true;
|
||||
var branches = new List<IfStatement.Branch>();
|
||||
IfStatement.Branch defaultBranch = null;
|
||||
|
||||
do
|
||||
{
|
||||
var isDefaultBranch = !first && !parser.MatchAndTake(ScriptTokenType.If);
|
||||
first = false;
|
||||
|
||||
Expression condition = null;
|
||||
if (!isDefaultBranch)
|
||||
{
|
||||
parser.Take(ScriptTokenType.LeftParen);
|
||||
|
||||
condition = parser.ParseExpression();
|
||||
|
||||
parser.Take(ScriptTokenType.RightParen);
|
||||
}
|
||||
|
||||
var block = parser.ParseBlock();
|
||||
var branch = new IfStatement.Branch(condition, block);
|
||||
|
||||
if (isDefaultBranch)
|
||||
defaultBranch = branch;
|
||||
else
|
||||
branches.Add(branch);
|
||||
|
||||
if (isDefaultBranch)
|
||||
break;
|
||||
} while (parser.MatchAndTake(ScriptTokenType.Else));
|
||||
|
||||
return new IfStatement(token, parser.Previous, branches, defaultBranch);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using ScriptConverter.Ast.Statements;
|
||||
|
||||
namespace ScriptConverter.Parser.Parselets.Statements
|
||||
{
|
||||
class ReturnParselet : IStatementParselet
|
||||
{
|
||||
public Statement Parse(ScriptParser parser, ScriptToken token, out bool trailingSemicolon)
|
||||
{
|
||||
trailingSemicolon = true;
|
||||
|
||||
if (parser.Match(ScriptTokenType.Semicolon))
|
||||
return new ReturnStatement(token, parser.Previous, null);
|
||||
|
||||
var value = parser.ParseExpression();
|
||||
return new ReturnStatement(token, parser.Previous, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
using System.Collections.Generic;
|
||||
using ScriptConverter.Ast.Expressions;
|
||||
using ScriptConverter.Ast.Statements;
|
||||
|
||||
namespace ScriptConverter.Parser.Parselets.Statements
|
||||
{
|
||||
class SwitchParselet : IStatementParselet
|
||||
{
|
||||
public Statement Parse(ScriptParser parser, ScriptToken token, out bool trailingSemicolon)
|
||||
{
|
||||
trailingSemicolon = false;
|
||||
|
||||
parser.Take(ScriptTokenType.LeftParen);
|
||||
|
||||
var expression = parser.ParseExpression();
|
||||
|
||||
parser.Take(ScriptTokenType.RightParen);
|
||||
parser.Take(ScriptTokenType.LeftBrace);
|
||||
|
||||
var hasDefault = false;
|
||||
var branches = new List<SwitchStatement.Branch>();
|
||||
|
||||
while (!parser.Match(ScriptTokenType.RightBrace))
|
||||
{
|
||||
var conditions = new List<Expression>();
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (parser.MatchAndTake(ScriptTokenType.Case))
|
||||
{
|
||||
var condition = parser.ParseExpression();
|
||||
conditions.Add(condition);
|
||||
|
||||
parser.Take(ScriptTokenType.Colon);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!parser.Match(ScriptTokenType.Default))
|
||||
break;
|
||||
|
||||
var defaultToken = parser.Take(ScriptTokenType.Default);
|
||||
|
||||
if (hasDefault)
|
||||
throw new CompilerException(defaultToken, "Multiple default labels");
|
||||
|
||||
conditions.Add(null); // special default condition
|
||||
hasDefault = true;
|
||||
|
||||
parser.Take(ScriptTokenType.Colon);
|
||||
}
|
||||
|
||||
if (conditions.Count > 0)
|
||||
{
|
||||
var block = ParseBlock(parser);
|
||||
var branch = new SwitchStatement.Branch(conditions, block);
|
||||
branches.Add(branch);
|
||||
continue;
|
||||
}
|
||||
|
||||
var errorToken = parser.Peek();
|
||||
throw new CompilerException(errorToken, "Expected Case or Default but found {0}", errorToken);
|
||||
}
|
||||
|
||||
parser.Take(ScriptTokenType.RightBrace);
|
||||
|
||||
return new SwitchStatement(token, parser.Previous, expression, branches);
|
||||
}
|
||||
|
||||
private static BlockStatement ParseBlock(ScriptParser parser)
|
||||
{
|
||||
var statements = new List<Statement>();
|
||||
var start = parser.Peek();
|
||||
|
||||
while (!parser.Match(ScriptTokenType.Case) &&
|
||||
!parser.Match(ScriptTokenType.Default) &&
|
||||
!parser.Match(ScriptTokenType.RightBrace))
|
||||
{
|
||||
statements.Add(parser.ParseStatement());
|
||||
}
|
||||
|
||||
return new BlockStatement(start, parser.Previous, statements, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
15
ScriptConverter/Parser/Parselets/Statements/ThrowParselet.cs
Normal file
15
ScriptConverter/Parser/Parselets/Statements/ThrowParselet.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using ScriptConverter.Ast.Statements;
|
||||
|
||||
namespace ScriptConverter.Parser.Parselets.Statements
|
||||
{
|
||||
class ThrowParselet : IStatementParselet
|
||||
{
|
||||
public Statement Parse(ScriptParser parser, ScriptToken token, out bool trailingSemicolon)
|
||||
{
|
||||
trailingSemicolon = true;
|
||||
|
||||
var value = parser.ParseExpression();
|
||||
return new ThrowStatement(token, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
34
ScriptConverter/Parser/Parselets/Statements/TryParselet.cs
Normal file
34
ScriptConverter/Parser/Parselets/Statements/TryParselet.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System.Collections.Generic;
|
||||
using ScriptConverter.Ast;
|
||||
using ScriptConverter.Ast.Statements;
|
||||
|
||||
namespace ScriptConverter.Parser.Parselets.Statements
|
||||
{
|
||||
class TryParselet : IStatementParselet
|
||||
{
|
||||
public Statement Parse(ScriptParser parser, ScriptToken token, out bool trailingSemicolon)
|
||||
{
|
||||
trailingSemicolon = false;
|
||||
|
||||
var mainBlock = parser.ParseBlock(false);
|
||||
var catches = new List<TryStatement.Branch>(2);
|
||||
|
||||
do
|
||||
{
|
||||
parser.Take(ScriptTokenType.Catch);
|
||||
parser.Take(ScriptTokenType.LeftParen);
|
||||
|
||||
ScriptType type;
|
||||
string name;
|
||||
parser.ParseNamedType(out type, out name);
|
||||
|
||||
parser.Take(ScriptTokenType.RightParen);
|
||||
|
||||
var block = parser.ParseBlock(false);
|
||||
catches.Add(new TryStatement.Branch(type, name, block));
|
||||
} while (parser.Match(ScriptTokenType.Catch));
|
||||
|
||||
return new TryStatement(token, parser.Previous, mainBlock, catches);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using System.Linq;
|
||||
using ScriptConverter.Ast;
|
||||
using ScriptConverter.Ast.Expressions;
|
||||
using ScriptConverter.Ast.Statements;
|
||||
|
||||
namespace ScriptConverter.Parser.Parselets.Statements
|
||||
{
|
||||
class VariableParselet : IStatementParselet
|
||||
{
|
||||
public Statement Parse(ScriptParser parser, ScriptToken token, out bool trailingSemicolon)
|
||||
{
|
||||
trailingSemicolon = true;
|
||||
|
||||
var baseType = parser.ParseType(token);
|
||||
|
||||
var definitions = parser.ParseSeparatedBy(ScriptTokenType.Comma, (_, first) =>
|
||||
{
|
||||
var name = parser.Take(ScriptTokenType.Identifier).Contents;
|
||||
|
||||
var arrayDims = 0;
|
||||
while (parser.MatchAndTake(ScriptTokenType.LeftSquare))
|
||||
{
|
||||
parser.Take(ScriptTokenType.RightSquare);
|
||||
arrayDims++;
|
||||
}
|
||||
|
||||
var type = baseType;
|
||||
|
||||
if (arrayDims > 0)
|
||||
type = new ScriptType(baseType.Name, baseType.ArrayDimensions + arrayDims, baseType.IsResizable);
|
||||
|
||||
Expression value = null;
|
||||
if (parser.MatchAndTake(ScriptTokenType.Assign))
|
||||
value = parser.ParseExpression();
|
||||
|
||||
return new VariableStatement.Definition(type, name, value);
|
||||
}).ToList();
|
||||
|
||||
return new VariableStatement(token, parser.Previous, baseType, false, definitions);
|
||||
}
|
||||
}
|
||||
}
|
||||
20
ScriptConverter/Parser/Parselets/Statements/WhileParselet.cs
Normal file
20
ScriptConverter/Parser/Parselets/Statements/WhileParselet.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using ScriptConverter.Ast.Statements;
|
||||
|
||||
namespace ScriptConverter.Parser.Parselets.Statements
|
||||
{
|
||||
class WhileParselet : IStatementParselet
|
||||
{
|
||||
public Statement Parse(ScriptParser parser, ScriptToken token, out bool trailingSemicolon)
|
||||
{
|
||||
trailingSemicolon = false;
|
||||
|
||||
parser.Take(ScriptTokenType.LeftParen);
|
||||
var condition = parser.ParseExpression();
|
||||
parser.Take(ScriptTokenType.RightParen);
|
||||
|
||||
var block = parser.ParseBlock();
|
||||
|
||||
return new WhileStatement(token, parser.Previous, condition, block);
|
||||
}
|
||||
}
|
||||
}
|
||||
109
ScriptConverter/Parser/Parser.cs
Normal file
109
ScriptConverter/Parser/Parser.cs
Normal file
@@ -0,0 +1,109 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ScriptConverter.Parser
|
||||
{
|
||||
abstract class Parser
|
||||
{
|
||||
private IEnumerator<ScriptToken> _tokens;
|
||||
private List<ScriptToken> _read;
|
||||
|
||||
protected Parser(IEnumerable<ScriptToken> tokens)
|
||||
{
|
||||
_tokens = tokens.GetEnumerator();
|
||||
_read = new List<ScriptToken>(8);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the token that was most recently taken.
|
||||
/// </summary>
|
||||
public ScriptToken Previous { get; private set; }
|
||||
|
||||
public IEnumerable<T> ParseSeparatedBy<T>(ScriptTokenType separator, Func<Parser, bool, T> parseFunc) where T : class
|
||||
{
|
||||
var first = parseFunc(this, true);
|
||||
|
||||
if (first == null)
|
||||
yield break;
|
||||
|
||||
yield return first;
|
||||
|
||||
while (MatchAndTake(separator))
|
||||
{
|
||||
var next = parseFunc(this, false);
|
||||
|
||||
if (next == null)
|
||||
yield break;
|
||||
|
||||
yield return next;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the next token matches the given type. If they match, take the token.
|
||||
/// </summary>
|
||||
public bool MatchAndTake(ScriptTokenType type)
|
||||
{
|
||||
var isMatch = Match(type);
|
||||
if (isMatch)
|
||||
Take();
|
||||
|
||||
return isMatch;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the next token matches the given type.
|
||||
/// </summary>
|
||||
public bool Match(ScriptTokenType type, int distance = 0)
|
||||
{
|
||||
return Peek(distance).Type == type;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Take a token from the stream. Throws an exception if the given type does not match the token type.
|
||||
/// </summary>
|
||||
public ScriptToken Take(ScriptTokenType type)
|
||||
{
|
||||
var token = Take();
|
||||
|
||||
if (token.Type != type)
|
||||
throw new CompilerException(token, CompilerError.ExpectedButFound, type, token);
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Take a token from the stream.
|
||||
/// </summary>
|
||||
public ScriptToken Take()
|
||||
{
|
||||
Peek();
|
||||
|
||||
var result = _read[0];
|
||||
_read.RemoveAt(0);
|
||||
|
||||
Previous = result;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Peek at future tokens in the stream. Distance is the number of tokens from the current one.
|
||||
/// </summary>
|
||||
public ScriptToken Peek(int distance = 0)
|
||||
{
|
||||
if (distance < 0)
|
||||
throw new ArgumentOutOfRangeException("distance", "distance can't be negative");
|
||||
|
||||
while (_read.Count <= distance)
|
||||
{
|
||||
_tokens.MoveNext();
|
||||
_read.Add(_tokens.Current);
|
||||
|
||||
//Console.WriteLine(_tokens.Current.Type);
|
||||
}
|
||||
|
||||
return _read[distance];
|
||||
}
|
||||
}
|
||||
}
|
||||
22
ScriptConverter/Parser/PrecedenceValue.cs
Normal file
22
ScriptConverter/Parser/PrecedenceValue.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
namespace ScriptConverter.Parser
|
||||
{
|
||||
enum PrecedenceValue
|
||||
{
|
||||
Invalid,
|
||||
Assignment,
|
||||
Ternary,
|
||||
LogicalOr,
|
||||
LogicalAnd,
|
||||
BitwiseOr,
|
||||
BitwiseXor,
|
||||
BitwiseAnd,
|
||||
Equality,
|
||||
Relational,
|
||||
BitwiseShift,
|
||||
Additive,
|
||||
Multiplicative,
|
||||
Cast,
|
||||
Prefix,
|
||||
Suffix
|
||||
}
|
||||
}
|
||||
105
ScriptConverter/Parser/ScriptLexer.Static.cs
Normal file
105
ScriptConverter/Parser/ScriptLexer.Static.cs
Normal file
@@ -0,0 +1,105 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ScriptConverter.Parser
|
||||
{
|
||||
partial class ScriptLexer
|
||||
{
|
||||
private static OperatorDictionary<ScriptTokenType> _operators;
|
||||
private static Dictionary<string, ScriptTokenType> _keywords;
|
||||
|
||||
static ScriptLexer()
|
||||
{
|
||||
EofToken = new ScriptToken(null, default(SourcePosition), default(SourcePosition), ScriptTokenType.Eof, null);
|
||||
|
||||
_operators = new OperatorDictionary<ScriptTokenType>
|
||||
{
|
||||
{ ";", ScriptTokenType.Semicolon },
|
||||
{ ",", ScriptTokenType.Comma },
|
||||
{ ".", ScriptTokenType.Dot },
|
||||
{ "=", ScriptTokenType.Assign },
|
||||
{ "?", ScriptTokenType.QuestionMark },
|
||||
{ ":", ScriptTokenType.Colon },
|
||||
|
||||
{ "(", ScriptTokenType.LeftParen },
|
||||
{ ")", ScriptTokenType.RightParen },
|
||||
|
||||
{ "{", ScriptTokenType.LeftBrace },
|
||||
{ "}", ScriptTokenType.RightBrace },
|
||||
|
||||
{ "[", ScriptTokenType.LeftSquare },
|
||||
{ "]", ScriptTokenType.RightSquare },
|
||||
|
||||
{ "+", ScriptTokenType.Add },
|
||||
{ "+=", ScriptTokenType.AddAssign },
|
||||
{ "-", ScriptTokenType.Subtract },
|
||||
{ "-=", ScriptTokenType.SubtractAssign },
|
||||
{ "*", ScriptTokenType.Multiply },
|
||||
{ "*=", ScriptTokenType.MultiplyAssign },
|
||||
{ "/", ScriptTokenType.Divide },
|
||||
{ "/=", ScriptTokenType.DivideAssign },
|
||||
{ "%", ScriptTokenType.Remainder },
|
||||
{ "%=", ScriptTokenType.RemainderAssign },
|
||||
{ "++", ScriptTokenType.Increment },
|
||||
{ "--", ScriptTokenType.Decrement },
|
||||
|
||||
{ "==", ScriptTokenType.EqualTo },
|
||||
{ "!=", ScriptTokenType.NotEqualTo },
|
||||
{ ">", ScriptTokenType.GreaterThan },
|
||||
{ ">=", ScriptTokenType.GreaterThanOrEqual },
|
||||
{ "<", ScriptTokenType.LessThan },
|
||||
{ "<=", ScriptTokenType.LessThanOrEqual },
|
||||
|
||||
{ "&&", ScriptTokenType.LogicalAnd },
|
||||
{ "||", ScriptTokenType.LogicalOr },
|
||||
{ "!", ScriptTokenType.LogicalNot },
|
||||
|
||||
{ "~", ScriptTokenType.BitwiseNot },
|
||||
{ "&", ScriptTokenType.BitwiseAnd },
|
||||
{ "&=", ScriptTokenType.BitwiseAndAssign },
|
||||
{ "|", ScriptTokenType.BitwiseOr },
|
||||
{ "|=", ScriptTokenType.BitwiseOrAssign },
|
||||
{ "^", ScriptTokenType.BitwiseXor },
|
||||
{ "^=", ScriptTokenType.BitwiseXorAssign },
|
||||
{ "<<", ScriptTokenType.BitwiseShiftLeft },
|
||||
{ "<<=", ScriptTokenType.BitwiseShiftLeftAssign },
|
||||
{ ">>", ScriptTokenType.BitwiseShiftRight },
|
||||
{ ">>=", ScriptTokenType.BitwiseShiftRightAssign },
|
||||
|
||||
{ "##", ScriptTokenType.Hash },
|
||||
|
||||
{ "#define", ScriptTokenType.PreprocessDefine },
|
||||
{ "#ifdef", ScriptTokenType.PreprocessIfDef },
|
||||
{ "#endif", ScriptTokenType.PreprocessEndIf },
|
||||
};
|
||||
|
||||
_keywords = new Dictionary<string, ScriptTokenType>
|
||||
{
|
||||
{ "null", ScriptTokenType.Null },
|
||||
{ "true", ScriptTokenType.True },
|
||||
{ "false", ScriptTokenType.False },
|
||||
|
||||
{ "return", ScriptTokenType.Return },
|
||||
{ "if", ScriptTokenType.If },
|
||||
{ "else", ScriptTokenType.Else },
|
||||
{ "for", ScriptTokenType.For },
|
||||
{ "while", ScriptTokenType.While },
|
||||
{ "do", ScriptTokenType.Do },
|
||||
{ "break", ScriptTokenType.Break },
|
||||
{ "continue", ScriptTokenType.Continue },
|
||||
{ "switch", ScriptTokenType.Switch },
|
||||
{ "case", ScriptTokenType.Case },
|
||||
{ "default", ScriptTokenType.Default },
|
||||
|
||||
{ "inherits", ScriptTokenType.Inherits },
|
||||
{ "include", ScriptTokenType.Include },
|
||||
{ "const", ScriptTokenType.Const },
|
||||
{ "public", ScriptTokenType.Public },
|
||||
{ "new", ScriptTokenType.New },
|
||||
{ "instanceof", ScriptTokenType.InstanceOf },
|
||||
{ "try", ScriptTokenType.Try },
|
||||
{ "catch", ScriptTokenType.Catch },
|
||||
{ "throw", ScriptTokenType.Throw },
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
254
ScriptConverter/Parser/ScriptLexer.cs
Normal file
254
ScriptConverter/Parser/ScriptLexer.cs
Normal file
@@ -0,0 +1,254 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace ScriptConverter.Parser
|
||||
{
|
||||
partial class ScriptLexer : Lexer<ScriptToken, ScriptTokenType>
|
||||
{
|
||||
public ScriptLexer(IEnumerable<char> source, string fileName = null)
|
||||
: base(source, fileName)
|
||||
{
|
||||
Rules = new List<LexerRule>
|
||||
{
|
||||
TryLexNumber,
|
||||
TryLexOperator,
|
||||
TryLexString,
|
||||
TryLexWord,
|
||||
};
|
||||
}
|
||||
|
||||
protected override bool SkipComment()
|
||||
{
|
||||
if (TakeIfNext("//"))
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
var ch = TakeChar();
|
||||
if (ch == '\0' || ch == '\n' || ch == '\r')
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (TakeIfNext("/*"))
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (TakeIfNext("*/"))
|
||||
return true;
|
||||
|
||||
var ch = TakeChar();
|
||||
if (ch == '\0')
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool TryLexOperator(char ch, out ScriptToken token)
|
||||
{
|
||||
var opList = _operators.Lookup(ch);
|
||||
if (opList != null)
|
||||
{
|
||||
var op = opList.FirstOrDefault(o => TakeIfNext(o.Item1));
|
||||
|
||||
if (op != null)
|
||||
{
|
||||
token = Token(op.Item2, op.Item1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
token = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool TryLexString(char ch, out ScriptToken token)
|
||||
{
|
||||
if (ch == '"' || ch == '\'')
|
||||
{
|
||||
TakeChar();
|
||||
|
||||
var stringTerminator = ch;
|
||||
var stringContentsBuilder = new StringBuilder();
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (AtEof)
|
||||
throw ErrorStart(CompilerError.UnterminatedString);
|
||||
|
||||
ch = TakeChar();
|
||||
|
||||
if (ch == stringTerminator)
|
||||
break;
|
||||
|
||||
if (ch != '\\')
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case '\n':
|
||||
stringContentsBuilder.Append("\\n");
|
||||
continue;
|
||||
case '\r':
|
||||
stringContentsBuilder.Append("\\r");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch < ' ' || ch > '~')
|
||||
{
|
||||
stringContentsBuilder.AppendFormat("\\u{0:X4}", (int)ch);
|
||||
continue;
|
||||
}
|
||||
|
||||
stringContentsBuilder.Append(ch);
|
||||
continue;
|
||||
}
|
||||
|
||||
// escape sequence
|
||||
ch = TakeChar();
|
||||
|
||||
if (AtEof)
|
||||
throw Error(CompilerError.UnexpectedEofString);
|
||||
|
||||
switch (ch)
|
||||
{
|
||||
case '\\':
|
||||
stringContentsBuilder.Append("\\\\");
|
||||
break;
|
||||
|
||||
case '"':
|
||||
stringContentsBuilder.Append("\\\"");
|
||||
break;
|
||||
|
||||
case '\'':
|
||||
stringContentsBuilder.Append("\\'");
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
stringContentsBuilder.Append("\\r");
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
stringContentsBuilder.Append("\\n");
|
||||
break;
|
||||
|
||||
case 't':
|
||||
stringContentsBuilder.Append("\\t");
|
||||
break;
|
||||
|
||||
case '0':
|
||||
stringContentsBuilder.Append("\\0");
|
||||
break;
|
||||
|
||||
// TODO: more escape sequences
|
||||
|
||||
default:
|
||||
throw Error(CompilerError.InvalidEscapeSequence, ch);
|
||||
}
|
||||
}
|
||||
|
||||
var stringContents = stringContentsBuilder.ToString();
|
||||
|
||||
if (stringTerminator == '\'')
|
||||
{
|
||||
token = Token(ScriptTokenType.SingleString, stringContents);
|
||||
return true;
|
||||
}
|
||||
|
||||
token = Token(ScriptTokenType.String, stringContents);
|
||||
return true;
|
||||
}
|
||||
|
||||
token = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool TryLexWord(char ch, out ScriptToken token)
|
||||
{
|
||||
if (char.IsLetter(ch) || ch == '_')
|
||||
{
|
||||
var wordContents = TakeWhile(c => char.IsLetterOrDigit(c) || c == '_');
|
||||
|
||||
ScriptTokenType keywordType;
|
||||
var isKeyword = _keywords.TryGetValue(wordContents, out keywordType);
|
||||
|
||||
// HACK: allow using enum as an identifier
|
||||
if (!isKeyword && wordContents == "enum")
|
||||
wordContents = "enum_";
|
||||
|
||||
token = Token(isKeyword ? keywordType : ScriptTokenType.Identifier, wordContents);
|
||||
return true;
|
||||
}
|
||||
|
||||
token = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool TryLexNumber(char ch, out ScriptToken token)
|
||||
{
|
||||
if (char.IsDigit(ch) || (ch == '.' && char.IsDigit(PeekChar(1))))
|
||||
{
|
||||
var format = NumberFormat.Decimal;
|
||||
var hasDecimal = false;
|
||||
var prefix = "";
|
||||
|
||||
if (ch == '0')
|
||||
{
|
||||
var nextChar = PeekChar(1);
|
||||
|
||||
if (nextChar == 'x' || nextChar == 'X')
|
||||
format = NumberFormat.Hexadecimal;
|
||||
|
||||
if (nextChar == 'b' || nextChar == 'B')
|
||||
format = NumberFormat.Binary;
|
||||
|
||||
if (format != NumberFormat.Decimal)
|
||||
{
|
||||
prefix = "" + TakeChar() + TakeChar();
|
||||
}
|
||||
}
|
||||
|
||||
if (ch == '.')
|
||||
{
|
||||
hasDecimal = true;
|
||||
prefix = "" + TakeChar();
|
||||
}
|
||||
|
||||
Func<char, bool> isHexLetter = c => (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f');
|
||||
Func<char, bool> isDigit = c => char.IsDigit(c) || (format == NumberFormat.Hexadecimal && isHexLetter(c));
|
||||
|
||||
var numberContents = TakeWhile(c =>
|
||||
{
|
||||
if (format == NumberFormat.Decimal && c == '.' && isDigit(PeekChar(1)) && !hasDecimal)
|
||||
{
|
||||
hasDecimal = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (format == NumberFormat.Decimal && (c == 'f' || c == 'd' || c == 'L') && !isDigit(PeekChar(1)))
|
||||
return true;
|
||||
|
||||
return isDigit(c);
|
||||
});
|
||||
|
||||
token = Token(ScriptTokenType.Number, prefix + numberContents);
|
||||
return true;
|
||||
}
|
||||
|
||||
token = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
enum NumberFormat
|
||||
{
|
||||
Decimal, Hexadecimal, Binary
|
||||
}
|
||||
|
||||
private ScriptToken Token(ScriptTokenType type, string contents)
|
||||
{
|
||||
return new ScriptToken(FileName, new SourcePosition(StartLine, StartColumn), new SourcePosition(Line, Column - 1), type, contents);
|
||||
}
|
||||
}
|
||||
}
|
||||
122
ScriptConverter/Parser/ScriptParser.Static.cs
Normal file
122
ScriptConverter/Parser/ScriptParser.Static.cs
Normal file
@@ -0,0 +1,122 @@
|
||||
using System.Collections.Generic;
|
||||
using ScriptConverter.Parser.Parselets;
|
||||
using ScriptConverter.Parser.Parselets.Declarations;
|
||||
using ScriptConverter.Parser.Parselets.Expressions;
|
||||
using ScriptConverter.Parser.Parselets.Statements;
|
||||
|
||||
namespace ScriptConverter.Parser
|
||||
{
|
||||
partial class ScriptParser
|
||||
{
|
||||
private static Dictionary<ScriptTokenType, IDeclarationParselet> _declarationParselets;
|
||||
private static Dictionary<ScriptTokenType, IStatementParselet> _statementParselets;
|
||||
private static Dictionary<ScriptTokenType, IPrefixParselet> _prefixParselets;
|
||||
private static Dictionary<ScriptTokenType, IInfixParselet> _infixParselets;
|
||||
|
||||
static ScriptParser()
|
||||
{
|
||||
_declarationParselets = new Dictionary<ScriptTokenType, IDeclarationParselet>();
|
||||
_statementParselets = new Dictionary<ScriptTokenType, IStatementParselet>();
|
||||
_prefixParselets = new Dictionary<ScriptTokenType, IPrefixParselet>();
|
||||
_infixParselets = new Dictionary<ScriptTokenType, IInfixParselet>();
|
||||
|
||||
// declarations
|
||||
RegisterDeclaration(ScriptTokenType.Const, new ConstParselet());
|
||||
RegisterDeclaration(ScriptTokenType.Include, new IncludeParselet());
|
||||
RegisterDeclaration(ScriptTokenType.Inherits, new InheritsParselet());
|
||||
RegisterDeclaration(ScriptTokenType.Identifier, new MethodParselet());
|
||||
RegisterDeclaration(ScriptTokenType.Public, new PublicParselet());
|
||||
|
||||
// statements
|
||||
RegisterStatement(ScriptTokenType.LeftBrace, new BlockParselet());
|
||||
RegisterStatement(ScriptTokenType.Break, new BreakParselet());
|
||||
RegisterStatement(ScriptTokenType.Const, new ConstVariableParselet());
|
||||
RegisterStatement(ScriptTokenType.Continue, new ContinueParselet());
|
||||
RegisterStatement(ScriptTokenType.Do, new DoParselet());
|
||||
RegisterStatement(ScriptTokenType.Semicolon, new EmptyParselet());
|
||||
RegisterStatement(ScriptTokenType.For, new ForParselet());
|
||||
RegisterStatement(ScriptTokenType.If, new IfParselet());
|
||||
RegisterStatement(ScriptTokenType.Return, new ReturnParselet());
|
||||
RegisterStatement(ScriptTokenType.Switch, new SwitchParselet());
|
||||
RegisterStatement(ScriptTokenType.Throw, new ThrowParselet());
|
||||
RegisterStatement(ScriptTokenType.Try, new TryParselet());
|
||||
RegisterStatement(ScriptTokenType.Identifier, new VariableParselet());
|
||||
RegisterStatement(ScriptTokenType.While, new WhileParselet());
|
||||
|
||||
// expressions
|
||||
RegisterPrefix(ScriptTokenType.LeftBrace, new ArrayInitializerParselet());
|
||||
RegisterInfix(ScriptTokenType.Add, new BinaryOperatorParselet(PrecedenceValue.Additive, false));
|
||||
RegisterInfix(ScriptTokenType.Subtract, new BinaryOperatorParselet(PrecedenceValue.Additive, false));
|
||||
RegisterInfix(ScriptTokenType.Multiply, new BinaryOperatorParselet(PrecedenceValue.Multiplicative, false));
|
||||
RegisterInfix(ScriptTokenType.Divide, new BinaryOperatorParselet(PrecedenceValue.Multiplicative, false));
|
||||
RegisterInfix(ScriptTokenType.Remainder, new BinaryOperatorParselet(PrecedenceValue.Multiplicative, false));
|
||||
RegisterInfix(ScriptTokenType.BitwiseShiftLeft, new BinaryOperatorParselet(PrecedenceValue.BitwiseShift, false));
|
||||
RegisterInfix(ScriptTokenType.BitwiseShiftRight, new BinaryOperatorParselet(PrecedenceValue.BitwiseShift, false));
|
||||
RegisterInfix(ScriptTokenType.BitwiseAnd, new BinaryOperatorParselet(PrecedenceValue.BitwiseAnd, false));
|
||||
RegisterInfix(ScriptTokenType.BitwiseOr, new BinaryOperatorParselet(PrecedenceValue.BitwiseOr, false));
|
||||
RegisterInfix(ScriptTokenType.BitwiseXor, new BinaryOperatorParselet(PrecedenceValue.BitwiseXor, false));
|
||||
RegisterInfix(ScriptTokenType.LogicalAnd, new BinaryOperatorParselet(PrecedenceValue.LogicalAnd, false));
|
||||
RegisterInfix(ScriptTokenType.LogicalOr, new BinaryOperatorParselet(PrecedenceValue.LogicalOr, false));
|
||||
RegisterInfix(ScriptTokenType.EqualTo, new BinaryOperatorParselet(PrecedenceValue.Equality, false));
|
||||
RegisterInfix(ScriptTokenType.NotEqualTo, new BinaryOperatorParselet(PrecedenceValue.Equality, false));
|
||||
RegisterInfix(ScriptTokenType.GreaterThan, new BinaryOperatorParselet(PrecedenceValue.Relational, false));
|
||||
RegisterInfix(ScriptTokenType.GreaterThanOrEqual, new BinaryOperatorParselet(PrecedenceValue.Relational, false));
|
||||
RegisterInfix(ScriptTokenType.LessThan, new BinaryOperatorParselet(PrecedenceValue.Relational, false));
|
||||
RegisterInfix(ScriptTokenType.LessThanOrEqual, new BinaryOperatorParselet(PrecedenceValue.Relational, false));
|
||||
RegisterInfix(ScriptTokenType.Assign, new BinaryOperatorParselet(PrecedenceValue.Assignment, true));
|
||||
RegisterInfix(ScriptTokenType.AddAssign, new BinaryOperatorParselet(PrecedenceValue.Assignment, true));
|
||||
RegisterInfix(ScriptTokenType.SubtractAssign, new BinaryOperatorParselet(PrecedenceValue.Assignment, true));
|
||||
RegisterInfix(ScriptTokenType.MultiplyAssign, new BinaryOperatorParselet(PrecedenceValue.Assignment, true));
|
||||
RegisterInfix(ScriptTokenType.DivideAssign, new BinaryOperatorParselet(PrecedenceValue.Assignment, true));
|
||||
RegisterInfix(ScriptTokenType.RemainderAssign, new BinaryOperatorParselet(PrecedenceValue.Assignment, true));
|
||||
RegisterInfix(ScriptTokenType.BitwiseShiftLeftAssign, new BinaryOperatorParselet(PrecedenceValue.Assignment, true));
|
||||
RegisterInfix(ScriptTokenType.BitwiseShiftRightAssign, new BinaryOperatorParselet(PrecedenceValue.Assignment, true));
|
||||
RegisterInfix(ScriptTokenType.BitwiseAndAssign, new BinaryOperatorParselet(PrecedenceValue.Assignment, true));
|
||||
RegisterInfix(ScriptTokenType.BitwiseOrAssign, new BinaryOperatorParselet(PrecedenceValue.Assignment, true));
|
||||
RegisterInfix(ScriptTokenType.BitwiseXorAssign, new BinaryOperatorParselet(PrecedenceValue.Assignment, true));
|
||||
RegisterPrefix(ScriptTokenType.True, new BoolParselet(true));
|
||||
RegisterPrefix(ScriptTokenType.False, new BoolParselet(false));
|
||||
RegisterInfix(ScriptTokenType.LeftParen, new CallParselet());
|
||||
RegisterInfix(ScriptTokenType.Dot, new FieldParselet());
|
||||
RegisterPrefix(ScriptTokenType.LeftParen, new GroupParselet());
|
||||
RegisterPrefix(ScriptTokenType.Hash, new HashParselet());
|
||||
RegisterPrefix(ScriptTokenType.Identifier, new IdentifierParselet());
|
||||
RegisterInfix(ScriptTokenType.LeftSquare, new IndexerParselet());
|
||||
RegisterInfix(ScriptTokenType.InstanceOf, new InstanceOfParselet());
|
||||
RegisterPrefix(ScriptTokenType.New, new NewParselet());
|
||||
RegisterPrefix(ScriptTokenType.Null, new NullParselet());
|
||||
RegisterPrefix(ScriptTokenType.Number, new NumberParselet());
|
||||
RegisterInfix(ScriptTokenType.Increment, new PostfixOperatorParselet(PrecedenceValue.Suffix));
|
||||
RegisterInfix(ScriptTokenType.Decrement, new PostfixOperatorParselet(PrecedenceValue.Suffix));
|
||||
RegisterPrefix(ScriptTokenType.Add, new PrefixOperatorParselet(PrecedenceValue.Prefix));
|
||||
RegisterPrefix(ScriptTokenType.Subtract, new PrefixOperatorParselet(PrecedenceValue.Prefix));
|
||||
RegisterPrefix(ScriptTokenType.BitwiseNot, new PrefixOperatorParselet(PrecedenceValue.Prefix));
|
||||
RegisterPrefix(ScriptTokenType.LogicalNot, new PrefixOperatorParselet(PrecedenceValue.Prefix));
|
||||
RegisterPrefix(ScriptTokenType.Increment, new PrefixOperatorParselet(PrecedenceValue.Prefix));
|
||||
RegisterPrefix(ScriptTokenType.Decrement, new PrefixOperatorParselet(PrecedenceValue.Prefix));
|
||||
RegisterPrefix(ScriptTokenType.String, new StringParselet(false));
|
||||
RegisterPrefix(ScriptTokenType.SingleString, new StringParselet(true));
|
||||
RegisterInfix(ScriptTokenType.QuestionMark, new TernaryParselet());
|
||||
}
|
||||
|
||||
static void RegisterDeclaration(ScriptTokenType type, IDeclarationParselet parselet)
|
||||
{
|
||||
_declarationParselets.Add(type, parselet);
|
||||
}
|
||||
|
||||
static void RegisterStatement(ScriptTokenType type, IStatementParselet parselet)
|
||||
{
|
||||
_statementParselets.Add(type, parselet);
|
||||
}
|
||||
|
||||
static void RegisterPrefix(ScriptTokenType type, IPrefixParselet parselet)
|
||||
{
|
||||
_prefixParselets.Add(type, parselet);
|
||||
}
|
||||
|
||||
static void RegisterInfix(ScriptTokenType type, IInfixParselet parselet)
|
||||
{
|
||||
_infixParselets.Add(type, parselet);
|
||||
}
|
||||
}
|
||||
}
|
||||
237
ScriptConverter/Parser/ScriptParser.cs
Normal file
237
ScriptConverter/Parser/ScriptParser.cs
Normal file
@@ -0,0 +1,237 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using ScriptConverter.Ast;
|
||||
using ScriptConverter.Ast.Declarations;
|
||||
using ScriptConverter.Ast.Expressions;
|
||||
using ScriptConverter.Ast.Statements;
|
||||
using ScriptConverter.Parser.Parselets;
|
||||
|
||||
namespace ScriptConverter.Parser
|
||||
{
|
||||
partial class ScriptParser : Parser
|
||||
{
|
||||
public ScriptParser(IEnumerable<ScriptToken> tokens)
|
||||
: base(tokens)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void ParseNamedType(out ScriptType type, out string name)
|
||||
{
|
||||
ParseNamedType(Take(), out type, out name);
|
||||
}
|
||||
|
||||
public void ParseNamedType(ScriptToken token, out ScriptType type, out string name)
|
||||
{
|
||||
type = ParseType(token);
|
||||
name = Take(ScriptTokenType.Identifier).Contents;
|
||||
|
||||
var arrayDims = 0;
|
||||
while (MatchAndTake(ScriptTokenType.LeftSquare))
|
||||
{
|
||||
Take(ScriptTokenType.RightSquare);
|
||||
arrayDims++;
|
||||
}
|
||||
|
||||
if (arrayDims == 0)
|
||||
return;
|
||||
|
||||
type = new ScriptType(type.Name, type.ArrayDimensions + arrayDims, type.IsResizable);
|
||||
}
|
||||
|
||||
public ScriptType ParseType()
|
||||
{
|
||||
return ParseType(Take());
|
||||
}
|
||||
|
||||
public ScriptType ParseType(ScriptToken token)
|
||||
{
|
||||
if (token.Type != ScriptTokenType.Identifier)
|
||||
throw new CompilerException(token, CompilerError.ExpectedButFound, ScriptTokenType.Identifier, token);
|
||||
|
||||
var isResizable = false;
|
||||
var arrayDims = 0;
|
||||
|
||||
if (token.Contents == "resizeable") // yes
|
||||
{
|
||||
isResizable = true;
|
||||
token = Take(ScriptTokenType.Identifier);
|
||||
}
|
||||
|
||||
var typeName = token.Contents;
|
||||
|
||||
if (Match(ScriptTokenType.Dot))
|
||||
{
|
||||
typeName += "." + string.Join(".", ParseSeparatedBy(ScriptTokenType.Dot, (_, first) =>
|
||||
{
|
||||
if (first)
|
||||
Take(ScriptTokenType.Dot);
|
||||
|
||||
return Take(ScriptTokenType.Identifier).Contents;
|
||||
}));
|
||||
}
|
||||
|
||||
if (isResizable)
|
||||
{
|
||||
Take(ScriptTokenType.LeftSquare);
|
||||
Take(ScriptTokenType.RightSquare);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (MatchAndTake(ScriptTokenType.LeftSquare))
|
||||
{
|
||||
Take(ScriptTokenType.RightSquare);
|
||||
arrayDims++;
|
||||
}
|
||||
}
|
||||
|
||||
return new ScriptType(typeName, arrayDims, isResizable);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse an expression into an expression tree. You can think of expressions as sub-statements.
|
||||
/// </summary>
|
||||
public Expression ParseExpression(int precendence = 0)
|
||||
{
|
||||
var token = Take();
|
||||
|
||||
IPrefixParselet prefixParselet;
|
||||
_prefixParselets.TryGetValue(token.Type, out prefixParselet);
|
||||
|
||||
if (prefixParselet == null)
|
||||
throw new CompilerException(token, CompilerError.ExpectedButFound, "Expression", token);
|
||||
|
||||
var left = prefixParselet.Parse(this, token);
|
||||
|
||||
while (GetPrecedence() > precendence)
|
||||
{
|
||||
token = Take();
|
||||
|
||||
IInfixParselet infixParselet;
|
||||
_infixParselets.TryGetValue(token.Type, out infixParselet);
|
||||
|
||||
if (infixParselet == null)
|
||||
throw new Exception("probably can't happen");
|
||||
|
||||
left = infixParselet.Parse(this, left, token);
|
||||
}
|
||||
|
||||
return left;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a statement into an expression tree.
|
||||
/// </summary>
|
||||
public Statement ParseStatement(bool takeTrailingSemicolon = true)
|
||||
{
|
||||
var token = Peek();
|
||||
|
||||
IStatementParselet statementParselet;
|
||||
_statementParselets.TryGetValue(token.Type, out statementParselet);
|
||||
|
||||
// HACK: workaround for variables
|
||||
if (token.Type == ScriptTokenType.Identifier && !IsVariableStatement())
|
||||
statementParselet = null;
|
||||
|
||||
if (statementParselet == null)
|
||||
{
|
||||
var expr = ParseExpression();
|
||||
|
||||
if (takeTrailingSemicolon)
|
||||
Take(ScriptTokenType.Semicolon);
|
||||
|
||||
return new NakedStatement(expr);
|
||||
}
|
||||
|
||||
token = Take();
|
||||
|
||||
bool hasTrailingSemicolon;
|
||||
var result = statementParselet.Parse(this, token, out hasTrailingSemicolon);
|
||||
|
||||
if (takeTrailingSemicolon && hasTrailingSemicolon)
|
||||
Take(ScriptTokenType.Semicolon);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a block of code into an expression tree. Blocks can either be a single statement or
|
||||
/// multiple surrounded by braces.
|
||||
/// </summary>
|
||||
public BlockStatement ParseBlock(bool allowSingle = true)
|
||||
{
|
||||
ScriptToken start;
|
||||
ScriptToken end;
|
||||
var statements = new List<Statement>();
|
||||
|
||||
if (allowSingle && !Match(ScriptTokenType.LeftBrace))
|
||||
{
|
||||
start = Peek();
|
||||
|
||||
statements.Add(ParseStatement());
|
||||
|
||||
end = Previous;
|
||||
|
||||
return new BlockStatement(start, end, statements);
|
||||
}
|
||||
|
||||
start = Take(ScriptTokenType.LeftBrace);
|
||||
|
||||
while (!Match(ScriptTokenType.RightBrace))
|
||||
{
|
||||
statements.Add(ParseStatement());
|
||||
}
|
||||
|
||||
end = Take(ScriptTokenType.RightBrace);
|
||||
|
||||
return new BlockStatement(start, end, statements);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses declarations until there are no more tokens available.
|
||||
/// </summary>
|
||||
public Document ParseAll()
|
||||
{
|
||||
var declarations = new List<Declaration>();
|
||||
|
||||
while (!Match(ScriptTokenType.Eof))
|
||||
{
|
||||
var token = Take();
|
||||
|
||||
if (token.Type == ScriptTokenType.Semicolon)
|
||||
continue;
|
||||
|
||||
IDeclarationParselet declarationParselet;
|
||||
if (!_declarationParselets.TryGetValue(token.Type, out declarationParselet))
|
||||
throw new CompilerException(token, "expected declaration"); // TODO
|
||||
|
||||
declarations.Add(declarationParselet.Parse(this, token));
|
||||
}
|
||||
|
||||
return new Document(declarations);
|
||||
}
|
||||
|
||||
private bool IsVariableStatement()
|
||||
{
|
||||
if (!Match(ScriptTokenType.Identifier))
|
||||
return false;
|
||||
|
||||
var i = 1;
|
||||
while (Match(ScriptTokenType.Dot, i) && Match(ScriptTokenType.Identifier, i + 1))
|
||||
{
|
||||
i += 2;
|
||||
}
|
||||
|
||||
return Match(ScriptTokenType.Identifier, i) ||
|
||||
(Match(ScriptTokenType.LeftSquare, i) && Match(ScriptTokenType.RightSquare, i + 1));
|
||||
}
|
||||
|
||||
private int GetPrecedence()
|
||||
{
|
||||
IInfixParselet infixParselet;
|
||||
_infixParselets.TryGetValue(Peek().Type, out infixParselet);
|
||||
|
||||
return infixParselet != null ? infixParselet.Precedence : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
35
ScriptConverter/Parser/SourcePosition.cs
Normal file
35
ScriptConverter/Parser/SourcePosition.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using System.Globalization;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace ScriptConverter.Parser
|
||||
{
|
||||
public struct SourcePosition
|
||||
{
|
||||
public readonly int Line;
|
||||
public readonly int Column;
|
||||
|
||||
public SourcePosition(int line, int column = -1)
|
||||
{
|
||||
Line = line;
|
||||
Column = column;
|
||||
}
|
||||
|
||||
[Pure]
|
||||
public override string ToString()
|
||||
{
|
||||
if (Column <= 0)
|
||||
return Line.ToString("G", CultureInfo.InvariantCulture);
|
||||
|
||||
return string.Format(CultureInfo.InvariantCulture, "{0:G}:{1:G}", Line, Column);
|
||||
}
|
||||
|
||||
[Pure]
|
||||
public string ToRangeString(SourcePosition end)
|
||||
{
|
||||
if (Line == end.Line && Column == end.Column)
|
||||
return ToString();
|
||||
|
||||
return string.Format(CultureInfo.InvariantCulture, "{0}-{1}", this, end);
|
||||
}
|
||||
}
|
||||
}
|
||||
172
ScriptConverter/Parser/Token.cs
Normal file
172
ScriptConverter/Parser/Token.cs
Normal file
@@ -0,0 +1,172 @@
|
||||
namespace ScriptConverter.Parser
|
||||
{
|
||||
abstract class Token<T>
|
||||
{
|
||||
public readonly string FileName;
|
||||
public readonly SourcePosition Start;
|
||||
public readonly SourcePosition End;
|
||||
|
||||
public readonly T Type;
|
||||
public readonly string Contents;
|
||||
|
||||
protected Token(string fileName, SourcePosition start, SourcePosition end, T type, string contents)
|
||||
{
|
||||
FileName = fileName;
|
||||
Start = start;
|
||||
End = end;
|
||||
|
||||
Type = type;
|
||||
Contents = contents;
|
||||
}
|
||||
|
||||
protected Token(Token<T> token, T type, string contents)
|
||||
: this(token.FileName, token.Start, token.End, type, contents)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected Token(T type, string contents)
|
||||
: this(null, new SourcePosition(-1), new SourcePosition(-1), type, contents)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public string RangeString
|
||||
{
|
||||
get { return Start.ToRangeString(End); }
|
||||
}
|
||||
}
|
||||
|
||||
enum ScriptTokenType
|
||||
{
|
||||
Identifier,
|
||||
|
||||
Number,
|
||||
SingleString,
|
||||
String,
|
||||
|
||||
Null,
|
||||
True,
|
||||
False,
|
||||
|
||||
Return,
|
||||
If,
|
||||
Else,
|
||||
For,
|
||||
While,
|
||||
Do,
|
||||
Break,
|
||||
Continue,
|
||||
Switch,
|
||||
Case,
|
||||
Default,
|
||||
|
||||
Hash,
|
||||
Inherits,
|
||||
Include,
|
||||
Const,
|
||||
Public,
|
||||
New,
|
||||
InstanceOf,
|
||||
Try,
|
||||
Catch,
|
||||
Throw,
|
||||
|
||||
Semicolon,
|
||||
Comma,
|
||||
Dot,
|
||||
Assign,
|
||||
QuestionMark,
|
||||
Colon,
|
||||
|
||||
LeftParen,
|
||||
RightParen,
|
||||
|
||||
LeftBrace,
|
||||
RightBrace,
|
||||
|
||||
LeftSquare,
|
||||
RightSquare,
|
||||
|
||||
Add,
|
||||
AddAssign,
|
||||
Subtract,
|
||||
SubtractAssign,
|
||||
Multiply,
|
||||
MultiplyAssign,
|
||||
Divide,
|
||||
DivideAssign,
|
||||
Remainder,
|
||||
RemainderAssign,
|
||||
Increment,
|
||||
Decrement,
|
||||
|
||||
EqualTo,
|
||||
NotEqualTo,
|
||||
GreaterThan,
|
||||
GreaterThanOrEqual,
|
||||
LessThan,
|
||||
LessThanOrEqual,
|
||||
|
||||
LogicalAnd,
|
||||
LogicalOr,
|
||||
LogicalNot,
|
||||
|
||||
BitwiseNot,
|
||||
BitwiseAnd,
|
||||
BitwiseAndAssign,
|
||||
BitwiseOr,
|
||||
BitwiseOrAssign,
|
||||
BitwiseXor,
|
||||
BitwiseXorAssign,
|
||||
BitwiseShiftLeft,
|
||||
BitwiseShiftLeftAssign,
|
||||
BitwiseShiftRight,
|
||||
BitwiseShiftRightAssign,
|
||||
|
||||
PreprocessDefine,
|
||||
PreprocessIfDef,
|
||||
PreprocessEndIf,
|
||||
|
||||
Eof
|
||||
}
|
||||
|
||||
class ScriptToken : Token<ScriptTokenType>
|
||||
{
|
||||
public ScriptToken(string fileName, SourcePosition start, SourcePosition end, ScriptTokenType type, string contents)
|
||||
: base(fileName, start, end, type, contents)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public ScriptToken(Token<ScriptTokenType> token, ScriptTokenType type, string contents)
|
||||
: base(token, type, contents)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public ScriptToken(ScriptTokenType type, string contents)
|
||||
: base(type, contents)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
case ScriptTokenType.Identifier:
|
||||
case ScriptTokenType.Number:
|
||||
case ScriptTokenType.String:
|
||||
var contentsStr = Contents;
|
||||
if (contentsStr.Length > 16)
|
||||
contentsStr = contentsStr.Substring(0, 13) + "...";
|
||||
|
||||
return string.Format("{0}('{1}')", Type, contentsStr);
|
||||
|
||||
default:
|
||||
return Type.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user