Skip to content

Commit

Permalink
Add vb.net dependency parser
Browse files Browse the repository at this point in the history
  • Loading branch information
gandarez committed Dec 31, 2020
1 parent 417cd9f commit 96579a0
Show file tree
Hide file tree
Showing 6 changed files with 200 additions and 0 deletions.
2 changes: 2 additions & 0 deletions pkg/deps/deps.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ func Detect(filepath string, language heartbeat.Language) ([]string, error) {
parser = &ParserScala{}
case heartbeat.LanguageSwift:
parser = &ParserSwift{}
case heartbeat.LanguageVBNet:
parser = &ParserVbNet{}
default:
jww.DEBUG.Printf("parsing dependencies not supported for language %q", language)
return nil, nil
Expand Down
5 changes: 5 additions & 0 deletions pkg/deps/deps_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,11 @@ func TestDetect(t *testing.T) {
Language: heartbeat.LanguageSwift,
Dependencies: []string{"Swift"},
},
"vb.net": {
Filepath: "testdata/vbnet_minimal.vb",
Language: heartbeat.LanguageVBNet,
Dependencies: []string{"WakaTime"},
},
}

for name, test := range tests {
Expand Down
14 changes: 14 additions & 0 deletions pkg/deps/testdata/vbnet.vb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
Imports System
Imports System.Diagnostics
Imports System.IO
Imports System.Net
Imports Microsoft.Win32
Imports WakaTime.Forms
Imports mat = Math.Foo
Imports pr = Proper.Bar

Module Program
Sub Main(args As String())
Console.WriteLine("Hello World")
End Sub
End Module
8 changes: 8 additions & 0 deletions pkg/deps/testdata/vbnet_minimal.vb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Imports System
Imports WakaTime.Forms

Module Program
Sub Main(args As String())
Console.WriteLine("Hello World")
End Sub
End Module
148 changes: 148 additions & 0 deletions pkg/deps/vbnet.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
package deps

import (
"fmt"
"io/ioutil"
"os"
"regexp"
"strings"

"github.com/alecthomas/chroma"
"github.com/alecthomas/chroma/lexers/v"
)

var vbnetExcludeRegex = regexp.MustCompile(`(?i)^(system|microsoft)$`)

// StateVbNet is a token parsing state.
type StateVbNet int

const (
// StateVbNetUnknown represents a unknown token parsing state.
StateVbNetUnknown StateVbNet = iota
// StateVbNetImport means we are in import section during token parsing.
StateVbNetImport
)

// ParserVbNet is a dependency parser for the vb.net programming language.
// It is not thread safe.
type ParserVbNet struct {
State StateVbNet
Buffer string
Output []string
}

// Parse parses dependencies from VB.Net file content using the chroma VB.Net lexer.
func (p *ParserVbNet) Parse(filepath string) ([]string, error) {
reader, err := os.Open(filepath)
if err != nil {
return nil, fmt.Errorf("failed to open file %q: %s", filepath, err)
}

defer reader.Close()

p.init()
defer p.init()

data, err := ioutil.ReadAll(reader)
if err != nil {
return nil, fmt.Errorf("failed to read from reader: %s", err)
}

iter, err := v.VBNet.Tokenise(nil, string(data))
if err != nil {
return nil, fmt.Errorf("failed to tokenize file content: %s", err)
}

for _, token := range iter.Tokens() {
p.processToken(token)
}

return p.Output, nil
}

func (p *ParserVbNet) append(dep string) {
dep = strings.TrimSpace(strings.Split(dep, ".")[0])

if len(dep) == 0 {
return
}

if vbnetExcludeRegex.MatchString(dep) {
return
}

p.Output = append(p.Output, dep)
}

func (p *ParserVbNet) init() {
p.Buffer = ""
p.Output = nil
p.State = StateVbNetUnknown
}

func (p *ParserVbNet) processToken(token chroma.Token) {
switch token.Type {
case chroma.Keyword:
p.processKeyword(token.Value)
case chroma.Name, chroma.NameNamespace:
p.processName(token.Value)
case chroma.Operator:
p.processOperator(token.Value)
case chroma.Punctuation:
p.processPunctuation(token.Value)
case chroma.Text:
p.processText(token.Value)
}
}

func (p *ParserVbNet) processKeyword(value string) {
if value == "Imports" {
p.State = StateVbNetImport
p.Buffer = ""
}
}

func (p *ParserVbNet) processName(value string) {
if p.State != StateVbNetImport {
return
}

if value == "." {
p.processPunctuation(value)
return
}

p.Buffer += value
}

func (p *ParserVbNet) processPunctuation(value string) {
if p.State != StateVbNetImport {
return
}

if value == "." {
p.Buffer += value
}
}

func (p *ParserVbNet) processOperator(value string) {
if p.State != StateVbNetImport {
return
}

if value == "=" {
p.Buffer = ""
}
}

func (p *ParserVbNet) processText(value string) {
if p.State != StateVbNetImport {
return
}

if value == "\n" {
p.append(p.Buffer)
p.State = StateVbNetUnknown
p.Buffer = ""
}
}
23 changes: 23 additions & 0 deletions pkg/deps/vbnet_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package deps_test

import (
"testing"

"github.com/wakatime/wakatime-cli/pkg/deps"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestParserVbNet_Parse(t *testing.T) {
parser := deps.ParserVbNet{}

dependencies, err := parser.Parse("testdata/vbnet.vb")
require.NoError(t, err)

assert.Equal(t, []string{
"WakaTime",
"Math",
"Proper",
}, dependencies)
}

0 comments on commit 96579a0

Please sign in to comment.