提交 22b537a1 编写于 作者: chai2010's avatar chai2010

assert 支持输出位置信息

上级 2ee36267
// 版权 @2023 _examples/hello 作者。保留所有权利。
import "testing"
func init {
// init work
}
func TestFailed {
testing.Assert(false)
ok := true
assert(ok)
ok = false
assert(ok, "message")
}
// 版权 @2023 _examples/hello 作者。保留所有权利。
import "testing"
func init {
// println("zz_test.wa")
}
func TestFoo {
testing.Assert(true)
assert(true, "foo ok")
}
func TestBar {
testing.Assert(true)
assert(true, "bar ok")
}
......@@ -36,6 +36,7 @@ func (p *App) RunTest(filename string, appArgs ...string) error {
return nil
}
var lastError error
for _, main := range mainPkg.TestInfo.Funcs {
output, err := compiler_wat.New().Compile(prog, main)
if err != nil {
......@@ -51,17 +52,25 @@ func (p *App) RunTest(filename string, appArgs ...string) error {
continue
}
if exitErr, ok := err.(*sys.ExitError); ok {
fmt.Printf("---- %s.%s [%v]\n", prog.Manifest.MainPkg, main, time.Now().Sub(startTime))
if s := sWithPrefix(string(stdoutStderr), " "); s != "" {
fmt.Println(s)
if err != nil {
lastError = err
if _, ok := err.(*sys.ExitError); ok {
fmt.Printf("---- %s.%s\n", prog.Manifest.MainPkg, main)
if s := sWithPrefix(string(stdoutStderr), " "); s != "" {
fmt.Println(s)
}
} else {
fmt.Println(err)
}
os.Exit(int(exitErr.ExitCode()))
}
fmt.Println(err)
}
fmt.Printf("ok %s %v\n", prog.Manifest.MainPkg, time.Now().Sub(startTime))
if lastError != nil {
fmt.Printf("FAIL %s %v\n", prog.Manifest.MainPkg, time.Now().Sub(startTime).Round(time.Microsecond))
os.Exit(1)
}
fmt.Printf("ok %s %v\n", prog.Manifest.MainPkg, time.Now().Sub(startTime).Round(time.Microsecond))
return nil
}
......
......@@ -15,6 +15,7 @@ import (
)
type Compiler struct {
prog *loader.Program
ssaPkg *ssa.Package
module *wir.Module
......@@ -29,6 +30,7 @@ func New() *Compiler {
}
func (p *Compiler) Compile(prog *loader.Program, mainFunc string) (output string, err error) {
p.prog = prog
p.CompileWsFiles(prog)
for _, pkg := range prog.Pkgs {
......@@ -145,9 +147,9 @@ func (p *Compiler) CompilePkgFunc(ssaPkg *ssa.Package) {
for _, v := range fns {
if len(v.Blocks) < 1 {
if v.RuntimeGetter() {
p.module.AddFunc(newFunctionGenerator(p.module).genGetter(v))
p.module.AddFunc(newFunctionGenerator(p.prog, p.module).genGetter(v))
} else if v.RuntimeSetter() {
p.module.AddFunc(newFunctionGenerator(p.module).genSetter(v))
p.module.AddFunc(newFunctionGenerator(p.prog, p.module).genSetter(v))
} else if iname0, iname1 := v.ImportName(); len(iname0) > 0 && len(iname1) > 0 {
var fn_name string
if len(v.LinkName()) > 0 {
......@@ -161,6 +163,6 @@ func (p *Compiler) CompilePkgFunc(ssaPkg *ssa.Package) {
}
continue
}
p.module.AddFunc(newFunctionGenerator(p.module).genFunction(v))
p.module.AddFunc(newFunctionGenerator(p.prog, p.module).genFunction(v))
}
}
......@@ -7,6 +7,7 @@ import (
"strings"
"wa-lang.org/wa/internal/constant"
"wa-lang.org/wa/internal/loader"
"wa-lang.org/wa/internal/token"
"wa-lang.org/wa/internal/types"
......@@ -22,6 +23,7 @@ type valueWrap struct {
}
type functionGenerator struct {
prog *loader.Program
module *wir.Module
locals_map map[ssa.Value]valueWrap
......@@ -34,8 +36,8 @@ type functionGenerator struct {
var_rets []wir.Value
}
func newFunctionGenerator(module *wir.Module) *functionGenerator {
return &functionGenerator{module: module, locals_map: make(map[ssa.Value]valueWrap)}
func newFunctionGenerator(prog *loader.Program, module *wir.Module) *functionGenerator {
return &functionGenerator{prog: prog, module: module, locals_map: make(map[ssa.Value]valueWrap)}
}
func (g *functionGenerator) getValue(i ssa.Value) valueWrap {
......@@ -143,7 +145,7 @@ func (g *functionGenerator) getValue(i ssa.Value) valueWrap {
if v.Parent() != nil {
if g.module.FindFunc(fn_name) == nil {
g.module.AddFunc(newFunctionGenerator(g.module).genFunction(v))
g.module.AddFunc(newFunctionGenerator(g.prog, g.module).genFunction(v))
}
}
......@@ -464,7 +466,7 @@ func (g *functionGenerator) genCall(inst *ssa.Call) (insts []wat.Inst, ret_type
}
callee := inst.Call.StaticCallee()
if callee.Parent() != nil {
g.module.AddFunc(newFunctionGenerator(g.module).genFunction(callee))
g.module.AddFunc(newFunctionGenerator(g.prog, g.module).genFunction(callee))
}
if len(callee.LinkName()) > 0 {
......@@ -503,13 +505,45 @@ func (g *functionGenerator) genCall(inst *ssa.Call) (insts []wat.Inst, ret_type
func (g *functionGenerator) genBuiltin(call *ssa.CallCommon) (insts []wat.Inst, ret_type wir.ValueType) {
switch call.Value.Name() {
case "assert":
// TODO: 支持字符串参数
arg := call.Args[0]
av := g.getValue(arg).value
avt := av.Type()
if avt.Equal(g.module.I32) || avt.Equal(g.module.U32) {
insts = append(insts, av.EmitPush()...)
for i, arg := range call.Args {
av := g.getValue(arg).value
avt := av.Type()
// assert(ok: bool, ...)
if i == 0 {
if !avt.Equal(g.module.I32) && !avt.Equal(g.module.U32) {
panic("call.Args[0] is not bool")
}
insts = append(insts, av.EmitPush()...)
continue
}
// assert(ok: bool, messag: string)
if i == 1 {
if !avt.Equal(g.module.STRING) {
panic("call.Args[1] is not string")
}
insts = append(insts, g.module.EmitStringValue(av)...)
continue
}
panic("unreachable")
}
// 位置信息
{
callPos := g.prog.Fset.Position(call.Pos())
s := wir.NewConst(callPos.String(), g.module.STRING)
insts = append(insts, g.module.EmitStringValue(s)...)
}
switch len(call.Args) {
case 1:
insts = append(insts, wat.NewInstCall("$runtime.assert"))
case 2:
insts = append(insts, wat.NewInstCall("$runtime.assertWithMessage"))
default:
panic("len(call.Args) == 1 or 2")
}
case "print", "println":
......@@ -813,7 +847,7 @@ func (g *functionGenerator) genMakeClosre(inst *ssa.MakeClosure) (insts []wat.In
func (g *functionGenerator) genMakeClosre_Anonymous(inst *ssa.MakeClosure) (insts []wat.Inst, ret_type wir.ValueType) {
f := inst.Fn.(*ssa.Function)
g.module.AddFunc(newFunctionGenerator(g.module).genFunction(f))
g.module.AddFunc(newFunctionGenerator(g.prog, g.module).genFunction(f))
ret_type = g.module.GenValueType_Closure(f.Signature)
if !ret_type.Equal(g.module.GenValueType(inst.Type())) {
......
......@@ -447,6 +447,13 @@ func (m *Module) EmitPrintString(v Value) (insts []wat.Inst) {
return
}
func (m *Module) EmitStringValue(v Value) (insts []wat.Inst) {
s := v.(*aString)
insts = append(insts, s.Extract("data").EmitPush()...)
insts = append(insts, s.Extract("len").EmitPush()...)
return
}
func (m *Module) emitPrintValue(v Value) (insts []wat.Inst) {
panic("Todo")
......
......@@ -34,7 +34,10 @@ func fdWrite(fd: i32, io: i32, iovs_len: i32, nwritten: i32) => (written: i32) {
func procExit(code: i32) {}
#wa:linkname $runtime.assert
func assert(ok: i32) {}
func assert(ok: i32, pos_msg_ptr: i32, pos_msg_len: i32) {}
#wa:linkname $runtime.assertWithMessage
func assertWithMessage(ok: i32, msg_ptr: i32, msg_len: i32, pos_msg_ptr: i32, pos_msg_len: i32) {}
#wa:linkname $runtime.waPrintI32
func waPrintI32(i: i32) {}
......
......@@ -31,7 +31,10 @@ func fdWrite(fd: i32, io: i32, iovs_len: i32, nwritten: i32) => (written: i32) {
func procExit(code: i32) {}
#wa:linkname $runtime.assert
func assert(ok: i32) {}
func assert(ok: i32, pos_msg_ptr: i32, pos_msg_len: i32) {}
#wa:linkname $runtime.assertMessage
func assertMessage(ok: i32, msg_ptr: i32, msg_len: i32, pos_msg_ptr: i32, pos_msg_len: i32) {}
#wa:linkname $runtime.waPrintI32
func waPrintI32(i: i32) {}
......
......@@ -35,9 +35,25 @@ func procExit(code: i32) {
}
#wa:linkname $runtime.assert
func assert(ok: i32) {
func assert(ok: i32, pos_msg_ptr: i32, pos_msg_len: i32) {
if ok == 0 {
println("assert failed")
print("assert failed (")
puts(pos_msg_ptr, pos_msg_len)
putchar(')')
putchar('\n')
procExit(1)
}
}
#wa:linkname $runtime.assertWithMessage
func assertWithMessage(ok: i32, msg_ptr: i32, msg_len: i32, pos_msg_ptr: i32, pos_msg_len: i32) {
if ok == 0 {
print("assert failed: ")
puts(msg_ptr, msg_len)
print(" (")
puts(pos_msg_ptr, pos_msg_len)
putchar(')')
putchar('\n')
procExit(1)
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册