Skip to content

Commit 0299977

Browse files
committed
function calls
1 parent 24bb4fe commit 0299977

File tree

3 files changed

+112
-15
lines changed

3 files changed

+112
-15
lines changed

src/commonMain/kotlin/com/github/murzagalin/evaluator/ast/Expression.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ sealed class Expression {
2121
val thirdExpression: Expression
2222
) : Expression()
2323

24+
data class FunctionCall(
25+
val token: Token.FunctionCall,
26+
val arguments: List<Expression>
27+
) : Expression()
28+
2429
data class Terminal(
2530
val token: Token.Operand
2631
) : Expression()

src/commonMain/kotlin/com/github/murzagalin/evaluator/ast/Parser.kt

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,24 @@ import com.github.murzagalin.evaluator.Token
55

66
/* the parser uses these rules
77
8-
* expression -> ternary_if
9-
* ternary_if -> logic_or ( "?" ternary_if ":" ternary_if )?
10-
* logic_or -> logic_and ( ( "or" | "||" ) logic_and )*
11-
* logic_and -> equality ( ( "and" | "&&" ) equality )*
12-
* equality -> comparison ( ( "!=" | "==" ) comparison )*
13-
* comparison -> sum ( ( ">" | ">=" | "<" | "<=" ) sum )*
14-
* sum -> factor ( ( "-" | "+" ) factor )*
15-
* factor -> unary ( ( "/" | "*" | "%") unary )*
16-
* unary -> ( "!" | "-" | "+" ) unary | exponent
17-
* exponent -> identifier ( "^" unary )*
18-
- identifier -> function | variable | number | boolean
8+
expression -> ternary_if
9+
ternary_if -> logic_or ( "?" ternary_if ":" ternary_if )?
10+
logic_or -> logic_and ( ( "or" | "||" ) logic_and )*
11+
logic_and -> equality ( ( "and" | "&&" ) equality )*
12+
equality -> comparison ( ( "!=" | "==" ) comparison )*
13+
comparison -> sum ( ( ">" | ">=" | "<" | "<=" ) sum )*
14+
sum -> factor ( ( "-" | "+" ) factor )*
15+
factor -> unary ( ( "/" | "*" | "%") unary )*
16+
unary -> ( "!" | "-" | "+" ) unary | exponent
17+
exponent -> identifier ( "^" unary )*
18+
identifier -> function | variable | number | boolean
1919
2020
function -> name "(" ( arguments )* ")"
2121
arguments -> expression ( ',' expression )*
22-
* variable -> name
23-
* name -> CHAR ( CHAR | DIGIT )*
24-
* boolean -> "true" | "false" | "TRUE" | "FALSE"
25-
* number -> DIGIT ( DIGIT )*
22+
variable -> name
23+
name -> CHAR ( CHAR | DIGIT )*
24+
boolean -> "true" | "false" | "TRUE" | "FALSE"
25+
number -> DIGIT ( DIGIT )*
2626
*/
2727

2828
class Parser {
@@ -166,6 +166,17 @@ class Parser {
166166

167167
return when (val token = tokens[ix++]) {
168168
is Token.Operand -> Expression.Terminal(token)
169+
is Token.FunctionCall -> {
170+
require(tokens[ix++] is Token.Bracket.Left) { "'(' expected after function call" }
171+
val arguments = mutableListOf<Expression>()
172+
while (tokens[ix] !is Token.Bracket.Right) {
173+
arguments += expression(tokens)
174+
if (tokens[ix] is Token.FunctionCall.Delimiter) ix++
175+
}
176+
require(tokens[ix] is Token.Bracket.Right) { "expected ')' after a function call" }
177+
178+
return Expression.FunctionCall(token, arguments)
179+
}
169180
is Token.Bracket.Left -> {
170181
val result = expression(tokens)
171182
require(tokens[ix++] is Token.Bracket.Right) { "')' expected after expression" }
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package com.github.murzagalin.evaluator.ast
2+
3+
import com.github.murzagalin.evaluator.DefaultFunctions
4+
import com.github.murzagalin.evaluator.Token
5+
import kotlin.test.Test
6+
import kotlin.test.assertEquals
7+
8+
class ParserFunctionsTest {
9+
10+
private val subject = Parser()
11+
12+
@Test
13+
fun parse_function_call_without_arguments() {
14+
val functionCall = Token.FunctionCall(0, DefaultFunctions.ABS)
15+
val expression = listOf(
16+
functionCall,
17+
Token.Bracket.Left,
18+
Token.Bracket.Right
19+
)
20+
21+
assertEquals(
22+
Expression.FunctionCall(
23+
functionCall,
24+
emptyList()
25+
),
26+
subject.parse(expression)
27+
)
28+
}
29+
30+
@Test
31+
fun parse_function_call_with_one_argument() {
32+
val functionCall = Token.FunctionCall(1, DefaultFunctions.MIN)
33+
val expression = listOf(
34+
functionCall,
35+
Token.Bracket.Left,
36+
Token.Operand.Number(1),
37+
Token.Bracket.Right
38+
)
39+
40+
assertEquals(
41+
Expression.FunctionCall(
42+
functionCall,
43+
listOf(Expression.Terminal(Token.Operand.Number(1)))
44+
),
45+
subject.parse(expression)
46+
)
47+
}
48+
49+
@Test
50+
fun parse_function_call_with_several_argument() {
51+
val functionCall = Token.FunctionCall(3, DefaultFunctions.MIN)
52+
val expression = listOf(
53+
functionCall,
54+
Token.Bracket.Left,
55+
Token.Operand.Number(1),
56+
Token.FunctionCall.Delimiter,
57+
Token.Operand.Number(2),
58+
Token.Operator.Plus,
59+
Token.Operand.Number(3),
60+
Token.FunctionCall.Delimiter,
61+
Token.Operand.Number(4),
62+
Token.Bracket.Right
63+
)
64+
65+
assertEquals(
66+
Expression.FunctionCall(
67+
functionCall,
68+
listOf(
69+
Expression.Terminal(Token.Operand.Number(1)),
70+
Expression.Binary(
71+
Token.Operator.Plus,
72+
Expression.Terminal(Token.Operand.Number(2)),
73+
Expression.Terminal(Token.Operand.Number(3))
74+
),
75+
Expression.Terminal(Token.Operand.Number(4)),
76+
)
77+
),
78+
subject.parse(expression)
79+
)
80+
}
81+
}

0 commit comments

Comments
 (0)