Slide 1

Slide 1 text

THE ISLISP INTERPRETER TANIGUCHI MASAYA @ SHIBUYA.LISP

Slide 2

Slide 2 text

INTRODUCE TANIGUCHI MASAYA ▸ ਺ֶΛઐ߈͍ͯ͠Δେֶੜ ▸ ܭࢉػ୅਺ॲཧܥʹ͍ͭͯษڧத ▸ CommonLisp, Go, JavaScript ͕޷͖ ▸ @ta2gch (Twitter / Github) ▸ ৄ͘͠͸https://ta2gch.github.ioΛ͝ཡ͍ͩ͘͞

Slide 3

Slide 3 text

AGENDA AGENDA ▸ Introduction to ISLisp and Iris ▸ History of the ISLisp ▸ The Features of the ISLisp ▸ The Features of the Iris ▸ The internals of Iris ▸ ILOS - ISLisp Object System ▸ Condition Systems of ISLisp ▸ Iris in the feature

Slide 4

Slide 4 text

INTRODUCTION TO ISLISP AND IRIS

Slide 5

Slide 5 text

INTRODUCTION TO ISLISP AND IRIS HISTORY OF ISLISP ▸ CommonLispʹ͍ͭͯޮ཰ͷྑ͞ͱֶशٴͼར༻ͷ༰қ͞ Λ໨ඪʹ֤ํݴΛࢀߟʹͯ͠։ൃ͞Εͨɻ ▸ ೔ຊͷKernel Languageͱ͍͏Ҋ͕౔୆ʹͳ͍ͬͯΔɻ ▸ ISO/IEC 13816:1997 - Programming Language ISLISP ▸ ISO/IEC 13816:2007 - Programming Language ISLISP ▸ OKI ISLisp Version 0.80 (1999/02/25)

Slide 6

Slide 6 text

INTRODUCTION TO ISLISP AND IRIS THE FEATURES OF ISLISP ▸ ILOS - ISLisp Object System͕͋Δ ▸ શͯͷܕ͕ILOSͷࢧ഑Լʹ͋Δ ▸ ੩తൣғΛجຊͱͭͭ͠΋ಈతൣғ͕ѻ͑Δ ▸ ίϯύΫτͳݴޠ࢓༷ (134ϖʔδఔ౓ʣ ▸ ύοέʔδ؅ཧγεςϜ͕ະࡦఆ ▸ PUBLIC DOMAINͷن֨ॻͷ૲Ҋ͕ެ։͞Ε͍ͯΔ ▸ ެࣜαΠτʹن֨४ڌ֬ೝ༻ͷݕূγεςϜ͕͋Δ

Slide 7

Slide 7 text

INTRODUCTION TO ISLISP AND IRIS DYNAMIC (defun http.request ()
 (format 
 (standard-output)
 “curl —X ~A ~A”
 (dynamic url)
 (dynamic method))) (dynamic-let
 ((url “islisp.js.org”)
 (method “GET”))
 (http.request)) ▸ΩʔϫʔυҾ਺͕ͳͯ͘΋ɺ
 ہॴಈతม਺Λ࢖ͬͯΩʔϫʔυҾ਺
 ͷΑ͏ͳ͜ͱ͕Ͱ͖Δ ▸CommonLispͱҧͬͯɺେҬม਺ͷΈ
 ಈతม਺ͱ͍͏͜ͱͰ͸ͳ͘ɺͲͪΒ΋
 ྆ํͷൣғΛαϙʔτ͍ͯ͠Δ

Slide 8

Slide 8 text

ࣗ࡞LISPɺ ࡞Γͨ͘ͳ͍ʁ

Slide 9

Slide 9 text

INTRODUCTION TO ISLISP AND IRIS IRIS ▸ 2017೥݄̓຤ΑΓ։ൃΛ։࢝ ▸ ISLispΠϯλϓϦλͷGoݴޠ࣮૷(8000ߦҐ) ▸ ެࣜαΠτ͸ islisp.js.org ▸ GopherjsʹΑΔJavaScript൛͕͋Δ ▸ ֦ுੑͷߴ͕͞ར఺ͱͳΔͷ༧ఆ ▸ ΫϩεϓϥοτϑΥʔϜ

Slide 10

Slide 10 text

INTRODUCTION TO ISLISP AND IRIS IRIS PLATFORMS ▸ Darwin ▸ Linux ▸ FreeBSD ▸ OpenBSD ▸ Windows ▸ NetBSD ▸ Plan9 ▸ Solaris ▸ Android ▸ Dragonfly Goͷαϙʔτ͢ΔϓϥοτϑΥʔϜ Gopherjsͷαϙʔτ͢ΔϓϥοτϑΥʔϜ ▸ Web Browsers ▸ Node.js

Slide 11

Slide 11 text

THE INTERNALS OF IRIS

Slide 12

Slide 12 text

THE INTERNALS OF IRIS OVERVIEW IRIS RUNTIME GOPHERJS GO CGO GO PLUGIN WEB BROWSERS NATIVE REPL NODE.JS WEB REPL JVM RHINO OS

Slide 13

Slide 13 text

THE INTERNALS OF IRIS ▸ GoݴޠͷϓϦϛςΟϒܕ(func, int, float, rune) ▸ ILOSࣗ਎͕༻ҙ͢ΔσʔλΛද͢ߏ଄ମͷܕ ▸ ILOSࣗ਎͕༻ҙ͢ΔΫϥεΛද͢ߏ଄ମͷܕ ▸ interfaceʹΑͬͯந৅Խͯ͠ಉ༷ʹѻ͏ɻ ILOS - ISLISP OBJECT SYSTEM

Slide 14

Slide 14 text

THE INTERNALS OF IRIS ILOS - ISLISP OBJECT SYSTEM type Class interface { Supers() []Class Slots() []Instance Initform(Instance) (Instance, bool) Initarg(Instance) (Instance, bool) Class() Class String() string } type Instance interface { Class() Class String() string } METACLASS 1 METACLASS 2 CLASS 1 CLASS 2 CLASS 3 INSTANCE 1 INSTANCE 3 INSTANCE 4 INSTANCE 2

Slide 15

Slide 15 text

THE INTERNALS OF IRIS ILOS - ISLISP OBJECT SYSTEM

Slide 16

Slide 16 text

THE INTERNALS OF IRIS ILOS - ISLISP OBJECT SYSTEM Meta Class

Slide 17

Slide 17 text

THE INTERNALS OF IRIS ILOS - ISLISP OBJECT SYSTEM Meta Class type Instance struct { class ilos.Class supers []ilos.Instance slots map[ilos.Instance]ilos.Instance }

Slide 18

Slide 18 text

THE INTERNALS OF IRIS ILOS - ISLISP OBJECT SYSTEM Meta Class

Slide 19

Slide 19 text

THE INTERNALS OF IRIS ILOS - ISLISP OBJECT SYSTEM Meta Class type Instance struct { class ilos.Class supers []ilos.Instance slots map[ilos.Instance]ilos.Instance }

Slide 20

Slide 20 text

THE INTERNALS OF IRIS ILOS - ISLISP OBJECT SYSTEM Array

Slide 21

Slide 21 text

THE INTERNALS OF IRIS ILOS - ISLISP OBJECT SYSTEM Array type GeneralArrayStar struct { Vector []GeneralArrayStar Scalar ilos.Instance }

Slide 22

Slide 22 text

THE INTERNALS OF IRIS ILOS - ISLISP OBJECT SYSTEM Array

Slide 23

Slide 23 text

THE INTERNALS OF IRIS ILOS - ISLISP OBJECT SYSTEM Array type GeneralVector []ilos.Instance

Slide 24

Slide 24 text

THE INTERNALS OF IRIS ILOS - ISLISP OBJECT SYSTEM Array

Slide 25

Slide 25 text

THE INTERNALS OF IRIS ILOS - ISLISP OBJECT SYSTEM Array type String []rune

Slide 26

Slide 26 text

THE INTERNALS OF IRIS ILOS - ISLISP OBJECT SYSTEM Character

Slide 27

Slide 27 text

THE INTERNALS OF IRIS ILOS - ISLISP OBJECT SYSTEM Character type Integer rune

Slide 28

Slide 28 text

THE INTERNALS OF IRIS ILOS - ISLISP OBJECT SYSTEM Function

Slide 29

Slide 29 text

THE INTERNALS OF IRIS ILOS - ISLISP OBJECT SYSTEM Function type Function struct { name ilos.Instance function interface{} }

Slide 30

Slide 30 text

THE INTERNALS OF IRIS ILOS - ISLISP OBJECT SYSTEM Function

Slide 31

Slide 31 text

THE INTERNALS OF IRIS ILOS - ISLISP OBJECT SYSTEM Function type method struct { qualifier ilos.Instance classList []ilos.Class function Function } type GenericFunction struct { funcSpec ilos.Instance lambdaList ilos.Instance methodCombination ilos.Instance genericFunctionClass ilos.Class methods []method }

Slide 32

Slide 32 text

THE INTERNALS OF IRIS ILOS - ISLISP OBJECT SYSTEM List and Symbol

Slide 33

Slide 33 text

THE INTERNALS OF IRIS ILOS - ISLISP OBJECT SYSTEM List and Symbol type Cons struct { Car ilos.Instance Cdr ilos.Instance }

Slide 34

Slide 34 text

THE INTERNALS OF IRIS ILOS - ISLISP OBJECT SYSTEM List and Symbol

Slide 35

Slide 35 text

THE INTERNALS OF IRIS ILOS - ISLISP OBJECT SYSTEM List and Symbol type Null struct {}

Slide 36

Slide 36 text

THE INTERNALS OF IRIS ILOS - ISLISP OBJECT SYSTEM List and Symbol

Slide 37

Slide 37 text

THE INTERNALS OF IRIS ILOS - ISLISP OBJECT SYSTEM List and Symbol type Symbol string

Slide 38

Slide 38 text

THE INTERNALS OF IRIS ILOS - ISLISP OBJECT SYSTEM Function

Slide 39

Slide 39 text

THE INTERNALS OF IRIS ILOS - ISLISP OBJECT SYSTEM Function type Float float64

Slide 40

Slide 40 text

THE INTERNALS OF IRIS ILOS - ISLISP OBJECT SYSTEM Function

Slide 41

Slide 41 text

THE INTERNALS OF IRIS ILOS - ISLISP OBJECT SYSTEM Function type Integer int

Slide 42

Slide 42 text

THE INTERNALS OF IRIS ILOS - ISLISP OBJECT SYSTEM Condition

Slide 43

Slide 43 text

THE INTERNALS OF IRIS ILOS - ISLISP OBJECT SYSTEM Condition type Instance struct { class ilos.Class supers []ilos.Instance slots map[ilos.Instance]ilos.Instance }

Slide 44

Slide 44 text

THE INTERNALS OF IRIS ILOS - ISLISP OBJECT SYSTEM Stream

Slide 45

Slide 45 text

THE INTERNALS OF IRIS ILOS - ISLISP OBJECT SYSTEM Stream type Stream struct { Reader io.Reader Writer io.Writer }

Slide 46

Slide 46 text

THE INTERNALS OF IRIS FUNCTION INSTANCE OF FUNCTION NATIVE FUNCTION .APPLY ENVIRONMENT INSTANCE INSTANCE INSTANCE INSTANCE Arguments - Reflection Return Escaping (defun foo (a) a)

Slide 47

Slide 47 text

THE INTERNALS OF IRIS FUNCTION func Car(e env.Environment, cons ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Cons, cons); err != nil { return nil, err } return cons.(*instance.Cons).Car, nil }

Slide 48

Slide 48 text

THE INTERNALS OF IRIS FUNCTION func Car(e env.Environment, cons ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Cons, cons); err != nil { return nil, err } return cons.(*instance.Cons).Car, nil } type Environment struct { // Lexical BlockTag stack TagbodyTag stack Function stack Variable stack // Global Class stack Macro stack Special stack Property map2 GensymID int Constant stack // Dynamic CatchTag stack DynamicVariable stack StandardInput ilos.Instance StandardOutput ilos.Instance ErrorOutput ilos.Instance Handler ilos.Instance }

Slide 49

Slide 49 text

THE INTERNALS OF IRIS FUNCTION func Car(e env.Environment, cons ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Cons, cons); err != nil { return nil, err } return cons.(*instance.Cons).Car, nil }

Slide 50

Slide 50 text

THE INTERNALS OF IRIS FUNCTION func Car(e env.Environment, cons ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Cons, cons); err != nil { return nil, err } return cons.(*instance.Cons).Car, nil } type Instance interface { Class() Class String() string }

Slide 51

Slide 51 text

THE INTERNALS OF IRIS FUNCTION func Car(e env.Environment, cons ilos.Instance) (ilos.Instance, ilos.Instance) { if err := ensure(class.Cons, cons); err != nil { return nil, err } return cons.(*instance.Cons).Car, nil }

