Skip to content

Commit

Permalink
Add __CALLER__ expression. When used as a default value, it will be s…
Browse files Browse the repository at this point in the history
…et to the location of the caller.

Also remove the requirement that neat.base is imported when using __RANGE__.
  • Loading branch information
FeepingCreature committed Nov 12, 2023
1 parent 401ddb2 commit d4ec082
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 29 deletions.
6 changes: 4 additions & 2 deletions src/neat/base.nt
Original file line number Diff line number Diff line change
Expand Up @@ -848,7 +848,7 @@ struct Parameter

Type type;

nullable Expression defaultValue;
(nullable Expression | :callerRange) defaultValue;

LocRange locRange;

Expand Down Expand Up @@ -1182,6 +1182,8 @@ abstract class CompilerBase
abstract (nullable Symbol | fail Error) lookup(
Context context, LocRange locRange, LookupReason reason, string name);

abstract (Expression | fail Error) locRangeExpr(Context context, LocRange locRange);

abstract Statement assignStatement(Reference target, Expression value);

abstract Statement assignStatement(Reference target, Expression value, LocRange locRange);
Expand Down Expand Up @@ -1318,7 +1320,7 @@ abstract class FunctionDeclarationBase : Symbol

override bool mayCallImplicit() {
for (param in params)
if (!param.defaultValue)
if (param.defaultValue == null)
return false;
return true;
}
Expand Down
23 changes: 23 additions & 0 deletions src/neat/compiler.nt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module neat.compiler;
macro import package(compiler).std.macro.assert;
macro import package(compiler).std.macro.listcomprehension;
macro import package(compiler).std.macro.once;
macro import package(compiler).std.macro.quasiquoting;

import backend.base;
import neat.array;
Expand Down Expand Up @@ -776,6 +777,28 @@ class CompilerImpl : CompilerBase
return context.namespace.lookup(name, context, reason, locRange);
}

override (Expression | fail Error) locRangeExpr(Context context, LocRange locRange)
{
auto fileId = astNumberLiteral(locRange.fileId, __RANGE__);
auto fromRow = astNumberLiteral(locRange.from.row, __RANGE__);
auto fromCol = astNumberLiteral(locRange.from.column, __RANGE__);
auto toRow = astNumberLiteral(locRange.to.row, __RANGE__);
auto toCol = astNumberLiteral(locRange.to.column, __RANGE__);
if (context.namespace.lookup("LocRange", context, LookupReason.identifier, locRange)??) {
// we're using __RANGE__ in neat.base: don't import it again
return (this.$expr LocRange($fileId, ($fromRow, $fromCol), ($toRow, $toCol)))
.compile(context)?
.beExpression(__RANGE__)?;
} else {
return (this.$expr ({
import package(compiler).neat.base : LocRange;
LocRange($fileId, ($fromRow, $fromCol), ($toRow, $toCol));
}))
.compile(context)?
.beExpression(__RANGE__)?;
}
}

