Ejemplo n.º 1
0
def RelativeTo(X, Y):
	xf, yf = isA(X, VectorField), isA(Y, VectorField)
	if xf or yf:
		if xf and yf and X.valueType != Y.valueType:
			raise RuntimeParseError('"X relative to Y" with X, Y fields of different types')
		fieldType = X.valueType if xf else Y.valueType
		error = '"X relative to Y" with field and value of different types'
		def helper(context):
			pos = context.position.toVector()
			xp = X[pos] if xf else toType(X, fieldType, error)
			yp = Y[pos] if yf else toType(Y, fieldType, error)
			return xp + yp
		return DelayedArgument({'position'}, helper)
	else:
		if isinstance(X, OrientedPoint):	# TODO too strict?
			if isinstance(Y, OrientedPoint):
				raise RuntimeParseError('"X relative to Y" with X, Y both oriented points')
			Y = toVector(Y, '"X relative to Y" with X an oriented point but Y not a vector')
			return X.relativize(Y)
		elif isinstance(Y, OrientedPoint):
			X = toVector(X, '"X relative to Y" with Y an oriented point but X not a vector')
			return Y.relativize(X)
		else:
			X = toTypes(X, (Vector, float), '"X relative to Y" with X neither a vector nor scalar')
			Y = toTypes(Y, (Vector, float), '"X relative to Y" with Y neither a vector nor scalar')
			return valueRequiringEqualTypes(X + Y, X, Y, '"X relative to Y" with vector and scalar')
Ejemplo n.º 2
0
 def __init__(self, opts):
     if isinstance(opts, dict):
         self.options = []
         self.weights = dict()
         ordered = []
         for opt, prob in opts.items():
             if not isinstance(prob, (float, int)):
                 raise RuntimeParseError(
                     f'discrete distribution weight {prob}'
                     ' is not a constant number')
             if prob < 0:
                 raise RuntimeParseError(
                     f'discrete distribution weight {prob} is negative')
             if prob == 0:
                 continue
             opt = toDistribution(opt)
             self.options.append(opt)
             self.weights[opt] = prob
             ordered.append(prob)
         self.cumulativeWeights = tuple(itertools.accumulate(ordered))
     else:
         self.options = tuple(toDistribution(opt) for opt in opts)
         self.cumulativeWeights = None
     if len(self.options) == 0:
         raise RuntimeParseError(
             'tried to make discrete distribution over empty domain!')
     valueType = type_support.unifyingType(self.options)
     super().__init__(*self.options, valueType=valueType)
Ejemplo n.º 3
0
    def __init__(self, opts):
        if isinstance(opts, dict):
            options, weights = [], []
            for opt, prob in opts.items():
                if not isinstance(prob, (float, int)):
                    raise RuntimeParseError(
                        f'discrete distribution weight {prob}'
                        ' is not a constant number')
                if prob < 0:
                    raise RuntimeParseError(
                        f'discrete distribution weight {prob} is negative')
                if prob == 0:
                    continue
                options.append(opt)
                weights.append(prob)
            self.optWeights = dict(zip(options, weights))
        else:
            weights = None
            options = tuple(opts)
            self.optWeights = None
        if len(options) == 0:
            raise RuntimeParseError(
                'tried to make discrete distribution over empty domain!')

        index = self.makeSelector(len(options) - 1, weights)
        super().__init__(index, options)
Ejemplo n.º 4
0
def ego(obj=None):
	global egoObject
	if obj is None:
		if egoObject is None:
			raise RuntimeParseError('referred to ego object not yet assigned')
	elif not isinstance(obj, Object):
		raise RuntimeParseError('tried to make non-object the ego object')
	else:
		egoObject = obj
	return egoObject
Ejemplo n.º 5
0
def mutate(*objects):  # TODO update syntax
    """Function implementing the mutate statement."""
    if evaluatingRequirement:
        raise RuntimeParseError('used mutate statement inside a requirement')
    if len(objects) == 0:
        objects = allObjects
    for obj in objects:
        if not isinstance(obj, Object):
            raise RuntimeParseError('"mutate X" with X not an object')
        obj.mutationEnabled = True