Slide 52

Slide 52 text

THE INTERNALS OF IRIS GENERIC FUNCTION INSTANCE OF GENERIC FUNCTION NATIVE FUNCTION .APPLY ENVIRONMENT INSTANCE INSTANCE INSTANCE INSTANCE Arguments Return Escaping NATIVE FUNCTION NATIVE FUNCTION - Selection
 - Ordering
 - Reflection
 - Combination (defgeneric foo (foo bar))
 (defmethod foo :around ((foo A) (bar B)) nil)

Slide 53

Slide 53 text

THE INTERNALS OF IRIS GENERIC FUNCTION INSTANCE OF GENERIC FUNCTION NATIVE FUNCTION .APPLY ENVIRONMENT INSTANCE INSTANCE INSTANCE INSTANCE Arguments Return Escaping NATIVE FUNCTION NATIVE FUNCTION - Selection
 - Ordering
 - Reflection
 - Combination (defgeneric foo (foo bar))
 (defmethod foo :around ((foo A) (bar B)) nil)

Slide 54

Slide 54 text

THE INTERNALS OF IRIS GENERIC FUNCTION 1. Simple Combination (nil) ▸ ༏ઌॱҐΛܾఆ ▸ ࠷༏ઌؔ਺ͷ໭Γ஋͕แׅؔ਺ͷ໭Γ஋ͱͳΔ ▸ CALL-NEXT-METHODͰ࣍఺༏ઌؔ਺Λݺͼग़ͤΔ 2. Standard Combination (نఆ) ▸ ༏ઌॱҐΛܾఆ ▸ ࠷༏ઌؔ਺ͷ໭Γ஋͕แׅؔ਺ͷ໭Γ஋ͱͳΔ ▸ :around → (:before) → ࢦఆແ͠ →(:after)ɹͷॱͰ࣮ߦ ▸ :aroundͱࢦఆແ͠ͷؔ਺͸CALL-NEXT-METHODͰ࣍఺༏ઌؔ਺Λݺͼग़ͤΔ

Slide 55

Slide 55 text

THE INTERNALS OF IRIS GENERIC FUNCTION e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } return methods[0].function.Apply(e, arguments ...) //Call first of method } // if f.methodCombination == NewSymbol("STANDARD") { test := func(i int) bool { return methods[i].qualifier == around } width := len(methods) if index := sort.Search(width, test); index < width { // if has :around methods // This callNextMethod is called in :around methods var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth for index, method := range methods[:int(depth.(Integer))+1] { if method.qualifier == around { // If have :around method e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set Current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil || methods[index+i+1].qualifier == around } if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } return methods[int(depth.(Integer))].function.Apply(e, arguments ...) // Call next method } } // If has no :around method then, // Do All :before mehtods for _, method := range methods { if method.qualifier == before { if _, err := method.function.Apply(e, arguments ...); err != nil { return nil, err } } } // Do the first of primary methods // this callNextMethod is called in primary methods var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth index := int(depth.(Integer)) // Convert depth to integer { width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil } index = sort.Search(width, test) // Get index of next mehotd e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set current depth } // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil } if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } return methods[index].function.Apply(e, arguments ...) // Call next method } // callNextMethod ends here index := 0 // index of the first primary method { // index != 0 is always true because this function has :around methods width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil } index = sort.Search(width, test) e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) } // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } // Do primary methods ret, err := methods[index].function.Apply(e, arguments ...) if err != nil { return nil, err } // Do all :after methods for i := len(methods) - 1; i >= 0; i -- { if methods[i].qualifier == after { if _, err := methods[i].function.Apply(e, arguments ...); err != nil { return nil, err } } } return ret, err } e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set Current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } return methods[index].function.Apply(e, arguments ...) } } { // Function has no :around methods // This callNextMethod is called in primary methods var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth index := int(depth.(Integer)) // Convert depth to integer { test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 index = sort.Search(width, test) } e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set Current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } return methods[int(depth.(Integer))].function.Apply(e, arguments ...) } // callNextMethod ends here // Do All :before mehtods for _, method := range methods { if method.qualifier == before { if _, err := method.function.Apply(e, arguments ...); err != nil { return nil, err } } } index := 0 // index of the first primary method { test := func(i int) bool { return methods[i].qualifier == nil } width := len(methods) index := sort.Search(width, test) e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) if index == len(methods) { return nil, NewUndefinedFunction(f.funcSpec) } } e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functions test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } ret, err := methods[index].function.Apply(e, arguments ...) // Do all :after methods for i := len(methods) - 1; i >= 0; i -- { if methods[i].qualifier == after { if _, err := methods[i].function.Apply(e, arguments ...); err != nil { return nil, err } } } return ret, err // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http: //mozilla.org/MPL/2.0/. package instance import ( "fmt" "reflect" "sort" "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" ) type Applicable interface { Apply(env.Environment, ...ilos.Instance) (ilos.Instance, ilos.Instance) } type Function struct { name ilos.Instance function interface{} } func NewFunction(name ilos.Instance, function interface{}) ilos.Instance { return Function{name, function} } func (Function) Class() ilos.Class { return FunctionClass } func (f Function) String() string { return fmt.Sprintf("#%v", f.Class()) } func (f Function) Apply(e env.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { fv := reflect.ValueOf(f.function) ft := reflect.TypeOf(f.function) argv := []reflect.Value{reflect.ValueOf(e)} for _, cadr := range arguments { argv = append(argv, reflect.ValueOf(cadr)) } if ft.NumIn() != len(argv) && (!ft.IsVariadic() || ft.NumIn()-2 >= len(argv)) { return nil, NewArityError() } rets := fv.Call(argv) a, _ := rets[0].Interface().(ilos.Instance) b, _ := rets[1].Interface().(ilos.Instance) return a, b } type method struct { qualifier ilos.Instance classList []ilos.Class function Function } type GenericFunction struct { funcSpec ilos.Instance lambdaList ilos.Instance methodCombination ilos.Instance genericFunctionClass ilos.Class methods []method } func NewGenericFunction(funcSpec, lambdaList, methodCombination ilos.Instance, genericFunctionClass ilos.Class) ilos.Instance { return &GenericFunction{funcSpec, lambdaList, methodCombination, genericFunctionClass, []method{}} } func (f *GenericFunction) AddMethod(qualifier, lambdaList ilos.Instance, classList []ilos.Class, function ilos.Instance) bool { if f.lambdaList.(List).Length() != lambdaList.(List).Length() { return false } for i, param := range f.lambdaList.(List).Slice() { if param == NewSymbol(":REST") || param == NewSymbol("&REST") { if lambdaList.(List).Nth(i) != NewSymbol(":REST") && lambdaList.(List).Nth(i) != NewSymbol("&REST") { return false } } } for i := range f.methods { if f.methods[i].qualifier == qualifier && reflect.DeepEqual(f.methods[i].classList, classList) { f.methods[i].function = function.(Function) return true } } f.methods = append(f.methods, method{qualifier, classList, function.(Function)}) return true } func (f *GenericFunction) Class() ilos.Class { return f.genericFunctionClass } func (f *GenericFunction) String() string { return fmt.Sprintf("#%v", f.Class()) } func (f *GenericFunction) Apply(e env.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { parameters := f.lambdaList.(List).Slice() variadic := false { test := func(i int) bool { return parameters[i] == NewSymbol(":REST") || parameters[i] == NewSymbol("&REST") } if sort.Search(len(parameters), test) < len(parameters) { variadic = true } } if (variadic && len(parameters)-2 > len(arguments)) || (!variadic && len(parameters) != len(arguments)) { return nil, NewArityError() } methods := []method{} for _, method := range f.methods { matched := true for i, c := range method.classList { if !ilos.InstanceOf(c, arguments[i]) { matched = false break } } if matched { methods = append(methods, method) } } before := NewSymbol(":BEFORE") around := NewSymbol(":AROUND") after := NewSymbol(":AFTER") sort.Slice(methods, func(a, b int) bool { for i := range methods[a].classList { if ilos.SubclassOf(methods[a].classList[i], methods[b].classList[i]) { return false } if ilos.SubclassOf(methods[b].classList[i], methods[a].classList[i]) { return true } } t := map[ilos.Instance]int{around: 4, before: 3, nil: 2, after: 1} return t[methods[a].qualifier] > t[methods[b].qualifier] }) nextMethodPisNil := NewFunction(NewSymbol("NEXT-METHOD-P"), func(e env.Environment) (ilos.Instance, ilos.Instance) { return Nil, nil }) nextMethodPisT := NewFunction(NewSymbol("NEXT-METHOD-P"), func(e env.Environment) (ilos.Instance, ilos.Instance) { return T, nil }) if f.methodCombination == NewSymbol("NIL") { var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) // To Recursive callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { // CALL-NEXT-METHOD depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth index := int(depth.(Integer)) + 1 // Get index of next method e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil)) if int(depth.(Integer))+1 < len(methods) { // If Generic Function has next method, set these functionss e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisT)) } return methods[index].function.Apply(e, arguments ...) // Call next method } e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(0)) // Set current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil)) if 1 < len(methods) { // If Generic Function has next method, set these functionss e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisT))

Slide 56

Slide 56 text

THE INTERNALS OF IRIS GENERIC FUNCTION e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } return methods[0].function.Apply(e, arguments ...) //Call first of method } // if f.methodCombination == NewSymbol("STANDARD") { test := func(i int) bool { return methods[i].qualifier == around } width := len(methods) if index := sort.Search(width, test); index < width { // if has :around methods // This callNextMethod is called in :around methods var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth for index, method := range methods[:int(depth.(Integer))+1] { if method.qualifier == around { // If have :around method e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set Current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil || methods[index+i+1].qualifier == around } if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } return methods[int(depth.(Integer))].function.Apply(e, arguments ...) // Call next method } } // If has no :around method then, // Do All :before mehtods for _, method := range methods { if method.qualifier == before { if _, err := method.function.Apply(e, arguments ...); err != nil { return nil, err } } } // Do the first of primary methods // this callNextMethod is called in primary methods var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth index := int(depth.(Integer)) // Convert depth to integer { width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil } index = sort.Search(width, test) // Get index of next mehotd e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set current depth } // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil } if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } return methods[index].function.Apply(e, arguments ...) // Call next method } // callNextMethod ends here index := 0 // index of the first primary method { // index != 0 is always true because this function has :around methods width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil } index = sort.Search(width, test) e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) } // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } // Do primary methods ret, err := methods[index].function.Apply(e, arguments ...) if err != nil { return nil, err } // Do all :after methods for i := len(methods) - 1; i >= 0; i -- { if methods[i].qualifier == after { if _, err := methods[i].function.Apply(e, arguments ...); err != nil { return nil, err } } } return ret, err } e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set Current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } return methods[index].function.Apply(e, arguments ...) } } { // Function has no :around methods // This callNextMethod is called in primary methods var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth index := int(depth.(Integer)) // Convert depth to integer { test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 index = sort.Search(width, test) } e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set Current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } return methods[int(depth.(Integer))].function.Apply(e, arguments ...) } // callNextMethod ends here // Do All :before mehtods for _, method := range methods { if method.qualifier == before { if _, err := method.function.Apply(e, arguments ...); err != nil { return nil, err } } } index := 0 // index of the first primary method { test := func(i int) bool { return methods[i].qualifier == nil } width := len(methods) index := sort.Search(width, test) e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) if index == len(methods) { return nil, NewUndefinedFunction(f.funcSpec) } } e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functions test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } ret, err := methods[index].function.Apply(e, arguments ...) // Do all :after methods for i := len(methods) - 1; i >= 0; i -- { if methods[i].qualifier == after { if _, err := methods[i].function.Apply(e, arguments ...); err != nil { return nil, err } } } return ret, err // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http: //mozilla.org/MPL/2.0/. package instance import ( "fmt" "reflect" "sort" "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" ) type Applicable interface { Apply(env.Environment, ...ilos.Instance) (ilos.Instance, ilos.Instance) } type Function struct { name ilos.Instance function interface{} } func NewFunction(name ilos.Instance, function interface{}) ilos.Instance { return Function{name, function} } func (Function) Class() ilos.Class { return FunctionClass } func (f Function) String() string { return fmt.Sprintf("#%v", f.Class()) } func (f Function) Apply(e env.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { fv := reflect.ValueOf(f.function) ft := reflect.TypeOf(f.function) argv := []reflect.Value{reflect.ValueOf(e)} for _, cadr := range arguments { argv = append(argv, reflect.ValueOf(cadr)) } if ft.NumIn() != len(argv) && (!ft.IsVariadic() || ft.NumIn()-2 >= len(argv)) { return nil, NewArityError() } rets := fv.Call(argv) a, _ := rets[0].Interface().(ilos.Instance) b, _ := rets[1].Interface().(ilos.Instance) return a, b } type method struct { qualifier ilos.Instance classList []ilos.Class function Function } type GenericFunction struct { funcSpec ilos.Instance lambdaList ilos.Instance methodCombination ilos.Instance genericFunctionClass ilos.Class methods []method } func NewGenericFunction(funcSpec, lambdaList, methodCombination ilos.Instance, genericFunctionClass ilos.Class) ilos.Instance { return &GenericFunction{funcSpec, lambdaList, methodCombination, genericFunctionClass, []method{}} } func (f *GenericFunction) AddMethod(qualifier, lambdaList ilos.Instance, classList []ilos.Class, function ilos.Instance) bool { if f.lambdaList.(List).Length() != lambdaList.(List).Length() { return false } for i, param := range f.lambdaList.(List).Slice() { if param == NewSymbol(":REST") || param == NewSymbol("&REST") { if lambdaList.(List).Nth(i) != NewSymbol(":REST") && lambdaList.(List).Nth(i) != NewSymbol("&REST") { return false } } } for i := range f.methods { if f.methods[i].qualifier == qualifier && reflect.DeepEqual(f.methods[i].classList, classList) { f.methods[i].function = function.(Function) return true } } f.methods = append(f.methods, method{qualifier, classList, function.(Function)}) return true } func (f *GenericFunction) Class() ilos.Class { return f.genericFunctionClass } func (f *GenericFunction) String() string { return fmt.Sprintf("#%v", f.Class()) } func (f *GenericFunction) Apply(e env.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { parameters := f.lambdaList.(List).Slice() variadic := false { test := func(i int) bool { return parameters[i] == NewSymbol(":REST") || parameters[i] == NewSymbol("&REST") } if sort.Search(len(parameters), test) < len(parameters) { variadic = true } } if (variadic && len(parameters)-2 > len(arguments)) || (!variadic && len(parameters) != len(arguments)) { return nil, NewArityError() } methods := []method{} for _, method := range f.methods { matched := true for i, c := range method.classList { if !ilos.InstanceOf(c, arguments[i]) { matched = false break } } if matched { methods = append(methods, method) } } before := NewSymbol(":BEFORE") around := NewSymbol(":AROUND") after := NewSymbol(":AFTER") sort.Slice(methods, func(a, b int) bool { for i := range methods[a].classList { if ilos.SubclassOf(methods[a].classList[i], methods[b].classList[i]) { return false } if ilos.SubclassOf(methods[b].classList[i], methods[a].classList[i]) { return true } } t := map[ilos.Instance]int{around: 4, before: 3, nil: 2, after: 1} return t[methods[a].qualifier] > t[methods[b].qualifier] }) nextMethodPisNil := NewFunction(NewSymbol("NEXT-METHOD-P"), func(e env.Environment) (ilos.Instance, ilos.Instance) { return Nil, nil }) nextMethodPisT := NewFunction(NewSymbol("NEXT-METHOD-P"), func(e env.Environment) (ilos.Instance, ilos.Instance) { return T, nil }) if f.methodCombination == NewSymbol("NIL") { var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) // To Recursive callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { // CALL-NEXT-METHOD depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth index := int(depth.(Integer)) + 1 // Get index of next method e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil)) if int(depth.(Integer))+1 < len(methods) { // If Generic Function has next method, set these functionss e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisT)) } return methods[index].function.Apply(e, arguments ...) // Call next method } e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(0)) // Set current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil)) if 1 < len(methods) { // If Generic Function has next method, set these functionss e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisT))

Slide 57

Slide 57 text

THE INTERNALS OF IRIS GENERIC FUNCTION e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } return methods[0].function.Apply(e, arguments ...) //Call first of method } // if f.methodCombination == NewSymbol("STANDARD") { test := func(i int) bool { return methods[i].qualifier == around } width := len(methods) if index := sort.Search(width, test); index < width { // if has :around methods // This callNextMethod is called in :around methods var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth for index, method := range methods[:int(depth.(Integer))+1] { if method.qualifier == around { // If have :around method e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set Current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil || methods[index+i+1].qualifier == around } if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } return methods[int(depth.(Integer))].function.Apply(e, arguments ...) // Call next method } } // If has no :around method then, // Do All :before mehtods for _, method := range methods { if method.qualifier == before { if _, err := method.function.Apply(e, arguments ...); err != nil { return nil, err } } } // Do the first of primary methods // this callNextMethod is called in primary methods var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth index := int(depth.(Integer)) // Convert depth to integer { width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil } index = sort.Search(width, test) // Get index of next mehotd e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set current depth } // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil } if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } return methods[index].function.Apply(e, arguments ...) // Call next method } // callNextMethod ends here index := 0 // index of the first primary method { // index != 0 is always true because this function has :around methods width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil } index = sort.Search(width, test) e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) } // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } // Do primary methods ret, err := methods[index].function.Apply(e, arguments ...) if err != nil { return nil, err } // Do all :after methods for i := len(methods) - 1; i >= 0; i -- { if methods[i].qualifier == after { if _, err := methods[i].function.Apply(e, arguments ...); err != nil { return nil, err } } } return ret, err } e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set Current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } return methods[index].function.Apply(e, arguments ...) } } { // Function has no :around methods // This callNextMethod is called in primary methods var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth index := int(depth.(Integer)) // Convert depth to integer { test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 index = sort.Search(width, test) } e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set Current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } return methods[int(depth.(Integer))].function.Apply(e, arguments ...) } // callNextMethod ends here // Do All :before mehtods for _, method := range methods { if method.qualifier == before { if _, err := method.function.Apply(e, arguments ...); err != nil { return nil, err } } } index := 0 // index of the first primary method { test := func(i int) bool { return methods[i].qualifier == nil } width := len(methods) index := sort.Search(width, test) e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) if index == len(methods) { return nil, NewUndefinedFunction(f.funcSpec) } } e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functions test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } ret, err := methods[index].function.Apply(e, arguments ...) // Do all :after methods for i := len(methods) - 1; i >= 0; i -- { if methods[i].qualifier == after { if _, err := methods[i].function.Apply(e, arguments ...); err != nil { return nil, err } } } return ret, err // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http: //mozilla.org/MPL/2.0/. package instance import ( "fmt" "reflect" "sort" "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" ) type Applicable interface { Apply(env.Environment, ...ilos.Instance) (ilos.Instance, ilos.Instance) } type Function struct { name ilos.Instance function interface{} } func NewFunction(name ilos.Instance, function interface{}) ilos.Instance { return Function{name, function} } func (Function) Class() ilos.Class { return FunctionClass } func (f Function) String() string { return fmt.Sprintf("#%v", f.Class()) } func (f Function) Apply(e env.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { fv := reflect.ValueOf(f.function) ft := reflect.TypeOf(f.function) argv := []reflect.Value{reflect.ValueOf(e)} for _, cadr := range arguments { argv = append(argv, reflect.ValueOf(cadr)) } if ft.NumIn() != len(argv) && (!ft.IsVariadic() || ft.NumIn()-2 >= len(argv)) { return nil, NewArityError() } rets := fv.Call(argv) a, _ := rets[0].Interface().(ilos.Instance) b, _ := rets[1].Interface().(ilos.Instance) return a, b } type method struct { qualifier ilos.Instance classList []ilos.Class function Function } type GenericFunction struct { funcSpec ilos.Instance lambdaList ilos.Instance methodCombination ilos.Instance genericFunctionClass ilos.Class methods []method } func NewGenericFunction(funcSpec, lambdaList, methodCombination ilos.Instance, genericFunctionClass ilos.Class) ilos.Instance { return &GenericFunction{funcSpec, lambdaList, methodCombination, genericFunctionClass, []method{}} } func (f *GenericFunction) AddMethod(qualifier, lambdaList ilos.Instance, classList []ilos.Class, function ilos.Instance) bool { if f.lambdaList.(List).Length() != lambdaList.(List).Length() { return false } for i, param := range f.lambdaList.(List).Slice() { if param == NewSymbol(":REST") || param == NewSymbol("&REST") { if lambdaList.(List).Nth(i) != NewSymbol(":REST") && lambdaList.(List).Nth(i) != NewSymbol("&REST") { return false } } } for i := range f.methods { if f.methods[i].qualifier == qualifier && reflect.DeepEqual(f.methods[i].classList, classList) { f.methods[i].function = function.(Function) return true } } f.methods = append(f.methods, method{qualifier, classList, function.(Function)}) return true } func (f *GenericFunction) Class() ilos.Class { return f.genericFunctionClass } func (f *GenericFunction) String() string { return fmt.Sprintf("#%v", f.Class()) } func (f *GenericFunction) Apply(e env.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { parameters := f.lambdaList.(List).Slice() variadic := false { test := func(i int) bool { return parameters[i] == NewSymbol(":REST") || parameters[i] == NewSymbol("&REST") } if sort.Search(len(parameters), test) < len(parameters) { variadic = true } } if (variadic && len(parameters)-2 > len(arguments)) || (!variadic && len(parameters) != len(arguments)) { return nil, NewArityError() } methods := []method{} for _, method := range f.methods { matched := true for i, c := range method.classList { if !ilos.InstanceOf(c, arguments[i]) { matched = false break } } if matched { methods = append(methods, method) } } before := NewSymbol(":BEFORE") around := NewSymbol(":AROUND") after := NewSymbol(":AFTER") sort.Slice(methods, func(a, b int) bool { for i := range methods[a].classList { if ilos.SubclassOf(methods[a].classList[i], methods[b].classList[i]) { return false } if ilos.SubclassOf(methods[b].classList[i], methods[a].classList[i]) { return true } } t := map[ilos.Instance]int{around: 4, before: 3, nil: 2, after: 1} return t[methods[a].qualifier] > t[methods[b].qualifier] }) nextMethodPisNil := NewFunction(NewSymbol("NEXT-METHOD-P"), func(e env.Environment) (ilos.Instance, ilos.Instance) { return Nil, nil }) nextMethodPisT := NewFunction(NewSymbol("NEXT-METHOD-P"), func(e env.Environment) (ilos.Instance, ilos.Instance) { return T, nil }) if f.methodCombination == NewSymbol("NIL") { var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) // To Recursive callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { // CALL-NEXT-METHOD depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth index := int(depth.(Integer)) + 1 // Get index of next method e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil)) if int(depth.(Integer))+1 < len(methods) { // If Generic Function has next method, set these functionss e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisT)) } return methods[index].function.Apply(e, arguments ...) // Call next method } e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(0)) // Set current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil)) if 1 < len(methods) { // If Generic Function has next method, set these functionss e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisT)) ௨ৗͷؔ਺ͷؔ਺ݺͼग़͠ͷ࣮૷ ϦϑϨΫγϣϯΛ࢖ͬͯωΠςΟϒؔ਺Λ ݺͼग़͢ɻ

Slide 58

Slide 58 text

