-
Notifications
You must be signed in to change notification settings - Fork 211
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
Add back declarative macro definition forms #516
Comments
How about "destructuring" syntax templates: syntax new = function (ctx) {
return match (ctx) {
case #`new ${ ident } ${ params }` => #`${ ident }.create ${ params }`
}
};
syntax let = function (ctx) {
return match (ctx) {
case #`let ${ ident } = ${ init : AssignmentExpression } ${ ...rest }` => #`
(function (${ ident }) {
${ ...rest }
})(${ init })
`
}
}; It's a little more verbose, but has nice symmetry with the current syntax template literals and es2015+ destructuring assignments. Perhaps this could be an option: syntax new = (#`new ${ ident } ${ params }`) => #`${ ident }.create ${ params }`; |
I have a port of Clojure threading macros in mind: syntaxrec threadFirst = ctx => {
const inner = ctx.next().value.inner();
let args, call;
match (inner) {
case #`(${ val }) { ${ ident } (${ args }) ${ ...rest } }` => {
args = #`${ val }, ${ ...args }`;
call = #`${ ident }(${ args })`;
}
case #`(${ val }) { ${ ident } ${ ...rest } }` => {
call = #`${ ident }(${ val })`;
}
}
return rest.isEmpty() ? call : #`threadFirst (${ call }) { ${ ...rest } }`;
}
const inc = x => x + 1;
const mult = (x, y) => x * y;
const div = (x, y) => x / y;
threadFirst (2) { inc mult(3) inc div(5) } // 2 |
I'm currently blocked on #519. In the meantime, I've got a question about semantics: let #`1 + ${a} - ${b}` = #`1 + 2 - 3`; // let a = #`2`, b = #`3`
let #`1 + ${c} - 3 + ${d}` = #`1 + 2 - 4 + 5`; // let c = #`2`, d = undefined
let #`1 + ${e} - ${f} + 4` = #`1 + 2 - 3 + 5`; // let e = #`2`, f = ? Should OTOH I was hoping matching could be naively implemented by checking that all of the placeholder variables point to a value. |
Humm...why doesn't the second and third cases just throw a "failed to match" error? |
Yeah. I guess for destructuring values shouldn't be allowed on the LHS. It would be an Unexpected token error if I tried that w/ objects or arrays. So destructuring only makes sense if just placeholders are present in the LHS template: let #`${a} ${b} ${c}` = #`(1 + 2) * 3`; // let a = #`(1 + 2)`, b = #`*`, c = #`3` And I suppose nested destructuring takes the analogy too far? let #`${ #`${a} ${b} ${c}` }` = #`(1 + 2)`; // let a = #`1`, b = #`+`, c = #`2` |
I'm thinking about this again and I have some ideas: const BindingElement = ctx => match(ctx) {
// isPunctuator(,) - consumes a ',' if it exists and is a Punctuator returning true or false
// comma? - comma is optional. if it isn't present ctx is reset to right before that point
// BindingTarget - call functions with those names w/ ctx as the argument
#`${binding: BindingTarget} = ${init: Expression} ${comma?: isPunctuator(,)}` => new T.BindingWithDefault({ binding, init })
#`${binding: BindingTarget} ${comma?: isPunctuator(,)}` => binding
};
const FormalParameters = ctx => match(ctx) {
#`()` => new T.FormalParameters({ items: List() })
#`(...${rest: BindingIdentifier})` => new T.FormalParameters({ items: List(), rest })
// ...items calls BindingIdentifier repeatedly and returns a List
#`(${...items: BindingElement} ...${rest: BindingIdentifier})` => new T.FormalParameters({ items, rest })
#`(${...items: BindingElement})` => new T.FormalParamters({ items })
};
function BindingTarget(ctx) {
return match(ctx) {
#`${name: Identifier}` => new T.BindingIdentifier({ name })
#`[]` => new T.ArrayBinding({ elements: List() })
#`[...${rest: BindingTarget}]` => T.ArrayBinding({ elements: List(), rest })
#`[${...elements: BindingElement} ...${rest: BindingTarget}]` => new T.ArrayBinding({ elements, rest })
#`[${...elements: BindingElement}]` => new T.ArrayBinding({ elements })
#`{}` => new T.ObjectBinding({ properties: List() })
#`{${...properties: BindingProperty}}` => new T.ObjectBinding({ properties })
};
}
syntax function = ctx => match(ctx) {
#`${star?: isPunctuator(*)} ${name?: BindingIdentifier} ${params: FormalParameters} ${body: Statement}` =>
new T.FunctionExpression({ name, isGenerator: star, params, body });
}; I don't intend to implement the enforester as a bunch of macros. This is just to show the features I have in mind. Though we could have the |
Yeah, I think I really like this. |
The declarative syntax was to me the biggest selling point of sweetjs. I understand there is obviously a lot of work that has to be done to the core in order to add this back. I was just wondering if a declarative syntax still in the works? Is there a list somewhere of what needs to be accomplished before it can be added back in? |
@jimmyhmiller I actually don't think there's anything holding this back. In fact I don't think we even need to do this in core since |
0.7.8 is still available and it works great. |
Version 1.0 only comes with primitive syntax transformer forms which is obviously not great for everyday use. Some initial syntax thoughts for a more declarative form:
This should happen after #378 and
import ... for macros
lands so the matching can just be a library.The text was updated successfully, but these errors were encountered: