mirror of
https://github.com/aNNiMON/Own-Programming-Language-Tutorial.git
synced 2024-09-20 00:34:20 +03:00
Урок 10. Пользовательские функции
This commit is contained in:
parent
ebed2615d5
commit
499fc8457b
18
program.txt
18
program.txt
@ -32,4 +32,20 @@ if (40 < 50 || 50 > 60) {
|
|||||||
else print "false"
|
else print "false"
|
||||||
|
|
||||||
print "sin(PI) = " + sin(PI/2)
|
print "sin(PI) = " + sin(PI/2)
|
||||||
echo(1,2,3,"4","5","text",sin(0),cos(0),sin(PI),cos(PI),PI)
|
echo(1,2,3,"4","5","text",sin(0),cos(0),sin(PI),cos(PI),PI)
|
||||||
|
|
||||||
|
a = "print"
|
||||||
|
print a
|
||||||
|
|
||||||
|
def name(a,b) {
|
||||||
|
echo("a = ", a, " b = ", b)
|
||||||
|
}
|
||||||
|
|
||||||
|
def sum(a,b) {
|
||||||
|
a = -60
|
||||||
|
return a+b
|
||||||
|
}
|
||||||
|
name(1,"text")
|
||||||
|
print sum(10, 15)
|
||||||
|
|
||||||
|
print a
|
39
src/com/annimon/ownlang/lib/UserDefinedFunction.java
Normal file
39
src/com/annimon/ownlang/lib/UserDefinedFunction.java
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
package com.annimon.ownlang.lib;
|
||||||
|
|
||||||
|
import com.annimon.ownlang.parser.ast.ReturnStatement;
|
||||||
|
import com.annimon.ownlang.parser.ast.Statement;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author aNNiMON
|
||||||
|
*/
|
||||||
|
public final class UserDefinedFunction implements Function {
|
||||||
|
|
||||||
|
private final List<String> argNames;
|
||||||
|
private final Statement body;
|
||||||
|
|
||||||
|
public UserDefinedFunction(List<String> argNames, Statement body) {
|
||||||
|
this.argNames = argNames;
|
||||||
|
this.body = body;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getArgsCount() {
|
||||||
|
return argNames.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getArgsName(int index) {
|
||||||
|
if (index < 0 || index >= getArgsCount()) return "";
|
||||||
|
return argNames.get(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Value execute(Value... args) {
|
||||||
|
try {
|
||||||
|
body.execute();
|
||||||
|
return NumberValue.ZERO;
|
||||||
|
} catch (ReturnStatement rt) {
|
||||||
|
return rt.getResult();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@ package com.annimon.ownlang.lib;
|
|||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Stack;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -9,9 +10,11 @@ import java.util.Map;
|
|||||||
*/
|
*/
|
||||||
public final class Variables {
|
public final class Variables {
|
||||||
|
|
||||||
private static final Map<String, Value> variables;
|
private static final Stack<Map<String, Value>> stack;
|
||||||
|
private static Map<String, Value> variables;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
stack = new Stack<>();
|
||||||
variables = new HashMap<>();
|
variables = new HashMap<>();
|
||||||
variables.put("PI", new NumberValue(Math.PI));
|
variables.put("PI", new NumberValue(Math.PI));
|
||||||
variables.put("ПИ", new NumberValue(Math.PI));
|
variables.put("ПИ", new NumberValue(Math.PI));
|
||||||
@ -19,6 +22,14 @@ public final class Variables {
|
|||||||
variables.put("GOLDEN_RATIO", new NumberValue(1.618));
|
variables.put("GOLDEN_RATIO", new NumberValue(1.618));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void push() {
|
||||||
|
stack.push(new HashMap<>(variables));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void pop() {
|
||||||
|
variables = stack.pop();
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean isExists(String key) {
|
public static boolean isExists(String key) {
|
||||||
return variables.containsKey(key);
|
return variables.containsKey(key);
|
||||||
}
|
}
|
||||||
|
@ -153,6 +153,8 @@ public final class Lexer {
|
|||||||
case "do": addToken(TokenType.DO); break;
|
case "do": addToken(TokenType.DO); break;
|
||||||
case "break": addToken(TokenType.BREAK); break;
|
case "break": addToken(TokenType.BREAK); break;
|
||||||
case "continue": addToken(TokenType.CONTINUE); break;
|
case "continue": addToken(TokenType.CONTINUE); break;
|
||||||
|
case "def": addToken(TokenType.DEF); break;
|
||||||
|
case "return": addToken(TokenType.RETURN); break;
|
||||||
default:
|
default:
|
||||||
addToken(TokenType.WORD, word);
|
addToken(TokenType.WORD, word);
|
||||||
break;
|
break;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.annimon.ownlang.parser;
|
package com.annimon.ownlang.parser;
|
||||||
|
|
||||||
import com.annimon.ownlang.parser.ast.*;
|
import com.annimon.ownlang.parser.ast.*;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -62,9 +63,15 @@ public final class Parser {
|
|||||||
if (match(TokenType.CONTINUE)) {
|
if (match(TokenType.CONTINUE)) {
|
||||||
return new ContinueStatement();
|
return new ContinueStatement();
|
||||||
}
|
}
|
||||||
|
if (match(TokenType.RETURN)) {
|
||||||
|
return new ReturnStatement(expression());
|
||||||
|
}
|
||||||
if (match(TokenType.FOR)) {
|
if (match(TokenType.FOR)) {
|
||||||
return forStatement();
|
return forStatement();
|
||||||
}
|
}
|
||||||
|
if (match(TokenType.DEF)) {
|
||||||
|
return functionDefine();
|
||||||
|
}
|
||||||
if (get(0).getType() == TokenType.WORD && get(1).getType() == TokenType.LPAREN) {
|
if (get(0).getType() == TokenType.WORD && get(1).getType() == TokenType.LPAREN) {
|
||||||
return new FunctionStatement(function());
|
return new FunctionStatement(function());
|
||||||
}
|
}
|
||||||
@ -117,6 +124,18 @@ public final class Parser {
|
|||||||
return new ForStatement(initialization, termination, increment, statement);
|
return new ForStatement(initialization, termination, increment, statement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private FunctionDefineStatement functionDefine() {
|
||||||
|
final String name = consume(TokenType.WORD).getText();
|
||||||
|
consume(TokenType.LPAREN);
|
||||||
|
final List<String> argNames = new ArrayList<>();
|
||||||
|
while (!match(TokenType.RPAREN)) {
|
||||||
|
argNames.add(consume(TokenType.WORD).getText());
|
||||||
|
match(TokenType.COMMA);
|
||||||
|
}
|
||||||
|
final Statement body = statementOrBlock();
|
||||||
|
return new FunctionDefineStatement(name, argNames, body);
|
||||||
|
}
|
||||||
|
|
||||||
private FunctionalExpression function() {
|
private FunctionalExpression function() {
|
||||||
final String name = consume(TokenType.WORD).getText();
|
final String name = consume(TokenType.WORD).getText();
|
||||||
consume(TokenType.LPAREN);
|
consume(TokenType.LPAREN);
|
||||||
|
@ -20,6 +20,8 @@ public enum TokenType {
|
|||||||
DO,
|
DO,
|
||||||
BREAK,
|
BREAK,
|
||||||
CONTINUE,
|
CONTINUE,
|
||||||
|
DEF,
|
||||||
|
RETURN,
|
||||||
|
|
||||||
PLUS,
|
PLUS,
|
||||||
MINUS,
|
MINUS,
|
||||||
|
@ -0,0 +1,32 @@
|
|||||||
|
package com.annimon.ownlang.parser.ast;
|
||||||
|
|
||||||
|
import com.annimon.ownlang.lib.Functions;
|
||||||
|
import com.annimon.ownlang.lib.UserDefinedFunction;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author aNNiMON
|
||||||
|
*/
|
||||||
|
public final class FunctionDefineStatement implements Statement {
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
private final List<String> argNames;
|
||||||
|
private final Statement body;
|
||||||
|
|
||||||
|
public FunctionDefineStatement(String name, List<String> argNames, Statement body) {
|
||||||
|
this.name = name;
|
||||||
|
this.argNames = argNames;
|
||||||
|
this.body = body;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute() {
|
||||||
|
Functions.set(name, new UserDefinedFunction(argNames, body));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "def (" + argNames.toString() + ") " + body.toString();
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,10 @@
|
|||||||
package com.annimon.ownlang.parser.ast;
|
package com.annimon.ownlang.parser.ast;
|
||||||
|
|
||||||
|
import com.annimon.ownlang.lib.Function;
|
||||||
import com.annimon.ownlang.lib.Functions;
|
import com.annimon.ownlang.lib.Functions;
|
||||||
|
import com.annimon.ownlang.lib.UserDefinedFunction;
|
||||||
import com.annimon.ownlang.lib.Value;
|
import com.annimon.ownlang.lib.Value;
|
||||||
|
import com.annimon.ownlang.lib.Variables;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -35,7 +38,21 @@ public final class FunctionalExpression implements Expression {
|
|||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
values[i] = arguments.get(i).eval();
|
values[i] = arguments.get(i).eval();
|
||||||
}
|
}
|
||||||
return Functions.get(name).execute(values);
|
|
||||||
|
final Function function = Functions.get(name);
|
||||||
|
if (function instanceof UserDefinedFunction) {
|
||||||
|
final UserDefinedFunction userFunction = (UserDefinedFunction) function;
|
||||||
|
if (size != userFunction.getArgsCount()) throw new RuntimeException("Args count mismatch");
|
||||||
|
|
||||||
|
Variables.push();
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
Variables.set(userFunction.getArgsName(i), values[i]);
|
||||||
|
}
|
||||||
|
final Value result = userFunction.execute(values);
|
||||||
|
Variables.pop();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return function.execute(values);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
32
src/com/annimon/ownlang/parser/ast/ReturnStatement.java
Normal file
32
src/com/annimon/ownlang/parser/ast/ReturnStatement.java
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package com.annimon.ownlang.parser.ast;
|
||||||
|
|
||||||
|
import com.annimon.ownlang.lib.Value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author aNNiMON
|
||||||
|
*/
|
||||||
|
public final class ReturnStatement extends RuntimeException implements Statement {
|
||||||
|
|
||||||
|
private final Expression expression;
|
||||||
|
private Value result;
|
||||||
|
|
||||||
|
public ReturnStatement(Expression expression) {
|
||||||
|
this.expression = expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Value getResult() {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute() {
|
||||||
|
result = expression.eval();
|
||||||
|
throw this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "return";
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user