THE INTERNALS OF IRIS GENERIC FUNCTION e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } return methods[0].function.Apply(e, arguments ...) //Call first of method } // if f.methodCombination == NewSymbol("STANDARD") { test := func(i int) bool { return methods[i].qualifier == around } width := len(methods) if index := sort.Search(width, test); index < width { // if has :around methods // This callNextMethod is called in :around methods var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth for index, method := range methods[:int(depth.(Integer))+1] { if method.qualifier == around { // If have :around method e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set Current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil || methods[index+i+1].qualifier == around } if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } return methods[int(depth.(Integer))].function.Apply(e, arguments ...) // Call next method } } // If has no :around method then, // Do All :before mehtods for _, method := range methods { if method.qualifier == before { if _, err := method.function.Apply(e, arguments ...); err != nil { return nil, err } } } // Do the first of primary methods // this callNextMethod is called in primary methods var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth index := int(depth.(Integer)) // Convert depth to integer { width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil } index = sort.Search(width, test) // Get index of next mehotd e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set current depth } // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil } if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } return methods[index].function.Apply(e, arguments ...) // Call next method } // callNextMethod ends here index := 0 // index of the first primary method { // index != 0 is always true because this function has :around methods width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil } index = sort.Search(width, test) e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) } // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } // Do primary methods ret, err := methods[index].function.Apply(e, arguments ...) if err != nil { return nil, err } // Do all :after methods for i := len(methods) - 1; i >= 0; i -- { if methods[i].qualifier == after { if _, err := methods[i].function.Apply(e, arguments ...); err != nil { return nil, err } } } return ret, err } e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set Current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } return methods[index].function.Apply(e, arguments ...) } } { // Function has no :around methods // This callNextMethod is called in primary methods var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth index := int(depth.(Integer)) // Convert depth to integer { test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 index = sort.Search(width, test) } e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set Current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } return methods[int(depth.(Integer))].function.Apply(e, arguments ...) } // callNextMethod ends here // Do All :before mehtods for _, method := range methods { if method.qualifier == before { if _, err := method.function.Apply(e, arguments ...); err != nil { return nil, err } } } index := 0 // index of the first primary method { test := func(i int) bool { return methods[i].qualifier == nil } width := len(methods) index := sort.Search(width, test) e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) if index == len(methods) { return nil, NewUndefinedFunction(f.funcSpec) } } e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functions test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } ret, err := methods[index].function.Apply(e, arguments ...) // Do all :after methods for i := len(methods) - 1; i >= 0; i -- { if methods[i].qualifier == after { if _, err := methods[i].function.Apply(e, arguments ...); err != nil { return nil, err } } } return ret, err // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http: //mozilla.org/MPL/2.0/. package instance import ( "fmt" "reflect" "sort" "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" ) type Applicable interface { Apply(env.Environment, ...ilos.Instance) (ilos.Instance, ilos.Instance) } type Function struct { name ilos.Instance function interface{} } func NewFunction(name ilos.Instance, function interface{}) ilos.Instance { return Function{name, function} } func (Function) Class() ilos.Class { return FunctionClass } func (f Function) String() string { return fmt.Sprintf("#%v", f.Class()) } func (f Function) Apply(e env.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { fv := reflect.ValueOf(f.function) ft := reflect.TypeOf(f.function) argv := []reflect.Value{reflect.ValueOf(e)} for _, cadr := range arguments { argv = append(argv, reflect.ValueOf(cadr)) } if ft.NumIn() != len(argv) && (!ft.IsVariadic() || ft.NumIn()-2 >= len(argv)) { return nil, NewArityError() } rets := fv.Call(argv) a, _ := rets[0].Interface().(ilos.Instance) b, _ := rets[1].Interface().(ilos.Instance) return a, b } type method struct { qualifier ilos.Instance classList []ilos.Class function Function } type GenericFunction struct { funcSpec ilos.Instance lambdaList ilos.Instance methodCombination ilos.Instance genericFunctionClass ilos.Class methods []method } func NewGenericFunction(funcSpec, lambdaList, methodCombination ilos.Instance, genericFunctionClass ilos.Class) ilos.Instance { return &GenericFunction{funcSpec, lambdaList, methodCombination, genericFunctionClass, []method{}} } func (f *GenericFunction) AddMethod(qualifier, lambdaList ilos.Instance, classList []ilos.Class, function ilos.Instance) bool { if f.lambdaList.(List).Length() != lambdaList.(List).Length() { return false } for i, param := range f.lambdaList.(List).Slice() { if param == NewSymbol(":REST") || param == NewSymbol("&REST") { if lambdaList.(List).Nth(i) != NewSymbol(":REST") && lambdaList.(List).Nth(i) != NewSymbol("&REST") { return false } } } for i := range f.methods { if f.methods[i].qualifier == qualifier && reflect.DeepEqual(f.methods[i].classList, classList) { f.methods[i].function = function.(Function) return true } } f.methods = append(f.methods, method{qualifier, classList, function.(Function)}) return true } func (f *GenericFunction) Class() ilos.Class { return f.genericFunctionClass } func (f *GenericFunction) String() string { return fmt.Sprintf("#%v", f.Class()) } func (f *GenericFunction) Apply(e env.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { parameters := f.lambdaList.(List).Slice() variadic := false { test := func(i int) bool { return parameters[i] == NewSymbol(":REST") || parameters[i] == NewSymbol("&REST") } if sort.Search(len(parameters), test) < len(parameters) { variadic = true } } if (variadic && len(parameters)-2 > len(arguments)) || (!variadic && len(parameters) != len(arguments)) { return nil, NewArityError() } methods := []method{} for _, method := range f.methods { matched := true for i, c := range method.classList { if !ilos.InstanceOf(c, arguments[i]) { matched = false break } } if matched { methods = append(methods, method) } } before := NewSymbol(":BEFORE") around := NewSymbol(":AROUND") after := NewSymbol(":AFTER") sort.Slice(methods, func(a, b int) bool { for i := range methods[a].classList { if ilos.SubclassOf(methods[a].classList[i], methods[b].classList[i]) { return false } if ilos.SubclassOf(methods[b].classList[i], methods[a].classList[i]) { return true } } t := map[ilos.Instance]int{around: 4, before: 3, nil: 2, after: 1} return t[methods[a].qualifier] > t[methods[b].qualifier] }) nextMethodPisNil := NewFunction(NewSymbol("NEXT-METHOD-P"), func(e env.Environment) (ilos.Instance, ilos.Instance) { return Nil, nil }) nextMethodPisT := NewFunction(NewSymbol("NEXT-METHOD-P"), func(e env.Environment) (ilos.Instance, ilos.Instance) { return T, nil }) if f.methodCombination == NewSymbol("NIL") { var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) // To Recursive callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { // CALL-NEXT-METHOD depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth index := int(depth.(Integer)) + 1 // Get index of next method e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil)) if int(depth.(Integer))+1 < len(methods) { // If Generic Function has next method, set these functionss e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisT)) } return methods[index].function.Apply(e, arguments ...) // Call next method } e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(0)) // Set current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil)) if 1 < len(methods) { // If Generic Function has next method, set these functionss e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisT)) ௨ৗͷؔ਺ͷؔ਺ݺͼग़͠ͷ࣮૷ ϦϑϨΫγϣϯΛ࢖ͬͯωΠςΟϒؔ਺Λ ݺͼग़͢ɻ

Slide 59

Slide 59 text

THE INTERNALS OF IRIS GENERIC FUNCTION e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } return methods[0].function.Apply(e, arguments ...) //Call first of method } // if f.methodCombination == NewSymbol("STANDARD") { test := func(i int) bool { return methods[i].qualifier == around } width := len(methods) if index := sort.Search(width, test); index < width { // if has :around methods // This callNextMethod is called in :around methods var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth for index, method := range methods[:int(depth.(Integer))+1] { if method.qualifier == around { // If have :around method e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set Current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil || methods[index+i+1].qualifier == around } if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } return methods[int(depth.(Integer))].function.Apply(e, arguments ...) // Call next method } } // If has no :around method then, // Do All :before mehtods for _, method := range methods { if method.qualifier == before { if _, err := method.function.Apply(e, arguments ...); err != nil { return nil, err } } } // Do the first of primary methods // this callNextMethod is called in primary methods var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth index := int(depth.(Integer)) // Convert depth to integer { width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil } index = sort.Search(width, test) // Get index of next mehotd e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set current depth } // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil } if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } return methods[index].function.Apply(e, arguments ...) // Call next method } // callNextMethod ends here index := 0 // index of the first primary method { // index != 0 is always true because this function has :around methods width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil } index = sort.Search(width, test) e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) } // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } // Do primary methods ret, err := methods[index].function.Apply(e, arguments ...) if err != nil { return nil, err } // Do all :after methods for i := len(methods) - 1; i >= 0; i -- { if methods[i].qualifier == after { if _, err := methods[i].function.Apply(e, arguments ...); err != nil { return nil, err } } } return ret, err } e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set Current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } return methods[index].function.Apply(e, arguments ...) } } { // Function has no :around methods // This callNextMethod is called in primary methods var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth index := int(depth.(Integer)) // Convert depth to integer { test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 index = sort.Search(width, test) } e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set Current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } return methods[int(depth.(Integer))].function.Apply(e, arguments ...) } // callNextMethod ends here // Do All :before mehtods for _, method := range methods { if method.qualifier == before { if _, err := method.function.Apply(e, arguments ...); err != nil { return nil, err } } } index := 0 // index of the first primary method { test := func(i int) bool { return methods[i].qualifier == nil } width := len(methods) index := sort.Search(width, test) e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) if index == len(methods) { return nil, NewUndefinedFunction(f.funcSpec) } } e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functions test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } ret, err := methods[index].function.Apply(e, arguments ...) // Do all :after methods for i := len(methods) - 1; i >= 0; i -- { if methods[i].qualifier == after { if _, err := methods[i].function.Apply(e, arguments ...); err != nil { return nil, err } } } return ret, err // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http: //mozilla.org/MPL/2.0/. package instance import ( "fmt" "reflect" "sort" "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" ) type Applicable interface { Apply(env.Environment, ...ilos.Instance) (ilos.Instance, ilos.Instance) } type Function struct { name ilos.Instance function interface{} } func NewFunction(name ilos.Instance, function interface{}) ilos.Instance { return Function{name, function} } func (Function) Class() ilos.Class { return FunctionClass } func (f Function) String() string { return fmt.Sprintf("#%v", f.Class()) } func (f Function) Apply(e env.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { fv := reflect.ValueOf(f.function) ft := reflect.TypeOf(f.function) argv := []reflect.Value{reflect.ValueOf(e)} for _, cadr := range arguments { argv = append(argv, reflect.ValueOf(cadr)) } if ft.NumIn() != len(argv) && (!ft.IsVariadic() || ft.NumIn()-2 >= len(argv)) { return nil, NewArityError() } rets := fv.Call(argv) a, _ := rets[0].Interface().(ilos.Instance) b, _ := rets[1].Interface().(ilos.Instance) return a, b } type method struct { qualifier ilos.Instance classList []ilos.Class function Function } type GenericFunction struct { funcSpec ilos.Instance lambdaList ilos.Instance methodCombination ilos.Instance genericFunctionClass ilos.Class methods []method } func NewGenericFunction(funcSpec, lambdaList, methodCombination ilos.Instance, genericFunctionClass ilos.Class) ilos.Instance { return &GenericFunction{funcSpec, lambdaList, methodCombination, genericFunctionClass, []method{}} } func (f *GenericFunction) AddMethod(qualifier, lambdaList ilos.Instance, classList []ilos.Class, function ilos.Instance) bool { if f.lambdaList.(List).Length() != lambdaList.(List).Length() { return false } for i, param := range f.lambdaList.(List).Slice() { if param == NewSymbol(":REST") || param == NewSymbol("&REST") { if lambdaList.(List).Nth(i) != NewSymbol(":REST") && lambdaList.(List).Nth(i) != NewSymbol("&REST") { return false } } } for i := range f.methods { if f.methods[i].qualifier == qualifier && reflect.DeepEqual(f.methods[i].classList, classList) { f.methods[i].function = function.(Function) return true } } f.methods = append(f.methods, method{qualifier, classList, function.(Function)}) return true } func (f *GenericFunction) Class() ilos.Class { return f.genericFunctionClass } func (f *GenericFunction) String() string { return fmt.Sprintf("#%v", f.Class()) } func (f *GenericFunction) Apply(e env.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { parameters := f.lambdaList.(List).Slice() variadic := false { test := func(i int) bool { return parameters[i] == NewSymbol(":REST") || parameters[i] == NewSymbol("&REST") } if sort.Search(len(parameters), test) < len(parameters) { variadic = true } } if (variadic && len(parameters)-2 > len(arguments)) || (!variadic && len(parameters) != len(arguments)) { return nil, NewArityError() } methods := []method{} for _, method := range f.methods { matched := true for i, c := range method.classList { if !ilos.InstanceOf(c, arguments[i]) { matched = false break } } if matched { methods = append(methods, method) } } before := NewSymbol(":BEFORE") around := NewSymbol(":AROUND") after := NewSymbol(":AFTER") sort.Slice(methods, func(a, b int) bool { for i := range methods[a].classList { if ilos.SubclassOf(methods[a].classList[i], methods[b].classList[i]) { return false } if ilos.SubclassOf(methods[b].classList[i], methods[a].classList[i]) { return true } } t := map[ilos.Instance]int{around: 4, before: 3, nil: 2, after: 1} return t[methods[a].qualifier] > t[methods[b].qualifier] }) nextMethodPisNil := NewFunction(NewSymbol("NEXT-METHOD-P"), func(e env.Environment) (ilos.Instance, ilos.Instance) { return Nil, nil }) nextMethodPisT := NewFunction(NewSymbol("NEXT-METHOD-P"), func(e env.Environment) (ilos.Instance, ilos.Instance) { return T, nil }) if f.methodCombination == NewSymbol("NIL") { var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) // To Recursive callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { // CALL-NEXT-METHOD depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth index := int(depth.(Integer)) + 1 // Get index of next method e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil)) if int(depth.(Integer))+1 < len(methods) { // If Generic Function has next method, set these functionss e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisT)) } return methods[index].function.Apply(e, arguments ...) // Call next method } e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(0)) // Set current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil)) if 1 < len(methods) { // If Generic Function has next method, set these functionss e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisT))

Slide 60

Slide 60 text

