mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2026-04-08 16:56:07 +00:00
Add math functions
This commit is contained in:
@@ -11,6 +11,9 @@ import com.dfsek.terra.api.structures.parser.lang.constants.NumericConstant;
|
||||
import com.dfsek.terra.api.structures.parser.lang.constants.StringConstant;
|
||||
import com.dfsek.terra.api.structures.parser.lang.functions.Function;
|
||||
import com.dfsek.terra.api.structures.parser.lang.functions.FunctionBuilder;
|
||||
import com.dfsek.terra.api.structures.parser.lang.functions.builtin.AbsFunction;
|
||||
import com.dfsek.terra.api.structures.parser.lang.functions.builtin.PowFunction;
|
||||
import com.dfsek.terra.api.structures.parser.lang.functions.builtin.SqrtFunction;
|
||||
import com.dfsek.terra.api.structures.parser.lang.keywords.BreakKeyword;
|
||||
import com.dfsek.terra.api.structures.parser.lang.keywords.ContinueKeyword;
|
||||
import com.dfsek.terra.api.structures.parser.lang.keywords.IfKeyword;
|
||||
@@ -42,14 +45,18 @@ import com.dfsek.terra.api.structures.tokenizer.Token;
|
||||
import com.dfsek.terra.api.structures.tokenizer.Tokenizer;
|
||||
import com.dfsek.terra.api.structures.tokenizer.exceptions.TokenizerException;
|
||||
import com.dfsek.terra.api.util.GlueList;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class Parser {
|
||||
private final String data;
|
||||
private final Map<String, FunctionBuilder<? extends Function<?>>> functions = new HashMap<>();
|
||||
private final Set<String> builtinFunctions = Sets.newHashSet("abs", "sqrt", "pow");
|
||||
|
||||
private String id;
|
||||
|
||||
public Parser(String data) {
|
||||
@@ -141,7 +148,8 @@ public class Parser {
|
||||
} else if(id.getType().equals(Token.Type.GROUP_BEGIN)) { // Parse grouped expression
|
||||
expression = parseGroup(tokens, variableMap);
|
||||
} else {
|
||||
if(functions.containsKey(id.getContent())) expression = parseFunction(tokens, false, variableMap);
|
||||
if(functions.containsKey(id.getContent()) || builtinFunctions.contains(id.getContent()))
|
||||
expression = parseFunction(tokens, false, variableMap);
|
||||
else if(variableMap.containsKey(id.getContent())) {
|
||||
ParserUtil.checkType(tokens.remove(0), Token.Type.IDENTIFIER);
|
||||
expression = new Getter(variableMap.get(id.getContent()));
|
||||
@@ -280,7 +288,7 @@ public class Parser {
|
||||
|
||||
ParserUtil.checkType(name, Token.Type.IDENTIFIER); // Name must be an identifier.
|
||||
|
||||
if(functions.containsKey(name.getContent()) || parsedVariables.containsKey(name.getContent()))
|
||||
if(functions.containsKey(name.getContent()) || parsedVariables.containsKey(name.getContent()) || builtinFunctions.contains(name.getContent()))
|
||||
throw new ParseException(name.getContent() + " is already defined in this scope: " + name.getPosition());
|
||||
|
||||
parsedVariables.put(name.getContent(), temp);
|
||||
@@ -313,11 +321,12 @@ public class Parser {
|
||||
return new Assignment<>((Variable<Object>) variable, (Returnable<Object>) expression, name.getPosition());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Function<?> parseFunction(List<Token> tokens, boolean fullStatement, Map<String, Variable<?>> variableMap) throws ParseException {
|
||||
Token identifier = tokens.remove(0);
|
||||
ParserUtil.checkType(identifier, Token.Type.IDENTIFIER); // First token must be identifier
|
||||
|
||||
if(!functions.containsKey(identifier.getContent()))
|
||||
if(!functions.containsKey(identifier.getContent()) && !builtinFunctions.contains(identifier.getContent()))
|
||||
throw new ParseException("No such function " + identifier.getContent() + ": " + identifier.getPosition());
|
||||
|
||||
ParserUtil.checkType(tokens.remove(0), Token.Type.GROUP_BEGIN); // Second is body begin
|
||||
@@ -325,22 +334,45 @@ public class Parser {
|
||||
|
||||
List<Returnable<?>> args = getArgs(tokens, variableMap); // Extract arguments, consume the rest.
|
||||
|
||||
tokens.remove(0); // Remove body end
|
||||
ParserUtil.checkType(tokens.remove(0), Token.Type.GROUP_END); // Remove body end
|
||||
|
||||
if(fullStatement) ParserUtil.checkType(tokens.get(0), Token.Type.STATEMENT_END);
|
||||
|
||||
FunctionBuilder<?> builder = functions.get(identifier.getContent());
|
||||
if(functions.containsKey(identifier.getContent())) {
|
||||
FunctionBuilder<?> builder = functions.get(identifier.getContent());
|
||||
|
||||
if(builder.argNumber() != -1 && args.size() != builder.argNumber())
|
||||
throw new ParseException("Expected " + builder.argNumber() + " arguments, found " + args.size() + ": " + identifier.getPosition());
|
||||
if(builder.argNumber() != -1 && args.size() != builder.argNumber())
|
||||
throw new ParseException("Expected " + builder.argNumber() + " arguments, found " + args.size() + ": " + identifier.getPosition());
|
||||
|
||||
for(int i = 0; i < args.size(); i++) {
|
||||
Returnable<?> argument = args.get(i);
|
||||
if(builder.getArgument(i) == null)
|
||||
throw new ParseException("Unexpected argument at position " + i + " in function " + identifier.getContent() + ": " + identifier.getPosition());
|
||||
ParserUtil.checkReturnType(argument, builder.getArgument(i));
|
||||
for(int i = 0; i < args.size(); i++) {
|
||||
Returnable<?> argument = args.get(i);
|
||||
if(builder.getArgument(i) == null)
|
||||
throw new ParseException("Unexpected argument at position " + i + " in function " + identifier.getContent() + ": " + identifier.getPosition());
|
||||
ParserUtil.checkReturnType(argument, builder.getArgument(i));
|
||||
}
|
||||
return builder.build(args, identifier.getPosition());
|
||||
} else {
|
||||
switch(identifier.getContent()) {
|
||||
case "abs":
|
||||
ParserUtil.checkReturnType(args.get(0), Returnable.ReturnType.NUMBER);
|
||||
if(args.size() != 1)
|
||||
throw new ParseException("Expected 1 arguments; found " + args.size() + ": " + identifier.getPosition());
|
||||
return new AbsFunction(identifier.getPosition(), (Returnable<Number>) args.get(0));
|
||||
case "sqrt":
|
||||
ParserUtil.checkReturnType(args.get(0), Returnable.ReturnType.NUMBER);
|
||||
if(args.size() != 1)
|
||||
throw new ParseException("Expected 1 arguments; found " + args.size() + ": " + identifier.getPosition());
|
||||
return new SqrtFunction(identifier.getPosition(), (Returnable<Number>) args.get(0));
|
||||
case "pow":
|
||||
ParserUtil.checkReturnType(args.get(0), Returnable.ReturnType.NUMBER);
|
||||
ParserUtil.checkReturnType(args.get(1), Returnable.ReturnType.NUMBER);
|
||||
if(args.size() != 2)
|
||||
throw new ParseException("Expected 1 arguments; found " + args.size() + ": " + identifier.getPosition());
|
||||
return new PowFunction(identifier.getPosition(), (Returnable<Number>) args.get(0), (Returnable<Number>) args.get(1));
|
||||
default:
|
||||
throw new UnsupportedOperationException("Unsupported function: " + identifier.getContent());
|
||||
}
|
||||
}
|
||||
return builder.build(args, identifier.getPosition());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.dfsek.terra.api.structures.parser.lang.functions.builtin;
|
||||
|
||||
import com.dfsek.terra.api.math.vector.Location;
|
||||
import com.dfsek.terra.api.platform.world.Chunk;
|
||||
import com.dfsek.terra.api.structures.parser.lang.Returnable;
|
||||
import com.dfsek.terra.api.structures.structure.Rotation;
|
||||
import com.dfsek.terra.api.structures.tokenizer.Position;
|
||||
import net.jafama.FastMath;
|
||||
|
||||
public class AbsFunction extends MathFunction {
|
||||
private final Returnable<Number> returnable;
|
||||
|
||||
public AbsFunction(Position position, Returnable<Number> returnable) {
|
||||
super(position);
|
||||
this.returnable = returnable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return "abs";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number apply(Location location, Rotation rotation, int recursions) {
|
||||
return FastMath.abs(returnable.apply(location, rotation, recursions).doubleValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number apply(Location location, Chunk chunk, Rotation rotation, int recursions) {
|
||||
return FastMath.abs(returnable.apply(location, chunk, rotation, recursions).doubleValue());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.dfsek.terra.api.structures.parser.lang.functions.builtin;
|
||||
|
||||
import com.dfsek.terra.api.structures.parser.lang.functions.Function;
|
||||
import com.dfsek.terra.api.structures.tokenizer.Position;
|
||||
|
||||
public abstract class MathFunction implements Function<Number> {
|
||||
private final Position position;
|
||||
|
||||
protected MathFunction(Position position) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReturnType returnType() {
|
||||
return ReturnType.NUMBER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.dfsek.terra.api.structures.parser.lang.functions.builtin;
|
||||
|
||||
import com.dfsek.terra.api.math.vector.Location;
|
||||
import com.dfsek.terra.api.platform.world.Chunk;
|
||||
import com.dfsek.terra.api.structures.parser.lang.Returnable;
|
||||
import com.dfsek.terra.api.structures.structure.Rotation;
|
||||
import com.dfsek.terra.api.structures.tokenizer.Position;
|
||||
import net.jafama.FastMath;
|
||||
|
||||
public class PowFunction extends MathFunction {
|
||||
private final Returnable<Number> base;
|
||||
private final Returnable<Number> power;
|
||||
|
||||
public PowFunction(Position position, Returnable<Number> base, Returnable<Number> power) {
|
||||
super(position);
|
||||
this.base = base;
|
||||
this.power = power;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return "pow";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number apply(Location location, Rotation rotation, int recursions) {
|
||||
return FastMath.pow(base.apply(location, rotation, recursions).doubleValue(), power.apply(location, rotation, recursions).doubleValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number apply(Location location, Chunk chunk, Rotation rotation, int recursions) {
|
||||
return FastMath.pow(base.apply(location, chunk, rotation, recursions).doubleValue(), power.apply(location, chunk, rotation, recursions).doubleValue());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.dfsek.terra.api.structures.parser.lang.functions.builtin;
|
||||
|
||||
import com.dfsek.terra.api.math.vector.Location;
|
||||
import com.dfsek.terra.api.platform.world.Chunk;
|
||||
import com.dfsek.terra.api.structures.parser.lang.Returnable;
|
||||
import com.dfsek.terra.api.structures.structure.Rotation;
|
||||
import com.dfsek.terra.api.structures.tokenizer.Position;
|
||||
import net.jafama.FastMath;
|
||||
|
||||
public class SqrtFunction extends MathFunction {
|
||||
private final Returnable<Number> returnable;
|
||||
|
||||
public SqrtFunction(Position position, Returnable<Number> returnable) {
|
||||
super(position);
|
||||
this.returnable = returnable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return "sqrt";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number apply(Location location, Rotation rotation, int recursions) {
|
||||
return FastMath.sqrt(returnable.apply(location, rotation, recursions).doubleValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number apply(Location location, Chunk chunk, Rotation rotation, int recursions) {
|
||||
return FastMath.sqrt(returnable.apply(location, chunk, rotation, recursions).doubleValue());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user