Refactor extend statement: remove unnecessary "as" keyword and push "this" variable context to the extend-statement scope

This commit is contained in:
2020-03-17 20:52:47 +01:00
parent 4cb234bdba
commit 70cb2e85bc
8 changed files with 47 additions and 45 deletions

View File

@@ -11,7 +11,7 @@ import io.smnp.type.matcher.Matcher
import io.smnp.type.model.Value import io.smnp.type.model.Value
object CustomMethod { object CustomMethod {
fun create(type: Matcher, objectIdentifier: String, node: FunctionDefinitionNode): Method { fun create(type: Matcher, node: FunctionDefinitionNode): Method {
val identifier = (node.identifier as IdentifierNode).token.rawValue val identifier = (node.identifier as IdentifierNode).token.rawValue
return object : Method(type, identifier) { return object : Method(type, identifier) {
@@ -23,7 +23,7 @@ object CustomMethod {
new method signature body { env, obj, args -> new method signature body { env, obj, args ->
val boundArguments = val boundArguments =
FunctionEnvironmentProvider.provideEnvironment(argumentsNode, args, env).toMutableMap() FunctionEnvironmentProvider.provideEnvironment(argumentsNode, args, env).toMutableMap()
boundArguments[objectIdentifier] = obj boundArguments["this"] = obj
try { try {
env.pushScope(boundArguments) env.pushScope(boundArguments)

View File

@@ -2,23 +2,18 @@ package io.smnp.dsl.ast.model.node
import io.smnp.dsl.token.model.entity.TokenPosition import io.smnp.dsl.token.model.entity.TokenPosition
class ExtendNode(type: Node, identifier: Node, functions: Node, position: TokenPosition) : Node(3, position) { class ExtendNode(type: Node, functions: Node, position: TokenPosition) : Node(2, position) {
operator fun component1(): Node = children[0] operator fun component1(): Node = children[0]
operator fun component2(): Node = children[1] operator fun component2(): Node = children[1]
operator fun component3(): Node = children[2]
val type: Node val type: Node
get() = children[0] get() = children[0]
val identifier: Node
get() = children[1]
val functions: Node val functions: Node
get() = children[2] get() = children[1]
init { init {
children[0] = type children[0] = type
children[1] = identifier children[1] = functions
children[2] = functions
} }
} }

View File

@@ -8,33 +8,38 @@ import io.smnp.dsl.token.model.entity.TokenList
import io.smnp.dsl.token.model.enumeration.TokenType import io.smnp.dsl.token.model.enumeration.TokenType
class ExtendParser : Parser() { class ExtendParser : Parser() {
override fun tryToParse(input: TokenList): ParserOutput { override fun tryToParse(input: TokenList): ParserOutput {
val simpleExtendParser = allOf( val simpleExtendParser = allOf(
terminal(TokenType.EXTEND), terminal(TokenType.EXTEND),
assert(SingleTypeParser(), "type to be extended"), assert(SingleTypeParser(), "type to be extended"),
assert(terminal(TokenType.AS), "'as' keyword with identifier"), terminal(TokenType.WITH),
assert(SimpleIdentifierParser(), "identifier"), assert(
terminal(TokenType.WITH), mapNode(FunctionDefinitionParser()) { BlockNode(Node.NONE, listOf(it), Node.NONE) },
assert(mapNode(FunctionDefinitionParser()) { BlockNode(Node.NONE, listOf(it), Node.NONE) }, "method definition") "method definition"
) { (extendToken, targetType, identifier, method) -> )
ExtendNode(targetType, identifier, method, extendToken.position) ) { (extendToken, targetType, _, method) ->
} ExtendNode(targetType, method, extendToken.position)
}
val complexExtendParser = allOf( val complexExtendParser = allOf(
terminal(TokenType.EXTEND), terminal(TokenType.EXTEND),
assert(SingleTypeParser(), "type to be extended"), assert(SingleTypeParser(), "type to be extended"),
assert(terminal(TokenType.AS), "'as' keyword with identifier"), assert(
assert(SimpleIdentifierParser(), "identifier"), loop(
assert(loop(terminal(TokenType.OPEN_CURLY), assert(FunctionDefinitionParser(), "method definition or }"), terminal(TokenType.CLOSE_CURLY)) { terminal(TokenType.OPEN_CURLY),
begin, methods, end -> BlockNode(begin, methods, end) assert(FunctionDefinitionParser(), "method definition or }"),
}, "block with methods' definitions or 'with' keyword with single method definition") terminal(TokenType.CLOSE_CURLY)
) { (extendToken, targetType, _, identifier, methods) -> ) { begin, methods, end ->
ExtendNode(targetType, identifier, methods, extendToken.position) BlockNode(begin, methods, end)
} }, "block with methods' definitions or 'with' keyword with single method definition"
)
) { (extendToken, targetType, methods) ->
ExtendNode(targetType, methods, extendToken.position)
}
return oneOf( return oneOf(
simpleExtendParser, simpleExtendParser,
complexExtendParser complexExtendParser
).parse(input) ).parse(input)
} }
} }

View File

@@ -2,7 +2,10 @@ package io.smnp.evaluation.evaluator
import io.smnp.callable.method.CustomMethod import io.smnp.callable.method.CustomMethod
import io.smnp.callable.util.FunctionSignatureParser import io.smnp.callable.util.FunctionSignatureParser
import io.smnp.dsl.ast.model.node.* import io.smnp.dsl.ast.model.node.ExtendNode
import io.smnp.dsl.ast.model.node.FunctionDefinitionNode
import io.smnp.dsl.ast.model.node.Node
import io.smnp.dsl.ast.model.node.SingleTypeNode
import io.smnp.environment.Environment import io.smnp.environment.Environment
import io.smnp.error.EnvironmentException import io.smnp.error.EnvironmentException
import io.smnp.error.PositionException import io.smnp.error.PositionException
@@ -13,12 +16,11 @@ class ExtendEvaluator : Evaluator() {
override fun supportedNodes() = listOf(ExtendNode::class) override fun supportedNodes() = listOf(ExtendNode::class)
override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput { override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput {
val (typeNode, identifierNode, methodsNode) = node as ExtendNode val (typeNode, methodsNode) = node as ExtendNode
val type = FunctionSignatureParser.matcherForSingleTypeNode(typeNode as SingleTypeNode) val type = FunctionSignatureParser.matcherForSingleTypeNode(typeNode as SingleTypeNode)
val identifier = (identifierNode as IdentifierNode).token.rawValue
methodsNode.children methodsNode.children
.map { it to CustomMethod.create(type, identifier, it as FunctionDefinitionNode) } .map { it to CustomMethod.create(type, it as FunctionDefinitionNode) }
.forEach { .forEach {
try { try {
environment.defineMethod(it.second) environment.defineMethod(it.second)

View File

@@ -14,7 +14,7 @@ function _flatten(list: list, output: list) {
return output; return output;
} }
extend list as this { extend list {
function flatten() { function flatten() {
return flatten(this); return flatten(this);
} }

View File

@@ -1,4 +1,4 @@
extend map as this { extend map {
function containsKey(key) { function containsKey(key) {
return this.keys.contains(key); return this.keys.contains(key);
} }

View File

@@ -1,4 +1,4 @@
extend note as this { extend note {
function withOctave(octave: int) { function withOctave(octave: int) {
return Note(this.pitch, octave, this.duration.get("numerator"), this.duration.get("denominator")); return Note(this.pitch, octave, this.duration.get("numerator"), this.duration.get("denominator"));
} }

View File

@@ -1,4 +1,4 @@
extend string as this { extend string {
function find(char: string) { function find(char: string) {
if(char.length > 1) { if(char.length > 1) {
throw "Only single character can act as a pattern to be found"; throw "Only single character can act as a pattern to be found";