THE INTERNALS OF IRIS GENERIC FUNCTION e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } return methods[0].function.Apply(e, arguments ...) //Call first of method } // if f.methodCombination == NewSymbol("STANDARD") { test := func(i int) bool { return methods[i].qualifier == around } width := len(methods) if index := sort.Search(width, test); index < width { // if has :around methods // This callNextMethod is called in :around methods var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth for index, method := range methods[:int(depth.(Integer))+1] { if method.qualifier == around { // If have :around method e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set Current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil || methods[index+i+1].qualifier == around } if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } return methods[int(depth.(Integer))].function.Apply(e, arguments ...) // Call next method } } // If has no :around method then, // Do All :before mehtods for _, method := range methods { if method.qualifier == before { if _, err := method.function.Apply(e, arguments ...); err != nil { return nil, err } } } // Do the first of primary methods // this callNextMethod is called in primary methods var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth index := int(depth.(Integer)) // Convert depth to integer { width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil } index = sort.Search(width, test) // Get index of next mehotd e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set current depth } // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil } if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } return methods[index].function.Apply(e, arguments ...) // Call next method } // callNextMethod ends here index := 0 // index of the first primary method { // index != 0 is always true because this function has :around methods width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil } index = sort.Search(width, test) e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) } // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } // Do primary methods ret, err := methods[index].function.Apply(e, arguments ...) if err != nil { return nil, err } // Do all :after methods for i := len(methods) - 1; i >= 0; i -- { if methods[i].qualifier == after { if _, err := methods[i].function.Apply(e, arguments ...); err != nil { return nil, err } } } return ret, err } e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set Current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } return methods[index].function.Apply(e, arguments ...) } } { // Function has no :around methods // This callNextMethod is called in primary methods var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth index := int(depth.(Integer)) // Convert depth to integer { test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 index = sort.Search(width, test) } e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set Current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } return methods[int(depth.(Integer))].function.Apply(e, arguments ...) } // callNextMethod ends here // Do All :before mehtods for _, method := range methods { if method.qualifier == before { if _, err := method.function.Apply(e, arguments ...); err != nil { return nil, err } } } index := 0 // index of the first primary method { test := func(i int) bool { return methods[i].qualifier == nil } width := len(methods) index := sort.Search(width, test) e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) if index == len(methods) { return nil, NewUndefinedFunction(f.funcSpec) } } e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functions test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } ret, err := methods[index].function.Apply(e, arguments ...) // Do all :after methods for i := len(methods) - 1; i >= 0; i -- { if methods[i].qualifier == after { if _, err := methods[i].function.Apply(e, arguments ...); err != nil { return nil, err } } } return ret, err // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http: //mozilla.org/MPL/2.0/. package instance import ( "fmt" "reflect" "sort" "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" ) type Applicable interface { Apply(env.Environment, ...ilos.Instance) (ilos.Instance, ilos.Instance) } type Function struct { name ilos.Instance function interface{} } func NewFunction(name ilos.Instance, function interface{}) ilos.Instance { return Function{name, function} } func (Function) Class() ilos.Class { return FunctionClass } func (f Function) String() string { return fmt.Sprintf("#%v", f.Class()) } func (f Function) Apply(e env.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { fv := reflect.ValueOf(f.function) ft := reflect.TypeOf(f.function) argv := []reflect.Value{reflect.ValueOf(e)} for _, cadr := range arguments { argv = append(argv, reflect.ValueOf(cadr)) } if ft.NumIn() != len(argv) && (!ft.IsVariadic() || ft.NumIn()-2 >= len(argv)) { return nil, NewArityError() } rets := fv.Call(argv) a, _ := rets[0].Interface().(ilos.Instance) b, _ := rets[1].Interface().(ilos.Instance) return a, b } type method struct { qualifier ilos.Instance classList []ilos.Class function Function } type GenericFunction struct { funcSpec ilos.Instance lambdaList ilos.Instance methodCombination ilos.Instance genericFunctionClass ilos.Class methods []method } func NewGenericFunction(funcSpec, lambdaList, methodCombination ilos.Instance, genericFunctionClass ilos.Class) ilos.Instance { return &GenericFunction{funcSpec, lambdaList, methodCombination, genericFunctionClass, []method{}} } func (f *GenericFunction) AddMethod(qualifier, lambdaList ilos.Instance, classList []ilos.Class, function ilos.Instance) bool { if f.lambdaList.(List).Length() != lambdaList.(List).Length() { return false } for i, param := range f.lambdaList.(List).Slice() { if param == NewSymbol(":REST") || param == NewSymbol("&REST") { if lambdaList.(List).Nth(i) != NewSymbol(":REST") && lambdaList.(List).Nth(i) != NewSymbol("&REST") { return false } } } for i := range f.methods { if f.methods[i].qualifier == qualifier && reflect.DeepEqual(f.methods[i].classList, classList) { f.methods[i].function = function.(Function) return true } } f.methods = append(f.methods, method{qualifier, classList, function.(Function)}) return true } func (f *GenericFunction) Class() ilos.Class { return f.genericFunctionClass } func (f *GenericFunction) String() string { return fmt.Sprintf("#%v", f.Class()) } func (f *GenericFunction) Apply(e env.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { parameters := f.lambdaList.(List).Slice() variadic := false { test := func(i int) bool { return parameters[i] == NewSymbol(":REST") || parameters[i] == NewSymbol("&REST") } if sort.Search(len(parameters), test) < len(parameters) { variadic = true } } if (variadic && len(parameters)-2 > len(arguments)) || (!variadic && len(parameters) != len(arguments)) { return nil, NewArityError() } methods := []method{} for _, method := range f.methods { matched := true for i, c := range method.classList { if !ilos.InstanceOf(c, arguments[i]) { matched = false break } } if matched { methods = append(methods, method) } } before := NewSymbol(":BEFORE") around := NewSymbol(":AROUND") after := NewSymbol(":AFTER") sort.Slice(methods, func(a, b int) bool { for i := range methods[a].classList { if ilos.SubclassOf(methods[a].classList[i], methods[b].classList[i]) { return false } if ilos.SubclassOf(methods[b].classList[i], methods[a].classList[i]) { return true } } t := map[ilos.Instance]int{around: 4, before: 3, nil: 2, after: 1} return t[methods[a].qualifier] > t[methods[b].qualifier] }) nextMethodPisNil := NewFunction(NewSymbol("NEXT-METHOD-P"), func(e env.Environment) (ilos.Instance, ilos.Instance) { return Nil, nil }) nextMethodPisT := NewFunction(NewSymbol("NEXT-METHOD-P"), func(e env.Environment) (ilos.Instance, ilos.Instance) { return T, nil }) if f.methodCombination == NewSymbol("NIL") { var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) // To Recursive callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { // CALL-NEXT-METHOD depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth index := int(depth.(Integer)) + 1 // Get index of next method e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil)) if int(depth.(Integer))+1 < len(methods) { // If Generic Function has next method, set these functionss e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisT)) } return methods[index].function.Apply(e, arguments ...) // Call next method } e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(0)) // Set current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil)) if 1 < len(methods) { // If Generic Function has next method, set these functionss e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisT))

Slide 61

Slide 61 text

THE INTERNALS OF IRIS GENERIC FUNCTION e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } return methods[0].function.Apply(e, arguments ...) //Call first of method } // if f.methodCombination == NewSymbol("STANDARD") { test := func(i int) bool { return methods[i].qualifier == around } width := len(methods) if index := sort.Search(width, test); index < width { // if has :around methods // This callNextMethod is called in :around methods var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth for index, method := range methods[:int(depth.(Integer))+1] { if method.qualifier == around { // If have :around method e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set Current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil || methods[index+i+1].qualifier == around } if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } return methods[int(depth.(Integer))].function.Apply(e, arguments ...) // Call next method } } // If has no :around method then, // Do All :before mehtods for _, method := range methods { if method.qualifier == before { if _, err := method.function.Apply(e, arguments ...); err != nil { return nil, err } } } // Do the first of primary methods // this callNextMethod is called in primary methods var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth index := int(depth.(Integer)) // Convert depth to integer { width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil } index = sort.Search(width, test) // Get index of next mehotd e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set current depth } // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil } if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } return methods[index].function.Apply(e, arguments ...) // Call next method } // callNextMethod ends here index := 0 // index of the first primary method { // index != 0 is always true because this function has :around methods width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil } index = sort.Search(width, test) e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) } // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } // Do primary methods ret, err := methods[index].function.Apply(e, arguments ...) if err != nil { return nil, err } // Do all :after methods for i := len(methods) - 1; i >= 0; i -- { if methods[i].qualifier == after { if _, err := methods[i].function.Apply(e, arguments ...); err != nil { return nil, err } } } return ret, err } e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set Current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } return methods[index].function.Apply(e, arguments ...) } } { // Function has no :around methods // This callNextMethod is called in primary methods var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth index := int(depth.(Integer)) // Convert depth to integer { test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 index = sort.Search(width, test) } e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set Current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } return methods[int(depth.(Integer))].function.Apply(e, arguments ...) } // callNextMethod ends here // Do All :before mehtods for _, method := range methods { if method.qualifier == before { if _, err := method.function.Apply(e, arguments ...); err != nil { return nil, err } } } index := 0 // index of the first primary method { test := func(i int) bool { return methods[i].qualifier == nil } width := len(methods) index := sort.Search(width, test) e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) if index == len(methods) { return nil, NewUndefinedFunction(f.funcSpec) } } e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functions test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } ret, err := methods[index].function.Apply(e, arguments ...) // Do all :after methods for i := len(methods) - 1; i >= 0; i -- { if methods[i].qualifier == after { if _, err := methods[i].function.Apply(e, arguments ...); err != nil { return nil, err } } } return ret, err // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http: //mozilla.org/MPL/2.0/. package instance import ( "fmt" "reflect" "sort" "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" ) type Applicable interface { Apply(env.Environment, ...ilos.Instance) (ilos.Instance, ilos.Instance) } type Function struct { name ilos.Instance function interface{} } func NewFunction(name ilos.Instance, function interface{}) ilos.Instance { return Function{name, function} } func (Function) Class() ilos.Class { return FunctionClass } func (f Function) String() string { return fmt.Sprintf("#%v", f.Class()) } func (f Function) Apply(e env.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { fv := reflect.ValueOf(f.function) ft := reflect.TypeOf(f.function) argv := []reflect.Value{reflect.ValueOf(e)} for _, cadr := range arguments { argv = append(argv, reflect.ValueOf(cadr)) } if ft.NumIn() != len(argv) && (!ft.IsVariadic() || ft.NumIn()-2 >= len(argv)) { return nil, NewArityError() } rets := fv.Call(argv) a, _ := rets[0].Interface().(ilos.Instance) b, _ := rets[1].Interface().(ilos.Instance) return a, b } type method struct { qualifier ilos.Instance classList []ilos.Class function Function } type GenericFunction struct { funcSpec ilos.Instance lambdaList ilos.Instance methodCombination ilos.Instance genericFunctionClass ilos.Class methods []method } func NewGenericFunction(funcSpec, lambdaList, methodCombination ilos.Instance, genericFunctionClass ilos.Class) ilos.Instance { return &GenericFunction{funcSpec, lambdaList, methodCombination, genericFunctionClass, []method{}} } func (f *GenericFunction) AddMethod(qualifier, lambdaList ilos.Instance, classList []ilos.Class, function ilos.Instance) bool { if f.lambdaList.(List).Length() != lambdaList.(List).Length() { return false } for i, param := range f.lambdaList.(List).Slice() { if param == NewSymbol(":REST") || param == NewSymbol("&REST") { if lambdaList.(List).Nth(i) != NewSymbol(":REST") && lambdaList.(List).Nth(i) != NewSymbol("&REST") { return false } } } for i := range f.methods { if f.methods[i].qualifier == qualifier && reflect.DeepEqual(f.methods[i].classList, classList) { f.methods[i].function = function.(Function) return true } } f.methods = append(f.methods, method{qualifier, classList, function.(Function)}) return true } func (f *GenericFunction) Class() ilos.Class { return f.genericFunctionClass } func (f *GenericFunction) String() string { return fmt.Sprintf("#%v", f.Class()) } func (f *GenericFunction) Apply(e env.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { parameters := f.lambdaList.(List).Slice() variadic := false { test := func(i int) bool { return parameters[i] == NewSymbol(":REST") || parameters[i] == NewSymbol("&REST") } if sort.Search(len(parameters), test) < len(parameters) { variadic = true } } if (variadic && len(parameters)-2 > len(arguments)) || (!variadic && len(parameters) != len(arguments)) { return nil, NewArityError() } methods := []method{} for _, method := range f.methods { matched := true for i, c := range method.classList { if !ilos.InstanceOf(c, arguments[i]) { matched = false break } } if matched { methods = append(methods, method) } } before := NewSymbol(":BEFORE") around := NewSymbol(":AROUND") after := NewSymbol(":AFTER") sort.Slice(methods, func(a, b int) bool { for i := range methods[a].classList { if ilos.SubclassOf(methods[a].classList[i], methods[b].classList[i]) { return false } if ilos.SubclassOf(methods[b].classList[i], methods[a].classList[i]) { return true } } t := map[ilos.Instance]int{around: 4, before: 3, nil: 2, after: 1} return t[methods[a].qualifier] > t[methods[b].qualifier] }) nextMethodPisNil := NewFunction(NewSymbol("NEXT-METHOD-P"), func(e env.Environment) (ilos.Instance, ilos.Instance) { return Nil, nil }) nextMethodPisT := NewFunction(NewSymbol("NEXT-METHOD-P"), func(e env.Environment) (ilos.Instance, ilos.Instance) { return T, nil }) if f.methodCombination == NewSymbol("NIL") { var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) // To Recursive callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { // CALL-NEXT-METHOD depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth index := int(depth.(Integer)) + 1 // Get index of next method e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil)) if int(depth.(Integer))+1 < len(methods) { // If Generic Function has next method, set these functionss e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisT)) } return methods[index].function.Apply(e, arguments ...) // Call next method } e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(0)) // Set current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil)) if 1 < len(methods) { // If Generic Function has next method, set these functionss e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisT))

Slide 62

Slide 62 text

THE INTERNALS OF IRIS GENERIC FUNCTION e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } return methods[0].function.Apply(e, arguments ...) //Call first of method } // if f.methodCombination == NewSymbol("STANDARD") { test := func(i int) bool { return methods[i].qualifier == around } width := len(methods) if index := sort.Search(width, test); index < width { // if has :around methods // This callNextMethod is called in :around methods var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth for index, method := range methods[:int(depth.(Integer))+1] { if method.qualifier == around { // If have :around method e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set Current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil || methods[index+i+1].qualifier == around } if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } return methods[int(depth.(Integer))].function.Apply(e, arguments ...) // Call next method } } // If has no :around method then, // Do All :before mehtods for _, method := range methods { if method.qualifier == before { if _, err := method.function.Apply(e, arguments ...); err != nil { return nil, err } } } // Do the first of primary methods // this callNextMethod is called in primary methods var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth index := int(depth.(Integer)) // Convert depth to integer { width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil } index = sort.Search(width, test) // Get index of next mehotd e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set current depth } // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil } if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } return methods[index].function.Apply(e, arguments ...) // Call next method } // callNextMethod ends here index := 0 // index of the first primary method { // index != 0 is always true because this function has :around methods width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil } index = sort.Search(width, test) e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) } // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } // Do primary methods ret, err := methods[index].function.Apply(e, arguments ...) if err != nil { return nil, err } // Do all :after methods for i := len(methods) - 1; i >= 0; i -- { if methods[i].qualifier == after { if _, err := methods[i].function.Apply(e, arguments ...); err != nil { return nil, err } } } return ret, err } e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set Current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } return methods[index].function.Apply(e, arguments ...) } } { // Function has no :around methods // This callNextMethod is called in primary methods var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth index := int(depth.(Integer)) // Convert depth to integer { test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 index = sort.Search(width, test) } e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set Current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } return methods[int(depth.(Integer))].function.Apply(e, arguments ...) } // callNextMethod ends here // Do All :before mehtods for _, method := range methods { if method.qualifier == before { if _, err := method.function.Apply(e, arguments ...); err != nil { return nil, err } } } index := 0 // index of the first primary method { test := func(i int) bool { return methods[i].qualifier == nil } width := len(methods) index := sort.Search(width, test) e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) if index == len(methods) { return nil, NewUndefinedFunction(f.funcSpec) } } e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functions test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } ret, err := methods[index].function.Apply(e, arguments ...) // Do all :after methods for i := len(methods) - 1; i >= 0; i -- { if methods[i].qualifier == after { if _, err := methods[i].function.Apply(e, arguments ...); err != nil { return nil, err } } } return ret, err // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http: //mozilla.org/MPL/2.0/. package instance import ( "fmt" "reflect" "sort" "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" ) type Applicable interface { Apply(env.Environment, ...ilos.Instance) (ilos.Instance, ilos.Instance) } type Function struct { name ilos.Instance function interface{} } func NewFunction(name ilos.Instance, function interface{}) ilos.Instance { return Function{name, function} } func (Function) Class() ilos.Class { return FunctionClass } func (f Function) String() string { return fmt.Sprintf("#%v", f.Class()) } func (f Function) Apply(e env.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { fv := reflect.ValueOf(f.function) ft := reflect.TypeOf(f.function) argv := []reflect.Value{reflect.ValueOf(e)} for _, cadr := range arguments { argv = append(argv, reflect.ValueOf(cadr)) } if ft.NumIn() != len(argv) && (!ft.IsVariadic() || ft.NumIn()-2 >= len(argv)) { return nil, NewArityError() } rets := fv.Call(argv) a, _ := rets[0].Interface().(ilos.Instance) b, _ := rets[1].Interface().(ilos.Instance) return a, b } type method struct { qualifier ilos.Instance classList []ilos.Class function Function } type GenericFunction struct { funcSpec ilos.Instance lambdaList ilos.Instance methodCombination ilos.Instance genericFunctionClass ilos.Class methods []method } func NewGenericFunction(funcSpec, lambdaList, methodCombination ilos.Instance, genericFunctionClass ilos.Class) ilos.Instance { return &GenericFunction{funcSpec, lambdaList, methodCombination, genericFunctionClass, []method{}} } func (f *GenericFunction) AddMethod(qualifier, lambdaList ilos.Instance, classList []ilos.Class, function ilos.Instance) bool { if f.lambdaList.(List).Length() != lambdaList.(List).Length() { return false } for i, param := range f.lambdaList.(List).Slice() { if param == NewSymbol(":REST") || param == NewSymbol("&REST") { if lambdaList.(List).Nth(i) != NewSymbol(":REST") && lambdaList.(List).Nth(i) != NewSymbol("&REST") { return false } } } for i := range f.methods { if f.methods[i].qualifier == qualifier && reflect.DeepEqual(f.methods[i].classList, classList) { f.methods[i].function = function.(Function) return true } } f.methods = append(f.methods, method{qualifier, classList, function.(Function)}) return true } func (f *GenericFunction) Class() ilos.Class { return f.genericFunctionClass } func (f *GenericFunction) String() string { return fmt.Sprintf("#%v", f.Class()) } func (f *GenericFunction) Apply(e env.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { parameters := f.lambdaList.(List).Slice() variadic := false { test := func(i int) bool { return parameters[i] == NewSymbol(":REST") || parameters[i] == NewSymbol("&REST") } if sort.Search(len(parameters), test) < len(parameters) { variadic = true } } if (variadic && len(parameters)-2 > len(arguments)) || (!variadic && len(parameters) != len(arguments)) { return nil, NewArityError() } methods := []method{} for _, method := range f.methods { matched := true for i, c := range method.classList { if !ilos.InstanceOf(c, arguments[i]) { matched = false break } } if matched { methods = append(methods, method) } } before := NewSymbol(":BEFORE") around := NewSymbol(":AROUND") after := NewSymbol(":AFTER") sort.Slice(methods, func(a, b int) bool { for i := range methods[a].classList { if ilos.SubclassOf(methods[a].classList[i], methods[b].classList[i]) { return false } if ilos.SubclassOf(methods[b].classList[i], methods[a].classList[i]) { return true } } t := map[ilos.Instance]int{around: 4, before: 3, nil: 2, after: 1} return t[methods[a].qualifier] > t[methods[b].qualifier] }) nextMethodPisNil := NewFunction(NewSymbol("NEXT-METHOD-P"), func(e env.Environment) (ilos.Instance, ilos.Instance) { return Nil, nil }) nextMethodPisT := NewFunction(NewSymbol("NEXT-METHOD-P"), func(e env.Environment) (ilos.Instance, ilos.Instance) { return T, nil }) if f.methodCombination == NewSymbol("NIL") { var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) // To Recursive callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { // CALL-NEXT-METHOD depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth index := int(depth.(Integer)) + 1 // Get index of next method e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil)) if int(depth.(Integer))+1 < len(methods) { // If Generic Function has next method, set these functionss e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisT)) } return methods[index].function.Apply(e, arguments ...) // Call next method } e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(0)) // Set current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil)) if 1 < len(methods) { // If Generic Function has next method, set these functionss e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisT)) แׅؔ਺ͷؔ਺ݺͼग़͠ͷ࣮૷ ຖճCALL-NEXT-METHODΛہॴؔ਺ͱͯ͠
 ༏ઌॱҐΛݩʹ௨ৗؔ਺ͱͯؔ͠਺Λଋറ͠ ͍ͯΔɻ࣮૷ʹΑΔ͕ɺҰൠʹಈతʹݺͼग़ ؔ͢਺Λܾఆ͍ͯ͠ΔͷͰίϯύΠϧʹΑΔ Ըܙ΋ड͚ͮΒ͍ɻ

Slide 63

Slide 63 text

