Skip to content

Commit

Permalink
core!: 1) add Pipe expression; 2) Converters at VM level; 3) IndexGet…
Browse files Browse the repository at this point in the history
… Proxy
  • Loading branch information
moisespsena committed Dec 13, 2023
1 parent 7ba056a commit 9dbacdc
Show file tree
Hide file tree
Showing 27 changed files with 531 additions and 146 deletions.
3 changes: 3 additions & 0 deletions builtin_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,9 @@ var (
TReflectMethod = &BuiltinObjType{
NameValue: "reflectMethod",
}
TIndexGetProxy = &BuiltinObjType{
NameValue: "indexGetProxy",
}
)

func init() {
Expand Down
32 changes: 30 additions & 2 deletions builtins.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ const (
BuiltinSortReverse
BuiltinFilter
BuiltinMap
BuiltinEach
BuiltinReduce
BuiltinForEach
BuiltinTypeName
Expand Down Expand Up @@ -127,6 +128,7 @@ var BuiltinsMap = map[string]BuiltinType{
"sortReverse": BuiltinSortReverse,
"filter": BuiltinFilter,
"map": BuiltinMap,
"each": BuiltinEach,
"reduce": BuiltinReduce,
"foreach": BuiltinForEach,
"typeName": BuiltinTypeName,
Expand Down Expand Up @@ -206,6 +208,24 @@ func (m BuiltinObjectsMap) Build() BuiltinObjectsMap {
return cp
}

func (m BuiltinObjectsMap) Append(obj ...Object) BuiltinObjectsMap {
var (
cp = make(BuiltinObjectsMap, len(m))
max BuiltinType
)

for t, obj := range m {
cp[t] = obj
if t > max {
max = t
}
}
for i, object := range obj {
cp[max+BuiltinType(i)] = object
}
return cp
}

// BuiltinObjects is list of builtins, exported for REPL.
var BuiltinObjects = BuiltinObjectsMap{
// :makeArray is a private builtin function to help destructuring array assignments
Expand Down Expand Up @@ -256,11 +276,11 @@ var BuiltinObjects = BuiltinObjectsMap{
},
BuiltinSort: &BuiltinFunction{
Name: "sort",
Value: funcPOROe(BuiltinSortFunc),
Value: funcPpVM_OCoROe(BuiltinSortFunc),
},
BuiltinSortReverse: &BuiltinFunction{
Name: "sortReverse",
Value: funcPOROe(BuiltinSortReverseFunc),
Value: funcPpVM_OCoROe(BuiltinSortReverseFunc),
},
BuiltinTypeName: &BuiltinFunction{
Name: "typeName",
Expand Down Expand Up @@ -456,6 +476,10 @@ func init() {
Name: "map",
Value: BuiltinMapFunc,
}
BuiltinObjects[BuiltinEach] = &BuiltinFunction{
Name: "each",
Value: BuiltinEachFunc,
}
BuiltinObjects[BuiltinReduce] = &BuiltinFunction{
Name: "reduce",
Value: BuiltinReduceFunc,
Expand Down Expand Up @@ -513,3 +537,7 @@ func init() {
// builtin addMethod
//
//gad:callable func(vm *VM, o CallerObject, handler CallerObject, override=bool) (err error)

// builtin sort, sortReverse
//
//gad:callable func(vm *VM, v Object, less=CallerObject) (ret Object, err error)
58 changes: 54 additions & 4 deletions builtins_funcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ func BuiltinAppendFunc(c Call) (Object, error) {
}
return obj, nil
case Appender:
return obj.Append(c.Args.Values()...)
return obj.Append(c.VM, c.Args.Values()...)
default:
return Nil, NewArgumentTypeError(
"1st",
Expand Down Expand Up @@ -245,10 +245,10 @@ func BuiltinCapFunc(arg Object) Object {
return Int(n)
}

func BuiltinSortFunc(arg Object) (ret Object, err error) {
func BuiltinSortFunc(vm *VM, arg Object, less CallerObject) (ret Object, err error) {
switch obj := arg.(type) {
case Sorter:
ret, err = obj.Sort()
ret, err = obj.Sort(vm, less)
case String:
s := []rune(obj)
sort.Slice(s, func(i, j int) bool {
Expand All @@ -273,7 +273,7 @@ func BuiltinSortFunc(arg Object) (ret Object, err error) {
return
}

func BuiltinSortReverseFunc(arg Object) (Object, error) {
func BuiltinSortReverseFunc(vm *VM, arg Object, less CallerObject) (Object, error) {
switch obj := arg.(type) {
case ReverseSorter:
return obj.SortReverse()
Expand Down Expand Up @@ -441,6 +441,56 @@ func BuiltinMapFunc(c Call) (_ Object, err error) {
return ret, nil
}

func BuiltinEachFunc(c Call) (_ Object, err error) {
var (
iterabler = &Arg{
Name: "iterable",
Accept: func(v Object) string {
if !Mapable(v) && !Iterable(v) {
return "mapable|iterable"
}
return ""
},
}

callback = &Arg{
Name: "callback",
Accept: func(v Object) string {
if !Callable(v) {
return "callable"
}
return ""
},
}
)

if err = c.Args.Destructure(iterabler, callback); err != nil {
return
}

var (
args = Array{Nil, Nil}
caller VMCaller
)

if caller, err = NewInvoker(c.VM, callback.Value).Caller(Args{args}, &c.NamedArgs); err != nil {
return
}

var (
it = iterabler.Value.(Iterabler).Iterate(c.VM)
fe = NewForEach(it, args, 0, caller)
)

for fe.Next() {
if _, err = fe.Call(); err != nil {
return
}
}

return iterabler.Value, nil
}

func BuiltinReduceFunc(c Call) (_ Object, err error) {
var (
iterabler = &Arg{
Expand Down
33 changes: 33 additions & 0 deletions builtins_zfuncs.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,8 @@ func (c *Compiler) Compile(nd ast.Node) error {
return c.compileReturnStmt(nt)
case *node.CallExpr:
return c.compileCallExpr(nt)
case *node.PipeExpr:
return c.compilePipeExpr(nt)
case *node.ImportExpr:
return c.compileImportExpr(nt)
case *node.CondExpr:
Expand Down
26 changes: 14 additions & 12 deletions compiler_nodes.go
Original file line number Diff line number Diff line change
Expand Up @@ -1319,6 +1319,20 @@ func (c *Compiler) compileSliceExpr(nd *node.SliceExpr) error {
return nil
}

func (c *Compiler) compilePipeExpr(nd *node.PipeExpr) error {
var call node.CallExpr
switch t := nd.Dst.(type) {
case *node.CallExpr:
call = *t
default:
call = node.CallExpr{
Func: t,
}
}
call.CallArgs.Args.Values = append([]node.Expr{nd.Src}, call.CallArgs.Args.Values...)
return c.Compile(&call)
}

func (c *Compiler) compileCallExpr(nd *node.CallExpr) error {
var (
selExpr *node.SelectorExpr
Expand All @@ -1333,18 +1347,6 @@ func (c *Compiler) compileCallExpr(nd *node.CallExpr) error {
selExpr, isSelector = nd.Func.(*node.SelectorExpr)
}
if isSelector {
switch t := selExpr.Sel.(type) {
case *node.StringLit:
if t.CanIdent() && t.Value[0] == '!' {
cp := *nd
cp.Func = &node.Ident{
NamePos: t.ValuePos,
Name: t.Value[1:],
}
cp.CallArgs.Args.Values = append([]node.Expr{selExpr.Expr}, cp.CallArgs.Args.Values...)
return c.compileCallExpr(&cp)
}
}
if err := c.Compile(selExpr.Expr); err != nil {
return err
}
Expand Down
33 changes: 28 additions & 5 deletions compiler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,31 @@ func concatInsts(insts ...[]byte) []byte {
return out
}

func TestCompiler_CompileNameCallerToIdentCall(t *testing.T) {
expectCompile(t, `global (a, x); a.!filter(x)`, bytecode(
func TestCompiler_CompilePipe(t *testing.T) {
expectCompile(t, `"a".|filter`, bytecode(
Array{String("a")},
compFunc(concatInsts(
makeInst(OpGetBuiltin, int(BuiltinFilter)),
makeInst(OpConstant, 0),
makeInst(OpCall, 1, 0),
makeInst(OpPop),
makeInst(OpReturn, 0),
)),
))
expectCompile(t, `var a; a.|filter`, bytecode(
Array{},
compFunc(concatInsts(
makeInst(OpNull),
makeInst(OpDefineLocal, 0),
makeInst(OpGetBuiltin, int(BuiltinFilter)),
makeInst(OpGetLocal, 0),
makeInst(OpCall, 1, 0),
makeInst(OpPop),
makeInst(OpReturn, 0),
),
withLocals(1)),
))
expectCompile(t, `global (a, x); a.|filter(x)`, bytecode(
Array{String("a"), String("x")},
compFunc(concatInsts(
makeInst(OpGetBuiltin, int(BuiltinFilter)),
Expand All @@ -128,7 +151,7 @@ func TestCompiler_CompileNameCallerToIdentCall(t *testing.T) {
),
withLocals(0)),
))
expectCompile(t, `global (a, x); a.!map(x)`, bytecode(
expectCompile(t, `global (a, x); a.|map(x)`, bytecode(
Array{String("a"), String("x")},
compFunc(concatInsts(
makeInst(OpGetBuiltin, int(BuiltinMap)),
Expand All @@ -140,7 +163,7 @@ func TestCompiler_CompileNameCallerToIdentCall(t *testing.T) {
),
withLocals(0)),
))
expectCompile(t, `global (a, x); a.!reduce(x)`, bytecode(
expectCompile(t, `global (a, x); a.|reduce(x)`, bytecode(
Array{String("a"), String("x")},
compFunc(concatInsts(
makeInst(OpGetBuiltin, int(BuiltinReduce)),
Expand All @@ -152,7 +175,7 @@ func TestCompiler_CompileNameCallerToIdentCall(t *testing.T) {
),
withLocals(0)),
))
expectCompile(t, `var x; [].!x()`, bytecode(
expectCompile(t, `var x; [].|x()`, bytecode(
Array{},
compFunc(concatInsts(
makeInst(OpNull),
Expand Down
53 changes: 53 additions & 0 deletions converter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package gad

import "reflect"

type ObjectConverters struct {
ToGoHandlers map[ObjectType]func(vm *VM, v Object) any
ToObjectHandlers map[reflect.Type]func(vm *VM, v any) (Object, error)
}

func NewObjectConverters() *ObjectConverters {
return &ObjectConverters{
ToGoHandlers: make(map[ObjectType]func(vm *VM, v Object) any),
ToObjectHandlers: make(map[reflect.Type]func(vm *VM, v any) (Object, error)),
}
}

func (oc *ObjectConverters) Register(objType ObjectType, togo func(vm *VM, v Object) any, goType reflect.Type, toObject func(vm *VM, v any) (Object, error)) *ObjectConverters {
if objType != nil {
oc.ToGoHandlers[objType] = togo
}
if goType != nil {
oc.ToObjectHandlers[goType] = toObject
}
return oc
}

func (oc *ObjectConverters) ToObject(vm *VM, v any) (Object, error) {
typ := reflect.TypeOf(v)
for typ.Kind() == reflect.Ptr {
typ = typ.Elem()
}

if h := oc.ToObjectHandlers[typ]; h != nil {
return h(vm, v)
}

return ToObject(v)
}

func (oc *ObjectConverters) ToInterface(vm *VM, v Object) any {
if h := oc.ToGoHandlers[v.Type()]; h != nil {
return h(vm, v)
}
return ToInterface(v)
}

func (vm *VM) ToObject(v any) (Object, error) {
return vm.ObjectConverters.ToObject(vm, v)
}

func (vm *VM) ToInterface(v Object) any {
return vm.ObjectConverters.ToInterface(vm, v)
}
Loading

0 comments on commit 9dbacdc

Please sign in to comment.