Skip to content

Commit fcad8fc

Browse files
committed
Implement Unsigned Right Shift and bitwise operations
bitwise xor uses ^ now, use ^^ for exponents in math
1 parent 719a3ed commit fcad8fc

File tree

11 files changed

+158
-33
lines changed

11 files changed

+158
-33
lines changed

src/Lib/Internal/Instruction.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,14 @@ public enum Instruction : byte
1414
Modulo,
1515
Power,
1616

17+
BitwiseAnd,
18+
BitwiseOr,
19+
BitwiseXor,
20+
BitwiseNot,
21+
LeftShift,
22+
RightShift,
23+
UnsignedRightShift,
24+
1725
AddConstant,
1826

1927
Pop,
@@ -26,8 +34,6 @@ public enum Instruction : byte
2634
GreaterEqual,
2735
Less,
2836
LessEqual,
29-
LeftShift,
30-
RightShift,
3137

3238
Variable,
3339
Get,

src/Lib/Internal/Lexer.cs

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Runtime.CompilerServices;
1+
using System.Collections.Immutable;
2+
using System.Runtime.CompilerServices;
23
using System.Text;
34
using Starscript.Util;
45

@@ -72,19 +73,21 @@ public void Next() {
7273
case '!': CreateToken(Match('=') ? Token.BangEqual : Token.Bang); break;
7374
case '>':
7475
CreateToken(
75-
Match('=')
76-
? Token.GreaterEqual
77-
: Match('>')
78-
? Token.RightShift
76+
Match('=')
77+
? Token.GreaterEqual
78+
: Match('>')
79+
? Match('>')
80+
? Token.TripleGreater
81+
: Token.DoubleGreater
7982
: Token.Greater
8083
);
8184
break;
8285
case '<':
8386
CreateToken(
84-
Match('=')
85-
? Token.LessEqual
86-
: Match('<')
87-
? Token.LeftShift
87+
Match('=')
88+
? Token.LessEqual
89+
: Match('<')
90+
? Token.DoubleLess
8891
: Token.Less
8992
);
9093
break;
@@ -94,7 +97,12 @@ public void Next() {
9497
case '*': CreateToken(Token.Star); break;
9598
case '/': CreateToken(Token.Slash); break;
9699
case '%': CreateToken(Token.Percentage); break;
97-
case '^': CreateToken(Token.UpArrow); break;
100+
case '^': CreateToken(
101+
Match('^')
102+
? Token.DoubleUpArrow
103+
: Token.UpArrow
104+
);
105+
break;
98106

99107
case '.': CreateToken(Token.Dot); break;
100108
case ',': CreateToken(Token.Comma); break;
@@ -110,6 +118,10 @@ public void Next() {
110118
CreateToken(Token.Section, Source[(Start + 1)..Current]);
111119
break;
112120

121+
case '&': CreateToken(Token.Ampersand); break;
122+
case '|': CreateToken(Token.VBar); break;
123+
case '~': CreateToken(Token.Tilde); break;
124+
113125
default: Unexpected(); break;
114126
}
115127
}
@@ -182,17 +194,25 @@ private void Number() {
182194
CreateToken(Token.Number);
183195
}
184196

197+
public static readonly ImmutableArray<string> Keywords = [NullKeyword, TrueKeyword, FalseKeyword, AndKeyword, OrKeyword];
198+
199+
private const string NullKeyword = "null";
200+
private const string TrueKeyword = "true";
201+
private const string FalseKeyword = "false";
202+
private const string AndKeyword = "and";
203+
private const string OrKeyword = "or";
204+
185205
private void Identifier() {
186206
while (!IsAtEnd && IsAlphanumeric(Peek())) Advance();
187207

188208
CreateToken(Token.Identifier);
189209

190210
switch (Lexeme) {
191-
case "null": Token = Token.Null; break;
192-
case "true": Token = Token.True; break;
193-
case "false": Token = Token.False; break;
194-
case "and": Token = Token.And; break;
195-
case "or": Token = Token.Or; break;
211+
case NullKeyword: Token = Token.Null; break;
212+
case TrueKeyword: Token = Token.True; break;
213+
case FalseKeyword: Token = Token.False; break;
214+
case AndKeyword: Token = Token.And; break;
215+
case OrKeyword: Token = Token.Or; break;
196216
}
197217
}
198218

src/Lib/Internal/Token.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,20 @@ public enum Token : byte
1313
Less, LessEqual,
1414

1515
Plus, Minus,
16-
Star, Slash, Percentage, UpArrow,
16+
Star, Slash, Percentage, UpArrow, DoubleUpArrow,
1717
Bang,
1818

1919
Dot, Comma,
2020
QuestionMark, Colon,
2121
LeftParen, RightParen,
2222
LeftBrace, RightBrace,
23-
LeftShift, RightShift,
2423

2524
Section,
25+
Ampersand,
26+
Tilde,
27+
VBar,
28+
DoubleGreater, TripleGreater,
29+
DoubleLess,
2630

2731
Error, EOF
2832
}

