This commit is contained in:
Tristan B. Velloza Kildaire 2024-05-08 15:48:30 +00:00 committed by GitHub
commit c30a514812
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 283 additions and 3 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

@ -1016,7 +1016,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 +1117,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

@ -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,84 @@ public class MetaProcessor
}
}
import niknaks.arrays : filter;
import niknaks.functional : predicateOf, Predicate;
import tlang.compiler.symbols.data : VariableExpression;
import std.string : cmp;
private void doAliasExpression(Container container, Statement curStmt)
{
bool oldCode = false;
import tlang.compiler.typecheck.resolution : Resolver;
Resolver resolver = tc.getResolver();
// Discover all declared aliases in current container
// TODO: Ordering might be a parameter to set (as this discovers alias declared even AFTER they are used)
bool isAliasDecl(Statement stmt)
{
return cast(AliasDeclaration)stmt !is null;
}
Statement[] declaredAliasesStmts;
resolver.collectUpwards(container, predicateOf!(isAliasDecl), declaredAliasesStmts);
AliasDeclaration[] declaredAliases = cast(AliasDeclaration[])declaredAliasesStmts;
DEBUG(format("All aliases available from (cntnr:%s, stmt=%s) upwards: %s", container, curStmt, declaredAliases));
// 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)
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,17 @@
module simple_aliases;
int c = 0;
int cnt()
{
c=c+1;
return c;
}
alias expr = cnt();
int main()
{
int i = expr;
int p = expr;
return i+p;
}