This commit is contained in:
Johanna Stuber 2021-03-06 22:19:22 +01:00
commit 907f766166
11 changed files with 80 additions and 36 deletions

View File

@ -36,12 +36,6 @@
padding-bottom: 24px; padding-bottom: 24px;
text-align: center; text-align: center;
} }
.help-field {
justify-content: center;
align-items: center;
}
kbd { kbd {
background-color: #eee; background-color: #eee;
border-radius: 3px; border-radius: 3px;

View File

@ -0,0 +1,3 @@
[part="value"] {
box-shadow: revert !important;
}

View File

@ -82,15 +82,20 @@ public class LambdaLexer {
char c = term.charAt(pos); char c = term.charAt(pos);
switch (c) { switch (c) {
case '-': case '-':
if (pos + 1 < term.length() && term.charAt(pos + 1) == '>') { if (pos + 1 < term.length()) {
t = new Token(TokenType.ARROW, "->", pos); if (term.charAt(pos + 1) == '>') {
advance(); t = new Token(TokenType.ARROW, "->", pos);
advance(); advance();
return new Result<>(t); advance();
return new Result<>(t);
} else {
return new Result<>(null, ParseError.UNEXPECTED_CHARACTER
.withCharacter(term.charAt(pos + 1), pos + 1));
}
} else { } else {
return new Result<>(null, ParseError.UNEXPECTED_CHARACTER); return new Result<>(null, ParseError.TOO_FEW_TOKENS); // actually too few *characters* ..
} }
// bunch of single-character tokens // bunch of single-character tokens
case '.': case '.':
t = new Token(TokenType.DOT, ".", pos); t = new Token(TokenType.DOT, ".", pos);
advance(); advance();
@ -124,7 +129,8 @@ public class LambdaLexer {
} while (pos < term.length() && Character.isLetterOrDigit(term.charAt(pos)) } while (pos < term.length() && Character.isLetterOrDigit(term.charAt(pos))
&& (int) term.charAt(pos) < 128); && (int) term.charAt(pos) < 128);
if (pos < term.length() && (int) term.charAt(pos) >= 128) { if (pos < term.length() && (int) term.charAt(pos) >= 128) {
return new Result<>(null, ParseError.UNEXPECTED_CHARACTER); return new Result<>(null, ParseError.UNEXPECTED_CHARACTER
.withCharacter(term.charAt(pos), pos));
} }
String s = sb.toString(); String s = sb.toString();
TokenType type; TokenType type;
@ -156,7 +162,7 @@ public class LambdaLexer {
} while (pos < term.length() && Character.isDigit(term.charAt(pos))); } while (pos < term.length() && Character.isDigit(term.charAt(pos)));
return new Result<>(new Token(TokenType.NUMBER, sb.toString(), startPos)); return new Result<>(new Token(TokenType.NUMBER, sb.toString(), startPos));
} else { } else {
return new Result<>(null, ParseError.UNEXPECTED_CHARACTER); return new Result<>(null, ParseError.UNEXPECTED_CHARACTER.withCharacter(c, pos));
} }
} }
} }

View File

@ -24,6 +24,8 @@ public enum ParseError {
UNEXPECTED_CHARACTER; UNEXPECTED_CHARACTER;
private Token cause = new Token(Token.TokenType.EOF, "", -1); private Token cause = new Token(Token.TokenType.EOF, "", -1);
private char wrongChar = '\0';
private int position = -1;
/** /**
* Attach a token to this error. * Attach a token to this error.
@ -36,6 +38,19 @@ public enum ParseError {
return this; return this;
} }
/**
* Attach a character and position to this error.
*
* @param cause the character
* @param position it's position
* @return this object
*/
public ParseError withCharacter(char cause, int position) {
this.wrongChar = cause;
this.position = position;
return this;
}
/** /**
* @return the token associated with this error, or null if none * @return the token associated with this error, or null if none
*/ */
@ -43,6 +58,14 @@ public enum ParseError {
return cause; return cause;
} }
public char getWrongCharacter() {
return wrongChar;
}
public int getPosition() {
return position;
}
ParseError() { ParseError() {
} }

View File

