Browse Source

развитие ast

kpmy 9 years ago
parent
commit
0225d49d66
7 changed files with 347 additions and 11 deletions
  1. 19 0
      README.md
  2. 5 1
      gen/generator.go
  3. 2 2
      gen/impl/impl.go
  4. 48 7
      gen/impl/sexpr/sexpr.go
  5. 171 0
      ir/ast.go
  6. 69 0
      ir/code.go
  7. 33 1
      tiss_test.go

+ 19 - 0
README.md

@@ -3,3 +3,22 @@
 For the good.
 For the good.
 
 
 * [wasm specs](https://github.com/WebAssembly/spec/tree/master/ml-proto)
 * [wasm specs](https://github.com/WebAssembly/spec/tree/master/ml-proto)
+
+````
+;; golang wasm generator github.com/kpmy/tiss
+(module
+	(type $t0
+		(func))
+	(func $fib
+		(param $x i64)
+		(result i64)
+		(local $i i64)
+		(return
+			(i64.const 0)))
+	(func $start
+		(type $t0)
+		(call $fib
+			(i64.const 0)))
+	(start $start))
+````
+**not so pretty :(*

+ 5 - 1
gen/generator.go

@@ -11,4 +11,8 @@ type Writer interface {
 	WriteValue(interface{}) error
 	WriteValue(interface{}) error
 }
 }
 
 
-var NewWriter func(io.Writer) Writer
+type Opts struct {
+	PrettyPrint bool
+}
+
+var NewWriter func(io.Writer, ...Opts) Writer

+ 2 - 2
gen/impl/impl.go

@@ -8,7 +8,7 @@ import (
 )
 )
 
 
 func init() {
 func init() {
-	gen.NewWriter = func(w io.Writer) gen.Writer {
-		return sexpr.New(w)
+	gen.NewWriter = func(w io.Writer, o ...gen.Opts) gen.Writer {
+		return sexpr.New(w, o...)
 	}
 	}
 }
 }

+ 48 - 7
gen/impl/sexpr/sexpr.go

@@ -3,6 +3,7 @@ package sexpr
 import (
 import (
 	"io"
 	"io"
 	"reflect"
 	"reflect"
+	"strconv"
 	"strings"
 	"strings"
 	"unicode"
 	"unicode"
 
 
@@ -16,8 +17,30 @@ const InvalidAtom Error = "invalid name of atom"
 
 
 const NameTag = "sexpr"
 const NameTag = "sexpr"
 
 
+type Named interface {
+	Name() string
+}
+
 type wr struct {
 type wr struct {
-	base io.Writer
+	base  io.Writer
+	opts  gen.Opts
+	depth int
+}
+
+func (w *wr) Ln() {
+	if w.opts.PrettyPrint {
+		w.base.Write([]byte("\n"))
+	}
+}
+
+func (w *wr) Tab() {
+	if w.opts.PrettyPrint {
+		var buf []rune
+		for i := 0; i < w.depth; i++ {
+			buf = append(buf, '\t')
+		}
+		w.base.Write([]byte(string(buf)))
+	}
 }
 }
 
 
 func (w *wr) Raw(s string) {
 func (w *wr) Raw(s string) {
@@ -47,16 +70,22 @@ func (w *wr) Atom(_v interface{}) {
 		w.Raw(v)
 		w.Raw(v)
 	case ir.Variable:
 	case ir.Variable:
 		w.Atom(v.ValueOf())
 		w.Atom(v.ValueOf())
+	case int:
+		w.Raw(strconv.Itoa(v))
 	default:
 	default:
 		Halt(100, "wrong atom ", reflect.TypeOf(v))
 		Halt(100, "wrong atom ", reflect.TypeOf(v))
 	}
 	}
 }
 }
 
 
 func getName(i interface{}) (ret string) {
 func getName(i interface{}) (ret string) {
-	t := reflect.ValueOf(i).Elem().Type()
-	for i := 0; i < t.NumField() && ret == ""; i++ {
-		s := t.Field(i)
-		ret = s.Tag.Get(NameTag)
+	if named, ok := i.(Named); ok {
+		ret = named.Name()
+	} else {
+		t := reflect.ValueOf(i).Elem().Type()
+		for i := 0; i < t.NumField() && ret == ""; i++ {
+			s := t.Field(i)
+			ret = s.Tag.Get(NameTag)
+		}
 	}
 	}
 	return
 	return
 }
 }
@@ -81,16 +110,20 @@ func (w *wr) WriteExpr(e ir.Expression) (err error) {
 	Assert(!fn.IsNil(e), 20)
 	Assert(!fn.IsNil(e), 20)
 	if err = e.Validate(); err == nil {
 	if err = e.Validate(); err == nil {
 		Do(func() {
 		Do(func() {
+			w.Ln()
+			w.Tab()
 			w.Raw("(")
 			w.Raw("(")
 			w.Atom(getName(e))
 			w.Atom(getName(e))
 			if n, ok := e.(ir.Node); ok {
 			if n, ok := e.(ir.Node); ok {
 				if el := n.Children(); len(el) > 0 {
 				if el := n.Children(); len(el) > 0 {
+					w.depth++
 					for _, _e := range el {
 					for _, _e := range el {
 						w.Raw(" ")
 						w.Raw(" ")
 						if err = w.WriteValue(_e); err != nil {
 						if err = w.WriteValue(_e); err != nil {
 							panic(err)
 							panic(err)
 						}
 						}
 					}
 					}
+					w.depth--
 				}
 				}
 			}
 			}
 			w.Raw(")")
 			w.Raw(")")
@@ -101,7 +134,15 @@ func (w *wr) WriteExpr(e ir.Expression) (err error) {
 	return err
 	return err
 }
 }
 
 
-func New(w io.Writer) gen.Writer {
+func New(w io.Writer, o ...gen.Opts) gen.Writer {
 	Assert(!fn.IsNil(w), 20)
 	Assert(!fn.IsNil(w), 20)
-	return &wr{base: w}
+	ret := &wr{base: w}
+	if len(o) > 0 {
+		ret.opts = o[0]
+	}
+	if ret.opts.PrettyPrint {
+		ret.Raw(";; github.com/kpmy/tiss/generator")
+	}
+
+	return ret
 }
 }

+ 171 - 0
ir/ast.go

@@ -7,16 +7,41 @@ import (
 	. "github.com/kpmy/ypk/tc"
 	. "github.com/kpmy/ypk/tc"
 )
 )
 
 
+type Type string
+
+const (
+	Ti32 Type = "i32"
+	Ti64 Type = "i64"
+	Tf32 Type = "f32"
+	Tf64 Type = "f64"
+)
+
 type Expression interface {
 type Expression interface {
 	Validate() error
 	Validate() error
 }
 }
 
 
+type CodeExpr interface {
+	Eval()
+}
+
 type Node interface {
 type Node interface {
 	Children() []interface{}
 	Children() []interface{}
 }
 }
 
 
 type ns struct{}
 type ns struct{}
 
 
+type named struct {
+	name string
+}
+
+func (n *named) Name(s ...string) string {
+	if len(s) > 0 {
+		Assert(s[0][0] == '$' || s[0] == "", 20)
+		n.name = s[0]
+	}
+	return n.name
+}
+
 type Variable struct {
 type Variable struct {
 	sv *string
 	sv *string
 	iv *int
 	iv *int
@@ -64,12 +89,158 @@ func (s *StartExpr) Children() (ret []interface{}) {
 	return []interface{}{s.Var}
 	return []interface{}{s.Var}
 }
 }
 
 
+type FuncExpr struct {
+	ns `sexpr:"func"`
+	named
+	Type   *TypeRef
+	Params []*Param
+	Locals []*Local
+	Result *ResultExpr
+	Code   []CodeExpr
+}
+
+func (f *FuncExpr) Validate() (err error) {
+	return
+}
+
+func (f *FuncExpr) Children() (ret []interface{}) {
+	if f.name != "" {
+		ret = append(ret, f.name)
+	}
+
+	if !fn.IsNil(f.Type) {
+		ret = append(ret, f.Type)
+	}
+
+	for _, p := range f.Params {
+		ret = append(ret, p)
+	}
+
+	if !fn.IsNil(f.Result) {
+		ret = append(ret, f.Result)
+	}
+
+	for _, l := range f.Locals {
+		ret = append(ret, l)
+	}
+
+	for _, c := range f.Code {
+		ret = append(ret, c)
+	}
+	return
+}
+
+type TypeRef struct {
+	ns   `sexpr:"type"`
+	Type Variable
+}
+
+func (t *TypeRef) Validate() error {
+	if t.Type.IsEmpty() {
+		return Error("invalid type ref")
+	}
+	return nil
+}
+
+func (t *TypeRef) Children() (ret []interface{}) {
+	return append(ret, t.Type)
+}
+
+type ResultExpr struct {
+	ns     `sexpr:"result"`
+	Result Type
+}
+
+func (r *ResultExpr) Validate() error {
+	if r.Result == "" {
+		return Error("empty result type")
+	}
+	return nil
+}
+
+func (r *ResultExpr) Children() (ret []interface{}) {
+	return append(ret, string(r.Result))
+}
+
+type TypeDef struct {
+	ns `sexpr:"type"`
+	named
+	Func *FuncExpr
+}
+
+func (t *TypeDef) Validate() error {
+	if fn.IsNil(t.Func) {
+		return Error("typedef func is null")
+	}
+	if t.Func.Name() != "" {
+		return Error("typedef func cannot have name")
+	}
+	return nil
+}
+
+func (t *TypeDef) Children() (ret []interface{}) {
+	if t.name != "" {
+		ret = append(ret, t.name)
+	}
+
+	ret = append(ret, t.Func)
+	return
+}
+
+type Param struct {
+	ns `sexpr:"param"`
+	object
+}
+
+type Local struct {
+	ns `sexpr:"local"`
+	object
+}
+
+type object struct {
+	named
+	typ Type
+}
+
+func (o *object) Type(t ...Type) Type {
+	if len(t) > 0 {
+		o.typ = t[0]
+	}
+	return o.typ
+}
+
+func (o *object) Validate() error {
+	if o.name == "" {
+		return Error("empty object name")
+	}
+
+	if o.typ == "" {
+		return Error("empty object type")
+	}
+
+	return nil
+}
+
+func (o *object) Children() (ret []interface{}) {
+	return append(ret, o.name, string(o.typ))
+}
+
 type Module struct {
 type Module struct {
 	ns    `sexpr:"module"`
 	ns    `sexpr:"module"`
 	Start *StartExpr
 	Start *StartExpr
+	Func  []*FuncExpr
+	Type  []*TypeDef
 }
 }
 
 
 func (m *Module) Children() (ret []interface{}) {
 func (m *Module) Children() (ret []interface{}) {
+	for _, t := range m.Type {
+		ret = append(ret, t)
+	}
+
+	for _, f := range m.Func {
+		ret = append(ret, f)
+	}
+
 	ret = append(ret, m.Start)
 	ret = append(ret, m.Start)
 	return
 	return
 }
 }

+ 69 - 0
ir/code.go

@@ -0,0 +1,69 @@
+package ir
+
+import (
+	"github.com/kpmy/ypk/fn"
+	. "github.com/kpmy/ypk/tc"
+)
+
+type ReturnExpr struct {
+	ns   `sexpr:"return"`
+	Expr CodeExpr
+}
+
+func (r *ReturnExpr) Validate() error { return nil }
+func (r *ReturnExpr) Eval()           {}
+func (r *ReturnExpr) Children() (ret []interface{}) {
+	return append(ret, r.Expr)
+}
+
+type ConstExpr struct {
+	Type  Type
+	Value interface{}
+}
+
+func (c *ConstExpr) Name() string {
+	return string(c.Type) + ".const"
+}
+
+func (c *ConstExpr) Validate() error {
+	if c.Type == "" {
+		return Error("empty type of const")
+	}
+
+	if fn.IsNil(c.Value) {
+		return Error("nil const value")
+	}
+
+	return nil
+}
+
+func (c *ConstExpr) Eval() {}
+
+func (c *ConstExpr) Children() (ret []interface{}) {
+	return append(ret, c.Value)
+}
+
+type CallExpr struct {
+	ns     `sexpr:"call"`
+	Var    Variable
+	Params []CodeExpr
+}
+
+func (c *CallExpr) Validate() error {
+	if c.Var.IsEmpty() {
+		return Error("empty call var")
+	}
+	return nil
+}
+
+func (c *CallExpr) Eval() {}
+
+func (c *CallExpr) Children() (ret []interface{}) {
+	ret = append(ret, c.Var)
+
+	for _, p := range c.Params {
+		ret = append(ret, p)
+	}
+
+	return
+}

+ 33 - 1
tiss_test.go

@@ -1,6 +1,8 @@
 package tiss
 package tiss
 
 
 import (
 import (
+	"bytes"
+	"io"
 	"os"
 	"os"
 	"testing"
 	"testing"
 
 
@@ -11,10 +13,40 @@ import (
 func TestDump(t *testing.T) {
 func TestDump(t *testing.T) {
 	if f, err := os.Create("dump.wasm"); err == nil {
 	if f, err := os.Create("dump.wasm"); err == nil {
 		defer f.Close()
 		defer f.Close()
+
 		m := &ir.Module{}
 		m := &ir.Module{}
+		td := &ir.TypeDef{}
+		td.Name("$t0")
+		td.Func = &ir.FuncExpr{}
+		m.Type = append(m.Type, td)
+
+		f0 := &ir.FuncExpr{}
+		f0.Name("$fib")
+		par := &ir.Param{}
+		par.Name("$x")
+		par.Type(ir.Ti64)
+		l0 := &ir.Local{}
+		l0.Name("$i")
+		l0.Type(ir.Ti64)
+		f0.Params = append(f0.Params, par)
+		f0.Locals = append(f0.Locals, l0)
+		f0.Result = &ir.ResultExpr{Result: ir.Ti64}
+		ret := &ir.ReturnExpr{}
+		ret.Expr = &ir.ConstExpr{Type: ir.Ti64, Value: 0}
+		f0.Code = append(f0.Code, ret)
+
+		fn := &ir.FuncExpr{}
+		fn.Name("$start")
+		fn.Type = &ir.TypeRef{Type: ir.ThisVariable("$t0")}
+		call := &ir.CallExpr{Var: ir.ThisVariable("$fib"), Params: []ir.CodeExpr{&ir.ConstExpr{Type: ir.Ti64, Value: 0}}}
+		fn.Code = append(fn.Code, call)
+		m.Func = append(m.Func, f0, fn)
 		m.Start = &ir.StartExpr{Var: ir.ThisVariable("$start")}
 		m.Start = &ir.StartExpr{Var: ir.ThisVariable("$start")}
-		if err = gen.NewWriter(f).WriteExpr(m); err == nil {
 
 
+		buf := bytes.NewBuffer(nil)
+		if err = gen.NewWriter(buf, gen.Opts{PrettyPrint: true}).WriteExpr(m); err == nil {
+			t.Log(buf.String())
+			io.Copy(f, buf)
 		} else {
 		} else {
 			t.Error(err)
 			t.Error(err)
 		}
 		}