Closed lojikil closed 1 year ago
Part of me doesn't really like this, because it means that the thing that determines an anonymous function call or not is whether or not something is immediately terminated by a ;
, and I've tended to prefer that things should be clear from the get go. we could add a def
form, but I'm not super thrilled about that either; it could be fun ... nuf
and match how gn
works, and that would mean anonymous functions are just fn
.
I should note, I saw the general case of this previously in parsing call forms; it's why we actually end up parsing a call and then if it's a single object returning that rather than a call AST... basically heading down the same route, but it makes thinking about easier in some ways.
also, I'm sorta loving the StandardML style now that I think about it:
fun foo 10 = 10
| foo 11 = 11
| foo n = n + 1
nuf
it allows us to get something like the case lambda form of fc
without having to do much more, and it feels like a real ambiguity win for beginners.
(the foo = fn ...
form would of course still stay, I just meant for most people it's a clear syntactic delineation in the lexeme stream)
As a note, I added a test for this in the self-hosting compiler, and it correctly compiles the two cases, so closing this at least. Also note that the self-hosting compiler will have support for the fun
form shortly as well.
a = fn x is int y { x + y; };
SandCityAST_Assignment(m_0=IdentType_Ident(m_0='a'), m_1=SandCityAST_FnBody(m_0=SandCityAST_ParameterArray(m_0=[SandCityAST_Declare(m_0=IdentType_Ident(m_0='x'), m_1=SandCityAST_IntT()), IdentType_Ident(m_0='y')]), m_1=SandCityAST_Block(m_0=[SandCityAST_OpCall(m_0=IdentType_Ident(m_0='+'), m_1=[IdentType_Ident(m_0='x'), IdentType_Ident(m_0='y')])])), m_2=SandCityAST_Unit())
f = fn x y { x + y; } 10 20;
SandCityAST_Assignment(m_0=IdentType_Ident(m_0='f'), m_1=SandCityAST_FunCall(m_0=SandCityAST_FnBody(m_0=SandCityAST_ParameterArray(m_0=[IdentType_Ident(m_0='x'), IdentType_Ident(m_0='y')]), m_1=SandCityAST_Block(m_0=[SandCityAST_OpCall(m_0=IdentType_Ident(m_0='+'), m_1=[IdentType_Ident(m_0='x'), IdentType_Ident(m_0='y')])])), m_1=[SandCityAST_Integer(m_0=IntType_Int(), m_1='10'), SandCityAST_Integer(m_0=IntType_Int(), m_1='20')]), m_2=SandCityAST_Unit())
I just realized there's a pretty interesting ambiguity in the syntax, mostly around defining functions vs applying anonymous functions. Witness:
Technically, the first is a function definition and the second is the application of a function, but we can't tell that until we get to the next token. It's still LL(1), but it's an interesting case I hadn't considered. Also, this does not impact
gn
, but does impactfc
, because of how they are syntactically defined, which is neat. I'll leave this issue open to stew on how I might want to handle that.