THE INTERNALS OF IRIS GENERIC FUNCTION e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } return methods[0].function.Apply(e, arguments ...) //Call first of method } // if f.methodCombination == NewSymbol("STANDARD") { test := func(i int) bool { return methods[i].qualifier == around } width := len(methods) if index := sort.Search(width, test); index < width { // if has :around methods // This callNextMethod is called in :around methods var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth for index, method := range methods[:int(depth.(Integer))+1] { if method.qualifier == around { // If have :around method e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set Current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil || methods[index+i+1].qualifier == around } if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } return methods[int(depth.(Integer))].function.Apply(e, arguments ...) // Call next method } } // If has no :around method then, // Do All :before mehtods for _, method := range methods { if method.qualifier == before { if _, err := method.function.Apply(e, arguments ...); err != nil { return nil, err } } } // Do the first of primary methods // this callNextMethod is called in primary methods var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth index := int(depth.(Integer)) // Convert depth to integer { width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil } index = sort.Search(width, test) // Get index of next mehotd e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set current depth } // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil } if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } return methods[index].function.Apply(e, arguments ...) // Call next method } // callNextMethod ends here index := 0 // index of the first primary method { // index != 0 is always true because this function has :around methods width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil } index = sort.Search(width, test) e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) } // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } // Do primary methods ret, err := methods[index].function.Apply(e, arguments ...) if err != nil { return nil, err } // Do all :after methods for i := len(methods) - 1; i >= 0; i -- { if methods[i].qualifier == after { if _, err := methods[i].function.Apply(e, arguments ...); err != nil { return nil, err } } } return ret, err } e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set Current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } return methods[index].function.Apply(e, arguments ...) } } { // Function has no :around methods // This callNextMethod is called in primary methods var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth index := int(depth.(Integer)) // Convert depth to integer { test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 index = sort.Search(width, test) } e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set Current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } return methods[int(depth.(Integer))].function.Apply(e, arguments ...) } // callNextMethod ends here // Do All :before mehtods for _, method := range methods { if method.qualifier == before { if _, err := method.function.Apply(e, arguments ...); err != nil { return nil, err } } } index := 0 // index of the first primary method { test := func(i int) bool { return methods[i].qualifier == nil } width := len(methods) index := sort.Search(width, test) e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) if index == len(methods) { return nil, NewUndefinedFunction(f.funcSpec) } } e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functions test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } ret, err := methods[index].function.Apply(e, arguments ...) // Do all :after methods for i := len(methods) - 1; i >= 0; i -- { if methods[i].qualifier == after { if _, err := methods[i].function.Apply(e, arguments ...); err != nil { return nil, err } } } return ret, err // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http: //mozilla.org/MPL/2.0/. package instance import ( "fmt" "reflect" "sort" "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" ) type Applicable interface { Apply(env.Environment, ...ilos.Instance) (ilos.Instance, ilos.Instance) } type Function struct { name ilos.Instance function interface{} } func NewFunction(name ilos.Instance, function interface{}) ilos.Instance { return Function{name, function} } func (Function) Class() ilos.Class { return FunctionClass } func (f Function) String() string { return fmt.Sprintf("#%v", f.Class()) } func (f Function) Apply(e env.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { fv := reflect.ValueOf(f.function) ft := reflect.TypeOf(f.function) argv := []reflect.Value{reflect.ValueOf(e)} for _, cadr := range arguments { argv = append(argv, reflect.ValueOf(cadr)) } if ft.NumIn() != len(argv) && (!ft.IsVariadic() || ft.NumIn()-2 >= len(argv)) { return nil, NewArityError() } rets := fv.Call(argv) a, _ := rets[0].Interface().(ilos.Instance) b, _ := rets[1].Interface().(ilos.Instance) return a, b } type method struct { qualifier ilos.Instance classList []ilos.Class function Function } type GenericFunction struct { funcSpec ilos.Instance lambdaList ilos.Instance methodCombination ilos.Instance genericFunctionClass ilos.Class methods []method } func NewGenericFunction(funcSpec, lambdaList, methodCombination ilos.Instance, genericFunctionClass ilos.Class) ilos.Instance { return &GenericFunction{funcSpec, lambdaList, methodCombination, genericFunctionClass, []method{}} } func (f *GenericFunction) AddMethod(qualifier, lambdaList ilos.Instance, classList []ilos.Class, function ilos.Instance) bool { if f.lambdaList.(List).Length() != lambdaList.(List).Length() { return false } for i, param := range f.lambdaList.(List).Slice() { if param == NewSymbol(":REST") || param == NewSymbol("&REST") { if lambdaList.(List).Nth(i) != NewSymbol(":REST") && lambdaList.(List).Nth(i) != NewSymbol("&REST") { return false } } } for i := range f.methods { if f.methods[i].qualifier == qualifier && reflect.DeepEqual(f.methods[i].classList, classList) { f.methods[i].function = function.(Function) return true } } f.methods = append(f.methods, method{qualifier, classList, function.(Function)}) return true } func (f *GenericFunction) Class() ilos.Class { return f.genericFunctionClass } func (f *GenericFunction) String() string { return fmt.Sprintf("#%v", f.Class()) } func (f *GenericFunction) Apply(e env.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { parameters := f.lambdaList.(List).Slice() variadic := false { test := func(i int) bool { return parameters[i] == NewSymbol(":REST") || parameters[i] == NewSymbol("&REST") } if sort.Search(len(parameters), test) < len(parameters) { variadic = true } } if (variadic && len(parameters)-2 > len(arguments)) || (!variadic && len(parameters) != len(arguments)) { return nil, NewArityError() } methods := []method{} for _, method := range f.methods { matched := true for i, c := range method.classList { if !ilos.InstanceOf(c, arguments[i]) { matched = false break } } if matched { methods = append(methods, method) } } before := NewSymbol(":BEFORE") around := NewSymbol(":AROUND") after := NewSymbol(":AFTER") sort.Slice(methods, func(a, b int) bool { for i := range methods[a].classList { if ilos.SubclassOf(methods[a].classList[i], methods[b].classList[i]) { return false } if ilos.SubclassOf(methods[b].classList[i], methods[a].classList[i]) { return true } } t := map[ilos.Instance]int{around: 4, before: 3, nil: 2, after: 1} return t[methods[a].qualifier] > t[methods[b].qualifier] }) nextMethodPisNil := NewFunction(NewSymbol("NEXT-METHOD-P"), func(e env.Environment) (ilos.Instance, ilos.Instance) { return Nil, nil }) nextMethodPisT := NewFunction(NewSymbol("NEXT-METHOD-P"), func(e env.Environment) (ilos.Instance, ilos.Instance) { return T, nil }) if f.methodCombination == NewSymbol("NIL") { var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) // To Recursive callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { // CALL-NEXT-METHOD depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth index := int(depth.(Integer)) + 1 // Get index of next method e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil)) if int(depth.(Integer))+1 < len(methods) { // If Generic Function has next method, set these functionss e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisT)) } return methods[index].function.Apply(e, arguments ...) // Call next method } e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(0)) // Set current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil)) if 1 < len(methods) { // If Generic Function has next method, set these functionss e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisT)) แׅؔ਺ͷؔ਺ݺͼग़͠ͷ࣮૷ ຖճCALL-NEXT-METHODΛہॴؔ਺ͱͯ͠
 ༏ઌॱҐΛݩʹ௨ৗؔ਺ͱͯؔ͠਺Λଋറ͠ ͍ͯΔɻ࣮૷ʹΑΔ͕ɺҰൠʹಈతʹݺͼग़ ؔ͢਺Λܾఆ͍ͯ͠ΔͷͰίϯύΠϧʹΑΔ Ըܙ΋ड͚ͮΒ͍ɻ

Slide 64

Slide 64 text

THE INTERNALS OF IRIS GENERIC FUNCTION e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } return methods[0].function.Apply(e, arguments ...) //Call first of method } // if f.methodCombination == NewSymbol("STANDARD") { test := func(i int) bool { return methods[i].qualifier == around } width := len(methods) if index := sort.Search(width, test); index < width { // if has :around methods // This callNextMethod is called in :around methods var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth for index, method := range methods[:int(depth.(Integer))+1] { if method.qualifier == around { // If have :around method e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set Current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil || methods[index+i+1].qualifier == around } if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } return methods[int(depth.(Integer))].function.Apply(e, arguments ...) // Call next method } } // If has no :around method then, // Do All :before mehtods for _, method := range methods { if method.qualifier == before { if _, err := method.function.Apply(e, arguments ...); err != nil { return nil, err } } } // Do the first of primary methods // this callNextMethod is called in primary methods var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth index := int(depth.(Integer)) // Convert depth to integer { width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil } index = sort.Search(width, test) // Get index of next mehotd e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set current depth } // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil } if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } return methods[index].function.Apply(e, arguments ...) // Call next method } // callNextMethod ends here index := 0 // index of the first primary method { // index != 0 is always true because this function has :around methods width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil } index = sort.Search(width, test) e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) } // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } // Do primary methods ret, err := methods[index].function.Apply(e, arguments ...) if err != nil { return nil, err } // Do all :after methods for i := len(methods) - 1; i >= 0; i -- { if methods[i].qualifier == after { if _, err := methods[i].function.Apply(e, arguments ...); err != nil { return nil, err } } } return ret, err } e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set Current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } return methods[index].function.Apply(e, arguments ...) } } { // Function has no :around methods // This callNextMethod is called in primary methods var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth index := int(depth.(Integer)) // Convert depth to integer { test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 index = sort.Search(width, test) } e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set Current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } return methods[int(depth.(Integer))].function.Apply(e, arguments ...) } // callNextMethod ends here // Do All :before mehtods for _, method := range methods { if method.qualifier == before { if _, err := method.function.Apply(e, arguments ...); err != nil { return nil, err } } } index := 0 // index of the first primary method { test := func(i int) bool { return methods[i].qualifier == nil } width := len(methods) index := sort.Search(width, test) e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) if index == len(methods) { return nil, NewUndefinedFunction(f.funcSpec) } } e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functions test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } ret, err := methods[index].function.Apply(e, arguments ...) // Do all :after methods for i := len(methods) - 1; i >= 0; i -- { if methods[i].qualifier == after { if _, err := methods[i].function.Apply(e, arguments ...); err != nil { return nil, err } } } return ret, err // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http: //mozilla.org/MPL/2.0/. package instance import ( "fmt" "reflect" "sort" "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" ) type Applicable interface { Apply(env.Environment, ...ilos.Instance) (ilos.Instance, ilos.Instance) } type Function struct { name ilos.Instance function interface{} } func NewFunction(name ilos.Instance, function interface{}) ilos.Instance { return Function{name, function} } func (Function) Class() ilos.Class { return FunctionClass } func (f Function) String() string { return fmt.Sprintf("#%v", f.Class()) } func (f Function) Apply(e env.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { fv := reflect.ValueOf(f.function) ft := reflect.TypeOf(f.function) argv := []reflect.Value{reflect.ValueOf(e)} for _, cadr := range arguments { argv = append(argv, reflect.ValueOf(cadr)) } if ft.NumIn() != len(argv) && (!ft.IsVariadic() || ft.NumIn()-2 >= len(argv)) { return nil, NewArityError() } rets := fv.Call(argv) a, _ := rets[0].Interface().(ilos.Instance) b, _ := rets[1].Interface().(ilos.Instance) return a, b } type method struct { qualifier ilos.Instance classList []ilos.Class function Function } type GenericFunction struct { funcSpec ilos.Instance lambdaList ilos.Instance methodCombination ilos.Instance genericFunctionClass ilos.Class methods []method } func NewGenericFunction(funcSpec, lambdaList, methodCombination ilos.Instance, genericFunctionClass ilos.Class) ilos.Instance { return &GenericFunction{funcSpec, lambdaList, methodCombination, genericFunctionClass, []method{}} } func (f *GenericFunction) AddMethod(qualifier, lambdaList ilos.Instance, classList []ilos.Class, function ilos.Instance) bool { if f.lambdaList.(List).Length() != lambdaList.(List).Length() { return false } for i, param := range f.lambdaList.(List).Slice() { if param == NewSymbol(":REST") || param == NewSymbol("&REST") { if lambdaList.(List).Nth(i) != NewSymbol(":REST") && lambdaList.(List).Nth(i) != NewSymbol("&REST") { return false } } } for i := range f.methods { if f.methods[i].qualifier == qualifier && reflect.DeepEqual(f.methods[i].classList, classList) { f.methods[i].function = function.(Function) return true } } f.methods = append(f.methods, method{qualifier, classList, function.(Function)}) return true } func (f *GenericFunction) Class() ilos.Class { return f.genericFunctionClass } func (f *GenericFunction) String() string { return fmt.Sprintf("#%v", f.Class()) } func (f *GenericFunction) Apply(e env.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { parameters := f.lambdaList.(List).Slice() variadic := false { test := func(i int) bool { return parameters[i] == NewSymbol(":REST") || parameters[i] == NewSymbol("&REST") } if sort.Search(len(parameters), test) < len(parameters) { variadic = true } } if (variadic && len(parameters)-2 > len(arguments)) || (!variadic && len(parameters) != len(arguments)) { return nil, NewArityError() } methods := []method{} for _, method := range f.methods { matched := true for i, c := range method.classList { if !ilos.InstanceOf(c, arguments[i]) { matched = false break } } if matched { methods = append(methods, method) } } before := NewSymbol(":BEFORE") around := NewSymbol(":AROUND") after := NewSymbol(":AFTER") sort.Slice(methods, func(a, b int) bool { for i := range methods[a].classList { if ilos.SubclassOf(methods[a].classList[i], methods[b].classList[i]) { return false } if ilos.SubclassOf(methods[b].classList[i], methods[a].classList[i]) { return true } } t := map[ilos.Instance]int{around: 4, before: 3, nil: 2, after: 1} return t[methods[a].qualifier] > t[methods[b].qualifier] }) nextMethodPisNil := NewFunction(NewSymbol("NEXT-METHOD-P"), func(e env.Environment) (ilos.Instance, ilos.Instance) { return Nil, nil }) nextMethodPisT := NewFunction(NewSymbol("NEXT-METHOD-P"), func(e env.Environment) (ilos.Instance, ilos.Instance) { return T, nil }) if f.methodCombination == NewSymbol("NIL") { var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) // To Recursive callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { // CALL-NEXT-METHOD depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth index := int(depth.(Integer)) + 1 // Get index of next method e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil)) if int(depth.(Integer))+1 < len(methods) { // If Generic Function has next method, set these functionss e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisT)) } return methods[index].function.Apply(e, arguments ...) // Call next method } e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(0)) // Set current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil)) if 1 < len(methods) { // If Generic Function has next method, set these functionss e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisT)) แׅؔ਺ͷؔ਺ݺͼग़͠ͷ࣮૷ ຖճCALL-NEXT-METHODΛہॴؔ਺ͱͯ͠
 ༏ઌॱҐΛݩʹ௨ৗؔ਺ͱͯؔ͠਺Λଋറ͠ ͍ͯΔɻ࣮૷ʹΑΔ͕ɺҰൠʹಈతʹݺͼग़ ؔ͢਺Λܾఆ͍ͯ͠ΔͷͰίϯύΠϧʹΑΔ Ըܙ΋ड͚ͮΒ͍ɻ

Slide 65

Slide 65 text