Ejemplo n.º 6
0
def RelativeTo(X, Y):
    """The 'X relative to Y' polymorphic operator.

	Allowed forms:
		F relative to G (with at least one a field, the other a field or heading)
		<vector> relative to <oriented point> (and vice versa)
		<vector> relative to <vector>
		<heading> relative to <heading>
	"""
    xf, yf = isA(X, VectorField), isA(Y, VectorField)
    if xf or yf:
        if xf and yf and X.valueType != Y.valueType:
            raise RuntimeParseError(
                '"X relative to Y" with X, Y fields of different types')
        fieldType = X.valueType if xf else Y.valueType
        error = '"X relative to Y" with field and value of different types'

        def helper(context):
            pos = context.position.toVector()
            xp = X[pos] if xf else toType(X, fieldType, error)
            yp = Y[pos] if yf else toType(Y, fieldType, error)
            return xp + yp

        return DelayedArgument({'position'}, helper)
    else:
        if isinstance(X, OrientedPoint):  # TODO too strict?
            if isinstance(Y, OrientedPoint):
                raise RuntimeParseError(
                    '"X relative to Y" with X, Y both oriented points')
            Y = toVector(
                Y,
                '"X relative to Y" with X an oriented point but Y not a vector'
            )
            return X.relativize(Y)
        elif isinstance(Y, OrientedPoint):
            X = toVector(
                X,
                '"X relative to Y" with Y an oriented point but X not a vector'
            )
            return Y.relativize(X)
        else:
            X = toTypes(
                X, (Vector, float),
                '"X relative to Y" with X neither a vector nor scalar')
            Y = toTypes(
                Y, (Vector, float),
                '"X relative to Y" with Y neither a vector nor scalar')
            return evaluateRequiringEqualTypes(
                lambda: X + Y, X, Y,
                '"X relative to Y" with vector and scalar')
Ejemplo n.º 7
0
def ego(obj=None):
    """Function implementing loads and stores to the 'ego' pseudo-variable.

	The translator calls this with no arguments for loads, and with the source
	value for stores.
	"""
    global egoObject
    if obj is None:
        if egoObject is None:
            raise RuntimeParseError('referred to ego object not yet assigned')
    elif not isinstance(obj, Object):
        raise RuntimeParseError('tried to make non-object the ego object')
    else:
        egoObject = obj
    return egoObject
Ejemplo n.º 8
0
def registerObject(obj):
	if activity > 0:
		assert not evaluatingRequirement
		assert isinstance(obj, Constructible)
		allObjects.append(obj)
	elif evaluatingRequirement:
		raise RuntimeParseError('tried to create an object inside a requirement')
Ejemplo n.º 9
0
def ApparentHeading(X, Y=None):
	if not isinstance(X, OrientedPoint):
		raise RuntimeParseError('"apparent heading of X from Y" with X not an OrientedPoint')
	if Y is None:
		Y = ego()
	Y = toVector(Y, '"relative heading of X from Y" with Y not a vector')
	return apparentHeadingAtPoint(X.position, X.heading, Y)
Ejemplo n.º 10
0
def param(**params):
    """Function implementing the param statement."""
    if evaluatingRequirement:
        raise RuntimeParseError(
            'tried to create a global parameter inside a requirement')
    for name, value in params.items():
        globalParameters[name] = toDistribution(value)
Ejemplo n.º 11
0
def mutate(*objects):		# TODO update syntax
	if len(objects) == 0:
		objects = allObjects
	for obj in objects:
		if not isinstance(obj, Object):
			raise RuntimeParseError('"mutate X" with X not an object')
		obj.mutationEnabled = True
Ejemplo n.º 12
0
def valueRequiringEqualTypes(val, thingA, thingB, typeError='type mismatch'):
    """Return the value, assuming thingA and thingB have the same type."""
    if not needsLazyEvaluation(thingA) and not needsLazyEvaluation(thingB):
        if underlyingType(thingA) is not underlyingType(thingB):
            raise RuntimeParseError(typeError)
        return val
    else:
        return TypeEqualityChecker(val, thingA, thingB, typeError)
Ejemplo n.º 13
0
def CanSee(X, Y):
	if not isinstance(X, Point):
		raise RuntimeParseError('"X can see Y" with X not a Point')
	if isinstance(Y, Object):
		return X.canSee(Y)
	else:
		Y = toVector(Y, '"X can see Y" with Y not a vector')
		return X.visibleRegion.containsPoint(Y)
Ejemplo n.º 14
0
def Follow(F, X, D):
	if not isinstance(F, VectorField):
		raise RuntimeParseError('"follow F from X for D" with F not a vector field')
	X = toVector(X, '"follow F from X for D" with X not a vector')
	D = toScalar(D, '"follow F from X for D" with D not a number')
	pos = F.followFrom(X, D)
	heading = F[pos]
	return OrientedPoint(position=pos, heading=heading)
Ejemplo n.º 15
0
 def dfs(spec):
     if spec in done:
         return
     elif spec in seen:
         raise RuntimeParseError(
             f'specifier for property {spec.property} '
             'depends on itself')
     seen.add(spec)
     for dep in spec.requiredProperties:
         child = properties.get(dep)
         if child is None:
             raise RuntimeParseError(
                 f'property {dep} required by '
                 f'specifier {spec} is not specified')
         else:
             dfs(child)
     order.append(spec)
     done.add(spec)