override Reference dereference(Expression value)
{
return new Dereference(value);
Expand Down
7 changes: 5 additions & 2 deletions src/neat/expr.nt
Original file line number Diff line number Diff line change
Expand Up @@ -568,8 +568,11 @@ enum CallQuality
mut bool withConv = false;
for (i, param in params) {
if (i >= args.length) {
if (auto defaultValue = param.defaultValue) {
finalArgs[i] = defaultValue;
// TODO
// if (auto defaultValue = param.defaultValue?) {
if (true) {
auto defaultValue = param.defaultValue.case(nullable Expression expr: expr.case(null: breakelse));
finalArgs[i] = defaultValue.case(:callerRange: context.compiler.locRangeExpr(context, locRange)?);
continue;
}
else return (:mismatch, locRange.fail("$(info)missing argument '$(param.name)'"));
Expand Down
24 changes: 23 additions & 1 deletion src/neat/function_.nt
Original file line number Diff line number Diff line change
Expand Up @@ -687,7 +687,25 @@ class LatentNestedFunction : LatentSymbol
override bool mayCallImplicit() => fun.mayCallImplicit;
}

/**
* When used as the default value in an argument list, will be resolved to the LocRange of the caller.
*/
class ASTCallerExpr : ASTSymbol
{
override (Symbol | fail Error) compile(Context context) {
return context.fail(this.locRange, "__CALLER__ can only used as default parameter");
}
override string repr() => "__CALLER__";
}

(Parameter | fail Error) compile(ASTParameter param, Context context) {
auto type = param.type.compile(context)?.beType(param.locRange)?;

if (param.defaultValue?.instanceOf(ASTCallerExpr)) {
return Parameter(isThisAssignment=false, param.name, param.mutable, type=type, defaultValue=:callerRange,
param.locRange);
}

(nullable Expression | fail Error) defaultValue(ASTParameter param, Type type) {
if (!param.defaultValue) return null;
auto context = context.withNamespace(findParent!ModuleBase(context.namespace));
Expand All @@ -696,13 +714,17 @@ class LatentNestedFunction : LatentSymbol
.beExpressionImplCall(context, param.locRange)?
.expectImplicitConvertTo(type, context, param.locRange)?;
}
auto type = param.type.compile(context)?.beType(param.locRange)?;
auto defaultValue = defaultValue(param, type)?;
return Parameter(isThisAssignment=false, param.name, param.mutable, type=type, defaultValue=defaultValue,
param.locRange);
}

(Parameter | fail Error) compile(ASTThisAssignment param, Type type, Context context) {
if (param.defaultValue?.instanceOf(ASTCallerExpr)) {
return Parameter(isThisAssignment=true, param.name, mutable=false, type=type, defaultValue=:callerRange,
param.locRange);
}

(nullable Expression | fail Error) defaultValue() {
if (!param.defaultValue) return null;
return param.defaultValue.compile(context)?
Expand Down
21 changes: 4 additions & 17 deletions src/neat/stuff.nt
Original file line number Diff line number Diff line change
Expand Up @@ -1715,23 +1715,7 @@ class ASTPrePostIncDec : ASTSymbol
class ASTLocRangeExpr : ASTSymbol
{
override (Symbol | fail Error) compile(Context context) {
with (context.compiler) {
auto fileId = astNumberLiteral(locRange.fileId, __RANGE__);
auto fromRow = astNumberLiteral(locRange.from.row, __RANGE__);
auto fromCol = astNumberLiteral(locRange.from.column, __RANGE__);
auto toRow = astNumberLiteral(locRange.to.row, __RANGE__);
auto toCol = astNumberLiteral(locRange.to.column, __RANGE__);
if (context.namespace.lookup("LocRange", context, LookupReason.identifier, this.locRange)??) {
// we're using __RANGE__ in neat.base: don't import it again
return (context.compiler.$expr LocRange($fileId, ($fromRow, $fromCol), ($toRow, $toCol)))
.compile(context);
} else {
return (context.compiler.$expr ({
import package(compiler).neat.base : LocRange;
LocRange($fileId, ($fromRow, $fromCol), ($toRow, $toCol));
})).compile(context);
}
}
return context.compiler.locRangeExpr(context, this.locRange);
}
override string repr() => "__RANGE__";
}
Expand Down Expand Up @@ -1763,6 +1747,9 @@ class ASTLocRangeExpr : ASTSymbol
parser.pinned = true;
return new ASTLocRangeExpr(parser.to(from));
}
if (name == "__CALLER__") {
return new ASTCallerExpr(parser.to(from));
}
if (name == "super") return new ASTSuper(parser.to(from));
return new ASTIdentifier(name, false, parser.to(from));
}
Expand Down
10 changes: 3 additions & 7 deletions test/runnable/here.nt
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,7 @@ void main() {
test;
}

void test(LocRange range = __RANGE__) {
// But these are wrong!
// As opposed to D, it uses the range of the *callee*, not the caller.
// I'm not sure what to do about this though. It's doing the right thing,
// just not the thing I wanted.
assert(range.(from.(row == 15 && column == 27)
&& to.(row == 15 && column == 36)));
void test(LocRange range = __CALLER__) {
assert(range.(from.(row == 12 && column == 4)
&& to.(row == 12 && column == 8)));
}

0 comments on commit d4ec082

Please sign in to comment.