diff --git a/grammar/grammar.jjt b/grammar/grammar.jjt index d8d09a87..fe9abd6f 100644 --- a/grammar/grammar.jjt +++ b/grammar/grammar.jjt @@ -30,6 +30,7 @@ import com.cinchapi.ccl.grammar.DirectionSymbol; import com.cinchapi.ccl.grammar.FunctionTokenSymbol; import com.cinchapi.ccl.grammar.KeySymbol; import com.cinchapi.ccl.grammar.ValueTokenSymbol; +import com.cinchapi.ccl.grammar.command.*; import com.cinchapi.ccl.type.function.KeyConditionFunction; import com.cinchapi.ccl.type.function.KeyRecordsFunction; import com.cinchapi.ccl.grammar.FunctionKeySymbol; @@ -44,6 +45,7 @@ import com.cinchapi.ccl.grammar.TimestampSymbol; import com.cinchapi.ccl.grammar.ValueSymbol; import com.cinchapi.ccl.grammar.PageSymbol; import com.cinchapi.ccl.grammar.OrderSymbol; +import com.cinchapi.ccl.grammar.ExpressionSymbol; import com.cinchapi.ccl.syntax.AbstractSyntaxTree; import com.cinchapi.ccl.syntax.ConditionTree; import com.cinchapi.ccl.type.Operator; @@ -53,6 +55,8 @@ import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Multimap; +import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.NoSuchElementException; import java.util.function.Function; @@ -97,6 +101,17 @@ public class Grammar { public Object transformValue(String token) { return valueTransformFunction.apply(token); } + + private boolean isValidJson(String json) { + // Basic JSON validation + int braceCount = 0; + for(char c : json.toCharArray()) { + if(c == '{') braceCount++; + if(c == '}') braceCount--; + if(braceCount < 0) return false; + } + return braceCount == 0; + } } PARSER_END(Grammar) @@ -109,11 +124,71 @@ SKIP : "\t" } +// Token definitions +TOKEN [IGNORE_CASE] : { + // Data modification commands + < ADD: "add" > +| < SET: "set" > +| < REMOVE: "remove" > +| < CLEAR: "clear" > +| < VERIFY_AND_SWAP: "verifyAndSwap" | "verify_and_swap" > +| < VERIFY_OR_SET: "verifyOrSet" | "verify_or_set" > + + // Record operations +| < INSERT: "insert" > + + // Link operations +| < LINK: "link" > +| < UNLINK: "unlink" > + + // Query operations +| < SELECT: "select" > +| < GET: "get" > +| < FIND: "find" > +| < FIND_OR_ADD: "findOrAdd" > +| < FIND_OR_INSERT: "findOrInsert" > +| < DESCRIBE: "describe" > +| < VERIFY: "verify" > +| < SEARCH: "search" > +| < BROWSE: "browse" > +| < CHRONOLOGIZE: "chronologize" > +| < DIFF: "diff" > +| < INVENTORY: "inventory" > +| < JSONIFY: "jsonify" > +| < NAVIGATE: "navigate" > +| < RECONCILE: "reconcile" > +| < REVIEW: "review" > +| < TRACE: "trace" > +| < CALCULATE: "calculate" > + + // Transaction operations +| < STAGE: "stage" > +| < COMMIT: "commit" > +| < ABORT: "abort" > + + // Revert operation +| < REVERT: "revert" > + + // Other keywords +| < IN: "in" > +| < INTO: "into" > +| < FROM: "from" > +| < TO: "to" > +| < AS_OF: "as of" > +| < AS: "as" > +| < FOR: "for" > +| < WITH: "with" > +| < OPEN_BRACE : "{" > +| < CLOSE_BRACE : "}" > +| < COLON : ":" > +} + + TOKEN : { < OPEN_PARENTHESES : "(" > } TOKEN : { < CLOSE_PARENTHESES : ")" > } TOKEN : { < OPEN_BRACKET : "[" > } TOKEN : { < CLOSE_BRACKET : "]" > } -TOKEN [IGNORE_CASE]: { < TIMESTAMP: "at" | "on" | "during" | "in" > } +TOKEN [IGNORE_CASE]: {< TIMESTAMP: "at" | "on" | "during" > } TOKEN [IGNORE_CASE]: { < WHERE: "where" > } TOKEN [IGNORE_CASE]: { < RESERVED_IDENTIFIER: "$id$" > } @@ -204,7 +279,10 @@ TOKEN : ASTStart StartCommandLine() #Start : {} { - ( LOOKAHEAD(4) + ( + Command() "\n" + | + LOOKAHEAD(4) ()? DisjunctionExpression() (Order())? (Page())? "\n" | Page() "\n" @@ -218,7 +296,10 @@ ASTStart StartCommandLine() #Start : {} ASTStart generateAST() #Start : {} { - ( LOOKAHEAD(4) + ( + Command() + | + LOOKAHEAD(4) ()? DisjunctionExpression() (Order())? (Page())? | Page() @@ -266,13 +347,13 @@ void RelationalExpression() #Expression : { key=Key() ( - operator=LinksToOperator() value1=LinksToValue() (timestamp=Timestamp())? + operator=LinksToOperator() value1=LinksToValue() (LOOKAHEAD(2) timestamp=Timestamp())? | - operator=RegexBasedOperator() value1=RegexValue() (timestamp=Timestamp())? + operator=RegexBasedOperator() value1=RegexValue() (LOOKAHEAD(2) timestamp=Timestamp())? | - operator=UnaryOperator() value1=UnaryValue() (timestamp=Timestamp())? + operator=UnaryOperator() value1=UnaryValue() (LOOKAHEAD(2) timestamp=Timestamp())? | - operator=BinaryOperator() value1=BinaryValue() value2=BinaryValue() (timestamp=Timestamp())? + operator=BinaryOperator() value1=BinaryValue() value2=BinaryValue() (LOOKAHEAD(2) timestamp=Timestamp())? ) { jjtThis.key(key); jjtThis.operator(operator); jjtThis.addValue(value1); @@ -478,7 +559,17 @@ TimestampSymbol Timestamp() : String timestamp = ""; } { - (LOOKAHEAD(2) (word= | word= | word= | word= | word= | word=) { timestamp += (timestamp.equals("")) ? word.image : " " + word.image; })+ + ( | ) (LOOKAHEAD(2) (word= | word= | word= | word= | word= | word=) { timestamp += (timestamp.equals("")) ? word.image : " " + word.image; })+ + { return new TimestampSymbol(NaturalLanguage.parseMicros(timestamp)); } +} + +TimestampSymbol TimestampReadCommand() : +{ + Token word; + String timestamp = ""; +} +{ + ( | | ) (LOOKAHEAD(2) (word= | word= | word= | word= | word= | word=) { timestamp += (timestamp.equals("")) ? word.image : " " + word.image; })+ { return new TimestampSymbol(NaturalLanguage.parseMicros(timestamp)); } } @@ -539,6 +630,7 @@ OrderComponentSymbol OrderClause() : DirectionSymbol direction = null; } { + (( direction=SymbolicDirection() key=Key() | @@ -671,4 +763,683 @@ FunctionValueSymbol ValueFunction() : } ) ) -} \ No newline at end of file +} + +void Command() #Command : { + CommandSymbol cmd; +} +{ + ( + cmd = DataModificationOperations() + | + cmd = RecordOperations() + | + cmd = LinkOperations() + | + cmd = QueryOperations() + | + cmd = TransactionOperations() + | + cmd = RevertCommand() + ) + { jjtThis.command(cmd); } +} + +CommandSymbol DataModificationOperations() : { + CommandSymbol cmd; +} +{ + ( + cmd = AddCommand() + | + cmd = SetCommand() + | + cmd = RemoveCommand() + | + cmd = ClearCommand() + | + cmd = VerifyAndSwapCommand() + | + cmd = VerifyOrSetCommand() + ) + { return cmd; } +} + +CommandSymbol AddCommand() : { + KeyTokenSymbol key; + ValueTokenSymbol value; + Token record = null; + Collection records = null; +} +{ + key=Key() value=UnaryValue() + ( + ( + ( + record= + { return new AddSymbol(key, value, Long.parseLong(record.image)); } + | + records=RecordCollection() + { return new AddSymbol(key, value, records); } + ))? + ) + { return new AddSymbol(key, value); } +} + +CommandSymbol SetCommand() : { + KeyTokenSymbol key; + ValueTokenSymbol value; + Token record; +} +{ + key=Key() value=UnaryValue() record= + { return new SetSymbol(key, value, Long.parseLong(record.image)); } +} + +CommandSymbol RemoveCommand() : { + KeyTokenSymbol key; + ValueTokenSymbol value = null; + Token record; + Collection records = null; +} +{ + key=Key() ( value=UnaryValue())? ( | ) + ( + record= { return new RemoveSymbol(key, value, Long.parseLong(record.image)); } + | + records=RecordCollection() { return new RemoveSymbol(key, value, records); } + ) +} + +CommandSymbol ClearCommand() : { + KeyTokenSymbol key = null; + Collection> keys = null; + Token record = null; + Collection records = null; +} +{ + + ( + LOOKAHEAD(2) + record= + { return new ClearSymbol((KeyTokenSymbol)null, Long.parseLong(record.image)); } + | + LOOKAHEAD(3) + records=RecordCollection() + { return new ClearSymbol((KeyTokenSymbol)null, records); } + | + LOOKAHEAD(3) + key=Key() record= + { return new ClearSymbol(key, Long.parseLong(record.image)); } + | + LOOKAHEAD(3) + key=Key() records=RecordCollection() + { return new ClearSymbol(key, records); } + | + LOOKAHEAD(7) + keys=KeyCollection() record= + { return new ClearSymbol(keys, Long.parseLong(record.image)); } + | + LOOKAHEAD(7) + keys=KeyCollection() records=RecordCollection() + { return new ClearSymbol(keys, records); } + ) +} + +CommandSymbol VerifyAndSwapCommand() : { + KeyTokenSymbol key; + ValueTokenSymbol expected; + ValueTokenSymbol replacement; + Token record; +} +{ + key=Key() expected=UnaryValue() record= + replacement=UnaryValue() + { return new VerifyAndSwapSymbol(key, expected, replacement, Long.parseLong(record.image)); } +} + +CommandSymbol VerifyOrSetCommand() : { + KeyTokenSymbol key; + ValueTokenSymbol value; + Token record; +} +{ + key=Key() value=UnaryValue() record= + { return new VerifyOrSetSymbol(key, value, Long.parseLong(record.image)); } +} + +CommandSymbol RecordOperations() : { + CommandSymbol cmd; +} +{ + cmd = InsertCommand() + { return cmd; } +} + +CommandSymbol InsertCommand() : { + String json; + Token record = null; + Collection records = null; +} +{ + json=JsonObject() + { + // Basic JSON validation + if(!isValidJson(json)) { + throw new ParseException("Malformed JSON"); + } + } + ( + ( | ) + ( + record= + { return new InsertSymbol(json, Long.parseLong(record.image)); } + | + records=RecordCollection() + { return new InsertSymbol(json, records); } + ) + )? + { return new InsertSymbol(json); } +} + +CommandSymbol LinkOperations() : { + CommandSymbol cmd; +} +{ + ( + cmd = LinkCommand() + | + cmd = UnlinkCommand() + ) + { return cmd; } +} + +CommandSymbol LinkCommand() : { + KeyTokenSymbol key; + Token source; + Token destination; + Collection destinations = null; +} +{ + key=Key() source= + ( + destination= + { + Collection dest = new ArrayList(); + dest.add(Long.parseLong(destination.image)); + return new LinkSymbol(key, Long.parseLong(source.image), dest); + } + | + destinations=RecordCollection() + { return new LinkSymbol(key, Long.parseLong(source.image), destinations); } + ) +} + +CommandSymbol UnlinkCommand() : { + KeyTokenSymbol key; + Token source; + Token destination; + Collection destinations = null; +} +{ + key=Key() source= + ( + destination= + { + Collection dest = new ArrayList(); + dest.add(Long.parseLong(destination.image)); + return new UnlinkSymbol(key, Long.parseLong(source.image), dest); + } + | + destinations=RecordCollection() + { return new UnlinkSymbol(key, Long.parseLong(source.image), destinations); } + ) +} + +CommandSymbol QueryOperations() : { + CommandSymbol cmd; +} +{ + ( + cmd = SelectCommand() + | + cmd = GetCommand() + | + cmd = FindCommand() + | + cmd = FindOrAddCommand() + | + cmd = FindOrInsertCommand() + | + cmd = DescribeCommand() + | + cmd = VerifyCommand() + | + cmd = SearchCommand() + | + cmd = BrowseCommand() + | + cmd = ChronologizeCommand() + | + cmd = DiffCommand() + | + cmd = InventoryCommand() + | + cmd = JsonifyCommand() + | + cmd = NavigateCommand() + | + cmd = ReconcileCommand() + | + cmd = ReviewCommand() + | + cmd = TraceCommand() + ) + { return cmd; } +} + +CommandSymbol SelectCommand() : { + Collection> keys = null; + KeyTokenSymbol key = null; + Token record = null; + Collection records = null; + TimestampSymbol timestamp = null; +} +{ +