Skip to content

Commit

Permalink
core!: 1) perform constructor of structs; 2) yield caller to dedent s…
Browse files Browse the repository at this point in the history
…tack caller
  • Loading branch information
moisespsena committed Jan 29, 2024
1 parent f8ba9c0 commit 02881b9
Show file tree
Hide file tree
Showing 21 changed files with 206 additions and 164 deletions.
6 changes: 3 additions & 3 deletions builtins.go
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ func (s *Builtins) Set(name string, obj Object) *Builtins {
}

func (s *Builtins) Call(t BuiltinType, c Call) (Object, error) {
return s.Objects[t].(CallerObject).Call(c)
return DoCall(s.Objects[t].(CallerObject), c)
}

func (s *Builtins) Caller(t BuiltinType) CallerObject {
Expand All @@ -280,7 +280,7 @@ func (s *Builtins) Caller(t BuiltinType) CallerObject {
func (s *Builtins) Invoker(t BuiltinType, c Call) func() (Object, error) {
caller := s.Objects[t].(CallerObject)
return func() (Object, error) {
return caller.Call(c)
return DoCall(caller, c)
}
}

Expand All @@ -289,7 +289,7 @@ func (s *Builtins) ArgsInvoker(t BuiltinType, c Call) func(arg ...Object) (Objec
c.Args = Args{nil}
return func(arg ...Object) (Object, error) {
c.Args[0] = arg
return caller.Call(c)
return DoCall(caller, c)
}
}

Expand Down
9 changes: 5 additions & 4 deletions bytecode.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,9 @@ func (t ParamType) Accept(vm *VM, ot ObjectType) (ok bool, err error) {
ok = true
return
} else if stot, _ := st.(ObjectType); stot != nil {
ok = IsTypeAssignableTo(stot, ot)
return
if ok = IsTypeAssignableTo(stot, ot); ok {
return
}
}
}
}
Expand Down Expand Up @@ -136,7 +137,7 @@ func (p *Params) String() string {
if ts := t.String(); ts == "" {
s[i] = p.Names[i]
} else {
s[i] = p.Names[i] + ":" + ts
s[i] = p.Names[i] + " " + ts
}
}
} else {
Expand Down Expand Up @@ -392,7 +393,7 @@ func (o *CompiledFunction) hash32() uint32 {
}

func (o *CompiledFunction) Call(c Call) (Object, error) {
return NewInvoker(c.VM, o).Invoke(c.Args, &c.NamedArgs)
return NewInvoker(c.VM, o).ValidArgs(c.SafeArgs).Invoke(c.Args, &c.NamedArgs)
}

func (o *CompiledFunction) SetNamedParams(params ...*NamedParam) {
Expand Down
23 changes: 23 additions & 0 deletions call.go
Original file line number Diff line number Diff line change
Expand Up @@ -519,3 +519,26 @@ func MustCallVargs(callee Object, args []Object, vargs ...Object) (Object, error
}
return callee.(CallerObject).Call(NewCall(nil, WithArgsV(args, vargs...)))
}

type yieldCall struct {
CallerObject
c *Call
}

func YieldCall(callerObject CallerObject, c *Call) CallerObject {
return &yieldCall{CallerObject: callerObject, c: c}
}

func (y *yieldCall) GetCaller() CallerObject {
return y.CallerObject
}

func (y *yieldCall) GetCall() *Call {
return y.c
}

func (y *yieldCall) Call(c Call) (Object, error) {
c2 := *y.c
c2.VM = c.VM
return DoCall(y.CallerObject, c2)
}
8 changes: 4 additions & 4 deletions cmd/gad/internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,15 +178,15 @@ func TestREPL(t *testing.T) {
})
t.Run("type_method_constructor", func(t *testing.T) {
r := newREPL(ctx, cw)
require.NoError(t, r.execute(`Point := struct("Point",fields={x:0, y:0});func new(p:Point, x,y){p.x = x;p.y = y}`))
require.NoError(t, r.execute(`Point := struct("Point",fields={x:0, y:0});func Point(x,y)=>Point(x=x,y=y)`))
cw.consume()
require.NoError(t, r.execute("func int(p:Point) => p.x * p.y"))
require.NoError(t, r.execute("func int(p Point) => p.x * p.y"))
cw.consume()
require.NoError(t, r.execute("str(int)"))
require.Equal(t, "⇦ \""+repr.Quote("builtinType int")+" with 1 methods:\\n "+
"1. "+repr.Quote("compiledFunction #7(p:Point)")+"\"",
"1. "+repr.Quote("compiledFunction #8(p Point)")+"\"",
strings.TrimSpace(string(cw.consume())))
require.NoError(t, r.execute("int(Point(x=2,y=8))"))
require.NoError(t, r.execute("int(Point(2,8))"))
require.Equal(t, "⇦ 16", strings.TrimSpace(string(cw.consume())))
})
t.Run("exit", func(t *testing.T) {
Expand Down
4 changes: 2 additions & 2 deletions compiler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2941,7 +2941,7 @@ func TestCompilerFuncWithMethods(t *testing.T) {
expectCompile(t, `func f0() {
return 100
}
func f0(i:int) {
func f0(i int) {
return i
}`,
bytecode(
Expand All @@ -2954,7 +2954,7 @@ func f0(i:int) {
compFunc(concatInsts(
makeInst(OpGetLocal, 0),
makeInst(OpReturn, 1),
), withLocals(1), withParams("i:int")),
), withLocals(1), withParams("i int")),
},
compFunc(concatInsts(
makeInst(OpConstant, 1),
Expand Down
2 changes: 1 addition & 1 deletion encoder/encoder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -603,7 +603,7 @@ func testBytecodeConstants(t *testing.T, expected, decoded []gad.Object) {
for decIt.Next() {
require.True(t, it.Next())
key := decIt.Key()
v1, err := expected[i].(gad.IndexGetter).IndexGet(nil, key)
v1, err := gad.Val(expected[i].(gad.IndexGetter).IndexGet(nil, key))
require.NoError(t, err)
v2, err := decIt.Value()
require.NoError(t, err)
Expand Down
2 changes: 1 addition & 1 deletion helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ func NewArgCaller(vm *VM, co CallerObject, args Array, namedArgs NamedArgs) func
NamedArgs: namedArgs,
}
return func() (ret Object, err error) {
return co.Call(call)
return DoCall(co, call)
}
}

Expand Down
2 changes: 1 addition & 1 deletion helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ func ExprToTextOverride(name string, f func(vm *VM, w Writer, old func(w Writer,
var n Int
n, err = f(c.VM, c.Args.MustGet(0).(Writer), func(w Writer, expr Object) (_ Int, err error) {
var n Object
n, err = c.Args.MustGet(1).(CallerObject).Call(Call{Args: Args{Array{w, expr}}})
n, err = Val(c.Args.MustGet(1).(CallerObject).Call(Call{Args: Args{Array{w, expr}}}))
return n.(Int), err
}, c.Args.MustGet(2))
return n, err
Expand Down
8 changes: 3 additions & 5 deletions methods.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,8 @@ func (o *CallerMethod) Remove() {
func (o *CallerMethod) String() string {
var ts = make([]string, len(o.Types))
for i := range ts {
if o.Types[i] == nil {
ts[i] = ":*"
} else {
ts[i] = ":" + o.Types[i].Name()
if o.Types[i] != nil {
ts[i] = " " + o.Types[i].Name()
}
}

Expand Down Expand Up @@ -176,7 +174,7 @@ func (o *CallerObjectWithMethods) Caller() CallerObject {
func (o *CallerObjectWithMethods) Call(c Call) (Object, error) {
caller, validate := o.CallerOf(c.Args)
c.SafeArgs = !validate
return caller.Call(c)
return YieldCall(caller, &c), nil
}

func (o *CallerObjectWithMethods) CallerOf(args Args) (CallerObject, bool) {
Expand Down
2 changes: 1 addition & 1 deletion objects_reflect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ func TestReflectSlice_IndexGet(t *testing.T) {
return
}

got, err := r.(IndexGetter).IndexGet(vm, tt.key)
got, err := Val(r.(IndexGetter).IndexGet(vm, tt.key))
if !checkError(t, fmt.Sprintf("IndexGet(%T)", tt.obj), tt.wantErr, err) {
return
}
Expand Down
50 changes: 17 additions & 33 deletions objects_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func (o Obj) DeepCopy(vm *VM) (r Object, err error) {
func (o *Obj) IndexSet(vm *VM, index, value Object) (err error) {
name := index.ToString()
if s := o.typ.SettersDict[name]; s != nil {
_, err = s.(CallerObject).Call(Call{VM: vm, Args: Args{Array{o, value}}})
_, err = DoCall(s.(CallerObject), Call{VM: vm, Args: Args{Array{o, value}}})
} else {
o.fields[name] = value
}
Expand All @@ -68,7 +68,7 @@ func (o *Obj) IndexSet(vm *VM, index, value Object) (err error) {
func (o *Obj) IndexGet(vm *VM, index Object) (Object, error) {
name := index.ToString()
if s := o.typ.GettersDict[name]; s != nil {
return s.(CallerObject).Call(Call{VM: vm, Args: Args{Array{o}}})
return YieldCall(s.(CallerObject), &Call{VM: vm, Args: Args{Array{o}}}), nil
} else {
v, ok := o.fields[name]
if ok {
Expand Down Expand Up @@ -122,14 +122,14 @@ func (o *Obj) Values() Array {
func (o *Obj) CallName(name string, c Call) (_ Object, err error) {
if m := o.typ.MethodsDict[name]; m != nil {
c.Args = append([]Array{{o}}, c.Args...)
return m.(CallerObject).Call(c)
return YieldCall(m.(CallerObject), &c), nil
}
var v Object
if v, err = o.IndexGet(c.VM, Str(name)); err != nil {
return
}
if Callable(v) {
return v.(CallerObject).Call(c)
return YieldCall(v.(CallerObject), &c), nil
}
return nil, ErrNotCallable.NewError("method " + strconv.Quote(name) + " of type " + v.Type().Name())
}
Expand Down Expand Up @@ -200,6 +200,10 @@ func NewObjType(typeName string) *ObjType {
}

func (o *ObjType) AddCallerMethod(vm *VM, types MultipleObjectTypes, handler CallerObject, override bool) error {
if len(types) == 0 {
// overrides default constructor. uses Type.new to instantiate.
override = true
}
return o.calllerMethods.Add(types, &CallerMethod{
CallerObject: handler,
}, override)
Expand All @@ -213,23 +217,6 @@ func (o *ObjType) CallerMethods() *MethodArgType {
return &o.calllerMethods
}

func (o *ObjType) callerOf(args Args) (co CallerObject, ok, new bool) {
var types []ObjectType
args.Walk(func(i int, arg Object) any {
if t, ok := arg.(ObjectType); ok {
types = append(types, t)
} else {
types = append(types, arg.Type())
}
return nil
})
if co, ok = o.CallerOfTypes(types); co == nil {
co, ok = o.CallerOfTypes(append([]ObjectType{o}, types...))
new = true
}
return
}

func (o *ObjType) CallerOf(args Args) (co CallerObject, ok bool) {
var types []ObjectType
args.Walk(func(i int, arg Object) any {
Expand Down Expand Up @@ -271,19 +258,9 @@ func (o *ObjType) NewCall(c Call) (Object, error) {
}

func (o *ObjType) Call(c Call) (_ Object, err error) {
if c.Args.Len() == 0 {
return o.NewCall(c)
}
caller, validate, new := o.callerOf(c.Args)
caller, validate := o.CallerOf(c.Args)
c.SafeArgs = !validate
if new {
obj := &Obj{typ: o, fields: make(Dict)}
c.Args = append(Args{Array{obj}}, c.Args...)
if _, err = caller.Call(c); err == nil {
return obj, nil
}
}
return caller.Call(c)
return YieldCall(caller, &c), nil
}

func (o *ObjType) Fields() Dict {
Expand Down Expand Up @@ -319,6 +296,13 @@ func (o *ObjType) IsChildOf(t ObjectType) bool {
return false
}

func (o *ObjType) CallName(name string, c Call) (ret Object, err error) {
if name == "new" {
return o.NewCall(c)
}
return nil, ErrInvalidIndex.NewError(name)
}

func (o *ObjType) IndexGet(_ *VM, index Object) (value Object, err error) {
switch index.ToString() {
case "fields":
Expand Down
12 changes: 4 additions & 8 deletions parser/node/expr.go
Original file line number Diff line number Diff line change
Expand Up @@ -600,18 +600,14 @@ func (e *TypedIdent) End() source.Pos {

func (e *TypedIdent) String() string {
if e != nil {
l := len(e.Type)
switch l {
case 0:
if l := len(e.Type); l == 0 {
return e.Ident.String()
case 1:
return e.Ident.String() + ":" + e.Type[0].String()
default:
var s = make([]string, len(e.Type))
} else {
var s = make([]string, l)
for i, ident := range e.Type {
s[i] = ident.String()
}
return e.Ident.String() + ":[" + strings.Join(s, ", ") + "]"
return e.Ident.String() + " " + strings.Join(s, "|")
}
}
return nullRep
Expand Down
17 changes: 2 additions & 15 deletions parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -1405,15 +1405,7 @@ func (p *Parser) ParseTypedIdent() *node.TypedIdent {
}

func (p *Parser) ParseType() (idents []*node.Ident) {
if p.Token.Token != token.Colon {
return
}

p.Expect(token.Colon)

if p.Token.Token == token.LBrack {
p.Next()

if p.Token.Token == token.Ident {
var (
exists = map[string]any{}
add = func(ident *node.Ident) {
Expand All @@ -1425,13 +1417,10 @@ func (p *Parser) ParseType() (idents []*node.Ident) {
)

add(p.ParseIdent())
for p.Token.Token == token.Comma {
for p.Token.Token == token.Or {
p.Next()
add(p.ParseIdent())
}
p.Expect(token.RBrack)
} else {
idents = append(idents, p.ParseIdent())
}
return
}
Expand Down Expand Up @@ -1729,13 +1718,11 @@ func (p *Parser) ParseGenDecl(
case *node.ClosureLit:
fn.Type.Token = keyword
if keyword == token.Const {
fn.Type.AllowMethods = true
fn.Type.Ident = vs.Idents[0]
}
case *node.FuncLit:
fn.Type.Token = keyword
if keyword == token.Const {
fn.Type.AllowMethods = true
fn.Type.Ident = vs.Idents[0]
}
}
Expand Down
Loading

0 comments on commit 02881b9

Please sign in to comment.