mirror of https://github.com/tbklang/tlang.git
Merge 9a9dc6d82e
into ce32cfe00d
This commit is contained in:
commit
c30a514812
|
@ -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
|
||||
|
||||
|
||||
##################################
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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() ~ "'");
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue