lojikil / coastML

a tiny experimental ML dialect combining Yeti & CarML
ISC License
12 stars 0 forks source link

syntactic ambiguity #8

Closed lojikil closed 1 year ago

lojikil commented 1 year ago

I just realized there's a pretty interesting ambiguity in the syntax, mostly around defining functions vs applying anonymous functions. Witness:

f = fn x y {
x + y
};
g = fn x y {
x + y
} 10 11;

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 impact fc, 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.

lojikil commented 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.

lojikil commented 1 year ago

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.

lojikil commented 1 year ago

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.

lojikil commented 1 year ago

(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)

lojikil commented 1 year ago

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())