This commit is contained in:
Tristan B. Velloza Kildaire 2024-05-08 20:04:38 +00:00 committed by GitHub
commit 3a43c3d4ae
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 409 additions and 5 deletions

View File

@ -542,6 +542,23 @@ jobs:
exit 1
fi
- name: Alias expression test that returns 3
run: |
set -e
./tlang compile source/tlang/testing/simple_aliases.t
set +e
./tlang.out
if [ $? = 3 ]
then
set -e
exit 0
else
set -e
exit 1
fi
##################################

View File

@ -495,7 +495,8 @@ unittest
"source/tlang/testing/universal_coerce/simple_coerce_literal_good.t",
"source/tlang/testing/universal_coerce/simple_coerce_literal_good_stdalo.t",
"source/tlang/testing/simple_function_return_type_check_good.t",
"source/tlang/testing/modules/a.t"
"source/tlang/testing/modules/a.t",
"source/tlang/testing/simple_aliases.t"
];
foreach(string testFileGood; testFilesGood)

View File

@ -12,6 +12,7 @@ import tlang.compiler.parsing.exceptions;
import tlang.compiler.core : Compiler;
import std.string : format;
import tlang.compiler.modman;
import tlang.compiler.symbols.aliases;
// TODO: Technically we could make a core parser etc
public final class Parser
@ -2324,6 +2325,43 @@ public final class Parser
}
}
/**
* Parses an alias declaration
*
* Returns: an `AliasDeclaration`
*/
private AliasDeclaration parseAliasDeclaration()
{
WARN("parseAliasDeclaration(): Enter");
AliasDeclaration aliasDecl;
/* Pop off the `alias` */
lexer.nextToken();
/* Consume the alias's name */
Token tok = lexer.getCurrentToken();
expect(SymbolType.IDENT_TYPE, tok);
string aliasName = tok.getToken();
/* Next token, expect `=` */
lexer.nextToken();
expect(SymbolType.ASSIGN, lexer.getCurrentToken());
/* Now consume an expression */
lexer.nextToken();
Expression aliasExpr = parseExpression();
expect(SymbolType.SEMICOLON, lexer.getCurrentToken());
lexer.nextToken();
/* Construct an alias with the name and expression */
aliasDecl = new AliasDeclaration(aliasName, aliasExpr);
WARN("parseAliasDeclaration(): Leave");
return aliasDecl;
}
// TODO: We need to add `parseComment()`
// support here (see issue #84)
// TODO: This ic currently dead code and ought to be used/implemented
@ -2405,6 +2443,11 @@ public final class Parser
ERROR("COMMENTS NOT YET PROPERLY SUPOORTED");
parseComment();
}
/* If it is an alias declaration */
else if(symbol == SymbolType.ALIAS)
{
statement = parseAliasDeclaration();
}
/* Error out */
else
{
@ -2794,6 +2837,11 @@ public final class Parser
ERROR("COMMENTS NOT YET PROPERLY SUPOORTED");
parseComment();
}
/* If it is an alias declaration */
else if(symbol == SymbolType.ALIAS)
{
modulle.addStatement(parseAliasDeclaration());
}
else
{
expect("parse(): Unknown '" ~ tok.getToken() ~ "'");

View File

@ -0,0 +1,35 @@
module tlang.compiler.symbols.aliases;
import tlang.compiler.symbols.data : Statement;
import tlang.compiler.symbols.expressions : Expression;
import std.string : format;
/**
* A declaration of an alias expression
*/
public final class AliasDeclaration : Statement
{
private string aliasName;
private Expression aliasExpr;
this(string aliasName, Expression aliasExpr)
{
this.aliasName = aliasName;
this.aliasExpr = aliasExpr;
}
public string getName()
{
return this.aliasName;
}
public Expression getExpr()
{
return this.aliasExpr;
}
public override string toString()
{
return format("Alias [name: %s]", this.aliasName);
}
}

View File

@ -305,6 +305,11 @@ public enum SymbolType
*/
SINGLE_LINE_COMMENT,
/**
* `alias` keyword
*/
ALIAS,
/**
* Unknown symbol
*/
@ -715,6 +720,11 @@ public SymbolType getSymbolType(Token tokenIn)
{
return SymbolType.IMPORT;
}
/* `alias` keyword */
else if(cmp("alias", token) == 0)
{
return SymbolType.ALIAS;
}
/* An identifier/type (of some sorts) - further inspection in parser is needed */
else if(isPathIdentifier(token) || isIdentifier(token))
{
@ -841,6 +851,7 @@ public SymbolType getSymbolType(Token tokenIn)
return SymbolType.SMALLER_THAN_OR_EQUALS;
}
return SymbolType.UNKNOWN;
}

