예제 #1
0
func interpretDoubleQuotedStringInContext(
	vm *vm,
	stringValue ast.InterpolatedString,
	context Value,
) (Value, error) {

	str := stringValue.Value
	currentBytes := []byte{}
	bytesToInterpret := [][]byte{}
	insideInterpolation := false
	for i := 0; i < len(str); i++ {
		if insideInterpolation {
			currentBytes = append(currentBytes, str[i])
		}

		if str[i] == '}' && i > 0 && str[i-1] != '\\' {
			insideInterpolation = false
			bytesToInterpret = append(bytesToInterpret, currentBytes)
			currentBytes = []byte{}
		} else if str[i] == '#' && len(str) > i && str[i+1] == '{' {
			insideInterpolation = true
		}
	}

	for _, bytes := range bytesToInterpret {
		substringToReplace := string(bytes)
		rubyValue, err := vm.EvaluateStringInContext(substringToReplace[1:len(substringToReplace)-1], context)
		if err != nil {
			return nil, err
		}

		valueAsString := gomads.Maybe(func() interface{} {
			method := rubyValue.Method("to_s")
			if method == nil {
				return nil
			}

			result, err := method.Execute(rubyValue, nil)
			if err != nil {
				return nil
			}

			return result.(*StringValue).RawString()
		}).OrSome(rubyValue.String()).Value().(string)

		str = strings.Replace(str, "#"+substringToReplace, valueAsString, 1)
	}

	return NewString(str, vm), nil
}
예제 #2
0
func interpretConstantInContext(
	vm *vm,
	constantNode ast.Constant,
	context Value,
) (Value, error) {

	maybeTarget := gomads.Maybe(func() interface{} {
		if vm.currentModuleName == "" {
			return vm.CurrentClasses["Object"]
		} else {
			return nil
		}
	}).OrSome(gomads.Maybe(func() interface{} {
		return vm.CurrentClasses[vm.currentModuleName]
	})).OrSome(gomads.Maybe(func() interface{} {
		return vm.CurrentModules[vm.currentModuleName]
	}))

	target, ok := maybeTarget.Value().(Module)

	maybeConstant := gomads.Maybe(func() interface{} {
		constant, err := target.Constant(constantNode.Name)
		if err == nil {
			return constant
		} else {
			return nil
		}
	}).OrSome(gomads.Maybe(func() interface{} {
		return vm.CurrentClasses[constantNode.Name]
	})).OrSome(gomads.Maybe(func() interface{} {
		return vm.CurrentModules[constantNode.Name]
	})).OrSome(gomads.Maybe(func() interface{} {
		if vm.currentModuleName == "" {
			return nil
		}

		parts := strings.Split(vm.currentModuleName, "::")
		count := len(parts) - 1
		for index, _ := range parts {
			namespace := append(parts[0:(count-index)], constantNode.Name)
			nameToLookup := strings.Join(namespace, "::")

			maybe := gomads.Maybe(func() interface{} {
				return vm.CurrentClasses[nameToLookup]
			}).OrSome(gomads.Maybe(func() interface{} {
				return vm.CurrentModules[nameToLookup]
			}))

			something, ok := maybe.Value().(Value)
			if ok {
				return something
			}
		}

		return nil
	}))

	constant, ok := maybeConstant.Value().(Value)
	if ok {
		return constant, nil
	} else {
		return nil, NewNameError(
			constantNode.Name,
			context.String(),
			context.Class().String(),
			vm.stack.String(),
		)
	}

}
예제 #3
0
func interpretClassInContext(
	vm *vm,
	class ast.Class,
	context Value,
) (Value, error) {

	var (
		value Value
		ok    bool
	)

	name := class.FullName()
	maybeTheValue := gomads.Maybe(func() interface{} {
		return vm.CurrentClasses[name]
	}).OrSome(gomads.Maybe(func() interface{} {
		return vm.CurrentModules[name]
	})).OrSome(gomads.Maybe(func() interface{} {
		module, ok := vm.CurrentClasses[class.Namespace]
		if !ok {
			return nil
		}

		value, err := module.Constant(class.Name)
		if err != nil {
			return nil
		}

		return value
	})).OrSome(gomads.Maybe(func() interface{} {
		module, ok := vm.CurrentModules[class.Namespace]
		if !ok {
			return nil
		}

		value, err := module.Constant(class.Name)
		if err != nil {
			return nil
		}

		return value
	})).OrSome(gomads.Maybe(func() interface{} {
		if vm.currentModuleName == "" {
			return nil
		}

		parts := strings.Split(vm.currentModuleName, "::")
		count := len(parts) - 1
		for index, _ := range parts {
			namespace := append(parts[0:(count-index)], name)
			nameToLookup := strings.Join(namespace, "::")

			maybe := gomads.Maybe(func() interface{} {
				return vm.CurrentClasses[nameToLookup]
			}).OrSome(gomads.Maybe(func() interface{} {
				return vm.CurrentModules[nameToLookup]
			}))

			something, ok := maybe.Value().(Value)
			if ok {
				return something
			}
		}

		return nil
	})).OrSome(
		NewNameError(
			name,
			context.String(),
			context.Class().String(),
			vm.stack.String(),
		),
	)

	value, ok = maybeTheValue.Value().(Value)

	if ok {
		return value, nil
	} else {
		return nil, value.(error)
	}
}
예제 #4
0
func interpretBareReferenceInContext(
	vm *vm,
	ref ast.BareReference,
	context Value,
) (Value, error) {

	var name string = ref.Name
	var returnErr error

	maybe := gomads.Maybe(func() interface{} {
		m, err := vm.localVariableStack.Retrieve(name)
		if err == nil {
			return m
		} else {
			return nil
		}
	}).OrSome(gomads.Maybe(func() interface{} {
		m, ok := vm.ObjectSpace[name]
		if ok {
			return m
		} else {
			return nil
		}
	})).OrSome(gomads.Maybe(func() interface{} {
		m, ok := vm.CurrentClasses[name]
		if ok {
			return m
		} else {
			return nil
		}
	})).OrSome(gomads.Maybe(func() interface{} {
		m, ok := vm.CurrentModules[name]
		if ok {
			return m
		} else {
			return nil
		}
	})).OrSome(gomads.Maybe(func() interface{} {
		maybeMethod := context.Method(name)
		if maybeMethod == nil {
			return nil
		}

		value, err := maybeMethod.Execute(context, nil)
		if err != nil {
			returnErr = err
			return nil
		} else {
			return value
		}
	}))

	if returnErr != nil {
		return nil, returnErr
	}

	value, ok := maybe.Value().(Value)
	if ok {
		return value, nil
	} else {
		return nil, NewNameError(
			name,
			context.String(),
			context.Class().String(),
			vm.stack.String(),
		)
	}
}