Skip to content
GitLab
Projects Groups Snippets
  • /
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
    • Contribute to GitLab
  • Sign in / Register
  • S sweet-core
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
  • Issues 62
    • Issues 62
    • List
    • Boards
    • Service Desk
    • Milestones
  • Merge requests 4
    • Merge requests 4
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
  • Deployments
    • Deployments
    • Environments
    • Releases
  • Packages and registries
    • Packages and registries
    • Package Registry
    • Infrastructure Registry
  • Monitor
    • Monitor
    • Incidents
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Repository
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • sweet-js
  • sweet-core
  • Wiki
  • design

design · Changes

Page history
updating the reader authored Aug 06, 2013 by Tim Disney's avatar Tim Disney
Hide whitespace changes
Inline Side-by-side
design.md
View page @ d1660008
# Preliminary Design # Preliminary Design
(note: some of this is already outdated, will revise)
## Reading ## Reading
To do macros we need to `read`. To `read` we need to match delimiters To do macros we need to `read`. To `read` we need to match delimiters
...@@ -17,29 +15,75 @@ So to handle the problem of `/` we can use "almost one" lookbehind to ...@@ -17,29 +15,75 @@ So to handle the problem of `/` we can use "almost one" lookbehind to
disambiguate. Algorithm: disambiguate. Algorithm:
skip over comments skip over comments
if tok is / if tok is /
if tok-1 is ) if tok-1 is ()
look back to matching ( if tok-2 in "if" "while" "for" "with"
if identifier before ( in "if" "while" "for" "with"
tok is start of regex literal tok is start of regex literal
else else
tok is divide tok is divide
if tok-1 is } else if tok-1 is {}
if end of function expression // described below if isBlock(tok-1)
tok is start of divide // named or anonymous function
if tok-2 is () and tok-3 is "function" or tok-4 is "function"
if function expression // how to determine is described below
tok is divide
else
tok is start of regex literal
else
tok is start of regex literal
else else
tok is start of regex literal tok is divide
else if tok-1 in punctuator // e.g. ";", "==", ">", "/", "+", etc.
if tok-1 in punctuator // e.g. ";", "==", ">", "/", "+", etc.
tok is start of regex literal tok is start of regex literal
else if tok-1 in keywords
if tok-1 in keywords // though some keywords will eventually result in a parse error // though some keywords will eventually result in a parse error (eg. debugger, break)
tok is start of regex literal tok is start of regex literal
else else
tok is divide tok is divide
assignOps = ["=", "+=", "-=", "*=", "/=", "%=",
"<<=", ">>=", ">>>=", "&=", "|=", "^=", ","];
binaryOps = ["+", "-", "*", "/", "%","<<", ">>", ">>>",
"&", "|", "^","&&", "||", "?", ":",
"instanceof"
"===", "==", ">=", "<=", "<", ">", "!=", "!=="];
unaryOps = ["++", "--", "~", "!", "delete", "void", "typeof", "throw", "new"];
function isBlock(tok)
if tok-1 is ( or [
// ... ({...} ...)
return false
else if tok-1 is ":" and parent token is {}
// ... {a:{...} ...}
return isBlock(the parent {})
else if tok-1 is one of assignOps unaryOps binaryOps
// ... + {...}
// ... typeof {...}
return false
else if tok-1 is "return"
// handle ASI
if lineNumber(tok) isnt lineNumber(tok-1)
// return
// {...}
return true
else
// return {...}
return false
else if tok-1 is "yield" // could also put "yield" in unaryOps
return false
else if tok-1 is one of "debugger" "break" "continue" "throw"
parse error
else if tok-1 is one of "void" "typeof" "in" "case" "delete"
// ... in {...}
return false
else
return true
Depending on context, `function name() {}` is either a function declaration or a Depending on context, `function name() {}` is either a function declaration or a
function expression. If it's a function expression then function expression. If it's a function expression then
a following `/` will be interpreted as a divide but if it's a a following `/` will be interpreted as a divide but if it's a
...@@ -57,13 +101,13 @@ following imply it is a function declaration: ...@@ -57,13 +101,13 @@ following imply it is a function declaration:
; } ) ] ident literal (including regex literal so need to be careful about /) ; } ) ] ident literal (including regex literal so need to be careful about /)
debugger break continue else debugger break continue else
And these imply it is an function expression.
( { [ , (assignment operators) (binary operators) (unary operators) And these imply it is a function expression.
( [ , (assignment operators) (binary operators) (unary operators)
in typeof instanceof new return case delete in typeof instanceof new return case delete
throw void throw void
And these will result in a parse error: And these will result in a parse error:
do break default finally for function if switch this do break default finally for function if switch this
...@@ -139,45 +183,6 @@ etc.) as really reserved. Macros can't override their meaning. ...@@ -139,45 +183,6 @@ etc.) as really reserved. Macros can't override their meaning.
Should we disallow FutureReservedWords too (`class`, `enum`, etc.)? Should we disallow FutureReservedWords too (`class`, `enum`, etc.)?
## Scope
Macro definitions should be scoped appropriately.
What should we do about hoisting? For example,
macro foo { ... }
function bar() {
foo(...)
if (x) {
var foo = function () { ... }
foo(...)
} else {
var foo = function () { ... }
}
}
Because of hoisting, the variable `foo` will shadow the macro definition of
`foo` in this code. But this is complex and annoying. Can we just say
that hoisting always happens after macro expansion? So the first
`foo(...)` is a macro invocation and the second `foo(...)` is a
function call? Does this cause any problems?
So I think we have to have hoisting happen after macro expansion. But what does this mean for hygiene?
macro foo { ... }
foo { bar = 4 }
var bar = 5;
## Hygiene
Should be [fun](http://www.quotationspage.com/quote/26964.html)...
## Modules
Details about importing macros from another module...
## Example Code ## Example Code
...@@ -445,25 +450,10 @@ These names aren't quite right. What is JavaScripty? ...@@ -445,25 +450,10 @@ These names aren't quite right. What is JavaScripty?
} }
} }
## Misc
* sub-form expansion? MTWT says parse and expand must be separate to do sub-form expansion.
## potential macros
heredoc or multi line strings.
s = heredoc {this is a nice
multiline string
that keeps spaces
the only problem is it can't break tokenization...
}
string templates
## Papers ## Papers
Papers I've been looking through: Useful papers on macros:
* Macros that work * Macros that work
* Macros that work together * Macros that work together
...@@ -475,7 +465,4 @@ Papers I've been looking through: ...@@ -475,7 +465,4 @@ Papers I've been looking through:
* Refining Syntactic Sugar: Tools for Supporting Macro Development * Refining Syntactic Sugar: Tools for Supporting Macro Development
* Fortifying Macros * Fortifying Macros
* Composable and Compilable Macros * Composable and Compilable Macros
What others might be helpful?
Clone repository
  • Example macros
  • FAQ
  • High level design overview
  • Home
  • Macro resources
  • Patterns
  • Syntax Case
  • case api
  • custom operators
  • design
  • expander design
  • modules
  • node loader
  • pattern_class
  • reader scratch
View All Pages