Starting Zig code generator with one test
This commit is contained in:
parent
bdf7ea85d3
commit
0bf8c3ef6b
2
Makefile
2
Makefile
@ -1,2 +1,2 @@
|
|||||||
run:
|
run:
|
||||||
go run internal/main.go -o hello.zig programs/hello.go
|
go run internal/main.go -o hello.zig programs/hello.go && zig run hello.zig
|
50
internal/zig/ast.go
Normal file
50
internal/zig/ast.go
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package zig
|
||||||
|
|
||||||
|
// https://github.com/ziglang/zig-spec/blob/master/grammar/grammar.peg
|
||||||
|
|
||||||
|
type Root struct {
|
||||||
|
ContainerDocComment string // //! Doc Comment
|
||||||
|
ContainerMembers []*ContainerMember
|
||||||
|
}
|
||||||
|
|
||||||
|
type ContainerMember struct {
|
||||||
|
// FIXME
|
||||||
|
Decls []Decl
|
||||||
|
}
|
||||||
|
|
||||||
|
type Decl interface{}
|
||||||
|
|
||||||
|
type FnDecl struct {
|
||||||
|
Name string
|
||||||
|
Params []*ParamDecl
|
||||||
|
CallConv string
|
||||||
|
ReturnType TypeExpr
|
||||||
|
Body *Block // nil means semicolon
|
||||||
|
}
|
||||||
|
|
||||||
|
type ParamDecl struct {
|
||||||
|
DocComment string // ??? It's what it says
|
||||||
|
Name string // Can be empty
|
||||||
|
Type TypeExpr // anytype when empty
|
||||||
|
}
|
||||||
|
|
||||||
|
type Block struct {
|
||||||
|
Label string
|
||||||
|
Stmts []Stmt
|
||||||
|
}
|
||||||
|
|
||||||
|
type Stmt interface{}
|
||||||
|
|
||||||
|
type ReturnStmt struct{}
|
||||||
|
|
||||||
|
type Expr interface{}
|
||||||
|
|
||||||
|
// This will need to become a real type expr someday
|
||||||
|
type TypeExpr string
|
||||||
|
|
||||||
|
func (t TypeExpr) String() string {
|
||||||
|
if string(t) == "" {
|
||||||
|
return "anytype"
|
||||||
|
}
|
||||||
|
return string(t)
|
||||||
|
}
|
108
internal/zig/zig.go
Normal file
108
internal/zig/zig.go
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
package zig
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
type formatter struct {
|
||||||
|
w io.Writer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *formatter) WriteString(s string) (n int, err error) {
|
||||||
|
return f.w.Write([]byte(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *formatter) Writef(format string, a ...any) (err error) {
|
||||||
|
_, err = f.w.Write(fmt.Appendf(nil, format, a...))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func Write(w io.Writer, root *Root) error {
|
||||||
|
f := &formatter{
|
||||||
|
w: w,
|
||||||
|
}
|
||||||
|
|
||||||
|
if root.ContainerDocComment != "" {
|
||||||
|
err := f.Writef("//! %s\n\n", root.ContainerDocComment)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, member := range root.ContainerMembers {
|
||||||
|
for _, decl := range member.Decls {
|
||||||
|
if err := writeDecl(f, decl); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeDecl(f *formatter, decl Decl) (err error) {
|
||||||
|
switch typ := decl.(type) {
|
||||||
|
case *FnDecl:
|
||||||
|
if err = f.Writef("fn %s(", typ.Name); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = writeParams(f, typ.Params); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = f.Writef(") %s", typ.ReturnType); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = writeBlock(f, typ.Body); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeParams(f *formatter, params []*ParamDecl) (err error) {
|
||||||
|
for _, param := range params {
|
||||||
|
if param.Name != "" {
|
||||||
|
if err = f.Writef("%s: ", param.Name); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err = f.Writef("%s", param.Type); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeBlock(f *formatter, block *Block) (err error) {
|
||||||
|
if block == nil {
|
||||||
|
if _, err = f.WriteString(";"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if err = f.Writef(" {\n"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, stmt := range block.Stmts {
|
||||||
|
if err = writeStmt(f, stmt); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Should this be the job of the formatter?
|
||||||
|
if _, err = f.WriteString("\n"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err = f.Writef("}\n"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeStmt(f *formatter, stmt Stmt) (err error) {
|
||||||
|
switch stmt.(type) {
|
||||||
|
case *ReturnStmt:
|
||||||
|
if _, err = f.WriteString("return;"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
55
internal/zig/zig_test.go
Normal file
55
internal/zig/zig_test.go
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
package zig_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cmp"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"git.frop.prof/luke/go-zig-compiler/internal/zig"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Expect[T cmp.Ordered](expected, actual T) error {
|
||||||
|
if expected != actual {
|
||||||
|
return fmt.Errorf("\nExpected: %v\nActual: %v", expected, actual)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHelloWorld(t *testing.T) {
|
||||||
|
expected := `//! Hello, world!
|
||||||
|
|
||||||
|
fn main() void {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
root := &zig.Root{
|
||||||
|
ContainerDocComment: "Hello, world!",
|
||||||
|
ContainerMembers: []*zig.ContainerMember{
|
||||||
|
{
|
||||||
|
Decls: []zig.Decl{
|
||||||
|
&zig.FnDecl{
|
||||||
|
Name: "main",
|
||||||
|
ReturnType: "void",
|
||||||
|
Body: &zig.Block{
|
||||||
|
Stmts: []zig.Stmt{
|
||||||
|
&zig.ReturnStmt{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
sb := new(strings.Builder)
|
||||||
|
err := zig.Write(sb, root)
|
||||||
|
if err != nil {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
actual := sb.String()
|
||||||
|
|
||||||
|
if err = Expect(expected, actual); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user