View File

@ -73,8 +73,42 @@ public final class Program : Container
public bool replace(Statement thiz, Statement that)
{
// TODO: Implement me
return false;
/* We cannot replace ourselves */
if(thiz == this)
{
return false;
}
/* If not ourselves, then search our body */
else
{
/* Check for module replacement */
for(size_t i = 0; i < this.modules.length; i++)
{
Module mod = this.modules[i];
/* If we are replacing a module */
if(thiz == mod)
{
this.modules[i] = cast(Module)that;
that.parentTo(this);
return true;
}
}
/* Check for replacement WITHIN each module */
for(size_t i = 0; i < this.modules.length; i++)
{
Module mod = this.modules[i];
/* If we are replacing WITHIN a module */
if(mod.replace(thiz, that))
{
return true;
}
}
return false;
}
}
public void addStatement(Statement statement)
@ -1016,7 +1050,7 @@ public class Call : IdentExpression
}
// FIXME: Finish adding proper `MStatementSearchable` and `MStatementReplaceable` to `FunctionCall`
public final class FunctionCall : Call, MStatementSearchable, MStatementReplaceable
public final class FunctionCall : Call, MStatementSearchable, MStatementReplaceable, MCloneable
{
/* Whether this is statement-level function call or not */
@ -1117,7 +1151,39 @@ public final class FunctionCall : Call, MStatementSearchable, MStatementReplacea
// {
// return false;
// }
return true;
return false;
}
/**
* Clones this integer literal
*
* Param:
* newParent = the `Container` to re-parent the
* cloned `Statement`'s self to
*
* Returns: the cloned `Statement`
*/
public override Statement clone(Container newParent = null)
{
// Clone arguments
Expression[] clonedArgs;
foreach(Expression arg; clonedArgs)
{
MCloneable argClonable = cast(MCloneable)arg;
if(argClonable)
{
clonedArgs ~= cast(Expression)argClonable.clone();
}
}
FunctionCall clonedFuncCall = new FunctionCall(this.name, clonedArgs);
DEBUG("haram");
// Parent outselves to the given parent
clonedFuncCall.parentTo(newParent);
return clonedFuncCall;
}
}

View File

@ -67,4 +67,88 @@ public interface MCloneable
* Returns: the cloned `Statement`
*/
public Statement clone(Container newParent = null);
}
/**
* Any AST type which implements this
* then will provide the ability to
* compare the AST nodes within itself
* (what that means is up to the implementing
* node)
*/
public interface MComparable
{
/**
* Compares the two nodes and reports
* on the position of `thiz` relative
* to `that`.
*
* Params:
* thiz = the first AST node
* that = the second AST node
* Returns: a `Pos`
*/
public Pos compare(Statement thiz, Statement that);
/**
* Compares the two statements and returns
* a value depending on which AST node
* precedes the other.
*
* Params:
* thiz = the first AST node
* that = the second AST node
* Returns: `true` if `thiz` comes before
* `that`, `false` otherwise
*/
public final bool isBefore(Statement thiz, Statement that)
{
return compare(thiz, that) == Pos.BEFORE;
}
/**
* Compares the two statements and returns
* a value depending on which AST node
* proceeds the other.
*
* Params:
* thiz = the first AST node
* that = the second AST node
* Returns: `true` if `thiz` comes after
* `that`, `false` otherwise
*/
public final bool isAfter(Statement thiz, Statement that)
{
return compare(thiz, that) == Pos.AFTER;
}
public enum Pos
{
/**
* If the position is the
* first node coming before
* the other
*/
BEFORE,
/**
* If the position is the
* first node coming after
* the other
*/
AFTER,
/**
* If both nodes are infact
* the same node
*/
SAME,
/**
* To be returned on an error
* dependant on implementation
*/
ERROR
}
}

View File

