Skip to content

Commit 29c9aab

Browse files
committed
feat(scanner): main markdown features
1 parent 4235a0b commit 29c9aab

File tree

1 file changed

+145
-0
lines changed

1 file changed

+145
-0
lines changed

scanner/scanner.go

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
package scanner
2+
3+
import (
4+
"bufio"
5+
"fmt"
6+
"log"
7+
"os"
8+
)
9+
10+
type Scanner struct {
11+
scan *bufio.Scanner
12+
isAtEnd bool // indicates if EOF is hit
13+
curLine []rune // contains the characters of the current line
14+
curChar rune // contains the character at the linePos of curLine
15+
linePos uint // indicates the scanners position on curLine
16+
line uint // indicates the scanners position in the file
17+
tokens []Token // holds scanned token
18+
}
19+
20+
// Returns a new instance of scanner.Scanner.
21+
// To do so, it opens the file, creates a bufio.Scanner with it, scans the first line and assigns all values in the scanner.Scanner struct accordingly
22+
func NewScanner(fileName string) Scanner {
23+
file, err := os.Open(fileName)
24+
if err != nil {
25+
log.Fatalln("couldn't open file", err)
26+
}
27+
scan := bufio.NewScanner(file)
28+
// get first line
29+
scan.Scan()
30+
31+
firstLine := []rune(scan.Text())
32+
33+
return Scanner{
34+
scan: scan,
35+
curLine: firstLine,
36+
curChar: firstLine[0],
37+
line: 0,
38+
linePos: 0,
39+
}
40+
}
41+
42+
// creates a scanner.Token struct with kind, position, value, line and appends it to the scanner.Scanner.tokens array
43+
func (s *Scanner) addToken(kind TokenKind, value string) {
44+
s.tokens = append(s.tokens, Token{
45+
Pos: s.linePos,
46+
Kind: kind,
47+
Value: value,
48+
Line: s.line,
49+
})
50+
}
51+
52+
// getter for scanner.Scanner.tokens
53+
func (s *Scanner) Tokens() []Token {
54+
return s.tokens
55+
}
56+
57+
// performs a lookup for the Token.Kind value for each token and prints the token values
58+
func (s *Scanner) PrintTokens() {
59+
for _, token := range s.tokens {
60+
fmt.Printf("[ '%s' | %d | %d | '%s' ]\n",
61+
TOKEN_LOOKUP_MAP[token.Kind],
62+
token.Pos,
63+
token.Line,
64+
token.Value,
65+
)
66+
}
67+
}
68+
69+
// getter for scanner.Scanner.isAtEnd
70+
func (s *Scanner) atEnd() bool {
71+
return s.isAtEnd
72+
}
73+
74+
// increments s.linePos by one and assigns the next char to s.curChar
75+
func (s *Scanner) advance() {
76+
if s.linePos+1 >= uint(len(s.curLine)) {
77+
s.curChar = '\n'
78+
s.linePos++
79+
return
80+
}
81+
82+
s.linePos++
83+
s.curChar = s.curLine[s.linePos]
84+
}
85+
86+
// increments s.line by one, assigns the next line to s.curChar and assigns the next char to s.curChar
87+
func (s *Scanner) advanceLine() {
88+
ok := s.scan.Scan()
89+
90+
if s.scan.Err() != nil || !ok {
91+
s.isAtEnd = true
92+
return
93+
}
94+
95+
s.curLine = []rune(s.scan.Text())
96+
s.line++
97+
s.linePos = 0
98+
for len(s.curLine) == 0 {
99+
s.scan.Scan()
100+
s.curLine = []rune(s.scan.Text())
101+
s.line++
102+
}
103+
s.curChar = s.curLine[s.linePos]
104+
}
105+
106+
// parses the file given to the Scanner line by line
107+
func (s *Scanner) Parse() {
108+
for !s.atEnd() {
109+
switch s.curChar {
110+
case '#':
111+
s.addToken(HASH, "")
112+
case '_':
113+
s.addToken(UNDERSCORE, "")
114+
case '*':
115+
s.addToken(STAR, "")
116+
case '\n':
117+
s.addToken(NEWLINE, "")
118+
s.advanceLine()
119+
continue
120+
case '-':
121+
s.addToken(DASH, "")
122+
case '[':
123+
s.addToken(STRAIGHTBRACEOPEN, "")
124+
case ']':
125+
s.addToken(STRAIGHTBRACECLOSE, "")
126+
case '(':
127+
s.addToken(PARENOPEN, "")
128+
case ')':
129+
s.addToken(PARENCLOSE, "")
130+
case '`':
131+
s.addToken(BACKTICK, "")
132+
default:
133+
var res []rune
134+
for s.curChar != '\n' {
135+
res = append(res, s.curChar)
136+
s.advance()
137+
}
138+
s.addToken(TEXT, string(res))
139+
s.addToken(NEWLINE, "")
140+
s.advanceLine()
141+
continue
142+
}
143+
s.advance()
144+
}
145+
}

0 commit comments

Comments
 (0)