Exemple #1
0
func panicEvalError(n ast.Node, s string) {
	var loc *token.Location
	if n != nil {
		loc = n.Loc()
	}
	panic(NewEvalError("Evaluation error", s, loc))
}
Exemple #2
0
func panicApplicationError(n ast.Node, s string) {
	var loc *token.Location
	if n != nil {
		loc = n.Loc()
	}
	panic(NewEvalError("Application panic", s, loc))
}
Exemple #3
0
func evalInvokeProcedure(dynamicEnv Env, f *Procedure, head ast.Node, unevaledArgs ast.Nodes, shouldEvalMacros bool) packet {
	defer func() {
		if e := recover(); e != nil {
			switch errorValue := e.(type) {
			case *EvalError:
				fmt.Printf("TRACE: (%v: %v): call to %v\n", head.Loc().Filename, head.Loc().Line, f.Name)
				panic(errorValue)
			default:
				panic(errorValue)
			}
		}
	}()

	// Validate parameters
	isVariableNumberOfParams := false
	for _, param := range f.Parameters {
		switch paramVal := param.(type) {
		case *ast.Symbol:
			if paramVal.Name == "&rest" {
				isVariableNumberOfParams = true
			}
		default:
			panicEvalError(head, "Procedure parameters should only be symbols: "+param.String())
		}
	}
	if !isVariableNumberOfParams {
		if len(unevaledArgs) != len(f.Parameters) {
			panicEvalError(head, fmt.Sprintf(
				"Procedure '%v' expects %v argument(s), but was given %v. Procedure parameter list: %v. Arguments: %v.",
				f.Name,
				len(f.Parameters),
				len(unevaledArgs),
				f.Parameters,
				unevaledArgs))
		}
	}

	// Create the lexical environment based on the procedure's lexical parent
	lexicalEnv := NewMapEnv(f.Name, f.ParentEnv)

	// Prepare the arguments for application
	var args []ast.Node
	if f.IsMacro {
		args = unevaledArgs
	} else {
		args = evalEachNode(dynamicEnv, unevaledArgs)
	}

	// Map arguments to parameters
	isMappingRestArgs := false
	iarg := 0
	for iparam, param := range f.Parameters {
		paramName := toSymbolName(param)
		if isMappingRestArgs {
			restArgs := args[iarg:]
			restList := ast.NewList(restArgs)
			lexicalEnv.Set(paramName, restList)
		} else if paramName == "&rest" {
			isMappingRestArgs = true
		} else {
			lexicalEnv.Set(paramName, args[iparam])
			iarg++
		}
	}

	if f.IsMacro {
		expandedMacro := trampoline(func() packet {
			return evalNode(lexicalEnv, f.Body)
		})

		if shouldEvalMacros {
			return bounce(func() packet {
				// This is executed in the environment of its application, not the
				// environment of its definition
				return evalNode(dynamicEnv, expandedMacro)
			})
		} else {
			return respond(expandedMacro)
		}
	} else {
		// Evaluate the body in the new lexical environment
		return bounce(func() packet {
			return evalNode(lexicalEnv, f.Body)
		})
	}
}