Merge 8090840d0e
into 7e958c5658
This commit is contained in:
commit
7807e8c212
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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 !!!! */
|
||||
|
|
Loading…
Reference in New Issue