137 lines
2.8 KiB
Go
137 lines
2.8 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
|
|
c "github.com/TwiN/go-color"
|
|
)
|
|
|
|
type token struct {
|
|
line int
|
|
column int
|
|
kind string
|
|
value string
|
|
}
|
|
|
|
const (
|
|
EOF = "EOF"
|
|
INDENT = "INDENT"
|
|
SPACE = "SPACE"
|
|
NEWLINE = "NEWLINE"
|
|
|
|
// Literals
|
|
IDENTIFIER = "IDENTIFIER"
|
|
NUMBER = "NUMBER"
|
|
|
|
// Operators
|
|
EQUALS = "EQUALS"
|
|
|
|
// that's all for now
|
|
)
|
|
|
|
func lex(source string) []token {
|
|
var tokens []token
|
|
|
|
last := func(n int) token {
|
|
return tokens[len(tokens)-n]
|
|
}
|
|
line := 1
|
|
column := 0
|
|
addToken := func(kind string, value string) {
|
|
tokens = append(tokens, token{line, column, kind, value})
|
|
}
|
|
|
|
for i := 0; i < len(source); i++ {
|
|
char := source[i]
|
|
column++
|
|
switch char {
|
|
case '=':
|
|
addToken(EQUALS, "=")
|
|
case '\n':
|
|
addToken(NEWLINE, "\n")
|
|
line++
|
|
column = 0
|
|
case ' ':
|
|
addToken(SPACE, " ")
|
|
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
|
|
if last(1).kind == NEWLINE || last(1).kind == INDENT {
|
|
addToken(INDENT, "\t")
|
|
} else {
|
|
addToken(SPACE, "\t")
|
|
}
|
|
default:
|
|
if char >= '0' && char <= '9' {
|
|
// keep going until we hit a non-number
|
|
var number string
|
|
for i < len(source) && source[i] >= '0' && source[i] <= '9' {
|
|
number += string(source[i])
|
|
column++
|
|
i++
|
|
}
|
|
i--
|
|
addToken(NUMBER, number)
|
|
} else if char >= 'a' && char <= 'z' || char >= 'A' && char <= 'Z' {
|
|
// keep going until we hit a non-letter
|
|
var identifier string
|
|
for i < len(source) && source[i] >= 'a' && source[i] <= 'z' || source[i] >= 'A' && source[i] <= 'Z' {
|
|
identifier += string(source[i])
|
|
column++
|
|
i++
|
|
}
|
|
i--
|
|
addToken(IDENTIFIER, identifier)
|
|
} else {
|
|
fmt.Println(c.InRed("error bruh"))
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
}
|
|
|
|
return tokens
|
|
}
|
|
|
|
func main() {
|
|
if len(os.Args) < 2 {
|
|
fmt.Println(c.InRed("No target file specified!"))
|
|
fmt.Println(c.InBlue("Run 'melt-script help' for more information."))
|
|
os.Exit(1)
|
|
}
|
|
target := os.Args[1]
|
|
|
|
fi, err := os.Stat(target)
|
|
if err != nil {
|
|
fmt.Println(c.InRed("Target file ") + c.InUnderline(c.InPurple(target)) + c.InRed(" does not exist!"))
|
|
os.Exit(1)
|
|
}
|
|
if fi.IsDir() {
|
|
fmt.Println(c.InUnderline(c.InPurple(target)) + c.InRed(" is a directory, please choose a file to compile!"))
|
|
os.Exit(1)
|
|
}
|
|
|
|
source, err := os.ReadFile(target)
|
|
if err != nil {
|
|
fmt.Println(c.InRed("Failed to read target file ") + c.InUnderline(c.InPurple(target)) + c.InRed("!"))
|
|
os.Exit(1)
|
|
}
|
|
|
|
// replace \r\n with \n
|
|
sourceString := strings.Replace(string(source), "\r\n", "\n", -1)
|
|
|
|
tokens := lex(sourceString)
|
|
// ast := parse(tokens)
|
|
// out := generate(ast)
|
|
|
|
for _, token := range tokens {
|
|
fmt.Printf("%d:%d %s %s\n", token.line, token.column, c.InYellow(token.kind), c.InGreen(token.value))
|
|
}
|
|
|
|
fmt.Println("success")
|
|
}
|