fix: name is now solace
This commit is contained in:
parent
ad3d1268a0
commit
471889d5f1
3 changed files with 464 additions and 92 deletions
62
README.md
62
README.md
|
@ -1,4 +1,5 @@
|
||||||
# STWL: Strongly Typed Web Language
|
# Solace
|
||||||
|
A language to find solace after using JavaScript
|
||||||
|
|
||||||
Proposal: A strongly typed, programming language that compiles to JavaScript, with the following features:
|
Proposal: A strongly typed, programming language that compiles to JavaScript, with the following features:
|
||||||
* Error unions: `Error!string`
|
* Error unions: `Error!string`
|
||||||
|
@ -15,9 +16,6 @@ Syntax example (very early proposal, might change):
|
||||||
import { func1, func2, func3 as funFunc } from './MyCoolModule'
|
import { func1, func2, func3 as funFunc } from './MyCoolModule'
|
||||||
import Cool from './MyCoolModule'
|
import Cool from './MyCoolModule'
|
||||||
|
|
||||||
// although I might add something like this in the future:
|
|
||||||
import './MyCoolModule' as Cool // because it just reads so much nicer
|
|
||||||
|
|
||||||
// Declarations can be constant, variable or live (a.k.a. reactive):
|
// Declarations can be constant, variable or live (a.k.a. reactive):
|
||||||
|
|
||||||
// Constants can never change
|
// Constants can never change
|
||||||
|
@ -64,5 +62,61 @@ Syntax example (very early proposal, might change):
|
||||||
_ -> 'outside town, hopefully'
|
_ -> 'outside town, hopefully'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Values can be optional
|
||||||
|
var userName: ?string = None // we don't know the name, yet
|
||||||
|
|
||||||
|
// Errors can be involved as well
|
||||||
|
var userName: !string = Error('user not found')
|
||||||
|
if (userFound) {
|
||||||
|
userName = 'Hans'
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Optional values and Error Unions explained:
|
||||||
|
*
|
||||||
|
* ?string would be string | null in Typescript,
|
||||||
|
* !string would be string | Error,
|
||||||
|
* !?string would be (string | null) | Error
|
||||||
|
* Error unions can be specific: NetworkError!string
|
||||||
|
* Optional values can either be a value or None (there is no null in Solace)
|
||||||
|
*/
|
||||||
|
|
||||||
|
// undefined
|
||||||
|
var userName: string // undefined, because it is not initialized
|
||||||
|
userName = undefined // Error! You cannot set anything to undefined
|
||||||
|
|
||||||
|
// In Solace, a value can either be explicitely optional and set to None,
|
||||||
|
// or it can be undefined, because there was no assignment, yet.
|
||||||
|
// This makes the distinction between undefined and null very clear:
|
||||||
|
if (userName is undefined) // not initialized at all
|
||||||
|
if (userName is None) // explicitely set to None
|
||||||
|
|
||||||
|
// Guards: certain places can make use of guards to tighten their matches:
|
||||||
|
match userName when Some(name) {
|
||||||
|
name => console.log('User is named', name)
|
||||||
|
} else {
|
||||||
|
console.log('User has no name?!')
|
||||||
|
}
|
||||||
|
|
||||||
|
// defer allows you to run a code block after a function finished
|
||||||
|
async fn deleteUser(userId: string) {
|
||||||
|
const user: ?User = await fetch(`/api/users/${userId}`)
|
||||||
|
|
||||||
|
// lets not forget to send the user a mail
|
||||||
|
defer when user is Some(_) {
|
||||||
|
sendEmail(userId, `Greetings ${user.name}, you have been deleted!`)
|
||||||
|
}
|
||||||
|
|
||||||
|
await deleteUser(userId)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// functions look like this
|
||||||
|
fn doMath(): ?number {
|
||||||
|
if (!computer.ready) return None
|
||||||
|
return 42
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
10
package.json
10
package.json
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "ohm-grammar-stwl",
|
"name": "ohm-grammar-solace",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"description": "Strongly Typed Web Language",
|
"description": "A language to find solace after using JavaScript",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"ohm",
|
"ohm",
|
||||||
|
@ -9,12 +9,12 @@
|
||||||
"javascript",
|
"javascript",
|
||||||
"typed",
|
"typed",
|
||||||
"peg",
|
"peg",
|
||||||
"stwl"
|
"solace"
|
||||||
],
|
],
|
||||||
"author": "koehr <n@koehr.ing>",
|
"author": "koehr <n@koehr.ing>",
|
||||||
"homepage": "https://git.koehr.ing/n/ohm-grammar-stwl",
|
"homepage": "https://git.koehr.ing/n/ohm-grammar-solace",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://git.koehr.ing/n/ohm-grammar-stwl/issues"
|
"url": "https://git.koehr.ing/n/ohm-grammar-solace/issues"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
|
484
stwl.ohm
484
stwl.ohm
|
@ -1,85 +1,12 @@
|
||||||
StronglyTypedWebLanguage {
|
STWL {
|
||||||
Program = Statement*
|
Program = &(Directive*) SourceElement*
|
||||||
|
/*
|
||||||
Statement = ConstDec
|
STWL - Strongly Typed Web Language is just a working title
|
||||||
| VarDec
|
|
||||||
| LiveDec
|
|
||||||
| ComputedDec
|
|
||||||
| TrackStmt
|
|
||||||
| ExprStmt
|
|
||||||
| Block
|
|
||||||
|
|
||||||
ConstDec = "const" identifier "=" Expr
|
|
||||||
VarDec = "var" identifier "=" Expr
|
|
||||||
LiveDec = "live" identifier "=" Expr
|
|
||||||
ComputedDec = "computed" identifier Block
|
|
||||||
|
|
||||||
TrackStmt = "track" ListOf<identifier, ","> LambdaParams? Block
|
|
||||||
ExprStmt = Expr // necessary?
|
|
||||||
|
|
||||||
Block = "{" Statement* "}"
|
|
||||||
LambdaParams = "|" ListOf<identifier, ","> "|"
|
|
||||||
|
|
||||||
ParExpr = "(" Expr ")"
|
|
||||||
Expr = AssignExpr
|
|
||||||
AssignExpr = CompareExpr ("=" CompareExpr)?
|
|
||||||
|
|
||||||
CompareExpr = AddExpr (CompareOp AddExpr)?
|
|
||||||
CompareOp = "==" | "!=" | "<=" | ">=" | "<" | ">"
|
|
||||||
|
|
||||||
AddExpr = MulExpr (("+"|"-") MulExpr)*
|
|
||||||
MulExpr = UnaryExpr (("*"|"/"|"%") UnaryExpr)*
|
|
||||||
|
|
||||||
UnaryExpr = "void" UnaryExpr -- voidExp
|
|
||||||
| "++" UnaryExpr -- preIncrement
|
|
||||||
| "--" UnaryExpr -- preDecrement
|
|
||||||
| "+" UnaryExpr -- unaryPlus
|
|
||||||
| "-" UnaryExpr -- unaryMinus
|
|
||||||
| "~" UnaryExpr -- bnot
|
|
||||||
| "!" UnaryExpr -- lnot
|
|
||||||
| PostfixExpr
|
|
||||||
| FunctionExpr
|
|
||||||
|
|
||||||
PostfixExpr = CallExpr "++" -- postIncrement
|
|
||||||
| CallExpr "--" -- postDecrement
|
|
||||||
| CallExpr
|
|
||||||
|
|
||||||
CallExpr = MemberExpr ("(" ListOf<Expr, ","> ")")?
|
|
||||||
MemberExpr = Literal ("." identifier)*
|
|
||||||
|
|
||||||
FunctionExpr = "fn" identifier "(" ListOf<identifier, ",">* ")" Block
|
|
||||||
|
|
||||||
Literal = numberLiteral
|
|
||||||
| stringLiteral
|
|
||||||
| booleanLiteral
|
|
||||||
| nullLiteral
|
|
||||||
| identifier
|
|
||||||
| ParExpr
|
|
||||||
| Block
|
|
||||||
|
|
||||||
// 123 or 12.34
|
|
||||||
numberLiteral = digit+ ("." digit+)?
|
|
||||||
|
|
||||||
stringLiteral = "\"" (~"\"" any)* "\""
|
|
||||||
| "'" (~"'" any)* "'"
|
|
||||||
| "`" (~"`" any)* "`"
|
|
||||||
|
|
||||||
identifier = ~reservedWord identifierStart (letter | digit | "$" | "_")*
|
|
||||||
identifierStart = letter | "$" | "_"
|
|
||||||
reservedWord = keyword | futureReservedWord | nullLiteral | booleanLiteral
|
|
||||||
|
|
||||||
nullLiteral = "null"
|
|
||||||
booleanLiteral = "true" | "false"
|
|
||||||
|
|
||||||
keyword = "const" | "var" | "live" | "computed" | "track" | "when" | "while"
|
|
||||||
| "if" | "else" | "for" | "unreachable" | "catch" | "async" | "await"
|
|
||||||
| "interface" | "struct" | "private" | "public" | "defer" | "fn"
|
|
||||||
| "break" | "void" | "return" | "import" | "export" | "switch"
|
|
||||||
| "continue"
|
|
||||||
|
|
||||||
futureReservedWord = "new" | "class" | "enum" | "extends" | "super"
|
|
||||||
| "implements" | "yield"
|
|
||||||
|
|
||||||
|
This grammar is based on the ES5 and ES6 grammars and extends/cuts it where
|
||||||
|
necessary to clear STWL from many, in my opinion unnecessary, features
|
||||||
|
while extending it with a clearer syntax
|
||||||
|
*/
|
||||||
|
|
||||||
sourceCharacter = any
|
sourceCharacter = any
|
||||||
|
|
||||||
|
@ -94,8 +21,6 @@ StronglyTypedWebLanguage {
|
||||||
| "\uFEFF" -- byteOrderMark
|
| "\uFEFF" -- byteOrderMark
|
||||||
| unicodeSpaceSeparator
|
| unicodeSpaceSeparator
|
||||||
|
|
||||||
unicodeSpaceSeparator = "\u2000".."\u200B" | "\u3000"
|
|
||||||
|
|
||||||
lineTerminator = "\n" | "\r" | "\u2028" | "\u2029"
|
lineTerminator = "\n" | "\r" | "\u2028" | "\u2029"
|
||||||
lineTerminatorSequence = "\n" | "\r" ~"\n" | "\u2028" | "\u2029" | "\r\n"
|
lineTerminatorSequence = "\n" | "\r" ~"\n" | "\u2028" | "\u2029" | "\r\n"
|
||||||
|
|
||||||
|
@ -103,4 +28,397 @@ StronglyTypedWebLanguage {
|
||||||
|
|
||||||
multiLineComment = "/*" (~"*/" sourceCharacter)* "*/"
|
multiLineComment = "/*" (~"*/" sourceCharacter)* "*/"
|
||||||
singleLineComment = "//" (~lineTerminator sourceCharacter)*
|
singleLineComment = "//" (~lineTerminator sourceCharacter)*
|
||||||
|
|
||||||
|
identifier (an identifier) = ~reservedWord identifierName
|
||||||
|
identifierName = identifierStart identifierPart*
|
||||||
|
|
||||||
|
identifierStart = letter | "$" | "_"
|
||||||
|
identifierPart = identifierStart | unicodeDigit
|
||||||
|
letter += unicodeCategoryNl
|
||||||
|
unicodeCategoryNl
|
||||||
|
= "\u2160".."\u2182" | "\u3007" | "\u3021".."\u3029"
|
||||||
|
unicodeDigit (a digit)
|
||||||
|
= "\u0030".."\u0039" | "\u0660".."\u0669" | "\u06F0".."\u06F9" | "\u0966".."\u096F" | "\u09E6".."\u09EF" | "\u0A66".."\u0A6F" | "\u0AE6".."\u0AEF" | "\u0B66".."\u0B6F" | "\u0BE7".."\u0BEF" | "\u0C66".."\u0C6F" | "\u0CE6".."\u0CEF" | "\u0D66".."\u0D6F" | "\u0E50".."\u0E59" | "\u0ED0".."\u0ED9" | "\u0F20".."\u0F29" | "\uFF10".."\uFF19"
|
||||||
|
|
||||||
|
unicodeSpaceSeparator = "\u2000".."\u200B" | "\u3000"
|
||||||
|
|
||||||
|
reservedWord = keyword | futureReservedWord | nullLiteral | booleanLiteral
|
||||||
|
|
||||||
|
// Note: keywords that are the complete prefix of another keyword should
|
||||||
|
// be prioritized (e.g. 'in' should come before 'instanceof')
|
||||||
|
keyword = for | while | do | break | continue | match
|
||||||
|
| if | else | const | var | live | computed
|
||||||
|
| catch | fn | return | void | this
|
||||||
|
| has | enum | interface | extends | implements | struct
|
||||||
|
| export | import | defer
|
||||||
|
|
||||||
|
futureReservedWord = fallthrough
|
||||||
|
|
||||||
|
literal = nullLiteral | booleanLiteral | numericLiteral
|
||||||
|
| stringLiteral | regularExpressionLiteral
|
||||||
|
|
||||||
|
// Optionals, which can be either Some<T> or None, are translated to T | null
|
||||||
|
nullLiteral = "None" ~identifierPart
|
||||||
|
booleanLiteral = ("true" | "false") ~identifierPart
|
||||||
|
|
||||||
|
// For semantics on how decimal literals are constructed, see section 7.8.3
|
||||||
|
|
||||||
|
// Note that the ordering of hexIntegerLiteral and decimalLiteral is reversed w.r.t. the spec
|
||||||
|
// This is intentional: the order decimalLiteral | hexIntegerLiteral will parse
|
||||||
|
// "0x..." as a decimal literal "0" followed by "x..."
|
||||||
|
numericLiteral = octalIntegerLiteral | hexIntegerLiteral | decimalLiteral
|
||||||
|
|
||||||
|
decimalLiteral = decimalIntegerLiteral "." decimalDigit* exponentPart -- bothParts
|
||||||
|
| "." decimalDigit+ exponentPart -- decimalsOnly
|
||||||
|
| decimalIntegerLiteral exponentPart -- integerOnly
|
||||||
|
|
||||||
|
decimalIntegerLiteral = nonZeroDigit decimalDigit* -- nonZero
|
||||||
|
| "0" -- zero
|
||||||
|
decimalDigit = "0".."9"
|
||||||
|
nonZeroDigit = "1".."9"
|
||||||
|
|
||||||
|
exponentPart = exponentIndicator signedInteger -- present
|
||||||
|
| -- absent
|
||||||
|
exponentIndicator = "e" | "E"
|
||||||
|
signedInteger = "+" decimalDigit* -- positive
|
||||||
|
| "-" decimalDigit* -- negative
|
||||||
|
| decimalDigit+ -- noSign
|
||||||
|
|
||||||
|
hexIntegerLiteral = "0x" hexDigit+
|
||||||
|
| "0X" hexDigit+
|
||||||
|
|
||||||
|
// hexDigit defined in Ohm's built-in rules (otherwise: hexDigit = "0".."9" | "a".."f" | "A".."F")
|
||||||
|
|
||||||
|
octalIntegerLiteral = "0" octalDigit+
|
||||||
|
|
||||||
|
octalDigit = "0".."7"
|
||||||
|
zeroToThree = "0".."3"
|
||||||
|
fourToSeven = "4".."7"
|
||||||
|
|
||||||
|
// For semantics on how string literals are constructed, see section 7.8.4
|
||||||
|
stringLiteral = "\"" doubleStringCharacter* "\""
|
||||||
|
| "'" singleStringCharacter* "'"
|
||||||
|
doubleStringCharacter = ~("\"" | "\\" | lineTerminator) sourceCharacter -- nonEscaped
|
||||||
|
| "\\" escapeSequence -- escaped
|
||||||
|
| lineContinuation -- lineContinuation
|
||||||
|
singleStringCharacter = ~("'" | "\\" | lineTerminator) sourceCharacter -- nonEscaped
|
||||||
|
| "\\" escapeSequence -- escaped
|
||||||
|
| lineContinuation -- lineContinuation
|
||||||
|
lineContinuation = "\\" lineTerminatorSequence
|
||||||
|
escapeSequence = unicodeEscapeSequence
|
||||||
|
| hexEscapeSequence
|
||||||
|
| octalEscapeSequence
|
||||||
|
| characterEscapeSequence // Must come last.
|
||||||
|
characterEscapeSequence = singleEscapeCharacter
|
||||||
|
| nonEscapeCharacter
|
||||||
|
singleEscapeCharacter = "'" | "\"" | "\\" | "b" | "f" | "n" | "r" | "t" | "v"
|
||||||
|
nonEscapeCharacter = ~(escapeCharacter | lineTerminator) sourceCharacter
|
||||||
|
escapeCharacter = singleEscapeCharacter | decimalDigit | "x" | "u"
|
||||||
|
octalEscapeSequence = zeroToThree octalDigit octalDigit -- whole
|
||||||
|
| fourToSeven octalDigit -- eightTimesfourToSeven
|
||||||
|
| zeroToThree octalDigit ~decimalDigit -- eightTimesZeroToThree
|
||||||
|
| octalDigit ~decimalDigit -- octal
|
||||||
|
hexEscapeSequence = "x" hexDigit hexDigit
|
||||||
|
unicodeEscapeSequence = "u" hexDigit hexDigit hexDigit hexDigit
|
||||||
|
|
||||||
|
// §7.8.5 Regular Expression Literals -- https://es5.github.io/#x7.8.5
|
||||||
|
|
||||||
|
regularExpressionLiteral = "/" regularExpressionBody "/" regularExpressionFlags
|
||||||
|
regularExpressionBody = regularExpressionFirstChar regularExpressionChar*
|
||||||
|
regularExpressionFirstChar = ~("*" | "\\" | "/" | "[") regularExpressionNonTerminator
|
||||||
|
| regularExpressionBackslashSequence
|
||||||
|
| regularExpressionClass
|
||||||
|
regularExpressionChar = ~("\\" | "/" | "[") regularExpressionNonTerminator
|
||||||
|
| regularExpressionBackslashSequence
|
||||||
|
| regularExpressionClass
|
||||||
|
regularExpressionBackslashSequence = "\\" regularExpressionNonTerminator
|
||||||
|
regularExpressionNonTerminator = ~(lineTerminator) sourceCharacter
|
||||||
|
regularExpressionClass = "[" regularExpressionClassChar* "]"
|
||||||
|
regularExpressionClassChar = ~("]" | "\\") regularExpressionNonTerminator
|
||||||
|
| regularExpressionBackslashSequence
|
||||||
|
regularExpressionFlags = identifierPart*
|
||||||
|
|
||||||
|
// === Implementation-level rules (not part of the spec) ===
|
||||||
|
|
||||||
|
multiLineCommentNoNL = "/*" (~("*/" | lineTerminator) sourceCharacter)* "*/"
|
||||||
|
|
||||||
|
// does not accept lineTerminators, not even implicit ones in a multiLineComment (cf. section 7.4)
|
||||||
|
spacesNoNL = (whitespace | singleLineComment | multiLineCommentNoNL)*
|
||||||
|
|
||||||
|
// A semicolon is "automatically inserted" if a newline or the end of the input stream is
|
||||||
|
// reached, or the offending token is "}".
|
||||||
|
// See https://es5.github.io/#x7.9 for more information.
|
||||||
|
// NOTE: Applications of this rule *must* appear in a lexical context -- either in the body of a
|
||||||
|
// lexical rule, or inside `#()`.
|
||||||
|
sc = space* (";" | end)
|
||||||
|
| spacesNoNL (lineTerminator | ~multiLineCommentNoNL multiLineComment | &"}")
|
||||||
|
|
||||||
|
// Convenience rules for parsing keyword tokens.
|
||||||
|
for = "for" ~identifierPart
|
||||||
|
while = "while" ~identifierPart
|
||||||
|
do = "do" ~identifierPart // will we support do-while loops?
|
||||||
|
break = "break" ~identifierPart
|
||||||
|
continue = "continue" ~identifierPart
|
||||||
|
if = "if" ~identifierPart
|
||||||
|
else = "else" ~identifierPart
|
||||||
|
const = "const" ~identifierPart
|
||||||
|
var = "var" ~identifierPart
|
||||||
|
live = "live" ~identifierPart
|
||||||
|
track = "track" ~identifierPart
|
||||||
|
computed = "computed" ~identifierPart
|
||||||
|
catch = "catch" ~identifierPart
|
||||||
|
fn = "fn" ~identifierPart
|
||||||
|
return = "return" ~identifierPart
|
||||||
|
void = "void" ~identifierPart
|
||||||
|
this = "_" ~identifierPart
|
||||||
|
in = "in" ~identifierPart -- value in ArrayLike
|
||||||
|
has = "has" ~identifierPart -- struct has Property
|
||||||
|
enum = "enum" ~identifierPart
|
||||||
|
interface = "interface" ~identifierPart
|
||||||
|
extends = "extends" ~identifierPart
|
||||||
|
implements = "implements" ~identifierPart
|
||||||
|
export = "export" ~identifierPart
|
||||||
|
import = "import" ~identifierPart
|
||||||
|
struct = "struct" ~identifierPart
|
||||||
|
defer = "defer" ~identifierPart
|
||||||
|
match = "match" ~identifierPart
|
||||||
|
fallthrough = "fallthrough" ~identifierPart
|
||||||
|
|
||||||
|
// end of lexical rules
|
||||||
|
|
||||||
|
noIn = ~in
|
||||||
|
withIn =
|
||||||
|
|
||||||
|
noHas = ~has
|
||||||
|
withHas =
|
||||||
|
|
||||||
|
noInHas = ~(in | has)
|
||||||
|
withInHas =
|
||||||
|
|
||||||
|
// §A.3 Expressions -- https://es5.github.io/#A.3
|
||||||
|
|
||||||
|
PrimaryExpression = this
|
||||||
|
| identifier
|
||||||
|
| literal
|
||||||
|
// ( litToken.type === "regexp"
|
||||||
|
// ? this.ast(_fromIdx, "RegExpExpr",{body: litToken.value.body
|
||||||
|
// flags: litToken.value.flags}, [])
|
||||||
|
// : this.ast(_fromIdx, "LiteralExpr",{type: litToken.type
|
||||||
|
// value: litToken.value}, []) )
|
||||||
|
| ArrayLiteral
|
||||||
|
| ObjectLiteral
|
||||||
|
| "(" Expression<withIn> ")" -- parenExpr
|
||||||
|
|
||||||
|
ArrayLiteral = "[" ListOf<AssignmentExpressionOrElision, ","> "]"
|
||||||
|
AssignmentExpressionOrElision = AssignmentExpression<withIn>
|
||||||
|
| -- elision
|
||||||
|
|
||||||
|
ObjectLiteral = "{" ListOf<PropertyAssignment, ","> "}" -- noTrailingComma
|
||||||
|
| "{" NonemptyListOf<PropertyAssignment, ","> "," "}" -- trailingComma
|
||||||
|
|
||||||
|
PropertyAssignment = get PropertyName "(" ")" "{" FunctionBody "}" -- getter
|
||||||
|
| set PropertyName "(" FormalParameter ")" "{" FunctionBody "}" -- setter
|
||||||
|
| PropertyName ":" AssignmentExpression<withIn> -- simple
|
||||||
|
|
||||||
|
PropertyName = identifierName
|
||||||
|
| stringLiteral
|
||||||
|
| numericLiteral
|
||||||
|
|
||||||
|
MemberExpression = MemberExpression "[" Expression<withIn> "]" -- arrayRefExp
|
||||||
|
| MemberExpression "." identifierName -- propRefExp
|
||||||
|
| new MemberExpression Arguments -- newExp
|
||||||
|
| FunctionExpression
|
||||||
|
| PrimaryExpression
|
||||||
|
|
||||||
|
NewExpression = MemberExpression
|
||||||
|
| new NewExpression -- newExp
|
||||||
|
|
||||||
|
CallExpression = CallExpression "[" Expression<withIn> "]" -- arrayRefExp
|
||||||
|
| CallExpression "." identifierName -- propRefExp
|
||||||
|
| CallExpression Arguments -- callExpExp
|
||||||
|
| MemberExpression Arguments -- memberExpExp
|
||||||
|
|
||||||
|
Arguments = "(" ListOf<AssignmentExpression<withIn>, ","> ")"
|
||||||
|
|
||||||
|
LeftHandSideExpression = CallExpression
|
||||||
|
| NewExpression
|
||||||
|
|
||||||
|
PostfixExpression = LeftHandSideExpression #(spacesNoNL "++") -- postIncrement
|
||||||
|
| LeftHandSideExpression #(spacesNoNL "--") -- postDecrement
|
||||||
|
| LeftHandSideExpression
|
||||||
|
|
||||||
|
UnaryExpression = void UnaryExpression -- voidExp
|
||||||
|
| "++" UnaryExpression -- preIncrement
|
||||||
|
| "--" UnaryExpression -- preDecrement
|
||||||
|
| "+" UnaryExpression -- unaryPlus
|
||||||
|
| "-" UnaryExpression -- unaryMinus
|
||||||
|
| "~" UnaryExpression -- bnot
|
||||||
|
| "!" UnaryExpression -- lnot
|
||||||
|
| PostfixExpression
|
||||||
|
|
||||||
|
MultiplicativeExpression = MultiplicativeExpression "*" UnaryExpression -- mul
|
||||||
|
| MultiplicativeExpression "/" UnaryExpression -- div
|
||||||
|
| MultiplicativeExpression "%" UnaryExpression -- mod
|
||||||
|
| UnaryExpression
|
||||||
|
|
||||||
|
AdditiveExpression = AdditiveExpression "+" MultiplicativeExpression -- add
|
||||||
|
| AdditiveExpression "-" MultiplicativeExpression -- sub
|
||||||
|
| MultiplicativeExpression
|
||||||
|
|
||||||
|
ShiftExpression = ShiftExpression "<<" AdditiveExpression -- lsl
|
||||||
|
| ShiftExpression ">>>" AdditiveExpression -- lsr
|
||||||
|
| ShiftExpression ">>" AdditiveExpression -- asr
|
||||||
|
| AdditiveExpression
|
||||||
|
|
||||||
|
RelationalExpression<guardIn>
|
||||||
|
= RelationalExpression<guardIn> "<" ShiftExpression -- lt
|
||||||
|
| RelationalExpression<guardIn> ">" ShiftExpression -- gt
|
||||||
|
| RelationalExpression<guardIn> "<=" ShiftExpression -- le
|
||||||
|
| RelationalExpression<guardIn> ">=" ShiftExpression -- ge
|
||||||
|
| RelationalExpression<guardIn> guardIn "in" ShiftExpression -- inExp
|
||||||
|
| ShiftExpression
|
||||||
|
|
||||||
|
EqualityExpression<guardIn>
|
||||||
|
= EqualityExpression<guardIn> "==" RelationalExpression<guardIn> -- equal
|
||||||
|
| EqualityExpression<guardIn> "!=" RelationalExpression<guardIn> -- notEqual
|
||||||
|
| EqualityExpression<guardIn> "===" RelationalExpression<guardIn> -- eq
|
||||||
|
| EqualityExpression<guardIn> "!==" RelationalExpression<guardIn> -- notEq
|
||||||
|
| RelationalExpression<guardIn>
|
||||||
|
|
||||||
|
BitwiseANDExpression<guardIn>
|
||||||
|
= BitwiseANDExpression<guardIn> "&" EqualityExpression<guardIn> -- band
|
||||||
|
| EqualityExpression<guardIn>
|
||||||
|
|
||||||
|
BitwiseXORExpression<guardIn>
|
||||||
|
= BitwiseXORExpression<guardIn> "^" BitwiseANDExpression<guardIn> -- bxor
|
||||||
|
| BitwiseANDExpression<guardIn>
|
||||||
|
|
||||||
|
BitwiseORExpression<guardIn>
|
||||||
|
= BitwiseORExpression<guardIn> "|" BitwiseXORExpression<guardIn> -- bor
|
||||||
|
| BitwiseXORExpression<guardIn>
|
||||||
|
|
||||||
|
LogicalANDExpression<guardIn>
|
||||||
|
= LogicalANDExpression<guardIn> "&&" BitwiseORExpression<guardIn> -- land
|
||||||
|
| BitwiseORExpression<guardIn>
|
||||||
|
|
||||||
|
LogicalORExpression<guardIn>
|
||||||
|
= LogicalORExpression<guardIn> "||" LogicalANDExpression<guardIn> -- lor
|
||||||
|
| LogicalANDExpression<guardIn>
|
||||||
|
|
||||||
|
ConditionalExpression<guardIn>
|
||||||
|
= LogicalORExpression<guardIn> "?" AssignmentExpression<withIn> ":" AssignmentExpression<guardIn> -- conditional
|
||||||
|
| LogicalORExpression<guardIn>
|
||||||
|
|
||||||
|
AssignmentExpression<guardIn>
|
||||||
|
= LeftHandSideExpression assignmentOperator AssignmentExpression<guardIn> -- assignment
|
||||||
|
| ConditionalExpression<guardIn>
|
||||||
|
|
||||||
|
Expression<guardIn> (an expression)
|
||||||
|
= Expression<guardIn> "," AssignmentExpression<guardIn> -- commaExp
|
||||||
|
| AssignmentExpression<guardIn>
|
||||||
|
|
||||||
|
assignmentOperator = "=" | ">>>=" | "<<=" | ">>="
|
||||||
|
| "*=" | "/=" | "%=" | "+=" | "-=" | "&=" | "^=" | "|="
|
||||||
|
|
||||||
|
// Statements -- (extends https://es5.github.io/#A.4)
|
||||||
|
|
||||||
|
Statement
|
||||||
|
= Block
|
||||||
|
| VariableStatement
|
||||||
|
| EmptyStatement
|
||||||
|
| ExpressionStatement
|
||||||
|
| IfStatement
|
||||||
|
| IterationStatement
|
||||||
|
| ContinueStatement
|
||||||
|
| BreakStatement
|
||||||
|
| ReturnStatement
|
||||||
|
|
||||||
|
Block = "{" StatementList "}"
|
||||||
|
LambdaParameters = "|" ListOf<identifier, ","> "|"
|
||||||
|
|
||||||
|
StatementList = Statement*
|
||||||
|
|
||||||
|
ComputedStatement = computed identifier Block
|
||||||
|
|
||||||
|
TrackStatement = track ListOf<identifier, ","> LambdaParameters? Block
|
||||||
|
|
||||||
|
VariableStatement = VariableAssignment VariableDeclarationList<withIn> #sc
|
||||||
|
|
||||||
|
VariableAssignment = var | const | live
|
||||||
|
|
||||||
|
VariableDeclarationList<guardIn> = NonemptyListOf<VariableDeclaration<guardIn>, ",">
|
||||||
|
|
||||||
|
VariableDeclaration<guardIn> = identifier Initialiser<guardIn>?
|
||||||
|
|
||||||
|
Initialiser<guardIn> = "=" AssignmentExpression<guardIn>
|
||||||
|
|
||||||
|
EmptyStatement = ";" // note: this semicolon eats newlines
|
||||||
|
|
||||||
|
ExpressionStatement = ~("{" | function) Expression<withIn> #sc
|
||||||
|
|
||||||
|
IfStatement = if "(" Expression<withIn> ")" Statement (else Statement)?
|
||||||
|
|
||||||
|
IterationStatement = do Statement while "(" Expression<withIn> ")" #sc -- doWhile
|
||||||
|
| while "(" Expression<withIn> ")" Statement -- whileDo
|
||||||
|
| for "(" Expression<noIn>? ";"
|
||||||
|
Expression<withIn>? ";"
|
||||||
|
Expression<withIn>? ")" Statement -- for3
|
||||||
|
| for "(" var VariableDeclarationList<noIn> ";"
|
||||||
|
Expression<withIn>? ";"
|
||||||
|
Expression<withIn>? ")" Statement -- for3var
|
||||||
|
| for "(" LeftHandSideExpression in
|
||||||
|
Expression<withIn> ")" Statement -- forIn
|
||||||
|
| for "(" var VariableDeclaration<noIn> in
|
||||||
|
Expression<withIn> ")" Statement -- forInVar
|
||||||
|
|
||||||
|
ContinueStatement = continue #((spacesNoNL identifier)? sc)
|
||||||
|
|
||||||
|
BreakStatement = break #((spacesNoNL identifier)? sc)
|
||||||
|
|
||||||
|
ReturnStatement = return (#(spacesNoNL ~space) Expression<withIn>)? #sc
|
||||||
|
|
||||||
|
Catch = catch "(" FormalParameter ")" Block
|
||||||
|
|
||||||
|
Defer = defer (when Expression<withIn>)? Block
|
||||||
|
|
||||||
|
// Pattern Matching
|
||||||
|
|
||||||
|
MatchExpr = match Expression<withIn> (if Pattern)? "{" MatchArm+ "}" (else Block)?
|
||||||
|
MatchArm = Pattern "=>" (Expression<withIn> | Block)
|
||||||
|
Pattern = identifier
|
||||||
|
| literal
|
||||||
|
| GuardPattern
|
||||||
|
GuardPattern = Expression<withIn> // Just an expression! No special syntax needed
|
||||||
|
|
||||||
|
|
||||||
|
// §A.5 Functions and Programs -- https://es5.github.io/#A.5
|
||||||
|
|
||||||
|
FunctionDeclaration
|
||||||
|
= function identifier "(" FormalParameterList ")" "{" FunctionBody "}"
|
||||||
|
|
||||||
|
FunctionExpression
|
||||||
|
= function identifier "(" FormalParameterList ")" "{" FunctionBody "}" -- named
|
||||||
|
| function "(" FormalParameterList ")" "{" FunctionBody "}" -- anonymous
|
||||||
|
|
||||||
|
FormalParameterList = ListOf<FormalParameter, ",">
|
||||||
|
|
||||||
|
FormalParameter = identifier
|
||||||
|
|
||||||
|
/*
|
||||||
|
Note: The Directive Prologue is the longest sequence of ExpressionStatement
|
||||||
|
productions occurring as the initial SourceElement (see https://es5.github.io/#x14.1)
|
||||||
|
*/
|
||||||
|
FunctionBody = &(Directive*) SourceElement*
|
||||||
|
|
||||||
|
SourceElement = Declaration | Statement
|
||||||
|
|
||||||
|
// Broken out so es6 can override to include ConstDecl and LetDecl
|
||||||
|
Declaration = FunctionDeclaration
|
||||||
|
|
||||||
|
Directive = stringLiteral #sc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ES5Lax <: ES5 {
|
||||||
|
futureReservedWord := futureReservedWordLax
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue