Skip to content

Commit

Permalink
Add basic project skeleton, with trivial interpreter in place (#1)
Browse files Browse the repository at this point in the history
This is pretty much a straight copy of
perlun/cslox@64da4fd,
with the following adjustments made:

- Rename the namespaces to Perlang.*

- Split the project into three parts: Perlang.Common,
  Perlang.Interpreter and Perlang.Parser. The idea here is to think
  already at an early stage about making the scanning and parsing parts
  reusable from non-interpreting/compiling scenarios. For example, to
  built a VS Code language server; it makes a lot of sense to not force
  all use cases that want to inspect Perlang source code to reimplement
  the whole language parser over and over again.

- Fix the code generated by scripts/generate_ast_classes.rb feel a bit
  more natural in the C# world, by using properties instead of plain
  fields. Also fixed the visibility since the generated code will now be
  in a different namespace from the classes that consume it.

- Try to improve the error handling slightly. It's still far from
  perfect and this is probably one of the things that will be improved
  on in the quite near future. Ideally, ParseStatements() and
  ParseExpression() would return not just the parsed
  statements/expression, but in case something goes wrong, the full list
  of parse errors should be available there. Nothing should be printed
  to stdout unless the consumer decides to print it.

- Extract a few interfaces like IInterpreter, IParseErrorHandler etc. We
  are not using any IOC container yet and time will tell if this will be
  necessary or not.
  • Loading branch information
perlun committed Jan 26, 2020
1 parent 4fc636b commit 3de39a3
Show file tree
Hide file tree
Showing 27 changed files with 2,445 additions and 0 deletions.
149 changes: 149 additions & 0 deletions Perlang.Common/Expr.cs
@@ -0,0 +1,149 @@
using System.Collections.Generic;

namespace Perlang
{
public abstract class Expr
{
public interface IVisitor<TR>
{
TR VisitAssignExpr(Assign expr);
TR VisitBinaryExpr(Binary expr);
TR VisitCallExpr(Call expr);
TR VisitGroupingExpr(Grouping expr);
TR VisitLiteralExpr(Literal expr);
TR VisitLogicalExpr(Logical expr);
TR VisitUnaryExpr(Unary expr);
TR VisitVariableExpr(Variable expr);
}

public class Assign : Expr
{
public Token Name { get; }
public Expr Value { get; }

public Assign(Token name, Expr value) {
Name = name;
Value = value;
}

public override TR Accept<TR>(IVisitor<TR> visitor)
{
return visitor.VisitAssignExpr(this);
}
}

public class Binary : Expr
{
public Expr Left { get; }
public Token Operator { get; }
public Expr Right { get; }

public Binary(Expr left, Token _operator, Expr right) {
Left = left;
Operator = _operator;
Right = right;
}

public override TR Accept<TR>(IVisitor<TR> visitor)
{
return visitor.VisitBinaryExpr(this);
}
}

public class Call : Expr
{
public Expr Callee { get; }
public Token Paren { get; }
public List<Expr> Arguments { get; }

public Call(Expr callee, Token paren, List<Expr> arguments) {
Callee = callee;
Paren = paren;
Arguments = arguments;
}

public override TR Accept<TR>(IVisitor<TR> visitor)
{
return visitor.VisitCallExpr(this);
}
}

public class Grouping : Expr
{
public Expr Expression { get; }

public Grouping(Expr expression) {
Expression = expression;
}

public override TR Accept<TR>(IVisitor<TR> visitor)
{
return visitor.VisitGroupingExpr(this);
}
}

public class Literal : Expr
{
public object Value { get; }

public Literal(object value) {
Value = value;
}

public override TR Accept<TR>(IVisitor<TR> visitor)
{
return visitor.VisitLiteralExpr(this);
}
}

public class Logical : Expr
{
public Expr Left { get; }
public Token Operator { get; }
public Expr Right { get; }

public Logical(Expr left, Token _operator, Expr right) {
Left = left;
Operator = _operator;
Right = right;
}

public override TR Accept<TR>(IVisitor<TR> visitor)
{
return visitor.VisitLogicalExpr(this);
}
}

public class Unary : Expr
{
public Token Operator { get; }
public Expr Right { get; }

public Unary(Token _operator, Expr right) {
Operator = _operator;
Right = right;
}

public override TR Accept<TR>(IVisitor<TR> visitor)
{
return visitor.VisitUnaryExpr(this);
}
}

public class Variable : Expr
{
public Token Name { get; }

public Variable(Token name) {
Name = name;
}

public override TR Accept<TR>(IVisitor<TR> visitor)
{
return visitor.VisitVariableExpr(this);
}
}

public abstract TR Accept<TR>(IVisitor<TR> visitor);
}
}
8 changes: 8 additions & 0 deletions Perlang.Common/Perlang.Common.csproj
@@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<RootNamespace>Perlang</RootNamespace>
</PropertyGroup>

</Project>
147 changes: 147 additions & 0 deletions Perlang.Common/Stmt.cs
@@ -0,0 +1,147 @@
using System.Collections.Generic;

namespace Perlang
{
public abstract class Stmt
{
public interface IVisitor<TR>
{
TR VisitBlockStmt(Block stmt);
TR VisitExpressionStmt(ExpressionStmt stmt);
TR VisitFunctionStmt(Function stmt);
TR VisitIfStmt(If stmt);
TR VisitPrintStmt(Print stmt);
TR VisitReturnStmt(Return stmt);
TR VisitVarStmt(Var stmt);
TR VisitWhileStmt(While stmt);
}

public class Block : Stmt
{
public List<Stmt> Statements { get; }

public Block(List<Stmt> statements) {
Statements = statements;
}

public override TR Accept<TR>(IVisitor<TR> visitor)
{
return visitor.VisitBlockStmt(this);
}
}

public class ExpressionStmt : Stmt
{
public Expr Expression { get; }

public ExpressionStmt(Expr expression) {
Expression = expression;
}

public override TR Accept<TR>(IVisitor<TR> visitor)
{
return visitor.VisitExpressionStmt(this);
}
}

public class Function : Stmt
{
public Token Name { get; }
public List<Token> Params { get; }
public List<Stmt> Body { get; }

public Function(Token name, List<Token> _params, List<Stmt> body) {
Name = name;
Params = _params;
Body = body;
}

public override TR Accept<TR>(IVisitor<TR> visitor)
{
return visitor.VisitFunctionStmt(this);
}
}

public class If : Stmt
{
public Expr Condition { get; }
public Stmt ThenBranch { get; }
public Stmt ElseBranch { get; }

public If(Expr condition, Stmt thenBranch, Stmt elseBranch) {
Condition = condition;
ThenBranch = thenBranch;
ElseBranch = elseBranch;
}

public override TR Accept<TR>(IVisitor<TR> visitor)
{
return visitor.VisitIfStmt(this);
}
}

public class Print : Stmt
{
public Expr Expression { get; }

public Print(Expr expression) {
Expression = expression;
}

public override TR Accept<TR>(IVisitor<TR> visitor)
{
return visitor.VisitPrintStmt(this);
}
}

public class Return : Stmt
{
public Token Keyword { get; }
public Expr Value { get; }

public Return(Token keyword, Expr value) {
Keyword = keyword;
Value = value;
}

public override TR Accept<TR>(IVisitor<TR> visitor)
{
return visitor.VisitReturnStmt(this);
}
}

public class Var : Stmt
{
public Token Name { get; }
public Expr Initializer { get; }

public Var(Token name, Expr initializer) {
Name = name;
Initializer = initializer;
}

public override TR Accept<TR>(IVisitor<TR> visitor)
{
return visitor.VisitVarStmt(this);
}
}

public class While : Stmt
{
public Expr Condition { get; }
public Stmt Body { get; }

public While(Expr condition, Stmt body) {
Condition = condition;
Body = body;
}

public override TR Accept<TR>(IVisitor<TR> visitor)
{
return visitor.VisitWhileStmt(this);
}
}

public abstract TR Accept<TR>(IVisitor<TR> visitor);
}
}
23 changes: 23 additions & 0 deletions Perlang.Common/Token.cs
@@ -0,0 +1,23 @@
namespace Perlang
{
public class Token
{
public TokenType Type { get; }
public string Lexeme { get; }
public object Literal { get; }
public int Line { get; }

public Token(TokenType type, string lexeme, object literal, int line)
{
Type = type;
Lexeme = lexeme;
Literal = literal;
Line = line;
}

public override string ToString()
{
return $"{Type} {Lexeme} {Literal}";
}
}
}
24 changes: 24 additions & 0 deletions Perlang.Common/TokenType.cs
@@ -0,0 +1,24 @@
namespace Perlang
{
public enum TokenType
{
// Single-character tokens.
LEFT_PAREN, RIGHT_PAREN, LEFT_BRACE, RIGHT_BRACE,
COMMA, DOT, MINUS, PLUS, SEMICOLON, SLASH, STAR,

// One or two character tokens.
BANG, BANG_EQUAL,
EQUAL, EQUAL_EQUAL,
GREATER, GREATER_EQUAL,
LESS, LESS_EQUAL,

// Literals.
IDENTIFIER, STRING, NUMBER,

// Keywords.
AND, CLASS, ELSE, FALSE, FUN, FOR, IF, NIL, OR,
PRINT, RETURN, SUPER, THIS, TRUE, VAR, WHILE,

EOF
}
}
10 changes: 10 additions & 0 deletions Perlang.Interpreter/ICallable.cs
@@ -0,0 +1,10 @@
using System.Collections.Generic;

namespace Perlang.Interpreter
{
internal interface ICallable
{
object Call(IInterpreter interpreter, List<object> arguments);
int Arity();
}
}
10 changes: 10 additions & 0 deletions Perlang.Interpreter/IInterpreter.cs
@@ -0,0 +1,10 @@
using System.Collections.Generic;

namespace Perlang.Interpreter
{
public interface IInterpreter
{
void ExecuteBlock(IEnumerable<Stmt> statements, PerlangEnvironment blockEnvironment);
void Resolve(Expr expr, int depth);
}
}
7 changes: 7 additions & 0 deletions Perlang.Interpreter/IResolveErrorHandler.cs
@@ -0,0 +1,7 @@
namespace Perlang.Interpreter
{
internal interface IResolveErrorHandler
{
void ResolveError(Token name, string message);
}
}
7 changes: 7 additions & 0 deletions Perlang.Interpreter/IRuntimeErrorHandler.cs
@@ -0,0 +1,7 @@
namespace Perlang.Interpreter
{
internal interface IRuntimeErrorHandler
{
void RuntimeError(RuntimeError error);
}
}

0 comments on commit 3de39a3

Please sign in to comment.