TextMate parser can parse single plain tokens / tokens with captures

This commit is contained in:
Corey Johnson & Nathan Sobo
2012-07-30 18:23:18 -06:00
parent 757258dd98
commit a2a58a3506
2 changed files with 63 additions and 11 deletions

View File

@@ -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']

View File

@@ -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)