diff --git a/grammars/Babel Language.json b/grammars/Babel Language.json index 225c699..f1c8fba 100644 --- a/grammars/Babel Language.json +++ b/grammars/Babel Language.json @@ -448,6 +448,26 @@ } ] }, + "type-argument-brackets": { + "patterns": [ + { + "comment": "Type arguments. This is complicated since we don't want to match things like foo < 123 || bar > baz", + "name": "meta.type-arguments.flowtype", + "begin": "\\s*+(<)(?=((?:(?>[^<>]+)|<\\g<-1>>)*)>)", + "end": "\\s*(>)", + "endCaptures": { + "1": { "name": "punctuation.flowtype" } + }, + "beginCaptures": { + "1": { "name": "punctuation.flowtype" } + }, + "patterns": [ + { "include": "#flowtype-parse-types" }, + { "include": "#literal-comma" } + ] + } + ] + }, "square-brackets": { "patterns": [ { @@ -1364,6 +1384,8 @@ { "include": "#comments" }, { "include": "#literal-keywords" }, { + "comment": "A new expression with no type params or arguments, like new Foo()", + "name": "meta.new-class.without-arguments.js", "match": "(?()", + "name": "meta.new-class.without-arguments.js", + "begin": "(?[^<>]+)|\\g<-1>)*>)\\s*+(\\()\\s*+(\\))))", + "end": "(?=.)", + "applyEndPatternLast": 1, + "beginCaptures": { + "1": { "name": "keyword.operator.new.js" }, + "2": { "name": "meta.function-call.without-arguments.js" }, + "3": { "name": "keyword.operator.private.js" }, + "4": { "name": "entity.name.type.instance.js" }, + "5": { "name": "keyword.operator.existential.js"} + }, + "patterns": [ + { "include": "#type-argument-brackets" }, + { "include": "#round-brackets" } + ] + }, + { + "comment": "A new expression with arguments and maybe type params, like new Foo(123)", + "name": "meta.new-class.with-arguments.js", + "begin": "(?[^<>]+)|\\g<-1>)*>)?\\s*+\\())", "end": "(?=.)", "applyEndPatternLast": 1, "beginCaptures": { @@ -1387,11 +1429,13 @@ "5": { "name": "keyword.operator.existential.js"} }, "patterns": [ + { "include": "#type-argument-brackets" }, { "include": "#round-brackets" } ] }, - { "include": "#literal-operators" }, + { "include": "#literal-operators" }, { + "comment": "A call expression with no type params or arguments, like foo()", "name": "meta.function-call.without-arguments.js", "match": "(?()", + "name": "meta.function-call.without-arguments.js", + "begin": "(?[^<>]+)|\\g<-1>)*>)\\s*+(\\()\\s*+(\\)))", + "end": "(?=.)", + "applyEndPatternLast": 1, + "beginCaptures": { + "1": { "name": "keyword.operator.private.js" }, + "2": { "name": "entity.name.function.js" }, + "3": { "name": "keyword.operator.existential.js"} + }, + "patterns": [ + { "include": "#type-argument-brackets" }, + { "include": "#round-brackets" } + ] + }, + { + "comment": "maybe in array form e.g. foo[bar]() or foo[bar]()", "name": "meta.function-call.without-arguments.js", - "begin": "(?[^\\[\\]]+)|\\g<-1>)*\\])\\s*+\\(\\s*+\\))", + "begin": "(?[^\\[\\]]+)|\\g<-1>)*\\])\\s*+(<(?:(?>[^<>]+)|\\g<-1>)*>)?\\s*+\\(\\s*+\\))", "end": "(?=.)", "applyEndPatternLast": 1, "beginCaptures": { @@ -1415,12 +1475,14 @@ }, "patterns": [ { "include": "#square-brackets"}, + { "include": "#type-argument-brackets" }, { "include": "#round-brackets" } ] }, { + "comment": "A call expression with arguments and maybe type params, like foo(123) or foo(123)", "name": "meta.function-call.with-arguments.js", - "begin": "(?[^<>]+)|\\g<-1>)*>)?\\s*+\\()", "end": "(?=.)", "applyEndPatternLast": 1, "beginCaptures": { @@ -1429,13 +1491,14 @@ "3": { "name": "keyword.operator.existential.js"} }, "patterns": [ + { "include": "#type-argument-brackets" }, { "include": "#round-brackets" } ] }, { - "comment": "maybe in array form e.g. foo[bar]()", - "name": "meta.function-call.without-arguments.js", - "begin": "(?[^\\[\\]]+)|\\g<-1>)*\\])\\s*+\\()", + "comment": "maybe in array form e.g. foo[bar](123)", + "name": "meta.function-call.with-arguments.js", + "begin": "(?[^\\[\\]]+)|\\g<-1>)*\\])\\s*+(<(?:(?>[^<>]+)|\\g<-1>)*>)?\\s*+\\()", "end": "(?=.)", "applyEndPatternLast": 1, "beginCaptures": { @@ -1445,6 +1508,7 @@ }, "patterns": [ { "include": "#square-brackets"}, + { "include": "#type-argument-brackets" }, { "include": "#round-brackets" } ] } diff --git a/spec/fixtures/grammar/babel-sublime/flow-function-call-with-type-arguments.js b/spec/fixtures/grammar/babel-sublime/flow-function-call-with-type-arguments.js new file mode 100644 index 0000000..b3b3bdb --- /dev/null +++ b/spec/fixtures/grammar/babel-sublime/flow-function-call-with-type-arguments.js @@ -0,0 +1,295 @@ +// SYNTAX TEST "source.js.jsx" + +new MyInstance(); +// <- meta.new-class.without-arguments.js keyword.operator.new.js + // <- meta.new-class.without-arguments.js keyword.operator.new.js +// ^^^^^^^^^^^^ meta.new-class.without-arguments.js +// ^^^^^^^^^^ entity.name.type.instance.js +// ^^^^^^^^^^ meta.function-call.without-arguments.js +// ^^ meta.brace.round.js +// ^ punctuation.terminator.statement.js + +new MyInstance(); +// <- meta.new-class.without-arguments.js keyword.operator.new.js + // <- meta.new-class.without-arguments.js keyword.operator.new.js +// ^^^^^^^^^^^^^^^^^^^^ meta.new-class.without-arguments.js +// ^^^^^^^^^^ entity.name.type.instance.js +// ^^^^^^^^^^ meta.function-call.without-arguments.js +// ^^^^^^^^ meta.type-arguments.flowtype +// ^ punctuation.flowtype +// ^^^^^^ support.type.builtin.primitive.flowtype +// ^ punctuation.flowtype +// ^^ meta.brace.round.js +// ^ punctuation.terminator.statement.js + +new MyInstance < string > (); +// <- meta.new-class.without-arguments.js keyword.operator.new.js + // <- meta.new-class.without-arguments.js keyword.operator.new.js +// ^^^^^^^^^^^^^^^^^^^^ meta.new-class.without-arguments.js +// ^^^^^^^^^^ entity.name.type.instance.js +// ^^^^^^^^^^ meta.function-call.without-arguments.js +// ^^^^^^^^^^ meta.type-arguments.flowtype +// ^ ^ punctuation.flowtype +// ^^^^^^ support.type.builtin.primitive.flowtype +// ^^ meta.brace.round.js +// ^ punctuation.terminator.statement.js + +new MyInstance, number>(); +// <- meta.new-class.without-arguments.js keyword.operator.new.js + // <- meta.new-class.without-arguments.js keyword.operator.new.js +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.new-class.without-arguments.js +// ^^^^^^^^^^ entity.name.type.instance.js +// ^^^^^^^^^^ meta.function-call.without-arguments.js +// ^^^^^^^^^^^^^^^^^^^^^ meta.type-arguments.flowtype +// ^ ^ punctuation.flowtype +// ^^^ support.type.class.flowtype +// ^ ^ punctuation.flowtype +// ^^^^^^ support.type.builtin.primitive.flowtype +// ^ meta.delimiter.comma.js +// ^^^^^^ support.type.builtin.primitive.flowtype +// ^^ meta.brace.round.js +// ^ punctuation.terminator.statement.js + +new MyInstance("hi"); +// <- meta.new-class.with-arguments.js keyword.operator.new.js + // <- meta.new-class.with-arguments.js keyword.operator.new.js +// ^^^^^^^^^^^^^^^^ meta.new-class.with-arguments.js +// ^^^^^^^^^^ entity.name.type.instance.js +// ^^^^^^^^^^ meta.function-call.with-arguments.js +// ^ meta.brace.round.js +// ^ meta.brace.round.js +// ^ punctuation.terminator.statement.js + +new MyInstance("hi"); +// <- meta.new-class.with-arguments.js keyword.operator.new.js + // <- meta.new-class.with-arguments.js keyword.operator.new.js +// ^^^^^^^^^^^^^^^^^^^^^^^^ meta.new-class.with-arguments.js +// ^^^^^^^^^^ entity.name.type.instance.js +// ^^^^^^^^^^ meta.function-call.with-arguments.js +// ^^^^^^^^ meta.type-arguments.flowtype +// ^ punctuation.flowtype +// ^^^^^^ support.type.builtin.primitive.flowtype +// ^ punctuation.flowtype +// ^ meta.brace.round.js +// ^ meta.brace.round.js +// ^ punctuation.terminator.statement.js + +new MyInstance < string > ("hi"); +// <- meta.new-class.with-arguments.js keyword.operator.new.js + // <- meta.new-class.with-arguments.js keyword.operator.new.js +// ^^^^^^^^^^^^^^^^^^^^^^^^ meta.new-class.with-arguments.js +// ^^^^^^^^^^ entity.name.type.instance.js +// ^^^^^^^^^^ meta.function-call.with-arguments.js +// ^^^^^^^^^^ meta.type-arguments.flowtype +// ^ ^ punctuation.flowtype +// ^^^^^^ support.type.builtin.primitive.flowtype +// ^ ^ meta.brace.round.js +// ^ punctuation.terminator.statement.js + +new MyInstance, number>("hi"); +// <- meta.new-class.with-arguments.js keyword.operator.new.js + // <- meta.new-class.with-arguments.js keyword.operator.new.js +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.new-class.with-arguments.js +// ^^^^^^^^^^ entity.name.type.instance.js +// ^^^^^^^^^^ meta.function-call.with-arguments.js +// ^^^^^^^^^^^^^^^^^^^^^ meta.type-arguments.flowtype +// ^ ^ punctuation.flowtype +// ^^^ support.type.class.flowtype +// ^ ^ punctuation.flowtype +// ^^^^^^ support.type.builtin.primitive.flowtype +// ^ meta.delimiter.comma.js +// ^^^^^^ support.type.builtin.primitive.flowtype +// ^ ^ meta.brace.round.js +// ^ punctuation.terminator.statement.js + +myFunction(); +// <- meta.function-call.without-arguments.js + // <- meta.function-call.without-arguments.js +// ^^^^^^^^ meta.function-call.without-arguments.js +// ^^^^^^ entity.name.function.js +// ^^ meta.brace.round.js +// ^ punctuation.terminator.statement.js + +myFunction(); +// <- meta.function-call.without-arguments.js + // <- meta.function-call.without-arguments.js +// ^^^^^^^^^^^^^^^^ meta.function-call.without-arguments.js +// ^^^^^^ entity.name.function.js +// ^^^^^^ meta.function-call.without-arguments.js +// ^^^^^^^^ meta.type-arguments.flowtype +// ^ punctuation.flowtype +// ^^^^^^ support.type.builtin.primitive.flowtype +// ^ punctuation.flowtype +// ^^ meta.brace.round.js +// ^ punctuation.terminator.statement.js + +myFunction < string > (); +// <- meta.function-call.without-arguments.js + // <- meta.function-call.without-arguments.js +// ^^^^^^^^^^^^^^^^ meta.function-call.without-arguments.js +// ^^^^^^ entity.name.function.js +// ^^^^^^ meta.function-call.without-arguments.js +// ^^^^^^^^^^ meta.type-arguments.flowtype +// ^ ^ punctuation.flowtype +// ^^^^^^ support.type.builtin.primitive.flowtype +// ^^ meta.brace.round.js +// ^ punctuation.terminator.statement.js + +myFunction, number>(); +// <- meta.function-call.without-arguments.js + // <- meta.function-call.without-arguments.js +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function-call.without-arguments.js +// ^^^^^^ entity.name.function.js +// ^^^^^^ meta.function-call.without-arguments.js +// ^^^^^^^^^^^^^^^^^^^^^ meta.type-arguments.flowtype +// ^ ^ punctuation.flowtype +// ^^^ support.type.class.flowtype +// ^ ^ punctuation.flowtype +// ^^^^^^ support.type.builtin.primitive.flowtype +// ^ meta.delimiter.comma.js +// ^^^^^^ support.type.builtin.primitive.flowtype +// ^ punctuation.flowtype +// ^^ meta.brace.round.js +// ^ punctuation.terminator.statement.js + +myObject[myProp](); +// <- meta.function-call.without-arguments.js + // <- meta.function-call.without-arguments.js +// ^^^^^^^^^^^^^^ meta.function-call.without-arguments.js +// ^ ^ meta.brace.square.js +// ^^^^^^ variable.other.readwrite.js +// ^^ meta.brace.round.js +// ^ punctuation.terminator.statement.js + +myObject[myProp](); +// <- meta.function-call.without-arguments.js + // <- meta.function-call.without-arguments.js +// ^^^^^^^^^^^^^^^^^^^^^^ meta.function-call.without-arguments.js +// ^ ^ meta.brace.square.js +// ^^^^^^ variable.other.readwrite.js +// ^ ^ punctuation.flowtype +// ^^^^^^ support.type.builtin.primitive.flowtype +// ^^ meta.brace.round.js +// ^ punctuation.terminator.statement.js + +myObject[myProp] < string > (); +// <- meta.function-call.without-arguments.js + // <- meta.function-call.without-arguments.js +// ^^^^^^^^^^^^^^^^^^^^^^ meta.function-call.without-arguments.js +// ^ ^ meta.brace.square.js +// ^^^^^^ variable.other.readwrite.js +// ^ ^ punctuation.flowtype +// ^^^^^^ support.type.builtin.primitive.flowtype +// ^^ meta.brace.round.js +// ^ punctuation.terminator.statement.js + +myObject[myProp], number>(); +// <- meta.function-call.without-arguments.js + // <- meta.function-call.without-arguments.js +// ^^^^^^^^^^^^^^^^^^^^^^ meta.function-call.without-arguments.js +// ^ ^ meta.brace.square.js +// ^^^^^^ variable.other.readwrite.js +// ^ ^ punctuation.flowtype +// ^^^ support.type.class.flowtype +// ^ ^ punctuation.flowtype +// ^^^^^^ support.type.builtin.primitive.flowtype +// ^ meta.delimiter.comma.js +// ^^^^^^ support.type.builtin.primitive.flowtype +// ^^ meta.brace.round.js +// ^ punctuation.terminator.statement.js + +myFunction("hi"); +// <- meta.function-call.with-arguments.js + // <- meta.function-call.with-arguments.js +// ^^^^^^^^^^^^ meta.function-call.with-arguments.js +// ^^^^^^ entity.name.function.js +// ^ ^ meta.brace.round.js +// ^ punctuation.terminator.statement.js + +myFunction("hi"); +// <- meta.function-call.with-arguments.js + // <- meta.function-call.with-arguments.js +// ^^^^^^^^^^^^^^^^^^^^ meta.function-call.with-arguments.js +// ^^^^^^ entity.name.function.js +// ^ ^ punctuation.flowtype +// ^^^^^^ support.type.builtin.primitive.flowtype +// ^ ^ meta.brace.round.js +// ^ punctuation.terminator.statement.js + +myFunction < string > ("hi"); +// <- meta.function-call.with-arguments.js + // <- meta.function-call.with-arguments.js +// ^^^^^^^^^^^^^^^^^^^^^^^^ meta.function-call.with-arguments.js +// ^^^^^^ entity.name.function.js +// ^ ^ punctuation.flowtype +// ^^^^^^ support.type.builtin.primitive.flowtype +// ^ ^ meta.brace.round.js +// ^ punctuation.terminator.statement.js + +myFunction, string>("hi"); +// <- meta.function-call.with-arguments.js + // <- meta.function-call.with-arguments.js +// ^^^^^^^^^^^^^^^^^^^^ meta.function-call.with-arguments.js +// ^^^^^^ entity.name.function.js +// ^ ^ punctuation.flowtype +// ^^^ support.type.class.flowtype +// ^ ^ punctuation.flowtype +// ^^^^^^ support.type.builtin.primitive.flowtype +// ^ meta.delimiter.comma.js +// ^^^^^^ support.type.builtin.primitive.flowtype +// ^ ^ meta.brace.round.js +// ^ punctuation.terminator.statement.js + +myObject[myProp]("hi"); +// <- meta.function-call.with-arguments.js + // <- meta.function-call.with-arguments.js +// ^^^^^^^^^^^^^^^^^^ meta.function-call.with-arguments.js +// ^ ^ meta.brace.square.js +// ^^^^^^ variable.other.readwrite.js +// ^ ^ meta.brace.round.js +// ^ punctuation.terminator.statement.js + +myObject[myProp]("hi"); +// <- meta.function-call.with-arguments.js + // <- meta.function-call.with-arguments.js +// ^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function-call.with-arguments.js +// ^ ^ meta.brace.square.js +// ^^^^^^ variable.other.readwrite.js +// ^ ^ punctuation.flowtype +// ^^^^^^ support.type.builtin.primitive.flowtype +// ^ ^ meta.brace.round.js +// ^ punctuation.terminator.statement.js + +myObject[myProp] < string > ("hi"); +// <- meta.function-call.with-arguments.js + // <- meta.function-call.with-arguments.js +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function-call.with-arguments.js +// ^ ^ meta.brace.square.js +// ^^^^^^ variable.other.readwrite.js +// ^ ^ punctuation.flowtype +// ^^^^^^ support.type.builtin.primitive.flowtype +// ^ ^ meta.brace.round.js +// ^ punctuation.terminator.statement.js + +myObject[myProp], number>("hi"); +// <- meta.function-call.with-arguments.js + // <- meta.function-call.with-arguments.js +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function-call.with-arguments.js +// ^ ^ meta.brace.square.js +// ^^^^^^ variable.other.readwrite.js +// ^ ^ punctuation.flowtype +// ^^^ support.type.class.flowtype +// ^ ^ punctuation.flowtype +// ^^^^^^ support.type.builtin.primitive.flowtype +// ^ meta.delimiter.comma.js +// ^^^^^^ support.type.builtin.primitive.flowtype +// ^ ^ meta.brace.round.js +// ^ punctuation.terminator.statement.js + +new MyInstance, number>() < 123; +new MyInstance, number>("hi") < 123; +myFunction, number>() < 123; +myObject[myProp], number>() < 123; +myObject, number>("hi") < 123; + +// >> only:(source.js.jsx) diff --git a/spec/grammar-spec.coffee b/spec/grammar-spec.coffee index d604fcb..05dd788 100644 --- a/spec/grammar-spec.coffee +++ b/spec/grammar-spec.coffee @@ -19,6 +19,7 @@ describe 'Grammar', -> # babel-sublime test files grammarTest path.join(__dirname, 'fixtures/grammar/babel-sublime/flow.js') + grammarTest path.join(__dirname, 'fixtures/grammar/babel-sublime/flow-function-call-with-type-arguments.js') grammarTest path.join(__dirname, 'fixtures/grammar/babel-sublime/js-class.js') grammarTest path.join(__dirname, 'fixtures/grammar/babel-sublime/js-functions.js') grammarTest path.join(__dirname, 'fixtures/grammar/babel-sublime/js-symbols.js')