src/Lib/Public/Compiler/Compiler.Visitors.cs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,16 +112,21 @@ public void Visit(Expr.Binary expr)
112112
case Token.Star: _output.Write(Multiply); break;
113113
case Token.Slash: _output.Write(Divide); break;
114114
case Token.Percentage: _output.Write(Modulo); break;
115-
case Token.UpArrow: _output.Write(Power); break;
115+
case Token.DoubleUpArrow: _output.Write(Power); break;
116116

117117
case Token.EqualEqual: _output.Write(Instruction.Equals); break;
118118
case Token.BangEqual: _output.Write(NotEquals); break;
119119
case Token.Greater: _output.Write(Greater); break;
120120
case Token.GreaterEqual: _output.Write(GreaterEqual); break;
121121
case Token.Less: _output.Write(Less); break;
122122
case Token.LessEqual: _output.Write(LessEqual); break;
123-
case Token.LeftShift: _output.Write(LeftShift); break;
124-
case Token.RightShift: _output.Write(RightShift); break;
123+
124+
case Token.Ampersand: _output.Write(BitwiseAnd); break;
125+
case Token.VBar: _output.Write(BitwiseOr); break;
126+
case Token.UpArrow: _output.Write(BitwiseXor); break;
127+
case Token.DoubleLess: _output.Write(LeftShift); break;
128+
case Token.DoubleGreater: _output.Write(RightShift); break;
129+
case Token.TripleGreater: _output.Write(UnsignedRightShift); break;
125130
}
126131

127132
#if DEBUG
@@ -140,6 +145,9 @@ public void Visit(Expr.Unary expr)
140145
case Token.Minus:
141146
_output.Write(Negate);
142147
break;
148+
case Token.Tilde:
149+
_output.Write(BitwiseNot);
150+
break;
143151
}
144152

145153
#if DEBUG

src/Lib/Public/Entities/SemanticTokenProvider.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,12 @@ public static void Provide(string source, List<SemanticToken> tokens)
2626
case Token.GreaterEqual:
2727
case Token.Less:
2828
case Token.LessEqual:
29-
case Token.LeftShift:
30-
case Token.RightShift:
29+
case Token.DoubleLess:
30+
case Token.DoubleGreater:
31+
case Token.TripleGreater:
32+
case Token.Ampersand:
33+
case Token.VBar:
34+
case Token.DoubleUpArrow:
3135
case Token.Plus:
3236
case Token.Minus:
3337
case Token.Star:

src/Lib/Public/Hypervisor/Abstraction/AbstractHypervisor.Insn.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,15 @@ public partial class AbstractHypervisor<TSelf>
2323
protected abstract void Divide();
2424
protected abstract void Modulo();
2525
protected abstract void Power();
26-
protected abstract void RightShift();
2726
protected abstract void LeftShift();
27+
protected abstract void RightShift();
28+
protected abstract void UnsignedRightShift();
29+
30+
protected abstract void BitwiseAnd();
31+
protected abstract void BitwiseOr();
32+
protected abstract void BitwiseXor();
33+
protected abstract void BitwiseNot();
34+
2835

