This commit is contained in:
Tristan B. Velloza Kildaire 2024-04-15 09:41:16 +00:00 committed by GitHub
commit 7807e8c212
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 310 additions and 9 deletions

View File

@ -1,14 +1,18 @@
/**
* Token definition
* Token and related types definitions
*/
module tlang.compiler.lexer.core.tokens;
import std.string : cmp;
import std.string : cmp, format;
import std.conv : to;
import tlang.compiler.reporting : Coords;
import tlang.compiler.reporting : LineInfo;
/**
* Defines a `Token` that a lexer
* would be able to produce
*
* Authors: Tristan Brice Velloza Kildaire (deavmi)
*/
public final class Token
{
@ -22,6 +26,12 @@ public final class Token
*/
private ulong line, column;
/**
* The line this token was
* lex'd from
*/
private string origin;
/**
* Constructs a new `Token` with the given
* contents and line information
@ -38,6 +48,30 @@ public final class Token
this.column = column;
}
/**
* Sets the origin string.
* This is the line in which
* this token was derived from.
*
* Params:
* line = the line
*/
public void setOrigin(string line)
{
this.origin = line;
}
/**
* Returns the origin string (if any)
* from which this token was derived
*
* Returns: the line
*/
private string getOrigin()
{
return this.origin;
}
/**
* Overrides the `==` operator to do equality
* based on the stored token's contents
@ -73,4 +107,26 @@ public final class Token
{
return token;
}
/**
* Returns the coordinates of
* this token
*
* Returns: the `Coords`
*/
public Coords getCoords()
{
return Coords(this.line, this.column);
}
/**
* Returns the line information
* of this particular token
*
* Returns: the `LineInfo`
*/
public LineInfo getLineInfo()
{
return LineInfo(getOrigin(), getCoords());
}
}

View File

@ -9,11 +9,18 @@ import tlang.compiler.lexer.core;
import core.stdc.stdlib;
import tlang.misc.exceptions : TError;
import tlang.compiler.parsing.exceptions;
import tlang.compiler.reporting : LineInfo;
import tlang.compiler.core : Compiler;
import std.string : format;
import tlang.compiler.modman;
// TODO: Technically we could make a core parser etc
/**
* Provided with a lexer this
* can parse the tokens into
* an in-memory AST structure
*
* Authors: Tristan Brice Velloza Kildaire (deavmi)
*/
public final class Parser
{
/**
@ -21,11 +28,27 @@ public final class Parser
*/
private LexerInterface lexer;
/**
/**
* The associated compiler
*/
private Compiler compiler;
/**
* Returns the `LineInfo` of
* the lexer's current token.
*
* This is useful when you want
* to associate a line with
* an AST node right before
* returning.
*
* Returns: the `LineInfo`
*/
private LineInfo getCurrentLineInfo()
{
return this.lexer.getCurrentToken().getLineInfo();
}
/**
* Crashes the program if the given token is not a symbol
* the same as the givne expected one
@ -40,8 +63,6 @@ public final class Parser
if (!isFine)
{
throw new SyntaxError(this, symbol, token);
// expect("Expected symbol of type " ~ to!(string)(symbol) ~ " but got " ~ to!(
// string)(actualType) ~ " with " ~ token.toString());
}
}
@ -290,6 +311,9 @@ public final class Parser
/* Parent the branch to the WhileLoop */
parentToContainer(whileLoop, [branch]);
/* Store line information at this point into AST node */
whileLoop.setLineInfo(getCurrentLineInfo());
WARN("parseWhile(): Leave");
return whileLoop;

View File

@ -6,6 +6,7 @@ import tlang.compiler.symbols.check;
import tlang.compiler.symbols.data;
import tlang.compiler.lexer.core.tokens : Token;
import std.conv : to;
import tlang.compiler.reporting : LineInfo, report;
public class ParserException : TError
{
@ -38,6 +39,10 @@ public final class SyntaxError : ParserException
super(parser);
msg = "Syntax error: Expected "~to!(string)(expected)~" but got "~to!(string)(provided)~", see "~providedToken.toString();
msg = report
(
"Syntax error: Expected "~to!(string)(expected)~" but got "~to!(string)(provided)~", see "~providedToken.toString(),
providedToken
);
}
}

