Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 39 additions & 24 deletions zenscript-code-model/src/main/antlr/ZenScriptParser.g4
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
parser grammar ZenScriptParser;
@parser::members {
public boolean dzs = false;
}

options { tokenVocab = ZenScriptLexer; }

Expand All @@ -11,11 +14,20 @@ topLevelElement
| classDeclaration
| functionDeclaration
| expandFunctionDeclaration
| statement
| topLevelStatement
;

classDeclaration
: 'zenClass' simpleClassName extendsSpecifier? classBody // extended for dzs
;


extendsSpecifier
: 'extends' qualifiedName (',' qualifiedName)*
;

importDeclaration
: 'import' qualifiedName ('as' alias = simpleName)? ';'
: 'import' qualifiedName ('as' alias = simpleName)? tailingSemi=';'?
;

qualifiedName
Expand All @@ -32,21 +44,18 @@ simpleName
;

functionDeclaration
: prefix='static'? 'function' simpleName '(' (formalParameter (',' formalParameter)*)? ')' ('as' returnType)? functionBody
| prefix=('static' | 'global')? 'function' simpleName? '(' (formalParameter (',' formalParameter)*)? ')' 'as' returnType ';' // dzs
;
// global is only in dzs
: prefix=('static' | 'global')? 'function' simpleName? '(' (formalParameter (',' formalParameter)*)? ')' ('as' returnType)? (
{!dzs}? functionBody |
{dzs}? tailingSemi=';' // dzs
);

expandFunctionDeclaration
: '$expand' typeLiteral '$' simpleName '(' (formalParameter (',' formalParameter)*)? ')' ('as' returnType)? functionBody
;

formalParameter
: simpleName ('as' typeLiteral)? ('=' defaultValue)?
| varargsPrefix simpleName ('as' typeLiteral)? ('=' defaultValue)? //dzs
;

varargsPrefix // dzs
: '...'
: ({dzs}? varargsPrefix='...')? simpleName ('as' typeLiteral)? ('=' defaultValue)?
;

defaultValue
Expand All @@ -61,9 +70,6 @@ functionBody
: '{' statement* '}'
;

classDeclaration
: 'zenClass' simpleClassName ('extends' qualifiedName (',' qualifiedName)*)? classBody // extended for dzs
;

simpleClassName
: simpleName
Expand All @@ -80,14 +86,14 @@ simpleClassName
;

classBody
: '{' classMemberDeclaration* '}'
: '{' additionalBracket='{'? classMemberDeclaration* '}'
;

classMemberDeclaration
: variableDeclaration
| constructorDeclaration
: constructorDeclaration
| functionDeclaration
| operatorFunctionDeclaration // dzs
| {dzs}? operatorFunctionDeclaration // dzs
| variableDeclaration
| invaildStatementInClassBody
;

Expand All @@ -96,17 +102,23 @@ invaildStatementInClassBody
;

constructorDeclaration
: 'zenConstructor' '(' (formalParameter (',' formalParameter)*)? ')' constructorBody
| 'zenConstructor' '(' (formalParameter (',' formalParameter)*)? ')' ';' // dzs
: 'zenConstructor' '(' (formalParameter (',' formalParameter)*)? ')' (
{!dzs}? constructorBody |
{dzs}? tailingSemi=';'
)
;


topLevelStatement
: statement
;

constructorBody
: '{' statement* '}'
;

variableDeclaration
: prefix=('var' | 'val' | 'static' | 'global') simpleName ('as' typeLiteral)? ('=' initializer = expression)? ';'
| prefix=('var' | 'val' | 'static' | 'global') simpleName 'as' typeLiteral ';' //dzs
: prefix=('var' | 'val' | 'static' | 'global') simpleName? ('as' typeLiteral)? ({!dzs}? ('=' initializer = expression)?) tailingSemi=';'?
;

operatorFunctionDeclaration // dzs
Expand Down Expand Up @@ -157,7 +169,7 @@ blockStatement
;

