mirror of
https://github.com/atom/atom.git
synced 2026-04-06 03:02:13 -04:00
TextMate parser can parse single plain tokens / tokens with captures
This commit is contained in:
@@ -12,7 +12,23 @@ describe "Parser", ->
|
||||
|
||||
describe ".getLineTokens(line, state)", ->
|
||||
describe "when the state is omitted (start state)", ->
|
||||
describe "when line matches a single pattern with no capture groups", ->
|
||||
fit "returns a single token with the correct scope", ->
|
||||
describe "when the entire line matches a single pattern with no capture groups", ->
|
||||
it "returns a single token with the correct scope", ->
|
||||
{tokens, state} = parser.getLineTokens("return")
|
||||
|
||||
console.log tokens
|
||||
|
||||
expect(tokens.length).toBe 1
|
||||
[token] = tokens
|
||||
expect(token.scopes).toEqual ['source.coffee', 'keyword.control.coffee']
|
||||
|
||||
describe "when the entire line matches a single pattern with capture groups", ->
|
||||
it "returns a single token with the correct scope", ->
|
||||
{tokens, state} = parser.getLineTokens("new foo.bar.Baz")
|
||||
|
||||
expect(tokens.length).toBe 3
|
||||
[newOperator, whitespace, className] = tokens
|
||||
expect(newOperator).toEqual value: 'new', scopes: ['source.coffee', 'meta.class.instance.constructor', 'keyword.operator.new.coffee']
|
||||
expect(whitespace).toEqual value: ' ', scopes: ['source.coffee', 'meta.class.instance.constructor']
|
||||
expect(className).toEqual value: 'foo.bar.Baz', scopes: ['source.coffee', 'meta.class.instance.constructor', 'entity.name.type.instance.coffee']
|
||||
|
||||
|
||||
@@ -1,20 +1,56 @@
|
||||
_ = require 'underscore'
|
||||
|
||||
module.exports =
|
||||
class Parser
|
||||
constructor: (@grammar) ->
|
||||
|
||||
getLineTokens: (line, state=@getStartState()) ->
|
||||
getLineTokens: (line, stateStack=@initialStateStack()) ->
|
||||
tokens = []
|
||||
currentScopes = _.pluck(stateStack, 'scopeName')
|
||||
state = _.last(stateStack)
|
||||
|
||||
getStartState: ->
|
||||
console.log @grammar
|
||||
bestMatch = { index: Infinity }
|
||||
bestPattern = null
|
||||
for pattern in state.patterns
|
||||
if match = pattern.match.search(line)
|
||||
if match.index < bestMatch.index
|
||||
bestMatch = match
|
||||
bestPattern = pattern
|
||||
|
||||
if bestPattern
|
||||
currentScopes = currentScopes.concat(bestPattern.name)
|
||||
|
||||
if captures = bestPattern.captures
|
||||
endOfLastCapture = 0
|
||||
for captureIndex in _.keys(captures)
|
||||
captureStartPosition = bestMatch.indices[captureIndex]
|
||||
captureText = bestMatch[captureIndex]
|
||||
captureScopeName = captures[captureIndex].name
|
||||
|
||||
if endOfLastCapture < captureStartPosition
|
||||
tokens.push
|
||||
value: bestMatch[0][endOfLastCapture...captureStartPosition]
|
||||
scopes: currentScopes
|
||||
|
||||
tokens.push
|
||||
value: captureText
|
||||
scopes: currentScopes.concat(captureScopeName)
|
||||
|
||||
endOfLastCapture = captureStartPosition + captureText.length
|
||||
else
|
||||
tokens.push
|
||||
value: bestMatch[0]
|
||||
scopes: currentScopes
|
||||
|
||||
{ state, tokens }
|
||||
|
||||
initialStateStack: ->
|
||||
[new ParserState(@grammar)]
|
||||
|
||||
class ParserState
|
||||
scopeName: null
|
||||
patterns: null
|
||||
|
||||
constructor: ({@scopeName, patterns}) ->
|
||||
|
||||
@patterns = patterns.map (pattern) ->
|
||||
console.log pattern.match
|
||||
|
||||
#matchcount = new RegExp("(?:(" + state[i].regex + ")|(.))").exec("a").length - 2;
|
||||
constructor: ({@scopeName, @patterns}) ->
|
||||
for pattern in @patterns
|
||||
pattern.match = new OnigRegExp(pattern.match)
|
||||
Reference in New Issue
Block a user