View File

@ -0,0 +1,187 @@
/**
* Reporting types and utilities
* for error reporting
*
* Authors: Tristan Brice Velloza Kildaire (deavmi)
*/
module tlang.compiler.reporting;
import tlang.compiler.lexer.core.tokens;
import std.string : strip, format;
/**
* Represents coordinates
*
* Authors: Tristan Brice Velloza Kildaire (deavmi)
*/
public struct Coords
{
private ulong line;
private ulong column;
/**
* Constructs a new set of coordinates
*
* Params:
* line = the line
* column = the column
*/
this(ulong line, ulong column)
{
this.line = line;
this.column = column;
}
/**
* Returns the line
*
* Returns: line index
*/
public ulong getLine()
{
return this.line;
}
/**
* Returns the column
*
* Returns: column index
*/
public ulong getColumn()
{
return this.column;
}
/**
* Returns a string representation
*
* Returns: the coordinates
*/
public string toString()
{
return format("line %d, column %d", this.line, this.column);
}
}
/**
* Represents line information
* which couples the line itself
* with the coordinates as well
*
* Authors: Tristan Brice Velloza Kildaire (deavmi)
*/
public struct LineInfo
{
private string line;
private Coords location;
/**
* Constructs a new `LineInfo`
* combining the line and its
* location
*
* Params:
* line = the line itself
* location = the location
*/
this(string line, Coords location)
{
this.line = line;
this.location = location;
}
/**
* Returns the line itself
*
* Returns: the line
*/
public string getLine()
{
return this.line;
}
/**
* Returns the location
* of this line
*
* Returns: the `Coords`
*/
public Coords getLocation()
{
return this.location;
}
/**
* Returns the string represenation
* of this line info
*
* Returns: a string
*/
public string toString()
{
return format("%s at %s", getLine(), getLocation());
}
}
public string report(string message, LineInfo linfo, ulong cursor = 0)
{
// Obtain the offending line
string offendingLine = linfo.getLine();
// Obtain where the offending line occurs
Coords offendingLocation = linfo.getLocation();
import std.stdio;
import niknaks.debugging : genX;
string pointer = format("%s^", genX(cursor, " "));
/**
* <message>
*
* <originString>
* ^ (at pos)
*
* At <Coords>
*/
string fullMessage = format
(
"%s\n\n\t%s\n\t%s\n\nAt %s",
message,
offendingLine,
pointer,
offendingLocation
);
return fullMessage;
}
public string report(string message, Token offendingToken)
{
// FIXME: Double check the boundries here
ulong pointerPos = offendingToken.getCoords().getColumn() < message.length ? offendingToken.getCoords().getColumn() : 0;
assert(pointerPos < message.length);
return report(message, offendingToken.getLineInfo(), pointerPos);
}
version(unittest)
{
import tlang.misc.logging;
}
unittest
{
string line = "int i = 20";
import tlang.compiler.lexer.kinds.basic : BasicLexer;
BasicLexer lex = new BasicLexer(line);
lex.performLex();
// TODO: In future when BasicLexer is updated
// we should remove this
lex.nextToken();
Token offending = lex.getCurrentToken();
offending.setOrigin(line);
string s = report("Cannot name a variable i", offending);
INFO(s);
}

View File

@ -187,9 +187,38 @@ public final class Program : Container
}
}
public class Statement
{
import tlang.compiler.reporting : LineInfo;
public abstract class Statement
{
/**
* Line information
*/
private LineInfo linfo;
/**
* Sets the line information
* for this AST node
*
* Params:
* linfo = the `LineInfo`
*/
public final void setLineInfo(LineInfo linfo)
{
this.linfo = linfo;
}
/**
* Gets the line information
* from where this was retrieved
*
* Returns: the line info
*/
public final LineInfo getLineInfo()
{
return this.linfo;
}
public byte weight = 0;
/* !!!! BEGIN TYPE CHECK ROUTINES AND DATA !!!! */