package com.kls.ast; import com.common.ast.Location; import com.klq.logic.question.Type; import com.kls.ast.node.*; import com.kls.ast.node.property.*; import com.kls.ast.node.value.*; import com.kls.parser.KLSBaseVisitor; import com.kls.parser.KLSParser; import com.sun.javaws.exceptions.InvalidArgumentException; import javafx.scene.text.Font; import org.antlr.v4.runtime.ParserRuleContext; import org.antlr.v4.runtime.misc.NotNull; import java.text.ParseException; import java.util.ArrayList; import java.util.List; /** * Created by Timon on 03.03.2015. */ public class ASTGenerator extends KLSBaseVisitor<ANodeBase> { private final String inputfile; public ASTGenerator(String inputfile) { this.inputfile = inputfile; } @Override public ANodeBase visitStylesheet(@NotNull KLSParser.StylesheetContext ctx) { StylesheetNode stylesheetNode = new StylesheetNode(getLocation(ctx)); for (KLSParser.PageContext page : ctx.page()) { PageNode pageNode = (PageNode) (visitPage(page)); stylesheetNode.getGroups().add(pageNode); } for (KLSParser.SectionContext section : ctx.section()) { SectionNode sectionNode = (SectionNode) (visitSection(section)); stylesheetNode.getGroups().add(sectionNode); } for (KLSParser.QuestionContext question : ctx.question()) { QuestionNode questionNode = (QuestionNode) (visitQuestion(question)); stylesheetNode.getSelectors().add(questionNode); } return stylesheetNode; } @Override public ANodeBase visitPage(@NotNull KLSParser.PageContext ctx) { List<SectionNode> sections = new ArrayList<>(); for (KLSParser.SectionContext section : ctx.section()) { SectionNode sectionNode = (SectionNode) (visitSection(section)); sections.add(sectionNode); } List<QuestionNode> questions = new ArrayList<>(); for (KLSParser.QuestionContext question : ctx.question()) { QuestionNode questionNode = (QuestionNode) (visitQuestion(question)); questions.add(questionNode); } DefaultNode def = (DefaultNode) (visitDefaultStyle(ctx.defaultStyle())); return new PageNode(ctx.title.getText(), sections, questions, def, getLocation(ctx)); } @Override public ANodeBase visitSection(@NotNull KLSParser.SectionContext ctx) { List<QuestionNode> questions = new ArrayList<>(); for (KLSParser.QuestionContext question : ctx.question()) { QuestionNode questionNode = (QuestionNode) (visitQuestion(question)); questions.add(questionNode); } String title = ctx.title.getText(); Location location = getLocation(ctx); if (ctx.defaultStyle() != null) { DefaultNode def = (DefaultNode) (visitDefaultStyle(ctx.defaultStyle())); return new SectionNode(title, questions, def, location); } else { return new SectionNode(title, questions, null, location); } } @Override public ANodeBase visitQuestion(@NotNull KLSParser.QuestionContext ctx) { List<DeclarationNode> declarations = new ArrayList<>(); if (ctx.full() != null) { for (KLSParser.DeclarationContext declarationContext : ctx.full().declaration()) { DeclarationNode declarationNode = (DeclarationNode) (visitDeclaration(declarationContext)); declarations.add(declarationNode); } return new QuestionNode(ctx.full().id.getText(), declarations, getLocation(ctx)); } else if (ctx.identifier() != null) { return new QuestionNode(ctx.identifier().id.getText(), declarations, getLocation(ctx)); } throw new IllegalArgumentException("Unknown question context."); } @Override public ANodeBase visitDeclaration(@NotNull KLSParser.DeclarationContext ctx) { PropertyNode propertyNode = (PropertyNode) visitProperty(ctx.property()); ValueNode valueNode = (ValueNode) visitValue(ctx.value()); /* if (propertyNode.getProperty().isCompatibleWith(valueNode.getValue())){ return new DeclarationNode(propertyNode, valueNode, getLocation(ctx)); }*/ return new DeclarationNode(propertyNode, valueNode, getLocation(ctx)); } @Override public ANodeBase visitProperty(@NotNull KLSParser.PropertyContext ctx) { AProperty property = parseProperty(ctx.getText()); assert(property != null); return new PropertyNode(property, getLocation(ctx)); } private AProperty parseProperty(String property){ String normalized = property.toLowerCase().trim(); if (normalized.equals(FontFamilyProperty.FONT_FAMILY)){ return new FontFamilyProperty(); } else if (normalized.equals(FontSizeProperty.FONT_SIZE)){ return new FontSizeProperty(); } else if (normalized.equals(FontStyleProperty.FONT_STYLE)){ return new FontStyleProperty(); } else if (normalized.equals(FontColorProperty.FONT_COLOR)){ return new FontColorProperty(); } else if (normalized.equals(BackgroundColorProperty.BACKGROUND_COLOR)){ return new BackgroundColorProperty(); } else if (normalized.equals(WidgetProperty.WIDGET)){ return new WidgetProperty(); } return null; } @Override public ANodeBase visitValue(@NotNull KLSParser.ValueContext ctx) { String valueString = ctx.getText(); AValue value = parseValue(valueString); return new ValueNode(value, getLocation(ctx)); } private AValue parseValue(String value) { String normalized = value.trim().toLowerCase(); if (isInt(normalized)) { return new FontSizeValue(Integer.parseInt(normalized)); } else if (isHexColor(normalized)) { return new ColorValue(normalized); } else if (isWidget(normalized)) { return new WidgetValue(getWidgetValue(normalized)); } else if (isFontStyle(normalized)) { return new FontStyleValue(normalized); } else { return new StringValue(normalized); } } private boolean isInt(String value) { try { Integer.parseInt(value); return true; } catch (NumberFormatException nfe) { return false; } } private boolean isHexColor(String value) { String hexPattern = "#" + "[0-9A-Fa-f]" + "{6}"; return value.matches(hexPattern); } private boolean isWidget(String value) { return getWidgetValue(value) != WidgetValue.Widget.NOT_A_WIDGET; } private WidgetValue.Widget getWidgetValue(String value) { if (value.equals(WidgetValue.Widget.SLIDER.toString())) { return WidgetValue.Widget.SLIDER; } else if (value.equals(WidgetValue.Widget.SPINBOX.toString())) { return WidgetValue.Widget.SPINBOX; } else if (value.equals(WidgetValue.Widget.TEXT.toString())) { return WidgetValue.Widget.TEXT; } else if (value.equals(WidgetValue.Widget.YES_NO_RADIO.toString())) { return WidgetValue.Widget.YES_NO_RADIO; } else if (value.equals(WidgetValue.Widget.YES_NO_DROPDOWN.toString())) { return WidgetValue.Widget.YES_NO_DROPDOWN; } else if (value.equals(WidgetValue.Widget.CHECKBOX.toString())) { return WidgetValue.Widget.CHECKBOX; } return WidgetValue.Widget.NOT_A_WIDGET; } private boolean isFontStyle(String value) { return value.matches(FontStyleValue.FONT_BOLD) || value.matches(FontStyleValue.FONT_ITALIC) || value.matches(FontStyleValue.FONT_UNDERLINED); } @Override public ANodeBase visitDefaultStyle(@NotNull KLSParser.DefaultStyleContext ctx) { List<DeclarationNode> declarations = new ArrayList<>(); for (KLSParser.DeclarationContext declarationContext : ctx.declaration()){ DeclarationNode declaration = (DeclarationNode) visitDeclaration(declarationContext); declarations.add(declaration); } Type type = Type.getEnum(ctx.klqType().getText()); return new DefaultNode(type, declarations, getLocation(ctx)); } private Location getLocation(ParserRuleContext context){ return new Location(inputfile, context); } }