WIP: dev #1

Draft
nub31 wants to merge 103 commits from dev into master
2 changed files with 63 additions and 16 deletions
Showing only changes of commit 9ccdd5f835 - Show all commits

View File

@@ -18,9 +18,10 @@ public sealed class Tokenizer(string fileName, string contents)
{ {
var tokens = new List<Token>(); var tokens = new List<Token>();
diagnostics = []; diagnostics = [];
try
{
while (true) while (true)
{
try
{ {
if (!TryPeek(out var c)) if (!TryPeek(out var c))
break; break;
@@ -31,12 +32,27 @@ public sealed class Tokenizer(string fileName, string contents)
continue; continue;
} }
tokens.Add(ParseToken()); if (c == '/' && Peek(1) == '/')
{
Consume();
Consume();
while (TryPeek(out c) && c != '\n')
{
Consume();
} }
Consume();
continue;
}
tokens.Add(ParseToken());
} }
catch (CompileException e) catch (CompileException e)
{ {
diagnostics.Add(e.Diagnostic); diagnostics.Add(e.Diagnostic);
// Skip current token if parsing failed, this prevents an infinite loop when ParseToken fails before consuming any tokens
TryConsume(out _);
}
} }
return tokens; return tokens;
@@ -57,6 +73,7 @@ public sealed class Tokenizer(string fileName, string contents)
Consume(); Consume();
var parsed = BigInteger.Zero; var parsed = BigInteger.Zero;
var seenDigit = false;
while (TryPeek(out c)) while (TryPeek(out c))
{ {
@@ -69,6 +86,7 @@ public sealed class Tokenizer(string fileName, string contents)
if (!char.IsAsciiHexDigit(c)) if (!char.IsAsciiHexDigit(c))
break; break;
seenDigit = true;
parsed <<= 4; parsed <<= 4;
Consume(); Consume();
@@ -81,6 +99,9 @@ public sealed class Tokenizer(string fileName, string contents)
}; };
} }
if (!seenDigit)
throw new CompileException(Diagnostic.Error("Expected hexadecimal digits after 0x").At(fileName, line, startColumn, column - startColumn).Build());
return new TokenIntLiteral(line, startColumn, column - startColumn, parsed); return new TokenIntLiteral(line, startColumn, column - startColumn, parsed);
} }
case '0' when Peek(1) is 'b': case '0' when Peek(1) is 'b':
@@ -89,6 +110,7 @@ public sealed class Tokenizer(string fileName, string contents)
Consume(); Consume();
var parsed = BigInteger.Zero; var parsed = BigInteger.Zero;
var seenDigit = false;
while (TryPeek(out c)) while (TryPeek(out c))
{ {
@@ -101,11 +123,16 @@ public sealed class Tokenizer(string fileName, string contents)
if (c is not '0' and not '1') if (c is not '0' and not '1')
break; break;
seenDigit = true;
parsed <<= 1; parsed <<= 1;
if (Consume() == '1') if (Consume() == '1')
parsed += BigInteger.One; parsed += BigInteger.One;
} }
if (!seenDigit)
throw new CompileException(Diagnostic.Error("Expected binary digits after 0b").At(fileName, line, startColumn, column - startColumn).Build());
return new TokenIntLiteral(line, startColumn, column - startColumn, parsed); return new TokenIntLiteral(line, startColumn, column - startColumn, parsed);
} }
default: default:
@@ -137,16 +164,26 @@ public sealed class Tokenizer(string fileName, string contents)
case '"': case '"':
{ {
Consume(); Consume();
var buf = new StringBuilder(); var buf = new StringBuilder();
while (TryPeek(out c) && c != '"') while (true)
{
if (!TryPeek(out c))
throw new CompileException(Diagnostic.Error("Unterminated string literal").At(fileName, line, column, 0).Build());
if (c == '"')
break;
if (c == '\n')
throw new CompileException(Diagnostic.Error("Unterminated string literal").At(fileName, line, column, 1).Build());
buf.Append(Consume()); buf.Append(Consume());
}
Consume(); Consume();
return new TokenStringLiteral(line, startColumn, column - startColumn, buf.ToString()); return new TokenStringLiteral(line, startColumn, column - startColumn, buf.ToString());
} }
case '{': case '{':
{ {
Consume(); Consume();
@@ -353,17 +390,20 @@ public sealed class Tokenizer(string fileName, string contents)
}; };
} }
throw new Exception($"Unexpected character '{c}'"); throw new CompileException(Diagnostic.Error($"Unexpected character '{c}'").At(fileName, line, column, 1).Build());
} }
} }
} }
private char Consume() private bool TryConsume(out char c)
{ {
if (index >= contents.Length) if (index >= contents.Length)
throw new CompileException(Diagnostic.Error("Unexpected end of file").At(fileName, line, column, 0).Build()); {
c = '\0';
return false;
}
var c = contents[index]; c = contents[index];
if (c == '\n') if (c == '\n')
{ {
@@ -377,6 +417,14 @@ public sealed class Tokenizer(string fileName, string contents)
index += 1; index += 1;
return true;
}
private char Consume()
{
if (!TryConsume(out var c))
throw new CompileException(Diagnostic.Error("Unexpected end of file").At(fileName, line, column, 0).Build());
return c; return c;
} }
@@ -498,14 +546,14 @@ public static class TokenExtensions
Symbol.OpenParen => "(", Symbol.OpenParen => "(",
Symbol.CloseParen => ")", Symbol.CloseParen => ")",
Symbol.Comma => ",", Symbol.Comma => ",",
Symbol.Period => ",", Symbol.Period => ".",
Symbol.Colon => ":", Symbol.Colon => ":",
Symbol.ColonColon => "::", Symbol.ColonColon => "::",
Symbol.Caret => "^", Symbol.Caret => "^",
Symbol.Bang => "!", Symbol.Bang => "!",
Symbol.Equal => "=", Symbol.Equal => "=",
Symbol.EqualEqual => "==", Symbol.EqualEqual => "==",
Symbol.BangEqual => "!+", Symbol.BangEqual => "!=",
Symbol.LessThan => "<", Symbol.LessThan => "<",
Symbol.LessThanLessThan => "<<", Symbol.LessThanLessThan => "<<",
Symbol.LessThanEqual => "<=", Symbol.LessThanEqual => "<=",

View File

@@ -14,7 +14,6 @@ func main(): i32 {
let i: i32 = 0 let i: i32 = 0
x = 1 + 2 * 34 x = 1 + 2 * 34
while i < 10 { while i < 10 {
i = i + 1 i = i + 1
x = i x = i