🧠 Feature: Meta-programming engine (#10)

* Parser

- Added new interface `Cloneable`

* Symbols

- Added new `Statement`-based type: `Macro` to support `Macro`(s)

* MetaProcessor

- Added the `MetaProcessor`

TypeChecker

- Added the `MetaProcessor` instance to the `TypeChecker`, it will be instantiated upon the `TypeChecker`'s construction and later have its `.process()` method called as the first call in `beginCheck()`

* TypedEntity

- Added a `setType(string)` method to update the internal `type` field

* MetaProcessor

- Added a type-re-writing facility via `typeRewrite(TypedEntity)` which will re-write the types such as `size_t`, `ssize_t` and so forth

Test cases

- Added a test case `meta/types.t` which tests this

* MetaProcessor

- Updated the constructor to only take in an instance of the `TypeChecker`
- Updated the `process()` method to take in a `Container` such that it can be used recursively
- Commented code
- Added a recursive call to `process(Container)` when `curStmt` is a kind-of `Container` (this ensures that we reach the `VariableParameter`s of `Function` (die to them making up the `Statement[]` of `Function` type)
- Removed unused `cmp` import `std.string`
- Added type-rewrite for `ssize_t` -> `long`

TypeChecker

- Updated the constructor call to `MetaProcessor` to use its new API
- Updated call to `process()` to now be `process(modulle)`

Test cases

- Updated `types.t` to test re-writing of the `Function`'s parameters

* MetaProcessor

- Added another FIXME

* Mcro

- Added interface `MTypeRewritable` to represent any AST node which has a `setType(string)` and `string getType()` method for rewriting- Added `Sizeof` which is a kind-of `IntegerLiteral`

Data

- Made `TypedEntity` implement the `MTypeRewritable` interface

Expressions

- Made `IntegerLiteral` non-final such that we can inherit from it
- Added a final `setNumber(string)` method to `NumberLiteral` to update the literal

MetaProcessor

- The type rewriting mechanism now operates on `MTypeRewritable` AST nodes
- Work has begun on `sizeOf_Literalize(Sizeof)` which is to determine the `Type` of the `Sizeof` statement and then calculate the memory width and update its literal (as it is a kind-of `NunberLiteral`) to said size

Test cases

- Added `meta/sizeof.t` to test `sizeof` functionality

* Mcro

- Added interface type `MStatementSearchable`

* Mcro

- Redefined `MStatementSearchable`
- Added `MStatementReplaceable`
- Added `Repr` (a kind-of `Expression`) which will be used as an example to test out the aforementioned two interfaces

* MStatementSearchable

- Added method `search(TypeInfo_Class clazzType)` which uses a `TypeInfo_Class` to search for all types matching that (and which are sub-types of `Statement` and then adds these to a list and returns it in the form of `Statement[]`

* MStatementReplaceable

- Implemented `replace(Statement thiz, Statement that)` which replaces the `Statement` in the first argument with that of the `Statement` in the second argument

* MStatementSearchable

- Added documentation for `search(TypeInfo_Class)` method

* Mcro

- Made `Repr` implement `MStatementSearchable`
- Added new interface `MCloneable` to represent PNode's which are deeply-cloneable

* Data

- Made `DiscardStatement` searchabe via implementing `MStatementSearchable`
- Added a stub override for implementing `MStatementReplaceable` in `DiscardStatement`

* Mcro

- Updated `MStatementReplaceable` to have its `replace(Statement, Statement)` method return a boolean `true` if the replacement was successful, else `false`

* Parsing

- Added the ability to parse a `Repr` statement

Check

- Added `GENERIC_TYPE_DECLARE` and `REPR` as new `SymbolType`(s)

Data

- `DiscardStatement` now implements the `bool replace(Statement, Statement)` method

MetaProcessor

- Added the ability to replace statements that occur within any _other_ statements which implement `MStatementSearchable` and `MStatementReplaceable`

Test cases

- Added `meta/simple_meta_replace.t` to test all of this

Diagrams

- Added diagram on how the meta system works

* MetaProcessor

- Removed unused `replace` method

* MetaProcessor

- Accept a new argument to the `MetaProcessor(TypeChecker)` constructor indicating whether or not the `MetaProcessor` is enabled or not

TypeChecker

- Enable the `MetaProcessor`

* Mcro

- Removed `Sizeof`, we will let it be parsed as a normal `FunctionCall` and then inspect in `MetaProcessor`

* MetaProcessor

- Disabled `sizeOf_Literalize` for now
- Search for all `FunctionCall` statements in `process(Container)`

* MetaProcessor

- Removed old code for testing `MStatementSearchable` and `MStatementReplaceable`
- Added note that we will have to investigate a recursive `MTypeRewritable` to be able to support things like `sizeof(size_t)`
- Implemented module-level `sizeof(<ident_type>)` support
- Added `Number`-kind of types support to `sizeOf_Literalize`(string)`

Containers (`Module`)

- Added `MStatementSearchable` and `MStatementReplaceable` support to `Module` container type

Data

- Added `MStatementSearchable` and `MStatementReplaceable` support to `Variable`
- Added `MStatementSearchable` and `MStatementReplaceable` support to `VariableAssignment`
- Work-in-progress for adding `MStatementSearchable` and `MStatementReplaceable` support to `FunctionCall`
- Added a note to return `false` in `DiscardStatement` if the statement to be replaced is us (the `DiscardSTatement`) ourselves

Test cases

- Updated the `meta/sizeof.t` test case

* Containers

- Inherit from `MStatementSearchable` and `MStatementReplaceable`
- Removed direct interface inheritance of `MStatementSearchable, MStatementReplaceable` and `MStatementReplaceable`, rely on `Container` now

* Struct

- Implemented the `search` method for `MStatementSearchable`
- Implemented the `replace` method for `MStatementReplaceable`

Clazz

- Implemented the `search` method for `MStatementSearchable`
- Implemented the `replace` method for `MStatementReplaceable`

BinaryOperatorExpression

- Implemented the `search` method for `MStatementSearchable`
- Implemented the `replace` method for `MStatementReplaceable`

Function

- Implemented the `search` method for `MStatementSearchable`
- Implemented the `replace` method for `MStatementReplaceable`

Variable

- Fixed the `replace` method implementation which had a bug that would never replace the node `VariableAssignment` inside of it

VariableAssignmentStdAlone

- Implemented the `search` method for `MStatementSearchable`
- Implemented the `replace` method for `MStatementReplaceable`

IfStatement

- Implemented the `search` method for `MStatementSearchable`
- Implemented the `replace` method for `MStatementReplaceable`

WhileLoop

- Implemented the `search` method for `MStatementSearchable`
- Implemented the `replace` method for `MStatementReplaceable`

ForLoop

- Implemented the `search` method for `MStatementSearchable`
- Implemented the `replace` method for `MStatementReplaceable`

Branch

- Implemented the `search` method for `MStatementSearchable`
- Implemented the `replace` method for `MStatementReplaceable`

* MetaProcessor

- Added a future TODO for occurence of certain types that are alises (i.e. `size_t` appearing in a expression context like `sizeof(size_t)`
- Now that all `Container`-based types are `MStatementReplaceable` we no longer need this check

* MetaProcessor

- Removed `break` which caused only one `sizeof()` function call to be replaced, we should have been looping over each `FunctionCall` found with `search` and then replacing ech that had a name of `sizeof` with a `NumberLiteral` expression
- Moved all type alias replacement code into a new method; `doTypeAlias(Container, Statement)`
- Added some rudiementary support for replacing any `IdentExpression` containing `size_t` with `uint`

IdentExpression

- Made it `MStatementSearchable` and `MStatementReplaceable`

Test cases

- Updated test case `meta/sizeof.t` to test the `sizeof(<expr>)` AST node in the `MetaProcessor`

Documentation

- Added diagram showing the `MStatementSearchable` and `MStatementReplaceable` in action

* Compiler

- If the T compiler was built on `X86` then set the maximum width to 4 bytes
- If the T compiler was built on `X86_64` then set the maximum width to 8 bytes
- Pass in the `Compiler` instance to the `TypeChecker` in `doTypeCheck()`

TypeChecker

- Added `Compiler` field and now accept it in constructor
- If just single parameter constructor then pass in `null` as the `Compiler` instance
- Added `getCompiler()` to get the instance

MetaProcessor

- Extract the `CompilerConfiguration` via the `TypeChecker`'s `getCompiler()`
- Implemented `getSystemType(string)` which will map `size_t`/`ssize_t` to the correct maximum width'd type your system supports via the `types:max_width` config entry

* CompilerConfiguration

- Added `defaultConfig()`

* Compiler

- Removed `defaultConfig()`
- During construction call `CompilerConfiguration.defaultConfig()` in order to generate the default config
- Pass the config into `TypeChecker` in `doTypeCheck()`

* TypeChecker

- No longer store a field for the `Compiler` but rather store a field for the `CompilerConfiguration`
- Removed single parameter constructor for `TypeChecker`
- Constructor now uses the default `CompilerConfiguration` if not specified; therefore fixing the issue with unit tests failing

MetaProcessor

- Extract the compiler configuration via `tc.getConfig()`
- Updated `typeRewrite(MTypeRewritable)` to use `getSystemType(string)` to lookup concrete types for `size_t`/`ssize_t`
- `doTypeAlias(Container, Statement)` now uses `getSsstemType(string)` to lookup the concrete types for alises such as `size_t`/`ssize_t`

* MetaProcessor

- Implemented `isSystemType(string)` which returns `true` if the provided type is a system type alias (such as `size_t` or `ssize_t`), `false` otherwise

* MetaProcessor

- Implemented `isTypeAlias(string)` which determines if the given type is a type alias.
- Implemented `getConcreteType(string typeAlias)` which transforms the type alias into its
concrete type; this method incorporates defensive programming in that it will only apply the transformation IF
the provided type alias is infact a type alias, otherwise it performs an identity transformation
and returns the "alias" untouched.

* TypeChecker

- Clean up

* MetaProcessor

- `doTypeAlias(Container, Statement)` now makes use of `isTypeAlias(string)` and `getConcreteType(string)`

* - `typeRewrite(MTypeRewritable)` now makes use of `isTypeAlias(string)` and `getConcreteType(string)`

* MetaProcessor

- Cleaned up

* MetaProcessor

- Removed unused import

* MetaProcessor

- Removed now-completed TODO

* MetaProcessor

- Updated comment before call to `doTypeAlias(Container, Statement)`

* Containers

- `Module` now applies re-parenting in its `replace()`
- `Struct` now applies re-parenting in its `replace()`
- `Clazz` now applies re-parenting in its `replace()`

Data

- `Function` now applies re-parenting in its `replace()`

* Test cases

- Added `simple_template_type_def.t` for future test cases

* - Updated `.gitignore`

* Check

- Removed `SymbolType.REPR` which was used for testing early versions of the `MetaProcessor`

* Mcro

- Removed `Repr` which was used for testing in the early stages of `MetaProcessor`

* Check

- Removed reference to `SymbolType.REPR` in checker

* Parser

- Removed reference to `SymbolType.REPR` and `Repr` which was used for testing the `MetaProcessor` in early stages
This commit is contained in:
Tristan B. Velloza Kildaire 2023-05-29 17:02:28 +02:00 committed by GitHub
parent c65c41eed2
commit 39508a5907
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 1534 additions and 36 deletions

1
.gitignore vendored
View File

@ -17,3 +17,4 @@ dub.selections.json
# Documentation )generated)
docs/
docs.json
desktop_dev.code-workspace

BIN
macro_ast_replacemenet.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 428 KiB

BIN
macro_ast_replacemenet.xcf Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 KiB

Binary file not shown.

View File

@ -189,4 +189,43 @@ public final class CompilerConfiguration
ConfigEntry _discard;
return hasConfig_internal(key, _discard);
}
/**
* Generates the default compiler configuration
*
* Returns: a `CompilerConfguration`
*/
public static CompilerConfiguration defaultConfig()
{
/* Generate a fresh new config */
CompilerConfiguration config = new CompilerConfiguration();
/* Enable Behaviour-C fixes */
config.addConfig(ConfigEntry("behavec:preinline_args", true));
/* Enable pretty code generation for DGen */
config.addConfig(ConfigEntry("dgen:pretty_code", true));
/* Enable entry point test generation for DGen */
config.addConfig(ConfigEntry("dgen:emit_entrypoint_test", true));
/* Set the mapping to hashing of entity names (TODO: This should be changed before release) */
config.addConfig(ConfigEntry("emit:mapper", "hashmapper"));
/**
* Configure, at compile time, the system type aliases
*/
version(X86)
{
/* Set maximum width to 4 bytes (32-bits) */
config.addConfig(ConfigEntry("types:max_width", 4));
}
else version(X86_64)
{
/* Set maximum width to 8 bytes (64-bits) */
config.addConfig(ConfigEntry("types:max_width", 8));
}
return config;
}
}

View File

@ -115,21 +115,6 @@ public class Compiler
/* The configuration */
private CompilerConfiguration config;
/* TODO: Make the default config */
private void defaultConfig()
{
/* Enable Behaviour-C fixes */
config.addConfig(ConfigEntry("behavec:preinline_args", true));
/* Enable pretty code generation for DGen */
config.addConfig(ConfigEntry("dgen:pretty_code", true));
/* Enable entry point test generation for DGen */
config.addConfig(ConfigEntry("dgen:emit_entrypoint_test", true));
/* Set the mapping to hashing of entity names (TODO: This should be changed before release) */
config.addConfig(ConfigEntry("emit:mapper", "hashmapper"));
}
public CompilerConfiguration getConfig()
{
@ -147,10 +132,8 @@ public class Compiler
this.inputSource = sourceCode;
this.emitOutFile = emitOutFile;
this.config = new CompilerConfiguration();
/* Enable the default config */
defaultConfig();
/* Get the default config */
this.config = CompilerConfiguration.defaultConfig();
}
/* Setup the lexer and begin lexing */
@ -207,7 +190,7 @@ public class Compiler
throw new CompilerException(CompilerError.PARSE_NOT_YET_PERFORMED);
}
this.typeChecker = new TypeChecker(modulle);
this.typeChecker = new TypeChecker(modulle, config);
/* Perform typechecking/codegen */
this.typeChecker.beginCheck();

View File

@ -0,0 +1,17 @@
module tlang.compiler.parsing.cloneable;
import tlang.compiler.symbols.data : Statement;
/**
* A parse-node/AST-node which implements `Cloneable` can
* be safely deeply cloned such that a full copy is returned.
*/
public interface Cloneable
{
/**
* Performs a deep clone of this parse node
*
* Returns: the clone
*/
public Statement clone();
}

View File

@ -64,6 +64,12 @@ public enum SymbolType
EXTERN,
EXTERN_EFUNC,
EXTERN_EVAR,
/**
* `generic`
*/
GENERIC_TYPE_DECLARE,
UNKNOWN
}
@ -380,6 +386,11 @@ public SymbolType getSymbolType(Token tokenIn)
{
return SymbolType.DISCARD;
}
/* generic keyword */
else if(cmp(token, "generic") == 0)
{
return SymbolType.GENERIC_TYPE_DECLARE;
}
/* An identifier/type (of some sorts) - further inspection in parser is needed */
else if(isPathIdentifier(token) || isIdentifier(token))
{

View File

@ -29,7 +29,9 @@ public Statement[] weightReorder(Statement[] statements)
return stmntsRed;
}
public interface Container
// TODO: Honestly all contains should be a kind-of `MStatementSearchable` and `MStatementReplaceable`
import tlang.compiler.symbols.mcro : MStatementSearchable, MStatementReplaceable, MStatementReplaceable;
public interface Container : MStatementSearchable, MStatementReplaceable
{
public void addStatement(Statement statement);
@ -38,6 +40,7 @@ public interface Container
public Statement[] getStatements();
}
public class Module : Entity, Container
{
this(string moduleName)
@ -62,6 +65,79 @@ public class Module : Entity, Container
{
return weightReorder(statements);
}
public override Statement[] search(TypeInfo_Class clazzType)
{
/* List of returned matches */
Statement[] matches;
/* Are we (ourselves) of this type? */
if(clazzType.isBaseOf(this.classinfo))
{
matches ~= [this];
}
/* Recurse on each `Statement` making up our body */
// NOTE: Using weight-reordered? Is that fine?
foreach(Statement curStmt; getStatements())
{
MStatementSearchable curStmtCasted = cast(MStatementSearchable)curStmt;
if(curStmtCasted)
{
matches ~= curStmtCasted.search(clazzType);
}
}
return matches;
}
public override bool replace(Statement thiz, Statement that)
{
/* If we (`this`) are `thiz`, then we cannot replace */
if(this == thiz)
{
return false;
}
/* If not ourself, then check the body statements */
else
{
/**
* First check each `Statement` that make sup our
* body and see if we can replace that, else see
* if we can recurse on each of the body statements
* and apply replacement therein
*/
// NOTE: Using weight-reordered? Is that fine?
Statement[] bodyStmts = getStatements();
for(ulong idx = 0; idx < bodyStmts.length; idx++)
{
Statement curBodyStmt = bodyStmts[idx];
/* Should we directly replace the Statement in the body? */
if(curBodyStmt == thiz)
{
// Replace the statement in the body
statements[idx] = that;
// Re-parent `that` to us
that.parentTo(this);
return true;
}
/* If we cannot, then recurse (try) on it */
else if(cast(MStatementReplaceable)curBodyStmt)
{
MStatementReplaceable curBodyStmtRepl = cast(MStatementReplaceable)curBodyStmt;
if(curBodyStmtRepl.replace(thiz, that))
{
return true;
}
}
}
return false;
}
}
}
/**
@ -94,6 +170,79 @@ public class Struct : Type, Container
{
super(name);
}
public override Statement[] search(TypeInfo_Class clazzType)
{
/* List of returned matches */
Statement[] matches;
/* Are we (ourselves) of this type? */
if(clazzType.isBaseOf(this.classinfo))
{
matches ~= [this];
}
/* Recurse on each `Statement` making up our body */
// NOTE: Using weight-reordered? Is that fine?
foreach(Statement curStmt; getStatements())
{
MStatementSearchable curStmtCasted = cast(MStatementSearchable)curStmt;
if(curStmtCasted)
{
matches ~= curStmtCasted.search(clazzType);
}
}
return matches;
}
public override bool replace(Statement thiz, Statement that)
{
/* If we (`this`) are `thiz`, then we cannot replace */
if(this == thiz)
{
return false;
}
/* If not ourself, then check the body statements */
else
{
/**
* First check each `Statement` that make sup our
* body and see if we can replace that, else see
* if we can recurse on each of the body statements
* and apply replacement therein
*/
// NOTE: Using weight-reordered? Is that fine?
Statement[] bodyStmts = getStatements();
for(ulong idx = 0; idx < bodyStmts.length; idx++)
{
Statement curBodyStmt = bodyStmts[idx];
/* Should we directly replace the Statement in the body? */
if(curBodyStmt == thiz)
{
// Replace the statement in the body
statements[idx] = that;
// Re-parent `that` to us
that.parentTo(this);
return true;
}
/* If we cannot, then recurse (try) on it */
else if(cast(MStatementReplaceable)curBodyStmt)
{
MStatementReplaceable curBodyStmtRepl = cast(MStatementReplaceable)curBodyStmt;
if(curBodyStmtRepl.replace(thiz, that))
{
return true;
}
}
}
return false;
}
}
}
public class Clazz : Type, Container
@ -139,5 +288,78 @@ public class Clazz : Type, Container
{
return weightReorder(statements);
}
public override Statement[] search(TypeInfo_Class clazzType)
{
/* List of returned matches */
Statement[] matches;
/* Are we (ourselves) of this type? */
if(clazzType.isBaseOf(this.classinfo))
{
matches ~= [this];
}
/* Recurse on each `Statement` making up our body */
// NOTE: Using weight-reordered? Is that fine?
foreach(Statement curStmt; getStatements())
{
MStatementSearchable curStmtCasted = cast(MStatementSearchable)curStmt;
if(curStmtCasted)
{
matches ~= curStmtCasted.search(clazzType);
}
}
return matches;
}
public override bool replace(Statement thiz, Statement that)
{
/* If we (`this`) are `thiz`, then we cannot replace */
if(this == thiz)
{
return false;
}
/* If not ourself, then check the body statements */
else
{
/**
* First check each `Statement` that make sup our
* body and see if we can replace that, else see
* if we can recurse on each of the body statements
* and apply replacement therein
*/
// NOTE: Using weight-reordered? Is that fine?
Statement[] bodyStmts = getStatements();
for(ulong idx = 0; idx < bodyStmts.length; idx++)
{
Statement curBodyStmt = bodyStmts[idx];
/* Should we directly replace the Statement in the body? */
if(curBodyStmt == thiz)
{
// Replace the statement in the body
statements[idx] = that;
// Re-parent `that` to us
that.parentTo(this);
return true;
}
/* If we cannot, then recurse (try) on it */
else if(cast(MStatementReplaceable)curBodyStmt)
{
MStatementReplaceable curBodyStmtRepl = cast(MStatementReplaceable)curBodyStmt;
if(curBodyStmtRepl.replace(thiz, that))
{
return true;
}
}
}
return false;
}
}
}

View File

@ -215,7 +215,8 @@ public class Entity : Statement
}
/* TODO: DO we need intermediary class, TypedEntity */
public class TypedEntity : Entity
import tlang.compiler.symbols.mcro : MTypeRewritable;
public class TypedEntity : Entity, MTypeRewritable
{
private string type;
@ -230,6 +231,11 @@ public class TypedEntity : Entity
{
return type;
}
public void setType(string type)
{
this.type = type;
}
}
public import tlang.compiler.symbols.containers;
@ -352,9 +358,93 @@ public class Function : TypedEntity, Container
return "Function (Name: "~name~", ReturnType: "~type~", Args: "~argTypes~")";
}
public override Statement[] search(TypeInfo_Class clazzType)
{
/* List of returned matches */
Statement[] matches;
/* Are we (ourselves) of this type? */
if(clazzType.isBaseOf(this.classinfo))
{
matches ~= [this];
}
/* Recurse on each `Statement` making up our body */
// NOTE: Using weight-reordered? Is that fine?
foreach(Statement curStmt; getStatements())
{
MStatementSearchable curStmtCasted = cast(MStatementSearchable)curStmt;
if(curStmtCasted)
{
matches ~= curStmtCasted.search(clazzType);
}
}
return matches;
}
public override bool replace(Statement thiz, Statement that)
{
/* If we (`this`) are `thiz`, then we cannot replace */
if(this == thiz)
{
return false;
}
/* If not ourself, then check the body statements */
else
{
/**
* First check each `Statement` that make sup our
* body and see if we can replace that, else see
* if we can recurse on each of the body statements
* and apply replacement therein
*/
// NOTE: Using weight-reordered? Is that fine?
Statement[] bodyStmts = getStatements();
for(ulong idx = 0; idx < bodyStmts.length; idx++)
{
Statement curBodyStmt = bodyStmts[idx];
/* Should we directly replace the Statement in the body? */
if(curBodyStmt == thiz)
{
// Replace the statement in the body
// NOTE: The respective Variable Param must be swapped out too if need be
// (varParams[] subsetOf Statements[])
for(ulong varParamIdx = 0; varParamIdx < params.length; varParamIdx++)
{
VariableParameter curVarParam = params[varParamIdx];
if(curVarParam == thiz)
{
params[varParamIdx] = cast(VariableParameter)that;
break;
}
}
bodyStatements[idx] = that;
// Re-parent `that` to us
that.parentTo(this);
return true;
}
/* If we cannot, then recurse (try) on it */
else if(cast(MStatementReplaceable)curBodyStmt)
{
MStatementReplaceable curBodyStmtRepl = cast(MStatementReplaceable)curBodyStmt;
if(curBodyStmtRepl.replace(thiz, that))
{
return true;
}
}
}
return false;
}
}
}
public class Variable : TypedEntity
public class Variable : TypedEntity, MStatementSearchable, MStatementReplaceable
{
/* TODO: Just make this an Expression */
private VariableAssignment assignment;
@ -382,6 +472,49 @@ public class Variable : TypedEntity
{
return "Variable (Ident: "~name~", Type: "~type~")";
}
public override Statement[] search(TypeInfo_Class clazzType)
{
/* List of returned matches */
Statement[] matches;
/* Are we (ourselves) of this type? */
if(clazzType.isBaseOf(this.classinfo))
{
matches ~= [this];
}
/**
* Recurse on the `VariableAssignment`
*/
MStatementSearchable innerStmt = cast(MStatementSearchable)assignment;
if(innerStmt)
{
matches ~= innerStmt.search(clazzType);
}
return matches;
}
public override bool replace(Statement thiz, Statement that)
{
/* If we, the `Variable`, are the `thiz` then we cannot perform replacement */
if(this == thiz)
{
return false;
}
/* Check if we should replace the `VariableAssignment` */
else if(thiz == assignment)
{
assignment = cast(VariableAssignment)that;
return true;
}
/* Recurse on the variable assignment */
else
{
return assignment.replace(thiz, that);
}
}
}
@ -394,7 +527,7 @@ public import tlang.compiler.symbols.expressions;
/**
* TODO: Rename to `VariableDeclarationAssignment`
*/
public class VariableAssignment : Statement
public class VariableAssignment : Statement, MStatementSearchable, MStatementReplaceable
{
private Expression expression;
private Variable variable;
@ -414,6 +547,8 @@ public class VariableAssignment : Statement
return variable;
}
// NOTE-to-self: Very interesting method we have here, is this just for debugging?
// (15th May 2023, whilst working on Meta)
public void setVariable(Variable variable)
{
this.variable = variable;
@ -423,12 +558,60 @@ public class VariableAssignment : Statement
{
return "[varAssignDec'd: To: "~variable.toString()~"]";
}
public override Statement[] search(TypeInfo_Class clazzType)
{
/* List of returned matches */
Statement[] matches;
/* Are we (ourselves) of this type? */
if(clazzType.isBaseOf(this.classinfo))
{
matches ~= [this];
}
/* Recurse on our `Expression` (if possible) */
MStatementSearchable innerStmt = cast(MStatementSearchable)expression;
if(innerStmt)
{
matches ~= innerStmt.search(clazzType);
}
return matches;
}
public override bool replace(Statement thiz, Statement that)
{
/* We cannot replace ourselves directly */
if(this == thiz)
{
return false;
}
/* Is the `Expression` the `thiz`, then swap out the expression */
else if(expression == thiz)
{
// TODO: Any reparenting needed?
expression = cast(Expression)that;
return true;
}
/* Recurse on the `Expression` being assigned (if possible) */
else if(cast(MStatementReplaceable)expression)
{
MStatementReplaceable replStmt = cast(MStatementReplaceable)expression;
return replStmt.replace(thiz, that);
}
/* If not matched */
else
{
return false;
}
}
}
/**
* TODO: Rename to ``
*/
public class VariableAssignmentStdAlone : Statement
public class VariableAssignmentStdAlone : Statement, MStatementSearchable, MStatementReplaceable
{
private Expression expression;
private string varName;
@ -456,6 +639,55 @@ public class VariableAssignmentStdAlone : Statement
{
return "[varAssignStdAlone: To: "~varName~"]";
}
public override Statement[] search(TypeInfo_Class clazzType)
{
/* List of returned matches */
Statement[] matches;
/* Are we (ourselves) of this type? */
if(clazzType.isBaseOf(this.classinfo))
{
matches ~= [this];
}
/**
* Recurse on the assigned `Expression`
*/
MStatementSearchable assignedStmtCasted = cast(MStatementSearchable)expression;
if(assignedStmtCasted)
{
matches ~= assignedStmtCasted.search(clazzType);
}
return matches;
}
public override bool replace(Statement thiz, Statement that)
{
/* If we, the `VariableAssignmentStdAlone`, are the `thiz` then we cannot perform replacement */
if(this == thiz)
{
return false;
}
/* Check if we should replace the `Expression` being assigned? */
else if(thiz == expression)
{
expression = cast(Expression)that;
return true;
}
/* Recurse on the assigned `Expression` (if possible) */
else if(cast(MStatementReplaceable)expression)
{
MStatementReplaceable expressionCasted = cast(MStatementReplaceable)expression;
return expressionCasted.replace(thiz, that);
}
/* None */
else
{
return false;
}
}
}
// TODO: Add an ArrayAssignment thing here, would be similiar to PointerDeference
@ -538,12 +770,8 @@ public class PointerDereferenceAssignment : Statement
}
}
public class IdentExpression : Expression
public class IdentExpression : Expression, MStatementSearchable, MStatementReplaceable
{
/* name */
private string name;
@ -561,6 +789,27 @@ public class IdentExpression : Expression
{
name = newName;
}
public override Statement[] search(TypeInfo_Class clazzType)
{
/* List of returned matches */
Statement[] matches;
/* Are we (ourselves) of this type? */
if(clazzType.isBaseOf(this.classinfo))
{
matches ~= [this];
}
return matches;
}
public override bool replace(Statement thiz, Statement that)
{
// Nothing to replace within us
return false;
}
}
public class VariableExpression : IdentExpression
@ -596,7 +845,8 @@ public class Call : IdentExpression
}
}
public final class FunctionCall : Call
// FIXME: Finish adding proper `MStatementSearchable` and `MStatementReplaceable` to `FunctionCall`
public final class FunctionCall : Call, MStatementSearchable, MStatementReplaceable
{
/* Whether this is statement-level function call or not */
@ -644,6 +894,61 @@ public final class FunctionCall : Call
{
return isStatementLevel;
}
public override Statement[] search(TypeInfo_Class clazzType)
{
// TODO: Implement me
/* List of returned matches */
Statement[] matches;
/* Are we (ourselves) of this type? */
if(clazzType.isBaseOf(this.classinfo))
{
matches ~= [this];
}
/**
* Recurse on each `Expression` (if possible)
*/
foreach(Expression callExp; arguments)
{
MStatementSearchable innerStmt = cast(MStatementSearchable)callExp;
if(innerStmt)
{
matches ~= innerStmt.search(clazzType);
}
}
return matches;
}
public override bool replace(Statement thiz, Statement that)
{
// TODO: Implement me
// /* Check if our `Expression` matches, then replace */
// if(expression == thiz)
// {
// // NOTE: This legit makes no sense and won't do anything, we could remove this
// // and honestly should probably make this return false
// // FIXME: Make this return `false` (see above)
// expression = cast(Expression)that;
// return true;
// }
// /* If not direct match, then recurse and replace (if possible) */
// else if(cast(MStatementReplaceable)expression)
// {
// MStatementReplaceable replStmt = cast(MStatementReplaceable)expression;
// return replStmt.replace(thiz, that);
// }
// /* If not direct match and not replaceable */
// else
// {
// return false;
// }
return true;
}
}
/**
@ -717,6 +1022,70 @@ public final class IfStatement : Entity, Container
{
return "IfStmt";
}
public override Statement[] search(TypeInfo_Class clazzType)
{
/* List of returned matches */
Statement[] matches;
/* Are we (ourselves) of this type? */
if(clazzType.isBaseOf(this.classinfo))
{
matches ~= [this];
}
/* Loop through each `Branch` and recurse on them */
foreach(Branch curBranch; branches)
{
matches ~= curBranch.search(clazzType);
}
return matches;
}
public override bool replace(Statement thiz, Statement that)
{
/* If we (`this`) are `thiz`, then we cannot replace */
if(this == thiz)
{
return false;
}
/* If not ourself, then check each `Branch` or recurse on them */
else
{
/**
* First check each `Branch` that makes up our
* branches array and see if we can replace that,
* else see if we can recurse on each of the branche
* and apply replacement therein
*/
Statement[] bodyStmts = getStatements();
for(ulong idx = 0; idx < bodyStmts.length; idx++)
{
Statement curBodyStmt = bodyStmts[idx];
/* Should we directly replace the Statement in the body? */
if(curBodyStmt == thiz)
{
// Replace the statement in the body
// FIXME: Apply parenting? Yes we should
branches[idx] = cast(Branch)that;
return true;
}
/* If we cannot, then recurse (try) on it */
else if(cast(MStatementReplaceable)curBodyStmt)
{
MStatementReplaceable curBodyStmtRepl = cast(MStatementReplaceable)curBodyStmt;
if(curBodyStmtRepl.replace(thiz, that))
{
return true;
}
}
}
return false;
}
}
}
/**
@ -785,6 +1154,50 @@ public final class WhileLoop : Entity, Container
{
return "WhileLoop";
}
public override Statement[] search(TypeInfo_Class clazzType)
{
/* List of returned matches */
Statement[] matches;
/* Are we (ourselves) of this type? */
if(clazzType.isBaseOf(this.classinfo))
{
matches ~= [this];
}
/* Recurse on the the `Branch` */
if(cast(MStatementSearchable)branch)
{
MStatementSearchable branchCasted = cast(MStatementSearchable)branch;
if(branchCasted)
{
matches ~= branchCasted.search(clazzType);
}
}
return matches;
}
public override bool replace(Statement thiz, Statement that)
{
/* If we (`this`) are `thiz`, then we cannot replace */
if(this == thiz)
{
return false;
}
/* If the `Branch` is to be replaced */
else if(branch == thiz)
{
branch = cast(Branch)that;
return true;
}
/* If not ourself, then recurse on the `Branch` */
else
{
return branch.replace(thiz, that);
}
}
}
public final class ForLoop : Entity, Container
@ -872,6 +1285,66 @@ public final class ForLoop : Entity, Container
{
return "ForLoop";
}
public override Statement[] search(TypeInfo_Class clazzType)
{
/* List of returned matches */
Statement[] matches;
/* Are we (ourselves) of this type? */
if(clazzType.isBaseOf(this.classinfo))
{
matches ~= [this];
}
/* Recurse on the pre-loop `Statement` */
if(cast(MStatementSearchable)preLoopStatement)
{
MStatementSearchable preLoopStatementCasted = cast(MStatementSearchable)preLoopStatement;
if(preLoopStatementCasted)
{
matches ~= preLoopStatementCasted.search(clazzType);
}
}
/* Recurse on the the `Branch` */
if(cast(MStatementSearchable)branch)
{
MStatementSearchable branchCasted = cast(MStatementSearchable)branch;
if(branchCasted)
{
matches ~= branchCasted.search(clazzType);
}
}
return matches;
}
public override bool replace(Statement thiz, Statement that)
{
/* If we (`this`) are `thiz`, then we cannot replace */
if(this == thiz)
{
return false;
}
/* If the `Branch` is to be replaced */
else if(branch == thiz)
{
branch = cast(Branch)that;
return true;
}
/* If the pre-loop `Statement` is to be replaced */
else if(preLoopStatement == thiz)
{
preLoopStatement = cast(Statement)that;
return true;
}
/* If not ourself, then recurse on the `Branch` */
else
{
return branch.replace(thiz, that);
}
}
}
/**
@ -954,9 +1427,97 @@ public final class Branch : Entity, Container
{
return "Branch";
}
public override Statement[] search(TypeInfo_Class clazzType)
{
/* List of returned matches */
Statement[] matches;
/* Are we (ourselves) of this type? */
if(clazzType.isBaseOf(this.classinfo))
{
matches ~= [this];
}
/* Recurse on the branch condition `Expression` */
if(cast(MStatementSearchable)branchCondition)
{
MStatementSearchable branchConditionCasted = cast(MStatementSearchable)branchCondition;
if(branchConditionCasted)
{
matches ~= branchConditionCasted.search(clazzType);
}
}
/* Recurse on each `Statement` making up our body */
// NOTE: Using weight-reordered? Is that fine?
foreach(Statement curStmt; getStatements())
{
MStatementSearchable curStmtCasted = cast(MStatementSearchable)curStmt;
if(curStmtCasted)
{
matches ~= curStmtCasted.search(clazzType);
}
}
return matches;
}
public override bool replace(Statement thiz, Statement that)
{
/* If we (`this`) are `thiz`, then we cannot replace */
if(this == thiz)
{
return false;
}
/* If the branch condition `Expression` is matching */
else if(branchCondition == thiz)
{
branchCondition = cast(Expression)that;
return true;
}
/* If not ourself, then check the body statements */
else
{
/**
* First check each `Statement` that make sup our
* body and see if we can replace that, else see
* if we can recurse on each of the body statements
* and apply replacement therein
*/
// NOTE: Using weight-reordered? Is that fine?
Statement[] bodyStmts = getStatements();
for(ulong idx = 0; idx < bodyStmts.length; idx++)
{
Statement curBodyStmt = bodyStmts[idx];
/* Should we directly replace the Statement in the body? */
if(curBodyStmt == thiz)
{
// Replace the statement in the body
// FIXME: Apply parenting? Yes we should
branchBody[idx] = that;
return true;
}
/* If we cannot, then recurse (try) on it */
else if(cast(MStatementReplaceable)curBodyStmt)
{
MStatementReplaceable curBodyStmtRepl = cast(MStatementReplaceable)curBodyStmt;
if(curBodyStmtRepl.replace(thiz, that))
{
return true;
}
}
}
return false;
}
}
}
public final class DiscardStatement : Statement
import tlang.compiler.symbols.mcro : MStatementSearchable, MStatementReplaceable;
public final class DiscardStatement : Statement, MStatementSearchable, MStatementReplaceable
{
private Expression expression;
@ -977,6 +1538,54 @@ public final class DiscardStatement : Statement
{
return "[DiscardStatement: (Exp: "~expression.toString()~")]";
}
public override Statement[] search(TypeInfo_Class clazzType)
{
/* List of returned matches */
Statement[] matches;
/* Are we (ourselves) of this type? */
if(clazzType.isBaseOf(this.classinfo))
{
matches ~= [this];
}
/* Recurse on our `Expression` (if possible) */
MStatementSearchable innerStmt = cast(MStatementSearchable)expression;
if(innerStmt)
{
matches ~= innerStmt.search(clazzType);
}
return matches;
}
public override bool replace(Statement thiz, Statement that)
{
import std.stdio;
writeln("Replace() enter discard");
/* Check if our `Expression` matches, then replace */
if(expression == thiz)
{
// NOTE: This legit makes no sense and won't do anything, we could remove this
// and honestly should probably make this return false
// FIXME: Make this return `false` (see above)
expression = cast(Expression)that;
return true;
}
/* If not direct match, then recurse and replace (if possible) */
else if(cast(MStatementReplaceable)expression)
{
MStatementReplaceable replStmt = cast(MStatementReplaceable)expression;
return replStmt.replace(thiz, that);
}
/* If not direct match and not replaceable */
else
{
return false;
}
}
}
public final class ExternStmt : Statement

View File

@ -56,7 +56,9 @@ public class UnaryOperatorExpression : OperatorExpression
}
}
public class BinaryOperatorExpression : OperatorExpression
import tlang.compiler.symbols.mcro : MStatementSearchable, MStatementReplaceable;
public class BinaryOperatorExpression : OperatorExpression, MStatementSearchable, MStatementReplaceable
{
private Expression lhs, rhs;
@ -83,6 +85,72 @@ public class BinaryOperatorExpression : OperatorExpression
/* TODO: FIll in */
return "[BinOpExp: Op: "~to!(string)(operator)~", Lhs: "~lhs.toString()~", Rhs: "~rhs.toString()~"]";
}
public override Statement[] search(TypeInfo_Class clazzType)
{
/* List of returned matches */
Statement[] matches;
/* Are we (ourselves) of this type? */
if(clazzType.isBaseOf(this.classinfo))
{
matches ~= [this];
}
/* Recurse on our left-hand side `Expression` (if possible) */
MStatementSearchable lhsCasted = cast(MStatementSearchable)lhs;
if(lhsCasted)
{
matches ~= lhsCasted.search(clazzType);
}
/* Recurse on our right-hand side `Expression` (if possible) */
MStatementSearchable rhsCasted = cast(MStatementSearchable)rhs;
if(rhsCasted)
{
matches ~= rhsCasted.search(clazzType);
}
return matches;
}
public override bool replace(Statement thiz, Statement that)
{
/* We cannot directly replace ourselves */
if(this == thiz)
{
return false;
}
/* Is the left-hand side `Expression` to be replaced? */
else if(thiz == lhs)
{
lhs = cast(Expression)that;
return true;
}
/* Is the right-hand side `Expression` to be replaced? */
else if(thiz == rhs)
{
rhs = cast(Expression)that;
return true;
}
/* If not direct match, then recurse and replace on left-hand side `Expression` (if possible) */
else if(cast(MStatementReplaceable)lhs)
{
MStatementReplaceable lhsCasted = cast(MStatementReplaceable)lhs;
return lhsCasted.replace(thiz, that);
}
/* If not direct match, then recurse and replace on right-hand side `Expression` (if possible) */
else if(cast(MStatementReplaceable)rhs)
{
MStatementReplaceable rhsCasted = cast(MStatementReplaceable)rhs;
return rhsCasted.replace(thiz, that);
}
/* If not direct match and not replaceable */
else
{
return false;
}
}
}
public enum IntegerLiteralEncoding
@ -93,7 +161,7 @@ public enum IntegerLiteralEncoding
UNSIGNED_LONG
}
public final class IntegerLiteral : NumberLiteral
public class IntegerLiteral : NumberLiteral
{
private IntegerLiteralEncoding encoding;
@ -143,6 +211,11 @@ public abstract class NumberLiteral : Expression
{
return numberLiteral;
}
public final void setNumber(string numberLiteral)
{
this.numberLiteral = numberLiteral;
}
}
public class Expression : Statement

View File

@ -0,0 +1,66 @@
module tlang.compiler.symbols.mcro;
import tlang.compiler.symbols.data;
public class Macro : Statement
{
}
public interface MTypeRewritable
{
public string getType();
public void setType(string type);
}
/**
* Anything which implements this has the ability
* to search for objects of the provided type,
* and return a list of them
*/
public interface MStatementSearchable
{
/**
* Searches for all objects of the given type
* and returns an array of them. Only if the given
* type is equal to or sub-of `Statement`
*
* Params:
* clazzType = the type to search for
* Returns: an array of `Statement` (a `Statement[]`)
*/
public Statement[] search(TypeInfo_Class clazzType);
}
/**
* Anything which implements this has the ability
* to, given an object `x`, return a `ref x` to it
* hence allowing us to replace it
*/
public interface MStatementReplaceable
{
/**
* Replace a given `Statement` with another `Statement`
*
* Params:
* thiz = the `Statement` to replace
* that = the `Statement` to insert in-place
* Returns: `true` if the replacement succeeded, `false` otherwise
*/
public bool replace(Statement thiz, Statement that);
}
/**
* Anything which implements this can make a full
* deep clone of itself
*/
public interface MCloneable
{
/**
* Returns a `Statement` which is a clone of this one
* itself
*
* Returns: the cloned `Statement`
*/
public Statement clone();
}

View File

@ -14,6 +14,8 @@ import tlang.compiler.typecheck.dependency.core;
import tlang.compiler.codegen.instruction;
import std.container.slist;
import std.algorithm : reverse;
import tlang.compiler.typecheck.meta;
import tlang.compiler.configuration;
/**
* The Parser only makes sure syntax
@ -24,23 +26,58 @@ import std.algorithm : reverse;
*/
public final class TypeChecker
{
/**
* The compiler configuration
*/
private CompilerConfiguration config;
private Module modulle;
/* The name resolver */
private Resolver resolver;
/**
* The meta-programming processor
*/
private MetaProcessor meta;
public Module getModule()
{
return modulle;
}
this(Module modulle)
/**
* Constructs a new `TypeChecker` based on the provided `Module`
* of which to typecheck its members and using the default
* compiler configuration
*
* Params:
* modulle = the `Module` to check
* config = the `CompilerConfiguration` (default if not specified)
*/
this(Module modulle, CompilerConfiguration config = CompilerConfiguration.defaultConfig())
{
this.modulle = modulle;
resolver = new Resolver(this);
this.config = config;
this.resolver = new Resolver(this);
this.meta = new MetaProcessor(this, true);
/* TODO: Module check?!?!? */
}
/**
* Returns the compiler configuration
*
* Returns: the `CompilerConfguration`
*/
public CompilerConfiguration getConfig()
{
return config;
}
/**
* I guess this should be called rather
* when processing assignments but I also
@ -2106,6 +2143,9 @@ public final class TypeChecker
*/
public void beginCheck()
{
/* Run the meta-processor on the AST tree (starting from the Module) */
meta.process(modulle);
/* Process all pseudo entities of the given module */
processPseudoEntities(modulle);

View File

@ -0,0 +1,413 @@
module tlang.compiler.typecheck.meta;
import tlang.compiler.symbols.data : Statement, TypedEntity, Function, FunctionCall, IdentExpression;
import tlang.compiler.symbols.expressions : Expression, IntegerLiteral, IntegerLiteralEncoding;
import tlang.compiler.symbols.typing.core;
import tlang.compiler.symbols.containers : Container;
import tlang.compiler.symbols.mcro;
import tlang.compiler.typecheck.core;
import gogga;
import std.conv : to;
import tlang.compiler.configuration;
/**
* The `MetaProcessor` is used to do a pass over a `Container`
* to process any macro and macro-like entities
*/
public class MetaProcessor
{
private TypeChecker tc;
private bool isMetaEnabled;
private CompilerConfiguration compilerConfig;
/**
* Constructs a new `MetaProcessor` for the purposes of
* modifying the AST tree before the typechecker traverses
* it
*
* Params:
* tc = the `TypeChecker` instance to process
* isMetaEnabled = `true` if to perform meta processing, otherwise `false`
*/
this(TypeChecker tc, bool isMetaEnabled)
{
this.tc = tc;
this.isMetaEnabled = isMetaEnabled;
this.compilerConfig = tc.getConfig();
}
/**
* Analyzes the provided `Container` and searches for any `Macro`-like
* parse-nodes to process
*/
public void process(Container container)
{
/* Only apply meta-processing if enabled */
if(!isMetaEnabled)
{
return;
}
/* Get all statements */
Statement[] stmts = container.getStatements();
foreach(Statement curStmt; stmts)
{
gprintln("MetaProcessor: Examining AST node '"~curStmt.toString()~"'...");
// Perform replacement of all type alises to concrete types, such as `size_t`
doTypeAlias(container, curStmt);
/**
* Search for any `sizeof(<ident_type>)` expressions
* and replace them with a `NumberLiteral`
*/
if(cast(MStatementSearchable)curStmt && cast(MStatementReplaceable)curStmt)
{
MStatementSearchable searchableStmt = cast(MStatementSearchable)curStmt;
Statement[] foundStmts = searchableStmt.search(FunctionCall.classinfo);
gprintln("Nah fr");
foreach(Statement curFoundStmt; foundStmts)
{
FunctionCall curFuncCall = cast(FunctionCall)curFoundStmt;
if(curFuncCall.getName() == "sizeof")
{
gprintln("Elo");
Expression[] arguments = curFuncCall.getCallArguments();
if(arguments.length == 1)
{
IdentExpression potentialIdentExp = cast(IdentExpression)arguments[0];
if(potentialIdentExp)
{
string typeName = potentialIdentExp.getName();
IntegerLiteral replacementStmt = sizeOf_Literalize(typeName);
gprintln("sizeof: Replace '"~curFoundStmt.toString()~"' with '"~replacementStmt.toString()~"'");
/* Traverse down from the `Container` we are process()'ing and apply the replacement */
MStatementReplaceable containerRepl = cast(MStatementReplaceable)container;
containerRepl.replace(curFoundStmt, replacementStmt);
}
else
{
// TODO: Throw an exception here that an ident_type should be present as the argument
gprintln("The argument to `sizeof` should be an ident", DebugType.ERROR);
}
}
else
{
// TODO: Throw an exception here as only 1 argument is allowed
gprintln("To use the `sizeof` macro you require a single argument to be passed to it", DebugType.ERROR);
}
}
}
}
/**
* If the current statement is a Container then recurse
*
* This will help us do the following:
*
* 1. Type re-writing of
* a. Functions (Parameters and Body as both make up its Statement[])
*/
if(cast(Container)curStmt)
{
process(cast(Container)curStmt);
}
}
}
/**
* Re-writes the types for things such as `size_t`, `ssize_t` and so forth
*
* Params:
* statement = the `MTypeRewritable` to apply re-writing to
*/
private void typeRewrite(MTypeRewritable statement)
{
/* Applies re-write to Variable's declared type and Function's return type */
string type = statement.getType();
/* Only re-write if type alias */
if(isTypeAlias(type))
{
/* Get the concrete type of `type` */
string concreteType = getConcreteType(type);
/* Rewrite the type */
statement.setType(concreteType);
}
}
/**
* Performs the replacement of type alieses such as `size_t`, `ssize_t`
* and so forth with their concrete type
*
* Params:
* container = the current `Container` being processsed
* curStmt = the current `Statement` to consider
*/
private void doTypeAlias(Container container, Statement curStmt)
{
/**
* Apply type-rewriting to any `MTypeRewritable` AST node
* (a.k.a. a node which contains a type and can have it set)
*
* NOTE: This is just for the "type" fields in AST nodes,
* we should have some full recursive re-writer.
*
* An example of why is for supporting something like:
*
* `sizeof(size_t)` <- currently is not supported by this
*/
if(cast(MTypeRewritable)curStmt)
{
typeRewrite(cast(MTypeRewritable)curStmt);
}
/**
* Here we will also search for any `IdentExpression`
* which contains `size_t`, `ssize_t` etc. and replace
* them
*/
if(cast(MStatementSearchable)curStmt && cast(MStatementReplaceable)curStmt)
{
MStatementSearchable searchableStmt = cast(MStatementSearchable)curStmt;
IdentExpression[] foundStmts = cast(IdentExpression[])searchableStmt.search(IdentExpression.classinfo);
// TODO: Implement me
// gprintln("IdentExpressions found: "~to!(string)(foundStmts));
/**
* Loop through all `IdentExpression`s and find any
* occurence of `size_t`/`ssize_t` and replace those
* with the concrete type
*/
foreach(IdentExpression identExp; foundStmts)
{
string identName = identExp.getName();
/* Determine if this is a type alias? */
if(isTypeAlias(identName))
{
// Determine the concrete type
string concereteType = getConcreteType(identName);
gprintln("Found type alias '"~identName~"' which concretely is '"~concereteType~"'");
// Replace with concrete type
container.replace(identExp, new IdentExpression(concereteType));
}
}
}
}
private IntegerLiteral sizeOf_Literalize(string typeName)
{
IntegerLiteral literal = new IntegerLiteral("TODO_LITERAL_GOES_HERESIZEOF_REPLACEMENT", IntegerLiteralEncoding.UNSIGNED_INTEGER);
// TODO: Via typechecker determine size with a lookup
Type type = tc.getType(tc.getModule(), typeName);
/* Calculated type size */
ulong typeSize = 0;
/**
* Calculate stack array size
*
* Algo: `<componentType>.size * stackArraySize`
*/
if(cast(StackArray)type)
{
StackArray stackArrayType = cast(StackArray)type;
ulong arrayLength = stackArrayType.getAllocatedSize();
Type componentType = stackArrayType.getComponentType();
ulong componentTypeSize = 0;
// FIXME: Later, when the Dependency Genrator supports more advanced component types,
// ... we will need to support this - for now assume that `componentType` is primitive
if(cast(Number)componentType)
{
Number numberType = cast(Number)componentType;
componentTypeSize = numberType.getSize();
}
typeSize = componentTypeSize*arrayLength;
}
/**
* Calculate the size of `Number`-based types
*/
else if(cast(Number)type)
{
Number numberType = cast(Number)type;
typeSize = numberType.getSize();
}
// TODO: We may eed toupdate Type so have bitwidth or only do this
// for basic types - in which case I guess we should throw an exception
// here.
// ulong typeSize =
/* Update the `Sizeof` kind-of-`IntegerLiteral` with the new size */
literal.setNumber(to!(string)(typeSize));
return literal;
}
/**
* Transforms the type alias into its concrete type.
*
* This method incorporates defensive programming in
* that it will only apply the transformation IF
* the provided type alias is infact a type alias,
* otherwise it performs an identity transformation
* and returns the "alias" untouched.
*
* Params:
* typeAlias = the potential type alias
* Returns: the concrete type, or `typeAlias` if
* not an alias
*/
private string getConcreteType(string typeAlias)
{
/* Check if this is a system type alias? If so, transform */
if(isSystemType(typeAlias))
{
return getSystemType(typeAlias);
}
// TODO: Add user-defined type alias support here
/* Else, return the "alias" untouched */
else
{
return typeAlias;
}
}
/**
* Determines if the given type is a type alias.
*
* Params:
* typeAlias = the type to check
* Returns: `true` if it is an alias, `false` otherwise
*/
private bool isTypeAlias(string typeAlias)
{
/* If this a system type alias? */
if(isSystemType(typeAlias))
{
return true;
}
// TODO: Support for user-defined type aliases
/* Otherwise, not a type alias */
else
{
return false;
}
}
/**
* Determines if the given type is a system type alias
*
* Params:
* typeAlias = the type to check
* Returns: `true` if system type alias, `false` otherwise
*/
private bool isSystemType(string typeAlias)
{
/* `size_t`/`ssize_t` system type aliases */
if(typeAlias == "size_t" || typeAlias == "ssize_t")
{
return true;
}
/* Else, not a system type alias */
else
{
return false;
}
}
/**
* Given a type alias (think `size_t`/`ssize_t` for example) this will
* look up in the compiler's configuration what that size should be
* resolved to
*
* Params:
* typeAlias = the system type alias to lookup
* Returns: the concrete type
*/
private string getSystemType(string typeAlias)
{
/* Determine machine's width */
ulong maxWidth = compilerConfig.getConfig("types:max_width").getNumber();
string maxType;
if(maxWidth == 1)
{
if(typeAlias == "size_t")
{
return "ubyte";
}
else if(typeAlias == "ssize_t")
{
return "byte";
}
else
{
assert(false);
}
}
else if(maxWidth == 2)
{
if(typeAlias == "size_t")
{
return "ushort";
}
else if(typeAlias == "ssize_t")
{
return "short";
}
else
{
assert(false);
}
}
else if(maxWidth == 4)
{
if(typeAlias == "size_t")
{
return "uint";
}
else if(typeAlias == "ssize_t")
{
return "int";
}
else
{
assert(false);
}
}
else if(maxWidth == 8)
{
if(typeAlias == "size_t")
{
return "ulong";
}
else if(typeAlias == "ssize_t")
{
return "long";
}
else
{
assert(false);
}
}
else
{
assert(false);
}
}
}

View File

@ -0,0 +1,6 @@
module simple_meta_replace;
void function()
{
discard repr;
}

View File

@ -0,0 +1,7 @@
module meta_sizeof;
size_t myVar1 = sizeof(uint);
size_t myVar2 = sizeof(ubyte);
size_t myVar3 = sizeof(ushort)+1;
myVar3 = sizeof(ulong)+sizeof(size_t);

View File

@ -0,0 +1,3 @@
module simple_template_type_def;
generic T;

View File

@ -0,0 +1,8 @@
module meta_types;
size_t myVar = 1;
size_t function(size_t param1)
{
return 1UL+myVar;
}