2936
protected abstract void Section(
3037
ref StringBuilder sb,

src/Lib/Public/Hypervisor/Abstraction/AbstractHypervisor.Runner.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,14 @@ protected virtual StringSegment RunInternal(ExecutableScript script, StringBuild
5252
case Instruction.Modulo: Modulo(); break;
5353
case Instruction.Power: Power(); break;
5454
case Instruction.Negate: Negate(); break;
55+
56+
// Bit shenanigans
57+
case Instruction.BitwiseNot: BitwiseNot(); break;
58+
case Instruction.BitwiseAnd: BitwiseAnd(); break;
59+
case Instruction.BitwiseOr: BitwiseOr(); break;
60+
case Instruction.BitwiseXor: BitwiseXor(); break;
5561
case Instruction.RightShift: RightShift(); break;
62+
case Instruction.UnsignedRightShift: UnsignedRightShift(); break;
5663
case Instruction.LeftShift: LeftShift(); break;
5764

5865
// Comparison

src/Lib/Public/Hypervisor/InsnImpl/Arithmetic.cs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,56 @@ protected override void RightShift()
8686
throw Error(">> operation requires 2 numbers.");
8787
}
8888

89+
protected override void UnsignedRightShift()
90+
{
91+
var (a, b) = PopPair();
92+
93+
if (a.IsNumber && b.IsNumber)
94+
Push(Convert.ToInt32(a.GetNumber()) >>> Convert.ToInt32(double.Truncate(b.GetNumber())));
95+
else
96+
throw Error(">> operation requires 2 numbers.");
97+
}
98+
99+
protected override void BitwiseAnd()
100+
{
101+
var (a, b) = PopPair();
102+
103+
if (a.IsNumber && b.IsNumber)
104+
Push(Convert.ToInt32(Math.Floor(a.GetNumber())) & Convert.ToInt32(Math.Floor(b.GetNumber())));
105+
else
106+
throw Error("& operation requires 2 numbers.");
107+
}
108+
109+
protected override void BitwiseOr()
110+
{
111+
var (a, b) = PopPair();
112+
113+
if (a.IsNumber && b.IsNumber)
114+
Push(Convert.ToInt32(Math.Floor(a.GetNumber())) | Convert.ToInt32(Math.Floor(b.GetNumber())));
115+
else
116+
throw Error("| operation requires 2 numbers.");
117+
}
118+
119+
protected override void BitwiseXor()
120+
{
121+
var (a, b) = PopPair();
122+
123+
if (a.IsNumber && b.IsNumber)
124+
Push(Convert.ToInt32(Math.Floor(a.GetNumber())) ^ Convert.ToInt32(Math.Floor(b.GetNumber())));
125+
else
126+
throw Error("^ operation requires 2 numbers.");
127+
}
128+
129+
protected override void BitwiseNot()
130+
{
131+
var a = Pop();
132+
133+
if (a.IsNumber)
134+
Push(~Convert.ToInt32(Math.Floor(a.GetNumber())));
135+
else
136+
throw Error("~ unary operation requires a number.");
137+
}
138+
89139
protected override void LeftShift()
90140
{
91141
var (a, b) = PopPair();

src/Lib/Public/Parser/Parser.Tokenization.cs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,11 +162,32 @@ private Expr Term()
162162
}
163163

164164
private Expr Factor()
165+
{
166+
int start = _previous.Start;
167+
Expr expr = Bitwise();
168+
169+
while (MatchAnyNext(Token.Star, Token.Slash, Token.Percentage, Token.DoubleUpArrow))
170+
{
171+
Token op = _previous.Token;
172+
Expr right = Bitwise();
173+
174+
#if DEBUG
175+
DebugLog(
176+
$"Expr {nameof(Expr.Binary)} created: Start {start}, End {_previous.End}, LeftType {expr.ExprName} Operator {Enum.GetName(op)}, RightType {right.ExprName}");
177+
#endif
178+
179+
expr = new Expr.Binary(start, _previous.End, expr, op, right);
180+
}
181+
182+
return expr;
183+
}
184+
185+
private Expr Bitwise()
165186
{
166187
int start = _previous.Start;
167188
Expr expr = Unary();
168189

169-
while (MatchAnyNext(Token.Star, Token.Slash, Token.Percentage, Token.UpArrow, Token.LeftShift, Token.RightShift))
190+
while (MatchAnyNext(Token.Ampersand, Token.VBar, Token.UpArrow, Token.DoubleLess, Token.DoubleGreater, Token.TripleGreater))
170191
{
171192
Token op = _previous.Token;
172193
Expr right = Unary();
@@ -184,7 +205,7 @@ private Expr Factor()
184205

185206
private Expr Unary()
186207
{
187-
if (MatchAnyNext(Token.Bang, Token.Minus))
208+
if (MatchAnyNext(Token.Bang, Token.Minus, Token.Tilde))
188209
{
189210
int start = _previous.Start;
190211

src/Lib/Public/Values/ValueMap.cs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ namespace Starscript;
66

77
public class ValueMap : IReadOnlyDictionary<string, Func<Value>>
88
{
9-
public static readonly ImmutableArray<string> Keywords = ["null", "true", "false", "and", "or"];
10-
119
private readonly Dictionary<string, Func<Value>> _entries;
1210

1311
/// <summary>
@@ -25,12 +23,12 @@ public ValueMap(Dictionary<string, Func<Value>>? entries = null)
2523
/// </summary>
2624
public ValueMap SetRaw(string name, Func<Value> value)
2725
{
28-
if (Keywords.Contains(name))
26+
if (Internal.Lexer.Keywords.Contains(name))
2927
throw new StarscriptException($"The name of a variable cannot be a keyword. " +
3028
$"Disallowed words: [{
31-
string.Join(", ", Keywords.Select(x => $"\"{x}\""))
29+
string.Join(", ", Internal.Lexer.Keywords.Select(x => $"\"{x}\""))
3230
}]");
33-
31+
3432
_entries[name] = value;
3533
return this;
3634
}

0 commit comments

Comments
 (0)