returnStatement
: 'return' expression? ';'
: 'return' expression? tailingSemi=';'?
;

breakStatement
Expand Down Expand Up @@ -189,9 +201,12 @@ whileStatement
;

expressionStatement
: expression ';'?
: expression tailingSemi=';'?
;




// Paraphrased from https://github.com/CraftTweaker/ZenScript/blob/master/src/main/java/stanhebben/zenscript/parser/expression/ParsedExpression.java
expression
// Not really sure about this
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package raylras.zen.model
import org.antlr.v4.runtime.CommonTokenStream
import org.antlr.v4.runtime.tree.ParseTree
import org.antlr.v4.runtime.tree.ParseTreeWalker
import raylras.zen.model.diagnose.DiagnoseHandler
import raylras.zen.model.parser.ZenScriptLexer
import raylras.zen.model.scope.Scope
import raylras.zen.model.symbol.*
Expand All @@ -21,6 +22,7 @@ class CompilationUnit(val path: Path, val env: CompilationEnvironment) {

val scopeMap = IdentityHashMap<ParseTree, Scope>()
val symbolMap = IdentityHashMap<ParseTree, Symbol>()
var diagnoseHandler: DiagnoseHandler = DiagnoseHandler(this)

lateinit var tokenStream: CommonTokenStream
lateinit var parseTree: ParseTree
Expand Down Expand Up @@ -156,6 +158,7 @@ class CompilationUnit(val path: Path, val env: CompilationEnvironment) {
classMap = emptyMap()
expandFunctionMap = emptyMap()
staticSymbolMap = emptyMap()
diagnoseHandler.clear()
}

override fun toString(): String = path.toString()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import org.antlr.v4.runtime.*
import org.antlr.v4.runtime.atn.PredictionMode
import org.antlr.v4.runtime.misc.ParseCancellationException
import org.antlr.v4.runtime.tree.ParseTree
import raylras.zen.model.diagnose.ParserErrorListener
import raylras.zen.model.diagnose.PrettyErrorStrategy
import raylras.zen.model.diagnose.resolveSyntaxErrors
import raylras.zen.model.parser.ZenScriptLexer
import raylras.zen.model.parser.ZenScriptParser
import raylras.zen.model.resolve.resolveDeclarations
Expand Down Expand Up @@ -51,10 +54,12 @@ fun createUnit(unitPath: Path, env: CompilationEnvironment): CompilationUnit {
return unit
}

fun CompilationEnvironment.load() {
fun CompilationEnvironment.load(unitCallback: (CompilationUnit) -> Unit = {}) {
this.clear()
this.getUnitPaths().forEach { path ->
createUnit(path, this).load()
val unit = createUnit(path, this)
unit.load()
unitCallback(unit)
}
}

Expand All @@ -69,10 +74,11 @@ fun CompilationUnit.load(source: String) {
fun CompilationUnit.load(charStream: CharStream) {
this.clear()
val tokenStream = lex(charStream)
val parseTree = parse(tokenStream)
val parseTree = parse(tokenStream, ParserErrorListener(this.diagnoseHandler), this.isDzsUnit)
this.tokenStream = tokenStream
this.parseTree = parseTree
this.resolveDeclarations()
this.resolveSyntaxErrors()
}

fun lex(charStream: CharStream): CommonTokenStream {
Expand All @@ -81,19 +87,21 @@ fun lex(charStream: CharStream): CommonTokenStream {
return CommonTokenStream(lexer)
}

fun parse(tokenStream: TokenStream): ParseTree {
fun parse(tokenStream: TokenStream, errorListener: ANTLRErrorListener, isDzs: Boolean): ParseTree {
val parser = ZenScriptParser(tokenStream)
parser.removeErrorListeners()
// faster but less robust strategy, effective when no syntax errors
parser.interpreter.predictionMode = PredictionMode.SLL
parser.errorHandler = BailErrorStrategy()
parser.dzs = isDzs
try {
return parser.compilationUnit()
} catch (_: ParseCancellationException) {
parser.reset()
// fall back to default strategy, slower but more robust
parser.interpreter.predictionMode = PredictionMode.LL
parser.errorHandler = DefaultErrorStrategy()
parser.errorHandler = PrettyErrorStrategy()
parser.addErrorListener(errorListener)
return parser.compilationUnit()
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package raylras.zen.model.diagnose

import raylras.zen.util.TextRange


enum class DiagnoseLevel {
Error,
Warning,
Hint
}
data class DiagnoseEntity(
val level: DiagnoseLevel,
val msg: String,
val range: TextRange,

) {


}

Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package raylras.zen.model.diagnose

import raylras.zen.model.CompilationUnit
import raylras.zen.util.TextRange

class DiagnoseHandler(
val unit: CompilationUnit
) {
val entities = mutableListOf<DiagnoseEntity>()
fun addEntity(entity: DiagnoseEntity) {
entities.add(entity)
}

fun addError(msg: String, range: TextRange) {
addEntity(DiagnoseEntity(DiagnoseLevel.Error, msg, range))
}

fun addSystemError(msg: String) {

}

fun clear() {
entities.clear()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package raylras.zen.model.diagnose

import org.antlr.v4.runtime.Token
import org.antlr.v4.runtime.misc.IntSet
import org.antlr.v4.runtime.misc.IntervalSet
import raylras.zen.model.Visitor

class ExpectedTokenVisitor(

): Visitor<Unit>() {
val result: IntervalSet = IntervalSet()


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package raylras.zen.model.diagnose

import org.antlr.v4.runtime.Parser
import org.antlr.v4.runtime.ParserRuleContext
import org.antlr.v4.runtime.RecognitionException

class MissingTokenException(recognizer: Parser) : RecognitionException(recognizer, recognizer.inputStream, recognizer.context) {

init {
offendingToken = recognizer.currentToken
}

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package raylras.zen.model.diagnose

import org.antlr.v4.runtime.BaseErrorListener
import org.antlr.v4.runtime.CommonTokenStream
import org.antlr.v4.runtime.FailedPredicateException
import org.antlr.v4.runtime.NoViableAltException
import org.antlr.v4.runtime.RecognitionException
import org.antlr.v4.runtime.Recognizer
import org.antlr.v4.runtime.Token
import raylras.zen.util.ANTLR_BASE_LINE
import raylras.zen.util.TextRange
import raylras.zen.util.textRange

class ParserErrorListener(
private val diagnoseHandler: DiagnoseHandler
) : BaseErrorListener() {
override fun syntaxError(
recognizer: Recognizer<*, *>,
offendingSymbol: Any?,
line: Int,
charPositionInLine: Int,
msg: String,
e: RecognitionException?
) {
val token = offendingSymbol as? Token ?: return
val range = when (e) {
is FailedPredicateException -> {
// grammar problem
diagnoseHandler.addSystemError(msg + ", at: " + token.textRange.toString())
return
}

is NoViableAltException -> {
val startToken = e.startToken
val startLine = startToken.line - ANTLR_BASE_LINE
val startColumn = startToken.charPositionInLine
val endLine = token.line - ANTLR_BASE_LINE
val endColumn = token.charPositionInLine + token.text.length
TextRange(startLine, startColumn, endLine, endColumn)
}

is MissingTokenException -> {
val tokenStream = recognizer.inputStream as? CommonTokenStream ?: return

val prev = tokenStream.LT(-1)
val prevLine = prev.line - ANTLR_BASE_LINE
val prevColumn = prev.charPositionInLine + prev.text.length
TextRange(prevLine, prevColumn, prevLine, prevColumn + 1)

}

else -> token.textRange
}
diagnoseHandler.addError(msg, range)
}
}
Loading