From 206959adbd99ce74ef2b50e8ff484b78aaf8b942 Mon Sep 17 00:00:00 2001 From: Juraj Kirchheim Date: Wed, 26 Sep 2018 14:06:16 +0200 Subject: [PATCH] Support new function type syntax. (#74) --- Test.hx | 4 +++ hscript/Expr.hx | 2 ++ hscript/Macro.hx | 5 ++++ hscript/Parser.hx | 63 ++++++++++++++++++++++++++++++++++++++++------ hscript/Printer.hx | 18 +++++++++++++ 5 files changed, 85 insertions(+), 7 deletions(-) diff --git a/Test.hx b/Test.hx index ea5962a..63a4533 100644 --- a/Test.hx +++ b/Test.hx @@ -105,6 +105,10 @@ class Test extends TestCase { assertScript("var f = (x,y) -> x + y; f(3,1)", 4); assertScript("var f = (x,y:Int) -> x + y; f(3,1)", 4); assertScript("var f = (x:Int,y:Int) -> x + y; f(3,1)", 4); + assertScript("var f:Int->Int->Int = (x:Int,y:Int) -> x + y; f(3,1)", 4, null, true); + assertScript("var f:(x:Int, y:Int)->Int = (x:Int,y:Int) -> x + y; f(3,1)", 4, null, true); + assertScript("var f:(x:Int)->(y:Int, z:Int)->Int = (x:Int) -> (y:Int, z:Int) -> x + y + z; f(3)(1, 2)", 6, null, true); + assertScript("var f:(x:Int)->(Int, Int)->Int = (x:Int) -> (y:Int, z:Int) -> x + y + z; f(3)(1, 2)", 6, null, true); } function testMap():Void { diff --git a/hscript/Expr.hx b/hscript/Expr.hx index 42536d3..bc02042 100644 --- a/hscript/Expr.hx +++ b/hscript/Expr.hx @@ -81,6 +81,8 @@ enum CType { CTFun( args : Array, ret : CType ); CTAnon( fields : Array<{ name : String, t : CType, ?meta : Metadata }> ); CTParent( t : CType ); + CTOpt( t : CType ); + CTNamed( n : String, t : CType ); } #if hscriptPos diff --git a/hscript/Macro.hx b/hscript/Macro.hx index 6a7125f..e68360b 100644 --- a/hscript/Macro.hx +++ b/hscript/Macro.hx @@ -113,6 +113,7 @@ class Macro { function convertType( t : Expr.CType ) : ComplexType { return switch( t ) { + case CTOpt(t): TOptional(convertType(t)); case CTPath(pack, args): var params = []; if( args != null ) @@ -127,6 +128,10 @@ class Macro { case CTParent(t): TParent(convertType(t)); case CTFun(args, ret): TFunction(map(args,convertType), convertType(ret)); + #if (haxe_ver >= 4) + case CTNamed(name, ct): + TNamed(name, convertType(ct)); + #end case CTAnon(fields): var tf = []; for( f in fields ) { diff --git a/hscript/Parser.hx b/hscript/Parser.hx index 10e5646..00e3ba1 100644 --- a/hscript/Parser.hx +++ b/hscript/Parser.hx @@ -794,8 +794,7 @@ class Parser { } } - function parseFunctionDecl() { - ensure(TPOpen); + function parseFunctionArgs() { var args = new Array(); var tk = token(); if( tk != TPClose ) { @@ -831,10 +830,16 @@ class Parser { unexpected(tk); } } - } + } + return args; + } + + function parseFunctionDecl() { + ensure(TPOpen); + var args = parseFunctionArgs(); var ret = null; if( allowTypes ) { - tk = token(); + var tk = token(); if( tk != TDoubleDot ) push(tk); else @@ -894,9 +899,53 @@ class Parser { } return parseTypeNext(CTPath(path, params)); case TPOpen: - var t = parseType(); - ensure(TPClose); - return parseTypeNext(CTParent(t)); + var a = token(), + b = token(); + + push(b); + push(a); + + function withReturn(args) { + switch token() { // I think it wouldn't hurt if ensure used enumEq + case TOp('->'): + case t: unexpected(t); + } + + return CTFun(args, parseType()); + } + + switch [a, b] { + case [TPClose, _] | [TId(_), TDoubleDot]: + + var args = [for (arg in parseFunctionArgs()) { + switch arg.value { + case null: + case v: + error(ECustom('Default values not allowed in function types'), #if hscriptPos v.pmin, v.pmax #else 0, 0 #end); + } + + CTNamed(arg.name, if (arg.opt) CTOpt(arg.t) else arg.t); + }]; + + return withReturn(args); + default: + + var t = parseType(); + return switch token() { + case TComma: + var args = [t]; + + while (true) { + args.push(parseType()); + if (!maybe(TComma)) break; + } + ensure(TPClose); + withReturn(args); + case TPClose: + parseTypeNext(CTParent(t)); + case t: unexpected(t); + } + } case TBrOpen: var fields = []; var meta = null; diff --git a/hscript/Printer.hx b/hscript/Printer.hx index 8bd1c47..07f8787 100644 --- a/hscript/Printer.hx +++ b/hscript/Printer.hx @@ -48,6 +48,9 @@ class Printer { function type( t : CType ) { switch( t ) { + case CTOpt(t): + add('?'); + type(t); case CTPath(path, params): add(path.join(".")); if( params != null ) { @@ -59,6 +62,21 @@ class Printer { } add(">"); } + #if (haxe_ver >= 4) + case CTNamed(name, t): + add(name); + add(':'); + type(t); + case CTFun(args, ret) if (Lambda.exists(args, function (a) return a.match(CTNamed(_, _)))): + add('('); + for (a in args) + switch a { + case CTNamed(_, _): type(a); + default: type(CTNamed('_', a)); + } + add(')->'); + type(ret); + #end case CTFun(args, ret): if( args.length == 0 ) add("Void -> ");