Compiler refactored: CompilerContext now is class member
This commit is contained in:
parent
950e8301c3
commit
6cf99fbd13
@ -118,7 +118,7 @@ suspend fun executeFile(fileName: String) {
|
|||||||
text = text.substring(pos + 1)
|
text = text.substring(pos + 1)
|
||||||
}
|
}
|
||||||
processErrors {
|
processErrors {
|
||||||
Compiler().compile(Source(fileName, text)).execute(baseContext)
|
Compiler.compile(Source(fileName, text)).execute(baseContext)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,44 +4,39 @@ package net.sergeych.lyng
|
|||||||
* The LYNG compiler.
|
* The LYNG compiler.
|
||||||
*/
|
*/
|
||||||
class Compiler(
|
class Compiler(
|
||||||
|
val cc: CompilerContext,
|
||||||
@Suppress("UNUSED_PARAMETER")
|
@Suppress("UNUSED_PARAMETER")
|
||||||
settings: Settings = Settings()
|
settings: Settings = Settings()
|
||||||
) {
|
) {
|
||||||
|
|
||||||
class Settings
|
class Settings
|
||||||
|
|
||||||
fun compile(source: Source): Script {
|
private fun parseScript(): Script {
|
||||||
return parseScript(
|
|
||||||
source.startPos,
|
|
||||||
CompilerContext(parseLyng(source))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseScript(start: Pos, cc: CompilerContext): Script {
|
|
||||||
val statements = mutableListOf<Statement>()
|
val statements = mutableListOf<Statement>()
|
||||||
|
val start = cc.currentPos()
|
||||||
// val returnScope = cc.startReturnScope()
|
// val returnScope = cc.startReturnScope()
|
||||||
while (parseStatement(cc, braceMeansLambda = true)?.also {
|
while (parseStatement( braceMeansLambda = true)?.also {
|
||||||
statements += it
|
statements += it
|
||||||
} != null) {/**/
|
} != null) {/**/
|
||||||
}
|
}
|
||||||
return Script(start, statements)//returnScope.needCatch)
|
return Script(start, statements)//returnScope.needCatch)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseStatement(cc: CompilerContext, braceMeansLambda: Boolean = false): Statement? {
|
private fun parseStatement(braceMeansLambda: Boolean = false): Statement? {
|
||||||
while (true) {
|
while (true) {
|
||||||
val t = cc.next()
|
val t = cc.next()
|
||||||
return when (t.type) {
|
return when (t.type) {
|
||||||
Token.Type.ID -> {
|
Token.Type.ID -> {
|
||||||
parseKeywordStatement(t, cc)
|
parseKeywordStatement(t)
|
||||||
?: run {
|
?: run {
|
||||||
cc.previous()
|
cc.previous()
|
||||||
parseExpression(cc)
|
parseExpression()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Token.Type.PLUS2, Token.Type.MINUS2 -> {
|
Token.Type.PLUS2, Token.Type.MINUS2 -> {
|
||||||
cc.previous()
|
cc.previous()
|
||||||
parseExpression(cc)
|
parseExpression()
|
||||||
}
|
}
|
||||||
|
|
||||||
Token.Type.LABEL -> continue
|
Token.Type.LABEL -> continue
|
||||||
@ -54,9 +49,9 @@ class Compiler(
|
|||||||
Token.Type.LBRACE -> {
|
Token.Type.LBRACE -> {
|
||||||
cc.previous()
|
cc.previous()
|
||||||
if (braceMeansLambda)
|
if (braceMeansLambda)
|
||||||
parseExpression(cc)
|
parseExpression()
|
||||||
else
|
else
|
||||||
parseBlock(cc)
|
parseBlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
Token.Type.RBRACE, Token.Type.RBRACKET -> {
|
Token.Type.RBRACE, Token.Type.RBRACKET -> {
|
||||||
@ -69,32 +64,32 @@ class Compiler(
|
|||||||
else -> {
|
else -> {
|
||||||
// could be expression
|
// could be expression
|
||||||
cc.previous()
|
cc.previous()
|
||||||
parseExpression(cc)
|
parseExpression()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseExpression(tokens: CompilerContext): Statement? {
|
private fun parseExpression(): Statement? {
|
||||||
val pos = tokens.currentPos()
|
val pos = cc.currentPos()
|
||||||
return parseExpressionLevel(tokens)?.let { a -> statement(pos) { a.getter(it).value } }
|
return parseExpressionLevel()?.let { a -> statement(pos) { a.getter(it).value } }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseExpressionLevel(tokens: CompilerContext, level: Int = 0): Accessor? {
|
private fun parseExpressionLevel(level: Int = 0): Accessor? {
|
||||||
if (level == lastLevel)
|
if (level == lastLevel)
|
||||||
return parseTerm(tokens)
|
return parseTerm()
|
||||||
var lvalue: Accessor? = parseExpressionLevel(tokens, level + 1) ?: return null
|
var lvalue: Accessor? = parseExpressionLevel( level + 1) ?: return null
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
||||||
val opToken = tokens.next()
|
val opToken = cc.next()
|
||||||
val op = byLevel[level][opToken.type]
|
val op = byLevel[level][opToken.type]
|
||||||
if (op == null) {
|
if (op == null) {
|
||||||
tokens.previous()
|
cc.previous()
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
val rvalue = parseExpressionLevel(tokens, level + 1)
|
val rvalue = parseExpressionLevel( level + 1)
|
||||||
?: throw ScriptError(opToken.pos, "Expecting expression")
|
?: throw ScriptError(opToken.pos, "Expecting expression")
|
||||||
|
|
||||||
lvalue = op.generate(opToken.pos, lvalue!!, rvalue)
|
lvalue = op.generate(opToken.pos, lvalue!!, rvalue)
|
||||||
@ -102,7 +97,7 @@ class Compiler(
|
|||||||
return lvalue
|
return lvalue
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseTerm(cc: CompilerContext): Accessor? {
|
private fun parseTerm(): Accessor? {
|
||||||
var operand: Accessor? = null
|
var operand: Accessor? = null
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -116,7 +111,7 @@ class Compiler(
|
|||||||
|
|
||||||
Token.Type.NOT -> {
|
Token.Type.NOT -> {
|
||||||
if (operand != null) throw ScriptError(t.pos, "unexpected operator not '!'")
|
if (operand != null) throw ScriptError(t.pos, "unexpected operator not '!'")
|
||||||
val op = parseTerm(cc) ?: throw ScriptError(t.pos, "Expecting expression")
|
val op = parseTerm() ?: throw ScriptError(t.pos, "Expecting expression")
|
||||||
operand = Accessor { op.getter(it).value.logicalNot(it).asReadonly }
|
operand = Accessor { op.getter(it).value.logicalNot(it).asReadonly }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,7 +128,7 @@ class Compiler(
|
|||||||
Token.Type.LPAREN -> {
|
Token.Type.LPAREN -> {
|
||||||
cc.next()
|
cc.next()
|
||||||
// instance method call
|
// instance method call
|
||||||
val args = parseArgs(cc).first
|
val args = parseArgs().first
|
||||||
isCall = true
|
isCall = true
|
||||||
operand = Accessor { context ->
|
operand = Accessor { context ->
|
||||||
context.pos = next.pos
|
context.pos = next.pos
|
||||||
@ -157,7 +152,7 @@ class Compiler(
|
|||||||
cc.next()
|
cc.next()
|
||||||
isCall = true
|
isCall = true
|
||||||
val lambda =
|
val lambda =
|
||||||
parseLambdaExpression(cc)
|
parseLambdaExpression()
|
||||||
operand = Accessor { context ->
|
operand = Accessor { context ->
|
||||||
context.pos = next.pos
|
context.pos = next.pos
|
||||||
val v = left.getter(context).value
|
val v = left.getter(context).value
|
||||||
@ -182,8 +177,8 @@ class Compiler(
|
|||||||
val x = left.getter(context).value
|
val x = left.getter(context).value
|
||||||
if (x == ObjNull && isOptional) ObjNull.asReadonly
|
if (x == ObjNull && isOptional) ObjNull.asReadonly
|
||||||
else x.readField(context, next.value)
|
else x.readField(context, next.value)
|
||||||
}) { cc, newValue ->
|
}) { cxt, newValue ->
|
||||||
left.getter(cc).value.writeField(cc, next.value, newValue)
|
left.getter(cxt).value.writeField(cxt, next.value, newValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -192,21 +187,20 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Token.Type.COLONCOLON -> {
|
Token.Type.COLONCOLON -> {
|
||||||
operand = parseScopeOperator(operand, cc)
|
operand = parseScopeOperator(operand)
|
||||||
}
|
}
|
||||||
|
|
||||||
Token.Type.LPAREN, Token.Type.NULL_COALESCE_INVOKE -> {
|
Token.Type.LPAREN, Token.Type.NULL_COALESCE_INVOKE -> {
|
||||||
operand?.let { left ->
|
operand?.let { left ->
|
||||||
// this is function call from <left>
|
// this is function call from <left>
|
||||||
operand = parseFunctionCall(
|
operand = parseFunctionCall(
|
||||||
cc,
|
|
||||||
left,
|
left,
|
||||||
false,
|
false,
|
||||||
t.type == Token.Type.NULL_COALESCE_INVOKE
|
t.type == Token.Type.NULL_COALESCE_INVOKE
|
||||||
)
|
)
|
||||||
} ?: run {
|
} ?: run {
|
||||||
// Expression in parentheses
|
// Expression in parentheses
|
||||||
val statement = parseStatement(cc) ?: throw ScriptError(t.pos, "Expecting expression")
|
val statement = parseStatement() ?: throw ScriptError(t.pos, "Expecting expression")
|
||||||
operand = Accessor {
|
operand = Accessor {
|
||||||
statement.execute(it).asReadonly
|
statement.execute(it).asReadonly
|
||||||
}
|
}
|
||||||
@ -219,7 +213,7 @@ class Compiler(
|
|||||||
operand?.let { left ->
|
operand?.let { left ->
|
||||||
// array access
|
// array access
|
||||||
val isOptional = t.type == Token.Type.NULL_COALESCE_INDEX
|
val isOptional = t.type == Token.Type.NULL_COALESCE_INDEX
|
||||||
val index = parseStatement(cc) ?: throw ScriptError(t.pos, "Expecting index expression")
|
val index = parseStatement() ?: throw ScriptError(t.pos, "Expecting index expression")
|
||||||
cc.skipTokenOfType(Token.Type.RBRACKET, "missing ']' at the end of the list literal")
|
cc.skipTokenOfType(Token.Type.RBRACKET, "missing ']' at the end of the list literal")
|
||||||
operand = Accessor({ cxt ->
|
operand = Accessor({ cxt ->
|
||||||
val i = index.execute(cxt)
|
val i = index.execute(cxt)
|
||||||
@ -233,7 +227,7 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
} ?: run {
|
} ?: run {
|
||||||
// array literal
|
// array literal
|
||||||
val entries = parseArrayLiteral(cc)
|
val entries = parseArrayLiteral()
|
||||||
// if it didn't throw, ot parsed ot and consumed it all
|
// if it didn't throw, ot parsed ot and consumed it all
|
||||||
operand = Accessor { cxt ->
|
operand = Accessor { cxt ->
|
||||||
val list = mutableListOf<Obj>()
|
val list = mutableListOf<Obj>()
|
||||||
@ -263,7 +257,7 @@ class Compiler(
|
|||||||
in stopKeywords -> {
|
in stopKeywords -> {
|
||||||
if (operand != null) throw ScriptError(t.pos, "unexpected keyword")
|
if (operand != null) throw ScriptError(t.pos, "unexpected keyword")
|
||||||
cc.previous()
|
cc.previous()
|
||||||
val s = parseStatement(cc) ?: throw ScriptError(t.pos, "Expecting valid statement")
|
val s = parseStatement() ?: throw ScriptError(t.pos, "Expecting valid statement")
|
||||||
operand = Accessor { s.execute(it).asReadonly }
|
operand = Accessor { s.execute(it).asReadonly }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -287,7 +281,7 @@ class Compiler(
|
|||||||
} ?: run {
|
} ?: run {
|
||||||
// variable to read or like
|
// variable to read or like
|
||||||
cc.previous()
|
cc.previous()
|
||||||
operand = parseAccessor(cc)
|
operand = parseAccessor()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -305,7 +299,7 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
} ?: run {
|
} ?: run {
|
||||||
// no lvalue means pre-increment, expression to increment follows
|
// no lvalue means pre-increment, expression to increment follows
|
||||||
val next = parseAccessor(cc) ?: throw ScriptError(t.pos, "Expecting expression")
|
val next = parseAccessor() ?: throw ScriptError(t.pos, "Expecting expression")
|
||||||
operand = Accessor { ctx ->
|
operand = Accessor { ctx ->
|
||||||
next.getter(ctx).also {
|
next.getter(ctx).also {
|
||||||
if (!it.isMutable) ctx.raiseError("Cannot increment immutable value")
|
if (!it.isMutable) ctx.raiseError("Cannot increment immutable value")
|
||||||
@ -326,7 +320,7 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
} ?: run {
|
} ?: run {
|
||||||
// no lvalue means pre-decrement, expression to decrement follows
|
// no lvalue means pre-decrement, expression to decrement follows
|
||||||
val next = parseAccessor(cc) ?: throw ScriptError(t.pos, "Expecting expression")
|
val next = parseAccessor() ?: throw ScriptError(t.pos, "Expecting expression")
|
||||||
operand = Accessor { ctx ->
|
operand = Accessor { ctx ->
|
||||||
next.getter(ctx).also {
|
next.getter(ctx).also {
|
||||||
if (!it.isMutable) ctx.raiseError("Cannot decrement immutable value")
|
if (!it.isMutable) ctx.raiseError("Cannot decrement immutable value")
|
||||||
@ -339,7 +333,7 @@ class Compiler(
|
|||||||
// range operator
|
// range operator
|
||||||
val isEndInclusive = t.type == Token.Type.DOTDOT
|
val isEndInclusive = t.type == Token.Type.DOTDOT
|
||||||
val left = operand
|
val left = operand
|
||||||
val right = parseExpression(cc)
|
val right = parseExpression()
|
||||||
operand = Accessor {
|
operand = Accessor {
|
||||||
ObjRange(
|
ObjRange(
|
||||||
left?.getter?.invoke(it)?.value ?: ObjNull,
|
left?.getter?.invoke(it)?.value ?: ObjNull,
|
||||||
@ -353,12 +347,11 @@ class Compiler(
|
|||||||
operand = operand?.let { left ->
|
operand = operand?.let { left ->
|
||||||
cc.previous()
|
cc.previous()
|
||||||
parseFunctionCall(
|
parseFunctionCall(
|
||||||
cc,
|
|
||||||
left,
|
left,
|
||||||
blockArgument = true,
|
blockArgument = true,
|
||||||
t.type == Token.Type.NULL_COALESCE_BLOCKINVOKE
|
t.type == Token.Type.NULL_COALESCE_BLOCKINVOKE
|
||||||
)
|
)
|
||||||
} ?: parseLambdaExpression(cc)
|
} ?: parseLambdaExpression()
|
||||||
}
|
}
|
||||||
|
|
||||||
Token.Type.RBRACKET, Token.Type.RPAREN -> {
|
Token.Type.RBRACKET, Token.Type.RPAREN -> {
|
||||||
@ -369,7 +362,7 @@ class Compiler(
|
|||||||
else -> {
|
else -> {
|
||||||
cc.previous()
|
cc.previous()
|
||||||
operand?.let { return it }
|
operand?.let { return it }
|
||||||
operand = parseAccessor(cc) ?: return null //throw ScriptError(t.pos, "Expecting expression")
|
operand = parseAccessor() ?: return null //throw ScriptError(t.pos, "Expecting expression")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -378,14 +371,14 @@ class Compiler(
|
|||||||
/**
|
/**
|
||||||
* Parse lambda expression, leading '{' is already consumed
|
* Parse lambda expression, leading '{' is already consumed
|
||||||
*/
|
*/
|
||||||
private fun parseLambdaExpression(cc: CompilerContext): Accessor {
|
private fun parseLambdaExpression(): Accessor {
|
||||||
// lambda args are different:
|
// lambda args are different:
|
||||||
val startPos = cc.currentPos()
|
val startPos = cc.currentPos()
|
||||||
val argsDeclaration = parseArgsDeclaration(cc)
|
val argsDeclaration = parseArgsDeclaration()
|
||||||
if (argsDeclaration != null && argsDeclaration.endTokenType != Token.Type.ARROW)
|
if (argsDeclaration != null && argsDeclaration.endTokenType != Token.Type.ARROW)
|
||||||
throw ScriptError(startPos, "lambda must have either valid arguments declaration with '->' or no arguments")
|
throw ScriptError(startPos, "lambda must have either valid arguments declaration with '->' or no arguments")
|
||||||
|
|
||||||
val body = parseBlock(cc, skipLeadingBrace = true)
|
val body = parseBlock(skipLeadingBrace = true)
|
||||||
|
|
||||||
var closure: Context? = null
|
var closure: Context? = null
|
||||||
|
|
||||||
@ -417,7 +410,7 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseArrayLiteral(cc: CompilerContext): List<ListEntry> {
|
private fun parseArrayLiteral(): List<ListEntry> {
|
||||||
// it should be called after Token.Type.LBRACKET is consumed
|
// it should be called after Token.Type.LBRACKET is consumed
|
||||||
val entries = mutableListOf<ListEntry>()
|
val entries = mutableListOf<ListEntry>()
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -429,19 +422,19 @@ class Compiler(
|
|||||||
|
|
||||||
Token.Type.RBRACKET -> return entries
|
Token.Type.RBRACKET -> return entries
|
||||||
Token.Type.ELLIPSIS -> {
|
Token.Type.ELLIPSIS -> {
|
||||||
parseExpressionLevel(cc)?.let { entries += ListEntry.Spread(it) }
|
parseExpressionLevel()?.let { entries += ListEntry.Spread(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
cc.previous()
|
cc.previous()
|
||||||
parseExpressionLevel(cc)?.let { entries += ListEntry.Element(it) }
|
parseExpressionLevel()?.let { entries += ListEntry.Element(it) }
|
||||||
?: throw ScriptError(t.pos, "invalid list literal: expecting expression")
|
?: throw ScriptError(t.pos, "invalid list literal: expecting expression")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseScopeOperator(operand: Accessor?, cc: CompilerContext): Accessor {
|
private fun parseScopeOperator(operand: Accessor?): Accessor {
|
||||||
// implement global scope maybe?
|
// implement global scope maybe?
|
||||||
if (operand == null) throw ScriptError(cc.next().pos, "Expecting expression before ::")
|
if (operand == null) throw ScriptError(cc.next().pos, "Expecting expression before ::")
|
||||||
val t = cc.next()
|
val t = cc.next()
|
||||||
@ -459,7 +452,7 @@ class Compiler(
|
|||||||
* Parse argument declaration, used in lambda (and later in fn too)
|
* Parse argument declaration, used in lambda (and later in fn too)
|
||||||
* @return declaration or null if there is no valid list of arguments
|
* @return declaration or null if there is no valid list of arguments
|
||||||
*/
|
*/
|
||||||
private fun parseArgsDeclaration(cc: CompilerContext, isClassDeclaration: Boolean = false): ArgsDeclaration? {
|
private fun parseArgsDeclaration(isClassDeclaration: Boolean = false): ArgsDeclaration? {
|
||||||
val result = mutableListOf<ArgsDeclaration.Item>()
|
val result = mutableListOf<ArgsDeclaration.Item>()
|
||||||
var endTokenType: Token.Type? = null
|
var endTokenType: Token.Type? = null
|
||||||
val startPos = cc.savePos()
|
val startPos = cc.savePos()
|
||||||
@ -504,10 +497,10 @@ class Compiler(
|
|||||||
|
|
||||||
var defaultValue: Statement? = null
|
var defaultValue: Statement? = null
|
||||||
cc.ifNextIs(Token.Type.ASSIGN) {
|
cc.ifNextIs(Token.Type.ASSIGN) {
|
||||||
defaultValue = parseExpression(cc)
|
defaultValue = parseExpression()
|
||||||
}
|
}
|
||||||
// type information
|
// type information
|
||||||
val typeInfo = parseTypeDeclaration(cc)
|
val typeInfo = parseTypeDeclaration()
|
||||||
val isEllipsis = cc.skipTokenOfType(Token.Type.ELLIPSIS, isOptional = true)
|
val isEllipsis = cc.skipTokenOfType(Token.Type.ELLIPSIS, isOptional = true)
|
||||||
result += ArgsDeclaration.Item(
|
result += ArgsDeclaration.Item(
|
||||||
t.value,
|
t.value,
|
||||||
@ -554,7 +547,7 @@ class Compiler(
|
|||||||
return ArgsDeclaration(result, endTokenType)
|
return ArgsDeclaration(result, endTokenType)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseTypeDeclaration(cc: CompilerContext): TypeDecl {
|
private fun parseTypeDeclaration(): TypeDecl {
|
||||||
return if (cc.skipTokenOfType(Token.Type.COLON, isOptional = true)) {
|
return if (cc.skipTokenOfType(Token.Type.COLON, isOptional = true)) {
|
||||||
val tt = cc.requireToken(Token.Type.ID, "type name or type expression required")
|
val tt = cc.requireToken(Token.Type.ID, "type name or type expression required")
|
||||||
val isNullable = cc.skipTokenOfType(Token.Type.QUESTION, isOptional = true)
|
val isNullable = cc.skipTokenOfType(Token.Type.QUESTION, isOptional = true)
|
||||||
@ -566,7 +559,7 @@ class Compiler(
|
|||||||
* Parse arguments list during the call and detect last block argument
|
* Parse arguments list during the call and detect last block argument
|
||||||
* _following the parenthesis_ call: `(1,2) { ... }`
|
* _following the parenthesis_ call: `(1,2) { ... }`
|
||||||
*/
|
*/
|
||||||
private fun parseArgs(cc: CompilerContext): Pair<List<ParsedArgument>, Boolean> {
|
private fun parseArgs(): Pair<List<ParsedArgument>, Boolean> {
|
||||||
|
|
||||||
val args = mutableListOf<ParsedArgument>()
|
val args = mutableListOf<ParsedArgument>()
|
||||||
do {
|
do {
|
||||||
@ -577,16 +570,16 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Token.Type.ELLIPSIS -> {
|
Token.Type.ELLIPSIS -> {
|
||||||
parseStatement(cc)?.let { args += ParsedArgument(it, t.pos, isSplat = true) }
|
parseStatement()?.let { args += ParsedArgument(it, t.pos, isSplat = true) }
|
||||||
?: throw ScriptError(t.pos, "Expecting arguments list")
|
?: throw ScriptError(t.pos, "Expecting arguments list")
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
cc.previous()
|
cc.previous()
|
||||||
parseExpression(cc)?.let { args += ParsedArgument(it, t.pos) }
|
parseExpression()?.let { args += ParsedArgument(it, t.pos) }
|
||||||
?: throw ScriptError(t.pos, "Expecting arguments list")
|
?: throw ScriptError(t.pos, "Expecting arguments list")
|
||||||
if (cc.current().type == Token.Type.COLON)
|
if (cc.current().type == Token.Type.COLON)
|
||||||
parseTypeDeclaration(cc)
|
parseTypeDeclaration()
|
||||||
// Here should be a valid termination:
|
// Here should be a valid termination:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -597,7 +590,7 @@ class Compiler(
|
|||||||
var lastBlockArgument = false
|
var lastBlockArgument = false
|
||||||
if (end.type == Token.Type.LBRACE) {
|
if (end.type == Token.Type.LBRACE) {
|
||||||
// last argument - callable
|
// last argument - callable
|
||||||
val callableAccessor = parseLambdaExpression(cc)
|
val callableAccessor = parseLambdaExpression()
|
||||||
args += ParsedArgument(
|
args += ParsedArgument(
|
||||||
// transform accessor to the callable:
|
// transform accessor to the callable:
|
||||||
statement {
|
statement {
|
||||||
@ -613,7 +606,6 @@ class Compiler(
|
|||||||
|
|
||||||
|
|
||||||
private fun parseFunctionCall(
|
private fun parseFunctionCall(
|
||||||
cc: CompilerContext,
|
|
||||||
left: Accessor,
|
left: Accessor,
|
||||||
blockArgument: Boolean,
|
blockArgument: Boolean,
|
||||||
isOptional: Boolean
|
isOptional: Boolean
|
||||||
@ -622,12 +614,12 @@ class Compiler(
|
|||||||
var detectedBlockArgument = blockArgument
|
var detectedBlockArgument = blockArgument
|
||||||
val args = if (blockArgument) {
|
val args = if (blockArgument) {
|
||||||
val blockArg = ParsedArgument(
|
val blockArg = ParsedArgument(
|
||||||
parseExpression(cc)
|
parseExpression()
|
||||||
?: throw ScriptError(cc.currentPos(), "lambda body expected"), cc.currentPos()
|
?: throw ScriptError(cc.currentPos(), "lambda body expected"), cc.currentPos()
|
||||||
)
|
)
|
||||||
listOf(blockArg)
|
listOf(blockArg)
|
||||||
} else {
|
} else {
|
||||||
val r = parseArgs(cc)
|
val r = parseArgs()
|
||||||
detectedBlockArgument = r.second
|
detectedBlockArgument = r.second
|
||||||
r.first
|
r.first
|
||||||
}
|
}
|
||||||
@ -647,13 +639,13 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseAccessor(cc: CompilerContext): Accessor? {
|
private fun parseAccessor(): Accessor? {
|
||||||
// could be: literal
|
// could be: literal
|
||||||
val t = cc.next()
|
val t = cc.next()
|
||||||
return when (t.type) {
|
return when (t.type) {
|
||||||
Token.Type.INT, Token.Type.REAL, Token.Type.HEX -> {
|
Token.Type.INT, Token.Type.REAL, Token.Type.HEX -> {
|
||||||
cc.previous()
|
cc.previous()
|
||||||
val n = parseNumber(true, cc)
|
val n = parseNumber(true)
|
||||||
Accessor {
|
Accessor {
|
||||||
n.asReadonly
|
n.asReadonly
|
||||||
}
|
}
|
||||||
@ -664,12 +656,12 @@ class Compiler(
|
|||||||
Token.Type.CHAR -> Accessor { ObjChar(t.value[0]).asReadonly }
|
Token.Type.CHAR -> Accessor { ObjChar(t.value[0]).asReadonly }
|
||||||
|
|
||||||
Token.Type.PLUS -> {
|
Token.Type.PLUS -> {
|
||||||
val n = parseNumber(true, cc)
|
val n = parseNumber(true)
|
||||||
Accessor { n.asReadonly }
|
Accessor { n.asReadonly }
|
||||||
}
|
}
|
||||||
|
|
||||||
Token.Type.MINUS -> {
|
Token.Type.MINUS -> {
|
||||||
val n = parseNumber(false, cc)
|
val n = parseNumber(false)
|
||||||
Accessor { n.asReadonly }
|
Accessor { n.asReadonly }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -701,8 +693,8 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseNumber(isPlus: Boolean, tokens: CompilerContext): Obj {
|
private fun parseNumber(isPlus: Boolean): Obj {
|
||||||
val t = tokens.next()
|
val t = cc.next()
|
||||||
return when (t.type) {
|
return when (t.type) {
|
||||||
Token.Type.INT, Token.Type.HEX -> {
|
Token.Type.INT, Token.Type.HEX -> {
|
||||||
val n = t.value.toLong(if (t.type == Token.Type.HEX) 16 else 10)
|
val n = t.value.toLong(if (t.type == Token.Type.HEX) 16 else 10)
|
||||||
@ -724,36 +716,36 @@ class Compiler(
|
|||||||
* Parse keyword-starting statement.
|
* Parse keyword-starting statement.
|
||||||
* @return parsed statement or null if, for example. [id] is not among keywords
|
* @return parsed statement or null if, for example. [id] is not among keywords
|
||||||
*/
|
*/
|
||||||
private fun parseKeywordStatement(id: Token, cc: CompilerContext): Statement? = when (id.value) {
|
private fun parseKeywordStatement(id: Token): Statement? = when (id.value) {
|
||||||
"val" -> parseVarDeclaration(false, Visibility.Public, cc)
|
"val" -> parseVarDeclaration(false, Visibility.Public)
|
||||||
"var" -> parseVarDeclaration(true, Visibility.Public, cc)
|
"var" -> parseVarDeclaration(true, Visibility.Public)
|
||||||
"while" -> parseWhileStatement(cc)
|
"while" -> parseWhileStatement()
|
||||||
"do" -> parseDoWhileStatement(cc)
|
"do" -> parseDoWhileStatement()
|
||||||
"for" -> parseForStatement(cc)
|
"for" -> parseForStatement()
|
||||||
"break" -> parseBreakStatement(id.pos, cc)
|
"break" -> parseBreakStatement(id.pos)
|
||||||
"continue" -> parseContinueStatement(id.pos, cc)
|
"continue" -> parseContinueStatement(id.pos)
|
||||||
"if" -> parseIfStatement(cc)
|
"if" -> parseIfStatement()
|
||||||
"class" -> parseClassDeclaration(cc, false)
|
"class" -> parseClassDeclaration(false)
|
||||||
"try" -> parseTryStatement(cc)
|
"try" -> parseTryStatement()
|
||||||
"throw" -> parseThrowStatement(cc)
|
"throw" -> parseThrowStatement()
|
||||||
"when" -> parseWhenStatement(cc)
|
"when" -> parseWhenStatement()
|
||||||
else -> {
|
else -> {
|
||||||
// triples
|
// triples
|
||||||
cc.previous()
|
cc.previous()
|
||||||
val isExtern = cc.skipId("extern")
|
val isExtern = cc.skipId("extern")
|
||||||
when {
|
when {
|
||||||
cc.matchQualifiers("fun", "private") -> parseFunctionDeclaration(cc, Visibility.Private, isExtern)
|
cc.matchQualifiers("fun", "private") -> parseFunctionDeclaration( Visibility.Private, isExtern)
|
||||||
cc.matchQualifiers("fn", "private") -> parseFunctionDeclaration(cc, Visibility.Private, isExtern)
|
cc.matchQualifiers("fn", "private") -> parseFunctionDeclaration( Visibility.Private, isExtern)
|
||||||
cc.matchQualifiers("fun", "open") -> parseFunctionDeclaration(cc, isOpen = true, isExtern = isExtern)
|
cc.matchQualifiers("fun", "open") -> parseFunctionDeclaration( isOpen = true, isExtern = isExtern)
|
||||||
cc.matchQualifiers("fn", "open") -> parseFunctionDeclaration(cc, isOpen = true, isExtern = isExtern)
|
cc.matchQualifiers("fn", "open") -> parseFunctionDeclaration( isOpen = true, isExtern = isExtern)
|
||||||
|
|
||||||
cc.matchQualifiers("fun") -> parseFunctionDeclaration(cc, isOpen = false, isExtern = isExtern)
|
cc.matchQualifiers("fun") -> parseFunctionDeclaration( isOpen = false, isExtern = isExtern)
|
||||||
cc.matchQualifiers("fn") -> parseFunctionDeclaration(cc, isOpen = false, isExtern = isExtern)
|
cc.matchQualifiers("fn") -> parseFunctionDeclaration( isOpen = false, isExtern = isExtern)
|
||||||
|
|
||||||
cc.matchQualifiers("val", "private") -> parseVarDeclaration(false, Visibility.Private, cc)
|
cc.matchQualifiers("val", "private") -> parseVarDeclaration(false, Visibility.Private)
|
||||||
cc.matchQualifiers("var", "private") -> parseVarDeclaration(true, Visibility.Private, cc)
|
cc.matchQualifiers("var", "private") -> parseVarDeclaration(true, Visibility.Private)
|
||||||
cc.matchQualifiers("val", "open") -> parseVarDeclaration(false, Visibility.Private, cc, true)
|
cc.matchQualifiers("val", "open") -> parseVarDeclaration(false, Visibility.Private, true)
|
||||||
cc.matchQualifiers("var", "open") -> parseVarDeclaration(true, Visibility.Private, cc, true)
|
cc.matchQualifiers("var", "open") -> parseVarDeclaration(true, Visibility.Private, true)
|
||||||
else -> {
|
else -> {
|
||||||
cc.next()
|
cc.next()
|
||||||
null
|
null
|
||||||
@ -764,12 +756,12 @@ class Compiler(
|
|||||||
|
|
||||||
data class WhenCase(val condition: Statement, val block: Statement)
|
data class WhenCase(val condition: Statement, val block: Statement)
|
||||||
|
|
||||||
private fun parseWhenStatement(cc: CompilerContext): Statement {
|
private fun parseWhenStatement(): Statement {
|
||||||
// has a value, when(value) ?
|
// has a value, when(value) ?
|
||||||
var t = cc.skipWsTokens()
|
var t = cc.skipWsTokens()
|
||||||
return if (t.type == Token.Type.LPAREN) {
|
return if (t.type == Token.Type.LPAREN) {
|
||||||
// when(value)
|
// when(value)
|
||||||
val value = parseStatement(cc) ?: throw ScriptError(cc.currentPos(), "when(value) expected")
|
val value = parseStatement() ?: throw ScriptError(cc.currentPos(), "when(value) expected")
|
||||||
cc.skipTokenOfType(Token.Type.RPAREN)
|
cc.skipTokenOfType(Token.Type.RPAREN)
|
||||||
t = cc.next()
|
t = cc.next()
|
||||||
if (t.type != Token.Type.LBRACE) throw ScriptError(t.pos, "when { ... } expected")
|
if (t.type != Token.Type.LBRACE) throw ScriptError(t.pos, "when { ... } expected")
|
||||||
@ -796,7 +788,7 @@ class Compiler(
|
|||||||
Token.Type.NOTIN -> {
|
Token.Type.NOTIN -> {
|
||||||
// we need a copy in the closure:
|
// we need a copy in the closure:
|
||||||
val isIn = t.type == Token.Type.IN
|
val isIn = t.type == Token.Type.IN
|
||||||
val container = parseExpression(cc) ?: throw ScriptError(cc.currentPos(), "type expected")
|
val container = parseExpression() ?: throw ScriptError(cc.currentPos(), "type expected")
|
||||||
currentCondition += statement {
|
currentCondition += statement {
|
||||||
val r = container.execute(this).contains(this, whenValue)
|
val r = container.execute(this).contains(this, whenValue)
|
||||||
ObjBool(if (isIn) r else !r)
|
ObjBool(if (isIn) r else !r)
|
||||||
@ -806,7 +798,7 @@ class Compiler(
|
|||||||
Token.Type.IS, Token.Type.NOTIS -> {
|
Token.Type.IS, Token.Type.NOTIS -> {
|
||||||
// we need a copy in the closure:
|
// we need a copy in the closure:
|
||||||
val isIn = t.type == Token.Type.IS
|
val isIn = t.type == Token.Type.IS
|
||||||
val caseType = parseExpression(cc) ?: throw ScriptError(cc.currentPos(), "type expected")
|
val caseType = parseExpression() ?: throw ScriptError(cc.currentPos(), "type expected")
|
||||||
currentCondition += statement {
|
currentCondition += statement {
|
||||||
val r = whenValue.isInstanceOf(caseType.execute(this))
|
val r = whenValue.isInstanceOf(caseType.execute(this))
|
||||||
ObjBool(if (isIn) r else !r)
|
ObjBool(if (isIn) r else !r)
|
||||||
@ -830,11 +822,11 @@ class Compiler(
|
|||||||
"when else block already defined"
|
"when else block already defined"
|
||||||
)
|
)
|
||||||
elseCase =
|
elseCase =
|
||||||
parseStatement(cc) ?: throw ScriptError(cc.currentPos(), "when else block expected")
|
parseStatement() ?: throw ScriptError(cc.currentPos(), "when else block expected")
|
||||||
skipParseBody = true
|
skipParseBody = true
|
||||||
} else {
|
} else {
|
||||||
cc.previous()
|
cc.previous()
|
||||||
val x = parseExpression(cc)
|
val x = parseExpression()
|
||||||
?: throw ScriptError(cc.currentPos(), "when case condition expected")
|
?: throw ScriptError(cc.currentPos(), "when case condition expected")
|
||||||
currentCondition += statement {
|
currentCondition += statement {
|
||||||
ObjBool(x.execute(this).compareTo(this, whenValue) == 0)
|
ObjBool(x.execute(this).compareTo(this, whenValue) == 0)
|
||||||
@ -845,7 +837,7 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
// parsed conditions?
|
// parsed conditions?
|
||||||
if (!skipParseBody) {
|
if (!skipParseBody) {
|
||||||
val block = parseStatement(cc) ?: throw ScriptError(cc.currentPos(), "when case block expected")
|
val block = parseStatement() ?: throw ScriptError(cc.currentPos(), "when case block expected")
|
||||||
for (c in currentCondition) cases += WhenCase(c, block)
|
for (c in currentCondition) cases += WhenCase(c, block)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -869,8 +861,8 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseThrowStatement(cc: CompilerContext): Statement {
|
private fun parseThrowStatement(): Statement {
|
||||||
val throwStatement = parseStatement(cc) ?: throw ScriptError(cc.currentPos(), "throw object expected")
|
val throwStatement = parseStatement() ?: throw ScriptError(cc.currentPos(), "throw object expected")
|
||||||
return statement {
|
return statement {
|
||||||
var errorObject = throwStatement.execute(this)
|
var errorObject = throwStatement.execute(this)
|
||||||
if (errorObject is ObjString)
|
if (errorObject is ObjString)
|
||||||
@ -887,8 +879,8 @@ class Compiler(
|
|||||||
val block: Statement
|
val block: Statement
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun parseTryStatement(cc: CompilerContext): Statement {
|
private fun parseTryStatement(): Statement {
|
||||||
val body = parseBlock(cc)
|
val body = parseBlock()
|
||||||
val catches = mutableListOf<CatchBlockData>()
|
val catches = mutableListOf<CatchBlockData>()
|
||||||
cc.skipTokens(Token.Type.NEWLINE)
|
cc.skipTokens(Token.Type.NEWLINE)
|
||||||
var t = cc.next()
|
var t = cc.next()
|
||||||
@ -925,7 +917,7 @@ class Compiler(
|
|||||||
exClassNames += "Exception"
|
exClassNames += "Exception"
|
||||||
cc.skipTokenOfType(Token.Type.RPAREN)
|
cc.skipTokenOfType(Token.Type.RPAREN)
|
||||||
}
|
}
|
||||||
val block = parseBlock(cc)
|
val block = parseBlock()
|
||||||
catches += CatchBlockData(catchVar, exClassNames, block)
|
catches += CatchBlockData(catchVar, exClassNames, block)
|
||||||
cc.skipTokens(Token.Type.NEWLINE)
|
cc.skipTokens(Token.Type.NEWLINE)
|
||||||
t = cc.next()
|
t = cc.next()
|
||||||
@ -934,13 +926,13 @@ class Compiler(
|
|||||||
cc.skipTokenOfType(Token.Type.LBRACE, "expected catch(...) or catch { ... } here")
|
cc.skipTokenOfType(Token.Type.LBRACE, "expected catch(...) or catch { ... } here")
|
||||||
catches += CatchBlockData(
|
catches += CatchBlockData(
|
||||||
Token("it", cc.currentPos(), Token.Type.ID), listOf("Exception"),
|
Token("it", cc.currentPos(), Token.Type.ID), listOf("Exception"),
|
||||||
parseBlock(cc, true)
|
parseBlock(true)
|
||||||
)
|
)
|
||||||
t = cc.next()
|
t = cc.next()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val finallyClause = if (t.value == "finally") {
|
val finallyClause = if (t.value == "finally") {
|
||||||
parseBlock(cc)
|
parseBlock()
|
||||||
} else {
|
} else {
|
||||||
cc.previous()
|
cc.previous()
|
||||||
null
|
null
|
||||||
@ -991,11 +983,11 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseClassDeclaration(cc: CompilerContext, isStruct: Boolean): Statement {
|
private fun parseClassDeclaration(isStruct: Boolean): Statement {
|
||||||
val nameToken = cc.requireToken(Token.Type.ID)
|
val nameToken = cc.requireToken(Token.Type.ID)
|
||||||
val constructorArgsDeclaration =
|
val constructorArgsDeclaration =
|
||||||
if (cc.skipTokenOfType(Token.Type.LPAREN, isOptional = true))
|
if (cc.skipTokenOfType(Token.Type.LPAREN, isOptional = true))
|
||||||
parseArgsDeclaration(cc, isClassDeclaration = true)
|
parseArgsDeclaration( isClassDeclaration = true)
|
||||||
else null
|
else null
|
||||||
|
|
||||||
if (constructorArgsDeclaration != null && constructorArgsDeclaration.endTokenType != Token.Type.RPAREN)
|
if (constructorArgsDeclaration != null && constructorArgsDeclaration.endTokenType != Token.Type.RPAREN)
|
||||||
@ -1009,7 +1001,7 @@ class Compiler(
|
|||||||
|
|
||||||
val bodyInit: Statement? = if (t.type == Token.Type.LBRACE) {
|
val bodyInit: Statement? = if (t.type == Token.Type.LBRACE) {
|
||||||
// parse body
|
// parse body
|
||||||
parseScript(t.pos, cc).also {
|
parseScript().also {
|
||||||
cc.skipTokens(Token.Type.RBRACE)
|
cc.skipTokens(Token.Type.RBRACE)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1052,7 +1044,7 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun getLabel(cc: CompilerContext, maxDepth: Int = 2): String? {
|
private fun getLabel(maxDepth: Int = 2): String? {
|
||||||
var cnt = 0
|
var cnt = 0
|
||||||
var found: String? = null
|
var found: String? = null
|
||||||
while (cc.hasPrevious() && cnt < maxDepth) {
|
while (cc.hasPrevious() && cnt < maxDepth) {
|
||||||
@ -1067,9 +1059,9 @@ class Compiler(
|
|||||||
return found
|
return found
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseForStatement(cc: CompilerContext): Statement {
|
private fun parseForStatement(): Statement {
|
||||||
val label = getLabel(cc)?.also { cc.labels += it }
|
val label = getLabel()?.also { cc.labels += it }
|
||||||
val start = ensureLparen(cc)
|
val start = ensureLparen()
|
||||||
|
|
||||||
val tVar = cc.next()
|
val tVar = cc.next()
|
||||||
if (tVar.type != Token.Type.ID)
|
if (tVar.type != Token.Type.ID)
|
||||||
@ -1077,16 +1069,16 @@ class Compiler(
|
|||||||
val tOp = cc.next()
|
val tOp = cc.next()
|
||||||
if (tOp.value == "in") {
|
if (tOp.value == "in") {
|
||||||
// in loop
|
// in loop
|
||||||
val source = parseStatement(cc) ?: throw ScriptError(start, "Bad for statement: expected expression")
|
val source = parseStatement() ?: throw ScriptError(start, "Bad for statement: expected expression")
|
||||||
ensureRparen(cc)
|
ensureRparen()
|
||||||
|
|
||||||
val (canBreak, body) = cc.parseLoop {
|
val (canBreak, body) = cc.parseLoop {
|
||||||
parseStatement(cc) ?: throw ScriptError(start, "Bad for statement: expected loop body")
|
parseStatement() ?: throw ScriptError(start, "Bad for statement: expected loop body")
|
||||||
}
|
}
|
||||||
// possible else clause
|
// possible else clause
|
||||||
cc.skipTokenOfType(Token.Type.NEWLINE, isOptional = true)
|
cc.skipTokenOfType(Token.Type.NEWLINE, isOptional = true)
|
||||||
val elseStatement = if (cc.next().let { it.type == Token.Type.ID && it.value == "else" }) {
|
val elseStatement = if (cc.next().let { it.type == Token.Type.ID && it.value == "else" }) {
|
||||||
parseStatement(cc)
|
parseStatement()
|
||||||
} else {
|
} else {
|
||||||
cc.previous()
|
cc.previous()
|
||||||
null
|
null
|
||||||
@ -1218,10 +1210,10 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("UNUSED_VARIABLE")
|
@Suppress("UNUSED_VARIABLE")
|
||||||
private fun parseDoWhileStatement(cc: CompilerContext): Statement {
|
private fun parseDoWhileStatement(): Statement {
|
||||||
val label = getLabel(cc)?.also { cc.labels += it }
|
val label = getLabel()?.also { cc.labels += it }
|
||||||
val (breakFound, body) = cc.parseLoop {
|
val (breakFound, body) = cc.parseLoop {
|
||||||
parseStatement(cc) ?: throw ScriptError(cc.currentPos(), "Bad while statement: expected statement")
|
parseStatement() ?: throw ScriptError(cc.currentPos(), "Bad while statement: expected statement")
|
||||||
}
|
}
|
||||||
label?.also { cc.labels -= it }
|
label?.also { cc.labels -= it }
|
||||||
|
|
||||||
@ -1231,14 +1223,14 @@ class Compiler(
|
|||||||
if (t.type != Token.Type.ID && t.value != "while")
|
if (t.type != Token.Type.ID && t.value != "while")
|
||||||
cc.skipTokenOfType(Token.Type.LPAREN, "expected '(' here")
|
cc.skipTokenOfType(Token.Type.LPAREN, "expected '(' here")
|
||||||
|
|
||||||
val conditionStart = ensureLparen(cc)
|
val conditionStart = ensureLparen()
|
||||||
val condition =
|
val condition =
|
||||||
parseExpression(cc) ?: throw ScriptError(conditionStart, "Bad while statement: expected expression")
|
parseExpression() ?: throw ScriptError(conditionStart, "Bad while statement: expected expression")
|
||||||
ensureRparen(cc)
|
ensureRparen()
|
||||||
|
|
||||||
cc.skipTokenOfType(Token.Type.NEWLINE, isOptional = true)
|
cc.skipTokenOfType(Token.Type.NEWLINE, isOptional = true)
|
||||||
val elseStatement = if (cc.next().let { it.type == Token.Type.ID && it.value == "else" }) {
|
val elseStatement = if (cc.next().let { it.type == Token.Type.ID && it.value == "else" }) {
|
||||||
parseStatement(cc)
|
parseStatement()
|
||||||
} else {
|
} else {
|
||||||
cc.previous()
|
cc.previous()
|
||||||
null
|
null
|
||||||
@ -1270,19 +1262,19 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseWhileStatement(cc: CompilerContext): Statement {
|
private fun parseWhileStatement(): Statement {
|
||||||
val label = getLabel(cc)?.also { cc.labels += it }
|
val label = getLabel()?.also { cc.labels += it }
|
||||||
val start = ensureLparen(cc)
|
val start = ensureLparen()
|
||||||
val condition =
|
val condition =
|
||||||
parseExpression(cc) ?: throw ScriptError(start, "Bad while statement: expected expression")
|
parseExpression() ?: throw ScriptError(start, "Bad while statement: expected expression")
|
||||||
ensureRparen(cc)
|
ensureRparen()
|
||||||
|
|
||||||
val body = parseStatement(cc) ?: throw ScriptError(start, "Bad while statement: expected statement")
|
val body = parseStatement() ?: throw ScriptError(start, "Bad while statement: expected statement")
|
||||||
label?.also { cc.labels -= it }
|
label?.also { cc.labels -= it }
|
||||||
|
|
||||||
cc.skipTokenOfType(Token.Type.NEWLINE, isOptional = true)
|
cc.skipTokenOfType(Token.Type.NEWLINE, isOptional = true)
|
||||||
val elseStatement = if (cc.next().let { it.type == Token.Type.ID && it.value == "else" }) {
|
val elseStatement = if (cc.next().let { it.type == Token.Type.ID && it.value == "else" }) {
|
||||||
parseStatement(cc)
|
parseStatement()
|
||||||
} else {
|
} else {
|
||||||
cc.previous()
|
cc.previous()
|
||||||
null
|
null
|
||||||
@ -1312,7 +1304,7 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseBreakStatement(start: Pos, cc: CompilerContext): Statement {
|
private fun parseBreakStatement(start: Pos): Statement {
|
||||||
var t = cc.next()
|
var t = cc.next()
|
||||||
|
|
||||||
val label = if (t.pos.line != start.line || t.type != Token.Type.ATLABEL) {
|
val label = if (t.pos.line != start.line || t.type != Token.Type.ATLABEL) {
|
||||||
@ -1333,7 +1325,7 @@ class Compiler(
|
|||||||
t.type != Token.Type.NEWLINE)
|
t.type != Token.Type.NEWLINE)
|
||||||
) {
|
) {
|
||||||
// we have something on this line, could be expression
|
// we have something on this line, could be expression
|
||||||
parseStatement(cc)
|
parseStatement()
|
||||||
} else null
|
} else null
|
||||||
|
|
||||||
cc.addBreak()
|
cc.addBreak()
|
||||||
@ -1348,7 +1340,7 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseContinueStatement(start: Pos, cc: CompilerContext): Statement {
|
private fun parseContinueStatement(start: Pos): Statement {
|
||||||
val t = cc.next()
|
val t = cc.next()
|
||||||
|
|
||||||
val label = if (t.pos.line != start.line || t.type != Token.Type.ATLABEL) {
|
val label = if (t.pos.line != start.line || t.type != Token.Type.ATLABEL) {
|
||||||
@ -1370,38 +1362,38 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ensureRparen(tokens: CompilerContext): Pos {
|
private fun ensureRparen(): Pos {
|
||||||
val t = tokens.next()
|
val t = cc.next()
|
||||||
if (t.type != Token.Type.RPAREN)
|
if (t.type != Token.Type.RPAREN)
|
||||||
throw ScriptError(t.pos, "expected ')'")
|
throw ScriptError(t.pos, "expected ')'")
|
||||||
return t.pos
|
return t.pos
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ensureLparen(tokens: CompilerContext): Pos {
|
private fun ensureLparen(): Pos {
|
||||||
val t = tokens.next()
|
val t = cc.next()
|
||||||
if (t.type != Token.Type.LPAREN)
|
if (t.type != Token.Type.LPAREN)
|
||||||
throw ScriptError(t.pos, "expected '('")
|
throw ScriptError(t.pos, "expected '('")
|
||||||
return t.pos
|
return t.pos
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseIfStatement(tokens: CompilerContext): Statement {
|
private fun parseIfStatement(): Statement {
|
||||||
val start = ensureLparen(tokens)
|
val start = ensureLparen()
|
||||||
|
|
||||||
val condition = parseExpression(tokens)
|
val condition = parseExpression()
|
||||||
?: throw ScriptError(start, "Bad if statement: expected expression")
|
?: throw ScriptError(start, "Bad if statement: expected expression")
|
||||||
|
|
||||||
val pos = ensureRparen(tokens)
|
val pos = ensureRparen()
|
||||||
|
|
||||||
val ifBody = parseStatement(tokens) ?: throw ScriptError(pos, "Bad if statement: expected statement")
|
val ifBody = parseStatement() ?: throw ScriptError(pos, "Bad if statement: expected statement")
|
||||||
|
|
||||||
tokens.skipTokenOfType(Token.Type.NEWLINE, isOptional = true)
|
cc.skipTokenOfType(Token.Type.NEWLINE, isOptional = true)
|
||||||
// could be else block:
|
// could be else block:
|
||||||
val t2 = tokens.next()
|
val t2 = cc.next()
|
||||||
|
|
||||||
// we generate different statements: optimization
|
// we generate different statements: optimization
|
||||||
return if (t2.type == Token.Type.ID && t2.value == "else") {
|
return if (t2.type == Token.Type.ID && t2.value == "else") {
|
||||||
val elseBody =
|
val elseBody =
|
||||||
parseStatement(tokens) ?: throw ScriptError(pos, "Bad else statement: expected statement")
|
parseStatement() ?: throw ScriptError(pos, "Bad else statement: expected statement")
|
||||||
return statement(start) {
|
return statement(start) {
|
||||||
if (condition.execute(it).toBool())
|
if (condition.execute(it).toBool())
|
||||||
ifBody.execute(it)
|
ifBody.execute(it)
|
||||||
@ -1409,7 +1401,7 @@ class Compiler(
|
|||||||
elseBody.execute(it)
|
elseBody.execute(it)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
tokens.previous()
|
cc.previous()
|
||||||
statement(start) {
|
statement(start) {
|
||||||
if (condition.execute(it).toBool())
|
if (condition.execute(it).toBool())
|
||||||
ifBody.execute(it)
|
ifBody.execute(it)
|
||||||
@ -1420,7 +1412,6 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun parseFunctionDeclaration(
|
private fun parseFunctionDeclaration(
|
||||||
cc: CompilerContext,
|
|
||||||
visibility: Visibility = Visibility.Public,
|
visibility: Visibility = Visibility.Public,
|
||||||
@Suppress("UNUSED_PARAMETER") isOpen: Boolean = false,
|
@Suppress("UNUSED_PARAMETER") isOpen: Boolean = false,
|
||||||
isExtern: Boolean = false
|
isExtern: Boolean = false
|
||||||
@ -1446,20 +1437,20 @@ class Compiler(
|
|||||||
if (t.type != Token.Type.LPAREN)
|
if (t.type != Token.Type.LPAREN)
|
||||||
throw ScriptError(t.pos, "Bad function definition: expected '(' after 'fn ${name}'")
|
throw ScriptError(t.pos, "Bad function definition: expected '(' after 'fn ${name}'")
|
||||||
|
|
||||||
val argsDeclaration = parseArgsDeclaration(cc)
|
val argsDeclaration = parseArgsDeclaration()
|
||||||
if (argsDeclaration == null || argsDeclaration.endTokenType != Token.Type.RPAREN)
|
if (argsDeclaration == null || argsDeclaration.endTokenType != Token.Type.RPAREN)
|
||||||
throw ScriptError(
|
throw ScriptError(
|
||||||
t.pos,
|
t.pos,
|
||||||
"Bad function definition: expected valid argument declaration or () after 'fn ${name}'"
|
"Bad function definition: expected valid argument declaration or () after 'fn ${name}'"
|
||||||
)
|
)
|
||||||
|
|
||||||
if (cc.current().type == Token.Type.COLON) parseTypeDeclaration(cc)
|
if (cc.current().type == Token.Type.COLON) parseTypeDeclaration()
|
||||||
|
|
||||||
// Here we should be at open body
|
// Here we should be at open body
|
||||||
val fnStatements = if (isExtern)
|
val fnStatements = if (isExtern)
|
||||||
statement { raiseError("extern function not provided: $name") }
|
statement { raiseError("extern function not provided: $name") }
|
||||||
else
|
else
|
||||||
parseBlock(cc)
|
parseBlock()
|
||||||
|
|
||||||
var closure: Context? = null
|
var closure: Context? = null
|
||||||
|
|
||||||
@ -1496,14 +1487,14 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseBlock(cc: CompilerContext, skipLeadingBrace: Boolean = false): Statement {
|
private fun parseBlock(skipLeadingBrace: Boolean = false): Statement {
|
||||||
val startPos = cc.currentPos()
|
val startPos = cc.currentPos()
|
||||||
if (!skipLeadingBrace) {
|
if (!skipLeadingBrace) {
|
||||||
val t = cc.next()
|
val t = cc.next()
|
||||||
if (t.type != Token.Type.LBRACE)
|
if (t.type != Token.Type.LBRACE)
|
||||||
throw ScriptError(t.pos, "Expected block body start: {")
|
throw ScriptError(t.pos, "Expected block body start: {")
|
||||||
}
|
}
|
||||||
val block = parseScript(startPos, cc)
|
val block = parseScript()
|
||||||
return statement(startPos) {
|
return statement(startPos) {
|
||||||
// block run on inner context:
|
// block run on inner context:
|
||||||
block.execute(if (it.skipContextCreation) it else it.copy(startPos))
|
block.execute(if (it.skipContextCreation) it else it.copy(startPos))
|
||||||
@ -1517,27 +1508,26 @@ class Compiler(
|
|||||||
private fun parseVarDeclaration(
|
private fun parseVarDeclaration(
|
||||||
isMutable: Boolean,
|
isMutable: Boolean,
|
||||||
visibility: Visibility,
|
visibility: Visibility,
|
||||||
tokens: CompilerContext,
|
|
||||||
@Suppress("UNUSED_PARAMETER") isOpen: Boolean = false
|
@Suppress("UNUSED_PARAMETER") isOpen: Boolean = false
|
||||||
): Statement {
|
): Statement {
|
||||||
val nameToken = tokens.next()
|
val nameToken = cc.next()
|
||||||
val start = nameToken.pos
|
val start = nameToken.pos
|
||||||
if (nameToken.type != Token.Type.ID)
|
if (nameToken.type != Token.Type.ID)
|
||||||
throw ScriptError(nameToken.pos, "Expected identifier here")
|
throw ScriptError(nameToken.pos, "Expected identifier here")
|
||||||
val name = nameToken.value
|
val name = nameToken.value
|
||||||
|
|
||||||
val eqToken = tokens.next()
|
val eqToken = cc.next()
|
||||||
var setNull = false
|
var setNull = false
|
||||||
if (eqToken.type != Token.Type.ASSIGN) {
|
if (eqToken.type != Token.Type.ASSIGN) {
|
||||||
if (!isMutable)
|
if (!isMutable)
|
||||||
throw ScriptError(start, "val must be initialized")
|
throw ScriptError(start, "val must be initialized")
|
||||||
else {
|
else {
|
||||||
tokens.previous()
|
cc.previous()
|
||||||
setNull = true
|
setNull = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val initialExpression = if (setNull) null else parseStatement(tokens, true)
|
val initialExpression = if (setNull) null else parseStatement( true)
|
||||||
?: throw ScriptError(eqToken.pos, "Expected initializer expression")
|
?: throw ScriptError(eqToken.pos, "Expected initializer expression")
|
||||||
|
|
||||||
return statement(nameToken.pos) { context ->
|
return statement(nameToken.pos) { context ->
|
||||||
@ -1571,6 +1561,10 @@ class Compiler(
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
|
fun compile(source: Source): Script {
|
||||||
|
return Compiler(CompilerContext(parseLyng(source))).parseScript()
|
||||||
|
}
|
||||||
|
|
||||||
private var lastPriority = 0
|
private var lastPriority = 0
|
||||||
val allOps = listOf(
|
val allOps = listOf(
|
||||||
// assignments, lowest priority
|
// assignments, lowest priority
|
||||||
@ -1691,7 +1685,7 @@ class Compiler(
|
|||||||
allOps.filter { it.priority == l }.associateBy { it.tokenType }
|
allOps.filter { it.priority == l }.associateBy { it.tokenType }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun compile(code: String): Script = Compiler().compile(Source("<eval>", code))
|
fun compile(code: String): Script = compile(Source("<eval>", code))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The keywords that stop processing of expression term
|
* The keywords that stop processing of expression term
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
package net.sergeych.lyng
|
package net.sergeych.lyng
|
||||||
|
|
||||||
internal class CompilerContext(val tokens: List<Token>) {
|
class CompilerContext(val tokens: List<Token>) {
|
||||||
val labels = mutableSetOf<String>()
|
val labels = mutableSetOf<String>()
|
||||||
|
|
||||||
var breakFound = false
|
var breakFound = false
|
||||||
private set
|
|
||||||
|
|
||||||
var loopLevel = 0
|
var loopLevel = 0
|
||||||
private set
|
|
||||||
|
|
||||||
inline fun <T> parseLoop(f: () -> T): Pair<Boolean, T> {
|
inline fun <T> parseLoop(f: () -> T): Pair<Boolean, T> {
|
||||||
if (++loopLevel == 0) breakFound = false
|
if (++loopLevel == 0) breakFound = false
|
||||||
|
@ -123,7 +123,7 @@ open class Context(
|
|||||||
fun addConst(name: String, value: Obj) = addItem(name, false, value)
|
fun addConst(name: String, value: Obj) = addItem(name, false, value)
|
||||||
|
|
||||||
suspend fun eval(code: String): Obj =
|
suspend fun eval(code: String): Obj =
|
||||||
Compiler().compile(code.toSource()).execute(this)
|
Compiler.compile(code.toSource()).execute(this)
|
||||||
|
|
||||||
fun containsLocal(name: String): Boolean = name in objects
|
fun containsLocal(name: String): Boolean = name in objects
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user