diff --git a/app/src/main/java/com/annimon/hotarufx/lexer/HotaruLexer.java b/app/src/main/java/com/annimon/hotarufx/lexer/HotaruLexer.java index cc10f56..e4c88d7 100644 --- a/app/src/main/java/com/annimon/hotarufx/lexer/HotaruLexer.java +++ b/app/src/main/java/com/annimon/hotarufx/lexer/HotaruLexer.java @@ -14,7 +14,7 @@ public class HotaruLexer extends Lexer { } private static final String TEXT_CHARS = "'\""; - private static final String OPERATOR_CHARS = "(){}:=+-.,"; + private static final String OPERATOR_CHARS = "(){}:=+-.,@"; private static final Map OPERATORS; static { @@ -29,6 +29,7 @@ public class HotaruLexer extends Lexer { OPERATORS.put("-", HotaruTokenId.MINUS); OPERATORS.put(".", HotaruTokenId.DOT); OPERATORS.put(",", HotaruTokenId.COMMA); + OPERATORS.put("@", HotaruTokenId.AT); } public HotaruLexer(String input) { diff --git a/app/src/main/java/com/annimon/hotarufx/lexer/HotaruTokenId.java b/app/src/main/java/com/annimon/hotarufx/lexer/HotaruTokenId.java index 00be239..dc8cb33 100644 --- a/app/src/main/java/com/annimon/hotarufx/lexer/HotaruTokenId.java +++ b/app/src/main/java/com/annimon/hotarufx/lexer/HotaruTokenId.java @@ -20,6 +20,7 @@ public enum HotaruTokenId { COLON(Category.OPERATOR), COMMA(Category.OPERATOR), DOT(Category.OPERATOR), + AT(Category.OPERATOR), SINGLE_LINE_COMMENT(Category.COMMENT), MULTI_LINE_COMMENT(Category.COMMENT), diff --git a/app/src/main/java/com/annimon/hotarufx/parser/HotaruParser.java b/app/src/main/java/com/annimon/hotarufx/parser/HotaruParser.java index 18452bb..88c177f 100644 --- a/app/src/main/java/com/annimon/hotarufx/parser/HotaruParser.java +++ b/app/src/main/java/com/annimon/hotarufx/parser/HotaruParser.java @@ -16,7 +16,7 @@ public class HotaruParser extends Parser { val parser = new HotaruParser(tokens); val program = parser.parse(); if (parser.getParseErrors().hasErrors()) { - throw new ParseException(); + throw new ParseException(parser.getParseErrors().toString()); } return program; } @@ -58,9 +58,14 @@ public class HotaruParser extends Parser { if (lookMatch(0, HotaruTokenId.LPAREN)) { return functionChain(expr); } + return objectAccess(expr); + } + + private Node objectAccess(Node expr) { if (lookMatch(0, HotaruTokenId.DOT)) { - final List indices = variableSuffix(); - if (indices == null || indices.isEmpty()) return expr; + val indices = variableSuffix(); + if (indices == null || indices.isEmpty()) + return expr; if (lookMatch(0, HotaruTokenId.LPAREN)) { // next function call @@ -159,6 +164,12 @@ public class HotaruParser extends Parser { if (lookMatch(0, HotaruTokenId.LPAREN)) { return functionChain(qualifiedNameExpr); } + // node@prop || map.node@prop + if (match(HotaruTokenId.AT)) { + val propName = consume(HotaruTokenId.WORD).getText(); + val expr = new PropertyNode(qualifiedNameExpr, propName); + return objectAccess(expr); + } return qualifiedNameExpr; } diff --git a/app/src/main/java/com/annimon/hotarufx/parser/ast/PropertyNode.java b/app/src/main/java/com/annimon/hotarufx/parser/ast/PropertyNode.java new file mode 100644 index 0000000..4ef7530 --- /dev/null +++ b/app/src/main/java/com/annimon/hotarufx/parser/ast/PropertyNode.java @@ -0,0 +1,16 @@ +package com.annimon.hotarufx.parser.ast; + +import com.annimon.hotarufx.parser.visitors.ResultVisitor; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public class PropertyNode extends ASTNode { + + public final Node node; + public final String property; + + @Override + public R accept(ResultVisitor visitor, T input) { + return visitor.visit(this, input); + } +} diff --git a/app/src/main/java/com/annimon/hotarufx/parser/visitors/InterpreterVisitor.java b/app/src/main/java/com/annimon/hotarufx/parser/visitors/InterpreterVisitor.java index 7bad326..045fd4e 100644 --- a/app/src/main/java/com/annimon/hotarufx/parser/visitors/InterpreterVisitor.java +++ b/app/src/main/java/com/annimon/hotarufx/parser/visitors/InterpreterVisitor.java @@ -61,6 +61,11 @@ public class InterpreterVisitor implements ResultVisitor { return new MapValue(map); } + @Override + public Value visit(PropertyNode node, Context context) { + return node.node.accept(this, context); + } + @Override public Value visit(UnaryNode node, Context context) { switch (node.operator) { diff --git a/app/src/main/java/com/annimon/hotarufx/parser/visitors/ResultVisitor.java b/app/src/main/java/com/annimon/hotarufx/parser/visitors/ResultVisitor.java index 6b8f945..b9b818e 100644 --- a/app/src/main/java/com/annimon/hotarufx/parser/visitors/ResultVisitor.java +++ b/app/src/main/java/com/annimon/hotarufx/parser/visitors/ResultVisitor.java @@ -6,6 +6,7 @@ import com.annimon.hotarufx.parser.ast.AssignNode; import com.annimon.hotarufx.parser.ast.BlockNode; import com.annimon.hotarufx.parser.ast.FunctionNode; import com.annimon.hotarufx.parser.ast.MapNode; +import com.annimon.hotarufx.parser.ast.PropertyNode; import com.annimon.hotarufx.parser.ast.UnaryNode; import com.annimon.hotarufx.parser.ast.ValueNode; import com.annimon.hotarufx.parser.ast.VariableNode; @@ -17,6 +18,7 @@ public interface ResultVisitor { R visit(BlockNode node, T t); R visit(FunctionNode node, T t); R visit(MapNode node, T t); + R visit(PropertyNode node, T t); R visit(UnaryNode node, T t); R visit(ValueNode node, T t); R visit(VariableNode node, T t);