@ -17,6 +17,7 @@ import java.util.regex.Pattern;
*/ */
public class TypeAssumptionParser { public class TypeAssumptionParser {
public static final Pattern TYPE_NAME_PATTERN = Pattern.compile("[a-zA-Z][a-zA-Z0-9]*");
private static final Pattern TYPE_VARIABLE_PATTERN = Pattern.compile("t(\\d+)"); private static final Pattern TYPE_VARIABLE_PATTERN = Pattern.compile("t(\\d+)");
/** /**
@ -28,7 +29,11 @@ public class TypeAssumptionParser {
public Result<Map<VarTerm, TypeAbstraction>, ParseError> parse(Map<String, String> assumptions) { public Result<Map<VarTerm, TypeAbstraction>, ParseError> parse(Map<String, String> assumptions) {
Map<VarTerm, TypeAbstraction> typeAssumptions = new LinkedHashMap<>(); Map<VarTerm, TypeAbstraction> typeAssumptions = new LinkedHashMap<>();
for (Map.Entry<String, String> entry : assumptions.entrySet()) { for (Map.Entry<String, String> entry : assumptions.entrySet()) {
VarTerm var = new VarTerm(entry.getKey()); String typeName = entry.getKey();
if (!TYPE_NAME_PATTERN.matcher(typeName).matches()) {
return new Result<>(null, ParseError.UNEXPECTED_CHARACTER);
}
VarTerm var = new VarTerm(typeName);
Result<TypeAbstraction, ParseError> typeAbs = parseType(entry.getValue()); Result<TypeAbstraction, ParseError> typeAbs = parseType(entry.getValue());
if (typeAbs.isError()) { if (typeAbs.isError()) {
return new Result<>(typeAbs); return new Result<>(typeAbs);

View File

@ -1,9 +1,4 @@
/** /**
* The util package contains classes used in all components of the application. * The util package contains classes used in all components of the application.
*/ */
@NonNullFields
@NonNullApi
package edu.kit.typicalc.util; package edu.kit.typicalc.util;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;

View File

@ -24,7 +24,7 @@ public class ErrorView extends VerticalLayout implements LocaleChangeObserver {
private static final int NO_ADDITIONAL_INFO = -1; private static final int NO_ADDITIONAL_INFO = -1;
private final H3 heading; private final H3 heading;
private Div errorMessage; private final Div errorMessage;
private final ParseError error; private final ParseError error;
public ErrorView(ParseError error) { public ErrorView(ParseError error) {
@ -46,6 +46,14 @@ public class ErrorView extends VerticalLayout implements LocaleChangeObserver {
if (error == ParseError.TOO_FEW_TOKENS) { if (error == ParseError.TOO_FEW_TOKENS) {
additionalInformation.add(new Span(getTranslation("root.tooFewTokensHelp"))); additionalInformation.add(new Span(getTranslation("root.tooFewTokensHelp")));
} else if (error == ParseError.UNEXPECTED_CHARACTER) {
char c = error.getWrongCharacter();
if (c != '\0') {
additionalInformation.add(new Span(getTranslation("root.wrongCharacter") + c));
additionalInformation.add(new Span(getTranslation("root.position") + error.getPosition()));
} else {
return summary;
}
} else { } else {
if (error.getCause().getPos() == NO_ADDITIONAL_INFO) { if (error.getCause().getPos() == NO_ADDITIONAL_INFO) {
return summary; return summary;

View File

@ -15,8 +15,6 @@ import com.vaadin.flow.i18n.LocaleChangeObserver;
* These panels are used for the Accordion in the {@link edu.kit.typicalc.view.main.HelpDialog}. * These panels are used for the Accordion in the {@link edu.kit.typicalc.view.main.HelpDialog}.
*/ */
public class HelpContentField extends AccordionPanel implements LocaleChangeObserver { public class HelpContentField extends AccordionPanel implements LocaleChangeObserver {
private static final String CLASSNAME = "help-field";
private static final long serialVersionUID = -2793005857762897734L; private static final long serialVersionUID = -2793005857762897734L;
private final String summaryKey; private final String summaryKey;

View File

@ -10,6 +10,7 @@ import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.textfield.TextField; import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.i18n.LocaleChangeEvent; import com.vaadin.flow.i18n.LocaleChangeEvent;
import com.vaadin.flow.i18n.LocaleChangeObserver; import com.vaadin.flow.i18n.LocaleChangeObserver;
import edu.kit.typicalc.model.parser.TypeAssumptionParser;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.util.List; import java.util.List;
@ -21,6 +22,7 @@ import java.util.function.Consumer;
*/ */
@JsModule("./src/type-input-listener.js") @JsModule("./src/type-input-listener.js")
@CssImport("./styles/view/main/type-assumption-field.css") @CssImport("./styles/view/main/type-assumption-field.css")
@CssImport(value = "./styles/view/main/type-assumption-input-field.css", themeFor = "vaadin-text-field")
public class TypeAssumptionField extends HorizontalLayout implements LocaleChangeObserver { public class TypeAssumptionField extends HorizontalLayout implements LocaleChangeObserver {
private static final long serialVersionUID = -81579298585584658L; private static final long serialVersionUID = -81579298585584658L;
@ -67,6 +69,8 @@ public class TypeAssumptionField extends HorizontalLayout implements LocaleChang
*/ */
protected TypeAssumptionField(Consumer<TypeAssumptionField> deleteSelf) { protected TypeAssumptionField(Consumer<TypeAssumptionField> deleteSelf) {
variableInputField = new TextField(); variableInputField = new TextField();
variableInputField.getElement().setAttribute(
"pattern", TypeAssumptionParser.TYPE_NAME_PATTERN.pattern());
typeInputField = new TextField(); typeInputField = new TextField();
typeInputField.setClassName(TYPE_FIELD_CLASS); typeInputField.setClassName(TYPE_FIELD_CLASS);
UI.getCurrent().getPage().executeJs("window.addTypeInputListener($0)", TYPE_FIELD_CLASS); UI.getCurrent().getPage().executeJs("window.addTypeInputListener($0)", TYPE_FIELD_CLASS);

View File

@ -91,10 +91,10 @@ Typicalc wurde als PSE-Projekt am KIT im WS20/21 entwickelt von<br>\
Arne Keller<br>\ Arne Keller<br>\
Johanna Stuber<br> Johanna Stuber<br>
root.TOO_FEW_TOKENS=Falsche Eingabe! Der Term endet abrupt. root.TOO_FEW_TOKENS=Falsche Eingabe! Die Eingabe endet abrupt.
root.tooFewTokensHelp=Überprüfe, ob alle Let-, Abs- und App-Terme über die nötigen Argumente verfügen. root.tooFewTokensHelp=Überprüfe, ob alle Let-, Abs- und App-Terme über die nötigen Argumente verfügen.
root.UNEXPECTED_TOKEN=Der Term entspricht nicht der im Info-Dialog spezifizierten Syntax! root.UNEXPECTED_TOKEN=Die Eingabe entspricht nicht der im Info-Dialog spezifizierten Syntax!
root.UNEXPECTED_CHARACTER=Der Term enhält ein Zeichen, welches an dieser Stelle nicht erlaubt ist! root.UNEXPECTED_CHARACTER=Die Eingabe enhält ein Zeichen, welches an dieser Stelle nicht erlaubt ist!
error.heading=Syntaktisch falsche Eingabe! error.heading=Syntaktisch falsche Eingabe!
root.wrongCharacter=Falsches Zeichen: \u0020 root.wrongCharacter=Falsches Zeichen: \u0020
root.position=An Position: \u0020 root.position=An Position: \u0020

View File

@ -209,6 +209,14 @@ class TypeAssumptionParserTest {
assertTrue(type.isError()); assertTrue(type.isError());
assertEquals(entry.getValue(), type.unwrapError()); assertEquals(entry.getValue(), type.unwrapError());
} }
TypeAssumptionParser parser = new TypeAssumptionParser();
Result<Map<VarTerm, TypeAbstraction>, ParseError> type = parser.parse(Map.of("föhn", "int"));
assertTrue(type.isError());
assertEquals(ParseError.UNEXPECTED_CHARACTER, type.unwrapError());
parser = new TypeAssumptionParser();
type = parser.parse(Map.of("1typ", "int"));
assertTrue(type.isError());
assertEquals(ParseError.UNEXPECTED_CHARACTER, type.unwrapError());
} }
@Test @Test