Ejemplo n.º 16
0
def coerceToAny(thing, types, error):
    """Coerce something into any of the given types, printing an error if impossible."""
    for ty in types:
        if canCoerce(thing, ty):
            return coerce(thing, ty)
    print(
        f'Failed to coerce {thing} of type {underlyingType(thing)} to {types}',
        file=sys.stderr)
    raise RuntimeParseError(error)
Ejemplo n.º 17
0
	def __init__(self, prop, value, deps=None, optionals={}):
		self.property = prop
		self.value = toDelayedArgument(value)
		if deps is None:
			deps = set()
		deps |= requiredProperties(value)
		if prop in deps:
			raise RuntimeParseError(f'specifier for property {prop} depends on itself')
		self.requiredProperties = deps
		self.optionals = optionals
Ejemplo n.º 18
0
def param(*quotedParams, **params):
    """Function implementing the param statement."""
    if evaluatingRequirement:
        raise RuntimeParseError(
            'tried to create a global parameter inside a requirement')
    for name, value in params.items():
        globalParameters[name] = toDistribution(value)
    assert len(quotedParams) % 2 == 0, quotedParams
    it = iter(quotedParams)
    for name, value in zip(it, it):
        globalParameters[name] = toDistribution(value)
Ejemplo n.º 19
0
def require(reqID, req, line, prob=1):
    """Function implementing the require statement."""
    if evaluatingRequirement:
        raise RuntimeParseError(
            'tried to create a requirement inside a requirement')
    # the translator wrapped the requirement in a lambda to prevent evaluation,
    # so we need to save the current values of all referenced names; throw in
    # the ego object too since it can be referred to implicitly
    assert reqID not in pendingRequirements
    pendingRequirements[reqID] = (req, getAllGlobals(req), egoObject, line,
                                  prob)
Ejemplo n.º 20
0
def registerObject(obj):
    """Add a Scenic object to the global list of created objects.

	This is called by the Object constructor."""
    if activity > 0:
        assert not evaluatingRequirement
        assert isinstance(obj, Constructible)
        allObjects.append(obj)
    elif evaluatingRequirement:
        raise RuntimeParseError(
            'tried to create an object inside a requirement')
Ejemplo n.º 21
0
def VisibleFrom(base):
    """The 'visible from <Point>' specifier.

	Specifies 'position', with no dependencies.

	This uses the given object's 'visibleRegion' property, and so correctly
	handles the view regions of Points, OrientedPoints, and Objects.
	"""
    if not isinstance(base, Point):
        raise RuntimeParseError(
            'specifier "visible from O" with O not a Point')
    return Specifier('position', Region.uniformPointIn(base.visibleRegion))
Ejemplo n.º 22
0
def Beyond(pos, offset, fromPt=None):
	pos = toVector(pos, 'specifier "beyond X by Y" with X not a vector')
	dType = underlyingType(offset)
	if dType is float or dType is int:
		offset = Vector(0, offset)
	elif dType is not Vector:
		raise RuntimeParseError('specifier "beyond X by Y" with Y not a number or vector')
	if fromPt is None:
		fromPt = ego()
	fromPt = toVector(fromPt, 'specifier "beyond X by Y from Z" with Z not a vector')
	lineOfSight = fromPt.angleTo(pos)
	return Specifier('position', pos.offsetRotated(lineOfSight, offset))
Ejemplo n.º 23
0
def ApparentHeading(X, Y=None):
    """The 'apparent heading of <oriented point> [from <vector>]' operator.

	If the 'from <vector>' is omitted, the position of ego is used.
	"""
    if not isinstance(X, OrientedPoint):
        raise RuntimeParseError(
            '"apparent heading of X from Y" with X not an OrientedPoint')
    if Y is None:
        Y = ego()
    Y = toVector(Y, '"relative heading of X from Y" with Y not a vector')
    return apparentHeadingAtPoint(X.position, X.heading, Y)
Ejemplo n.º 24
0
	def __init__(self, requiredProperties, attributes, value):
		self.requiredProperties = requiredProperties
		self.value = value

		def enabled(thing, default):
			if thing in attributes:
				attributes.remove(thing)
				return True
			else:
				return default
		self.isAdditive = enabled('additive', False)
		for attr in attributes:
			raise RuntimeParseError(f'unknown property attribute "{attr}"')
