partial ast
This commit is contained in:
parent
fc5f2f1172
commit
7e49d405f5
4 changed files with 135 additions and 44 deletions
7
.vscode/launch.json
vendored
Normal file
7
.vscode/launch.json
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": []
|
||||||
|
}
|
5
.vscode/settings.json
vendored
Normal file
5
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"cSpell.words": [
|
||||||
|
"glox"
|
||||||
|
]
|
||||||
|
}
|
3
README.md
Normal file
3
README.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# GLOX
|
||||||
|
|
||||||
|
Lox interpreter written i Go.
|
164
glox.go
164
glox.go
|
@ -7,23 +7,72 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"unicode"
|
"unicode"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
switch len(os.Args) {
|
expr := &Binary{
|
||||||
case 1:
|
left: &Literal{value: 1},
|
||||||
runPrompt()
|
op: Token{typ: PLUS, lexeme: "+", literal: "", line: 1},
|
||||||
case 2:
|
right: &Binary{
|
||||||
runFile(os.Args[1])
|
left: &Literal{value: 3},
|
||||||
default:
|
op: Token{typ: PLUS, lexeme: "+", literal: "", line: 1},
|
||||||
println("Usage: glox [file]")
|
right: &Literal{value: 4},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
println((&AstStringer{}).String(expr))
|
||||||
|
|
||||||
|
// switch len(os.Args) {
|
||||||
|
// case 1:
|
||||||
|
// runPrompt()
|
||||||
|
// case 2:
|
||||||
|
// runFile(os.Args[1])
|
||||||
|
// default:
|
||||||
|
// println("Usage: glox [file]")
|
||||||
|
// os.Exit(1)
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
func runPrompt() {
|
||||||
|
scanner := bufio.NewScanner(os.Stdin)
|
||||||
|
scanner.Split(bufio.ScanLines)
|
||||||
|
|
||||||
|
for {
|
||||||
|
print("> ")
|
||||||
|
scanner.Scan()
|
||||||
|
line := scanner.Text()
|
||||||
|
if len(line) == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
run([]byte(scanner.Text()))
|
||||||
|
hadError = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func runFile(path string) {
|
||||||
|
file, err := os.ReadFile(path)
|
||||||
|
|
||||||
|
panic(err)
|
||||||
|
|
||||||
|
run(file)
|
||||||
|
|
||||||
|
if hadError {
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func run(source []byte) {
|
||||||
|
tokens := newScanner(source).scan()
|
||||||
|
|
||||||
|
for _, token := range tokens {
|
||||||
|
println(token.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var hadError = false
|
var hadError = false
|
||||||
|
|
||||||
//go:generate go run golang.org/x/tools/cmd/stringer -type=TokenType
|
//go:generate go run golang.org/x/tools/cmd/stringer -type=TokenType
|
||||||
|
@ -98,6 +147,69 @@ var keywords = map[string]TokenType{
|
||||||
"while": WHILE,
|
"while": WHILE,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Expr interface {
|
||||||
|
expr()
|
||||||
|
accept(v Visitor)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Unary struct {
|
||||||
|
op Token
|
||||||
|
right Expr
|
||||||
|
}
|
||||||
|
|
||||||
|
type Grouping struct {
|
||||||
|
expr Expr
|
||||||
|
}
|
||||||
|
|
||||||
|
type Literal struct {
|
||||||
|
value any
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Literal) expr() {}
|
||||||
|
func (l *Literal) accept(v Visitor) {
|
||||||
|
v.visitLiteral(l)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Binary struct {
|
||||||
|
left Expr
|
||||||
|
op Token
|
||||||
|
right Expr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Binary) expr() {}
|
||||||
|
func (b *Binary) accept(v Visitor) {
|
||||||
|
v.visitBinary(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Visitor interface {
|
||||||
|
visitBinary(b *Binary)
|
||||||
|
visitLiteral(l *Literal)
|
||||||
|
}
|
||||||
|
|
||||||
|
type AstStringer struct {
|
||||||
|
str strings.Builder
|
||||||
|
}
|
||||||
|
|
||||||
|
func (as *AstStringer) String(expr Expr) string {
|
||||||
|
expr.accept(as)
|
||||||
|
return as.str.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (as *AstStringer) visitBinary(b *Binary) {
|
||||||
|
as.str.WriteString("(")
|
||||||
|
as.str.WriteString(b.op.lexeme)
|
||||||
|
as.str.WriteString(" ")
|
||||||
|
b.left.accept(as)
|
||||||
|
as.str.WriteString(" ")
|
||||||
|
b.right.accept(as)
|
||||||
|
as.str.WriteString(")")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (as *AstStringer) visitLiteral(l *Literal) {
|
||||||
|
as.str.WriteString(fmt.Sprintf("%v", l.value))
|
||||||
|
}
|
||||||
|
|
||||||
type Token struct {
|
type Token struct {
|
||||||
typ TokenType
|
typ TokenType
|
||||||
lexeme string
|
lexeme string
|
||||||
|
@ -105,7 +217,7 @@ type Token struct {
|
||||||
line int
|
line int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Token) string() string {
|
func (t *Token) String() string {
|
||||||
return fmt.Sprintf("%s - %s - %v", t.typ, t.lexeme, t.literal)
|
return fmt.Sprintf("%s - %s - %v", t.typ, t.lexeme, t.literal)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -322,39 +434,3 @@ func panic(err error) {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func runPrompt() {
|
|
||||||
scanner := bufio.NewScanner(os.Stdin)
|
|
||||||
scanner.Split(bufio.ScanLines)
|
|
||||||
|
|
||||||
for {
|
|
||||||
print("> ")
|
|
||||||
scanner.Scan()
|
|
||||||
line := scanner.Text()
|
|
||||||
if len(line) == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
run([]byte(scanner.Text()))
|
|
||||||
hadError = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func runFile(path string) {
|
|
||||||
file, err := os.ReadFile(path)
|
|
||||||
|
|
||||||
panic(err)
|
|
||||||
|
|
||||||
run(file)
|
|
||||||
|
|
||||||
if hadError {
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func run(source []byte) {
|
|
||||||
tokens := newScanner(source).scan()
|
|
||||||
|
|
||||||
for _, token := range tokens {
|
|
||||||
println(token.string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue