bolt/scripts/bolt.pegjs

553 lines
14 KiB
JavaScript

{
const {
setParents,
SourceFile,
SyntaxKind,
TuplePattern,
ListPattern,
Identifier,
StructDefinition,
StructField,
EnumDefinition,
EnumField,
FunctionDefinition,
FunctionExpression,
FunctionCall,
VariableDefinition,
Param,
MatchExpression,
MatchCase,
IntegerExpression,
CharLiteral,
StringLiteral,
ReturnStatement,
ExpressionStatement,
ContinueStatement,
BreakStatement,
TypeReference,
TypeAlias,
MemberAccess,
AssignExpression,
FunctionBody
} = require('./syntax')
function loc() {
const { start, end } = location()
return { start, end, fileId: options.fileId }
}
function buildRightRecursive(e1, rest) {
if (rest.length === 0) {
return e1
}
const tail = rest.slice(0, rest.length-2)
const head = rest[rest.length-1]
const nested = buildRightRecursive(head[3], tail)
return new FunctionCall(head[1], [e1, nested], null, null, null, loc())
}
function buildLeftRecursive(e1, rest) {
if (rest.length === 0) {
return e1
}
const [head, ...tail] = rest
const nested = buildLeftRecursive(head[3], tail)
return new FunctionCall(head[1], [e1, nested], null, null, null, loc())
}
}
File
= body:Statements {
const sourceFile = new SourceFile(body, null, loc())
setParents(sourceFile)
return sourceFile
}
Statements
= @(__ @Statement)* __
EOS
= __ ';'
/ _ LineComment? EOLF
/ _ &'}'
/ __ EOF
IdentifierStart = [a-zA-Z]
IdentifierPart = [a-zA-Z0-9]
Identifier "identifier"
= !ReservedWord text:$(IdentifierStart IdentifierPart*) {
return new Identifier(text, null, null, null, loc())
}
FunctionKeyword = 'func' !IdentifierPart
ReturnKeyword = 'return' !IdentifierPart
BreakKeyword = 'break' !IdentifierPart
ContinueKeyword = 'continue' !IdentifierPart
VariableKeyword = 'var' !IdentifierPart
ConstantKeyword = 'const' !IdentifierPart
MatchKeyword = 'match' !IdentifierPart
ClassKeyword = 'class' !IdentifierPart
TypeKeyword = 'type' !IdentifierPart
StructKeyword = 'struct' !IdentifierPart
Keyword
= FunctionKeyword
/ ReturnKeyword
/ BreakKeyword
/ ContinueKeyword
/ VariableKeyword
/ ConstantKeyword
/ MatchKeyword
ReservedWord
= 'if' !IdentifierPart
/ 'else' !IdentifierPart
/ 'while' !IdentifierPart
/ 'loop' !IdentifierPart
/ Keyword
TypeDecl
= TypeReference
TypeReference
= name:Identifier {
return new TypeReference(name, null, null, null, loc())
}
Statement
= ReturnStatement
/ BreakStatement
/ ContinueStatement
/ FunctionDefinition
/ VariableDefinition
/ TypeClassDefinition
/ StructDefinition
/ ExpressionStatement
/ TypeAlias
TypeAlias
= TypeKeyword __ name:Identifier __ '=' __ typeDecl:TypeDecl EOS {
return new TypeAlias(name, typeDecl, null, null, null, loc())
}
TypeClassDefinition
= TypeKeyword __ ClassKeyword __ name:Identifier __ param:Identifier __ '{' __ members:(@FunctionSignature EOS __)* '}' EOS {
return new TypeClass(name, param, members, null, null, null, loc())
}
StructField
= name:Identifier __ ':' __ typeDecl:TypeDecl {
return new StructField(name, typeDecl, null, null, null, loc())
}
StructDefinition
= StructKeyword __ name:Identifier __ '{' members:(__ @StructField EOS)* __ '}' {
return new StructDefinition(name, members, null, null, null, loc())
}
ExpressionStatement
= expression:Expr EOS {
return new ExpressionStatement(expression, null, null, null, loc())
}
ReturnStatement
= ReturnKeyword EOS {
return new ReturnStatement(expression, null, null, null, loc())
}
/ ReturnKeyword __ expression:Expr EOS {
return new ReturnStatement(expression, null, null, null, loc())
}
BreakStatement
= BreakKeyword EOS {
return new BreakStatement(null, null, null, null, loc())
}
/ keyword:BreakKeyword __ label:Identifier EOS {
return BreakStatement(label, null, null, null, loc())
}
ContinueStatement
= ContinueKeyword EOS {
return new ContinueStatement(null, null, null, null, loc())
}
/ ContinueKeyword __ label:Identifier EOS {
return new ContinueStatement(label, null, null, null, loc())
}
Param
= pattern:Pattern typeDecl:(__ ':' __ @TypeDecl)? defaultValue:(__ '=' @Expr)? {
return new Param(pattern, typeDecl, defaultValue, null, null, null, loc())
}
OpParam
= pattern:Identifier {
return new Param(pattern, null, null, null, null, null, loc())
}
/ '(' pattern:Pattern __ typeDecl:(__ ':' __ @TypeDecl)? defaultValue:(__ '=' @Expr)? __ ')' {
return new Param(pattern, typeDecl, defaultValue, null, null, null, loc())
}
Pattern
= TuplePattern
/ VarPattern
/ ConstPattern
VarPattern
= Identifier
PatternList
= list:(first:Pattern rest:(__ ',' __ @Pattern)* { return [first, ...rest] })? {
if (list === null)
return []
return list
}
TuplePattern
= '(' elements:PatternList ')' {
return new TuplePattern(elements, null, null, null, loc())
}
ConstPattern
= StringLiteral
/ CharLiteral
/ IntegerExpression
ParamList
= params:(Param (__ ',' __ @Param)*)? {
if (params === null)
return []
return [params[0], ...params[1]]
}
ArrayAccessParams
= '[' pn:ParamList ']' {
return [new Identifier('[]', null, null, null, loc()), pn]
}
FunctionSignature
= p1:OpParam __ rest:ArrayAccessParams {
const [name, pn] = rest
return [name, [p1, ...pn]]
}
/ name:Identifier __ '(' __ params:ParamList __ ')' {
return [name, params]
}
/ name:UnaryOperator __ p:OpParam {
return [name, [p]]
}
/ p:OpParam __ name:PostfixOperator {
return [name, [p]]
}
/ p1:OpParam __ name:BinOperator __ p2:OpParam {
return [name, [p1, p2]]
}
FunctionBody
= statements:Statements {
return new FunctionBody(statements, null, null, null, loc())
}
FunctionDefinition
= FunctionKeyword __ sig:FunctionSignature __ ':' __ returnTypeDecl:TypeDecl __ '{' __ body:FunctionBody __ '}' EOS {
const [name, params] = sig
return new FunctionDefinition(name, params, returnTypeDecl, body, null, null, null, loc())
}
/ FunctionKeyword __ sig:FunctionSignature __ ':' __ returnTypeDecl:TypeDecl EOS {
const [name, params] = sig
return new FunctionDefinition(name, params, returnTypeDecl, null, null, null, null, loc())
}
/ FunctionKeyword __ sig:FunctionSignature __ '{' __ body:FunctionBody __ '}' EOS {
const [name, params] = sig
return new FunctionDefinition(name, params, null, body, null, null, null, loc())
}
/ FunctionKeyword __ sig:FunctionSignature EOS {
const [name, params] = sig
return new FunctionDefinition(name, params, null, null, null, null, null, loc())
}
VariableDefinition
= VariableKeyword __ pattern:Pattern EOS {
return new VariableDefinition(pattern, null, null, null, null, null, loc())
}
/ VariableKeyword __ pattern:Pattern __ ':' __ typeDecl:TypeDecl EOS {
return new VariableDefinition(pattern, pattern, null, null, null, null, loc())
}
/ VariableKeyword __ pattern:Pattern __ '=' __ expression:Expr EOS {
return new VariableDefinition(pattern, null, expression, null, null, null, loc())
}
/ VariableKeyword __ pattern:Pattern __ ':' __ typeDecl:TypeDecl __ '=' __ expression:Expr EOS {
return new VariableDefinition(pattern, typeDecl, expression, null, null, null, loc())
}
Expr
= DelimExpr
DelimExpr
= first:ExprNoDelim rest:(__ ',' __ @ExprNoDelim)* {
if (rest.length === 0)
return first
return new ExpressionSequence([first, ...rest], null, null, null, loc())
}
ExprNoDelim
= AssignExpr
LOrOperator = '||' { return new Identifier('||', null, null, null, loc()) }
LAndOperator = '&&' { return new Identifier('&&', null, null, null, loc()) }
BOrOperator = '|' ![|=] { return new Identifier('|', null, null, null, loc()) }
BXOrOperator = '^' !'=' { return new Identifier('^', null, null, null, loc()) }
BAndOperator = '&' !'&=' { return new Identifier('&', null, null, null, loc()) }
EqOperator = '==' { return new Identifier('==', null, null, null, loc()) }
DotOperator = '.' { return new Identifier('.', null, null, null, loc()) }
ExptOperator = '**' { return new Identifier('**', null, null, null, loc()) }
BinOperator
= LOrOperator
/ LAndOperator
/ BOrOperator
/ BXOrOperator
/ BAndOperator
/ EqOperator
/ RelOperator
/ ShiftOperator
/ AddOperator
/ MulOperator
/ DotOperator
PostfixOperator
= text:$("++" / "--") {
return new Identifier(text, null, null, null, loc())
}
AssignOperator
= text:$('=' !'=' / '+=' / '-=' / '**=' / '*=' / '/=' / '%=' / '<<=' / '>>=' / '>>>=' / '&=' / '^=' / '|=') {
return new Identifier(text, null, null, null, loc())
}
RelOperator
= text:$("<=" / ">=" / "<" !"<" / ">" !">") {
return new Identifier(text, null, null, null, loc())
}
ShiftOperator
= text:$("<<" !"=" / ">>>" !"=") {
return new Identifier(text, null, null, null, loc())
}
AddOperator
= text:$("+" ![+=] / "-" ![-=]) {
return new Identifier(text, null, null, null, loc())
}
MulOperator
= text:$("*" ![*=] / "/" !"=" / "%" !"=") {
return new Identifier(text, null, null, null, loc())
}
UnaryOperator
= text:$("++" / "--" / "+" !"=" / "-" !"=" / "~" / "!") {
return new Identifier(text, null, null, null, loc())
}
AssignExpr
= left:(@(MemberAccessExpr / Pattern) __ AssignOperator __)* right:LOrExpr {
if (left.length === 0)
return right
let out = right
for (let i = left.length-1; i >= 0; i--) {
out = new AssignExpression(left[i], out, null, null, null, loc())
}
return out
}
LOrExpr
= first:LAndExpr rest:(__ LOrOperator __ LAndExpr)* {
return buildLeftRecursive(first, rest)
}
LAndExpr
= first:BOrExpr rest:(__ LAndOperator __ BOrExpr)* {
return buildLeftRecursive(first, rest)
}
BOrExpr
= first:BXOrExpr rest:(__ BOrOperator __ BXOrExpr)* {
return buildLeftRecursive(first, rest)
}
BXOrExpr
= first:BAndExpr rest:(__ BXOrOperator __ BAndExpr)* {
return buildLeftRecursive(first, rest)
}
BAndExpr
= first:EqExpr rest:(__ BAndOperator __ EqExpr)* {
return buildLeftRecursive(first, rest)
}
EqExpr
= first:RelExpr rest:(__ EqOperator __ RelExpr)* {
return buildLeftRecursive(first, rest)
}
RelExpr
= first:ShiftExpr rest:(__ RelOperator __ ShiftExpr)* {
return buildLeftRecursive(first, rest)
}
ShiftExpr
= first:AddExpr rest:(__ ShiftOperator __ AddExpr)* {
return buildLeftRecursive(first, rest)
}
AddExpr
= first:MulExpr rest:(__ AddOperator __ MulExpr)* {
return buildLeftRecursive(first, rest)
}
MulExpr
= first:ExptExpr rest:(__ MulOperator __ ExptExpr)* {
return buildLeftRecursive(first, rest)
}
ExptExpr
= first:UnaryExpr rest:(__ ExptOperator __ UnaryExpr)* {
return buildRightRecursive(first, rest)
}
PostfixExpr
= e:CallExpr _ operator:PostfixOperator {
return new FunctionCall(operator, [e], null, null, null, loc())
}
UnaryExpr
= PostfixExpr
/ CallExpr
/ operator:UnaryOperator _ e:UnaryExpr {
return new FunctionCall(operator, [e], null, null, null, loc())
}
ArgList
= args:(Expr (__ ',' __ @Expr)) {
if (args === null)
return args
return [args[0], ...args[1]]
}
CallExpr
= operator:ExprNoCall args:(__ '(' __ @ArgList __ ')')? {
if (args === null)
return operator
return new FunctionCall(operator, args, null, null, null, loc())
}
VarRefExpr
= Identifier
ASCIISpecialChar
= '\\' char:. {
switch (char) {
case 'v': return '\v'
case 'b': return '\b'
case 'f': return '\f'
case 'r': return '\r'
case 't': return '\t'
case 'b': return '\b'
case 'n': return '\n'
case '0': return '\0'
default: return char
}
}
EscapeSeq
= ASCIISpecialChar
IntegerExpression
= digits:$([0-9]+) {
return new IntegerExpression(Number(digits), null, null, null, loc())
}
Char
= EscapeSeq / .
StringLiteral
= '"' chars:(!'"' @Char)* '"' {
return new StringLiteral(chars.join(''), null, null, null, loc())
}
CharLiteral
= '\'' value:Char '\'' {
return new CharLiteral(value, null, null, null, loc())
}
NestExpr
= '(' __ @Expr __ ')'
MatchCase
= pattern:Pattern __ '->' __ expression:ExprNoDelim {
return new MatchCase(pattern, expression, null, null, null, loc())
}
MatchExpr
= MatchKeyword __ expression:Expr __ '{' __ first:MatchCase rest:(__ ',' __ @MatchCase)* (__ ',')? __ '}' {
return new MatchExpression(expression, [first, ...rest], null, null, null, loc())
}
ArrayAccessArgs
= '[' args:ArgList ']' {
return [new Identifier('[]', null, null, null, loc()), args]
}
ExprNoCall
= arg0:MemberAccessExpr rest:(__ ArrayAccessArgs)? {
if (rest === null)
return arg0
const [operator, argn] = rest
return new FunctionCall(operator, [arg0, ...argn], null, null, null, loc())
}
MemberAccessExpr
= first:PrimExpr rest:(__ DotOperator __ @Identifier)* {
if (rest.length === 0) {
return first
}
return new MemberAccess(first, rest, null, null, null, loc())
}
PrimExpr
= NestExpr
/ MatchExpr
/ VarRefExpr
/ IntegerExpression
/ StringLiteral
/ CharLiteral
WS "whitespace" = [\t\r\n ]
BL "blank space" = [\t\r ]
BlockComment
= $('/*' (!'*/' (BlockComment / .))* '*/')
LineComment
= $('//' (!EOLF .)*)
EOF "end of file" = !.
EOL "end of line"
= "\n"
/ "\r\n"
/ "\r"
/ "\u2028"
/ "\u2029"
EOLF = EOL / EOF
Comment
= BlockComment
/ LineComment
__ = (WS / Comment)*
_ = (BL / BlockComment)*