@ -9,6 +9,8 @@ import tlang.compiler.typecheck.core;
import tlang.misc.logging;
import std.conv : to;
import tlang.compiler.configuration;
import tlang.compiler.symbols.aliases : AliasDeclaration;
import std.string : format;
/**
* The `MetaProcessor` is used to do a pass over a `Container`
@ -55,6 +57,9 @@ public class MetaProcessor
{
DEBUG("MetaProcessor: Examining AST node '"~curStmt.toString()~"'...");
// Perform alias expression replacement
doAliasExpression(container, curStmt);
// Perform replacement of all type alises to concrete types, such as `size_t`
doTypeAlias(container, curStmt);
@ -119,6 +124,86 @@ public class MetaProcessor
}
}
import niknaks.arrays : filter;
import niknaks.functional : predicateOf, Predicate;
import tlang.compiler.symbols.data : VariableExpression;
import std.string : cmp;
import tlang.compiler.typecheck.resolution : Resolver;
private AliasDeclaration[] findAliasesFrom(Container from)
{
Resolver resolver = tc.getResolver(); // TODO: Remove from here, make a field
// Predicate to only find aliases (amongst all the different types of statements)
bool isAliasDecl(Statement stmt) { return cast(AliasDeclaration)stmt !is null; }
Statement[] declaredAliasesStmts;
resolver.collectUpwards(from, predicateOf!(isAliasDecl), declaredAliasesStmts);
return cast(AliasDeclaration[])declaredAliasesStmts;
}
private void doAliasExpression(Container container, Statement curStmt)
{
DEBUG(format("doAliasExpression(cntnr:%s, stmt=%s)", container, curStmt));
// Find any VariableExpression(s) from curStmt (TODO: should be container or nah?)
MStatementSearchable searchableStmt = cast(MStatementSearchable)curStmt;
if(searchableStmt)
{
VariableExpression[] foundStmts = cast(VariableExpression[])searchableStmt.search(VariableExpression.classinfo);
// Now, for all VariableExpressions, do
foreach(VariableExpression varExp; foundStmts)
{
// Extract the name/referent, then match all aliases
// that have the same name
// (these should have been generated from closest to
// furthest when obtained from the resolver, so any
// tie breaking would be the logically closest
// alias with the same name)
//
// Achor the search to start from the VarExp
AliasDeclaration[] declaredAliases = findAliasesFrom(varExp.parentOf());
DEBUG("DeclAlis: ", declaredAliases);
AliasDeclaration[] matched;
string varExpIdent = varExp.getName();
bool filterAliasesToName(AliasDeclaration aliasDecl)
{
return cmp(aliasDecl.getName(), varExpIdent) == 0;
}
filter!(AliasDeclaration)(declaredAliases, predicateOf!(filterAliasesToName), matched);
DEBUG(format("Matched aliases for VarExp '%s': %s", varExpIdent, matched));
// If there is no match then it isn't an alias referent
// hence we only care IF it IS an alias referent
if(matched.length)
{
// Nearest matched alias
AliasDeclaration nearestAlias = matched[0];
// Now extract the alias's expression and clone it
// and make its parent the VariableExpression's
// (as it will take its exact place)
MCloneable cloneableExpr = cast(MCloneable)nearestAlias.getExpr();
assert(cloneableExpr);
Expression clonedExpr = cast(Expression)cloneableExpr.clone(varExp.parentOf());
// Now, from the current container, replace the
// VariableExpression with the cloned expression
MStatementReplaceable containerRepl = cast(MStatementReplaceable)container;
assert(containerRepl);
assert(containerRepl.replace(varExp, clonedExpr));
}
}
}
else
{
DEBUG("Skipping non MStatementSearchable node");
}
}
/**
* Re-writes the types for things such as `size_t`, `ssize_t` and so forth
*

View File

@ -390,6 +390,42 @@ public final class Resolver
return resolveWithin(currentContainer, derive_nameMatch(name));
}
public void collectWithin(Container currentContainer, Predicate!(Statement) pred, ref Statement[] collection)
{
Statement[] statements = currentContainer.getStatements();
foreach(Statement statement; statements)
{
if(pred(statement))
{
collection ~= statement;
}
}
}
public void collectUpwards(Container currentContainer, Predicate!(Statement) pred, ref Statement[] collected)
{
// Collect everything at the current level
collectWithin(currentContainer, pred, collected);
// If the current container a Statement
if(cast(Statement)currentContainer)
{
Statement cntnrStmt = cast(Statement)currentContainer;
if(pred(cntnrStmt))
{
collected ~= cntnrStmt;
}
// Does it have a parent?
Container parent = cntnrStmt.parentOf();
if(parent)
{
collectUpwards(parent, pred, collected);
}
}
}
/**
* Performs a horizontal-based search of the given
* `Container`, returning the first `Entity` found

View File

@ -0,0 +1,21 @@
module simple_aliases;
int c = 0;
int cnt()
{
c=c+1;
return c;
}
alias expr = cnt();
alias inner = 1;
int main()
{
alias inner = 0;
int i = expr;
int p = expr;
int o = inner;
return i+p+o;
}