├── .gitignore
├── Bow.sln
├── Bow
├── Bow.csproj
├── Bow
│ ├── Bow.cs
│ ├── Errors
│ │ ├── BowBreak.cs
│ │ ├── BowEOFError.cs
│ │ ├── BowNameError.cs
│ │ ├── BowReturn.cs
│ │ ├── BowRuntimeError.cs
│ │ ├── BowSyntaxError.cs
│ │ └── BowTypeError.cs
│ ├── Interpret
│ │ └── Interpreter.cs
│ ├── Parse
│ │ ├── Environment
│ │ │ ├── Env.cs
│ │ │ └── Symbols
│ │ │ │ ├── FunctionSymbol.cs
│ │ │ │ └── VariableSymbol.cs
│ │ ├── Expressions
│ │ │ ├── BinaryExpression.cs
│ │ │ ├── Expression.cs
│ │ │ ├── FunctionExpression.cs
│ │ │ ├── LiteralExpression.cs
│ │ │ ├── Literals
│ │ │ │ ├── BooLiteral.cs
│ │ │ │ ├── DecLiteral.cs
│ │ │ │ ├── Literal.cs
│ │ │ │ ├── NullReturn.cs
│ │ │ │ └── StrLiteral.cs
│ │ │ ├── UnaryExpression.cs
│ │ │ └── VariableExpression.cs
│ │ ├── Parser.cs
│ │ └── Statements
│ │ │ ├── Assignment.cs
│ │ │ ├── Break.cs
│ │ │ ├── Declaration.cs
│ │ │ ├── Function.cs
│ │ │ ├── If.cs
│ │ │ ├── LitStatements.cs
│ │ │ ├── Return.cs
│ │ │ ├── Statement.cs
│ │ │ └── Switch.cs
│ └── Tokenise
│ │ ├── Keywords.cs
│ │ ├── Lexer.cs
│ │ ├── Token.cs
│ │ └── TokenType.cs
└── Program.cs
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | bin/
3 | obj/
4 | /packages/
5 | riderModule.iml
6 | /_ReSharper.Caches/
7 | Bow/test.bow
8 | .vs/
9 |
--------------------------------------------------------------------------------
/Bow.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bow", "Bow\Bow.csproj", "{0C5734BC-CC2D-4BB9-AB63-9C88A4CCA544}"
4 | EndProject
5 | Global
6 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
7 | Debug|Any CPU = Debug|Any CPU
8 | Release|Any CPU = Release|Any CPU
9 | EndGlobalSection
10 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
11 | {0C5734BC-CC2D-4BB9-AB63-9C88A4CCA544}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
12 | {0C5734BC-CC2D-4BB9-AB63-9C88A4CCA544}.Debug|Any CPU.Build.0 = Debug|Any CPU
13 | {0C5734BC-CC2D-4BB9-AB63-9C88A4CCA544}.Release|Any CPU.ActiveCfg = Release|Any CPU
14 | {0C5734BC-CC2D-4BB9-AB63-9C88A4CCA544}.Release|Any CPU.Build.0 = Release|Any CPU
15 | EndGlobalSection
16 | EndGlobal
17 |
--------------------------------------------------------------------------------
/Bow/Bow.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net6.0
6 | enable
7 | enable
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Bow/Bow/Bow.cs:
--------------------------------------------------------------------------------
1 | using Parse;
2 | using Parse.Statements;
3 | using Parse.Environment;
4 |
5 | using Interpret;
6 |
7 | using Errors;
8 | using Tokenise;
9 |
10 | public class Bow
11 | {
12 | private readonly string _code;
13 | private readonly bool _debug;
14 | private readonly bool _inShell;
15 |
16 | public Bow(string fileName, bool inShell=false, bool debug=false)
17 | {
18 | _code = inShell ? fileName : String.Join("\n", File.ReadAllLines(fileName));
19 | _debug = debug;
20 | _inShell = inShell;
21 | }
22 |
23 | public void Run()
24 | {
25 | string nextCode = "";
26 |
27 | try
28 | {
29 | List tokens = new Lexer(_code).ScanTokens();
30 | if (_debug)
31 | {
32 | foreach (var token in tokens)
33 | {
34 | Console.WriteLine(token.Inspect());
35 | }
36 | Console.WriteLine("\n\n");
37 | }
38 |
39 | List statements = new Parser(tokens).Parse();
40 | new Interpreter(statements).Interpret(_inShell);
41 | }
42 | catch (BowSyntaxError ex)
43 | {
44 | Console.WriteLine($"\x1B[91mBow Syntax Error: {(_debug ? ex : ex.Message)}\x1B[0m");
45 | }
46 | catch (BowTypeError ex)
47 | {
48 | Console.WriteLine($"\x1B[91mBow Type Error: {(_debug ? ex : ex.Message)}\x1B[0m");
49 | }
50 | catch (BowNameError ex)
51 | {
52 | Console.WriteLine($"\x1B[91mBow Name Error: {(_debug ? ex : ex.Message)}\x1B[0m");
53 | }
54 | catch (BowEOFError ex)
55 | {
56 | if (_inShell)
57 | {
58 | nextCode = _code;
59 | }
60 | else
61 | {
62 | Console.WriteLine($"\x1B[91mBow EOF Error: {(_debug ? ex : ex.Message)}\x1B[0m");
63 | }
64 | }
65 | finally
66 | {
67 | if (_debug)
68 | {
69 | Env.Output();
70 | }
71 |
72 | if (_inShell)
73 | {
74 | RunShell(false, nextCode);
75 | }
76 | }
77 | }
78 |
79 | public static void RunShell(bool firstCall=true, string lines="")
80 | {
81 | if (firstCall) Console.WriteLine("\x1B[1;4mBow Interactive Shell\x1B[0m\n");
82 |
83 | string prompt = lines == "" ? "bow" : " ";
84 | Console.Write($"\x1B[92m{prompt}>\x1B[0m ");
85 |
86 | string? line = Console.ReadLine();
87 | line ??= "";
88 |
89 | if (line == "exit")
90 | {
91 | return;
92 | }
93 |
94 | lines += line + "\n";
95 |
96 | new Bow(lines, true).Run();
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/Bow/Bow/Errors/BowBreak.cs:
--------------------------------------------------------------------------------
1 | namespace Errors;
2 |
3 | [Serializable]
4 | public class BowBreak : Exception
5 | {
6 | public BowBreak() : base() { }
7 | public BowBreak(string message) : base(message) { }
8 | public BowBreak(string message, Exception inner) : base(message, inner) { }
9 |
10 | protected BowBreak(System.Runtime.Serialization.SerializationInfo info,
11 | System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
12 | }
13 |
--------------------------------------------------------------------------------
/Bow/Bow/Errors/BowEOFError.cs:
--------------------------------------------------------------------------------
1 | namespace Errors;
2 |
3 | [Serializable]
4 | public class BowEOFError : Exception
5 | {
6 | public BowEOFError() : base() { }
7 | public BowEOFError(string message) : base(message) { }
8 | public BowEOFError(string message, Exception inner) : base(message, inner) { }
9 |
10 | protected BowEOFError(System.Runtime.Serialization.SerializationInfo info,
11 | System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
12 | }
13 |
--------------------------------------------------------------------------------
/Bow/Bow/Errors/BowNameError.cs:
--------------------------------------------------------------------------------
1 | namespace Errors;
2 |
3 | [Serializable]
4 | public class BowNameError : Exception
5 | {
6 | public BowNameError() : base() { }
7 | public BowNameError(string message) : base(message) { }
8 | public BowNameError(string message, Exception inner) : base(message, inner) { }
9 |
10 | protected BowNameError(System.Runtime.Serialization.SerializationInfo info,
11 | System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
12 | }
13 |
--------------------------------------------------------------------------------
/Bow/Bow/Errors/BowReturn.cs:
--------------------------------------------------------------------------------
1 | using Parse.Expressions.Literals;
2 |
3 | namespace Errors;
4 |
5 | [Serializable]
6 | public class BowReturn : Exception
7 | {
8 | public Literal? Literal { get; }
9 |
10 | public BowReturn() : base() { }
11 | public BowReturn(string message) : base(message) { }
12 | public BowReturn(string message, Exception inner) : base(message, inner) { }
13 |
14 | public BowReturn(Literal? literal) : base()
15 | {
16 | Literal = literal;
17 |
18 | }
19 |
20 | protected BowReturn(System.Runtime.Serialization.SerializationInfo info,
21 | System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
22 | }
23 |
--------------------------------------------------------------------------------
/Bow/Bow/Errors/BowRuntimeError.cs:
--------------------------------------------------------------------------------
1 | namespace Errors;
2 |
3 | [Serializable]
4 | public class BowRuntimeError : Exception
5 | {
6 | public BowRuntimeError() : base() { }
7 | public BowRuntimeError(string message) : base(message) { }
8 | public BowRuntimeError(string message, Exception inner) : base(message, inner) { }
9 |
10 | protected BowRuntimeError(System.Runtime.Serialization.SerializationInfo info,
11 | System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
12 | }
13 |
--------------------------------------------------------------------------------
/Bow/Bow/Errors/BowSyntaxError.cs:
--------------------------------------------------------------------------------
1 | namespace Errors;
2 |
3 | [Serializable]
4 | public class BowSyntaxError : Exception
5 | {
6 | public BowSyntaxError() : base() { }
7 | public BowSyntaxError(string message) : base(message) { }
8 | public BowSyntaxError(string message, Exception inner) : base(message, inner) { }
9 |
10 | protected BowSyntaxError(System.Runtime.Serialization.SerializationInfo info,
11 | System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
12 | }
13 |
--------------------------------------------------------------------------------
/Bow/Bow/Errors/BowTypeError.cs:
--------------------------------------------------------------------------------
1 | namespace Errors;
2 |
3 | [Serializable]
4 | public class BowTypeError : Exception
5 | {
6 | public BowTypeError() : base() { }
7 | public BowTypeError(string message) : base(message) { }
8 | public BowTypeError(string message, Exception inner) : base(message, inner) { }
9 |
10 | protected BowTypeError(System.Runtime.Serialization.SerializationInfo info,
11 | System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
12 | }
13 |
--------------------------------------------------------------------------------
/Bow/Bow/Interpret/Interpreter.cs:
--------------------------------------------------------------------------------
1 | using Parse.Statements;
2 |
3 | namespace Interpret;
4 |
5 | public class Interpreter
6 | {
7 | private readonly List _statements;
8 |
9 | public Interpreter(List statements)
10 | {
11 | _statements = statements;
12 | }
13 |
14 | public void Interpret(bool inShell=false)
15 | {
16 | foreach (var statement in _statements.SkipLast(inShell ? 1 : 0))
17 | {
18 | statement.Interpret();
19 | }
20 |
21 |
22 | if (inShell && _statements.Count > 0)
23 | {
24 | Console.WriteLine($"\x1B[95m> \x1B[93m{_statements.Last().Interpret(inShell)}\x1B[0m");
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Bow/Bow/Parse/Environment/Env.cs:
--------------------------------------------------------------------------------
1 | using Errors;
2 | using Parse.Expressions;
3 |
4 | namespace Parse.Environment;
5 |
6 | public class Env
7 | {
8 | public static int NestLevel = 0;
9 | private static readonly List Scopes = new() { new Env() };
10 | private readonly Dictionary _variables;
11 | private readonly Dictionary _functions;
12 |
13 | public Env()
14 | {
15 | _variables = new Dictionary();
16 | _functions = new Dictionary();
17 | }
18 |
19 | public Env(Dictionary variables)
20 | {
21 | _variables = variables;
22 | _functions = new Dictionary();
23 | }
24 |
25 | public static void PushScope(Env env)
26 | {
27 | NestLevel++;
28 | Scopes.Insert(0, env);
29 | }
30 |
31 | public static void PopScope()
32 | {
33 | NestLevel--;
34 | Scopes.RemoveAt(0);
35 | }
36 |
37 | public static void SetNestLevel(int level)
38 | {
39 | while (NestLevel > level)
40 | {
41 | PopScope();
42 | }
43 | }
44 |
45 | public static void AddVariable(VariableSymbol symbol)
46 | {
47 | if (FunctionExpression.IsBuiltinFunction(symbol.Name))
48 | {
49 | throw new BowNameError($"Unable to redefine built-in function '{symbol.Name}'");
50 | }
51 |
52 | Env scope = Scopes[0];
53 |
54 | if (!scope._variables.ContainsKey(symbol.Name))
55 | {
56 | scope._variables.Add(symbol.Name, symbol);
57 | }
58 | }
59 |
60 | public static VariableSymbol GetVariable(string name)
61 | {
62 | foreach (Env scope in Scopes)
63 | {
64 | if (scope._variables.ContainsKey(name))
65 | {
66 | return scope._variables[name];
67 | }
68 | }
69 |
70 | throw new BowNameError($"Variable '{name}' not found");
71 | }
72 |
73 | public static bool IsVariableDefined(string name)
74 | {
75 | try
76 | {
77 | GetVariable(name);
78 | return true;
79 | }
80 | catch (BowNameError)
81 | {
82 | return false;
83 | }
84 | }
85 |
86 | public static bool IsVariableDefinedLocally(string name)
87 | {
88 | return Scopes[0]._variables.ContainsKey(name);
89 | }
90 |
91 | private static void OutputVariables()
92 | {
93 | Console.WriteLine("\nVariables:");
94 | foreach (Env scope in Scopes)
95 | {
96 | foreach (KeyValuePair pair in scope._variables)
97 | {
98 | string value = pair.Value.Literal.DisplayValue;
99 |
100 | Console.WriteLine($"{pair.Key} = {value}");
101 | }
102 | }
103 | }
104 |
105 | public static void AddFunction(FunctionSymbol symbol)
106 | {
107 | if (FunctionExpression.IsBuiltinFunction(symbol.Name))
108 | {
109 | throw new BowNameError($"Unable to redefine built-in function '{symbol.Name}'");
110 | }
111 |
112 | Env scope = Scopes[0];
113 |
114 | if (!scope._functions.ContainsKey(symbol.Name))
115 | {
116 | scope._functions.Add(symbol.Name, symbol);
117 | }
118 | }
119 |
120 | public static FunctionSymbol GetFunction(string name, int line)
121 | {
122 | foreach (Env scope in Scopes)
123 | {
124 | if (scope._functions.ContainsKey(name))
125 | {
126 | return scope._functions[name];
127 | }
128 | }
129 |
130 | throw new BowNameError($"Function '{name}' not found on line {line}");
131 | }
132 |
133 | public static bool IsFunctionDefined(string name, int line)
134 | {
135 | try
136 | {
137 | GetFunction(name, line);
138 | return true;
139 | }
140 | catch (BowNameError)
141 | {
142 | return FunctionExpression.IsBuiltinFunction(name);
143 | }
144 | }
145 |
146 | private static void OutputFunctions()
147 | {
148 | Console.WriteLine("\nFunctions:");
149 | foreach (Env scope in Scopes)
150 | {
151 | foreach (KeyValuePair pair in scope._functions)
152 | {
153 | Console.WriteLine(pair.Key);
154 | }
155 | }
156 | }
157 |
158 | public static void Output()
159 | {
160 | Console.WriteLine("\n");
161 | OutputVariables();
162 | OutputFunctions();
163 | }
164 | }
165 |
--------------------------------------------------------------------------------
/Bow/Bow/Parse/Environment/Symbols/FunctionSymbol.cs:
--------------------------------------------------------------------------------
1 | using Parse.Statements;
2 |
3 | namespace Parse.Environment;
4 |
5 | public class FunctionSymbol
6 | {
7 | public string Name { get; }
8 | public List>> Parameters { get; }
9 | public List ReturnTypes { get; }
10 | public List Statements { get; }
11 | public int Line { get; }
12 |
13 | public FunctionSymbol(string name, List>> parameters, List returnTypes,
14 | List statements, int line)
15 | {
16 | Name = name;
17 | Parameters = parameters;
18 | ReturnTypes = returnTypes;
19 | Statements = statements;
20 | Line = line;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Bow/Bow/Parse/Environment/Symbols/VariableSymbol.cs:
--------------------------------------------------------------------------------
1 | using Parse.Expressions.Literals;
2 |
3 | namespace Parse.Environment;
4 |
5 | public class VariableSymbol
6 | {
7 | public string Name { get; }
8 | public Literal Literal { get; private set; }
9 | public int Line { get; }
10 | public bool IsConstant { get; }
11 |
12 | public VariableSymbol(string name, Literal literal, int line, bool isConstant)
13 | {
14 | Name = name;
15 | Literal = literal;
16 | Line = line;
17 | IsConstant = isConstant;
18 | }
19 |
20 | public void SetValue(Literal newValue)
21 | {
22 | Literal = newValue;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Bow/Bow/Parse/Expressions/BinaryExpression.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 | using Errors;
3 | using Tokenise;
4 |
5 | using Parse.Expressions.Literals;
6 |
7 | namespace Parse.Expressions;
8 |
9 | public class BinaryExpression : Expression
10 | {
11 | private readonly Expression _left;
12 | private readonly Expression _right;
13 | private readonly Token _operator;
14 | private readonly int _line;
15 |
16 | public BinaryExpression(Expression left, Token op, Expression right, int line)
17 | {
18 | _left = left;
19 | _right = right;
20 | _operator = op;
21 | _line = line;
22 | }
23 |
24 | public override Literal Evaluate()
25 | {
26 | Literal left = _left.Evaluate();
27 | Literal right = _right.Evaluate();
28 |
29 | if (left.Type == TokenType.NullReturn || right.Type == TokenType.NullReturn)
30 | {
31 | throw new BowTypeError($"Cannot perform operation on non-returning function on line {_line}");
32 | }
33 |
34 | if (left.Type != right.Type)
35 | {
36 | throw new BowTypeError($"Cannot perform operation on two different types on line {_line}");
37 | }
38 |
39 | // Comparison Operators
40 |
41 | if (left.Type == TokenType.DecLiteral)
42 | {
43 | switch (_operator.Type)
44 | {
45 | case TokenType.LessThan:
46 | return new BooLiteral(left.Value < right.Value);
47 | case TokenType.LessThanEqual:
48 | return new BooLiteral(left.Value <= right.Value);
49 | case TokenType.GreaterThan:
50 | return new BooLiteral(left.Value > right.Value);
51 | case TokenType.GreaterThanEqual:
52 | return new BooLiteral(left.Value >= right.Value);
53 | }
54 | }
55 |
56 | switch (_operator.Type)
57 | {
58 | case TokenType.Equal:
59 | return new BooLiteral(left.Value == right.Value);
60 | case TokenType.NotEqual:
61 | return new BooLiteral(left.Value != right.Value);
62 | }
63 |
64 | // Arithmetic Operators
65 |
66 | switch (left.Type)
67 | {
68 | case TokenType.BooLiteral:
69 | return _operator.Type switch
70 | {
71 | TokenType.And => new BooLiteral(left.Value && right.Value),
72 | TokenType.Or => new BooLiteral(left.Value || right.Value),
73 | _ => throw new BowTypeError($"Can't perform {_operator.Type} operation on booleans on line {_line}")
74 | };
75 | case TokenType.StrLiteral:
76 | return _operator.Type switch
77 | {
78 | TokenType.Plus => new StrLiteral(left.Value + right.Value),
79 | _ => throw new BowTypeError(
80 | $"Can't perform {_operator.Type} operation on strings on line {_line}")
81 | };
82 | case TokenType.DecLiteral:
83 | return _operator.Type switch
84 | {
85 | TokenType.Plus => new DecLiteral(left.Value + right.Value),
86 | TokenType.Minus => new DecLiteral(left.Value - right.Value),
87 | TokenType.Star => new DecLiteral(left.Value * right.Value),
88 | TokenType.Slash => new DecLiteral(left.Value / right.Value),
89 | _ => throw new BowTypeError(
90 | $"Can't perform `{_operator.Type} operation on decimals on line {_line}")
91 | };
92 | default:
93 | throw new BowTypeError($"Can't perform operations on {left.Type} on line {_line}");
94 | }
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/Bow/Bow/Parse/Expressions/Expression.cs:
--------------------------------------------------------------------------------
1 | using Parse.Expressions.Literals;
2 |
3 | namespace Parse.Expressions;
4 |
5 | public class Expression
6 | {
7 | public virtual Literal Evaluate()
8 | {
9 | throw new NotImplementedException();
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Bow/Bow/Parse/Expressions/FunctionExpression.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using Errors;
3 | using Tokenise;
4 | using Parse.Statements;
5 | using Parse.Environment;
6 | using Parse.Expressions.Literals;
7 |
8 | namespace Parse.Expressions;
9 |
10 | public class FunctionExpression : Expression
11 | {
12 | private readonly string _name;
13 | private readonly List _parameters;
14 | private readonly int _line;
15 |
16 | public FunctionExpression(string name, List parameters, int line)
17 | {
18 | _name = name;
19 | _parameters = parameters;
20 | _line = line;
21 | }
22 |
23 | public override Literal Evaluate()
24 | {
25 | bool isBuiltin = IsBuiltinFunction(_name);
26 |
27 | return ExecuteFunction(isBuiltin);
28 | }
29 |
30 | private void CheckParametersLength(List>> accepted)
31 | {
32 | if (_parameters.Count < accepted.Count)
33 | {
34 | throw new BowSyntaxError($"Not enough parameters for function {_name} on line {_line}");
35 | }
36 |
37 | if (_parameters.Count > accepted.Count)
38 | {
39 | throw new BowSyntaxError($"Too many parameters for function {_name} on line {_line}");
40 | }
41 | }
42 |
43 | private Literal ExecuteFunction(bool isBuiltin)
44 | {
45 | return isBuiltin ? ExecuteBuiltinFunction() : ExecuteUserFunction();
46 | }
47 |
48 | private Literal ExecuteUserFunction()
49 | {
50 | FunctionSymbol function = Env.GetFunction(_name, _line);
51 |
52 | CheckParametersLength(function.Parameters);
53 |
54 | Dictionary parameters = new();
55 |
56 | foreach (var param in _parameters.Select((value, i) => new { i, value }))
57 | {
58 | Literal paramLiteral = param.value.Evaluate();
59 |
60 | string name = function.Parameters[param.i].Item1;
61 |
62 | if (!function.Parameters[param.i].Item2.Contains(paramLiteral.Type))
63 | {
64 | throw new BowSyntaxError($"Incorrect type for parameter '{name}' of function '{_name}' on line {_line}");
65 | }
66 |
67 | parameters.Add(name, new VariableSymbol(name, paramLiteral, _line, false));
68 | }
69 |
70 | Literal? value = null;
71 |
72 | int nestLevel = Env.NestLevel;
73 |
74 | Env.PushScope(new Env(parameters));
75 |
76 | try
77 | {
78 | foreach (Statement statement in function.Statements)
79 | {
80 | statement.Interpret();
81 | }
82 | }
83 | catch (BowReturn ex)
84 | {
85 | value = ex.Literal;
86 | }
87 | finally
88 | {
89 | Env.SetNestLevel(nestLevel);
90 | }
91 |
92 | CheckReturnTypes(value, function.ReturnTypes);
93 |
94 | if (value is null)
95 | {
96 | return new NullReturn();
97 | }
98 |
99 | return value.Type switch
100 | {
101 | TokenType.StrLiteral => new StrLiteral(value.Value),
102 | TokenType.BooLiteral => new BooLiteral(value.Value),
103 | TokenType.DecLiteral => new DecLiteral(value.Value),
104 | _ => throw new BowRuntimeError($"Variable expression contains unknown type {value.Type} on line {_line}")
105 | };
106 | }
107 |
108 | private void CheckReturnTypes(Literal? value, List types)
109 | {
110 | if (value is null && types.Count != 0)
111 | {
112 | throw new BowTypeError($"Function call unexpectedly did not return anything on line {_line}");
113 | }
114 |
115 | if (value is null)
116 | {
117 | return;
118 | }
119 |
120 | if (!types.Contains(value.Type))
121 | {
122 | throw new BowTypeError($"Function call did not return a correct type on line {_line}");
123 | }
124 | }
125 |
126 | private Literal ExecuteBuiltinFunction()
127 | {
128 | Type builtins = typeof(Builtins);
129 |
130 | const BindingFlags flags = BindingFlags.InvokeMethod |
131 | BindingFlags.Public |
132 | BindingFlags.Static;
133 |
134 | MethodInfo? func = builtins.GetMethod(_name, flags);
135 |
136 | if (func == null)
137 | {
138 | throw new BowNameError($"Unknown function '{_name}' on line {_line}");
139 | }
140 |
141 | object[] parameters = _parameters.Select(param => param.Evaluate().Value).ToArray();
142 |
143 | try
144 | {
145 | return (Literal)(func.Invoke(null, parameters) ?? new NullReturn());
146 | }
147 | catch (TargetParameterCountException)
148 | {
149 | throw new BowSyntaxError($"Incorrect number of parameters for function '{_name}' on line {_line}");
150 | }
151 | catch (ArgumentException)
152 | {
153 | throw new BowTypeError($"Incorrect type for parameter on line {_line}");
154 | }
155 | }
156 |
157 | public static bool IsBuiltinFunction(string name)
158 | {
159 | const BindingFlags flags = BindingFlags.InvokeMethod |
160 | BindingFlags.Public |
161 | BindingFlags.Static;
162 |
163 | MethodInfo? func = typeof(Builtins).GetMethod(name, flags);
164 |
165 | return func != null;
166 | }
167 | }
168 |
169 | public class Builtins
170 | {
171 | public static Literal output(string value)
172 | {
173 | Console.WriteLine(value);
174 | return new NullReturn();
175 | }
176 |
177 | public static Literal input(string message="")
178 | {
179 | Console.Write(message);
180 | return new StrLiteral(Console.ReadLine() ?? "");
181 | }
182 | }
183 |
--------------------------------------------------------------------------------
/Bow/Bow/Parse/Expressions/LiteralExpression.cs:
--------------------------------------------------------------------------------
1 | using Parse.Expressions.Literals;
2 |
3 | namespace Parse.Expressions;
4 |
5 | public class LiteralExpression : Expression
6 | {
7 | private readonly Literal _literal;
8 | private readonly int _line;
9 |
10 | public LiteralExpression(Literal literal, int line)
11 | {
12 | _literal = literal;
13 | _line = line;
14 | }
15 |
16 | public override Literal Evaluate()
17 | {
18 | return _literal;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Bow/Bow/Parse/Expressions/Literals/BooLiteral.cs:
--------------------------------------------------------------------------------
1 | using Tokenise;
2 |
3 | namespace Parse.Expressions.Literals;
4 |
5 | public class BooLiteral : Literal
6 | {
7 | public BooLiteral(string value)
8 | {
9 | Value = bool.Parse(value);
10 | Type = TokenType.BooLiteral;
11 | }
12 |
13 | public BooLiteral(bool value)
14 | {
15 | Value = value;
16 | Type = TokenType.BooLiteral;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Bow/Bow/Parse/Expressions/Literals/DecLiteral.cs:
--------------------------------------------------------------------------------
1 | using Tokenise;
2 |
3 | namespace Parse.Expressions.Literals;
4 |
5 | public class DecLiteral : Literal
6 | {
7 | public DecLiteral(string value)
8 | {
9 | Value = double.Parse(value);
10 | Type = TokenType.DecLiteral;
11 | }
12 |
13 | public DecLiteral(double value)
14 | {
15 | Value = value;
16 | Type = TokenType.DecLiteral;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Bow/Bow/Parse/Expressions/Literals/Literal.cs:
--------------------------------------------------------------------------------
1 | using Tokenise;
2 | namespace Parse.Expressions.Literals;
3 |
4 | public class Literal
5 | {
6 | public dynamic Value { get; init; } = "";
7 | public string Type { get; init; } = "";
8 |
9 | public string DisplayValue
10 | {
11 | get
12 | {
13 | if (Type == TokenType.StrLiteral)
14 | {
15 | return $"\"{Value}\"";
16 | }
17 |
18 | return Value.ToString();
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Bow/Bow/Parse/Expressions/Literals/NullReturn.cs:
--------------------------------------------------------------------------------
1 | using Tokenise;
2 |
3 | namespace Parse.Expressions.Literals;
4 |
5 | public class NullReturn : Literal
6 | {
7 | public NullReturn()
8 | {
9 | Value = "null";
10 | Type = TokenType.NullReturn;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Bow/Bow/Parse/Expressions/Literals/StrLiteral.cs:
--------------------------------------------------------------------------------
1 | using Tokenise;
2 |
3 | namespace Parse.Expressions.Literals;
4 |
5 | public class StrLiteral : Literal
6 | {
7 | public StrLiteral(string value)
8 | {
9 | Value = value;
10 | Type = TokenType.StrLiteral;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Bow/Bow/Parse/Expressions/UnaryExpression.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 | using Errors;
3 | using Tokenise;
4 | using Parse.Expressions.Literals;
5 |
6 | namespace Parse.Expressions;
7 |
8 | public class UnaryExpression : Expression
9 | {
10 | private readonly Expression _right;
11 | private readonly Token _operator;
12 | private readonly int _line;
13 |
14 | public UnaryExpression(Token op, Expression right, int line)
15 | {
16 | _right = right;
17 | _operator = op;
18 | _line = line;
19 | }
20 |
21 | public override Literal Evaluate()
22 | {
23 | Literal right = _right.Evaluate();
24 |
25 | if (right.Type == TokenType.NullReturn)
26 | {
27 | throw new BowTypeError($"Cannot perform operation on non-returning function on line {_line}");
28 | }
29 |
30 | switch (_operator.Type)
31 | {
32 | case TokenType.Minus:
33 | if (right.Type != TokenType.DecLiteral)
34 | {
35 | throw new BowTypeError($"Can't negate non-decimal value on line {_line}");
36 | }
37 | return new DecLiteral(-right.Value);
38 | default:
39 | throw new BowTypeError($"Can't perform `{_operator.Type} operation {right.Type} on line {_line}");
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Bow/Bow/Parse/Expressions/VariableExpression.cs:
--------------------------------------------------------------------------------
1 | using Errors;
2 | using Tokenise;
3 | using Parse.Environment;
4 | using Parse.Expressions.Literals;
5 |
6 | namespace Parse.Expressions;
7 |
8 | public class VariableExpression : Expression
9 | {
10 | private readonly string _name;
11 | private readonly int _line;
12 |
13 | public VariableExpression(string name, int line)
14 | {
15 | _name = name;
16 | _line = line;
17 | }
18 |
19 | public override Literal Evaluate()
20 | {
21 | Literal value = Env.IsFunctionDefined(_name, _line)
22 | ? new FunctionExpression(_name, new(), _line).Evaluate()
23 | : Env.GetVariable(_name).Literal;
24 |
25 | return value.Type switch
26 | {
27 | TokenType.StrLiteral => new StrLiteral(value.Value),
28 | TokenType.BooLiteral => new BooLiteral(value.Value),
29 | TokenType.DecLiteral => new DecLiteral(value.Value),
30 | TokenType.NullReturn => new NullReturn(),
31 | _ => throw new BowRuntimeError($"Variable expression contains unknown type {value.Type} on line {_line}")
32 | };
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Bow/Bow/Parse/Parser.cs:
--------------------------------------------------------------------------------
1 | using Errors;
2 | using Tokenise;
3 |
4 | using Parse.Statements;
5 | using Parse.Expressions;
6 | using Parse.Expressions.Literals;
7 |
8 | namespace Parse;
9 |
10 | public class Parser
11 | {
12 | private int _current;
13 | private readonly List _tokens;
14 |
15 | public Parser(List tokens)
16 | {
17 | _tokens = tokens;
18 | }
19 |
20 | public List Parse()
21 | {
22 | List statements = new();
23 |
24 | while (!IsAtEnd())
25 | {
26 | statements.Add(GetStatement());
27 | }
28 |
29 | return statements;
30 | }
31 |
32 | private bool Match(string[] tokens)
33 | {
34 | if (tokens.Contains(Peek().Type))
35 | {
36 | Advance();
37 | return true;
38 | }
39 |
40 | return false;
41 | }
42 |
43 | private Token Peek()
44 | {
45 | return _tokens[_current];
46 | }
47 |
48 | private Token Advance()
49 | {
50 | if (_current < _tokens.Count)
51 | {
52 | Token token = _tokens[_current];
53 | _current++;
54 | return token;
55 | }
56 |
57 | throw new BowEOFError($"Unexpected EOF at line {_tokens[_current].Line}");
58 | }
59 |
60 | private Token Previous()
61 | {
62 | if (_current > 0)
63 | {
64 | return _tokens[_current - 1];
65 | }
66 |
67 | throw new BowRuntimeError("Cannot call Previous() on the first token");
68 | }
69 |
70 | private void Undo()
71 | {
72 | if (_current > 0)
73 | {
74 | _current--;
75 | }
76 | }
77 |
78 | private bool IsAtEnd()
79 | {
80 | return Peek().Type == TokenType.EOF;
81 | }
82 |
83 | // Statements
84 |
85 | private Statement GetStatement()
86 | {
87 | if (Match(new[] { TokenType.Identifier }))
88 | {
89 | string name = Previous().Literal;
90 |
91 | if (Match(new[] { TokenType.OpenDeclare }))
92 | {
93 | return DeclareStatement(name, Previous().Line);
94 | }
95 |
96 | if (Match(new[] { TokenType.Assign }))
97 | {
98 | return AssignStatement(name, Previous().Line);
99 | }
100 |
101 | return LiteralStatement(Previous().Line);
102 | }
103 |
104 | if (Match(new[] { TokenType.If }))
105 | {
106 | return IfStatement(Previous().Line);
107 | }
108 |
109 | if (Match(new[] { TokenType.Fun }))
110 | {
111 | return FunctionStatement(Previous().Line);
112 | }
113 |
114 | if (Match(new[] { TokenType.ReturnArrow }))
115 | {
116 | return ReturnStatement();
117 | }
118 |
119 | if (Match(new[] { TokenType.Break }))
120 | {
121 | return new Break(Previous().Line);
122 | }
123 |
124 | if (Match(new[] { TokenType.Switch }))
125 | {
126 | return SwitchStatement();
127 | }
128 |
129 | if (Match(new[] { TokenType.DecLiteral, TokenType.BooLiteral, TokenType.StrLiteral, TokenType.LeftBracket }))
130 | {
131 | return LiteralStatement(Previous().Line);
132 | }
133 |
134 | Advance();
135 | throw new BowSyntaxError($"Unexpected token '{Previous().Lexeme}' on line {Previous().Line}");
136 | }
137 |
138 | private List GetStatementBlock(string[] terminators, int line)
139 | {
140 | List statementList = new();
141 |
142 | while (!IsAtEnd() && !Match(terminators))
143 | {
144 | statementList.Add(GetStatement());
145 | }
146 |
147 | if (!terminators.Contains(Previous().Type))
148 | {
149 | throw new BowEOFError($"Unexpected EOF while looking for '{string.Join(", ", terminators)}'");
150 | }
151 |
152 | if (statementList.Count == 0)
153 | {
154 | throw new BowSyntaxError($"Empty statement block on line {line}");
155 | }
156 |
157 | return statementList;
158 | }
159 |
160 | private List GetCaseStatementBlock(int line)
161 | {
162 | List statementList = new();
163 |
164 | while (!IsAtEnd() && !EndOfCaseBlock())
165 | {
166 | statementList.Add(GetStatement());
167 | }
168 |
169 | string[] terminators =
170 | {
171 | TokenType.CloseBlock, TokenType.Identifier, TokenType.BooLiteral, TokenType.StrLiteral,
172 | TokenType.DecLiteral, TokenType.Other
173 | };
174 |
175 | if (!terminators.Contains(Peek().Type))
176 | {
177 | throw new BowEOFError($"Unexpected EOF while looking for end of switch branch on line {line}");
178 | }
179 |
180 | if (statementList.Count == 0)
181 | {
182 | throw new BowSyntaxError($"Empty statement block on line {line}");
183 | }
184 |
185 | return statementList;
186 | }
187 |
188 | private bool EndOfCaseBlock()
189 | {
190 | if (Match(new[] { TokenType.CloseBlock }))
191 | {
192 | Undo();
193 | return true;
194 | }
195 |
196 | if (Match(new[]
197 | {
198 | TokenType.Identifier, TokenType.BooLiteral, TokenType.StrLiteral, TokenType.DecLiteral, TokenType.Other
199 | }))
200 | {
201 | if (Match(new[] { TokenType.CaseBranch }))
202 | {
203 | Undo();
204 | Undo();
205 | return true;
206 | }
207 |
208 | Undo();
209 | return false;
210 | }
211 |
212 | return false;
213 | }
214 |
215 | private Statement DeclareStatement(string name, int line)
216 | {
217 | var (type, isConstant) = DeclareType(line);
218 |
219 | if (!Match(new[] { TokenType.CloseDeclare }))
220 | {
221 | throw new BowSyntaxError($"Missing end of declaration arrow on line {line}");
222 | }
223 |
224 | Expression valueExpression = GetExpression(Previous().Line);
225 |
226 | return new Declaration(name, valueExpression, type, isConstant, line);
227 | }
228 |
229 | private (string, bool) DeclareType(int line)
230 | {
231 | string type;
232 | bool isConstant;
233 |
234 | if (Match(new[] { TokenType.Var }))
235 | {
236 | isConstant = false;
237 | }
238 | else if (Match(new[] { TokenType.Con }))
239 | {
240 | isConstant = true;
241 | }
242 | else
243 | {
244 | throw new BowSyntaxError($"Declaration arrow missing 'var' or 'con' on line {line}");
245 | }
246 |
247 | if (
248 | Match(new[] { TokenType.Str, TokenType.Dec, TokenType.Boo }))
249 | {
250 | type = Previous().Type + "LITERAL";
251 | }
252 | else
253 | {
254 | throw new BowSyntaxError($"Declaration arrow invalid type on line {line}");
255 | }
256 |
257 | return (type, isConstant);
258 | }
259 |
260 | private Statement AssignStatement(string name, int line)
261 | {
262 | Expression valueExpression = GetExpression(Previous().Line);
263 |
264 | return new Assignment(name, valueExpression, line);
265 | }
266 |
267 | private Statement IfStatement(int line)
268 | {
269 | Expression ifCondition = GetExpression(Previous().Line);
270 |
271 | if (!Match(new[] { TokenType.OpenBlock }))
272 | {
273 | throw new BowSyntaxError($"Missing '==>' on line {Peek().Line}");
274 | }
275 |
276 | List ifStatements = GetStatementBlock(new[] { TokenType.CloseBlock }, line);
277 |
278 | List>> altIfs = AltIfs(line);
279 |
280 | List altStatements = Alt(line);
281 |
282 | return new If(ifCondition, ifStatements, altIfs, altStatements, line);
283 | }
284 |
285 | private List>> AltIfs(int line)
286 | {
287 | List>> altIfs = new();
288 |
289 | while (Match(new[] { TokenType.AltIf }))
290 | {
291 | Expression altCondition = GetExpression(Previous().Line);
292 |
293 | if (!Match(new[] { TokenType.OpenBlock }))
294 | {
295 | throw new BowSyntaxError($"Missing '==>' on line {Peek().Line}");
296 | }
297 |
298 | List altIfStatements = GetStatementBlock(new[] { TokenType.CloseBlock }, line);
299 |
300 | altIfs.Add(Tuple.Create(altCondition, altIfStatements));
301 | }
302 |
303 | return altIfs;
304 | }
305 |
306 | private List Alt(int line)
307 | {
308 | List altStatements = new();
309 |
310 | if (Match(new[] { TokenType.Alt }))
311 | {
312 | if (!Match(new[] { TokenType.OpenBlock }))
313 | {
314 | throw new BowSyntaxError($"Missing '==>' on line {Peek().Line}");
315 | }
316 |
317 | altStatements = GetStatementBlock(new[] { TokenType.CloseBlock }, line);
318 | }
319 |
320 | return altStatements;
321 | }
322 |
323 | private Statement FunctionStatement(int line)
324 | {
325 | if (!Match(new [] { TokenType.Identifier }))
326 | {
327 | throw new BowSyntaxError($"Missing function name on line {line}");
328 | }
329 |
330 | string name = Previous().Literal;
331 |
332 | List>> parameters = FunParameters(line);
333 |
334 | List returnTypes = new();
335 |
336 | if (!Match(new[] { TokenType.OpenBlock }))
337 | {
338 | if (Match(new[] { TokenType.Equal }))
339 | {
340 | returnTypes = GetTypes(Previous().Line);
341 |
342 | if (!Match(new[] { TokenType.FunTypeOpenBlock }))
343 | {
344 | throw new BowSyntaxError($"Missing end of function type return arrow on line {Previous().Line}");
345 | }
346 | }
347 | }
348 |
349 | List statements = GetStatementBlock(new[] { TokenType.CloseBlock }, line);
350 |
351 | return new Function(name, parameters, returnTypes, statements, line);
352 | }
353 |
354 | private List>> FunParameters(int line)
355 | {
356 | List>> parameters = new();
357 |
358 | if (!Match(new[] { TokenType.LeftBracket })) return parameters;
359 |
360 | if (!Match(new[] { TokenType.RightBracket }))
361 | {
362 | if (IsAtEnd())
363 | {
364 | throw new BowEOFError($"Unexpected EOF when looking for parameters on line {line}");
365 | }
366 |
367 | parameters.Add(GetParameter(line));
368 | }
369 |
370 | while (Match(new[] { TokenType.Comma }))
371 | {
372 | if (IsAtEnd())
373 | {
374 | throw new BowEOFError($"Unexpected EOF when looking for parameters on line {line}");
375 | }
376 |
377 | parameters.Add(GetParameter(line));
378 | }
379 |
380 | if (!Match(new[] { TokenType.RightBracket }))
381 | {
382 | throw new BowSyntaxError($"Missing ')' on line {line}");
383 | }
384 |
385 | return parameters;
386 | }
387 |
388 | private Tuple> GetParameter(int line)
389 | {
390 | if (!Match(new[] { TokenType.Identifier }))
391 | {
392 | throw new BowSyntaxError($"Missing parameter name on line {line}");
393 | }
394 |
395 | string name = Previous().Literal;
396 |
397 | if (!Match(new[] { TokenType.Minus }))
398 | {
399 | throw new BowSyntaxError($"Missing opening type '-' on line {line}");
400 | }
401 |
402 | List types = GetTypes(line);
403 |
404 | if (!Match(new[] { TokenType.Minus }))
405 | {
406 | throw new BowSyntaxError($"Missing closing type '-' on line {line}");
407 | }
408 |
409 | return Tuple.Create(name, types);
410 | }
411 |
412 | private List GetTypes(int line)
413 | {
414 | List types = new();
415 |
416 | if (!Match(new[] { TokenType.Str, TokenType.Dec, TokenType.Boo }))
417 | {
418 | throw new BowTypeError($"Unknown type on line {line}");
419 | }
420 |
421 | types.Add(Previous().Type + "LITERAL");
422 |
423 | while (Match(new[] { TokenType.Seperator }))
424 | {
425 | if (!Match(new[] { TokenType.Str, TokenType.Dec, TokenType.Boo }))
426 | {
427 | throw new BowTypeError($"Unknown type on line {line}");
428 | }
429 |
430 | types.Add(Previous().Type + "LITERAL");
431 | }
432 |
433 | return types;
434 | }
435 |
436 | private Statement ReturnStatement()
437 | {
438 | Expression returnExpression = GetExpression(Previous().Line, false);
439 |
440 | return new Return(returnExpression);
441 | }
442 |
443 | private Statement SwitchStatement()
444 | {
445 | Expression caseExpression = GetExpression(Previous().Line);
446 |
447 | if (!Match(new[] { TokenType.OpenBlock }))
448 | {
449 | throw new BowSyntaxError($"Missing '==>' on line {Peek().Line}");
450 | }
451 |
452 | List, List>> cases = GetCases(Previous().Line);
453 | List other = GetOther(Previous().Line);
454 |
455 | if (!Match(new[] { TokenType.CloseBlock }))
456 | {
457 | throw new BowEOFError($"Missing '<==' on line {Previous().Line}");
458 | }
459 |
460 | return new Switch(caseExpression, cases, other, Previous().Line);
461 | }
462 |
463 | private List, List>> GetCases(int line)
464 | {
465 | List, List>> cases = new();
466 |
467 | while (Peek().Type != TokenType.Other && Peek().Type != TokenType.CloseBlock)
468 | {
469 | List caseExpressions = new() { GetExpression(line) };
470 |
471 | while (Match(new[] { TokenType.Seperator }))
472 | {
473 | caseExpressions.Add(GetExpression(line));
474 | }
475 |
476 | if (!Match(new[] { TokenType.CaseBranch }))
477 | {
478 | throw new BowSyntaxError($"Missing case branch arrow on line {line}");
479 | }
480 |
481 | List statements = GetCaseStatementBlock(line);
482 |
483 | cases.Add(Tuple.Create(caseExpressions, statements));
484 | }
485 |
486 | return cases;
487 | }
488 |
489 | private List GetOther(int line)
490 | {
491 | if (!Match(new[] { TokenType.Other }))
492 | {
493 | return new();
494 | }
495 |
496 | if (!Match(new[] { TokenType.CaseBranch }))
497 | {
498 | throw new BowSyntaxError($"Missing case branch arrow on line {line}");
499 | }
500 |
501 | List statements = GetStatementBlock(new[] { TokenType.CloseBlock }, line);
502 | Undo(); // Get back the <== for checking
503 | return statements;
504 | }
505 |
506 | private Statement LiteralStatement(int line)
507 | {
508 | Undo();
509 |
510 | Expression valueExpression = GetExpression(line);
511 |
512 | return new LitStatement(valueExpression, line);
513 | }
514 |
515 | // Expressions
516 |
517 | private Expression GetExpression(int line, bool checkNone=true)
518 | {
519 | Expression expression = GetOr(line);
520 |
521 | if (checkNone && expression == null)
522 | {
523 | throw new BowSyntaxError($"missing expression on line {line}");
524 | }
525 |
526 | return expression;
527 | }
528 |
529 | private Expression GetOr(int line)
530 | {
531 | Expression expression = GetAnd(line);
532 |
533 | while (Match(new[] { TokenType.Or }))
534 | {
535 | Token op = Previous();
536 | Expression right = GetAnd(line);
537 | expression = new BinaryExpression(expression, op, right, line);
538 | }
539 |
540 | return expression;
541 | }
542 |
543 | private Expression GetAnd(int line)
544 | {
545 | Expression expression = GetComparison(line);
546 |
547 | while (Match(new[] { TokenType.And }))
548 | {
549 | Token op = Previous();
550 | Expression right = GetComparison(line);
551 | expression = new BinaryExpression(expression, op, right, line);
552 | }
553 |
554 | return expression;
555 | }
556 |
557 | private Expression GetComparison(int line)
558 | {
559 | Expression expression = GetTerm(line);
560 |
561 | while (Match(new[]
562 | {
563 | TokenType.Equal, TokenType.NotEqual, TokenType.LessThan, TokenType.LessThanEqual,
564 | TokenType.GreaterThan, TokenType.GreaterThanEqual
565 | }))
566 | {
567 | Token op = Previous();
568 | Expression right = GetTerm(line);
569 | expression = new BinaryExpression(expression, op, right, line);
570 | }
571 |
572 | return expression;
573 | }
574 |
575 | private Expression GetTerm(int line)
576 | {
577 | Expression expression = GetFactor(line);
578 |
579 | while (Match(new[] { TokenType.Plus, TokenType.Minus }))
580 | {
581 | Token op = Previous();
582 | Expression right = GetFactor(line);
583 | expression = new BinaryExpression(expression, op, right, op.Line);
584 | }
585 |
586 | return expression;
587 | }
588 |
589 | private Expression GetFactor(int line)
590 | {
591 | Expression expression = GetUnary(line);
592 |
593 | while (Match(new[] { TokenType.Star, TokenType.Slash }))
594 | {
595 | Token op = Previous();
596 | Expression right = GetUnary(line);
597 | expression = new BinaryExpression(expression, op, right, op.Line);
598 | }
599 |
600 | return expression;
601 | }
602 |
603 | private Expression GetUnary(int line)
604 | {
605 | if (Match(new[] { TokenType.Minus }))
606 | {
607 | Token op = Previous();
608 | Expression right = GetUnary(line);
609 | return new UnaryExpression(op, right, op.Line);
610 | }
611 |
612 | return Primary(line);
613 | }
614 |
615 | private Expression Primary(int line)
616 | {
617 | if (IsAtEnd())
618 | {
619 | throw new BowEOFError($"Unexpected EOF on line {Peek().Line}");
620 | }
621 |
622 | if (Match(new[] { TokenType.BooLiteral }))
623 | {
624 | return new LiteralExpression(new BooLiteral(Previous().Literal), line);
625 | }
626 |
627 | if (Match(new[] { TokenType.DecLiteral }))
628 | {
629 | return new LiteralExpression(new DecLiteral(Previous().Literal), line);
630 | }
631 |
632 | if (Match(new[] { TokenType.StrLiteral }))
633 | {
634 | return new LiteralExpression(new StrLiteral(Previous().Literal), line);
635 | }
636 |
637 | if (Match(new[] { TokenType.Identifier }))
638 | {
639 | string name = Previous().Literal;
640 |
641 | if (Match(new[] { TokenType.LeftBracket }))
642 | {
643 | List parameters = new();
644 |
645 | if (Peek().Type != TokenType.RightBracket)
646 | {
647 | parameters.Add(GetExpression(line));
648 |
649 | while (Match(new[] { TokenType.Comma }))
650 | {
651 | if (IsAtEnd())
652 | {
653 | throw new BowEOFError($"Unexpected EOF when looking for parameters on line {line}");
654 | }
655 |
656 | parameters.Add(GetExpression(line));
657 | }
658 | }
659 |
660 | if (!Match(new[] { TokenType.RightBracket }))
661 | {
662 | throw new BowSyntaxError($"Missing ')' on line {line}");
663 | }
664 |
665 | return new FunctionExpression(name, parameters, Previous().Line);
666 | }
667 |
668 | return new VariableExpression(name, Previous().Line);
669 | }
670 |
671 | if (Match(new[] { TokenType.LeftBracket }))
672 | {
673 | Expression expression = GetExpression(line);
674 |
675 | if (!Match(new[] { TokenType.RightBracket }))
676 | {
677 | throw new BowEOFError($"Missing ')' on line {Peek().Line}");
678 | }
679 |
680 | return expression;
681 | }
682 |
683 | throw new BowSyntaxError($"Unexpected token '{Previous().Lexeme}' on line {Previous().Line}");
684 | }
685 | }
686 |
--------------------------------------------------------------------------------
/Bow/Bow/Parse/Statements/Assignment.cs:
--------------------------------------------------------------------------------
1 | using Errors;
2 | using Tokenise;
3 | using Parse.Environment;
4 | using Parse.Expressions;
5 | using Parse.Expressions.Literals;
6 |
7 | namespace Parse.Statements;
8 |
9 | public class Assignment : Statement
10 | {
11 | private readonly string _name;
12 | private readonly Expression _valueExpression;
13 | private readonly int _line;
14 |
15 | public Assignment(string name, Expression valueExpression, int line)
16 | {
17 | _name = name;
18 | _valueExpression = valueExpression;
19 | _line = line;
20 | }
21 |
22 | public override void Interpret()
23 | {
24 | Literal value = _valueExpression.Evaluate();
25 |
26 | if (!Env.IsVariableDefined(_name))
27 | {
28 | throw new BowSyntaxError($"Unknown variable '{_name}' on line {_line}");
29 | }
30 |
31 | VariableSymbol symbol = Env.GetVariable(_name);
32 |
33 | if (symbol.IsConstant)
34 | {
35 | throw new BowSyntaxError($"Cannot assign to constant '{_name}' on line {_line}");
36 | }
37 |
38 | Literal oldValue = symbol.Literal;
39 |
40 | if (oldValue.Type != value.Type)
41 | {
42 | throw new BowTypeError(
43 | $"Can't assign {value.Type} to variable of type {oldValue.Type[..3]} on line {_line}");
44 | }
45 |
46 | Literal newValue = oldValue.Type switch
47 | {
48 | TokenType.BooLiteral => new BooLiteral(value.Value),
49 | TokenType.DecLiteral => new DecLiteral(value.Value),
50 | TokenType.StrLiteral => new StrLiteral(value.Value),
51 | _ => throw new BowRuntimeError($"Current symbol type is incorrect on line {_line}")
52 | };
53 |
54 | symbol.SetValue(newValue);
55 | }
56 |
57 | public override string Interpret(bool lastInShell)
58 | {
59 | Interpret();
60 |
61 | return lastInShell ? Env.GetVariable(_name).Literal.DisplayValue : "";
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/Bow/Bow/Parse/Statements/Break.cs:
--------------------------------------------------------------------------------
1 | using Errors;
2 |
3 | namespace Parse.Statements;
4 |
5 | public class Break : Statement
6 | {
7 | private readonly int _line;
8 |
9 | public Break(int line)
10 | {
11 | _line = line;
12 | }
13 |
14 | public override void Interpret()
15 | {
16 | throw new BowBreak($"Unexpected break on line {_line}"); // Will be caught by loops and switches
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Bow/Bow/Parse/Statements/Declaration.cs:
--------------------------------------------------------------------------------
1 | using Errors;
2 | using Tokenise;
3 | using Parse.Environment;
4 | using Parse.Expressions;
5 | using Parse.Expressions.Literals;
6 |
7 | namespace Parse.Statements;
8 |
9 | public class Declaration : Statement
10 | {
11 | private readonly string _name;
12 | private readonly string _type;
13 | private readonly Expression _valueExpression;
14 | private readonly int _line;
15 | private readonly bool _isConstant;
16 |
17 | public Declaration(string name, Expression valueExpression, string type, bool isConstant, int line)
18 | {
19 | _name = name;
20 | _valueExpression = valueExpression;
21 | _type = type;
22 | _line = line;
23 | _isConstant = isConstant;
24 | }
25 |
26 | public override void Interpret()
27 | {
28 | Literal value = _valueExpression.Evaluate();
29 |
30 | if (Env.IsVariableDefinedLocally(_name))
31 | {
32 | throw new BowSyntaxError($"Can't re-declare variable '{_name}' on line {_line}");
33 | }
34 |
35 | if (_type != value.Type)
36 | {
37 | throw new BowTypeError($"Can't assign {value.Type} to variable of type {_type[..3]} on line {_line}");
38 | }
39 |
40 | VariableSymbol symbol = new VariableSymbol(_name, value, _line, _isConstant);
41 |
42 | Env.AddVariable(symbol);
43 | }
44 |
45 | public override string Interpret(bool lastInShell)
46 | {
47 | Interpret();
48 |
49 | return lastInShell ? Env.GetVariable(_name).Literal.DisplayValue : "";
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Bow/Bow/Parse/Statements/Function.cs:
--------------------------------------------------------------------------------
1 | using Errors;
2 | using Tokenise;
3 | using Parse.Environment;
4 | using Parse.Expressions;
5 | using Parse.Expressions.Literals;
6 |
7 | namespace Parse.Statements;
8 |
9 | public class Function : Statement
10 | {
11 | private readonly string _name;
12 | private readonly List>> _parameters;
13 | private readonly List _returnTypes;
14 | private readonly List _statements;
15 | private readonly int _line;
16 |
17 | public Function(string name, List>> parameters, List returnTypes,
18 | List statements, int line)
19 | {
20 | _name = name;
21 | _parameters = parameters;
22 | _returnTypes = returnTypes;
23 | _statements = statements;
24 | _line = line;
25 | }
26 |
27 | public override void Interpret()
28 | {
29 | FunctionSymbol symbol = new FunctionSymbol(_name, _parameters, _returnTypes, _statements, _line);
30 | Env.AddFunction(symbol);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Bow/Bow/Parse/Statements/If.cs:
--------------------------------------------------------------------------------
1 | using Errors;
2 | using Parse.Expressions;
3 | using Parse.Environment;
4 | using Parse.Expressions.Literals;
5 | using Tokenise;
6 |
7 | namespace Parse.Statements;
8 |
9 | public class If : Statement
10 | {
11 | private readonly Expression _ifCondition;
12 | private readonly List _ifStatements;
13 | private readonly List>> _altIfs;
14 | private readonly List _altStatements;
15 | private readonly int _line;
16 |
17 | public If(Expression ifCondition, List ifStatements, List>> altIfs,
18 | List altStatements, int line)
19 | {
20 | _ifCondition = ifCondition;
21 | _ifStatements = ifStatements;
22 | _altIfs = altIfs;
23 | _altStatements = altStatements;
24 | _line = line;
25 | }
26 |
27 | public override void Interpret()
28 | {
29 | Literal condition = _ifCondition.Evaluate();
30 |
31 | if (condition.Type != TokenType.BooLiteral)
32 | {
33 | throw new BowTypeError($"If condition must be a boolean, but was {condition.Type} on line {_line}");
34 | }
35 |
36 | // If statement
37 |
38 | if (condition.Value)
39 | {
40 | InterpretBranch(_ifStatements);
41 | return;
42 | }
43 |
44 | // Alt if statements
45 |
46 | foreach (var (altIfCondition, altIfStatements) in _altIfs)
47 | {
48 | Literal evalledAltIfCondition = altIfCondition.Evaluate();
49 |
50 | if (evalledAltIfCondition.Type != TokenType.BooLiteral)
51 | {
52 | throw new BowTypeError(
53 | $"AltIf condition must be a boolean, but was {evalledAltIfCondition.Type} on line {_line}");
54 | }
55 |
56 | if (evalledAltIfCondition.Value)
57 | {
58 | InterpretBranch(altIfStatements);
59 | return;
60 | }
61 | }
62 |
63 | // Alt statement
64 |
65 | InterpretBranch(_altStatements);
66 | }
67 |
68 | private void InterpretBranch(List statements)
69 | {
70 | Env.PushScope(new Env());
71 |
72 | foreach (Statement statement in statements)
73 | {
74 | statement.Interpret();
75 | }
76 |
77 | Env.PopScope();
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/Bow/Bow/Parse/Statements/LitStatements.cs:
--------------------------------------------------------------------------------
1 | using Tokenise;
2 | using Parse.Expressions;
3 | using Parse.Expressions.Literals;
4 |
5 | namespace Parse.Statements;
6 |
7 | public class LitStatement : Statement
8 | {
9 | private readonly Expression _valueExpression;
10 | private readonly int _line;
11 |
12 | public LitStatement(Expression valueExpression, int line)
13 | {
14 | _valueExpression = valueExpression;
15 | _line = line;
16 | }
17 |
18 | public override void Interpret()
19 | {
20 | _valueExpression.Evaluate();
21 | }
22 |
23 | public override string Interpret(bool lastInShell)
24 | {
25 | return lastInShell ? _valueExpression.Evaluate().DisplayValue : "";
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Bow/Bow/Parse/Statements/Return.cs:
--------------------------------------------------------------------------------
1 | using Errors;
2 | using Parse.Expressions;
3 | using Parse.Expressions.Literals;
4 |
5 |
6 | namespace Parse.Statements;
7 |
8 | public class Return : Statement
9 | {
10 | private readonly Expression? _expression;
11 |
12 | public Return(Expression? expression)
13 | {
14 | _expression = expression;
15 | }
16 |
17 | public override void Interpret()
18 | {
19 | Literal? literal = null;
20 | if (_expression is not null)
21 | {
22 | literal = _expression.Evaluate();
23 | }
24 |
25 | throw new BowReturn(literal);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Bow/Bow/Parse/Statements/Statement.cs:
--------------------------------------------------------------------------------
1 | namespace Parse.Statements;
2 |
3 | public class Statement
4 | {
5 | public virtual void Interpret()
6 | {
7 | throw new NotImplementedException();
8 | }
9 |
10 | public virtual string Interpret(bool lastInShell)
11 | {
12 | Interpret();
13 |
14 | return "";
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Bow/Bow/Parse/Statements/Switch.cs:
--------------------------------------------------------------------------------
1 | using Errors;
2 | using Parse.Expressions;
3 | using Parse.Environment;
4 | using Parse.Expressions.Literals;
5 |
6 | using Microsoft.CSharp.RuntimeBinder;
7 |
8 | namespace Parse.Statements;
9 |
10 | public class Switch : Statement
11 | {
12 | private readonly Expression _switchExpression;
13 | private readonly List, List>> _cases;
14 | private readonly List _other;
15 | private readonly int _line;
16 |
17 | public Switch(Expression switchExpression, List, List>> cases, List other, int line)
18 | {
19 | _switchExpression = switchExpression;
20 | _cases = cases;
21 | _other = other;
22 | _line = line;
23 | }
24 |
25 | public override void Interpret()
26 | {
27 | Literal switchExpression = _switchExpression.Evaluate();
28 |
29 | int count = 0;
30 | bool match = false;
31 | bool escaped = false;
32 | while (count < _cases.Count)
33 | {
34 | var (comparisons, statements) = _cases[count];
35 |
36 | foreach (Expression comparison in comparisons)
37 | {
38 | Literal comparisonLiteral = comparison.Evaluate();
39 | if (comparisonLiteral.Type != switchExpression.Type)
40 | {
41 | throw new BowTypeError($"Cannot compare {comparisonLiteral.Type} with {switchExpression.Type} on line {_line}");
42 | }
43 |
44 | if (match || comparisonLiteral.Value == switchExpression.Value)
45 | {
46 | try
47 | {
48 | InterpretBranch(statements);
49 | }
50 | catch (BowBreak)
51 | {
52 | escaped = true;
53 | }
54 |
55 | match = true;
56 | break;
57 | }
58 | }
59 |
60 | if (escaped) break;
61 |
62 | count++;
63 | }
64 |
65 | if (!escaped)
66 | {
67 | try
68 | {
69 | InterpretBranch(_other);
70 | }
71 | catch (BowBreak) { }
72 | }
73 | }
74 |
75 | private void InterpretBranch(List statements)
76 | {
77 | Env.PushScope(new Env());
78 |
79 | foreach (Statement statement in statements)
80 | {
81 | statement.Interpret();
82 | }
83 |
84 | Env.PopScope();
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/Bow/Bow/Tokenise/Keywords.cs:
--------------------------------------------------------------------------------
1 | namespace Tokenise;
2 |
3 | public struct Keywords
4 | {
5 | private static readonly Dictionary Words = new()
6 | {
7 | { "var", TokenType.Var },
8 | { "con", TokenType.Con },
9 | { "str", TokenType.Str },
10 | { "dec", TokenType.Dec },
11 | { "boo", TokenType.Boo },
12 | { "true", TokenType.BooLiteral },
13 | { "false", TokenType.BooLiteral },
14 | { "if", TokenType.If },
15 | { "alt", TokenType.Alt },
16 | { "altif", TokenType.AltIf },
17 | { "switch", TokenType.Switch },
18 | { "other", TokenType.Other },
19 | { "break", TokenType.Break },
20 | { "fun", TokenType.Fun }
21 | };
22 |
23 | public static bool Contains(string key)
24 | {
25 | return Words.ContainsKey(key);
26 | }
27 |
28 | public static string GetTokenType(string key)
29 | {
30 | return Words[key];
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Bow/Bow/Tokenise/Lexer.cs:
--------------------------------------------------------------------------------
1 | using Errors;
2 |
3 | namespace Tokenise;
4 |
5 | public class Lexer
6 | {
7 | private int _start;
8 | private int _current;
9 | private int _line = 1;
10 | private readonly string _code;
11 | private readonly List _tokens = new();
12 |
13 | public Lexer(string code)
14 | {
15 | _code = code;
16 | }
17 |
18 | public List ScanTokens()
19 | {
20 | while (!IsAtEnd())
21 | {
22 | _start = _current;
23 | ScanToken();
24 | }
25 |
26 | _tokens.Add(new Token(TokenType.EOF, "", "\0", _line));
27 |
28 | return _tokens;
29 | }
30 |
31 | private void ScanToken()
32 | {
33 | char C = Advance();
34 |
35 | switch (C)
36 | {
37 | case '(':
38 | AddToken(TokenType.LeftBracket);
39 | break;
40 | case ')':
41 | AddToken(TokenType.RightBracket);
42 | break;
43 | case ',':
44 | AddToken(TokenType.Comma);
45 | break;
46 | case '+':
47 | AddToken(TokenType.Plus);
48 | break;
49 | case '-':
50 | Minus();
51 | break;
52 | case '*':
53 | AddToken(TokenType.Star);
54 | break;
55 | case '/':
56 | AddToken(TokenType.Slash);
57 | break;
58 | case '.':
59 | AddToken(TokenType.Dot);
60 | break;
61 | case '\'': case '"':
62 | Str();
63 | break;
64 | case '>':
65 | GreaterThan();
66 | break;
67 | case '<':
68 | LessThan();
69 | break;
70 | case '=':
71 | Equals();
72 | break;
73 | case '!':
74 | Bang();
75 | break;
76 | case '&':
77 | And();
78 | break;
79 | case '|':
80 | Or();
81 | break;
82 | case '?':
83 | Question();
84 | break;
85 | case ' ': case '\r': case '\t':
86 | break;
87 | case '\n':
88 | _line++;
89 | break;
90 | default:
91 | if (Char.IsDigit(C))
92 | {
93 | Dec();
94 | }
95 | else if (Char.IsLetter(C))
96 | {
97 | Identifier();
98 | }
99 | else
100 | {
101 | throw new BowSyntaxError($"Unrecognised character {C} on line {_line}");
102 | }
103 | break;
104 | }
105 | }
106 |
107 | private void AddToken(string type, string literal="")
108 | {
109 | _tokens.Add(new Token(type, _code[_start.._current], literal, _line));
110 | }
111 |
112 | private char Advance()
113 | {
114 | char C = _code[_current];
115 | _current++;
116 |
117 | return C;
118 | }
119 |
120 | private bool IsAtEnd()
121 | {
122 | return _current >= _code.Length;
123 | }
124 |
125 | private char Peek()
126 | {
127 | return IsAtEnd() ? '\0' : _code[_current];
128 | }
129 |
130 | private char PeekNext()
131 | {
132 | return _current + 1 > _code.Length ? '\0' : _code[_current + 1];
133 | }
134 |
135 | private void Minus()
136 | {
137 | if (Peek() == '<')
138 | {
139 | Advance();
140 | AddToken(TokenType.CloseDeclare);
141 | }
142 | else
143 | {
144 | AddToken(TokenType.Minus);
145 | }
146 | }
147 |
148 | private void GreaterThan()
149 | {
150 | if (Peek() == '=')
151 | {
152 | Advance();
153 | AddToken(TokenType.GreaterThanEqual);
154 | }
155 | else
156 | {
157 | AddToken(TokenType.GreaterThan);
158 | }
159 | }
160 |
161 | private void LessThan()
162 | {
163 | if (Peek() == '-')
164 | {
165 | Advance();
166 | LeftSingleArrow();
167 | }
168 | else if (Peek() == '=')
169 | {
170 | Advance();
171 | LessThanEqual();
172 | }
173 | else
174 | {
175 | AddToken(TokenType.LessThan);
176 | }
177 | }
178 |
179 | private void LeftSingleArrow()
180 | {
181 | if (Peek() == '<')
182 | {
183 | Advance();
184 | AddToken(TokenType.Assign);
185 | }
186 | else if (Peek() == '-')
187 | {
188 | Advance();
189 | AddToken(TokenType.ReturnArrow);
190 | }
191 | else
192 | {
193 | AddToken(TokenType.OpenDeclare);
194 | }
195 | }
196 |
197 | private void LessThanEqual()
198 | {
199 | if (Peek() == '=')
200 | {
201 | Advance();
202 | AddToken(TokenType.CloseBlock);
203 | }
204 | else
205 | {
206 | AddToken(TokenType.LessThanEqual);
207 | }
208 | }
209 |
210 | private void Equals()
211 | {
212 | if (Peek() == '=')
213 | {
214 | Advance();
215 | RightDoubleArrow();
216 | }
217 | else if (Peek() == '>')
218 | {
219 | Advance();
220 | AddToken(TokenType.FunTypeOpenBlock);
221 | }
222 | else
223 | {
224 | AddToken(TokenType.Equal);
225 | }
226 | }
227 |
228 | private void RightDoubleArrow()
229 | {
230 | if (Peek() != '>')
231 | {
232 | throw new BowSyntaxError($"Malformed open block arrow on line {_line}");
233 | }
234 |
235 | Advance();
236 | AddToken(TokenType.OpenBlock);
237 | }
238 |
239 | private void Bang()
240 | {
241 | if (Peek() == '=')
242 | {
243 | Advance();
244 | AddToken(TokenType.NotEqual);
245 | }
246 | else
247 | {
248 | AddToken(TokenType.Not);
249 | }
250 | }
251 |
252 | private void And()
253 | {
254 | if (Peek() != '&')
255 | {
256 | throw new BowSyntaxError($"Expected '&' on line {_line}");
257 | }
258 |
259 | Advance();
260 | AddToken(TokenType.And);
261 | }
262 |
263 | private void Or()
264 | {
265 | if (Peek() != '|')
266 | {
267 | AddToken(TokenType.Seperator);
268 | }
269 | else
270 | {
271 | Advance();
272 | AddToken(TokenType.Or);
273 | }
274 | }
275 |
276 | private void Question()
277 | {
278 | if (Peek() != '-')
279 | {
280 | throw new BowSyntaxError($"'Malformed case branch arrow on line {_line}");
281 | }
282 |
283 | Advance();
284 | CaseBranch();
285 | }
286 |
287 | private void CaseBranch()
288 | {
289 | if (Peek() != '>')
290 | {
291 | throw new BowSyntaxError($"'Malformed case branch arrow on line {_line}");
292 | }
293 |
294 | Advance();
295 | AddToken(TokenType.CaseBranch);
296 | }
297 |
298 | private void Str()
299 | {
300 | char type = _code[_current - 1];
301 |
302 | while (!IsAtEnd() && Peek() != type)
303 | {
304 | if (Peek() == '\n')
305 | {
306 | _line++;
307 | }
308 |
309 | Advance();
310 | }
311 |
312 | if (IsAtEnd())
313 | {
314 | throw new BowEOFError($"unterminated string on line {_line}");
315 | }
316 |
317 | Advance();
318 |
319 | string value = _code[(_start + 1)..(_current - 1)];
320 | AddToken(TokenType.StrLiteral, value);
321 | }
322 |
323 | private void Dec()
324 | {
325 | while (Char.IsDigit(Peek()))
326 | {
327 | Advance();
328 | }
329 |
330 | if (Peek() == '.' && Char.IsDigit(PeekNext()))
331 | {
332 | Advance();
333 |
334 | while (Char.IsDigit(Peek()))
335 | {
336 | Advance();
337 | }
338 | }
339 |
340 | AddToken(TokenType.DecLiteral, _code[_start.._current]);
341 | }
342 |
343 | private void Identifier()
344 | {
345 | while (Char.IsLetterOrDigit(Peek()) || Peek() == '_')
346 | {
347 | Advance();
348 | }
349 |
350 | string identifier = _code[_start.._current];
351 |
352 | if (Keywords.Contains(identifier))
353 | {
354 | AddToken(Keywords.GetTokenType(identifier), identifier);
355 | }
356 | else
357 | {
358 | AddToken(TokenType.Identifier, identifier);
359 | }
360 | }
361 | }
362 |
--------------------------------------------------------------------------------
/Bow/Bow/Tokenise/Token.cs:
--------------------------------------------------------------------------------
1 | namespace Tokenise;
2 |
3 | public class Token
4 | {
5 | public string Type { get; }
6 | public string Lexeme { get; }
7 | public string Literal { get; }
8 | public int Line { get; }
9 |
10 | public Token(string type, string lexeme, string literal, int line)
11 | {
12 | Type = type;
13 | Lexeme = lexeme;
14 | Literal = literal;
15 | Line = line;
16 | }
17 |
18 | public string Inspect()
19 | {
20 | return $"";
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Bow/Bow/Tokenise/TokenType.cs:
--------------------------------------------------------------------------------
1 | namespace Tokenise;
2 |
3 | public struct TokenType
4 | {
5 | public const string
6 | LeftBracket = "LEFT_BRACKET",
7 | RightBracket = "RIGHT_BRACKET",
8 |
9 | Comma = "COMMA",
10 | Seperator = "SEPERATOR",
11 |
12 | Plus = "PLUS",
13 | Minus = "MINUS",
14 | Star = "STAR",
15 | Slash = "SLASH",
16 | Dot = "DOT",
17 |
18 | Equal = "EQUAL",
19 | NotEqual = "NOT_EQUAL",
20 | LessThan = "LESS_THAN",
21 | LessThanEqual = "LESS_THAN_EQUAL",
22 | GreaterThan = "GREATER_THAN",
23 | GreaterThanEqual = "GREATER_THAN_EQUAL",
24 |
25 | Not = "NOT",
26 | And = "AND",
27 | Or = "OR",
28 |
29 | StrLiteral = "STRLITERAL",
30 | DecLiteral = "DECLITERAL",
31 | BooLiteral = "BOOLITERAL",
32 |
33 | NullReturn = "NULL_RETURN",
34 |
35 | Str = "STR",
36 | Dec = "DEC",
37 | Boo = "BOO",
38 |
39 | Var = "VAR",
40 | Con = "CON",
41 |
42 | Assign = "ASSIGN",
43 | OpenDeclare = "OPEN_DECLARE",
44 | CloseDeclare = "CLOSE_DECLARE",
45 | Identifier = "IDENTIFIER",
46 |
47 | If = "IF",
48 | Alt = "ALT",
49 | AltIf = "ALT_IF",
50 |
51 | Switch = "SWITCH",
52 | Other = "OTHER",
53 | Break = "BREAK",
54 | CaseBranch = "CASE_BRANCH",
55 |
56 | Fun = "FUN",
57 |
58 | OpenBlock = "OPEN_BLOCK",
59 | CloseBlock = "CLOSE_BLOCK",
60 | FunTypeOpenBlock = "Fun_Type_Open_Block",
61 |
62 | ReturnArrow = "RETURN_ARROW",
63 |
64 | EOF = "EOF";
65 | }
66 |
--------------------------------------------------------------------------------
/Bow/Program.cs:
--------------------------------------------------------------------------------
1 | if (args.Length > 0)
2 | {
3 | new Bow(args[0], false, args.Contains("--debug")).Run();
4 | }
5 | else
6 | {
7 | Bow.RunShell();
8 | }
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 | # Bow
3 |
4 | Bow is a statically typed interpretted language which has a lot of arrows in it.
5 |
--------------------------------------------------------------------------------