THE INTERNALS OF IRIS GENERIC FUNCTION e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } return methods[0].function.Apply(e, arguments ...) //Call first of method } // if f.methodCombination == NewSymbol("STANDARD") { test := func(i int) bool { return methods[i].qualifier == around } width := len(methods) if index := sort.Search(width, test); index < width { // if has :around methods // This callNextMethod is called in :around methods var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth for index, method := range methods[:int(depth.(Integer))+1] { if method.qualifier == around { // If have :around method e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set Current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil || methods[index+i+1].qualifier == around } if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } return methods[int(depth.(Integer))].function.Apply(e, arguments ...) // Call next method } } // If has no :around method then, // Do All :before mehtods for _, method := range methods { if method.qualifier == before { if _, err := method.function.Apply(e, arguments ...); err != nil { return nil, err } } } // Do the first of primary methods // this callNextMethod is called in primary methods var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth index := int(depth.(Integer)) // Convert depth to integer { width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil } index = sort.Search(width, test) // Get index of next mehotd e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set current depth } // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil } if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } return methods[index].function.Apply(e, arguments ...) // Call next method } // callNextMethod ends here index := 0 // index of the first primary method { // index != 0 is always true because this function has :around methods width := len(methods) - index - 1 test := func(i int) bool { return methods[index+i+1].qualifier == nil } index = sort.Search(width, test) e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) } // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } // Do primary methods ret, err := methods[index].function.Apply(e, arguments ...) if err != nil { return nil, err } // Do all :after methods for i := len(methods) - 1; i >= 0; i -- { if methods[i].qualifier == after { if _, err := methods[i].function.Apply(e, arguments ...); err != nil { return nil, err } } } return ret, err } e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set Current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } return methods[index].function.Apply(e, arguments ...) } } { // Function has no :around methods // This callNextMethod is called in primary methods var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth index := int(depth.(Integer)) // Convert depth to integer { test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 index = sort.Search(width, test) } e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set Current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functionss test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } return methods[int(depth.(Integer))].function.Apply(e, arguments ...) } // callNextMethod ends here // Do All :before mehtods for _, method := range methods { if method.qualifier == before { if _, err := method.function.Apply(e, arguments ...); err != nil { return nil, err } } } index := 0 // index of the first primary method { test := func(i int) bool { return methods[i].qualifier == nil } width := len(methods) index := sort.Search(width, test) e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) if index == len(methods) { return nil, NewUndefinedFunction(f.funcSpec) } } e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil) { // If Generic Function has next method, set these functions test := func(i int) bool { return methods[index+i+1].qualifier == nil } width := len(methods) - index - 1 if sort.Search(width, test) < width { e.Function.Define(NewSymbol("NEXT-METHOD-P"), nextMethodPisT) e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) } } ret, err := methods[index].function.Apply(e, arguments ...) // Do all :after methods for i := len(methods) - 1; i >= 0; i -- { if methods[i].qualifier == after { if _, err := methods[i].function.Apply(e, arguments ...); err != nil { return nil, err } } } return ret, err // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http: //mozilla.org/MPL/2.0/. package instance import ( "fmt" "reflect" "sort" "github.com/ta2gch/iris/runtime/env" "github.com/ta2gch/iris/runtime/ilos" ) type Applicable interface { Apply(env.Environment, ...ilos.Instance) (ilos.Instance, ilos.Instance) } type Function struct { name ilos.Instance function interface{} } func NewFunction(name ilos.Instance, function interface{}) ilos.Instance { return Function{name, function} } func (Function) Class() ilos.Class { return FunctionClass } func (f Function) String() string { return fmt.Sprintf("#%v", f.Class()) } func (f Function) Apply(e env.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { fv := reflect.ValueOf(f.function) ft := reflect.TypeOf(f.function) argv := []reflect.Value{reflect.ValueOf(e)} for _, cadr := range arguments { argv = append(argv, reflect.ValueOf(cadr)) } if ft.NumIn() != len(argv) && (!ft.IsVariadic() || ft.NumIn()-2 >= len(argv)) { return nil, NewArityError() } rets := fv.Call(argv) a, _ := rets[0].Interface().(ilos.Instance) b, _ := rets[1].Interface().(ilos.Instance) return a, b } type method struct { qualifier ilos.Instance classList []ilos.Class function Function } type GenericFunction struct { funcSpec ilos.Instance lambdaList ilos.Instance methodCombination ilos.Instance genericFunctionClass ilos.Class methods []method } func NewGenericFunction(funcSpec, lambdaList, methodCombination ilos.Instance, genericFunctionClass ilos.Class) ilos.Instance { return &GenericFunction{funcSpec, lambdaList, methodCombination, genericFunctionClass, []method{}} } func (f *GenericFunction) AddMethod(qualifier, lambdaList ilos.Instance, classList []ilos.Class, function ilos.Instance) bool { if f.lambdaList.(List).Length() != lambdaList.(List).Length() { return false } for i, param := range f.lambdaList.(List).Slice() { if param == NewSymbol(":REST") || param == NewSymbol("&REST") { if lambdaList.(List).Nth(i) != NewSymbol(":REST") && lambdaList.(List).Nth(i) != NewSymbol("&REST") { return false } } } for i := range f.methods { if f.methods[i].qualifier == qualifier && reflect.DeepEqual(f.methods[i].classList, classList) { f.methods[i].function = function.(Function) return true } } f.methods = append(f.methods, method{qualifier, classList, function.(Function)}) return true } func (f *GenericFunction) Class() ilos.Class { return f.genericFunctionClass } func (f *GenericFunction) String() string { return fmt.Sprintf("#%v", f.Class()) } func (f *GenericFunction) Apply(e env.Environment, arguments ...ilos.Instance) (ilos.Instance, ilos.Instance) { parameters := f.lambdaList.(List).Slice() variadic := false { test := func(i int) bool { return parameters[i] == NewSymbol(":REST") || parameters[i] == NewSymbol("&REST") } if sort.Search(len(parameters), test) < len(parameters) { variadic = true } } if (variadic && len(parameters)-2 > len(arguments)) || (!variadic && len(parameters) != len(arguments)) { return nil, NewArityError() } methods := []method{} for _, method := range f.methods { matched := true for i, c := range method.classList { if !ilos.InstanceOf(c, arguments[i]) { matched = false break } } if matched { methods = append(methods, method) } } before := NewSymbol(":BEFORE") around := NewSymbol(":AROUND") after := NewSymbol(":AFTER") sort.Slice(methods, func(a, b int) bool { for i := range methods[a].classList { if ilos.SubclassOf(methods[a].classList[i], methods[b].classList[i]) { return false } if ilos.SubclassOf(methods[b].classList[i], methods[a].classList[i]) { return true } } t := map[ilos.Instance]int{around: 4, before: 3, nil: 2, after: 1} return t[methods[a].qualifier] > t[methods[b].qualifier] }) nextMethodPisNil := NewFunction(NewSymbol("NEXT-METHOD-P"), func(e env.Environment) (ilos.Instance, ilos.Instance) { return Nil, nil }) nextMethodPisT := NewFunction(NewSymbol("NEXT-METHOD-P"), func(e env.Environment) (ilos.Instance, ilos.Instance) { return T, nil }) if f.methodCombination == NewSymbol("NIL") { var callNextMethod func(e env.Environment) (ilos.Instance, ilos.Instance) // To Recursive callNextMethod = func(e env.Environment) (ilos.Instance, ilos.Instance) { // CALL-NEXT-METHOD depth, _ := e.DynamicVariable.Get(NewSymbol("IRIS/DEPTH")) // Get previous depth index := int(depth.(Integer)) + 1 // Get index of next method e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(index)) // Set current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil)) if int(depth.(Integer))+1 < len(methods) { // If Generic Function has next method, set these functionss e.Function.Define(NewSymbol("CALL-NEXT-METHOD"), NewFunction(NewSymbol("CALL-NEXT-METHOD"), callNextMethod)) e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisT)) } return methods[index].function.Apply(e, arguments ...) // Call next method } e.DynamicVariable.Define(NewSymbol("IRIS/DEPTH"), NewInteger(0)) // Set current depth // If Generic Function has no next-mehtods, NEXT-METHOD-P e function returns nil e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisNil)) if 1 < len(methods) { // If Generic Function has next method, set these functionss e.Function.Define(NewSymbol("NEXT-METHOD-P"), NewFunction(NewSymbol("NEXT-METHOD-P"), nextMethodPisT))

Slide 66

Slide 66 text

THE INTERNALS OF IRIS NON-LOCAL EXITS 1. block / return-from 2. tagbody / go 3. catch / throw 4. with-handler / singnal-condition LEXICAL LEXICAL DYNAMIC DYNAMIC

Slide 67

Slide 67 text

THE INTERNALS OF IRIS BLOCK / RETURN-FROM (block sum-block (for ((x '(1 a 2 3) (cdr x)) (sum 0 (+ sum (car x)))) ((null x) sum) (cond ((not (numberp (car x))) (return-from sum-block 0)))))

Slide 68

Slide 68 text

THE INTERNALS OF IRIS TAGBODY / GO (defmacro with-retry (:rest forms) (let ((tag (gensym))) `(block ,tag (tagbody ,tag (return-from ,tag (flet ((retry () (go ,tag))) ,@forms)))))) (let ((i -5)) (with-retry ;; if-error is a hypothetical error correction function ;; not supplied by ISLISP. (if-error (sqrt (setq i (+ i 4))) (retry))))

Slide 69

Slide 69 text

THE INTERNALS OF IRIS CATCH / THROW (defun foo (x) (catch 'block-sum (bar x))) (defun bar (x) (for ((l x (cdr l)) (sum 0 (+ sum (car l)))) ((null l) sum) (cond ((not (numberp (car l))) (throw 'block-sum 0))))) (foo '(1 2 3 4)) (foo '(1 2 a 4))

Slide 70

Slide 70 text

THE INTERNALS OF IRIS WITH-HANDLER / SIGNAL-CONDITION (defun handler (c) ɹ(continue-condition c true)) (with-handler #'handler ɹ(cerror “continue-message“ “error-message”))

Slide 71

Slide 71 text

THE INTERNALS OF IRIS NON-LOCAL EXITS 1. ҰൠʹCݴޠͰ࣮૷͢Δ৔߹͸setjmp/longjmpͱ͍͏Cݴ ޠࣗମͷελοΫΛר͖໭͢େҬ୤ग़Λ࢖ͬͯΠϯλϓϦ λࣗମͷελοΫ΋ר͖໭͢Α͏ʹ࣮ͯ͠૷͍ͯ͠Δ PROCEDURE A PROCEDURE B1 PROCEDURE B3 PROCEDURE B2 PROCEDURE C ENVIRONMENT A ENVIRONMENT B Jump

Slide 72

Slide 72 text

THE INTERNALS OF IRIS NON-LOCAL EXITS 1. Goݴޠͷ৔߹setjmpͱlongjmp͕࢖͑ͳ͍ 2. ؀ڥʹcatch͍ͨ͠৔ॴΛελοΫʹϓογϡ͢Δɻ 3. ୤ग़༻໭Γ஋ΛEvalͳͲ͕ॲཧΛৼΓ෼͚Δɻ PROCEDURE A PROCEDURE B1 PROCEDURE B1 PROCEDURE B1 PROCEDURE C FAIL SUCCESS MATCH ENVIRONMENT A ENVIRONMENT B SUCCESS

Slide 73

Slide 73 text

IRIS IN THE FEATURE

Slide 74

Slide 74 text

IRIS IN THE FEATURE PARALLELIZED MAP ▸ Goݴޠʹ͸ڧྗͳฒྻ࣮ߦγεςϜ͕૊Έࠐ·Ε͍ͯΔɻ ▸ GoroutineΛ࢖ͬͯΧδϡΞϧʹฒྻԽΛߦ͑ΔΑ͏ʹ͢Δ ▸ Clojure΍lparallelͷฒྻԽΛࢀߟʹ͢Δͭ΋Γ

Slide 75

Slide 75 text

IRIS IN THE FEATURE PLUGIN & FFI SUPPORT ▸ Goݴޠʹ͸ಈతʹϥΠϒϥϦΛಡΈࠐΉγεςϜ΋͋Δ ▸ PluginΛ࢖ͬͯศརͳϥΠϒϥϦͷϥούʔΛॻ͘ ▸ Goͷඪ४ϥΠϒϥϦʹ͸ศརͳ΋ͷ͕ͨ͘͞Μ͋Δɻ ▸ ը૾ॲཧ ▸ ҉߸Խ ▸ ଟഒ௕੔਺ ▸ HTTP & SMTPͳͲͷωοτϫʔΫϓϩτίϧͷ࣮૷ ▸ ɹCGOΛ࢖͑͹CݴޠͷϥΠϒϥϦ΋ಡΈࠐΊΔɻ ▸ جຊతʹωΠςΟϒؔ਺ΛILOSͷؔ਺ΠϯελϯεͰแΉ͚ͩͳͷͰ؆୯ʹϥοϐϯάͰ͖Δ

Slide 76

Slide 76 text

IRIS IN THE FEATURE PACKAGE SYSTEM ▸ ͔ͭͯJavaScriptʹ͸ύοέʔδ؅ཧγεςϜ͕ͳ͔ͬͨ ▸ Webpack΍browserifyɺRequireJSͱ͍ͬͨJavaScript͚ͩ Ͱ࣮૷͞ΕͨASTϨϕϧͷม׵ͷΈͰύοέʔδ؅ཧΛ࣮ݱ ͍ͯͨ͠ɻ ▸ ISLisp΋ISLispͷΈΛ࢖ͬͯASTϨϕϧͷม׵ͷΈͰύο έʔδ؅ཧΛ࣮ݱ͢Δ

Slide 77

Slide 77 text

IRIS islisp.js.org