diff --git a/examples/network/github_timeline.own b/examples/network/github_timeline.own index b04c2c2..41dfc0a 100644 --- a/examples/network/github_timeline.own +++ b/examples/network/github_timeline.own @@ -19,42 +19,42 @@ thread(::http, "https://api.github.com/events", def(r) { }) def show_github_events(event) { - println event["created_at"] - actor = event["actor"] - println "User: https://github.com/" + actor["login"] + println event.created_at + actor = event.actor + println "User: https://github.com/" + actor.login println github_event_type(event) println "-" * 50 } def github_event_type(event) { - type = event["type"] - repo = "https://github.com/" + event["repo"]["name"] - payload = event["payload"] + type = event.type + repo = "https://github.com/" + event.repo.name + payload = event.payload if (type == "CommitCommentEvent") { - return "commented commit in " + repo + "\n" + payload["comment"]["body"] + return "commented commit in " + repo + "\n" + payload.comment.body } if (type == "CreateEvent") { - return "created " + payload["ref_type"] + " on " + repo + return "created " + payload.ref_type + " on " + repo } if (type == "DeleteEvent") { - return "deleted " + payload["ref_type"] + " on " + repo + return "deleted " + payload.ref_type + " on " + repo } if (type == "ForkEvent") { return "forked repository " + repo } if (type == "IssueCommentEvent") { - return "commented issue " + payload["issue"]["title"] + " on " + repo + "\n" + payload["comment"]["body"] + return "commented issue " + payload.issue.title + " on " + repo + "\n" + payload.comment.body } if (type == "IssuesEvent") { - return payload["action"] + " issue '" + payload["issue"]["title"] + "' on " + repo + return payload.action + " issue '" + payload.issue.title + "' on " + repo } if (type == "PullRequestEvent") { - pr = payload["pull_request"] - return payload["action"] + " pull request #" + payload["number"] + " '" + pr["title"] + "' on " + repo + pr = payload.pull_request + return payload.action + " pull request #" + payload.number + " '" + pr.title + "' on " + repo } if (type == "PushEvent") { - return "pushed " + length(payload["commits"]) + " commits to " + repo + return "pushed " + length(payload.commits) + " commits to " + repo } if (type == "WatchEvent") { return "start watching repository " + repo diff --git a/src/com/annimon/ownlang/parser/Lexer.java b/src/com/annimon/ownlang/parser/Lexer.java index 2005dc3..455f8e8 100644 --- a/src/com/annimon/ownlang/parser/Lexer.java +++ b/src/com/annimon/ownlang/parser/Lexer.java @@ -11,7 +11,7 @@ import java.util.Map; */ public final class Lexer { - private static final String OPERATOR_CHARS = "+-*/%()[]{}=<>!&|,^~?:"; + private static final String OPERATOR_CHARS = "+-*/%()[]{}=<>!&|.,^~?:"; private static final Map OPERATORS; static { @@ -30,6 +30,7 @@ public final class Lexer { OPERATORS.put("=", TokenType.EQ); OPERATORS.put("<", TokenType.LT); OPERATORS.put(">", TokenType.GT); + OPERATORS.put(".", TokenType.DOT); OPERATORS.put(",", TokenType.COMMA); OPERATORS.put("^", TokenType.CARET); OPERATORS.put("~", TokenType.TILDE); diff --git a/src/com/annimon/ownlang/parser/Parser.java b/src/com/annimon/ownlang/parser/Parser.java index 9608ebf..7b68c9a 100644 --- a/src/com/annimon/ownlang/parser/Parser.java +++ b/src/com/annimon/ownlang/parser/Parser.java @@ -237,6 +237,19 @@ public final class Parser { return new ArrayAccessExpression(variable, indices); } + private ArrayAccessExpression object() { + // object.field1.field2 + // Syntaxic sugar for object["field1"]["field2"] + final String variable = consume(TokenType.WORD).getText(); + final List indices = new ArrayList<>(); + while (match(TokenType.DOT)) { + final String fieldName = consume(TokenType.WORD).getText(); + final Expression key = new ValueExpression(fieldName); + indices.add(key); + } + return new ArrayAccessExpression(variable, indices); + } + private Expression expression() { return ternary(); } @@ -459,6 +472,9 @@ public final class Parser { if (lookMatch(0, TokenType.WORD) && lookMatch(1, TokenType.LPAREN)) { return function(); } + if (lookMatch(0, TokenType.WORD) && lookMatch(1, TokenType.DOT)) { + return object(); + } if (lookMatch(0, TokenType.LBRACKET)) { return array(); } diff --git a/src/com/annimon/ownlang/parser/TokenType.java b/src/com/annimon/ownlang/parser/TokenType.java index adc344a..77e4723 100644 --- a/src/com/annimon/ownlang/parser/TokenType.java +++ b/src/com/annimon/ownlang/parser/TokenType.java @@ -61,6 +61,7 @@ public enum TokenType { LBRACE, // { RBRACE, // } COMMA, // , + DOT, // . EOF }