1. Introduction
This is the reference document for Sweet.js. For a gentle explaination of Sweet’s concepts see the tutorial.
2. Command Line API
-
--out-file <file>
: write result to file -
--out-dir <dir>
: write result to directory -
--no-babel
: do not use babel backend
3. Binding Forms
3.1. syntax
syntax <name> = <init>
Bind <name>
to the result of evaluating <init>
in the compiletime environment. Scoping follows let
(i.e. block scoped with a temporal dead zone).
If the result of evaluating <init>
is a function, then the result is a syntax transformer.
4. Syntax Transformer
transformer : (TransformerContext) -> List(Syntax)
A syntax transformer is a function bound to a compile-time name. A syntax transformer is invoked with a transformer context that provides access to the syntax at the call-site and returns a list of syntax objects.
4.1. Transformer Context
A transformer context is an iterable object that provides access to syntax at the call-site of a syntax transformer.
TransformerContext = { name: () -> Syntax next: () -> { done: boolean, value: Syntax } expand: (string) -> { done: boolean, value: Syntax } mark: () -> Marker reset: (Marker?) -> undefined }
Each call to next
returns the syntax object following the transformer call.
A call to expand
initiates expansion at the current state of the iterator and matches the specified grammar production. Matching is "greedy" so expand('expr')
with the syntax 1 + 2
matches the entire binary expression rather than just 1
. The following productions are accepted by expand
:
-
Statement
with aliasstmt
-
AssignmentExpression
with aliasexpr
-
Expression
-
BlockStatement
-
WhileStatement
-
IfStatement
-
ForStatement
-
SwitchStatement
-
BreakStatement
-
ContinueStatement
-
DebuggerStatement
-
WithStatement
-
TryStatement
-
ThrowStatement
-
ClassDeclaration
-
FunctionDeclaration
-
LabeledStatement
-
VariableDeclarationStatement
-
ReturnStatement
-
ExpressionStatement
-
YieldExpression
-
ClassExpression
-
ArrowExpression
-
NewExpression
-
ThisExpression
-
FunctionExpression
-
IdentifierExpression
-
LiteralNumericExpression
-
LiteralInfinityExpression
-
LiteralStringExpression
-
TemplateExpression
-
LiteralBooleanExpression
-
LiteralNullExpression
-
LiteralRegExpExpression
-
ObjectExpression
-
ArrayExpression
-
UnaryExpression
-
UpdateExpression
-
BinaryExpression
-
StaticMemberExpression
-
ComputedMemberExpression
-
AssignmentExpression
-
CompoundAssignmentExpression
-
ConditionalExpression
The name()
method returns the syntax object of the macro name at the macro invocation site. This is useful[1] because it allows a macro transformer to get access to the lexical context at the invocation site.
A call to mark
returns a pointer to the current state of the iterator.
Calling reset
with no arguments returns the context to its initial state, while passing a Marker instance returns the context to the state pointed to by the marker.
syntax m = function (ctx) {
ctx.expand('expr');
ctx.reset();
const a = ctx.next().value;
ctx.next();
const marker = ctx.mark();
ctx.expand('expr');
ctx.reset(marker);
const b = ctx.next().value;
return #`${a} + ${b} + 24`; // 30 + 42 + 24
}
m 30 + 42 + 66
5. Syntax Objects
Syntax objects represent the syntax from the source program. Syntax objects have a number of methods to inspect their contents and construct new syntax object.
5.1. val
Syntax.prototype.val() -> string?
Returns a nullable value representing the textual value of the syntax object. For example, the .val()
of the identifier foo
is the string "foo"
. Some syntax objects (in particular delimiters) do not have a reasonable representation of their syntax and so .val()
returns null
in these cases.
syntax m = ctx => {
let id = ctx.next().value;
let delim = ctx.next().value;
id.val() === 'foo'; // true
delim.val() === null; // true
// ...
}
m foo (1)
5.2. lineNumber
Syntax.prototype.lineNumber() -> number
Returns the original line number for this syntax object.
5.3. inner
Syntax.prototype.inner() -> TransformerContext
If the syntax object is a delimiter, returns a transformer context iterator into the delimiter. Otherwise, throw an exception.
syntax m = ctx => {
let delim = ctx.next().value;
var arr = [];
for (let item of delim.inner()) {
arr.push(item);
}
return #`[${arr}]`;
}
m {
1, 2, 3
}
5.4. from
Syntax.prototype.from(type, value) -> Syntax
type : string
value : any
Construct a new syntax object from the provided type
and value
using the instance syntax object’s lexical context. Valid types are:
-
'null'
-
'number'
-
'string'
-
'punctuator'
-
'keyword'
-
'identifier'
-
'regularExpression'
-
'braces'
-
'brackets'
-
'parens'
Note
|
Be careful which syntax object you use to create a new syntax object via
You may be tempted to reuse the syntax object provided by |
5.5. fromNull
Syntax.prototype.fromNull() -> Syntax
Creates a null literal with the instance syntax object’s lexical context.
syntax m = ctx => {
let dummy = #`dummy`.get(0);
return #`${dummy.fromNull()}`;
}
m
null
5.6. fromNumber
Syntax.prototype.fromNumber(value) -> Syntax
value : number
Creates a numeric literal matching value
with the instance syntax object’s lexical context.
syntax m = ctx => {
let dummy = #`dummy`.get(0);
return #`${dummy.fromNumber(1)}`;
}
m
1
5.7. fromString
Syntax.prototype.fromString(value) -> Syntax
value : string
Creates a string literal matching value
with the instance syntax object’s lexical context.
syntax to_str = ctx => {
let dummy = #`dummy`.get(0);
let arg = ctx.next().value;
return #`${dummy.fromString(arg.val())}`;
}
to_str foo
'foo'
5.8. fromPunctuator
Syntax.prototype.fromPunctuator(value) -> Syntax
value : string
Creates a punctuator (e.g. +
, ==
, etc.) matching value
with the instance syntax object’s lexical context.
syntax m = ctx => {
let dummy = #`dummy`.get(0);
return #`1 ${dummy.fromPunctuator('+')} 1`;
}
m
1 + 1
5.9. fromKeyword
Syntax.prototype.fromKeyword(value) -> Syntax
value : string
Creates a keyword matching value
with the instance syntax object’s lexical context.
syntax m = ctx => {
let dummy = #`dummy`.get(0);
return #`${dummy.fromKeyword('let')} x = 1`;
}
m
let x = 1
5.10. fromIdentifier
Syntax.prototype.fromIdentifier(value) -> Syntax
value : string
Creates a identifier matching value
with the instance syntax object’s lexical context.
syntax m = ctx => {
let dummy = #`dummy`.get(0);
let arg = ctx.next().value;
return #`${dummy.fromIdentifier(arg.val())}`;
}
m foo
foo
5.11. fromRegularExpression
Syntax.prototype.fromRegularExpression(value) -> Syntax
value : string
Creates a regular expression literal matching value
with the instance syntax object’s lexical context.
syntax m = ctx => {
let dummy = #`dummy`.get(0);
return #`${dummy.fromRegularExpression('[a-zA-Z]*')}`;
}
m
/[a-zA-Z]/
5.12. fromBraces
Syntax.prototype.fromBraces(inner) -> Syntax
inner : List(Syntax)
Creates a curly brace delimiter with inner syntax objects inner
with the instance syntax object’s lexical context.
syntax m = ctx => {
let dummy = #`dummy`.get(0);
let block = #`let x = 1;`;
return #`${dummy.fromBraces(block)}`;
}
m
{ let x = 1; }
5.13. fromBrackets
Syntax.prototype.fromBrackets(inner) -> Syntax
inner : List(Syntax)
Creates a square bracket delimiter with inner syntax objects inner
with the instance syntax object’s lexical context.
syntax m = ctx => {
let dummy = #`dummy`.get(0);
let elements = #`1, 2, 3`;
return #`${dummy.fromBrackets(elements)}`;
}
m
[1, 2, 3]
5.14. fromParens
Syntax.prototype.fromParens(inner) -> Syntax
inner : List(Syntax)
Creates a parenthesis delimiter with inner syntax objects inner
with the instance syntax object’s lexical context.
syntax m = ctx => {
let dummy = #`dummy`.get(0);
let expr = #`5 * 5`;
return #`1 + ${dummy.fromParens(expr)}`;
}
m
1 + (5 * 5)
5.15. isIdentifier
Syntax.prototype.isIdentifier() -> boolean
Returns true if the syntax object is an identifier.
5.16. isBooleanLiteral
Syntax.prototype.isBooleanLiteral() -> boolean
Returns true if the syntax object is a boolean literal.
5.17. isNullLiteral
Syntax.prototype.isNullLiteral() -> boolean
Returns true if the syntax object is a null literal.
5.18. isNumericLiteral
Syntax.prototype.isNumericLiteral() -> boolean
Returns true if the syntax object is a numeric literal.
5.19. isStringLiteral
Syntax.prototype.isStringLiteral() -> boolean
Returns true if the syntax object is a string literal.
5.20. isKeyword
Syntax.prototype.isKeyword() -> boolean
Returns true if the syntax object is a keyword.
5.21. isPunctuator
Syntax.prototype.isPunctuator() -> boolean
Returns true if the syntax object is a puncuator.
5.22. isRegularExpression
Syntax.prototype.isRegularExpression() -> boolean
Returns true if the syntax object is a regular expression literal.
5.23. isTemplate
Syntax.prototype.isTemplate() -> boolean
Returns true if the syntax object is a template literal.
5.24. isDelimiter
Syntax.prototype.isDelimiter() -> boolean
Returns true if the syntax object is a delimiter.
5.25. isParens
Syntax.prototype.isParens() -> boolean
Returns true if the syntax object is a parenthesis delimiter (e.g. ( … )
).
5.26. isBrackets
Syntax.prototype.isBrackets() -> boolean
Returns true if the syntax object is a bracket delimiter (e.g. [ … ]
).
5.27. isBraces
Syntax.prototype.isBraces() -> boolean
Returns true if the syntax object is a braces delimiter (e.g. { … }
).
5.28. isSyntaxTemplate
Syntax.prototype.isSyntaxTemplate() -> boolean
Returns true if the syntax object is a syntax template.
6. Syntax Templates
Syntax templates construct a list of syntax objects from a literal representation using backtick (#`foo bar baz`
). They are similar to ES2015 templates but with the special sweet.js specific #
template tag.
Syntax templates support interpolations just like normal templates via ${…}
:
syntax m = function (ctx) {
return #`${ctx.next().value} + 24`;
}
m 42
The expressions inside an interpolation must evaluate to a syntax object, an array, a list, or an transformer context.