mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2026-06-17 14:21:08 +00:00
add escape character to parser string literals
This commit is contained in:
@@ -3,10 +3,10 @@ package com.dfsek.terra.api.structures.parser;
|
|||||||
import com.dfsek.terra.api.math.vector.Location;
|
import com.dfsek.terra.api.math.vector.Location;
|
||||||
import com.dfsek.terra.api.platform.world.Chunk;
|
import com.dfsek.terra.api.platform.world.Chunk;
|
||||||
|
|
||||||
public interface Function {
|
public interface Function<T> {
|
||||||
void apply(Location location);
|
T apply(Location location);
|
||||||
|
|
||||||
void apply(Location location, Chunk chunk);
|
T apply(Location location, Chunk chunk);
|
||||||
|
|
||||||
String name();
|
String name();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,21 +15,21 @@ import java.util.stream.Collectors;
|
|||||||
|
|
||||||
public class Parser {
|
public class Parser {
|
||||||
private final String data;
|
private final String data;
|
||||||
private final Map<String, FunctionBuilder<? extends Function>> functions = new HashMap<>();
|
private final Map<String, FunctionBuilder<? extends Function<?>>> functions = new HashMap<>();
|
||||||
Set<Token.Type> allowedArguments = Sets.newHashSet(Token.Type.STRING, Token.Type.NUMBER, Token.Type.IDENTIFIER);
|
Set<Token.Type> allowedArguments = Sets.newHashSet(Token.Type.STRING, Token.Type.NUMBER, Token.Type.IDENTIFIER);
|
||||||
|
|
||||||
public Parser(String data) {
|
public Parser(String data) {
|
||||||
this.data = data;
|
this.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Parser addFunction(String name, FunctionBuilder<? extends Function> functionBuilder) {
|
public Parser addFunction(String name, FunctionBuilder<? extends Function<?>> functionBuilder) {
|
||||||
functions.put(name, functionBuilder);
|
functions.put(name, functionBuilder);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Function> parse() throws ParseException {
|
public List<Function<?>> parse() throws ParseException {
|
||||||
Tokenizer tokenizer = new Tokenizer(data);
|
Tokenizer tokenizer = new Tokenizer(data);
|
||||||
List<Function> builtFunctions = new GlueList<>();
|
List<Function<?>> builtFunctions = new GlueList<>();
|
||||||
List<Token> functionBuilder = new GlueList<>();
|
List<Token> functionBuilder = new GlueList<>();
|
||||||
Token token = null;
|
Token token = null;
|
||||||
while(tokenizer.hasNext()) {
|
while(tokenizer.hasNext()) {
|
||||||
@@ -46,32 +46,15 @@ public class Parser {
|
|||||||
|
|
||||||
checkType(functionBuilder.remove(0), Token.Type.BODY_BEGIN); // Second is body begin
|
checkType(functionBuilder.remove(0), Token.Type.BODY_BEGIN); // Second is body begin
|
||||||
|
|
||||||
boolean expectingSeparator = false;
|
|
||||||
|
|
||||||
List<Token> args = new GlueList<>();
|
List<Token> args = getArgs(functionBuilder); // Extract arguments, consume the rest.
|
||||||
|
|
||||||
while(!functionBuilder.get(0).getType().equals(Token.Type.BODY_END)) {
|
|
||||||
Token current = functionBuilder.remove(0);
|
|
||||||
if(expectingSeparator) {
|
|
||||||
checkType(current, Token.Type.SEPARATOR);
|
|
||||||
expectingSeparator = false;
|
|
||||||
} else {
|
|
||||||
if(!allowedArguments.contains(current.getType()))
|
|
||||||
throw new ParseException("Token type " + current.getType() + " not allowed in arguments: " + current.getStart());
|
|
||||||
args.add(current);
|
|
||||||
expectingSeparator = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
functionBuilder.remove(0); // Remove body end
|
functionBuilder.remove(0); // Remove body end
|
||||||
|
|
||||||
for(Token t : args) System.out.println("TOKEN: " + t);
|
|
||||||
|
|
||||||
checkType(functionBuilder.remove(0), Token.Type.STATEMENT_END);
|
checkType(functionBuilder.remove(0), Token.Type.STATEMENT_END);
|
||||||
|
|
||||||
List<String> arg = args.stream().map(Token::getContent).collect(Collectors.toList());
|
List<String> arg = args.stream().map(Token::getContent).collect(Collectors.toList());
|
||||||
|
|
||||||
for(String s : arg) System.out.println("ARG: " + s);
|
|
||||||
FunctionBuilder<?> builder = functions.get(identifier.getContent());
|
FunctionBuilder<?> builder = functions.get(identifier.getContent());
|
||||||
if(arg.size() != builder.getArguments().size())
|
if(arg.size() != builder.getArguments().size())
|
||||||
throw new ParseException("Expected " + builder.getArguments().size() + " arguments, found " + arg.size() + ": " + identifier.getStart());
|
throw new ParseException("Expected " + builder.getArguments().size() + " arguments, found " + arg.size() + ": " + identifier.getStart());
|
||||||
@@ -89,6 +72,25 @@ public class Parser {
|
|||||||
return builtFunctions;
|
return builtFunctions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<Token> getArgs(List<Token> functionBuilder) throws ParseException {
|
||||||
|
List<Token> args = new GlueList<>();
|
||||||
|
boolean expectingSeparator = false;
|
||||||
|
|
||||||
|
while(!functionBuilder.get(0).getType().equals(Token.Type.BODY_END)) {
|
||||||
|
Token current = functionBuilder.remove(0);
|
||||||
|
if(expectingSeparator) {
|
||||||
|
checkType(current, Token.Type.SEPARATOR);
|
||||||
|
expectingSeparator = false;
|
||||||
|
} else {
|
||||||
|
if(!allowedArguments.contains(current.getType()))
|
||||||
|
throw new ParseException("Token type " + current.getType() + " not allowed in arguments: " + current.getStart());
|
||||||
|
args.add(current);
|
||||||
|
expectingSeparator = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
private void checkType(Token token, Token.Type expected) throws ParseException {
|
private void checkType(Token token, Token.Type expected) throws ParseException {
|
||||||
if(!token.getType().equals(expected))
|
if(!token.getType().equals(expected))
|
||||||
throw new ParseException("Expected " + expected + " but found " + token.getType() + ": " + token.getStart());
|
throw new ParseException("Expected " + expected + " but found " + token.getType() + ": " + token.getStart());
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
package com.dfsek.terra.api.structures.parser.lang;
|
||||||
|
|
||||||
|
public class Block {
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
package com.dfsek.terra.api.structures.parser.lang;
|
||||||
|
|
||||||
|
public class Expression {
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
package com.dfsek.terra.api.structures.parser.lang;
|
||||||
|
|
||||||
|
public interface Item {
|
||||||
|
}
|
||||||
@@ -29,6 +29,6 @@ public class Token {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public enum Type {
|
public enum Type {
|
||||||
IDENTIFIER, NUMBER, STRING, BOOLEAN, BODY_BEGIN, BODY_END, STATEMENT_END, SEPARATOR
|
IDENTIFIER, NUMBER, STRING, BOOLEAN, BODY_BEGIN, BODY_END, STATEMENT_END, SEPARATOR, BLOCK_BEGIN, BLOCK_END
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ import java.util.Set;
|
|||||||
public class Tokenizer {
|
public class Tokenizer {
|
||||||
private final Lookahead reader;
|
private final Lookahead reader;
|
||||||
|
|
||||||
private final Set<Character> syntaxSignificant = Sets.newHashSet(';', '(', ')', '"', '[', ']', ',');
|
private final Set<Character> syntaxSignificant = Sets.newHashSet(';', '(', ')', '"', ',', '\\', // Currently used chars
|
||||||
|
'{', '}'); // Reserved chars
|
||||||
|
|
||||||
|
|
||||||
public Tokenizer(String data) {
|
public Tokenizer(String data) {
|
||||||
@@ -42,7 +43,13 @@ public class Tokenizer {
|
|||||||
if(reader.current().is('"')) {
|
if(reader.current().is('"')) {
|
||||||
reader.consume(); // Consume first quote
|
reader.consume(); // Consume first quote
|
||||||
StringBuilder string = new StringBuilder();
|
StringBuilder string = new StringBuilder();
|
||||||
while(!reader.current().is('"')) {
|
boolean ignoreNext = false;
|
||||||
|
while((!reader.current().is('"')) || ignoreNext) {
|
||||||
|
if(reader.current().is('\\') && !ignoreNext) {
|
||||||
|
ignoreNext = true;
|
||||||
|
reader.consume();
|
||||||
|
continue;
|
||||||
|
} else ignoreNext = false;
|
||||||
if(reader.current().isEOF())
|
if(reader.current().isEOF())
|
||||||
throw new FormatException("No end of string literal found. " + reader.getLine() + ":" + reader.getIndex());
|
throw new FormatException("No end of string literal found. " + reader.getLine() + ":" + reader.getIndex());
|
||||||
string.append(reader.consume());
|
string.append(reader.consume());
|
||||||
@@ -59,6 +66,10 @@ public class Tokenizer {
|
|||||||
return new Token(reader.consume().toString(), Token.Type.STATEMENT_END, new Position(reader.getLine(), reader.getIndex()));
|
return new Token(reader.consume().toString(), Token.Type.STATEMENT_END, new Position(reader.getLine(), reader.getIndex()));
|
||||||
if(reader.current().is(','))
|
if(reader.current().is(','))
|
||||||
return new Token(reader.consume().toString(), Token.Type.SEPARATOR, new Position(reader.getLine(), reader.getIndex()));
|
return new Token(reader.consume().toString(), Token.Type.SEPARATOR, new Position(reader.getLine(), reader.getIndex()));
|
||||||
|
if(reader.current().is('{'))
|
||||||
|
return new Token(reader.consume().toString(), Token.Type.BLOCK_BEGIN, new Position(reader.getLine(), reader.getIndex()));
|
||||||
|
if(reader.current().is('}'))
|
||||||
|
return new Token(reader.consume().toString(), Token.Type.BLOCK_END, new Position(reader.getLine(), reader.getIndex()));
|
||||||
|
|
||||||
StringBuilder token = new StringBuilder();
|
StringBuilder token = new StringBuilder();
|
||||||
while(!reader.current().isEOF() && !isSyntaxSignificant(reader.current().getCharacter())) {
|
while(!reader.current().isEOF() && !isSyntaxSignificant(reader.current().getCharacter())) {
|
||||||
|
|||||||
@@ -31,14 +31,15 @@ public class ParserTest {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
List<Function> functions = parser.parse();
|
long l = System.nanoTime();
|
||||||
|
List<Function<?>> functions = parser.parse();
|
||||||
|
long t = System.nanoTime() - l;
|
||||||
|
System.out.println("Took " + (double) t / 1000000);
|
||||||
|
|
||||||
for(Function f : functions) {
|
for(Function<?> f : functions) System.out.println(f);
|
||||||
System.out.println(f);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class Test1 implements Function {
|
private static class Test1 implements Function<Void> {
|
||||||
private final String a;
|
private final String a;
|
||||||
private final double b;
|
private final double b;
|
||||||
|
|
||||||
@@ -56,18 +57,23 @@ public class ParserTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void apply(Location location) {
|
public Void apply(Location location) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void apply(Location location, Chunk chunk) {
|
public Void apply(Location location, Chunk chunk) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String name() {
|
public String name() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "string: " + a + ", double: " + b;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,2 @@
|
|||||||
test("hello", 1);
|
test("hello", 1);
|
||||||
|
test("ghgj{}()\"\\hgjhgj", 3.4);
|
||||||
test("ghgjhgjhgj", 3.4);
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user