Ejemplo n.º 25
0
def CanSee(X, Y):
    """The 'X can see Y' polymorphic operator.

	Allowed forms:
		<point> can see <object>
		<point> can see <vector>
	"""
    if not isinstance(X, Point):
        raise RuntimeParseError('"X can see Y" with X not a Point')
    if isinstance(Y, Point):
        return X.canSee(Y)
    else:
        Y = toVector(Y, '"X can see Y" with Y not a vector')
        return X.visibleRegion.containsPoint(Y)
Ejemplo n.º 26
0
def evaluateRequiringEqualTypes(func,
                                thingA,
                                thingB,
                                typeError='type mismatch'):
    """Evaluate the func, assuming thingA and thingB have the same type.

	If func produces a lazy value, it should not have any required properties beyond
	those of thingA and thingB."""
    if not needsLazyEvaluation(thingA) and not needsLazyEvaluation(thingB):
        if underlyingType(thingA) is not underlyingType(thingB):
            raise RuntimeParseError(typeError)
        return func()
    else:
        # cannot check the types now; create proxy object to check types after evaluation
        return TypeEqualityChecker(func, thingA, thingB, typeError)
Ejemplo n.º 27
0
def leftSpecHelper(syntax, pos, dist, axis, toComponents, makeOffset):
	extras = set()
	dType = underlyingType(dist)
	if dType is float or dType is int:
		dx, dy = toComponents(dist)
	elif dType is Vector:
		dx, dy = dist
	else:
		raise RuntimeParseError(f'"{syntax} X by D" with D not a number or vector')
	if isinstance(pos, OrientedPoint):		# TODO too strict?
		val = lambda self: pos.relativePosition(makeOffset(self, dx, dy))
		new = DelayedArgument({axis}, val)
		extras.add('heading')
	else:
		pos = toVector(pos, f'specifier "{syntax} X" with X not a vector')
		val = lambda self: pos.offsetRotated(self.heading, makeOffset(self, dx, dy))
		new = DelayedArgument({axis, 'heading'}, val)
	return Specifier('position', new, optionals=extras)
Ejemplo n.º 28
0
def Following(field, dist, fromPt=None):
    """The 'following F [from X] for D' specifier.

	Specifies 'position', and optionally 'heading', with no dependencies.

	Allowed forms:
		following <field> [from <vector>] for <number>

	If the 'from <vector>' is omitted, the position of ego is used.
	"""
    if fromPt is None:
        fromPt = ego()
    else:
        dist, fromPt = fromPt, dist
    if not isinstance(field, VectorField):
        raise RuntimeParseError(
            '"following F" specifier with F not a vector field')
    fromPt = toVector(fromPt, '"following F from X for D" with X not a vector')
    dist = toScalar(dist, '"following F for D" with D not a number')
    pos = field.followFrom(fromPt, dist)
    heading = field[pos]
    val = OrientedPoint(position=pos, heading=heading)
    return Specifier('position', val, optionals={'heading'})
Ejemplo n.º 29
0
 def closure(values):
     # rebind any names referring to sampled objects
     for name, value in bindings.items():
         if value in values:
             namespace[name] = values[value]
     # rebind ego object, which can be referred to implicitly
     if ego is not None:
         veneer.egoObject = values[ego]
     # evaluate requirement condition, reporting errors on the correct line
     try:
         veneer.evaluatingRequirement = True
         result = req()
         assert not needsSampling(result)
         if needsLazyEvaluation(result):
             raise RuntimeParseError(
                 f'requirement on line {line} uses value'
                 ' undefined outside of object definition')
         return result
     except RuntimeParseError as e:
         cause = e if showInternalBacktrace else None
         raise InterpreterParseError(e, line) from cause
     finally:
         veneer.evaluatingRequirement = False
Ejemplo n.º 30
0
def Beyond(pos, offset, fromPt=None):
    """The 'beyond X by Y [from Z]' polymorphic specifier.

	Specifies 'position', with no dependencies.

	Allowed forms:
		beyond <vector> by <number> [from <vector>]
		beyond <vector> by <vector> [from <vector>]

	If the 'from <vector>' is omitted, the position of ego is used.
	"""
    pos = toVector(pos, 'specifier "beyond X by Y" with X not a vector')
    dType = underlyingType(offset)
    if dType is float or dType is int:
        offset = Vector(0, offset)
    elif dType is not Vector:
        raise RuntimeParseError(
            'specifier "beyond X by Y" with Y not a number or vector')
    if fromPt is None:
        fromPt = ego()
    fromPt = toVector(fromPt,
                      'specifier "beyond X by Y from Z" with Z not a vector')
    lineOfSight = fromPt.angleTo(pos)
    return Specifier('position', pos.offsetRotated(lineOfSight, offset))