Add keywords, strings, comments, and better output to Script
This commit is contained in:
parent
ebfa4528e0
commit
181334c028
120
Script/main.go
120
Script/main.go
|
|
@ -24,14 +24,28 @@ const (
|
||||||
// Literals
|
// Literals
|
||||||
IDENTIFIER = "IDENTIFIER"
|
IDENTIFIER = "IDENTIFIER"
|
||||||
NUMBER = "NUMBER"
|
NUMBER = "NUMBER"
|
||||||
|
COMMENT = "COMMENT"
|
||||||
|
STRING = "STRING"
|
||||||
|
KEYWORD = "KEYWORD"
|
||||||
|
|
||||||
// Operators
|
// Operators
|
||||||
EQUALS = "EQUALS"
|
EQUALS = "EQUALS"
|
||||||
|
|
||||||
// that's all for now
|
// OPEN_BRACE = "OPEN_BRACE"
|
||||||
|
// CLOSE_BRACE = "CLOSE_BRACE"
|
||||||
)
|
)
|
||||||
|
|
||||||
func lex(source string) []token {
|
func lex(source string) []token {
|
||||||
|
keywords := map[string]bool{
|
||||||
|
"if": true,
|
||||||
|
"elseif": true,
|
||||||
|
"else": true,
|
||||||
|
"loop": true,
|
||||||
|
"for": true,
|
||||||
|
"break": true,
|
||||||
|
"continue": true,
|
||||||
|
}
|
||||||
|
|
||||||
var tokens []token
|
var tokens []token
|
||||||
|
|
||||||
last := func(n int) token {
|
last := func(n int) token {
|
||||||
|
|
@ -39,10 +53,20 @@ func lex(source string) []token {
|
||||||
}
|
}
|
||||||
line := 1
|
line := 1
|
||||||
column := 0
|
column := 0
|
||||||
addToken := func(kind string, value string) {
|
|
||||||
tokens = append(tokens, token{line, column, kind, value})
|
addToken := func(kind string, value string, linecol ...int) {
|
||||||
|
currentLine := line
|
||||||
|
currentColumn := column
|
||||||
|
if len(linecol) > 0 {
|
||||||
|
currentLine = linecol[0]
|
||||||
|
}
|
||||||
|
if len(linecol) > 1 {
|
||||||
|
currentColumn = linecol[1]
|
||||||
|
}
|
||||||
|
tokens = append(tokens, token{currentLine, currentColumn, kind, value})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ParseLoop:
|
||||||
for i := 0; i < len(source); i++ {
|
for i := 0; i < len(source); i++ {
|
||||||
char := source[i]
|
char := source[i]
|
||||||
column++
|
column++
|
||||||
|
|
@ -56,39 +80,86 @@ func lex(source string) []token {
|
||||||
case ' ':
|
case ' ':
|
||||||
addToken(SPACE, " ")
|
addToken(SPACE, " ")
|
||||||
case '\t':
|
case '\t':
|
||||||
if len(tokens) == 0 {
|
|
||||||
fmt.Println(c.InRed("error bruh"))
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
// only if last token is a newline or an indent
|
// only if last token is a newline or an indent
|
||||||
if last(1).kind == NEWLINE || last(1).kind == INDENT {
|
if last(1).kind == NEWLINE || last(1).kind == INDENT {
|
||||||
addToken(INDENT, "\t")
|
addToken(INDENT, "\t")
|
||||||
|
column += 3
|
||||||
} else {
|
} else {
|
||||||
addToken(SPACE, "\t")
|
addToken(SPACE, "\t")
|
||||||
}
|
}
|
||||||
|
case ';':
|
||||||
|
// parse till end of line
|
||||||
|
startColumn := column
|
||||||
|
i++ // skip the semicolon
|
||||||
|
var comment string
|
||||||
|
for i < len(source) && source[i] != '\n' {
|
||||||
|
comment += string(source[i])
|
||||||
|
column++
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
column--
|
||||||
|
i--
|
||||||
|
addToken(COMMENT, comment, line, startColumn)
|
||||||
|
case '"':
|
||||||
|
startLine := line
|
||||||
|
startColumn := column
|
||||||
|
|
||||||
|
var stringLiteral string
|
||||||
|
|
||||||
|
column++
|
||||||
|
i++ // skip the first quote
|
||||||
|
for i < len(source) && source[i] != '"' {
|
||||||
|
stringLiteral += string(source[i])
|
||||||
|
column++
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
addToken(STRING, stringLiteral, startLine, startColumn)
|
||||||
default:
|
default:
|
||||||
if char >= '0' && char <= '9' {
|
if char >= '0' && char <= '9' {
|
||||||
// keep going until we hit a non-number
|
startLine := line
|
||||||
|
startColumn := column
|
||||||
|
|
||||||
var number string
|
var number string
|
||||||
|
|
||||||
|
// keep going until we hit a non-number
|
||||||
for i < len(source) && source[i] >= '0' && source[i] <= '9' {
|
for i < len(source) && source[i] >= '0' && source[i] <= '9' {
|
||||||
number += string(source[i])
|
number += string(source[i])
|
||||||
column++
|
column++
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
column--
|
||||||
i--
|
i--
|
||||||
addToken(NUMBER, number)
|
addToken(NUMBER, number, startLine, startColumn)
|
||||||
} else if char >= 'a' && char <= 'z' || char >= 'A' && char <= 'Z' {
|
} else if char >= 'a' && char <= 'z' || char >= 'A' && char <= 'Z' {
|
||||||
|
startLine := line
|
||||||
|
startColumn := column
|
||||||
// keep going until we hit a non-letter
|
// keep going until we hit a non-letter
|
||||||
var identifier string
|
var identifierOrKeyword string
|
||||||
for i < len(source) && source[i] >= 'a' && source[i] <= 'z' || source[i] >= 'A' && source[i] <= 'Z' {
|
|
||||||
identifier += string(source[i])
|
for i < len(source) && (source[i] >= 'a' && source[i] <= 'z' || source[i] >= 'A' && source[i] <= 'Z') {
|
||||||
|
identifierOrKeyword += string(source[i])
|
||||||
column++
|
column++
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
column--
|
||||||
i--
|
i--
|
||||||
addToken(IDENTIFIER, identifier)
|
|
||||||
|
// check if it's a keyword
|
||||||
|
if keywords[identifierOrKeyword] {
|
||||||
|
addToken(KEYWORD, identifierOrKeyword, startLine, startColumn)
|
||||||
|
continue ParseLoop
|
||||||
|
}
|
||||||
|
|
||||||
|
if i == len(source) {
|
||||||
|
// you can't end a program with an identifier (yet)
|
||||||
|
fmt.Println(c.InRed("cant end program with identifier"))
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
addToken(IDENTIFIER, identifierOrKeyword, startLine, startColumn)
|
||||||
} else {
|
} else {
|
||||||
fmt.Println(c.InRed("error bruh"))
|
fmt.Println(c.InRed("that isnt a valid character"), c.InYellow(string(char)))
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -125,12 +196,23 @@ func main() {
|
||||||
sourceString := strings.Replace(string(source), "\r\n", "\n", -1)
|
sourceString := strings.Replace(string(source), "\r\n", "\n", -1)
|
||||||
|
|
||||||
tokens := lex(sourceString)
|
tokens := lex(sourceString)
|
||||||
// ast := parse(tokens)
|
// out := generate(tokens)
|
||||||
// out := generate(ast)
|
|
||||||
|
|
||||||
for _, token := range tokens {
|
for _, token := range tokens {
|
||||||
fmt.Printf("%d:%d %s %s\n", token.line, token.column, c.InYellow(token.kind), c.InGreen(token.value))
|
if token.kind == "SPACE" {
|
||||||
}
|
continue
|
||||||
|
}
|
||||||
|
if token.kind == "NEWLINE" {
|
||||||
|
fmt.Println("──────┼─────────────┼─────────────────────────────")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
toPrint := []string{
|
||||||
|
fmt.Sprintf("%d:%d", token.line, token.column),
|
||||||
|
c.InYellow(token.kind),
|
||||||
|
c.InPurple(token.value),
|
||||||
|
}
|
||||||
|
|
||||||
fmt.Println("success")
|
// print in a nice format
|
||||||
|
fmt.Printf("%-5s │ %-20s │ %s\n", toPrint[0], toPrint[1], toPrint[2])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
x = 1 ; comments with semicolons
|
||||||
|
|
||||||
|
print "x is {x}" ; %x?
|
||||||
|
print "double x is {2x}"
|
||||||
|
if x is 1
|
||||||
|
print "x is equal to 1" ; here we go
|
||||||
|
elseif x
|
||||||
|
print "x is truthy"
|
||||||
|
else
|
||||||
|
print "x is falsy"
|
||||||
|
|
||||||
|
loop
|
||||||
|
print "infinite loop"
|
||||||
|
print "just kidding"
|
||||||
|
break
|
||||||
Loading…
Reference in New Issue