Skip to content
This repository has been archived by the owner on Mar 15, 2019. It is now read-only.

Commit

Permalink
make an Object interface, more stdlib func
Browse files Browse the repository at this point in the history
  • Loading branch information
mna committed Sep 8, 2013
1 parent dc526b1 commit 73b4ae1
Show file tree
Hide file tree
Showing 10 changed files with 203 additions and 47 deletions.
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Expand Up @@ -11,7 +11,7 @@ In any case, the steps are the following, provided you already have a GitHub acc

* File an issue (if it doesn't already exist)
* Fork the repository
* Create a working branch
* Create a working branch from the *next* branch
* Add test(s) to prove the bug, and write the fix. Make sure to use `gofmt` on your Go code
* Run all the tests to make sure the fix did not break something else
* Submit the pull request
Expand Down
6 changes: 3 additions & 3 deletions runtime/builtin.go
Expand Up @@ -6,7 +6,7 @@ import (

type builtinMod struct {
ctx *Ctx
ob *Object
ob Object
}

func (b *builtinMod) ID() string {
Expand Down Expand Up @@ -85,8 +85,8 @@ func (b *builtinMod) _recover(args ...Val) (ret Val) {
func (b *builtinMod) _len(args ...Val) Val {
ExpectAtLeastNArgs(1, args)
switch v := args[0].(type) {
case *Object:
return Number(len(v.m))
case Object:
return v.Len()
case null:
return Number(0)
default:
Expand Down
4 changes: 2 additions & 2 deletions runtime/ctx.go
Expand Up @@ -49,7 +49,7 @@ type Ctx struct {
// Modules management
loadingMods map[string]bool // Modules currently being loaded
loadedMods map[string]Module
builtin *Object
builtin Object
}

// NewCtx returns a new execution context, using the provided module resolver
Expand All @@ -70,7 +70,7 @@ func NewCtx(resolver ModuleResolver, comp Compiler) *Ctx {
if v, err := b.Run(); err != nil {
panic("error loading angora builtin module: " + err.Error())
} else {
c.builtin = v.(*Object)
c.builtin = v.(Object)
}
return c
}
Expand Down
6 changes: 3 additions & 3 deletions runtime/funcvm.go
Expand Up @@ -307,15 +307,15 @@ func (f *funcVM) run(args ...Val) Val {

case bytecode.OP_SFLD:
vr, k, vl := f.pop(), f.pop(), f.pop()
if ob, ok := vr.(*Object); ok {
if ob, ok := vr.(Object); ok {
ob.Set(k, vl)
} else {
panic(ErrValNotAnObject)
}

case bytecode.OP_GFLD:
vr, k := f.pop(), f.pop()
if ob, ok := vr.(*Object); ok {
if ob, ok := vr.(Object); ok {
f.push(ob.Get(k))
} else {
panic(ErrValNotAnObject)
Expand All @@ -328,7 +328,7 @@ func (f *funcVM) run(args ...Val) Val {
for j := ix; j > 0; j-- {
args[j-1] = f.pop()
}
if ob, ok := vr.(*Object); ok {
if ob, ok := vr.(Object); ok {
f.push(ob.callMethod(k, args...))
} else {
panic(ErrValNotAnObject)
Expand Down
57 changes: 30 additions & 27 deletions runtime/object.go
Expand Up @@ -24,20 +24,28 @@ var (
ErrInvalidNilKey = errors.New("field key cannot be nil")
)

// An Object is a map of values, an associative array.
type Object struct {
type Object interface {
Val
Get(Val) Val
Set(Val, Val)
Len() Val
callMethod(Val, ...Val) Val
}

// An object is a map of values, an associative array.
type object struct {
m map[Val]Val
}

// NewObject returns a new instance of an object.
func NewObject() *Object {
return &Object{
func NewObject() Object {
return &object{
make(map[Val]Val),
}
}

// dump pretty-prints the content of the object.
func (o *Object) dump() string {
func (o *object) dump() string {
buf := bytes.NewBuffer(nil)
for k, v := range o.m {
buf.WriteString(fmt.Sprintf(" %s: %s, ", k.dump(), v.dump()))
Expand All @@ -47,7 +55,7 @@ func (o *Object) dump() string {

// Int returns the integer value of the object. Such behaviour can be defined
// if a `__toInt` method is available on the object.
func (o *Object) Int() int64 {
func (o *object) Int() int64 {
if i, ok := o.m[String("__toInt")]; ok {
if f, ok := i.(Func); ok {
return f.Call(o).Int()
Expand All @@ -58,7 +66,7 @@ func (o *Object) Int() int64 {

// Float returns the float value of the object. Such behaviour can be defined
// if a `__toFloat` method is available on the object.
func (o *Object) Float() float64 {
func (o *object) Float() float64 {
if l, ok := o.m[String("__toFloat")]; ok {
if f, ok := l.(Func); ok {
return f.Call(o).Float()
Expand All @@ -69,7 +77,7 @@ func (o *Object) Float() float64 {

// String returns the string value of the object. Such behaviour can be defined
// if a `__toString` method is available on the object.
func (o *Object) String() string {
func (o *object) String() string {
if s, ok := o.m[String("__toString")]; ok {
if f, ok := s.(Func); ok {
return f.Call(o).String()
Expand All @@ -80,7 +88,7 @@ func (o *Object) String() string {

// Bool returns the boolean value of the object. Such behaviour can be defined
// if a `__toBool` method is available on the object. Otherwise it returns true.
func (o *Object) Bool() bool {
func (o *object) Bool() bool {
if b, ok := o.m[String("__toBool")]; ok {
if f, ok := b.(Func); ok {
return f.Call(o).Bool()
Expand All @@ -92,7 +100,7 @@ func (o *Object) Bool() bool {

// Native returns the Go native value of the object. Such behaviour can be defined
// if a `__toNative` method is available on the object.
func (o *Object) Native() interface{} {
func (o *object) Native() interface{} {
if n, ok := o.m[String("__toNative")]; ok {
if f, ok := n.(Func); ok {
return f.Call(o).Native()
Expand All @@ -104,7 +112,7 @@ func (o *Object) Native() interface{} {
// Cmp compares the object to another value. Such behaviour can be defined
// if a `__cmp` method is available on the object. Otherwise it returns 0 if
// the compared value is the object, or -1 otherwise.
func (o *Object) Cmp(v Val) int {
func (o *object) Cmp(v Val) int {
// First check for a custom Cmp method
if c, ok := o.m[String("__cmp")]; ok {
if f, ok := c.(Func); ok {
Expand All @@ -118,7 +126,7 @@ func (o *Object) Cmp(v Val) int {
return -1
}

func (ø *Object) callBinaryMethod(nm String, err error, v Val) Val {
func (ø *object) callBinaryMethod(nm String, err error, v Val) Val {
if m, ok := ø.m[nm]; ok {
if f, ok := m.(Func); ok {
return f.Call(ø, v)
Expand All @@ -129,37 +137,37 @@ func (ø *Object) callBinaryMethod(nm String, err error, v Val) Val {

// Add performs addition. Such behaviour can be defined
// if a `__add` method is available on the object.
func (o *Object) Add(v Val) Val {
func (o *object) Add(v Val) Val {
return o.callBinaryMethod(String("__add"), ErrInvalidOpAddOnObj, v)
}

// Sub performs subtraction. Such behaviour can be defined
// if a `__sub` method is available on the object.
func (o *Object) Sub(v Val) Val {
func (o *object) Sub(v Val) Val {
return o.callBinaryMethod(String("__sub"), ErrInvalidOpSubOnObj, v)
}

// Mul performs multiplication. Such behaviour can be defined
// if a `__mul` method is available on the object.
func (o *Object) Mul(v Val) Val {
func (o *object) Mul(v Val) Val {
return o.callBinaryMethod(String("__mul"), ErrInvalidOpMulOnObj, v)
}

// Div performs division. Such behaviour can be defined
// if a `__div` method is available on the object.
func (o *Object) Div(v Val) Val {
func (o *object) Div(v Val) Val {
return o.callBinaryMethod(String("__div"), ErrInvalidOpDivOnObj, v)
}

// Mod computes the modulo. Such behaviour can be defined
// if a `__mod` method is available on the object.
func (o *Object) Mod(v Val) Val {
func (o *object) Mod(v Val) Val {
return o.callBinaryMethod(String("__mod"), ErrInvalidOpModOnObj, v)
}

// Unm computes the unary minus. Such behaviour can be defined
// if a `__unm` method is available on the object.
func (o *Object) Unm() Val {
func (o *object) Unm() Val {
if m, ok := o.m[String("__unm")]; ok {
if f, ok := m.(Func); ok {
return f.Call(o)
Expand All @@ -170,7 +178,7 @@ func (o *Object) Unm() Val {

// Get the length of the object. The behaviour can be overridden
// if a `__len` method is available on the object.
func (o *Object) Len() Val {
func (o *object) Len() Val {
if m, ok := o.m[String("__len")]; ok {
if f, ok := m.(Func); ok {
return f.Call(o)
Expand All @@ -181,7 +189,7 @@ func (o *Object) Len() Val {

// Get returns the value of the field identified by key. It returns Nil
// if the field does not exist.
func (o *Object) Get(key Val) Val {
func (o *object) Get(key Val) Val {
if v, ok := o.m[key]; ok {
return v
}
Expand All @@ -191,7 +199,7 @@ func (o *Object) Get(key Val) Val {
// Set assigns the value v to the field identified by key. If the value
// is Nil, set instead removes the key from the object. If the key is nil,
// an error is raised.
func (o *Object) Set(key Val, v Val) {
func (o *object) Set(key Val, v Val) {
if v == Nil {
delete(o.m, key)
} else if key == Nil {
Expand All @@ -201,15 +209,10 @@ func (o *Object) Set(key Val, v Val) {
}
}

// Delete removes the field identified by the key from the object.
func (o *Object) Delete(key Val) {
delete(o.m, key)
}

// callMethod calls the method identified by nm with the provided arguments.
// It panics if the field does not hold a function. If the field does not
// exist and a method named `__noSuchMethod` is defined, it is called instead.
func (o *Object) callMethod(nm Val, args ...Val) Val {
func (o *object) callMethod(nm Val, args ...Val) Val {
v, ok := o.m[nm]
if ok {
if f, ok := v.(Func); ok {
Expand Down
4 changes: 2 additions & 2 deletions runtime/stdlib/conv.go
Expand Up @@ -6,7 +6,7 @@ import (

type ConvMod struct {
ctx *runtime.Ctx
ob *runtime.Object
ob runtime.Object
}

func (c *ConvMod) ID() string {
Expand Down Expand Up @@ -56,7 +56,7 @@ func (c *ConvMod) conv_Type(args ...runtime.Val) runtime.Val {
return runtime.String("bool")
case runtime.Func:
return runtime.String("func")
case *runtime.Object:
case runtime.Object:
return runtime.String("object")
default:
return runtime.String("nil")
Expand Down
29 changes: 28 additions & 1 deletion runtime/stdlib/fmt.go
@@ -1,14 +1,15 @@
package stdlib

import (
"bufio"
"fmt"

"github.com/PuerkitoBio/agora/runtime"
)

type FmtMod struct {
ctx *runtime.Ctx
ob *runtime.Object
ob runtime.Object
}

func (f *FmtMod) ID() string {
Expand All @@ -22,6 +23,8 @@ func (f *FmtMod) Run(_ ...runtime.Val) (v runtime.Val, err error) {
f.ob = runtime.NewObject()
f.ob.Set(runtime.String("Print"), runtime.NewNativeFunc(f.ctx, "fmt.Print", f.fmt_Print))
f.ob.Set(runtime.String("Println"), runtime.NewNativeFunc(f.ctx, "fmt.Println", f.fmt_Println))
f.ob.Set(runtime.String("Scanln"), runtime.NewNativeFunc(f.ctx, "fmt.Scanln", f.fmt_Scanln))
f.ob.Set(runtime.String("Scanint"), runtime.NewNativeFunc(f.ctx, "fmt.Scanint", f.fmt_Scanint))
}
return f.ob, nil
}
Expand Down Expand Up @@ -59,3 +62,27 @@ func (f *FmtMod) fmt_Println(args ...runtime.Val) runtime.Val {
}
return runtime.Number(n)
}

func (f *FmtMod) fmt_Scanln(args ...runtime.Val) runtime.Val {
var (
b, l []byte
e error
pre bool
)
r := bufio.NewReader(f.ctx.Stdin)
for l, pre, e = r.ReadLine(); pre && e == nil; l, pre, e = r.ReadLine() {
b = append(b, l...)
}
if e != nil {
panic(e)
}
return runtime.String(b)
}

func (f *FmtMod) fmt_Scanint(args ...runtime.Val) runtime.Val {
var i int
if _, e := fmt.Fscanf(f.ctx.Stdin, "%d", &i); e != nil {
panic(e)
}
return runtime.Number(i)
}
2 changes: 1 addition & 1 deletion runtime/stdlib/math.go
Expand Up @@ -9,7 +9,7 @@ import (

type MathMod struct {
ctx *runtime.Ctx
ob *runtime.Object
ob runtime.Object
}

func (m *MathMod) ID() string {
Expand Down

0 comments on commit 73b4ae1

Please sign in to comment.