ref #13 get rid pf tokens for private/protected, added open attribute parsing
This commit is contained in:
parent
59a76efdce
commit
dacdcd7faa
@ -39,13 +39,6 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Token.Type.PRIVATE, Token.Type.PROTECTED -> {
|
|
||||||
if (cc.nextIdValue() in setOf("var", "val", "class", "fun", "fn")) {
|
|
||||||
continue
|
|
||||||
} else
|
|
||||||
throw ScriptError(t.pos, "unexpected keyword ${t.value}")
|
|
||||||
}
|
|
||||||
|
|
||||||
Token.Type.PLUS2, Token.Type.MINUS2 -> {
|
Token.Type.PLUS2, Token.Type.MINUS2 -> {
|
||||||
cc.previous()
|
cc.previous()
|
||||||
parseExpression(cc)
|
parseExpression(cc)
|
||||||
@ -149,7 +142,7 @@ class Compiler(
|
|||||||
v.invokeInstanceMethod(
|
v.invokeInstanceMethod(
|
||||||
context,
|
context,
|
||||||
next.value,
|
next.value,
|
||||||
args.toArguments(context,false)
|
args.toArguments(context, false)
|
||||||
), isMutable = false
|
), isMutable = false
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -157,7 +150,7 @@ class Compiler(
|
|||||||
|
|
||||||
Token.Type.LBRACE -> {
|
Token.Type.LBRACE -> {
|
||||||
// single lambda arg, like assertTrows { ... }
|
// single lambda arg, like assertTrows { ... }
|
||||||
cc.next()
|
cc.next()
|
||||||
isCall = true
|
isCall = true
|
||||||
val lambda =
|
val lambda =
|
||||||
parseExpression(cc) ?: throw ScriptError(t.pos, "expected valid lambda here")
|
parseExpression(cc) ?: throw ScriptError(t.pos, "expected valid lambda here")
|
||||||
@ -170,7 +163,7 @@ class Compiler(
|
|||||||
v.invokeInstanceMethod(
|
v.invokeInstanceMethod(
|
||||||
context,
|
context,
|
||||||
next.value,
|
next.value,
|
||||||
Arguments(listOf(lambda),true)
|
Arguments(listOf(lambda), true)
|
||||||
), isMutable = false
|
), isMutable = false
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -458,17 +451,14 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Token.Type.NEWLINE -> {}
|
Token.Type.NEWLINE -> {}
|
||||||
Token.Type.PROTECTED, Token.Type.PRIVATE -> {
|
|
||||||
if (!isClassDeclaration) {
|
|
||||||
cc.restorePos(startPos); return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Token.Type.ID -> {
|
Token.Type.ID -> {
|
||||||
// visibility
|
// visibility
|
||||||
val visibility = if (isClassDeclaration)
|
val visibility = if( isClassDeclaration && t.value == "private" ) {
|
||||||
cc.getVisibility(Visibility.Public)
|
t = cc.next()
|
||||||
else Visibility.Public
|
Visibility.Private
|
||||||
|
} else Visibility.Public
|
||||||
|
|
||||||
// val/var?
|
// val/var?
|
||||||
val access = when (t.value) {
|
val access = when (t.value) {
|
||||||
"val" -> {
|
"val" -> {
|
||||||
@ -707,8 +697,8 @@ class Compiler(
|
|||||||
* @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, cc: CompilerContext): Statement? = when (id.value) {
|
||||||
"val" -> parseVarDeclaration(id.value, false, cc)
|
"val" -> parseVarDeclaration(false, Visibility.Public, cc)
|
||||||
"var" -> parseVarDeclaration(id.value, true, cc)
|
"var" -> parseVarDeclaration(true, Visibility.Public, cc)
|
||||||
"while" -> parseWhileStatement(cc)
|
"while" -> parseWhileStatement(cc)
|
||||||
"do" -> parseDoWhileStatement(cc)
|
"do" -> parseDoWhileStatement(cc)
|
||||||
"for" -> parseForStatement(cc)
|
"for" -> parseForStatement(cc)
|
||||||
@ -719,16 +709,33 @@ class Compiler(
|
|||||||
"class" -> parseClassDeclaration(cc, false)
|
"class" -> parseClassDeclaration(cc, false)
|
||||||
"try" -> parseTryStatement(cc)
|
"try" -> parseTryStatement(cc)
|
||||||
"throw" -> parseThrowStatement(cc)
|
"throw" -> parseThrowStatement(cc)
|
||||||
else -> null
|
else -> {
|
||||||
|
// triples
|
||||||
|
cc.previous()
|
||||||
|
when {
|
||||||
|
cc.matchQualifiers("fun", "private") -> parseFunctionDeclaration(cc, Visibility.Private)
|
||||||
|
cc.matchQualifiers("fn", "private") -> parseFunctionDeclaration(cc, Visibility.Private)
|
||||||
|
cc.matchQualifiers("fun", "open") -> parseFunctionDeclaration(cc, isOpen = true)
|
||||||
|
cc.matchQualifiers("fn", "open") -> parseFunctionDeclaration(cc, isOpen = true)
|
||||||
|
cc.matchQualifiers("val", "private") -> parseVarDeclaration(false, Visibility.Private, cc)
|
||||||
|
cc.matchQualifiers("var", "private") -> parseVarDeclaration(true, Visibility.Private, cc)
|
||||||
|
cc.matchQualifiers("val", "open") -> parseVarDeclaration(false, Visibility.Private, cc, true)
|
||||||
|
cc.matchQualifiers("var", "open") -> parseVarDeclaration(true, Visibility.Private, cc, true)
|
||||||
|
else -> {
|
||||||
|
cc.next()
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseThrowStatement(cc: CompilerContext): Statement {
|
private fun parseThrowStatement(cc: CompilerContext): Statement {
|
||||||
val throwStatement = parseStatement(cc) ?: throw ScriptError(cc.currentPos(), "throw object expected")
|
val throwStatement = parseStatement(cc) ?: 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)
|
||||||
errorObject = ObjException(this, errorObject.value)
|
errorObject = ObjException(this, errorObject.value)
|
||||||
if( errorObject is ObjException )
|
if (errorObject is ObjException)
|
||||||
raiseError(errorObject)
|
raiseError(errorObject)
|
||||||
else raiseError("this is not an exception object: $errorObject")
|
else raiseError("this is not an exception object: $errorObject")
|
||||||
}
|
}
|
||||||
@ -745,7 +752,7 @@ class Compiler(
|
|||||||
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()
|
||||||
while( t.value == "catch" ) {
|
while (t.value == "catch") {
|
||||||
|
|
||||||
if (cc.skipTokenOfType(Token.Type.LPAREN, isOptional = true)) {
|
if (cc.skipTokenOfType(Token.Type.LPAREN, isOptional = true)) {
|
||||||
t = cc.next()
|
t = cc.next()
|
||||||
@ -785,19 +792,21 @@ class Compiler(
|
|||||||
} else {
|
} else {
|
||||||
// no (e: Exception) block: should be shortest variant `catch { ... }`
|
// no (e: Exception) block: should be shortest variant `catch { ... }`
|
||||||
cc.skipTokenOfType(Token.Type.LBRACE, "expected catch(...) or catch { ... } here")
|
cc.skipTokenOfType(Token.Type.LBRACE, "expected catch(...) or catch { ... } here")
|
||||||
catches += CatchBlockData(Token("it", cc.currentPos(), Token.Type.ID), listOf("Exception"),
|
catches += CatchBlockData(
|
||||||
parseBlock(cc,true))
|
Token("it", cc.currentPos(), Token.Type.ID), listOf("Exception"),
|
||||||
|
parseBlock(cc, true)
|
||||||
|
)
|
||||||
t = cc.next()
|
t = cc.next()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val finallyClause = if( t.value == "finally" ) {
|
val finallyClause = if (t.value == "finally") {
|
||||||
parseBlock(cc)
|
parseBlock(cc)
|
||||||
} else {
|
} else {
|
||||||
cc.previous()
|
cc.previous()
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
if( catches.isEmpty() && finallyClause == null )
|
if (catches.isEmpty() && finallyClause == null)
|
||||||
throw ScriptError(cc.currentPos(), "try block must have either catch or finally clause or both")
|
throw ScriptError(cc.currentPos(), "try block must have either catch or finally clause or both")
|
||||||
|
|
||||||
return statement {
|
return statement {
|
||||||
@ -805,26 +814,25 @@ class Compiler(
|
|||||||
try {
|
try {
|
||||||
// body is a parsed block, it already has separate context
|
// body is a parsed block, it already has separate context
|
||||||
result = body.execute(this)
|
result = body.execute(this)
|
||||||
}
|
} catch (e: Exception) {
|
||||||
catch (e: Exception) {
|
|
||||||
// convert to appropriate exception
|
// convert to appropriate exception
|
||||||
val objException = when(e) {
|
val objException = when (e) {
|
||||||
is ExecutionError -> e.errorObject
|
is ExecutionError -> e.errorObject
|
||||||
else -> ObjUnknownException(this, e.message ?: e.toString())
|
else -> ObjUnknownException(this, e.message ?: e.toString())
|
||||||
}
|
}
|
||||||
// let's see if we should catch it:
|
// let's see if we should catch it:
|
||||||
var isCaught = false
|
var isCaught = false
|
||||||
for( cdata in catches ) {
|
for (cdata in catches) {
|
||||||
var exceptionObject: ObjException? = null
|
var exceptionObject: ObjException? = null
|
||||||
for (exceptionClassName in cdata.classNames) {
|
for (exceptionClassName in cdata.classNames) {
|
||||||
val exObj = ObjException.getErrorClass(exceptionClassName)
|
val exObj = ObjException.getErrorClass(exceptionClassName)
|
||||||
?: raiseSymbolNotFound("error clas not exists: $exceptionClassName")
|
?: raiseSymbolNotFound("error clas not exists: $exceptionClassName")
|
||||||
if( objException.isInstanceOf(exObj) ) {
|
if (objException.isInstanceOf(exObj)) {
|
||||||
exceptionObject = objException
|
exceptionObject = objException
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( exceptionObject != null ) {
|
if (exceptionObject != null) {
|
||||||
val catchContext = this.copy(pos = cdata.catchVar.pos)
|
val catchContext = this.copy(pos = cdata.catchVar.pos)
|
||||||
catchContext.addItem(cdata.catchVar.value, false, objException)
|
catchContext.addItem(cdata.catchVar.value, false, objException)
|
||||||
result = cdata.block.execute(catchContext)
|
result = cdata.block.execute(catchContext)
|
||||||
@ -833,10 +841,9 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// rethrow if not caught this exception
|
// rethrow if not caught this exception
|
||||||
if( !isCaught )
|
if (!isCaught)
|
||||||
throw e
|
throw e
|
||||||
}
|
} finally {
|
||||||
finally {
|
|
||||||
// finally clause does not alter result!
|
// finally clause does not alter result!
|
||||||
finallyClause?.execute(this)
|
finallyClause?.execute(this)
|
||||||
}
|
}
|
||||||
@ -1081,8 +1088,8 @@ class Compiler(
|
|||||||
cc.skipTokens(Token.Type.NEWLINE)
|
cc.skipTokens(Token.Type.NEWLINE)
|
||||||
|
|
||||||
val t = cc.next()
|
val t = cc.next()
|
||||||
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(cc)
|
||||||
val condition =
|
val condition =
|
||||||
@ -1106,10 +1113,9 @@ class Compiler(
|
|||||||
doContext = it.copy().apply { skipContextCreation = true }
|
doContext = it.copy().apply { skipContextCreation = true }
|
||||||
try {
|
try {
|
||||||
result = body.execute(doContext)
|
result = body.execute(doContext)
|
||||||
}
|
} catch (e: LoopBreakContinueException) {
|
||||||
catch( e: LoopBreakContinueException) {
|
if (e.label == label || e.label == null) {
|
||||||
if( e.label == label || e.label == null ) {
|
if (e.doContinue) continue
|
||||||
if( e.doContinue ) continue
|
|
||||||
else {
|
else {
|
||||||
result = e.result
|
result = e.result
|
||||||
wasBroken = true
|
wasBroken = true
|
||||||
@ -1118,8 +1124,8 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
throw e
|
throw e
|
||||||
}
|
}
|
||||||
} while( condition.execute(doContext).toBool() )
|
} while (condition.execute(doContext).toBool())
|
||||||
if( !wasBroken ) elseStatement?.let { s -> result = s.execute(it) }
|
if (!wasBroken) elseStatement?.let { s -> result = s.execute(it) }
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1273,9 +1279,11 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseFunctionDeclaration(tokens: CompilerContext): Statement {
|
private fun parseFunctionDeclaration(
|
||||||
val visibility = tokens.getVisibility()
|
tokens: CompilerContext,
|
||||||
|
visibility: Visibility = Visibility.Public,
|
||||||
|
@Suppress("UNUSED_PARAMETER") isOpen: Boolean = false
|
||||||
|
): Statement {
|
||||||
var t = tokens.next()
|
var t = tokens.next()
|
||||||
val start = t.pos
|
val start = t.pos
|
||||||
val name = if (t.type != Token.Type.ID)
|
val name = if (t.type != Token.Type.ID)
|
||||||
@ -1329,7 +1337,7 @@ class Compiler(
|
|||||||
val block = parseScript(startPos, cc)
|
val block = parseScript(startPos, cc)
|
||||||
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))
|
||||||
}.also {
|
}.also {
|
||||||
val t1 = cc.next()
|
val t1 = cc.next()
|
||||||
if (t1.type != Token.Type.RBRACE)
|
if (t1.type != Token.Type.RBRACE)
|
||||||
@ -1337,26 +1345,22 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseVarDeclaration(kind: String, mutable: Boolean, tokens: CompilerContext): Statement {
|
private fun parseVarDeclaration(
|
||||||
// we are just after var/val, visibility if exists is 2 steps behind
|
isMutable: Boolean,
|
||||||
val visibility = when (tokens.atOffset(-2)?.type) {
|
visibility: Visibility,
|
||||||
Token.Type.PRIVATE ->
|
tokens: CompilerContext,
|
||||||
Visibility.Private
|
@Suppress("UNUSED_PARAMETER") isOpen: Boolean = false
|
||||||
|
): Statement {
|
||||||
Token.Type.PROTECTED -> Visibility.Protected
|
|
||||||
else -> Visibility.Public
|
|
||||||
}
|
|
||||||
|
|
||||||
val nameToken = tokens.next()
|
val nameToken = tokens.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 after '$kind'")
|
throw ScriptError(nameToken.pos, "Expected identifier here")
|
||||||
val name = nameToken.value
|
val name = nameToken.value
|
||||||
|
|
||||||
val eqToken = tokens.next()
|
val eqToken = tokens.next()
|
||||||
var setNull = false
|
var setNull = false
|
||||||
if (eqToken.type != Token.Type.ASSIGN) {
|
if (eqToken.type != Token.Type.ASSIGN) {
|
||||||
if (!mutable)
|
if (!isMutable)
|
||||||
throw ScriptError(start, "val must be initialized")
|
throw ScriptError(start, "val must be initialized")
|
||||||
else {
|
else {
|
||||||
tokens.previous()
|
tokens.previous()
|
||||||
@ -1375,7 +1379,7 @@ class Compiler(
|
|||||||
// create a separate copy:
|
// create a separate copy:
|
||||||
val initValue = initialExpression?.execute(context)?.byValueCopy() ?: ObjNull
|
val initValue = initialExpression?.execute(context)?.byValueCopy() ?: ObjNull
|
||||||
|
|
||||||
context.addItem(name, mutable, initValue, visibility)
|
context.addItem(name, isMutable, initValue, visibility)
|
||||||
initValue
|
initValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1519,7 +1523,8 @@ class Compiler(
|
|||||||
/**
|
/**
|
||||||
* The keywords that stop processing of expression term
|
* The keywords that stop processing of expression term
|
||||||
*/
|
*/
|
||||||
val stopKeywords = setOf("do", "break", "continue", "return", "if", "when", "do", "while", "for", "class", "struct")
|
val stopKeywords =
|
||||||
|
setOf("do", "break", "continue", "return", "if", "when", "do", "while", "for", "class", "struct")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,6 +102,7 @@ internal class CompilerContext(val tokens: List<Token>) {
|
|||||||
* Return value of the next token if it is an identifier, null otherwise.
|
* Return value of the next token if it is an identifier, null otherwise.
|
||||||
* Does not change position.
|
* Does not change position.
|
||||||
*/
|
*/
|
||||||
|
@Suppress("unused")
|
||||||
fun nextIdValue(): String? {
|
fun nextIdValue(): String? {
|
||||||
return if (hasNext()) {
|
return if (hasNext()) {
|
||||||
val nt = tokens[currentIndex]
|
val nt = tokens[currentIndex]
|
||||||
@ -117,21 +118,31 @@ internal class CompilerContext(val tokens: List<Token>) {
|
|||||||
/**
|
/**
|
||||||
* If the token at current position plus offset (could be negative) exists, returns it, otherwise returns null.
|
* If the token at current position plus offset (could be negative) exists, returns it, otherwise returns null.
|
||||||
*/
|
*/
|
||||||
|
@Suppress("unused")
|
||||||
fun atOffset(offset: Int): Token? =
|
fun atOffset(offset: Int): Token? =
|
||||||
if (currentIndex + offset in tokens.indices) tokens[currentIndex + offset] else null
|
if (currentIndex + offset in tokens.indices) tokens[currentIndex + offset] else null
|
||||||
|
|
||||||
/**
|
fun matchQualifiers(keyword: String, vararg qualifiers: String): Boolean {
|
||||||
* Scan backwards as deep as specified looking for visibility token. Does not change position.
|
val pos = savePos()
|
||||||
*/
|
var count = 0
|
||||||
fun getVisibility(default: Visibility = Visibility.Public, depths: Int = 2): Visibility {
|
while( count < qualifiers.size) {
|
||||||
for( i in -depths .. -1) {
|
val t = next()
|
||||||
when( atOffset(i)?.type) {
|
when(t.type) {
|
||||||
Token.Type.PROTECTED -> return Visibility.Protected
|
Token.Type.ID -> {
|
||||||
Token.Type.PRIVATE -> return Visibility.Private
|
if( t.value in qualifiers ) count++
|
||||||
else -> {}
|
else { restorePos(pos); return false }
|
||||||
|
}
|
||||||
|
Token.Type.MULTILINE_COMMENT, Token.Type.SINLGE_LINE_COMMENT, Token.Type.NEWLINE -> {}
|
||||||
|
else -> { restorePos(pos); return false }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return default
|
val t = next()
|
||||||
|
if( t.type == Token.Type.ID && t.value == keyword ) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
restorePos(pos)
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// fun expectKeyword(vararg keyword: String): String {
|
// fun expectKeyword(vararg keyword: String): String {
|
||||||
|
@ -137,14 +137,18 @@ private class Parser(fromPos: Pos) {
|
|||||||
if (currentChar == '.') {
|
if (currentChar == '.') {
|
||||||
pos.advance()
|
pos.advance()
|
||||||
// .. already parsed:
|
// .. already parsed:
|
||||||
if (currentChar == '.') {
|
when (currentChar) {
|
||||||
pos.advance()
|
'.' -> {
|
||||||
Token("...", from, Token.Type.ELLIPSIS)
|
pos.advance()
|
||||||
} else if (currentChar == '<') {
|
Token("...", from, Token.Type.ELLIPSIS)
|
||||||
pos.advance()
|
}
|
||||||
Token("..<", from, Token.Type.DOTDOTLT)
|
'<' -> {
|
||||||
} else {
|
pos.advance()
|
||||||
Token("..", from, Token.Type.DOTDOT)
|
Token("..<", from, Token.Type.DOTDOTLT)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
Token("..", from, Token.Type.DOTDOT)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
Token(".", from, Token.Type.DOT)
|
Token(".", from, Token.Type.DOT)
|
||||||
@ -280,8 +284,6 @@ private class Parser(fromPos: Pos) {
|
|||||||
when (text) {
|
when (text) {
|
||||||
"in" -> Token("in", from, Token.Type.IN)
|
"in" -> Token("in", from, Token.Type.IN)
|
||||||
"is" -> Token("is", from, Token.Type.IS)
|
"is" -> Token("is", from, Token.Type.IS)
|
||||||
"protected" -> Token("protected", from, Token.Type.PROTECTED)
|
|
||||||
"private" -> Token("private", from, Token.Type.PRIVATE)
|
|
||||||
else -> Token(text, from, Token.Type.ID)
|
else -> Token(text, from, Token.Type.ID)
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
@ -338,7 +340,7 @@ private class Parser(fromPos: Pos) {
|
|||||||
// could be integer, also hex:
|
// could be integer, also hex:
|
||||||
if (currentChar == 'x' && p1 == "0") {
|
if (currentChar == 'x' && p1 == "0") {
|
||||||
pos.advance()
|
pos.advance()
|
||||||
Token(loadChars({ it in hexDigits }), start, Token.Type.HEX).also {
|
Token(loadChars { it in hexDigits }, start, Token.Type.HEX).also {
|
||||||
if (currentChar.isLetter())
|
if (currentChar.isLetter())
|
||||||
raise("invalid hex literal")
|
raise("invalid hex literal")
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,6 @@ data class Token(val value: String, val pos: Pos, val type: Type) {
|
|||||||
AND, BITAND, OR, BITOR, NOT, BITNOT, DOT, ARROW, QUESTION, COLONCOLON,
|
AND, BITAND, OR, BITOR, NOT, BITNOT, DOT, ARROW, QUESTION, COLONCOLON,
|
||||||
SINLGE_LINE_COMMENT, MULTILINE_COMMENT,
|
SINLGE_LINE_COMMENT, MULTILINE_COMMENT,
|
||||||
LABEL, ATLABEL, // label@ at@label
|
LABEL, ATLABEL, // label@ at@label
|
||||||
PRIVATE, PROTECTED,
|
|
||||||
//PUBLIC, PROTECTED, INTERNAL, EXPORT, OPEN, INLINE, OVERRIDE, ABSTRACT, SEALED, EXTERNAL, VAL, VAR, CONST, TYPE, FUN, CLASS, INTERFACE, ENUM, OBJECT, TRAIT, THIS,
|
//PUBLIC, PROTECTED, INTERNAL, EXPORT, OPEN, INLINE, OVERRIDE, ABSTRACT, SEALED, EXTERNAL, VAL, VAR, CONST, TYPE, FUN, CLASS, INTERFACE, ENUM, OBJECT, TRAIT, THIS,
|
||||||
ELLIPSIS, DOTDOT, DOTDOTLT,
|
ELLIPSIS, DOTDOT, DOTDOTLT,
|
||||||
NEWLINE,
|
NEWLINE,
|
||||||
|
@ -1876,4 +1876,23 @@ class ScriptTest {
|
|||||||
""".trimIndent())
|
""".trimIndent())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testReturnValue1() = runTest {
|
||||||
|
val r = eval("""
|
||||||
|
class Point(x,y) {
|
||||||
|
println("1")
|
||||||
|
fun length() { sqrt(d2()) }
|
||||||
|
println("2")
|
||||||
|
private fun d2() {x*x + y*y}
|
||||||
|
println("3")
|
||||||
|
}
|
||||||
|
println("Helluva")
|
||||||
|
val p = Point(3,4)
|
||||||
|
// assertEquals( 5, p.length() )
|
||||||
|
// assertThrows { p.d2() }
|
||||||
|
"111"
|
||||||
|
""".trimIndent())
|
||||||
|
assertEquals("111", r.toString())
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user