Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lambda syntax #5

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
44 changes: 44 additions & 0 deletions t/advanced/10lambda.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#! winxed

// Tests for lambda -> syntax

using extern Test.More plan, is;

function main[main]()
{
plan(13);

// Defining basic lambdas, assinging to variables
var f1 = -> { return 4; };
is(f1(), 4);

var f2 = -> 4;
is(f2(), 4);

// Lambdas with arguments
var f3 = ->(int x) { return x + 1; };
is(f3(4), 5);

var f4 = ->(int x) x + 1;
is(f4(4), 5);

// Inline definition and call
is((-> { return 5; })(), 5);
is((-> 5)(), 5);
is((->(int x) { return x + 1; })(4), 5);
is((->(int x) x + 1)(4), 5);

// Lambdas returning lambdas
var f5 = -> { return -> { return 5; }; };
is(f5()(), 5);

var f6 = -> -> 5;
is(f6()(), 5);

is((-> -> 5)()(), 5);

// Lambdas as arguments to functions and lambdas
var f7 = ->(f7_inner) { return f7_inner(); };
is(f7(-> { return 5; }), 5);
is(f7(-> 5), 5);
}
47 changes: 47 additions & 0 deletions t/advanced/10lambda_y_comb.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#! winxed

// Tests for closures and lambdas, using Y-combinators as an example

using extern Test.More plan, is;

// "normal" Y-combinator using function syntax
function Y(outer)
{
return (function(func) {
return func(func);
})(function(func) {
return outer(function(arg) {
return func(func)(arg);
});
});
}

// Y-combinator written with lambdas
function Y_lambda(var outer) {
return (->(func) func(func))(->(func) outer(->(arg) func(func)(arg)));
}

// Naive recursive implementation of a factorial
function factorial_recursive(int n)
{
return n == 0 ? 1 : n * int(factorial_recursive(n - 1));
}

function main()
{
plan(5);
is(factorial_recursive(6), 720, "recursive factorial gives correct results");

var factorial_y = function(var func) {
return function(int n) {
return n == 0 ? 1 : n * int(func(n - 1));
};
};
var lambda_fact = ->(func) ->(int n) n == 0 ? 1 : n * int(func(n - 1));

is(Y(factorial_y)(6), 720, "Normal Y(factorial) works");
is(Y_lambda(factorial_y)(6), 720, "Y_lambda(factorial) works");

is(Y(lambda_fact)(6), 720, "Y(lambda_fact) works");
is(Y_lambda(lambda_fact)(6), 720, "Y_lambda(lambda_fact) works");
}
88 changes: 80 additions & 8 deletions winxedst1.winxed
Original file line number Diff line number Diff line change
Expand Up @@ -654,7 +654,7 @@ class Tokenizer
':': getop
},
'+': { '+': getop, '=': getop },
'-': { '-': getop, '=': getop },
'-': { '-': getop, '=': getop, '>': getop },
'*': { '=': getop },
'|': { '|': getop },
'&': { '&': getop },
Expand Down Expand Up @@ -2867,10 +2867,14 @@ class FunctionExpr : Expr
function FunctionExpr(tk, owner, start)
{
self.Expr(owner, start);
var t = tk.get();
if (!t.isop('('))
Expected('anonymous function', t);
self.fn = new LocalFunctionStatement(start, tk, owner);
if (start.isop('->')) {
self.fn = new LambdaFunctionStatement(start, tk, owner);
} else {
var t = tk.get();
if (!t.isop('('))
Expected('anonymous function', t);
self.fn = new LocalFunctionStatement(start, tk, owner);
}
}
function checkresult() { return REGvar; }
function optimize()
Expand Down Expand Up @@ -5401,7 +5405,7 @@ class CallExpr : Expr
call = sym.emit_get(e, self);
break;
case sym instanceof Builtin:
InternalError("Builtin unexpeted here", self);
InternalError("Builtin unexpected here", self.start);
default:
call = join("", [ "'", funref.getName(), "'" ] );
}
Expand Down Expand Up @@ -6505,6 +6509,8 @@ function parseExpr_0(tk, owner)
return parseNew(tk, owner, t);
case t.iskeyword('function'):
return new FunctionExpr(tk, owner, t);
case t.isop('->'):
return new FunctionExpr(tk, owner, t);
case t.iskeyword('class'):
return new OpClassExpr(tk, owner, t);
case t.isidentifier():
Expand Down Expand Up @@ -6920,7 +6926,7 @@ class ReturnYieldStatement : Statement
{
var values = self.values;
if (values != null)
values = values.optimize();
self.values = values.optimize();
return self;
}
function emit(e)
Expand Down Expand Up @@ -6961,6 +6967,39 @@ class ReturnStatement : ReturnYieldStatement
}
}

class SimpleReturnStatement : ReturnStatement
{
function SimpleReturnStatement(start, tk, owner)
{
self.Statement(start, owner);
self.values = parseExpr(tk, owner);
}

function emit(e)
{
// Experimental tailcall optimization
var value = self.values;
if (value.cantailcall()) {
self.annotate(e);
return value.emit(e, '.tailcall');
}

string reg;
if (value.isnull()) {
string pnull = self.owner.tempreg(REGvar);
e.emitnull(pnull);
reg = pnull;
}
else
reg = value.emit_get(e);

self.annotate(e);
self.emitret(e);
e.print(reg);
e.say(')');
}
}

class YieldStatement : ReturnYieldStatement
{
function YieldStatement(start, tk, owner)
Expand Down Expand Up @@ -8830,7 +8869,10 @@ class FunctionBase : BlockStatement
else {
e.comment('Body');
body.emit(e);
e.annotate(body.getend());
int can_getend = 0;
${ can can_getend, body, "getend" };
if (can_getend)
e.annotate(body.getend());
}
e.say("\n.end # ", name, "\n");

Expand Down Expand Up @@ -8993,6 +9035,36 @@ class LocalFunctionStatement : FunctionBase
}
}

//*********************************************
// LambdaFunctionStatement
//*********************************************

class LambdaFunctionStatement : LocalFunctionStatement
{
function LambdaFunctionStatement(start, tk, owner)
{
self.FunctionBase(start, owner);
self.outer = owner.getouter();
self.outer.makesubid();
var subid = self.makesubid();
self.name = subid;
var t = tk.get();
if (t.isop('(')) {
self.parse_parameters(tk);
t = tk.get();
} else
self.params = [];

if (t.isop('{'))
self.body = new CompoundStatement(t, tk, self);
else {
tk.unget(t);
self.body = new SimpleReturnStatement(t, tk, self);
}
owner.addlocalfunction(self);
}
}

//*********************************************
// MethodStatement
//*********************************************
Expand Down